Convert Bitmap to Graphic to Vektorgrafik (Metafile) -> Return ByteToArray



  • Hallo,

    ich möchte gerne ein Bitmap in eine Graphic umwandeln. Danach soll die Graphic in eine Vektorgrafik (.emf oder .wmf), welche sich in einem MemoryStream befindet, umgewandelt werden. Anschließend soll die Vektorgrafik als Byte-Array zurückgegeben werden.

    Derzeitiger Quellcode:

    //Form1.cs
    
                Bitmap bm = new Bitmap(500, 500);
                Graphics g = Graphics.FromImage(bm);
                Vektor v = new Vektor();
                byte[] ByteArray = v.DrawVector(g);
    
    //Vektor.cs
    
            public byte[] DrawVector(Graphics Canvas)
            {
                MemoryStream ms = new MemoryStream();
    
                //GetHdc = Window Handle zu einem Device Context (Gerätekontext, z.B. Drucker, Bildschirm etc.)
                using (Metafile mf = new Metafile(ms, Canvas.GetHdc())) //Haufenweise Exceptions, z.B. wird die Height oder Width nicht übernommen
                {
                    using (Graphics gra = Graphics.FromImage(mf))
                    {
                        //Zeichne irgendwas
                        gra.DrawLine(Pens.Black, new Point(1,5), new Point(10,10));
                        gra.Save();
                        //mf.Save funktioniert nicht!? "Ungültiger Parameter" oder "Ausnahmefehler GDI+" (abhängig vom ImageFormat)
                        //mf.Save(ms, ImageFormat.Emf);
                    }
                    //MemoryStream wird automatisch nach dem Zeichnen gefüllt
                }
                //Schließen
                Canvas.ReleaseHdc();
                Canvas.Dispose();              
                ms.Close();
    
                return ms.ToArray();
    
                //mf.Save als ImageFormat.Emf ist nicht möglich:
                //When you use the Save method to save a graphic image as a Windows Metafile Format (WMF) or Enhanced Metafile Format (EMF) file, 
                //the resulting file is saved as a Portable Network Graphics (PNG) file instead. This behavior occurs 
                //because the GDI+ component of the .NET Framework does not have an encoder that you can use to save files as .wmf or .emf files.
            }
    

    Es ist wichtig, dass es eine Vektorgrafik sein soll! Ich kriege zwar einen Return Wert, jedoch ist der immer gleich (egal was ich übergebe). Stimmt das!?
    Des Weiteren hat die Metafile etliche Exceptions. Verstehe nicht, warum die Metafile z.B. nicht die Höhe übernimmt.



  • Ich glaub nicht dass du das so einfach gebacken bekommen wirst.
    Soweit ich weiss enthält das .NET Framework keinen Code um eine Bitmap-Grafik in eine Vektorgrafik zu verwandeln.
    Ist halt auch alles andere als einfach - zumindest wenn man es schlau machen will.
    (Und mit "schlau" meine ich alles was schlauer ist als für jeden Pixel einfach ein Quadrat in der Vektorgrafik zu zeichnen.)



  • Ich habs ja schon geschafft, dass ich die Bitmap in eine Grafik umwandle und dann diese auf meiner Festplatte als Datei (.emf) abspeichern kann, jedoch ist dies nicht mein Ziel. Ich hatte schon viel komplexere Strukturen, jedoch wollte ich diese nicht hier posten... Ein einfacher Code zur Veranschaulichung meines Problems würde reichen.
    Das ich nicht einfach so von Bitmap oder Image zu Vektorgrafik umkonvertieren kann ist mir klar, sitze da auch schon seit Stunden dran und hab auch "ganz Google abgesucht"...



  • Wenn du eine Bitmap in ein Metafile umwandelst, bekommst du (wenns funktioniert hat) ein Metafile, das die Bitmap enthält. Also dieselbe Bitmap + Overhead.



  • @fff619
    Also was das Erstellen eines EMF Byte-Arrays angeht, das ist relativ einfach. Zwar nicht wirklich intuitiv, aber einfach:

    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.IO;
    
    namespace EMF
    {
    	class Program
    	{
    		static void Main(string[] args)
    		{
    			RectangleF bounds = new RectangleF(0, 0, 400, 300);
    
    			var bytes = CreateEmfBytes(
    				bounds,
    				gfx =>
    				{
    					gfx.Clear(Color.OrangeRed);
    					gfx.DrawEllipse(Pens.Black, bounds);
    					using (var font = new Font(FontFamily.GenericMonospace, bounds.Height * 0.25f, FontStyle.Bold, GraphicsUnit.Pixel))
    					using (var brush = new SolidBrush(Color.White))
    					{
    						StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
    						sf.Alignment = StringAlignment.Center;
    						sf.LineAlignment = StringAlignment.Center;
    						gfx.DrawString("Boojah!", font, brush, bounds, sf);
    					}
    				});
    
    			// save to file so we can verify the data
    			using (FileStream file = File.Create("g:\\_mf\\foo.emf"))
    			{
    				file.Write(bytes, 0, bytes.Length);
    			}
    		}
    
    		static byte[] CreateEmfBytes(RectangleF bounds, Action<Graphics> drawCallback)
    		{
    			using (var memStream = new MemoryStream())
    			{
    				using (var mf = CreateMetafile(memStream, bounds, MetafileFrameUnit.Pixel, EmfType.EmfPlusOnly))
    				using (var gfx = Graphics.FromImage(mf))
    				{
    					MetafileHeader header = mf.GetMetafileHeader();
    					gfx.ScaleTransform(header.DpiX / gfx.DpiX, header.DpiY / gfx.DpiY);
    
    					gfx.SmoothingMode = SmoothingMode.HighQuality;
    					gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
    					gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
    					gfx.CompositingQuality = CompositingQuality.HighQuality;
    
    					gfx.PageUnit = GraphicsUnit.Pixel;
    					gfx.SetClip(bounds);
    
    					drawCallback(gfx);
    				}
    
    				return memStream.ToArray();
    			}
    		}
    
    		static Metafile CreateMetafile(Stream backingStream, RectangleF bounds, MetafileFrameUnit frameUnit, EmfType emfType)
    		{
    			using (var dummyGfx = Graphics.FromHwndInternal(IntPtr.Zero))
    			{
    				IntPtr referenceHdc = dummyGfx.GetHdc();
    				try
    				{
    					return new Metafile(backingStream, referenceHdc, bounds, frameUnit, emfType);
    				}
    				finally
    				{
    					dummyGfx.ReleaseHdc();
    				}
    			}
    		}
    	}
    }
    

    Der schwierige Teil wird jetzt die Bitmap in ne Vektorgrafik zu verwandeln. Und dabei kann GDI+ dir nicht helfen. Einfach nur "DrawImage" wird vermutlich insofern funktionieren dass du dann EMF Daten hast die dir die Bitmap zeichnen. Nur ganz sicher nicht als Vektorgrafik.



  • Vielleicht hilft dir dies weiter ...



  • @schmidt-webdesign.net nicht wirklich :/, trotzdem danke

    @hustbaer Vielen Dank! Hab's etwas umgeschrieben und es klappt so wie ich es wollte, hab den Code jedoch nicht hier bei mir. Werde mich später nochmal melden 🙂


Anmelden zum Antworten