Exemple #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FillRegionProcessor" /> class.
 /// </summary>
 /// <param name="options">The graphics options.</param>
 /// <param name="brush">The details how to fill the region of interest.</param>
 /// <param name="region">The region of interest to be filled.</param>
 public FillRegionProcessor(ShapeGraphicsOptions options, IBrush brush, Region region)
 {
     this.Region       = region;
     this.Brush        = brush;
     this.ShapeOptions = options;
     this.Options      = (GraphicsOptions)options;
 }
        /// <summary>
        /// Creates a <see cref="FontGlyphSource"/> instance.
        /// </summary>
        public FontGlyphSource(IFontInstance fontInstance, float size, string name, char firstChar = ' ', char lastChar = '~')
        {
            if (!float.IsFinite(size) || float.IsNegative(size))
            {
                throw new ArgumentOutOfRangeException(nameof(size), size, nameof(size) + " must be finite and positive.");
            }

            if (lastChar < firstChar)
            {
                throw new ArgumentException(nameof(LastChar) + " can't be lower than " + nameof(firstChar));
            }

            FontInstance = fontInstance ?? throw new ArgumentNullException(nameof(fontInstance));

            FirstChar = firstChar;
            LastChar  = lastChar;
            Size      = size;
            Name      = name;

            glyphPaths = CreatePaths(out pathColors, out glyphSizes, out renderOffsets);

            ShapeGraphicsOptions = new ShapeGraphicsOptions
            {
                ShapeOptions = { IntersectionRule = IntersectionRule.Nonzero },
            };
        }
Exemple #3
0
        public void LargeGeoJson_Lines(TestImageProvider <Rgba32> provider, string geoJsonFile, int aa, float sx, float sy)
        {
            string jsonContent = File.ReadAllText(TestFile.GetInputFileFullPath(geoJsonFile));

            PointF[][] points = PolygonFactory.GetGeoJsonPoints(jsonContent, Matrix3x2.CreateScale(sx, sy));

            using Image <Rgba32> image = provider.GetImage();
            var options = new ShapeGraphicsOptions()
            {
                GraphicsOptions = new GraphicsOptions()
                {
                    Antialias = aa > 0, AntialiasSubpixelDepth = aa
                },
            };

            foreach (PointF[] loop in points)
            {
                image.Mutate(c => c.DrawLines(options, Color.White, 1.0f, loop));
            }

            string details = $"_{System.IO.Path.GetFileName(geoJsonFile)}_{sx}x{sy}_aa{aa}";

            image.DebugSave(
                provider,
                details,
                appendPixelTypeToFileName: false,
                appendSourceFileOrDescription: false);
        }
Exemple #4
0
        private Image <Rgba32> FillGeoJsonPolygons(TestImageProvider <Rgba32> provider, string geoJsonFile, int aa, Vector2 scale, Vector2 pixelOffset)
        {
            string jsonContent = File.ReadAllText(TestFile.GetInputFileFullPath(geoJsonFile));

            PointF[][] points = PolygonFactory.GetGeoJsonPoints(jsonContent, Matrix3x2.CreateScale(scale) * Matrix3x2.CreateTranslation(pixelOffset));

            Image <Rgba32> image   = provider.GetImage();
            var            options = new ShapeGraphicsOptions()
            {
                GraphicsOptions = new GraphicsOptions()
                {
                    Antialias = aa > 0, AntialiasSubpixelDepth = aa
                },
            };
            var rnd = new Random(42);

            byte[] rgb = new byte[3];
            foreach (PointF[] loop in points)
            {
                rnd.NextBytes(rgb);

                var color = Color.FromRgb(rgb[0], rgb[1], rgb[2]);
                image.Mutate(c => c.FillPolygon(options, color, loop));
            }

            return(image);
        }
Exemple #5
0
 public static void DrawLine(Image tex, int x0, int y0, int x1, int y1, Color col, int thickness)
 {
     tex.Mutate(ctx =>
     {
         var options = new ShapeGraphicsOptions();
         ctx.DrawLines(options, col, thickness, new PointF(x0, y0), new PointF(x1, y1));
     });
 }
Exemple #6
0
        public void DrawTextCoreOld()
        {
            using (var image = new Image <Rgba32>(800, 800))
            {
                Fonts.Font font = Fonts.SystemFonts.CreateFont("Arial", 12);
                image.Mutate(x => DrawTextOldVersion(
                                 x,
                                 new TextGraphicsOptions {
                    GraphicsOptions = { Antialias = true }, TextOptions = { WrapTextWidth = 780 }
                },
                                 this.TextToRender,
                                 font,
                                 Processing.Brushes.Solid(Color.HotPink),
                                 null,
                                 new PointF(10, 10)));
            }

            IImageProcessingContext DrawTextOldVersion(
                IImageProcessingContext source,
                TextGraphicsOptions options,
                string text,
                Fonts.Font font,
                IBrush brush,
                IPen pen,
                PointF location)
            {
                const float dpiX = 72;
                const float dpiY = 72;

                var style = new Fonts.RendererOptions(font, dpiX, dpiY, location)
                {
                    ApplyKerning        = options.TextOptions.ApplyKerning,
                    TabWidth            = options.TextOptions.TabWidth,
                    WrappingWidth       = options.TextOptions.WrapTextWidth,
                    HorizontalAlignment = options.TextOptions.HorizontalAlignment,
                    VerticalAlignment   = options.TextOptions.VerticalAlignment
                };

                IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, style);

                var pathOptions = new ShapeGraphicsOptions()
                {
                    GraphicsOptions = options.GraphicsOptions
                };

                if (brush != null)
                {
                    source.Fill(pathOptions, brush, glyphs);
                }

                if (pen != null)
                {
                    source.Draw(pathOptions, pen, glyphs);
                }

                return(source);
            }
        }
Exemple #7
0
        /// <inheritdoc />
        public System.IO.Stream FillPolygon(System.IO.Stream sourceImageStream, string polygonColorCode, Polygon polygon)
        {
            #region validation

            if (sourceImageStream == null)
            {
                throw new ArgumentNullException(nameof(sourceImageStream));
            }

            if (string.IsNullOrEmpty(polygonColorCode))
            {
                throw new ArgumentNullException(nameof(polygonColorCode));
            }

            Regex regex = HexColorUtil.GetHexColorRegex();
            if (!regex.IsMatch(polygonColorCode))
            {
                throw new ArgumentException($"Color code {polygonColorCode } is malformed!");
            }

            if (polygon == null)
            {
                throw new ArgumentNullException(nameof(polygon));
            }

            if (polygon.Points == null)
            {
                throw new ArgumentException(nameof(polygon.Points));
            }

            if (polygon.Points.Count() < 2)
            {
                throw new ArgumentException($"Polygon {nameof(polygon)} has to contain more than one entry!");
            }

            #endregion

            IBrush brush = new SolidBrush(Rgba32Util.InitFromHex(polygonColorCode));

            ShapeGraphicsOptions graphicsOptions = new ShapeGraphicsOptions()
            {
                GraphicsOptions = new GraphicsOptions()
                {
                    ColorBlendingMode = PixelColorBlendingMode.Normal
                }
            };

            using (Image <Rgba32> originalImage = LoadImageFromStream <Rgba32>(sourceImageStream, out IImageFormat imageFormat))
            {
                originalImage.Mutate(c => c.FillPolygon(graphicsOptions, brush, polygon.Points.Select(p => new PointF(p.X, p.Y)).ToArray()));

                return(SaveAsStream(originalImage, imageFormat));
            }
        }
        public void Brush()
        {
            this.operations.Clear(this.nonDefaultOptions, this.brush, this.path);

            FillPathProcessor processor = this.Verify <FillPathProcessor>();

            ShapeGraphicsOptions expectedOptions = this.nonDefaultOptions;

            Assert.Equal(expectedOptions.ShapeOptions, processor.Options.ShapeOptions);
            Assert.Equal(1, processor.Options.GraphicsOptions.BlendPercentage);
            Assert.Equal(PixelFormats.PixelAlphaCompositionMode.Src, processor.Options.GraphicsOptions.AlphaCompositionMode);
            Assert.Equal(PixelFormats.PixelColorBlendingMode.Normal, processor.Options.GraphicsOptions.ColorBlendingMode);

            Assert.Equal(this.path, processor.Shape);
            Assert.Equal(this.brush, processor.Brush);
        }
        private void RenderShapeToCanvas(SvgGraphicsElement svgGraphicsElement, IPath path)
        {
            var matrix = CalulateUpdatedMatrix(svgGraphicsElement);

            var brush = svgGraphicsElement.CreateFillPaintServer()?.Accept(BrushGenerator <TPixel> .Instance);

            IBrush strokFill = null;
            IPath  outline   = null;

            if (svgGraphicsElement.StrokeWidth > 0)
            {
                strokFill = svgGraphicsElement.CreateStrokePaintServer()?.Accept(BrushGenerator <TPixel> .Instance);
                if (strokFill != null)
                {
                    var pattern = svgGraphicsElement.Style.StrokeDashArray.Value?.Select(X => X.Value).ToArray();
                    var joint   = svgGraphicsElement.Style.StrokeLineJoin.AsJointStyle();
                    var end     = svgGraphicsElement.Style.StrokeLineCap.AsEndCapStyle();
                    if (pattern == null || pattern.Length == 0)
                    {
                        outline = path.GenerateOutline(svgGraphicsElement.StrokeWidth, joint, end);
                    }
                    else
                    {
                        outline = path.GenerateOutline(svgGraphicsElement.StrokeWidth,
                                                       pattern,
                                                       false,
                                                       joint, end);
                    }
                }
            }

            var shapeOptions = new ShapeOptions {
                IntersectionRule = IntersectionRule.Nonzero
            };
            var shapeGraphicsOptions = new ShapeGraphicsOptions(new GraphicsOptions(), shapeOptions);

            if (brush != null)
            {
                image.Fill(shapeGraphicsOptions, brush, path.Transform(matrix));
            }

            if (outline != null && strokFill != null)
            {
                image.Fill(shapeGraphicsOptions, strokFill, outline.Transform(matrix));
            }
        }
Exemple #10
0
        protected override Task <byte[]> RenderGlyphs(IPathCollection glyphs, Int32 squareSize, Rgba32 foregroundColor, Rgba32 backgroundColor, CancellationToken cancellationToken)
        {
            using (var img = new Image <Rgba32>(squareSize, squareSize)) {
                var graphicsOptions = new ShapeGraphicsOptions();
                var brush           = new SolidBrush(foregroundColor);

                img.Mutate(ctx => ctx
                           .Fill(backgroundColor)
                           .Fill(graphicsOptions, brush, glyphs));

                using (var ms = new MemoryStream()) {
                    img.SaveAsPng(ms);
                    ms.Seek(0, SeekOrigin.Begin);
                    return(Task.FromResult(ms.ToArray()));
                }
            }
        }
Exemple #11
0
        public void ColorSet()
        {
            this.operations.Clear(this.nonDefaultOptions, Color.Red, this.path);

            FillRegionProcessor processor = this.Verify <FillRegionProcessor>();

            ShapeGraphicsOptions expectedOptions = this.nonDefaultOptions;

            Assert.Equal(expectedOptions.ShapeOptions, processor.Options.ShapeOptions);

            Assert.Equal(1, processor.Options.GraphicsOptions.BlendPercentage);
            Assert.Equal(PixelFormats.PixelAlphaCompositionMode.Src, processor.Options.GraphicsOptions.AlphaCompositionMode);
            Assert.Equal(PixelFormats.PixelColorBlendingMode.Normal, processor.Options.GraphicsOptions.ColorBlendingMode);
            Assert.Equal(this.path, processor.Region);
            Assert.NotEqual(this.brush, processor.Brush);
            SolidBrush brush = Assert.IsType <SolidBrush>(processor.Brush);

            Assert.Equal(Color.Red, brush.Color);
        }
Exemple #12
0
        public void RectangleHasMissingBottomRightCorner()
        {
            var testImage = new Image <Rgb24>(Configuration.Default, 100, 100, Color.Black);

            var rectangle = new RectangleF(10.5f, 10.5f, 79, 79);
            var pen       = new Pen(Color.Red, 1f);

            var options = new ShapeGraphicsOptions()
            {
                BlendPercentage        = 1,
                Antialias              = false,
                ColorBlendingMode      = PixelColorBlendingMode.Normal,
                AntialiasSubpixelDepth = 0,
            };

            testImage.Mutate(x => x.Draw(pen, rectangle));

            testImage.Save(this.TestOutputDirectory.CombinePath("rectangle.png"));

            // expected
            //      88 | 89 | 90
            // 88 | B  | R  | B
            // 89 | R  | R  | B
            // 90 | B  | B  | B

            // smoke test: when this test fails, bug in ImageSharp has been fixed
            // should be black
            Assert.AreEqual(
                Color.Black.ToPixel <Rgb24>(),
                testImage[88, 88]);

            // should be red (bug is that it is blended)
            Assert.AreEqual(
                new Rgb24(249, 0, 0),
                testImage[89, 89]);

            // should be black
            Assert.AreEqual(
                Color.Black.ToPixel <Rgb24>(),
                testImage[90, 90]);
        }
Exemple #13
0
        private Visualizer()
        {
            var fontDir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts);

            var dir       = new DirectoryInfo(fontDir);
            var arialFile = dir.EnumerateFiles("arial.ttf").First();

            var fonts = new FontCollection();
            var arial = fonts.Install(arialFile.FullName);

            shapeGraphicsOptions = new ShapeGraphicsOptions();
            foregroundBrush      = new SolidBrush(Color.Black);
            edgeThickness        = 1;
            font = arial.CreateFont(12);

            nodeHeight       = 24;
            nodeSegmentWidth = 50;
            layerHeight      = nodeHeight * 3;

            pageMargin = 12;

            drawables = new List <Drawable>();
        }
            static IImageProcessingContext DrawTextOldVersion(
                IImageProcessingContext source,
                TextGraphicsOptions options,
                string text,
                Fonts.Font font,
                IBrush brush,
                IPen pen,
                PointF location)
            {
                var style = new Fonts.RendererOptions(font, options.TextOptions.DpiX, options.TextOptions.DpiY, location)
                {
                    ApplyKerning        = options.TextOptions.ApplyKerning,
                    TabWidth            = options.TextOptions.TabWidth,
                    WrappingWidth       = options.TextOptions.WrapTextWidth,
                    HorizontalAlignment = options.TextOptions.HorizontalAlignment,
                    VerticalAlignment   = options.TextOptions.VerticalAlignment
                };

                IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, style);

                var pathOptions = new ShapeGraphicsOptions()
                {
                    GraphicsOptions = options.GraphicsOptions
                };

                if (brush != null)
                {
                    source.Fill(pathOptions, brush, glyphs);
                }

                if (pen != null)
                {
                    source.Draw(pathOptions, pen, glyphs);
                }

                return(source);
            }
Exemple #15
0
 public RecursiveImageProcessor(ShapeGraphicsOptions options, IPath path, Action <IImageProcessingContext> innerProcessing)
 {
     this.Options = options;
     this.Path    = path;
     this.InnerProcessingOperations = innerProcessing;
 }
Exemple #16
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FillPathProcessor" /> class.
 /// </summary>
 /// <param name="options">The graphics options.</param>
 /// <param name="brush">The details how to fill the region of interest.</param>
 /// <param name="shape">The shape to be filled.</param>
 public FillPathProcessor(ShapeGraphicsOptions options, IBrush brush, IPath shape)
 {
     this.Shape   = shape;
     this.Brush   = brush;
     this.Options = options;
 }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source)
        {
            Configuration        configuration = this.Configuration;
            GraphicsOptions      options       = this.definition.Options;
            ShapeGraphicsOptions shapeOptions  = this.definition.ShapeOptions;
            IBrush    brush  = this.definition.Brush;
            Region    region = this.definition.Region;
            Rectangle rect   = region.Bounds;

            // Align start/end positions.
            int minX = Math.Max(0, rect.Left);
            int maxX = Math.Min(source.Width, rect.Right);
            int minY = Math.Max(0, rect.Top);
            int maxY = Math.Min(source.Height, rect.Bottom);

            if (minX >= maxX)
            {
                return; // no effect inside image;
            }

            if (minY >= maxY)
            {
                return; // no effect inside image;
            }

            int   maxIntersections = region.MaxIntersections;
            float subpixelCount    = 4;

            // we need to offset the pixel grid to account for when we outline a path.
            // basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
            // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
            // region to align with the pixel grid.
            float offset = 0.5f;

            if (options.Antialias)
            {
                offset        = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset.
                subpixelCount = options.AntialiasSubpixelDepth;
                if (subpixelCount < 4)
                {
                    subpixelCount = 4;
                }
            }

            using (BrushApplicator <TPixel> applicator = brush.CreateApplicator(configuration, options, source, rect))
            {
                int             scanlineWidth = maxX - minX;
                MemoryAllocator allocator     = this.Configuration.MemoryAllocator;
                using (IMemoryOwner <float> bBuffer = allocator.Allocate <float>(maxIntersections))
                    using (IMemoryOwner <float> bScanline = allocator.Allocate <float>(scanlineWidth))
                    {
                        bool  scanlineDirty         = true;
                        float subpixelFraction      = 1f / subpixelCount;
                        float subpixelFractionPoint = subpixelFraction / subpixelCount;

                        Span <float> buffer   = bBuffer.Memory.Span;
                        Span <float> scanline = bScanline.Memory.Span;

                        bool   isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush);
                        TPixel solidBrushColor             = isSolidBrushWithoutBlending ? solidBrush.Color.ToPixel <TPixel>() : default;

                        for (int y = minY; y < maxY; y++)
                        {
                            if (scanlineDirty)
                            {
                                scanline.Clear();
                                scanlineDirty = false;
                            }

                            float yPlusOne = y + 1;
                            for (float subPixel = y; subPixel < yPlusOne; subPixel += subpixelFraction)
                            {
                                int pointsFound = region.Scan(subPixel + offset, buffer, configuration, shapeOptions.IntersectionRule);
                                if (pointsFound == 0)
                                {
                                    // nothing on this line, skip
                                    continue;
                                }

                                for (int point = 0; point < pointsFound && point < buffer.Length - 1; point += 2)
                                {
                                    // points will be paired up
                                    float scanStart = buffer[point] - minX;
                                    float scanEnd   = buffer[point + 1] - minX;
                                    int   startX    = (int)MathF.Floor(scanStart + offset);
                                    int   endX      = (int)MathF.Floor(scanEnd + offset);

                                    if (startX >= 0 && startX < scanline.Length)
                                    {
                                        for (float x = scanStart; x < startX + 1; x += subpixelFraction)
                                        {
                                            scanline[startX] += subpixelFractionPoint;
                                            scanlineDirty     = true;
                                        }
                                    }

                                    if (endX >= 0 && endX < scanline.Length)
                                    {
                                        for (float x = endX; x < scanEnd; x += subpixelFraction)
                                        {
                                            scanline[endX] += subpixelFractionPoint;
                                            scanlineDirty   = true;
                                        }
                                    }

                                    int nextX = startX + 1;
                                    endX  = Math.Min(endX, scanline.Length); // reduce to end to the right edge
                                    nextX = Math.Max(nextX, 0);
                                    for (int x = nextX; x < endX; x++)
                                    {
                                        scanline[x]  += subpixelFraction;
                                        scanlineDirty = true;
                                    }
                                }
                            }

                            if (scanlineDirty)
                            {
                                if (!options.Antialias)
                                {
                                    bool hasOnes  = false;
                                    bool hasZeros = false;
                                    for (int x = 0; x < scanlineWidth; x++)
                                    {
                                        if (scanline[x] >= 0.5)
                                        {
                                            scanline[x] = 1;
                                            hasOnes     = true;
                                        }
                                        else
                                        {
                                            scanline[x] = 0;
                                            hasZeros    = true;
                                        }
                                    }

                                    if (isSolidBrushWithoutBlending && hasOnes != hasZeros)
                                    {
                                        if (hasOnes)
                                        {
                                            source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrushColor);
                                        }

                                        continue;
                                    }
                                }

                                applicator.Apply(scanline, minX, y);
                            }
                        }
                    }
            }
        }
Exemple #18
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DrawPathProcessor" /> class.
 /// </summary>
 /// <param name="options">The graphics options.</param>
 /// <param name="pen">The details how to outline the region of interest.</param>
 /// <param name="shape">The shape to be filled.</param>
 public DrawPathProcessor(ShapeGraphicsOptions options, IPen pen, IPath shape)
 {
     this.Shape   = shape;
     this.Pen     = pen;
     this.Options = options;
 }