Verwenden von Druckergeräteschriftarten

Die Schriftarten, die sich in Druckern befinden, können manchmal nützlich und schwierig im Anwendungsprogrammcode zu verwenden sein. In diesem Artikel wird beschrieben, wie Sie ermitteln können, welche druckerresidenten Geräteschriftarten für die Verwendung in einem Win32-Druckergerätekontext verfügbar sind. Der Artikel beschreibt auch mehrere Probleme, die auftreten können, wenn Sie versuchen, diese Druckerschriftarten im Anwendungscode zu verwenden.

Ursprüngliche Produktversion: Win32-Druckergerät
Ursprüngliche KB-Nummer: 201978

Zusammenfassung

In den meisten Fällen verlässt sich ein Softwareentwickler auf das Betriebssystem, um die Schriftarten bereitzustellen, die für seine Zeichnung verwendet werden. Hierzu können Sie eine vom Betriebssystem bereitgestellte Schriftart über die Anwendungsprogrammierschnittstelle (Application Programming Interface, API) oder über das allgemeine Dialogfeld Schriftart auswählen auswählen. Die Anwendung ist jedoch in der Regel nicht mit der verwendeten Schriftart beschäftigt, nur sie erfüllt bestimmte Anforderungen, und der Benutzer bevorzugt die Schriftart. Die folgenden Anforderungen müssen berücksichtigt werden:

  • Die Schriftart muss eine bestimmte Größe aufweisen.
  • Schriftart muss Zeichen (auch als Glyphen bezeichnet) enthalten.
  • Schriftart muss einen bestimmten Stil aufweisen.

Wenn die Anwendung das Dokument druckt, wird die Schriftart (oder eine ähnliche Schriftart) auf dem Drucker verwendet, ohne dass eine bestimmte Aktion der Anwendung erfolgt. Dies ist in der Regel das richtige Ergebnis für die Anwendung, und dies führt zu guten gedruckten Ergebnissen bei angemessenen Geschwindigkeiten.

Manchmal muss ein Anwendungsentwickler jedoch nur eine bestimmte Schriftart speziell von einem Zieldrucker auswählen. In der Vergangenheit war dies bei Druckdruckern (z. B. Punktmatrixdruckern) erforderlich, um bestimmte Formatierungen zu erhalten oder den Druck zu beschleunigen.

Heutzutage sind die meisten Drucker grundsätzlich als Rastergeräte konzipiert und können einen Punkt (ein Pixel) auf jedem Teil des Papiers so effizient zeichnen wie alle Zeichensymbole. Für die meisten Anwendungen ist es kein Problem, ob ein Zeichensymbol als ganzes Formular aus einer druckeridentischen Definition oder als Sammlung von Pixeln gezeichnet wird, die das Betriebssystem bereitstellt. Möglicherweise möchten Sie jedoch trotzdem eine Schriftart verwenden, die nur vom Drucker bereitgestellt wird. Dies kann beispielsweise auftreten, weil die Schriftart eindeutig ist und im Betriebssystem keinen ähnlichen Ersatz aufweist, oder weil Sie den Mehraufwand für das Herunterladen einer Schriftartdefinition auf den Drucker vermeiden möchten.

Geräteschriftarten

Für die Zwecke dieses Artikels sind Geräteschriftarten alle Schriftarten, deren Definition entweder dauerhaft oder vorübergehend im Speicher des Druckers vorhanden ist. Diese Geräteschriftarten bieten eine Zeichenglyphendefinition, die von der Seitenraster-Hardware des Druckers pro Zeichen adressiert werden kann, um die Form auf Papier frei zu machen.

Geräteschriftarten können in drei grundlegende Typen kategorisiert werden:

  • Echte Geräteschriftarten. Für die Zwecke dieses Artikels sind dies Schriftarten, die nur von der Druckerhardware bereitgestellt werden und die Sie nur auf dem Drucker verwenden können.

  • Ersetzung der Geräteschriftart. Schriftarten, die im Betriebssystem vorhanden sind und die auch von der Druckerhardware bereitgestellt werden. In diesem Fall kann die Druckerhardware die Schriftarten des Betriebssystems ersetzen.

  • Herunterladbare Schriftarten. Schriftarten, die das Betriebssystem bereitstellt, deren Definition jedoch auf den Drucker heruntergeladen und auf dem Drucker verwendet werden kann, als ob die Druckerhardware die Schriftarten direkt bereitstellt.

Herunterladbare Schriftarten

Das Betriebssystem bietet herunterladbare Schriftarten, die auch als weiche Schriftarten bezeichnet werden. Wenn Sie ein Dokument drucken, wird die Definition für die Schriftart als Teil des Druckauftrags bereitgestellt. Wenn der Drucker den Druckauftrag verarbeitet, wird die Schriftdefinition im Druckerspeicher installiert, sodass die Schriftdefinition auf der gedruckten Seite des Dokuments freihand gemacht werden kann.

Einige argumentieren, dass es sich bei diesen Schriftarten um Geräteschriftarten handelt, da der Drucker die Zeichensymbole der Schriftart zeichnet. Wenn jedoch eine Schriftartdefinition heruntergeladen wird oder eine Glyphe über eine Bitmap auf den Drucker gezeichnet wird, wird nur eine gewisse Mehraufwand- oder Druckauftragspoolgröße gespeichert. Dieser Prozess erfolgt transparent für die Anwendung, sodass die Schriftart im Betriebssystem auf dem Bildschirm und auf dem Drucker verwendet werden kann. Da sich dieser Artikel auf die Verwendung von Geräteschriftarten konzentriert, die nur vom Drucker bereitgestellt werden, wird in diesem Artikel nicht beschrieben, wie herunterladbare Schriftarten verwendet werden.

Ersetzung der Geräteschriftart

Die Geräteschriftart wird ersetzt, wenn es zwei unterschiedliche Schriftartdefinitionen gibt: eine, die vom Betriebssystem verwendet wird, und eine, die der Drucker verwendet. Das heißt, eine Anwendung wählt eine Schriftart im Betriebssystem in einem Dokument auf dem Bildschirm aus und verwendet sie. Wenn Sie das Dokument drucken, wird die gedruckte Ausgabe mit der ähnlich definierten Schriftart gezeichnet, die der Drucker bereitstellt. Daher wurde die Schriftart im Betriebssystem auf dem Drucker durch die vom Drucker definierte Schriftart ersetzt.

Dies tritt in der Regel auf PostScript-Druckern auf, wenn eine allgemeine Windows TrueType-Schriftart verwendet wird. Ein Beispiel hierfür ist die Arial-Schriftart TrueType, die in der Regel mithilfe der PostScript-Schriftartdefinition für die Schriftart Helvetica auf den meisten PostScript-Geräten gedruckt wird. Dies ist ein Beispiel für eine Ersetzung mit einer ähnlichen Schriftart, deren Schriftartname sich unterscheidet. In diesem Fall können Sie diese ähnliche Schriftartdefinition in der Regel direkt suchen und verwenden, da die ähnliche Schriftartdefinition auch als echte Geräteschriftart verfügbar gemacht wird. Dies wird weiter unten in diesem Artikel erläutert.

Die Geräteschriftart wird auch ersetzt, wenn die Schriftart auf dem Drucker denselben Namen wie die Schriftart hat, die das Betriebssystem bereitstellt. Dies tritt in der Regel auf Druckern wie Hewlett-Packard LaserJet-Druckern auf. Diese Drucker verfügen in der Regel über eigene Versionen der Windows-Kernschriftarten wie Arial und Times New Roman. Obwohl diese Schriftarten in der Regel auch auf der Suche nach echten Geräteschriftarten gefunden werden können, kann ihre Verwendung manchmal nicht garantiert werden, da die Druckertreiber häufig selbst auswählen oder über die Benutzereinstellungen auswählen, ob stattdessen die Schriftart verwendet werden soll, die das Betriebssystem bereitstellt.

Echte Geräteschriftarten

Echte Geräteschriftarten sind solche, die nur über eine Definition auf dem Drucker verfügen. Die einzige Möglichkeit, diese Schriftarten zu verwenden, besteht darin, dass die Anwendung die Schriftart spezifisch identifiziert und für die Verwendung im Kontext des Druckergeräts erstellt.

Wenn Sie genügend Informationen über ein Gerät kennen, können Sie eine logische Schriftbeschreibung in einer LOGFONT Struktur erstellen, die zur Realisierung der Geräteschriftart führt. Insbesondere ist es wichtig, die richtigen Informationen für das Element, das lfFacenamelfHeight Element und den Zeichensatz der Schriftart anzugeben. Außerdem sollte das lfOutPrecision Element ein OUT_DEVICE_PRECIS Flag enthalten, um den Schriftartenzuordnungsprozess zu beeinflussen, um Geräteschriftarten anstelle ähnlich benannter Systemschriftarten auszuwählen.

Wenn die Beschreibung der Schriftart nicht bekannt ist, können Sie Schriftarten auflisten, um Geräteschriftarten zu ermitteln. Um eine Liste der Geräteschriftarten zu erhalten, die der Drucker unterstützt, verwenden Sie eine der Schriftartenumerationsfunktionen wie EnumFontFamiliesEx. Anwendungscode, der in die Rückruffunktion eingefügt wird, kann die Daten untersuchen, die an die Rückruffunktion übergeben werden, um zu bestimmen, welche Schriftartinstanzen eine Geräteschriftart beschreiben.

Verwenden von echten Geräteschriftarten

Der Prozess der Verwendung einer Geräteschriftart im Kontext eines Druckergeräts folgt den folgenden allgemeinen Schritten:

  1. Identifizieren Sie die wahren Geräteschriftarten durch Enumeration der Schriftarten in einem Druckergerätekontext.
  2. Wählen Sie Schriftarten aus, die nur gerätegeschützt sind, wie durch die FontType Flags und durch den Ausschlussprozess angegeben.
  3. Verwenden Sie druckerspezifische Metriken im MM_TEXT Zuordnungsmodus, um den Text, der mit der Geräteschriftart gezeichnet wird, genau zu platzieren.

Auflisten der Schriftarten eines Druckergerätekontexts

Um alle Schriftarten aufzulisten, die in einem Gerätekontext verfügbar sind, können Sie Rückruffunktionen und die EnumFontFamiliesEx -Funktion aus der Win32-API (Application Programming Interface) verwenden. Um alle Schriftarten für einen Gerätekontext aufzuzählen, müssen Sie zweimal aufrufen EnumFontFamiliesEx : zuerst, um eine Liste der Schriftfamilien abzurufen, und ein zweites Mal, um alle unterschiedlichen Schriftarten abzurufen, die in jeder Schriftfamilie enthalten sind.

Um alle Geräteschriftarten in einem Druckergerätekontext zu finden, müssen Sie alle Schriftarten des Druckergerätekontexts auflisten. Wenn jede Schriftart an die Rückruffunktionen übergeben wird, wird die Schriftart untersucht, um festzustellen, ob es sich um eine Geräteschriftart handelt. Die PrinterDeviceFontEnum Rückruffunktionen und PrinterDeviceFontFamiliesEnum im folgenden Beispielcode führen diesen Vorgang aus.

// Data structure to pass data through the font enumeration callbacks.
typedef struct PrintEnumFontData
{
    HDC             hPrinterDC;
    HDC             hEnumDC;
    int             curx, cury;
    ENUMLOGFONTEX   elf;
} PRINTENUMFONTDATA;

int CALLBACK PrinterDeviceFontEnum(
  ENUMLOGFONTEX *lpelfe,    // logical-font data
  NEWTEXTMETRICEX *lpntme,  // physical-font data
  DWORD FontType,           // type of font
  LPARAM lParam             // application-defined data
)
{
    // Crack the data out of the enumeration parameter.
    PRINTENUMFONTDATA *     ppeft = (PRINTENUMFONTDATA*) lParam;

    // Printing information
    TEXTMETRIC              tm;
    HFONT                   hfont, holdfont;
    int                     pagecx, pagecy;

    // Data to determine where this font came from
    ENUMEDFONT      df = { FontType, lpelfe };  // To look for a system version

    // What is the printable area of the page?
    pagecx = GetDeviceCaps(ppeft->hPrinterDC, HORZRES);
    pagecy = GetDeviceCaps(ppeft->hPrinterDC, VERTRES);

    // Is it a device font?
    // If it is, make sure that it is also not a TrueType font because
    // that is most likely a downloaded font.
    // Also, look for any system-provided fonts that are also
    // masquerading as printer device fonts. This implies that they will be
    // downloaded to the printer as is the case with Adobe Type 1 fonts.
    // If they are downloaded, you do not want to include them in this demonstration.
    if (FontType & DEVICE_FONTTYPE &&
        !(FontType & TRUETYPE_FONTTYPE) &&
        !IsSystemFont(&df))
    {
        TCHAR           Buffer[MAX_PATH];           // description of font
        LPTSTR          szFontType;                 // description of type
        LPTSTR          pStyle = "Regular";         // Fonts Style defaults to Regular

        // At this point in this code, the lpelfe parameter has been examined
        // and found to describe a printer device font.
        // Do something interesting with it as follows:

        // Build a sample string that describes the font.
        if (lpelfe->elfLogFont.lfItalic)
        {
            pStyle = "Italic";
            if (lpelfe->elfLogFont.lfWeight > FW_NORMAL)
                pStyle = "Bold Italic";
        }
        else if (lpelfe->elfLogFont.lfWeight > FW_NORMAL)
            pStyle = "Bold";

        // Determine if the font is scalable or a bitmap font.
        if (FontType & RASTER_FONTTYPE)
            szFontType = TEXT("Bitmap Font");
        else
        {
            // This is an instance of a scalable font, 
            // use 12 pt because it is easy to read.
            szFontType = TEXT("Scalable Font");
            lpelfe->elfLogFont.lfHeight = MulDiv(12, GetDeviceCaps(ppeft->hPrinterDC, LOGPIXELSY), 72);
            lpelfe->elfLogFont.lfWidth = 0;
        }

        // Skip all fonts after this font that are the same scale as the last one.
        // However, let different sizes of 'bitmap' fonts through.
        // This is a cheat that relies on enumeration order.
        // Really, you should keep a 'used' list and compare against the list.
        if (FontType & RASTER_FONTTYPE || !CompareLogFontEx(&ppeft->elf, lpelfe))
        {

            hfont = CreateFontIndirect(&lpelfe->elfLogFont);
            holdfont = (HFONT)SelectObject(ppeft->hPrinterDC, hfont);
            GetTextMetrics(ppeft->hPrinterDC, &tm);

            // If beyond bottom of page, get a new page.
            if (pagecy < ppeft->cury + tm.tmExternalLeading + tm.tmHeight)
            {
                EndPage(ppeft->hPrinterDC);
                StartPage(ppeft->hPrinterDC);
                ppeft->cury = 0;
            }

            // Draw our sample text.
            wsprintf(Buffer, "%s %s [%s]  FontType: %s", lpelfe->elfFullName, pStyle, lpelfe->elfScript, szFontType);
            ppeft->cury += tm.tmExternalLeading;
            TextOut(ppeft->hPrinterDC, ppeft->curx, ppeft->cury, Buffer, lstrlen(Buffer));
            ppeft->cury += tm.tmHeight;

            // Clean up.
            SelectObject(ppeft->hPrinterDC, holdfont);
            DeleteObject(hfont);

            // Make a note of the font that you used so that the next time
            // this callback is called, you can skip different scales of
            // the same font.
            CopyMemory(&ppeft->elf, lpelfe, sizeof(ENUMLOGFONTEX));
        }
    }
    // Otherwise, continue enumeration without doing anything with this
    // particular font.

    return 1;
}

int CALLBACK PrinterDeviceFontFamiliesEnum(
  ENUMLOGFONTEX *lpelfe,    // logical-font data
  NEWTEXTMETRICEX *lpntme,  // physical-font data
  DWORD FontType,           // type of font
  LPARAM lParam             // application-defined data
)
{
    PRINTENUMFONTDATA * ppeft = (PRINTENUMFONTDATA*) lParam;

    ZeroMemory(&ppeft->elf, sizeof(ppeft->elf));

    // Is it a device font?
    // If it is, make sure that it is also not a TrueType font because
    // that is most likely a downloaded font.
    if (FontType & DEVICE_FONTTYPE && !(FontType & (TRUETYPE_FONTTYPE)))
    {

        // Enumerate all of the font instances that are part of this
        // font family.
        return EnumFontFamiliesEx(ppeft->hEnumDC,
            &lpelfe->elfLogFont,
            (FONTENUMPROC)PrinterDeviceFontEnum,
            lParam,
            0);
    }

    // Otherwise, if you are not interested in this particular font, 
    // continue enumeration so that you can find more.
    return 1;
}

BOOL CALLBACK AbortProc(HDC hdc, int iError)
/*
    This minimal AbortProc implementation stops the print
    job when an error occurs.
 */
{
    if (iError)
        return FALSE;
    return TRUE;
}

BOOL PrintDeviceFontList(HDC hPrinterDC)
{
    int ret;
    LOGFONT             lf;     // Describes the start of the font enumeration
    PRINTENUMFONTDATA peft =
    {
        hPrinterDC,             // Device Context on which to print
        hPrinterDC,             // Device Context to enumerate
        0, 0,                   // Current print location
        NULL                    // Last device font that is used to print
    };
    DOCINFO di;                 // Description of the print job

    // Start the print job.
    ZeroMemory(&di, sizeof(di));
    di.cbSize = sizeof(di);
    di.lpszDocName = TEXT("Printer Font List");

    // Set a minimal AbortProc because there should always be one.
    ret = SetAbortProc(hPrinterDC, (ABORTPROC) AbortProc);
    if (ret < 1) return false;

    ret = StartDoc(hPrinterDC, &di);
    if (ret < 1) return false;

    ret = StartPage(hPrinterDC);
    if (ret < 1)
    {
        AbortDoc(hPrinterDC);
        return false;
    }

    // Enumerate everything to start, weed out non-device fonts, 
    // and then print non-device fonts during enumeration.
    ZeroMemory(&lf, sizeof(lf));
    lf.lfCharSet = DEFAULT_CHARSET;

    // Call the enumeration with your callback function that prints
    // the device fonts that it finds.
    ret = EnumFontFamiliesEx(hPrinterDC,
        &lf,
        (FONTENUMPROC)PrinterDeviceFontFamiliesEnum,
        (LPARAM)&peft,
        0);

    // The value 1 is returned by the callback functions to continue
    // the enumeration. When the enumeration completes, EnumFontFamiliesEx
    // returns the last value that the callback returns.
    // Therefore, you succeed if you get 1. Let it print.
    if (ret == 1)
    {
        EndPage(hPrinterDC);
        EndDoc(hPrinterDC);
        return true;
    }

    // Otherwise, exit because you failed somewhere in the process.
    AbortDoc(hPrinterDC);
    return false;
}

Sie können im Beispielcode sehen, wo die EnumFontFamiliesEx Funktion zweimal aufgerufen wird. Der erste Aufruf erfolgt in der PrintDeviceFontList Funktion. Der zweite Aufruf befindet sich in der PrinterDeviceFontFamiliesEnum Rückruffunktion.

PrintDeviceFontList ist die Funktion der obersten Ebene. PrintDeviceFontList führt zwei Aufgaben aus, indem sie einen Druckauftrag im Kontext des Druckergeräts starten und dann den ersten Aufruf von aufrufen, EnumFontFamiliesEx um den Schriftenumerationsprozess zu starten. Gemäß der Dokumentation des Platform Software Development Kit (SDK) werden alle Schriftartenfamilien aufgelistet, wenn Sie das LOGFONT Element der Struktur lfCharSet auf den DEFAULT_CHARSET -Wert EnumFontFamiliesEx festlegen. Nachdem die Schriftartenumeration abgeschlossen ist, schließt der Code die Aufgabe für die Druckauftragsverwaltung ab, indem die EndDoc -Methode aufgerufen wird.

Die PrinterDeviceFontFamiliesEnum Rückruffunktion wird für jede Schriftfamilie von der EnumFontFamiliesEx Funktion aufgerufen. In dieser Rückruffunktion sucht der Code zunächst die Schriftartenfamilien, um nur die Geräteschriftarten zu finden, die durch den FontType -Parameter gekennzeichnet sind. Außerdem werden alle Schriftarten angezeigt, die als TrueType gekennzeichnet sind, da es sich bei diesen Schriftarten wahrscheinlich um herunterladbare Schriftarten handelt. Für die Schriftartenfamilien, die als Geräteschriftarten betrachtet werden, wird die EnumFontFamiliesEx Funktion erneut aufgerufen, aber die ENUMLOGFONTEX Struktur übergeben, die die Rückruffunktion empfangen hat. Die Verwendung des Rückrufparameters als Eingabeparameter für den zweiten Enumerationsfunktionsaufruf bewirkt, dass die zweite Enumeration alle unterschiedlichen Schriftarten in dieser Schriftfamilie auflistet.

Geräteschriftarten auswählen

Sie können bestimmte Kriterien von Druckergeräteschriftarten verwenden, um diese Schriftarten von allen anderen Schriftarten zu unterscheiden, die aufgelistet werden. Suchen Sie insbesondere nach dem DEVICE_FONTTYPE Wert im DWORD-Parameter der FontType Rückruffunktion. Fast alle Schriftarten, die mit diesem Wert an die Rückruffunktion übergeben werden, sind Geräteschriftarten für den Druckergerätekontext (mit Ausnahme von Adobe-Schriftarten).

Im Beispielcode wird die PrinterDeviceFontEnum Rückruffunktion von der zweiten Enumeration für jede einzelne Schriftart in der Schriftfamilie aufgerufen. Die PrinterDeviceFontEnum Rückruffunktion führt drei Aufgaben aus:

  • Verwendet erneut die Kriterien für die Geräteschriftart, um sicherzustellen, dass die Funktion nur Schriftarten verarbeitet, die als Geräteschriftarten erkannt werden.

  • Sucht mithilfe einer anderen Schriftartenumeration nach der Schriftart, um festzustellen, ob die Geräteschriftart auch im Bildschirmgerätekontext des Systems verwendet wird.

  • Druckt ein Beispiel der Schriftart auf den Druckauftrag, der erstellt wird, um die Verwendung der Schriftart zu veranschaulichen. Diese Rückruffunktion verwendet eine Funktion namens IsSystemFont, die Teil des folgenden Beispielcodes ist:

BOOL CompareLogFontEx(
  CONST ENUMLOGFONTEX * Destination,   // copy destination
  CONST ENUMLOGFONTEX * Source  // memory block
)
/*
    Returns true if the two ENUMLOGFONTEX buffers compare.
    Return false if the two buffers differ in someway as described by the 
    criteria below.
*/
{

    // Compare the string descriptions:
    if (lstrcmpi((LPCTSTR )Destination->elfFullName, (LPCTSTR )Source->elfFullName) != 0)
        return false;
    if (lstrcmpi((LPCTSTR )Destination->elfScript, (LPCTSTR )Source->elfScript) != 0)
        return false;
    if (lstrcmpi((LPCTSTR )Destination->elfStyle, (LPCTSTR )Source->elfStyle) != 0)
        return false;

    // Height and Width are not compared because they will change
    // based upon the device on which the font is enumerated.
    //  LONG lfHeight;
    //  LONG lfWidth;

    // Compare the LOGFONT properties:
    //  LONG lfEscapement;
    if (Destination->elfLogFont.lfEscapement != Source->elfLogFont.lfEscapement) return false;
    //  LONG lfOrientation;
    if (Destination->elfLogFont.lfOrientation != Source->elfLogFont.lfOrientation) return false;
    //  LONG lfWeight;
    if (Destination->elfLogFont.lfWeight != Source->elfLogFont.lfWeight) return false;
    //  BYTE lfItalic;
    if (Destination->elfLogFont.lfItalic != Source->elfLogFont.lfItalic) return false;
    //  BYTE lfUnderline;
    if (Destination->elfLogFont.lfUnderline != Source->elfLogFont.lfUnderline) return false;
    //  BYTE lfStrikeOut;
    if (Destination->elfLogFont.lfStrikeOut != Source->elfLogFont.lfStrikeOut) return false;
    //  BYTE lfCharSet;
    if (Destination->elfLogFont.lfCharSet != Source->elfLogFont.lfCharSet) return false;
    //  BYTE lfOutPrecision;
    if (Destination->elfLogFont.lfOutPrecision != Source->elfLogFont.lfOutPrecision) return false;
    //  BYTE lfClipPrecision;
    if (Destination->elfLogFont.lfClipPrecision != Source->elfLogFont.lfClipPrecision) return false;
    //  BYTE lfQuality;
    if (Destination->elfLogFont.lfQuality != Source->elfLogFont.lfQuality) return false;
    //  BYTE lfPitchAndFamily;
    if (Destination->elfLogFont.lfPitchAndFamily != Source->elfLogFont.lfPitchAndFamily) return false;
    //  TCHAR lfFaceName[LF_FACESIZE];
    if (lstrcmpi((LPCTSTR )Destination->elfLogFont.lfFaceName, (LPCTSTR )Source->elfLogFont.lfFaceName) != 0) return false;

    // Conclusion: the two LOGFONT enumeration buffers are comparable.
    return true;
}

typedef struct structEnumedFont
{
    DWORD FontType;
    ENUMLOGFONTEX * elfx;
} ENUMEDFONT;

int CALLBACK FindSystemFontEnum(
  ENUMLOGFONTEX *lpelfe,    // logical-font data
  NEWTEXTMETRICEX *lpntme,  // physical-font data
  DWORD FontType,           // type of font
  LPARAM lParam             // application-defined data
)
{
    ENUMEDFONT  *   pdf  = (ENUMEDFONT *)lParam;
    ENUMLOGFONTEX * lpelfeSrc = pdf->elfx;

    lpelfe->elfLogFont.lfHeight = lpelfeSrc->elfLogFont.lfHeight;
    lpelfe->elfLogFont.lfWidth = lpelfeSrc->elfLogFont.lfWidth;

if (CompareLogFontEx(lpelfeSrc, lpelfe) && FontType == pdf->FontType)
        return 0;       // System font found. Stop enumeration.
        return 1;
}

BOOL IsSystemFont(ENUMEDFONT *pdf)
/*
    Utility function that takes a font that is enumerated from a printer device
    that is in the pdf parameter and that looks for it on a Screen Device
    Context to conclude that the font passed in that came from the 
    printer is really supplied by the system.
 */
{
    HDC hScreenDC = GetDC(NULL);    // Get the screen device context.

    // If the enumeration stops by returning zero (0),
    // the font was found on the screen device context so it is a
    // system-supplied font.
    BOOL fFound = !EnumFontFamiliesEx(hScreenDC,
        &pdf->elfx->elfLogFont,
        (FONTENUMPROC)FindSystemFontEnum,
        (LPARAM)pdf,
        0);

    // Cleanup
    ReleaseDC(NULL, hScreenDC);
    return fFound;
}

Diese Funktion erkennt, wenn eine Schriftart, die als Geräteschriftart gekennzeichnet ist, aber keine echte Geräteschriftart ist (gemäß der Definition in diesem Artikel). Dies tritt auf, wenn Adobe-Schriftarten entweder über den Adobe Type Manager oder den nativen Adobe-Rasterizer, der in Windows 2000 oder Windows XP vorhanden ist, im System installiert werden.

In diesem Fall handelt es sich bei der Schriftart tatsächlich um eine vom System bereitgestellte Schriftart, die auf den Drucker heruntergeladen wird, was manchmal bei TrueType-Schriftarten vorkommt. Leider gibt es kein Flag, das Sie für Windows 98, Windows Millennium Edition (Me), Windows 2000 und Windows XP verwenden können, das angibt, dass die Schriftart eine Adobe-Schriftart ist, die das System bereitstellt (im Gegensatz zu TrueType-Schriftarten, die ein Flag enthalten). Es gibt einen Hinweis im Member der NEWTEXTMETRIC Struktur ntmFlags , aber dieser ist nur in Windows 2000 und höher verfügbar. Daher muss der Code auf einen Prozess der Beseitigung zurückgreifen. Die Schriftart wird entfernt, wenn IsSystemFontdetermines die Geräteschriftart sowohl vom Bildschirmgerätekontext als auch vom Kontext des Druckergeräts bereitgestellt wird.

Um wiederholte Beispiele einer skalierten Schriftart zu vermeiden, bemerkt der Code auch, wenn bereits eine gewünschte Schriftart verwendet wurde. Die spezifische Implementierung dieser Methode basiert auf der Enumerationsreihenfolge der Schriftarten, um zu sehen, wann sequenzielle Enumerationen einer Schriftart dieselbe Schriftart, aber eine andere Skala aufweisen. Um Schriftarten zu entfernen, die nur eine andere Skala aufweisen, verwendet der Code die CompareLogFontEx -Funktion.

Hinweis

In der Dokumentation zum Programmieren von Windows-Betriebssystemen wird nicht angegeben, dass Schriftartinstanzen, die sich nur nach Skalierung unterscheiden, sequenziell aufgelistet werden. Im Codebeispiel wird diese Technik verwendet, da die Enumeration auf diese Weise funktionierte und die Verringerung der Anzahl von Beispielzeilen auf der gedruckten Seite kein kritisches Feature des Demonstrationscodes ist. Wenn Sie sich darauf verlassen möchten, unterschiedliche Skalierungen derselben Schriftart zu vermeiden, müssen Sie eine Datenstruktur der verwendeten Geräteschriftarten beibehalten. Anschließend muss das Programm die aktuell aufgezählte Schriftart anhand dieser Datenstruktur überprüfen.

Skalierbare im Vergleich zu Bitmap-Schriftarten

Es gibt zwei Arten von Geräteschriftarten, die auf Druckern aufgelistet werden können:

  • Bitmap- oder Rasterschriftarten
  • Skalierbare Schriftarten

Bitmapschriftarten sind Schriftarten, die über eine Zeichensymboldefinition mit einer festen Größe verfügen. Skalierbare Schriftarten sind Schriftarten, die über eine mathematische Definition im Drucker verfügen, sodass sie in jeder Größe gezeichnet werden können. Mit anderen Worten, ihre Größe skaliert.

Das klassische Beispiel für eine Bitmapschriftart ist Courier 10 Zeichen pro Zoll (cpi). Wie der Name schon sagt, ist diese Schriftart ein Haltepunkt für den Übergang von Schreibmaschinen zu Auswirkungsdruckern. Sie wird als Bitmapschriftart bezeichnet, da sich die gängigste Definition der Schriftart in einem ROM-Bitmapbild eines Punktmatrixdruckers befand.

Beispiele für skalierbare, druckerbasierte Schriftarten finden Sie in den meisten PostScript-Druckern, in denen es in der Regel einen Standardsatz von PostScript-Schriftarten wie Helvetica und Times gibt.

Geräteschriftarten, die nicht skalierbar sind, verfügen über ein Bit, das im FontType Parameter der Rückruffunktion festgelegt ist. Dieses Bit wird durch das Symbol RASTER_FONTTYPE im SDK dargestellt. Wenn der FontType Parameter für die Rückruffunktion nicht RASTER_FONTTYPEbit festgelegt ist, ist die Schriftart eine skalierbare Schriftart. Ein Beispiel dafür, wie Dies bestimmt wird, finden Sie in der PrinterDeviceFontEnum Rückruffunktion des Beispielcodes.

Zeichnen der Geräteschriftarten

Nachdem Schriftarten gefunden wurden, bei denen es sich um Geräteschriftarten handelt, werden sie im Beispiel in dem Druckergerätekontext verwendet, für den die Enumeration durchgeführt wurde. Geräteschriftarten werden ähnlich wie andere Schriftarten verwendet, indem eine logische Beschreibung mit der CreateFontIndirect Funktion erstellt wird. Dieser Funktionsaufruf wird übergeben, das LOGFONT an die Rückruffunktion der Schriftartenumeration übergeben wurde. Nachdem der HFONT erstellt wurde, wird es im Kontext des Druckergeräts verwendet, indem es mit dem SelectObject Funktionsaufruf im Gerätekontext ausgewählt wird.

Metriken für die Geräteschriftart werden über den GetTextMetrics Funktionsaufruf abgerufen. Es empfiehlt sich, Druckergerätekontexte mithilfe des MM_TEXT Zuordnungsmodus zu verwenden, bei dem es sich um den Standardzuordnungsmodus für einen Gerätekontext handelt. Wenn Sie den Zuordnungsmodus MM_TEXT verwenden, vermeiden Sie mathematische Fehler, die während des Einheitenkonvertierungsprozesses anderer Zuordnungsmodi auftreten können.

Wenn Sie eine Geräteschriftart im Kontext eines Druckergeräts verwenden, müssen Sie darauf achten, dass Sie die Metriken für die Schriftart und die Zeichenfolgen nicht in andere Gerätekontexte übertragen. Dies gilt insbesondere für Speichergerätekontexte. Per Definition ist ein Speichergerätekontext nicht der Druckauftrag, sondern ein temporärer Speicherpuffer von Rastergrafiken und kann daher keine Geräteschriftart verwenden.

Es gibt einen weiteren wichtigen Aspekt bei der Verwendung von Druckergeräteschriftarten: Sie können keine Vorschau des Typs What-You-See-Is-What-You-Get für den Druckauftrag bereitstellen. Schriftarten, die sich in der Druckerhardware befinden, können nicht auf den Bildschirm gezeichnet werden. Am nächsten können Sie eine Vorschau des Druckauftrags anzeigen, indem Sie eine vom System bereitgestellte Schriftart suchen, die die allgemeinen Merkmale einer Schriftart eines Druckergeräts aufweist, und dann die Glyphen dieser Schriftart auf dem Bildschirm zeichnen, indem Sie die ExtTextOut Funktion verwenden, um die Platzierung der Zeichensymbole auf der gedruckten Seite zu simulieren.

Probleme bei der Verwendung von Geräteschriftarten

Bei der Verwendung von Geräteschriftarten können die folgenden Probleme auftreten:

  • Es gibt eine Geräteschriftart, aber der Druckertreiber listet sie nicht auf.

    Es gibt zwei Gründe, warum Sie eine Geräteschriftart nicht finden können, indem Sie die Schriftarten auflisten, die für die Verwendung im Kontext eines Druckergeräts verfügbar sind:

    • Der Druckertreiber wurde geschrieben, um diese Geräteschriftart aus irgendeinem Grund auszuschließen.
    • Der Druckertreiber listet die Schriftart auf, aber die Schriftart ist im FontType Parameter nicht ordnungsgemäß als Geräteschriftart gekennzeichnet.
  • Es gibt Systemschriftarten, die als Geräteschriftarten aufzuzählen scheinen.

    Dieses Problem tritt auf, wenn eine vom System bereitgestellte Schriftart auf einen Drucker heruntergeladen wird.

    Wenn dies bei TrueType-Schriftarten der Fall ist, empfängt die Rückruffunktion für die Schriftartenumeration einen Aufruf mit und TRUETYPE_FONTTYPE den bits, die DEVICE_FONTTYPE für den FontType Parameter festgelegt sind. Dies wird im Beispielcode behandelt, indem keine Schriftarten eingeschlossen werden, die diese Kombinationen von Bits enthalten.

    Dies geschieht auch bei Adobe PostScript-Schriftarten, die im System installiert sind und auf den Drucker heruntergeladen werden. Eine Möglichkeit, diese Schriftarten von den anderen Geräteschriftarten zu unterscheiden, besteht darin, sie sowohl in einem Systembildschirmgerätekontext als auch im Kontext des Druckergeräts zu suchen. Wenn dieselbe Schriftart in beiden Gerätekontexten aufgelistet werden kann, wird die Schriftart wahrscheinlich auf den Drucker heruntergeladen, wenn sie im Kontext des Druckergeräts verwendet wird.

  • Mein Druckertreiber listet mehrere skalierbare Geräteschriftarten auf, aber sie scheinen mit Ausnahme ihrer Größen identisch zu sein.

    Viele Druckertreiber listen eine skalierbare Schriftart auf, indem sie mehrere verschiedene Instanzen derselben Schriftart mit unterschiedlichen Größen bereitstellen. Dies wird im Beispielcode behandelt, indem die verschiedenen Instanzen der Schriftarten verglichen werden, von denen angenommen wird, dass sie mithilfe der CompareLogFontEx -Funktion skalierbar sind.

    Hinweis

    Wenn der FontType Parameter für die Rückruffunktion festgelegt RASTER_FONTTYPEbit ist, stellen die mehreren Enumerationen Beschreibungen bestimmter Instanzen der nicht skalierbaren Schriftarten für jede Größe bereit. Jeder Rückruf listet die einzigen Größen auf, in denen diese Schriftart verfügbar ist.

  • Einige Drucker scheinen keine Geräteschriftarten zu haben.

    Das stimmt. Einige Drucker, d. h. Tintenstrahldrucker, stellen keine Geräteschriftarten bereit. Bei diesen Druckern handelt es sich ausschließlich um Rastergeräte und daher nicht über druckeridente Schriftartdefinitionen.