Search code examples
c#wpfimagegeometrygeometrydrawing

How to save Geometry as image?


How to save Geometry as image?

For example i have List<Geometry>.

I want it to be as follows:

for (int i = 0; i < GeometryList.Count; i++)
{
       Pen TestPen = new Pen(Brushes.Black, 1);
       GeometryDrawing TestDrawing = new GeometryDrawing(Brushes.Black, TestPen, TestGeometry);

       Bitmap b = TestDrawing as Bitmap;

       b.Save(System.AppDomain.CurrentDomain.BaseDirectory + i + ".png", ImageFormat.Png);
}

Update:

The code I wrote a few hours ago:

    private void CreateFontMap(string PathTofont)
    {

        GlyphTypeface font = new GlyphTypeface(new Uri(PathTofont));


        List<ushort> fontNum = new List<ushort>();

        foreach (KeyValuePair<int, ushort> kvp in font.CharacterToGlyphMap)
        {
            fontNum.Add(kvp.Value);
        }

        if (fontNum.Count > 0)
        {
            int mapWidth = 50 * 20;
            int mapHeight = 50 * (getRowNum(fontNum.Count + 1) + 1);

            Bitmap b = new Bitmap(mapWidth, mapHeight);
            Graphics g = Graphics.FromImage(b);

            System.Windows.Media.Pen glyphPen = new System.Windows.Media.Pen(System.Windows.Media.Brushes.Red, 1);
            Geometry glyphGeometry;

            for (int i = 0; i < fontNum.Count; i++)
            {                    
                glyphGeometry = font.GetGlyphOutline(fontNum[i], 50, 1);

                RenderTargetBitmap bmp = new RenderTargetBitmap(50, 50, 96, 96, PixelFormats.Pbgra32);

                DrawingVisual viz = new DrawingVisual();
                DrawingContext dc = viz.RenderOpen();
                dc.DrawGeometry(System.Windows.Media.Brushes.Red, null, glyphGeometry);
                dc.Close();

                bmp.Render(viz);

                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(bmp));

                MemoryStream myStream = new MemoryStream();

                encoder.Save(myStream);

                int rowNum = (getRowNum(i));
                g.DrawImage(System.Drawing.Bitmap.FromStream(myStream), new PointF((i - rowNum * 20) * 50, rowNum * 50));
            }
            g.Dispose();
            b.Save(System.AppDomain.CurrentDomain.BaseDirectory + "map.png", ImageFormat.Png);
            b.Dispose();
        }
    }

    private int getRowNum(int p)
    {
        return p / 20;
    }

But instead of Img1, I get Img2.

Update 2: I changed this:

DrawingVisual viz = new DrawingVisual();
DrawingContext dc = viz.RenderOpen();
dc.DrawGeometry(System.Windows.Media.Brushes.Red, null, glyphGeometry);
dc.Close();

to:

DrawingVisual viz = new DrawingVisual();
DrawingContext dc = viz.RenderOpen();
dc.DrawImage(geometryImage, new Rect(0, 0, 50, 50));
dc.Close();

and added:

glyphDrawing = new GeometryDrawing(System.Windows.Media.Brushes.Black,  glyphPen, glyphGeometry);
DrawingImage geometryImage = new DrawingImage(glyphDrawing);
geometryImage.Freeze();
img1.Source = geometryImage;

And all working.


Solution

  • // Create the bitmap we'll render to
    RenderTargetBitmap bmp = 
                new RenderTargetBitmap(100, 100, // Size
                                                        96, 96, // DPI 
                                                        PixelFormats.Pbgra32);
    
    // Create a list of random circle geometries
    List<Geometry> geoList = new List<Geometry>();
    Random rand = new Random();
    for (int i=0; i<10; i++)
    {
        double radius = rand.Next(5, 10);
        Point center = new Point(rand.Next(25, 75), rand.Next(25,75));
        geoList.Add(new EllipseGeometry(center, radius, radius));
    }
    // The light-weight visual element that will draw the geometries
    DrawingVisual viz = new DrawingVisual();
    using (DrawingContext dc = viz.RenderOpen())
    { // The DC lets us draw to the DrawingVisual directly
        foreach (var g in geoList)
            dc.DrawGeometry(Brushes.Red, null, g);
    } // the DC is closed as it falls out of the using statement
    
    // draw the visual on the bitmap
    bmp.Render(viz);
    
    // instantiate an encoder to save the file
    PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
    // add this bitmap to the encoders set of frames
    pngEncoder.Frames.Add(BitmapFrame.Create(bmp));
    
    // save the bitmap as an .png file
    using (FileStream file = new FileStream("Spots.png", FileMode.Create))
        pngEncoder.Save(file);
    

    Based on your comments to the section above, it looks like you're trying to create a table of glyphs for a font and save it out to an image file. Here's how you accomplish this:

    // I'm generating the glyphs differently for testing.
    // I tested with fontName="Arial"
    Typeface face = new Typeface(fontName);
    GlyphTypeface font;
    
    if (!face.TryGetGlyphTypeface(out font))
        return; // bail if something goes wrong
    
    int ColumnCount = 10;
    int MaxDrawCount = 30; // use int.MaxValue to draw them all            
    double fontSize = 50d;
    // the height of each cell has to include over/underhanging glyphs
    Size cellSize = new Size(fontSize, fontSize * font.Height);
    
    var Glyphs = from glyphIndex in font.CharacterToGlyphMap.Values
                        select font.GetGlyphOutline(glyphIndex, fontSize, 1d);            
    
    // now create the visual we'll draw them to
    DrawingVisual viz = new DrawingVisual();
    int drawCount = -1;
    using (DrawingContext dc = viz.RenderOpen())
    {
        foreach (var g in Glyphs)
        {
            drawCount++;
            if (drawCount >= MaxDrawCount)
                break; // don't draw more than you want
            if (g.IsEmpty()) continue; // don't draw the blank ones
            // center horizontally in the cell
            double xOffset = (drawCount % ColumnCount) * cellSize.Width + cellSize.Width / 2d - g.Bounds.Width / 2d;
            // place the character on the baseline of the cell
            double yOffset = (drawCount / ColumnCount) * cellSize.Height + fontSize * font.Baseline;
            dc.PushTransform(new TranslateTransform(xOffset, yOffset));
            dc.DrawGeometry(Brushes.Red, null, g);
            dc.Pop(); // get rid of the transform
        }
    }
    
    int RowCount = drawCount / ColumnCount;
    if (drawCount % ColumnCount != 0) 
        RowCount++; // to include partial rows
    int bitWidth = (int)Math.Ceiling(cellSize.Width * ColumnCount);
    int bitHeight = (int)Math.Ceiling(cellSize.Height * RowCount);
    RenderTargetBitmap bmp = new RenderTargetBitmap(
                                                    bitWidth, bitHeight,
                                                    96, 96,
                                                    PixelFormats.Pbgra32);
    bmp.Render(viz);
    
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(bmp));
    using (FileStream file = new FileStream("FontTable.png", FileMode.Create))
        encoder.Save(file);