Metafiles

WINDOWS Metafiles sind eine weitere Möglichkeit zur Abspeicherung von Grafiken. Im Gegensatz zu Bitmaps, in den die Bildinformation als einzelne Punkten enthalten ist, enthalten WMF-Dateien (WindowsMetaFile) die Bildinformation als kodierte GDI-Befehle. Dadurch kann eine WMF-Grafik ohne Qualitätsverlust beliebig skaliert werden da beim Ändern der Grafikgröße nur die Koordinaten für die Grafikbefehle neu berechnet werden.

Um eine WMF-Datei zu erstellen (nicht um sie einzulesen) müssen Sie sich zuerst einen Metafile-DC holen. Die MFC stellt dazu die Klasse CMetaFileDC zur Verfügung. Dieser DC-Objekt ist aber noch an keine Datei gebunden. Um das DC-Objekt mit einer Datei zu verbinden, rufen Sie die CMetaFileDC-Methode CreateEnhanced(...) auf. Diese Methode erhält zuerst einen Zeiger auf ein CDC-Objekt, das als Referenz für das WMF dienen soll. Wenn Sie hier den Wert NULL angeben wird der aktuelle Bildschirm als Referenz für die Auflösung (Größe) verwendet. Danach ist der Namen der zu erstellenden WMF-Datei anzugeben. Diese Datei sollte die Extension EMF (für Extented MetaFile) besitzen. Der nächste Parameter zeigt auf eine RECT-Struktur, die die Ausdehnung der abzuspeichernden Grafik in HIMETRIC Einheiten (0,01 mm) definiert. Wird hierfür der Wert NULL angegeben, dann wird die Ausdehnung automatisch so berechnet, dass die gesamte Grafik darin Platz findet. Mit Hilfe des letzten Parameters kann die Grafik noch mit einem Kommentar versehen. Diese Kommentar besteht aus zwei Teilen: dem Namen der Applikation, die die Grafik erzeugt hat, und einem Titel. Die Kommentarteile sind durch eine '0' zu trennen und der Kommentar selbst ist mit zwei Null-Bytes abzuschließen. Wenn Sie keinen Kommentar benötigen, so können Sie auch hier den Wert NULL angeben.

Um nun in eine WMF-Datei 'zu zeichnen' verwenden Sie gleichen Anweisungen wie beim Zeichnen innerhalb eines Fensters nur mit dem Unterschied, dass Sie hier jetzt nicht mit dem Fenster-DC Objekt zeichnen sondern mit dem vorher erstellten CMetaFileDC Objekt.

Einige CDC-Methoden werten beim Zeichen die Membervariable m_hAttribDC des DCs aus. Diese wird aber von CreateEnhanced(...) nicht gesetzt. Sie sollten daher diese Membervariable vor dem ersten Zeichen mit der CDC-Membervariable m_hDC initialisieren.

Wurde die Grafik komplett gezeichnet, muss die WMF-Datei geschlossen werden. Um die WMF-Datei zu schließen rufen Sie die CMetaFileDC-Methode CloseEnhanced(...) auf. Sie liefert als Returnwert ein Handle auf die erstellte WMF-Datei. Mit Hilfe dieses Handles könnten Sie dann die WMF-Datei wiedergeben (was wir nachher in einem zweiten Schritt tun werden) oder auch einzelne Einträge der WMF-Datei (GDI-Anweisungen) editieren. Wird das erhaltene Metafile-Handle nicht mehr benötigt, so muss es durch den Aufruf der API-Funktion DeleteEnhMetaFile(...) freigegeben werden.

Wenn Sie in Metafiles zeichnen achten Sie immer darauf, dass Sie alle beim Zeichnen belegten Ressourcen auch wieder freigeben, d.h. zu jedem SelectObject(...) sollte auch ein DeleteObject(...) vorhanden sein. Tun Sie dies nicht, so kann es Ihnen unter Umständen bei wiederholter Wiedergabe (Anzeige) der WMF-Datei passieren dass der GDI-Heap überläuft!

Sehen wir uns nun an, wie ein und die selbe OnDraw(...) Methode des Ansichtsobjektes dazu verwendet werden kann um einmal in eine WMF-Datei zu zeichnen und das andere mal innerhalb des Fensters.

/////////////////////////////////////////////////////////////////////////
// CGdiDrawView Zeichnen

void CGdiDrawView::OnDraw(CDC* pDC)
{
    CGdiDrawDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

    // ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten hinzufügen

    CPen CBluePen(PS_DASH,0,RGB(0,0,255)); // Stift erstellen

    // Das ist der DC, mit dem gezeichnet wird
    CDC *pPaintDC;

    if (m_bWMF)
    {
        // Falls in WMF-Datei zeichnen
        pPaintDC = new CMetaFileDC;
        ((CMetaFileDC*)pPaintDC)->CreateEnhanced(pDC,"curve.emf",NULL,NULL);
        pPaintDC->m_hAttribDC = pPaintDC->m_hDC;
    }
    else
        // Es wird ins Fenster gezeichnet
        pPaintDC = pDC;

    // Hier wird nun gezeichnet
    pPaintDC->SetBkColor(RGB(0,255,0));
    pPaintDC->SetBkMode(OPAQUE);

    pPaintDC->SelectObject(&CBluePen);
    pPaintDC->MoveTo(0,m_CMin.y);
    pPaintDC->LineTo(0,m_CMax.y);
    ....
    if (m_bWMF)
    {
        // Falls WMF-Datei erstellt wurde, WMF schliessen
        HENHMETAFILE hWMF = ((CMetaFileDC*)pPaintDC)->CloseEnhanced();
        ::DeleteEnhMetaFile(hWMF);
        m_bWMF = FALSE;
        // und Fenster auch neu darstellen lassen
        Invalidate();
    }
}

Kommen wir nun zum Einlesen einer WMF-Datei. Auch hier muss zuerst die gewünschte WMF-Datei geöffnet werden. Leider bietet die MFC keine direkte Unterstützung hierfür an sondern es muss die API-Funktion GetEnhMetaFile(...) eingesetzt werden. Als Parameter erhält die Funktion den Namen der zu ladenden  WMF-Datei und als Returnwert wird das Metafile-Handle geliefert. Um den Inhalt der Datei (das sind die kodierten GDI-Befehle) wiederzugeben, wird die CDC-Methode PlayMetaFile(...) verwendet. Sie erhält als ersten Parameter das von GetEnhMetaFile(...) zurückgelieferte Handle und im zweiten Parameter wird der Bereich spezifiziert, innerhalb dessen die WMF-Datei dargestellt wird. Die Ausgabe der WMF-Datei wird hierbei entsprechend skaliert. Wird das Handle der Metafile-Datei nicht mehr benötigt, so muss es mit der bereits bekannten API-Funktion DeleteEnhMetaFile(...) freigegeben werden.

Damit würde sich für die Wiedergabe einer WMF-Datei folgende OnDraw(...) Methode ergeben:

void CWMFReadView::OnDraw(CDC* pDC)
{
    CWMFReadDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

    // ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten hinzufügen

    // WMF-Datei im gesamten Fenster darstellen
    RECT ClientRect;
    GetClientRect(&ClientRect);

    HENHMETAFILE hWMF = ::GetEnhMetaFile("curve.emf");
    if (hWMF != NULL)
    {
        pDC->PlayMetaFile(hWMF,&ClientRect);
        ::DeleteEnhMetaFile(hWMF);
    }
}
Es gibt noch ein weiteres Format der WMF-Dateien das aber aus Zeiten von WINDOWS 3.x stammt. Dateien mit diesem 'alten' Format haben in der Regel die Extension WMF. Das 'alte' WMF-Format unterstützt wesentlich weniger GDI-Funktionen. Dies sind insbesondere die Funktionen, die sich mit den Koordinatentransformationen befassen. Um 'alte' WMF-Dateien zu bearbeiten sind andere Funktionen/Methoden notwendig. So verbinden Sie z.B. eine solche Datei mit dem CMetaFileDC über die Methode Create(...) anstelle der aufgeführten CreateEnhanced(...)   Methode.

Damit verlassen wir nun endgültig die Darstellung von Grafikdateien und wenden uns in der nächsten Lektion noch einigen weiteren GDI-Funktionen zu.



Copyright © 2004

Senden Sie Emails mit Fragen oder Kommentaren zu dieser Website an: mailto:info@cpp-tutor.de
 Wolfgang Schröder, Lerchenweg 23, D-72805 Lichtenstein. Tel: +49 7129 6470