2008-09-30 11 views

Antwort

2

Eine Metadatei ist eine Datei, die eine Sequenz von GDI-Operationen aufzeichnet. Es ist skalierbar, da die ursprüngliche Sequenz von Operationen, die das Bild erzeugt haben, erfasst wird und daher die Koordinaten, die aufgezeichnet wurden, skaliert werden können.

Ich denke, in .NET, dass Sie ein Metafile Objekt erstellen, erstellen Sie ein Graphics Objekt mit Graphics.FromImage, dann führen Sie Ihre Zeichenschritte. Die Datei wird automatisch aktualisiert, wenn Sie darauf zeichnen. Sie finden ein kleines Beispiel in der Dokumentation für Graphics.AddMetafileComment. Wenn Sie wirklich eine Bitmap in einer Metadatei speichern möchten, verwenden Sie diese Schritte, und verwenden Sie dann Graphics.DrawImage, um die Bitmap zu zeichnen. Wenn es jedoch skaliert wird, wird es unter Verwendung von StretchBlt gestreckt.

2

Die Frage war: "Gibt es eine andere Möglichkeit, das Bild in einem EMF/WMF zu speichern?" Nicht "was ist Metadatei" oder "wie Metadatei erstellen" oder "wie Metadatei mit Grafik verwenden".

Ich kümmere mich auch für Antwort auf diese Frage In der Tat „wie EMF/WMF speichern“, wenn Sie verwenden:

Graphics grfx = CreateGraphics(); 
    MemoryStream ms = new MemoryStream(); 
    IntPtr ipHdc = grfx.GetHdc(); 

    Metafile mf = new Metafile(ms, ipHdc); 

    grfx.ReleaseHdc(ipHdc); 
    grfx.Dispose(); 
    grfx = Graphics.FromImage(mf); 

    grfx.FillEllipse(Brushes.Gray, 0, 0, 100, 100); 
    grfx.DrawEllipse(Pens.Black, 0, 0, 100, 100); 
    grfx.DrawArc(new Pen(Color.Red, 10), 20, 20, 60, 60, 30, 120); 
    grfx.Dispose(); 

    mf.Save(@"C:\file.emf", ImageFormat.Emf); 
    mf.Save(@"C:\file.png", ImageFormat.Png); 

In beiden Fällen Bild als Format png gespeichert wird. Und das ist das Problem, das ich nicht lösen kann:/

+0

Beachten Sie, dass Sie 'System.Drawing.Imaging' für' Metafile' und 'System.IO' für' MemoryStream' verwenden müssen. –

9

Wenn ich mich richtig erinnere, kann es mit einer Kombination aus dem Metafile.GetHenhmetafile(), der API GetEnhMetaFileBits() und Stream.Write(), so etwas wie

getan werden
[DllImport("gdi32")] static extern uint GetEnhMetaFileBits(IntPtr hemf, uint cbBuffer, byte[] lpbBuffer); 


IntPtr h = metafile.GetHenhMetafile(); 
int size = GetEnhMetaFileBits(h, 0, null); 
byte[] data = new byte[size]; 
GetEnhMetaFileBits(h, size, data); 
using (FileStream w = File.Create("out.emf")) { 
    w.Write(data, 0, size); 
} 
// TODO: I don't remember whether the handle needs to be closed, but I guess not. 

Ich denke, so habe ich das Problem gelöst, als ich es hatte.

+0

Während es so aussieht, dass dies funktionieren sollte, finde ich, dass es die gerasterte Version der Metadatei ausgibt, nicht die Vektor-GDI-Datensätze. Darüber hinaus müssen Sie DeleteEnhMetaFile (h) aufrufen und beachten, dass das Aufrufen von GetHenhMetaFile() das Metadateiobjekt in einen ungültigen Status versetzt. –

+0

Sie müssen DeleteEnhMetafile (h) aufrufen, wenn Sie fertig sind, und das Metafile-Objekt wird durch den GetHenhMetafile-Aufruf in einen ungültigen Status versetzt. Wenn es sich bei der Metadatei um eine Raster-basierte Metadatei handelt, erhalten Sie eine rasterbasierte .emf-Datei auf der Festplatte. Wenn es sich um eine vektorbasierte Metadatei handelt, erhalten Sie eine vektorbasierte .emf-Datei auf der Festplatte. In der Regel ruft Metafile.Save ("filename", System.Drawing.Imaging.ImageFormat.Emf) eine PNG-Datei auf. –

2

Die Antwort von erikkallen ist korrekt. Ich habe versucht, diese von VB.NET und hatte 2 verschiedene DllImports verwenden, um es an die Arbeit:

<System.Runtime.InteropServices.DllImportAttribute("gdi32.dll", EntryPoint:="GetEnhMetaFileBits")> _ 
    Public Shared Function GetEnhMetaFileBits(<System.Runtime.InteropServices.InAttribute()> ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData As IntPtr) As UInteger 
End Function 

    <System.Runtime.InteropServices.DllImportAttribute("gdi32.dll", EntryPoint:="GetEnhMetaFileBits")> _ 
    Public Shared Function GetEnhMetaFileBits(<System.Runtime.InteropServices.InAttribute()> ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData() As Byte) As UInteger 
End Function 

Der erste Import wird für den ersten Aufruf verwendet, um die emf Größe. Der zweite Import, um die tatsächlichen Bits zu erhalten. Alternativ können Sie verwenden:

Dim h As IntPtr = mf.GetHenhmetafile() 
CopyEnhMetaFileW(h, FileName) 

Dies kopiert die emf Bits direkt in die angegebene Datei.

18

Image ist eine abstrakte Klasse: was Sie tun möchten, hängt davon ab, ob Sie mit einem Metafile oder einem Bitmap zu tun haben.

Erstellen Sie ein Bild mit GDI + und speichern Sie es als eine EMF ist einfach mit Metafile. Per Mikes post:

var path = @"c:\foo.emf" 
var g = CreateGraphics(); // get a graphics object from your form, or wherever 
var img = new Metafile(path, g.GetHdc()); // file is created here 
var ig = Graphics.FromImage(img); 
// call drawing methods on ig, causing writes to the file 
ig.Dispose(); img.Dispose(); g.ReleaseHdc(); g.Dispose(); 

Dies ist, was Sie die meiste Zeit tun wollen, denn das ist, was EMF ist für: Speichern Vektorbilder in Form von GDI + Zeichenbefehle.

Sie können eine Bitmap in eine EMF-Datei speichern, indem Sie die obige Methode verwenden und ig.DrawImage(your_bitmap) aufrufen, aber beachten Sie, dass dies Ihre Rasterdaten nicht magisch in ein Vektorbild konvertiert.

+1

Wunderbar, ich hatte diese einfache Möglichkeit, eine Metadatei basierend auf dem Metafile-Konstruktor zu erstellen, völlig übersehen. Ich muss zugeben, dass es etwas verwirrend ist, ein Original-HDC zu übertragen, aber trotzdem funktioniert es. –

0

Ich suchte nach einer Möglichkeit, die GDI-Anweisungen in einem Metafile-Objekt in einer EMF-Datei zu speichern. Hans Beitrag half mir, das Problem zu lösen. Das war bevor ich zu SOF kam. Danke, Han. Hier ist was I tried.

 
    [DllImport("gdi32.dll")] 
    static extern IntPtr CopyEnhMetaFile( // Copy EMF to file 
     IntPtr hemfSrc, // Handle to EMF 
     String lpszFile // File 
    ); 

    [DllImport("gdi32.dll")] 
    static extern int DeleteEnhMetaFile( // Delete EMF 
     IntPtr hemf // Handle to EMF 
    ); 

    // Code that creates the metafile 
    // Metafile metafile = ... 

    // Get a handle to the metafile 
    IntPtr iptrMetafileHandle = metafile.GetHenhmetafile(); 

    // Export metafile to an image file 
    CopyEnhMetaFile(
     iptrMetafileHandle, 
      "image.emf"); 

    // Delete the metafile from memory 
    DeleteEnhMetaFile(iptrMetafileHandle); 

0

Es scheint viel Verwirrung über Vektor vs. Bitmap zu bestehen. Der gesamte Code in diesem Thread erzeugt Bitmap-Dateien (Nicht-Vektor-Dateien) - die Vektor-GDI-Aufrufe werden nicht beibehalten. Um dies selbst zu beweisen, laden Sie das Tool "EMF Parser" herunter und prüfen Sie die Ausgabedateien: http://downloads.zdnet.com/abstract.aspx?docid=749645.

Dieses Problem hat viele Entwickler dazu gebracht, sich Sorgen zu machen. Sicher wäre es schön, wenn Microsoft das beheben und das eigene EMF-Format korrekt unterstützen würde.

+1

Sie sind falsch. Die Antwort von user120789 erstellt beispielsweise Vektorgrafiken. – reinierpost

+0

-1: da 'reinierpost' erwähnt wird, erstellt die benutzer120789-lösung eine vektorgrafik – user1027167

2

Sie müssen auch die CopyEnhMetaFile Handler schließen:

IntPtr ptr2 = CopyEnhMetaFile(iptrMetafileHandle, "image.emf"); 
DeleteEnhMetaFile(ptr2); 

// Delete the metafile from memory 
DeleteEnhMetaFile(iptrMetafileHandle); 

Ansonsten können Sie die Datei nicht löschen, weil es immer noch durch den Prozess verwendet wird.

1

Ich würde empfehlen, solche extern und unmanaged Cruft in einer verwalteten .NET-App zu vermeiden.

Convert an image into WMF with .NET?

P. S.: Stattdessen würde ich etwas ein bisschen mehr wie die verwaltete Lösung gegeben in diesem Thread empfehlen Ich beantworte diesen alten Thread, weil dies die beste Antwort war, die ich gefunden habe, aber dann endete die Entwicklung einer gemanagten Lösung, die mich dann zu dem obigen Link führte. Um also anderen die Zeit zu ersparen, dachte ich mir, ich würde das hier darauf hinweisen.

+0

danke für den link, ich hatte schon seit fast einer woche nach einer lösung gesucht ... – David

Verwandte Themen