4

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.

M8R-wp4emq
  • 53
  • 1
  • 5

3 Answers3

3

For anyone who is wanting to render geometry centered in a fixed size, this is the code to do it:

const int TargetSize = 14;

private static void Save(Geometry geometry, string fileName)
{
    var rect = geometry.GetRenderBounds(new Pen(Brushes.Black, 0));

    var bigger = rect.Width > rect.Height ? rect.Width : rect.Height;
    var scale = TargetSize / bigger;

    Geometry scaledGeometry = Geometry.Combine(geometry, geometry, GeometryCombineMode.Intersect, new ScaleTransform(scale, scale));
    rect = scaledGeometry.GetRenderBounds(new Pen(Brushes.Black, 0));

    Geometry transformedGeometry = Geometry.Combine(scaledGeometry, scaledGeometry, GeometryCombineMode.Intersect, new TranslateTransform(((TargetSize - rect.Width) / 2) - rect.Left, ((TargetSize - rect.Height) / 2) - rect.Top));

    RenderTargetBitmap bmp = new RenderTargetBitmap(TargetSize, TargetSize, // Size
                                                    96, 96, // DPI 
                                                    PixelFormats.Pbgra32);

    DrawingVisual viz = new DrawingVisual();
    using (DrawingContext dc = viz.RenderOpen())
    {
        dc.DrawGeometry(Brushes.Black, null, transformedGeometry);
    }

    bmp.Render(viz);

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

    using (FileStream file = new FileStream(fileName, FileMode.Create))
        pngEncoder.Save(file);
}
Matt Whitfield
  • 6,436
  • 3
  • 29
  • 44
1
// 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);
CodeGnome
  • 251
  • 1
  • 4
  • I did just a few hours ago. [Code](http://pastebin.com/pJzeQYdB) But instead of [Img1](http://nekaka.com/d/WQE1jYvvE8), I get [Img2](http://nekaka.com/d/1jYt8n45EZ) – M8R-wp4emq Jan 31 '12 at 15:26
  • 1
    The glyphs are tricky because the geometries are drawn as if you're starting at the lower left corner. If you draw one at the point (0,0), the top of the character is at (0, -glyphHeight), so it'll all be offscreen. – CodeGnome Jan 31 '12 at 17:22
1

I use this:

        private void GenerateFontMap(string PathTofont, int GlyphsPerRow, int WidthAndHeight)       

        {

        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 = WidthAndHeight * GlyphsPerRow;
            int mapHeight = WidthAndHeight * ((fontNum.Count + 1) / GlyphsPerRow + 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.Black, 1);
            Geometry glyphGeometry;
            GeometryDrawing glyphDrawing;
            PngBitmapEncoder encoder;
            RenderTargetBitmap bmp;
            DrawingVisual viz;

            for (int i = 0; i < fontNum.Count; i++)
            {                    
                glyphGeometry = font.GetGlyphOutline(fontNum[i], WidthAndHeight, 1);
                glyphDrawing = new GeometryDrawing(System.Windows.Media.Brushes.Black, glyphPen, glyphGeometry);

                DrawingImage geometryImage = new DrawingImage(glyphDrawing);
                geometryImage.Freeze();

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

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

                bmp.Render(viz);

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

                MemoryStream myStream = new MemoryStream();
                encoder.Save(myStream);

                g.DrawImage(System.Drawing.Bitmap.FromStream(myStream), new PointF((i - (i / GlyphsPerRow) * GlyphsPerRow) * WidthAndHeight, i / GlyphsPerRow * WidthAndHeight));
            }
            g.Dispose();
            b.Save("map.png", ImageFormat.Png);
            b.Dispose();
        }
    }
M8R-wp4emq
  • 53
  • 1
  • 5