public DreamEffect() { Name = "Dream"; var diagonalGradient = new LinearGradient { StartPoint = new Point(0.0, 0.0), EndPoint = new Point(1.0, 1.0), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(255, 133, 147, 201)}, new GradientStop {Offset = 1.0, Color = Color.FromArgb(255, 245, 152, 157)} } }; var overlayFactory = new OverlayFactory( "ms-appx:///images/Filters_Landscape_Overlay_Dream.jpg", "ms-appx:///images/Filters_Portrait_Overlay_Dream.jpg", "ms-appx:///images/Filters_Square_Overlay_Dream.jpg"); LayerList = new LayerList( new AdjustmentLayer(LayerStyle.Normal(), new LevelsEffect(0.75, 0.85, 0.15)), new Layer(LayerStyle.Softlight(), context => new GradientImageSource(context.BackgroundLayer.ImageSize, diagonalGradient)), new Layer(LayerStyle.Overlay(), context => overlayFactory.CreateAsync(context.BackgroundLayer.ImageSize)) ); }
public LinearGradientImageSourceEffectProcessor() { Name = "Linear Gradient"; m_endX = 1.0; m_endY = 1.0; m_linearGradient = new LinearGradient(new Point(0.0, 0.0), new Point(1.0, 1.0)); m_linearGradient.Stops = new[] { new GradientStop{Offset=0.0, Color=Colors.Red}, new GradientStop{Offset=0.5, Color=Colors.Green}, new GradientStop{Offset=1.0, Color=Colors.Cyan} }; m_gradientImageSource = new GradientImageSource(new Size(800,500), m_linearGradient); SetupEffectCategory(m_gradientImageSource); m_propertyDescriptions = new Dictionary<string, PropertyDescription>(); m_propertyDescriptions.Add("StartX", new PropertyDescription(-1.0, 2.0, 0)); m_propertyDescriptions.Add("StartY", new PropertyDescription(-1.0, 2.0, 0)); m_propertyDescriptions.Add("EndX", new PropertyDescription(-1.0, 2.0, 0)); m_propertyDescriptions.Add("EndY", new PropertyDescription(-1.0, 2.0, 0)); AddEditors(); }
private static void SetGradientStops(LinearGradient gradient, FocusBand focusBand, Size sourceSize, KernelGenerator edge1KernelGenerator, KernelGenerator edge2KernelGenerator, bool applySmallBlurFocusArea) { var blurArea1FirstOffset = GetOffset(gradient, focusBand.Edge1); var blurArea2FirstOffset = GetOffset(gradient, focusBand.Edge2); var focusBandEdge1Pixels = new Point(focusBand.Edge1.X * sourceSize.Width, focusBand.Edge1.Y * sourceSize.Height); var focusBandEdge2Pixels = new Point(focusBand.Edge2.X * sourceSize.Width, focusBand.Edge2.Y * sourceSize.Height); var focusBandWidth = Math.Abs(blurArea1FirstOffset - blurArea2FirstOffset); var focusBandWidthPixels = Distance(focusBandEdge1Pixels, focusBandEdge2Pixels); double blurAreaWidth; if (focusBandWidthPixels > 0) { var scaleFactor = focusBandWidth / focusBandWidthPixels; var blurAreaWidthPixels = (sourceSize.Height - focusBandWidthPixels) / 2 * 0.9; if (blurAreaWidthPixels < 1.0) { gradient.Stops = new[] { new GradientStop() { Offset = 0.5, Color = Color.FromArgb(255, 0, 0, 0) } }; return; } blurAreaWidth = blurAreaWidthPixels * scaleFactor; } else { blurAreaWidth = 0.5; applySmallBlurFocusArea = true; } double blurArea1LastOffset; double blurArea2LastOffset; if (blurArea1FirstOffset > blurArea2FirstOffset) { blurArea1LastOffset = blurArea1FirstOffset + blurAreaWidth; blurArea2LastOffset = blurArea2FirstOffset - blurAreaWidth; } else { blurArea1LastOffset = blurArea1FirstOffset - blurAreaWidth; blurArea2LastOffset = blurArea2FirstOffset + blurAreaWidth; } var stops1 = GetGradientStops(gradient, applySmallBlurFocusArea, edge1KernelGenerator, blurArea1FirstOffset, blurArea1LastOffset); var stops2 = GetGradientStops(gradient, applySmallBlurFocusArea, edge2KernelGenerator, blurArea2FirstOffset, blurArea2LastOffset, (byte)(edge1KernelGenerator.GetKernelBands().Count)); List<GradientStop> stops = new List<GradientStop>(); stops.AddRange(stops1); stops.AddRange(stops2); var validStops = EnsureMinDiffBetweenPoints(stops); gradient.Stops = validStops.ToArray(); }
/// <summary> /// Provides a configured LinearGradient that can be used in combination with a GradientImageSource to provide a mask for the LensBlurEffect. /// Generates a map for BlendEffect. /// </summary> /// <param name="band">The band that represents the focus area in the image. Pixels within this band won't be blurred. /// Areas outside of the area will be progressively more blurred as the distance from the focus band increases.</param> /// <param name="kernelSpanFromEdge1">Strength at Edge1.</param> /// <param name="kernelSpanFromEdge2">Strength at Edge2.</param> /// <returns>A LinearGradient that can be used in combination with a GradientImageSource to be used by LensBlur.</returns> public static LinearGradient GenerateGradient(FocusBand band, Size sourceSize, KernelGenerator edge1KernelGenerator, KernelGenerator edge2KernelGenerator, bool applySmallBlurFocusArea) { var gradient = new LinearGradient(); var lineFunction = GradientLine.CreateFunction(band); SetGradientPoints(gradient, lineFunction); SetGradientStops(gradient, band, sourceSize, edge1KernelGenerator, edge2KernelGenerator, applySmallBlurFocusArea); return gradient; }
public static ColorBase GetColor(Brush brush, double opacity, Rect bounds, double angle = 0) { var solidBrush = brush as SolidColorBrush; if (solidBrush != null) { return GetRgbColor(solidBrush.Color, opacity); } var linerBrush = brush as LinearGradientBrush; if (linerBrush != null) { var startPoint = new Point(bounds.X + linerBrush.StartPoint.X * bounds.Width, bounds.Y + linerBrush.StartPoint.Y * bounds.Height); var endPoint = new Point(bounds.X + linerBrush.EndPoint.X * bounds.Width, bounds.Y + linerBrush.EndPoint.Y * bounds.Height); LinearGradient gradient = new LinearGradient(startPoint, endPoint); foreach (var stop in linerBrush.GradientStops) { gradient.GradientStops.Add(new Telerik.Windows.Documents.Fixed.Model.ColorSpaces.GradientStop(GetRgbColor(stop.Color, opacity), stop.Offset)); } gradient.Position.RotateAt(angle, bounds.Center().X, bounds.Center().Y); return gradient; } var radialBrush = brush as RadialGradientBrush; if (radialBrush != null) { var startPoint = new Point(bounds.X + radialBrush.GradientOrigin.X * bounds.Width, bounds.Y + radialBrush.GradientOrigin.Y * bounds.Height); var endPoint = new Point(bounds.X + radialBrush.Center.X * bounds.Width, bounds.Y + radialBrush.Center.Y * bounds.Height); var radiusX = radialBrush.RadiusX * bounds.Width; var radiusY = radialBrush.RadiusY * bounds.Height; Point scale = new Point(1, 1); if (radiusX > radiusY) scale.X = radiusX / radiusY; else if (radiusY > radiusX) scale.Y = radiusY / radiusX; RadialGradient gradient = new RadialGradient(startPoint, endPoint, 0, Math.Min(radiusX, radiusY)); for (int i = 0; i < radialBrush.GradientStops.Count; i++) { var stop = radialBrush.GradientStops[i]; var color = GetRgbColor(stop.Color, opacity); gradient.GradientStops.Add(new Telerik.Windows.Documents.Fixed.Model.ColorSpaces.GradientStop(color, stop.Offset)); } gradient.Position.ScaleAt(scale.X, scale.Y, bounds.Center().X, bounds.Center().Y); gradient.Position.RotateAt(angle, bounds.Center().X, bounds.Center().Y); return gradient; } return RgbColors.Black; }
void DrawBookmark(Context cr, double x, double y) { var color1 = Style.BookmarkColor1; var color2 = Style.BookmarkColor2; DrawRoundRectangle(cr, x + 1, y + 1, 8, Width - 4, Editor.LineHeight - 4); using (var pat = new LinearGradient(x + Width / 4, y, x + Width / 2, y + Editor.LineHeight - 4)) { pat.AddColorStop(0, color1); pat.AddColorStop(1, color2); cr.Pattern = pat; cr.FillPreserve(); } using (var pat = new LinearGradient(x, y + Editor.LineHeight, x + Width, y)) { pat.AddColorStop(0, color2); //pat.AddColorStop (1, color1); cr.Pattern = pat; cr.Stroke(); } }
public RetroEffect() { var globalCurve = new Curve { Points = new[] { new Point(0, 0), new Point(41, 59), new Point(112, 146), new Point(189, 211), new Point(255, 255) } }; var redCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 0), new Point(75, 61), new Point(255, 255) }); Curve.Compose(redCurve, globalCurve, redCurve); var greenCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 0), new Point(59, 34), new Point(182, 199), new Point(255, 255) }); Curve.Compose(greenCurve, globalCurve, greenCurve); var blueCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 91), new Point(128, 128), new Point(255, 185) }); Curve.Compose(blueCurve, globalCurve, blueCurve); var yellowPurpleGradient = new LinearGradient { StartPoint = new Point(0.0, 0.5), EndPoint = new Point(1.0, 0.5), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(255, 255, 255, 0)}, new GradientStop {Offset = 0.5, Color = Color.FromArgb(255, 148, 106, 77)}, new GradientStop {Offset = 1.0, Color = Color.FromArgb(255, 72, 3, 131)} } }; var redTransparentGradient = new LinearGradient { StartPoint = new Point(0.0, 0.5), EndPoint = new Point(1.0, 0.5), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(255, 255, 0, 0)}, new GradientStop {Offset = 1.0, Color = Color.FromArgb(0, 255, 0, 0)} } }; var spotGradient = new RadialGradient { CenterPoint = new Point(0.5, 0.3), EllipseRadius = new EllipseRadius(0, 0.2), Stops = new[] { new GradientStop {Offset = 0.0, Color = Color.FromArgb(255, 255, 255, 255)}, new GradientStop {Offset = 1.0, Color = Color.FromArgb(0, 255, 255, 255)} } }; var vignetteGradient = new RadialGradient { CenterPoint = new Point(0.5, 0.5), EllipseRadius = new EllipseRadius(1.0, 0), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(255, 255, 255, 255)}, new GradientStop {Offset = 0.9, Color = Color.FromArgb(255, 0, 0, 0)} } }; LayerList = new LayerList() { new AdjustmentLayer(LayerStyle.Normal(), new CurvesEffect(redCurve, greenCurve, blueCurve)), new Layer(LayerStyle.Softlight(0.3), context => new GradientImageSource(context.BackgroundLayer.ImageSize, yellowPurpleGradient)), new Layer(LayerStyle.Screen(0.75, targetArea: new Rect(0, 0, 0.4, 1.0)), context => new GradientImageSource(new Size(context.BackgroundLayer.ImageSize.Width * 0.4, context.BackgroundLayer.ImageSize.Height), redTransparentGradient)), new Layer(LayerStyle.Softlight(), context => new GradientImageSource(context.BackgroundLayer.ImageSize, spotGradient)), new Layer(LayerStyle.Softlight(0.6), context => new GradientImageSource(context.BackgroundLayer.ImageSize, vignetteGradient)) }; }
private static void SetGradientPoints(LinearGradient gradient, Func<double, Point> pointFunction) { gradient.StartPoint = pointFunction(0); gradient.EndPoint = pointFunction(1); }
private static double GetOffset(LinearGradient gradient, Point p) { var distnacePFromP1 = Distance(p, gradient.StartPoint); var distnaceP1FromP2 = Distance(gradient.StartPoint, gradient.EndPoint); var offset = distnacePFromP1 / distnaceP1FromP2; return offset; }
private static Tiling CreateTiling(double offsetX, double offsetY, double width, SimpleColor color) { Tiling tiling = new Tiling(new Rect(0, 0, width, 2)); tiling.Position.Translate(offsetX, offsetY); var tilingEditor = new FixedContentEditor(tiling); tilingEditor.GraphicProperties.IsStroked = false; tilingEditor.GraphicProperties.FillColor = color; tilingEditor.DrawRectangle(new Rect(0, 0, width, 1)); LinearGradient gradient = new LinearGradient(new Point(0, 0), new Point(width, 0)); gradient.GradientStops.Add(new GradientStop(color, 0)); gradient.GradientStops.Add(new GradientStop(RgbColors.White, .5)); gradient.GradientStops.Add(new GradientStop(color, 1)); tilingEditor.GraphicProperties.FillColor = gradient; tilingEditor.DrawRectangle(new Rect(0, 1, width, 1)); return tiling; }
public GlamMeLomoEffect() { var globalCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 0), new Point(41, 59), new Point(112, 146), new Point(189, 211), new Point(255, 255) }); var redCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 0), new Point(101, 45), new Point(191, 193), new Point(255, 255) }); Curve.Compose(redCurve, globalCurve, redCurve); var greenCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 0), new Point(78, 61), new Point(187, 199), new Point(255, 255) }); Curve.Compose(greenCurve, globalCurve, greenCurve); var blueCurve = new Curve(CurveInterpolation.NaturalCubicSpline, new[] { new Point(0, 0), new Point(56, 71), new Point(204, 181), new Point(255, 255) }); Curve.Compose(blueCurve, globalCurve, blueCurve); var linearGradient = new LinearGradient { StartPoint = new Point(0.0, 0.5), EndPoint = new Point(1.0, 0.5), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(255, 135, 135, 135) }, new GradientStop {Offset = 1.0, Color = Color.FromArgb(255, 193, 193, 193) } } }; var vignetteGradient = new RadialGradient { CenterPoint = new Point(0.5, 0.5), EllipseRadius = new EllipseRadius(2.0, 0), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(0, 255, 255, 255)}, new GradientStop {Offset = 0.9, Color = Color.FromArgb(255, 0, 0, 0)} } }; var vignette2Gradient = new RadialGradient { CenterPoint = new Point(0.5, 0.5), EllipseRadius = new EllipseRadius(1.0, 0), Stops = new[] { new GradientStop {Offset = 0, Color = Color.FromArgb(0, 0, 0, 0)}, new GradientStop {Offset = 0.5, Color = Color.FromArgb(0, 0, 0, 0)}, new GradientStop {Offset = 1.0, Color = Color.FromArgb(255, 0, 0, 0)} } }; LayerList = new LayerList() { new AdjustmentLayer(LayerStyle.Normal(), new CurvesEffect(redCurve, greenCurve, blueCurve)), new Layer(LayerStyle.Overlay(), context => new GradientImageSource(context.BackgroundLayer.ImageSize, linearGradient)), new Layer(LayerStyle.Softlight(0.4), context => new GradientImageSource(context.BackgroundLayer.ImageSize, vignetteGradient)), new Layer(LayerStyle.Darken(0.5), context => new GradientImageSource(context.BackgroundLayer.ImageSize, vignette2Gradient)) }; }
/// <summary> /// Fill to buffer base rows data information using non-zero rule /// </summary> /// <param name="paint">linear gradient object</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="isForward">is diagonal gradient is forward</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> void OnFillingTransformedDiagonalNonZero(LinearGradient paint, uint opacity, RowData[] rows, int startRowIndex, int endRowIndex, bool isForward, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue) { throw new NotImplementedException(); }
/// <summary> /// Fill to buffer base rows data information using non-zero rule /// </summary> /// <param name="paint">linear gradient object</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> void OnFillingTransformedVerticalNonZero(LinearGradient paint, uint opacity, RowData[] rows, int startRowIndex, int endRowIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue) { // now not need to check null or not uint[] builtColors = paint.GetLinearColors(opacity); #region private variable for filling int currentCoverage, scLastCoverage, scLastX = 0; int tempCover = 0; int currentArea = 0; int lastXPosition = 0; int startXPosition = 0; byte calculatedCoverage = 0; int currentColorIndexScaled = 0; CellData currentCellData = null; uint colorData = 0; uint dst, dstRB, dstG; //uint colorG = 0; //uint colorRB = 0; // each row color index will increase value double startRowIncrement = 0; #endregion #region varialbe for vertical double startY = paint.StartY; double endY = paint.EndY; double distance = endY - startY; #endregion #region variable for transform #region transform line 1,1 => 101,1 double currentYTransformed = 1 * InvertedMatrixShy + 1 * InvertedMatrixSy + InvertedMatrixTy; double destYToTransformed = 101 * InvertedMatrixShy + 1 * InvertedMatrixSy + InvertedMatrixTy; #endregion // in vertical we need increment by x after steps double transformedRatio = (destYToTransformed - currentYTransformed) / 100; // when transformed horizonline increase 1, x will increase by increment. int incrementTranformedColorIndexScaled = (int)((transformedRatio / distance) * ColorIndexIncludeIncrementScale); #endregion #region prepare value for rows //transform first cell of row currentYTransformed = startRowIndex * InvertedMatrixSy + InvertedMatrixTy; currentYTransformed = ((currentYTransformed - startY) / distance); //calculate row increment startRowIncrement = ((InvertedMatrixSy / distance)); #endregion #region FILLING if (paint.Ramp.NoBlendingColor) {// no blending color if (paint.Style != GradientStyle.Pad) { #region optimized for reflect and repeat mode incrementTranformedColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; if (incrementTranformedColorIndexScaled < 0) { incrementTranformedColorIndexScaled = ColorIndexIncludeIncrementDoubleScale - incrementTranformedColorIndexScaled; } #endregion // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup #region filling without blend for horizontal lines startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { #region transform for row currentColorIndexScaled = (int) (currentYTransformed * ColorIndexIncludeIncrementScale); if (currentColorIndexScaled < 0) { currentColorIndexScaled += ColorIndexIncludeIncrementDoubleScale; } currentYTransformed += startRowIncrement; #endregion // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value if (scLastCoverage >= 254) { while (startXPosition < lastXPosition) { //BufferData[startXPosition++] = colorData; //BufferData[startXPosition++] = builtColors[(currentColorIndexScaled >> IncrementColorIndexShift) ]; BufferData[startXPosition++] = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; //currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } else { while (startXPosition < lastXPosition) { colorData = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; calculatedCoverage = (byte)((colorData >> 24)); calculatedCoverage = (byte)((scLastCoverage * calculatedCoverage) >> 8); if (calculatedCoverage >= 255) { BufferData[startXPosition] = colorData; } else { //// blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion } startXPosition++; currentColorIndexScaled++; } } #endregion } else { // incre color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * incrementTranformedColorIndexScaled; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion colorData = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; calculatedCoverage = (byte)(colorData >> 24); #region blend pixel tempCover = (int)((tempCover * calculatedCoverage) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion #endregion } #endregion // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } #endregion } else {//GradientStyle.Pad mode #region GradientStyle.Pad // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup #region filling without blend for horizontal lines startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { #region transform for row currentColorIndexScaled = (int) (currentYTransformed * ColorIndexIncludeIncrementScale); //if (currentColorIndexScaled < 0) //{ // currentColorIndexScaled += ColorIndexIncludeIncrementDoubleScale; //} currentYTransformed += startRowIncrement; #endregion // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value if (scLastCoverage >= 254) { while (startXPosition < lastXPosition) { //BufferData[startXPosition++] = colorData; //BufferData[startXPosition++] = builtColors[(currentColorIndexScaled >> IncrementColorIndexShift) ]; BufferData[startXPosition++] = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : currentColorIndexScaled >> IncrementColorIndexShift)]; // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; //currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } else { while (startXPosition < lastXPosition) { //colorData = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; colorData = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : currentColorIndexScaled >> IncrementColorIndexShift)]; // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; calculatedCoverage = (byte)((colorData >> 24)); calculatedCoverage = (byte)((scLastCoverage * calculatedCoverage) >> 8); if (calculatedCoverage >= 255) { BufferData[startXPosition] = colorData; } else { // blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion } startXPosition++; currentColorIndexScaled++; } } #endregion } else { // incre color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * incrementTranformedColorIndexScaled; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion colorData = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : currentColorIndexScaled >> IncrementColorIndexShift)]; calculatedCoverage = (byte)(colorData >> 24); #region blend pixel tempCover = (int)((tempCover * calculatedCoverage) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion #endregion } #endregion // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } #endregion #endregion }//GradientStyle.Pad mode }// no blending color else {// has blending color if (paint.Style != GradientStyle.Pad) { #region optimized for reflect and repeat mode incrementTranformedColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; if (incrementTranformedColorIndexScaled < 0) { incrementTranformedColorIndexScaled = ColorIndexIncludeIncrementDoubleScale - incrementTranformedColorIndexScaled; } #endregion // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup #region filling without blend for horizontal lines startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { #region transform for row currentColorIndexScaled = (int) (currentYTransformed * ColorIndexIncludeIncrementScale); if (currentColorIndexScaled < 0) { currentColorIndexScaled += ColorIndexIncludeIncrementDoubleScale; } currentYTransformed += startRowIncrement; #endregion // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; while (startXPosition < lastXPosition) { colorData = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; currentColorIndexScaled += incrementTranformedColorIndexScaled; calculatedCoverage = (byte)(colorData >> 24); calculatedCoverage = (byte)((scLastCoverage * calculatedCoverage) >> 8); if (calculatedCoverage >= 254) { BufferData[startXPosition] = colorData; } else { #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0x00FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | ((uint)gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion } startXPosition++; currentColorIndexScaled++; } #endregion } else { // incre color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * incrementTranformedColorIndexScaled; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion colorData = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; calculatedCoverage = (byte)(colorData >> 24); #region blend pixel tempCover = (int)((tempCover * calculatedCoverage) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion #endregion } #endregion // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } #endregion } else { #region GradientStyle.Pad // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup #region filling without blend for horizontal lines startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { #region transform for row currentColorIndexScaled = (int) (currentYTransformed * ColorIndexIncludeIncrementScale); //if (currentColorIndexScaled < 0) //{ // currentColorIndexScaled += ColorIndexIncludeIncrementDoubleScale; //} currentYTransformed += startRowIncrement; #endregion // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; while (startXPosition < lastXPosition) { //colorData = builtColors[(currentColorIndexScaled & ColorIndexIncludeIncrementDoubleMask) >> IncrementColorIndexShift]; colorData = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : currentColorIndexScaled >> IncrementColorIndexShift)]; currentColorIndexScaled += incrementTranformedColorIndexScaled; calculatedCoverage = (byte)(colorData >> 24); calculatedCoverage = (byte)((scLastCoverage * calculatedCoverage) >> 8); if (calculatedCoverage >= 254) { BufferData[startXPosition] = colorData; } else { #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0x00FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | ((uint)gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion } startXPosition++; currentColorIndexScaled++; } #endregion } else { // incre color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * incrementTranformedColorIndexScaled; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion colorData = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : currentColorIndexScaled >> IncrementColorIndexShift)]; calculatedCoverage = (byte)(colorData >> 24); #region blend pixel tempCover = (int)((tempCover * calculatedCoverage) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = (((((colorData & 0x00FF00FF) - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | ((uint)(gammaLutGreen[(((((((colorData & 0xFF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | ((uint)gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion #endregion } #endregion // incre color index currentColorIndexScaled += incrementTranformedColorIndexScaled; scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } #endregion #endregion } }//has blending color #endregion }
/// <summary> /// Fill to buffer base rows data information using non-zero rule /// </summary> /// <param name="paint">linear gradient object</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="isForward">is diagonal gradient is forward</param> void OnFillingDiagonalNonZero( LinearGradient paint, uint opacity, RowData[] rows, int startRowIndex, int endRowIndex, bool isForward) { #region Explain for fomula /* * CALCULATION NEED FOLLOWING VALUES * 1/ INCREMENT * increment, when x from n to n+1 , * index of color will increase from * f(n) to f(n) + increment * * this increment value is calculated by * Linear from A to B * A C B' * * * * * * * * * * * * * * * * * * * * * * B * AC = w of the rect * BB' |_ AB * So AB' = (AB * AB)/AC = d * d / w * And increment is increment = 256 / AB' * it mean when x go from A to B' * color index will increase from 0=>255 ( 256 steps) * * * 2/ DISTANCE * (x3,y3) * * * * * * * * * * * * * * * (x1,y1)* * * * * * * * (x2,y2) * * x3,y3 can be calculated by following fomula * x3 = x1 - height of paint = x1 - ( y2- y1); * y3 = y1 + width of paint = y1 + ( x2 - x1); * * to determine color at point(x,y) to line (x1,y1)-(x3,y3) * from this distance we can determine the color at this * point by lookup to color array * * distance = ((x - x3) * (y3-y1) * - ( y - y3) * (x3 -x1))/(distance from start and end point of paint); */ #endregion #region Pre-process double x1 = 0; double y1 = 0; double x2 = 0; double y2 = 0; if (isForward) { x1 = paint.StartX; y1 = paint.StartY; x2 = paint.EndX; y2 = paint.EndY; } else { x1 = paint.EndX; y1 = paint.StartY; x2 = paint.StartX; y2 = paint.EndY; } double widthOfPaint = x2 - x1; double heightOfPaint = y2 - y1; //note: start and end point is random // start not always on top-left // so width of paint and height of paint may be negative if (widthOfPaint == 0) { // this will change to vertical OnFillingVerticalNonZero(paint, opacity, rows, startRowIndex, endRowIndex); return; } else if (heightOfPaint == 0) { // this will change to horizontal OnFillingHorizontalNonZero(paint, opacity, rows, startRowIndex, endRowIndex); return; } #endregion #region calculate the increasement double x3 = x1 - heightOfPaint; double y3 = y1 + widthOfPaint; double lengthOfPaint = Math.Sqrt((widthOfPaint * widthOfPaint) + (heightOfPaint * heightOfPaint)); //int distanceOfPaintScaled = (int)(distanceOfPaint * DistanceScale); double incrementColorIndex = (double)(widthOfPaint * ColorIndexScale) / (lengthOfPaint * lengthOfPaint); // increment by distance scale // increment may be greater than 512, but in reflect,repeat mode, // just modulo it // get the remain when divide by 512 // incrementColorIndex = incrementColorIndex - (((int)incrementColorIndex / ColorIndexDoubleScale) * ColorIndexDoubleScale); //incrementX < 512, calculate incrementIndex // ( that scale by 256 for approxiate calculation ) int scaledIncrementColorIndex = (int)(incrementColorIndex * IncrementColorIndexScale); #endregion // now not need to check null or not uint[] builtColors = paint.GetLinearColors(opacity); #region private variable for filling int currentCoverage, scLastCoverage, scLastX = 0; int tempCover = 0; int currentArea = 0; int lastXPosition = 0; int startXPosition = 0; byte calculatedCoverage = 0; // this color index is scaled int currentColorIndexScaled = 0; CellData currentCellData = null; uint colorData = 0; uint dst, dstRB, dstG; double firstPointDistance = 0; #endregion #region optimization for color index // the ORIGIN fomula for each row, we need to calculate this //firstPointDistance = (((x3) * (y3 - y1) - (startRowIndex - y3) * (x3 - x1)) / distanceOfPaint); //// color index = (distance from point to line => scaled) * 256/ (distance of paint scaled) //currentColorIndexScaled = // (int)((firstPointDistance * ColorIndexIncludeIncrementScale / distanceOfPaint)); // currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; // mod ( 512 << 8) // now we need calculate for first time only and after a row, we need to add and small value //firstPointDistance is x value when line cut the horizontal at position startRowIndex //firstPointDistance = (((x3) * (y3 - y1) - (startRowIndex - y3) * (x3 - x1)) /(lengthOfPaint)); // y = slope * x + beta //=> slope * x - y + beta = 0 double slope = (y3 - y1) / (x3 - x1); double beta = (y3 - slope * x3); // fomula to calculate distance from point to line a*x + b*y + c= 0 // is d = (a*x1 + b*y1 + c) / sqrt(a*a + b*b) // in this case d = (slope * x1 + (-1) * y1 + beta) / sqrt ( slope * slope + (-1) * (-1)) //firstPointDistance = (-startRowIndex + beta) / Math.Sqrt(slope * slope + 1); //http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html firstPointDistance = ((x3 - x1) * (y1 - startRowIndex) - (x1 - 0) * (y3 - y1)) / lengthOfPaint; int startOfRowIndex = (int)((firstPointDistance * ColorIndexIncludeIncrementScale / lengthOfPaint)); int rowColorIndexIncrementScaled = (int)(((-(x3 - x1) / lengthOfPaint) * ColorIndexIncludeIncrementScale / lengthOfPaint)); #endregion #region FILLING if (paint.Ramp.NoBlendingColor) { if (paint.Style != GradientStyle.Pad) { #region GradientStyle.Reflect || GradientStyle.Repeat // in case reflect and repeat, we don't care value that out of range startOfRowIndex &= ColorIndexIncludeIncrementDoubleMask; rowColorIndexIncrementScaled &= ColorIndexIncludeIncrementDoubleMask; scaledIncrementColorIndex &= ColorIndexIncludeIncrementDoubleMask; #region filling without blend for horizontal lines // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { // calculate the first cell color index #region second way to implement color index currentColorIndexScaled = startOfRowIndex; #endregion #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value if (scLastCoverage >= 254) { while (startXPosition < lastXPosition) { BufferData[startXPosition] = builtColors[currentColorIndexScaled < 0 ? (currentColorIndexScaled >> IncrementColorIndexShift) + 512 : (currentColorIndexScaled >> IncrementColorIndexShift)]; startXPosition++; // increase current color index currentColorIndexScaled += scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } else { calculatedCoverage = (byte)scLastCoverage; while (startXPosition < lastXPosition) { dst = BufferData[startXPosition]; colorData = builtColors[currentColorIndexScaled < 0 ? (currentColorIndexScaled >> IncrementColorIndexShift) + 512 : (currentColorIndexScaled >> IncrementColorIndexShift)]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); startXPosition++; // increase the current color index currentColorIndexScaled += scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } #endregion } else { // not filling but must set and increase the color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion // get current color data #region blend pixel //tempCover = (int)((tempCover * colorAlpha) >> 8); ////if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here dst = BufferData[startXPosition]; colorData = builtColors[currentColorIndexScaled < 0 ? (currentColorIndexScaled >> IncrementColorIndexShift) + 512 : (currentColorIndexScaled >> IncrementColorIndexShift)]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion #endregion } #endregion // alway increment color index currentColorIndexScaled += scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; // assign value for next loop scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } #region each row we need increase the value of color index startOfRowIndex += rowColorIndexIncrementScaled; startOfRowIndex &= ColorIndexIncludeIncrementDoubleMask; #endregion } #endregion #endregion }//Reflect or Repeat mode else {//Pad mode #region GradientStyle.Pad // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { // calculate the first cell color index #region second way to implement color index currentColorIndexScaled = startOfRowIndex; #endregion #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value if (scLastCoverage >= 254) { while (startXPosition < lastXPosition) { BufferData[startXPosition] = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : (currentColorIndexScaled >> IncrementColorIndexShift))]; startXPosition++; // increase current color index currentColorIndexScaled += scaledIncrementColorIndex; } } else { calculatedCoverage = (byte)scLastCoverage; while (startXPosition < lastXPosition) { colorData = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : (currentColorIndexScaled >> IncrementColorIndexShift))]; #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion startXPosition++; // increase the current color index currentColorIndexScaled += scaledIncrementColorIndex; } } #endregion } else { // not filling but must set and increase the color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * scaledIncrementColorIndex; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion // get current color data #region blend pixel calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here dst = BufferData[startXPosition]; colorData = builtColors[ currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : (currentColorIndexScaled >> IncrementColorIndexShift))]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion #endregion } #endregion // alway increment color index currentColorIndexScaled += scaledIncrementColorIndex; // assign value for next loop scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } #region each row we need increase the value of color index startOfRowIndex += rowColorIndexIncrementScaled; #endregion } #endregion }//Pad mode }//paint.Ramp.NoBlendingColor else {//has blending color // blending include alpha of built color if (paint.Style != GradientStyle.Pad) { #region GradientStyle.Reflect || GradientStyle.Repeat // in case reflect and repeat, we don't care value that out of range startOfRowIndex &= ColorIndexIncludeIncrementDoubleMask; rowColorIndexIncrementScaled &= ColorIndexIncludeIncrementDoubleMask; // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup #region filling without blend for horizontal lines startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { // calculate the first cell color index #region second way to implement color index currentColorIndexScaled = startOfRowIndex; #endregion #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; while (startXPosition < lastXPosition) { colorData = builtColors[currentColorIndexScaled < 0 ? (currentColorIndexScaled >> IncrementColorIndexShift) + 512 : (currentColorIndexScaled >> IncrementColorIndexShift)]; // get current color index value calculatedCoverage = (byte)(((colorData >> 24) * scLastCoverage) >> 8); #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); startXPosition++; #endregion // increase the current color index currentColorIndexScaled += scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } #endregion } else { // not filling but must set and increase the color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion // get current color data #region blend pixel //tempCover = (int)((tempCover * colorAlpha) >> 8); ////if (tempCover > 255) tempCover = 255; //calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here colorData = builtColors[currentColorIndexScaled < 0 ? (currentColorIndexScaled >> IncrementColorIndexShift) + 512 : (currentColorIndexScaled >> IncrementColorIndexShift)]; calculatedCoverage = (byte)(((colorData >> 24) * tempCover) >> 8); dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion #endregion } #endregion // alway increment color index currentColorIndexScaled += scaledIncrementColorIndex; currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; // assign value for next loop scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } #region each row we need increase the value of color index startOfRowIndex += rowColorIndexIncrementScaled; startOfRowIndex &= ColorIndexIncludeIncrementDoubleMask; #endregion } #endregion #endregion }//Reflect or Repeat mode else {//Pad mode #region GradientStyle.Pad // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { // calculate the first cell color index #region second way to implement color index currentColorIndexScaled = startOfRowIndex; #endregion #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1)) { if (scLastCoverage != 0) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value while (startXPosition < lastXPosition) { colorData = builtColors[currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : (currentColorIndexScaled >> IncrementColorIndexShift))]; calculatedCoverage = (byte)(((colorData >> 24) * scLastCoverage) >> 8); #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion startXPosition++; // increase the current color index currentColorIndexScaled += scaledIncrementColorIndex; //currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } #endregion } else { // not filling but must set and increase the color index currentColorIndexScaled += (currentCellData.X - scLastX - 1) * scaledIncrementColorIndex; //currentColorIndexScaled &= ColorIndexIncludeIncrementDoubleMask; } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion // get current color data #region blend pixel //calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here colorData = builtColors[currentColorIndexScaled < 0 ? 0 : (currentColorIndexScaled > ColorIndexIncludeIncrementScale ? 255 : (currentColorIndexScaled >> IncrementColorIndexShift))]; calculatedCoverage = (byte)(((colorData >> 24) * tempCover) >> 8); dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x0000FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)((((((colorData & 0x00FF00FF) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion #endregion } #endregion // alway increment color index currentColorIndexScaled += scaledIncrementColorIndex; // assign value for next loop scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } #region each row we need increase the value of color index startOfRowIndex += rowColorIndexIncrementScaled; #endregion } #endregion }//Pad mode }//has blending color #endregion }
/// <summary> /// Fill to buffer base rows data information using non-zero rule /// </summary> /// <param name="paint">linear gradient object</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> void OnFillingHorizontalNonZero( LinearGradient paint, uint opacity, RowData[] rows, int startRowIndex, int endRowIndex) { // now not need to check null or not uint[] builtColors = paint.GetLinearColors(opacity); /* Base on startX, endX, we need build fixedColor array * contain width-count elements. So that, at a column, * we can lookup color for that column. */ #region Build fixed color double startX = paint.StartX; double endX = paint.EndX; // width of this int width = CurrentEndXIndex - CurrentStartXIndex + 1; uint[] fixedColor = new uint[width]; int distanceScaled = (int)(Math.Abs(startX - endX) * DistanceScale); if (distanceScaled == 0) { FillingException.Publish(typeof(LinearGradient), "Start point and end point are too close"); return; } #region build fixed-color array if (paint.Style == GradientStyle.Pad) { #region GradientStyle.Pad int startXScaled = (int)(startX * DistanceScale); int startFixedIndex = ((( (((width + CurrentStartXIndex) << DistanceShift) - startXScaled) << ColorIndexShift) / distanceScaled)) << IncrementColorIndexShift; int colorIncrement = (DistanceScale * ColorIndexIncludeIncrementScale) / distanceScaled; if (endX < startX) { colorIncrement = -colorIncrement; startFixedIndex = -startFixedIndex; } while (width-- > 0) { fixedColor[width] = builtColors[ startFixedIndex < 0 ? 0 : (startFixedIndex > ColorIndexIncludeIncrementScale ? 255 : (startFixedIndex >> IncrementColorIndexShift))]; startFixedIndex -= colorIncrement; } #endregion } else { #region GradientStyle.Repeat || GradientStyle.Reflect int startXScaled = (int)(startX * DistanceScale); int startFixedIndex = ((( (((width + CurrentStartXIndex) << DistanceShift) - startXScaled) << ColorIndexShift) / distanceScaled)) << IncrementColorIndexShift; int colorIncrement = (DistanceScale * ColorIndexIncludeIncrementScale) / distanceScaled; if (endX < startX) { colorIncrement = -colorIncrement; } startFixedIndex &= ColorIndexIncludeIncrementDoubleMask; while (width-- > 0) { fixedColor[width] = builtColors[ startFixedIndex < 0 ? (startFixedIndex >> IncrementColorIndexShift) + 512 : (startFixedIndex >> IncrementColorIndexShift)]; startFixedIndex -= colorIncrement; startFixedIndex &= ColorIndexIncludeIncrementDoubleMask; } #endregion } #endregion #endregion #region private variable for filling int currentCoverage, scLastCoverage, scLastX = 0; int tempCover = 0; int currentArea = 0; int lastXPosition = 0; int startXPosition = 0; byte calculatedCoverage = 0; int currentColorIndexValue = 0; CellData currentCellData = null; uint colorData = 0; uint dst, dstRB, dstG; #endregion #region FILLING if (paint.Ramp.NoBlendingColor) { #region filling without blend for horizontal lines // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1) && (scLastCoverage != 0)) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion if (scLastCoverage != 0) { #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value currentColorIndexValue = scLastX + 1 - CurrentStartXIndex; if (scLastCoverage >= 255) { while (startXPosition < lastXPosition) { BufferData[startXPosition++] = fixedColor[currentColorIndexValue++]; } } else { while (startXPosition < lastXPosition) { colorData = fixedColor[currentColorIndexValue]; calculatedCoverage = (byte)((colorData >> 24)); calculatedCoverage = (byte)((scLastCoverage * calculatedCoverage) >> 8); if (calculatedCoverage >= 255) { BufferData[startXPosition] = colorData; } else { #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x00FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((((colorData & 0x00FF00FF)) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion } startXPosition++; currentColorIndexValue++; } } #endregion } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion // get current color data colorData = fixedColor[currentCellData.X - CurrentStartXIndex]; calculatedCoverage = (byte)(colorData >> 24); #region blend pixel tempCover = (int)((tempCover * calculatedCoverage) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x00FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((((colorData & 0x00FF00FF)) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion #endregion } #endregion scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } #endregion }//paint.Ramp.NoBlendingColor else {//has blending color #region perform normal filling startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1) && (scLastCoverage != 0)) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region non-zero checking code if (scLastCoverage > 255) scLastCoverage = 255; #endregion if (scLastCoverage != 0) { #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value currentColorIndexValue = scLastX + 1 - CurrentStartXIndex; while (startXPosition < lastXPosition) { colorData = fixedColor[currentColorIndexValue]; calculatedCoverage = (byte)(colorData >> 24); calculatedCoverage = (byte)((scLastCoverage * calculatedCoverage) >> 8); if (calculatedCoverage >= 255) { BufferData[startXPosition] = colorData; } else { #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x00FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((((colorData & 0x00FF00FF)) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion } startXPosition++; currentColorIndexValue++; } #endregion } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region non-zero checking code if (tempCover > 255) tempCover = 255; #endregion // get current color data colorData = fixedColor[currentCellData.X - CurrentStartXIndex]; calculatedCoverage = (byte)(colorData >> 24); #region blend pixel tempCover = (int)((tempCover * calculatedCoverage) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((((colorData & 0x00FF00) >> 8) - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((((colorData & 0x00FF00FF)) - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion #endregion } #endregion scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } #endregion }//has blending color #endregion }
/// <summary> /// Fill to buffer base rows data information using non-zero rule /// </summary> /// <param name="paint">linear gradient object</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> void OnFillingVerticalEvenOdd( LinearGradient paint, uint opacity, RowData[] rows, int startRowIndex, int endRowIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue) { // now not need to check null or not uint[] builtColors = paint.GetLinearColors(opacity); /*Base on startX,endX, we need build fixedColor array * contain width count elements. So that, at a column, we * can lookup color for that column. */ #region build fixed color double startY = paint.StartY; double endY = paint.EndY; // width of this int height = endRowIndex - startRowIndex + 1; uint[] fixedColor = new uint[height]; int distanceScaled = (int)(Math.Abs(startY - endY) * DistanceScale); if (distanceScaled == 0) { FillingException.Publish(typeof(LinearGradient), "Start point and end point are too close"); return; } #region building fixed color array if (paint.Style == GradientStyle.Pad) { #region GradientStyle.Pad int startFixedIndex = ((( (((height + startRowIndex) << DistanceShift) - (int)(startY * DistanceScale)) << ColorIndexShift) / distanceScaled)) << IncrementColorIndexShift; int colorIncrement = (DistanceScale * ColorIndexIncludeIncrementScale) / distanceScaled; if (endY < startY) { colorIncrement = -colorIncrement; startFixedIndex = -startFixedIndex; } while (height-- > 0) { fixedColor[height] = builtColors[startFixedIndex < 0 ? 0 : (startFixedIndex > ColorIndexIncludeIncrementScale ? 255 : (startFixedIndex >> IncrementColorIndexShift))]; startFixedIndex -= colorIncrement; } #endregion } else { #region GradientStyle.Repeat || GradientStyle.Reflect int startFixedIndex = ((( (((height + startRowIndex) << DistanceShift) - (int)(startY * DistanceScale)) << ColorIndexShift) / distanceScaled)) << IncrementColorIndexShift; int colorIncrement = (DistanceScale * ColorIndexIncludeIncrementScale) / distanceScaled; if (endY < startY) { colorIncrement = -colorIncrement; } startFixedIndex &= ColorIndexIncludeIncrementDoubleMask; while (height-- > 0) { fixedColor[height] = builtColors[ startFixedIndex < 0 ? (startFixedIndex >> IncrementColorIndexShift) + 512 : (startFixedIndex >> IncrementColorIndexShift)]; startFixedIndex -= colorIncrement; startFixedIndex &= ColorIndexIncludeIncrementDoubleMask; } #endregion } #endregion #endregion #region private variable for filling int currentCoverage, scLastCoverage, scLastX = 0; int tempCover = 0; int currentArea = 0; int lastXPosition = 0; int startXPosition = 0; byte calculatedCoverage = 0; int currentColorIndexValue = 0; CellData currentCellData = null; uint colorData = 0; uint colorAlpha = 0; uint colorG = 0; uint colorRB = 0; uint dst, dstRB, dstG; #endregion #region FILLING if (paint.Ramp.NoBlendingColor) { // when no need to blending, when draw a horizontal line // do not need check the back color, alway setup #region filling without blend for horizontal lines startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { #region calculate and get current color colorData = fixedColor[currentColorIndexValue]; colorAlpha = (colorData >> 24); colorG = (colorData & 0x0000FF00) >> 8; colorRB = (colorData & 0x00FF00FF); #endregion // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1) && (scLastCoverage != 0)) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); //#region non-zero checking code //if (scLastCoverage > 255) scLastCoverage = 255; //#endregion #region even-odd change scLastCoverage &= 511; if (scLastCoverage > 256) { scLastCoverage = 512 - scLastCoverage; } #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; // get current color index value if (scLastCoverage >= 254) { while (startXPosition < lastXPosition) { BufferData[startXPosition++] = colorData; } } else { while (startXPosition < lastXPosition) { calculatedCoverage = (byte)((scLastCoverage * colorAlpha) >> 8); if (calculatedCoverage >= 254) { BufferData[startXPosition] = colorData; } else { #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = ((((colorRB - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion } startXPosition++; } } #endregion } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); //#region non-zero checking code //if (tempCover > 255) tempCover = 255; //#endregion #region even-odd change tempCover &= 511; if (tempCover > 256) { tempCover = 512 - tempCover; } #endregion // get current color data #region blend pixel tempCover = (int)((tempCover * colorAlpha) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = ((((colorRB - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion #endregion } #endregion scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } // increase color index currentColorIndexValue++; } #endregion } else { #region perform normal filling startRowIndex--; while (++startRowIndex <= endRowIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startRowIndex] != null) { #region calculate and get current color colorData = fixedColor[currentColorIndexValue]; colorAlpha = (colorData >> 24); colorG = (colorData & 0x0000FF00) >> 8; colorRB = (colorData & 0x00FF00FF); #endregion // get first cell in current row currentCellData = rows[startRowIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1) && (scLastCoverage != 0)) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region even-odd change scLastCoverage &= 511; if (scLastCoverage > 256) { scLastCoverage = 512 - scLastCoverage; } #endregion #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startRowIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; while (startXPosition < lastXPosition) { calculatedCoverage = (byte)((scLastCoverage * colorAlpha) >> 8); if (calculatedCoverage >= 254) { BufferData[startXPosition] = colorData; } else { #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = ((((colorRB - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion } startXPosition++; } #endregion } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region even-odd change tempCover &= 511; if (tempCover > 256) { tempCover = 512 - tempCover; } #endregion #region blend pixel tempCover = (int)((tempCover * colorAlpha) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startRowIndex * BufferStride + currentCellData.X; #region blend here //dst = BufferData[startXPosition]; //dstRB = dst & 0x00FF00FF; //dstG = (dst >> 8) & 0xFF; //BufferData[startXPosition] = // (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) // | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) // | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #region gamma apply dst = BufferData[startXPosition]; dstG = (dst >> 8) & 0xFF; dstRB = ((((colorRB - (dst & 0x00FF00FF)) * calculatedCoverage) >> 8) + (dst & 0x00FF00FF)); BufferData[startXPosition] = (uint)((AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (((uint)gammaLutGreen[(((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) & 0xFF)] << 8)) | ((uint)gammaLutRed[(dstRB & 0x00FF0000) >> 16] << 16) | (gammaLutBlue[(dstRB & 0x00FF)])); #endregion #endregion #endregion } #endregion scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } // increase color index currentColorIndexValue++; } #endregion } #endregion }
private static List<GradientStop> GetGradientStops(LinearGradient gradient, bool applySmallBlurFocusArea, KernelGenerator kernelGenerator, double firstStopOffset, double lastStopOffset, byte firstKernelIndex = 0) { var stops = new List<GradientStop>(); if (kernelGenerator.GetKernelBands().Count > 0) { double sumOfBandWidths = kernelGenerator.GetKernelBands().Select(band => band.Width).Sum(); var focusAreaColor = GetFocusAreaColor(applySmallBlurFocusArea); stops.Add(new GradientStop() { Color = Color.FromArgb(255, focusAreaColor, focusAreaColor, focusAreaColor), Offset = firstStopOffset }); var currentStopOffset = lastStopOffset - firstStopOffset > 0 ? firstStopOffset + minDiffBetweenStops : firstStopOffset - minDiffBetweenStops; var kernelBands = kernelGenerator.GetKernelBands(); byte kernelIndex = firstKernelIndex; foreach (var band in kernelBands) { kernelIndex++; stops.Add(new GradientStop() { Color = Color.FromArgb(255, kernelIndex, kernelIndex, kernelIndex), Offset = currentStopOffset }); currentStopOffset = currentStopOffset + (band.Width / sumOfBandWidths) * (lastStopOffset - firstStopOffset) * FocusToBlurTransitionWidth; } stops.Add(new GradientStop() { Color = Color.FromArgb(255, kernelIndex, kernelIndex, kernelIndex), Offset = currentStopOffset }); stops = EnsureMinDiffBetweenPoints(stops); } return stops; }
public static IImageProvider Generate(IImageProvider objectMaskSource, LinearGradient gradient, Size size, IReadOnlyList<ILensBlurKernel> kernels) { var backgroundSource = new GradientImageSource(size, gradient); var blendEffect = new BlendEffect(backgroundSource, objectMaskSource, BlendFunction.Lighten); return new IndexRemappingEffect(blendEffect, kernels.Count + 2); }