Usare i tipi di carattere del dispositivo stampante

I tipi di carattere presenti nelle stampanti possono talvolta essere utili e difficili da usare nel codice del programma dell'applicazione. Questo articolo descrive come determinare quali tipi di carattere del dispositivo residenti nella stampante sono disponibili per l'uso in un contesto di dispositivo della stampante Win32. L'articolo descrive anche diversi problemi che possono verificarsi quando si tenta di usare i tipi di carattere della stampante nel codice dell'applicazione.

Versione originale del prodotto: Dispositivo stampante Win32
Numero KB originale: 201978

Riepilogo

Nella maggior parte dei casi, uno sviluppatore di software si basa sul sistema operativo per fornire i tipi di carattere che verranno usati per il disegno. A tale scopo, è possibile selezionare un tipo di carattere fornito dal sistema operativo tramite l'API (Application Programming Interface) o la finestra di dialogo Scegli carattere comune. Tuttavia, l'applicazione in genere non riguarda il tipo di carattere specifico usato, ma soddisfa solo determinati requisiti e l'utente preferisce il tipo di carattere. I requisiti includono:

  • Il tipo di carattere deve avere una certa dimensione.
  • Il tipo di carattere deve contenere caratteri (noti anche come glifi).
  • Il tipo di carattere deve avere un determinato stile.

In genere, quando l'applicazione stampa il documento, il tipo di carattere (o un tipo di carattere simile a esso) viene usato sulla stampante senza alcuna azione specifica da parte dell'applicazione. Questo è in genere il risultato corretto per l'applicazione e produce buoni risultati stampati a velocità ragionevoli.

Tuttavia, a volte uno sviluppatore di applicazioni potrebbe dover selezionare solo un determinato tipo di carattere specifico da una stampante di destinazione. Storicamente, questo era necessario per le stampanti di tipo impatto (ad esempio, stampanti a matrice di punti) per ottenere una certa formattazione o per velocizzare la stampa.

Oggi, la maggior parte delle stampanti è fondamentalmente progettata come dispositivi raster e può disegnare un punto (un pixel) su qualsiasi parte della carta con la stessa efficienza di tutti i glifi dei caratteri. Per la maggior parte delle applicazioni, non è un problema se un glifo di caratteri viene disegnato come un intero modulo da una definizione residente della stampante o viene disegnato come una raccolta di pixel forniti dal sistema operativo. Tuttavia, è comunque possibile usare un tipo di carattere fornito solo dalla stampante. Ad esempio, questo problema può verificarsi perché il tipo di carattere è univoco e non ha alcun sostituto simile nel sistema operativo o forse perché si vuole evitare il sovraccarico di download di una definizione di tipo di carattere nella stampante.

Tipi di carattere del dispositivo

Ai fini di questo articolo, i tipi di carattere del dispositivo sono qualsiasi tipo di carattere la cui definizione esiste in modo permanente o temporaneo nella memoria della stampante. Questi tipi di carattere del dispositivo forniscono una definizione di glifo di caratteri che può essere indirizzata per carattere dall'hardware del rasterizzatore della pagina della stampante per inchiostrare la forma sulla carta.

I tipi di carattere del dispositivo possono essere classificati in tre tipi di base:

  • Caratteri del dispositivo true. Ai fini di questo articolo, si tratta di tipi di carattere forniti solo dall'hardware della stampante e che è possibile usare solo sulla stampante.

  • Sostituzione del tipo di carattere del dispositivo. Tipi di carattere presenti nel sistema operativo e forniti anche dall'hardware della stampante. In questo caso, l'hardware della stampante può sostituire i tipi di carattere del sistema operativo.

  • Tipi di carattere scaricabili. Tipi di carattere forniti dal sistema operativo, ma la cui definizione può essere scaricata nella stampante e usata sulla stampante come se l'hardware della stampante fornisse direttamente i tipi di carattere.

Tipi di carattere scaricabili

Il sistema operativo fornisce tipi di carattere scaricabili, noti anche come tipi di carattere soft. Quando si stampa un documento, la definizione per il tipo di carattere viene fornita come parte del processo di stampa. Quando la stampante elabora il processo di stampa, la definizione del tipo di carattere viene installata nella memoria della stampante in modo che la definizione del tipo di carattere possa essere attivata nella pagina stampata del documento.

Alcuni sostengono che, poiché la stampante sta disegnando i glifi carattere del carattere, questi tipi di carattere sono tipi di carattere dispositivo. Tuttavia, quando una definizione di carattere viene scaricata o quando un glifo viene disegnato sulla stampante tramite una bitmap, vengono salvate solo alcune dimensioni dello spooling del processo di stampa o sovraccarico. Questo processo viene eseguito in modo trasparente per l'applicazione in modo che il tipo di carattere nel sistema operativo possa essere utilizzato sullo schermo e sulla stampante. Poiché questo articolo è incentrato su come usare i tipi di carattere del dispositivo forniti solo dalla stampante, questo articolo non descrive come usare i tipi di carattere scaricabili.

Sostituzione del tipo di carattere del dispositivo

La sostituzione dei tipi di carattere del dispositivo si verifica quando sono presenti due definizioni di tipi di carattere distinte: una usata dal sistema operativo e una usata dalla stampante. Ovvero, un'applicazione seleziona e usa un tipo di carattere nel sistema operativo in un documento sullo schermo. Quando si stampa il documento, l'output stampato viene disegnato usando il tipo di carattere definito in modo analogo fornito dalla stampante. Pertanto, il tipo di carattere nel sistema operativo è stato sostituito nella stampante con il tipo di carattere definito dalla stampante.

Ciò si verifica in genere nelle stampanti PostScript quando viene usato un tipo di carattere Windows TrueType comune. Un esempio è il tipo di carattere TrueType Arial che viene in genere stampato usando la definizione del carattere PostScript per il tipo di carattere Helvetica nella maggior parte dei dispositivi PostScript. Questo è un esempio di sostituzione usando un tipo di carattere simile il cui nome del carattere è diverso. In questo caso, è in genere possibile trovare e usare direttamente questa definizione di tipo di carattere simile perché la definizione di tipo di carattere simile viene esposta anche come tipo di carattere del dispositivo reale. Questo argomento è illustrato più avanti in questo articolo.

La sostituzione del tipo di carattere del dispositivo si verifica anche quando il tipo di carattere nella stampante ha lo stesso nome del tipo di carattere fornito dal sistema operativo. Ciò si verifica in genere su stampanti come Hewlett-Packard stampanti LaserJet. Tali stampanti hanno in genere le proprie versioni dei tipi di carattere di base di Windows, ad esempio Arial e Times New Roman. Anche se questi tipi di carattere possono essere trovati anche in genere cercando i veri tipi di carattere del dispositivo, il loro uso a volte non può essere garantito perché i driver della stampante spesso selezionano autonomamente o selezionano tramite le impostazioni utente se usare il tipo di carattere fornito dal sistema operativo.

Caratteri del dispositivo true

I caratteri del dispositivo true sono quelli che hanno solo una definizione sulla stampante. L'unico modo in cui un'applicazione può usare questi tipi di carattere consiste nell'identificare in modo specifico il tipo di carattere e crearlo per l'uso nel contesto del dispositivo della stampante.

Se si conoscono informazioni sufficienti su un dispositivo, è possibile creare una descrizione del carattere logico in una LOGFONT struttura che comporterà la realizzazione del tipo di carattere del dispositivo. In particolare, è importante fornire le informazioni corrette per il lfFacename membro, il lfHeight membro e il set di caratteri del tipo di carattere. Inoltre, il lfOutPrecision membro deve contenere un OUT_DEVICE_PRECIS flag per influenzare il processo di mapping dei tipi di carattere per scegliere i tipi di carattere del dispositivo anziché i tipi di carattere di sistema denominati in modo analogo.

Se la descrizione del tipo di carattere non è nota, è possibile enumerare i tipi di carattere per individuare i tipi di carattere del dispositivo. Per ottenere un elenco dei tipi di carattere del dispositivo supportati dalla stampante, usare una delle funzioni di enumerazione dei tipi di carattere, ad EnumFontFamiliesExesempio . Il codice dell'applicazione inserito nella funzione di callback può esaminare i dati passati alla funzione di callback per determinare quali istanze del tipo di carattere descrivono un tipo di carattere del dispositivo.

Usare i caratteri del dispositivo true

Il processo di utilizzo di un tipo di carattere del dispositivo in un contesto di dispositivo della stampante segue questi passaggi generali:

  1. Identificare i veri tipi di carattere del dispositivo tramite l'enumerazione dei tipi di carattere in un contesto di dispositivo della stampante.
  2. Selezionare i tipi di carattere che sono solo dispositivo come indicato dai FontType flag e dal processo di eliminazione.
  3. Usare metriche specifiche della MM_TEXT stampante nella modalità di mapping per posizionare accuratamente il testo disegnato usando il tipo di carattere del dispositivo.

Enumerare i tipi di carattere di un contesto di dispositivo della stampante

Per enumerare tutti i tipi di carattere disponibili in un contesto di dispositivo, è possibile usare le funzioni di callback e la EnumFontFamiliesEx funzione dall'API (Application Programming Interface) Win32. Per enumerare tutti i tipi di carattere per un contesto di dispositivo, è necessario chiamare EnumFontFamiliesEx due volte: prima di tutto per ottenere un elenco di famiglie di tipi di carattere e una seconda volta per ottenere tutti i tipi di carattere distinti che si trovano in ogni famiglia di caratteri.

Per trovare tutti i tipi di carattere del dispositivo in un contesto di dispositivo della stampante, è necessario enumerare tutti i tipi di carattere del contesto del dispositivo della stampante. Quando ogni tipo di carattere viene passato alle funzioni di callback, il tipo di carattere viene esaminato per determinare se si tratta di un tipo di carattere del dispositivo. Le PrinterDeviceFontEnum funzioni di callback e PrinterDeviceFontFamiliesEnum nel codice di esempio seguente eseguono questa operazione.

// 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;
}

È possibile visualizzare nel codice di esempio in cui la EnumFontFamiliesEx funzione viene chiamata due volte. La prima chiamata viene eseguita nella PrintDeviceFontList funzione . La seconda chiamata si trova nella PrinterDeviceFontFamiliesEnum funzione di callback.

PrintDeviceFontList è la funzione di primo livello. PrintDeviceFontList esegue due attività avviando un processo di stampa nel contesto del dispositivo della stampante e quindi richiamando la prima chiamata a per EnumFontFamiliesEx avviare il processo di enumerazione dei tipi di carattere. In base alla documentazione di Platform Software Development Kit (SDK), quando si imposta il LOGFONT membro della lfCharSet struttura sul DEFAULT_CHARSET valore , EnumFontFamiliesEx enumera tutte le famiglie di tipi di carattere. Al termine dell'enumerazione dei tipi di carattere, il codice completa l'attività di gestione del processo di stampa chiamando il EndDoc metodo .

La PrinterDeviceFontFamiliesEnum funzione di callback viene chiamata per ogni famiglia di caratteri dalla EnumFontFamiliesEx funzione . In tale funzione di callback, il codice inizialmente controlla le famiglie di tipi di carattere per trovare solo i tipi di carattere del dispositivo contrassegnati dal FontType parametro . Vengono inoltre visualizzati tutti i tipi di carattere contrassegnati come TrueType perché è probabile che tali tipi di carattere siano scaricabili. Per le famiglie di tipi di carattere considerate tipi di carattere del dispositivo, la EnumFontFamiliesEx funzione viene chiamata di nuovo, ma viene passata la ENUMLOGFONTEX struttura ricevuta dalla funzione di callback. L'uso del parametro di callback come parametro di input per la seconda chiamata di funzione di enumerazione fa sì che la seconda enumerazione elenchi tutti i tipi di carattere distinti nella famiglia di tipi di carattere.

Selezionare i tipi di carattere del dispositivo

È possibile usare determinati criteri dei tipi di carattere del dispositivo stampante per distinguere questi tipi di carattere da qualsiasi altro tipo di carattere enumerato. In particolare, cercare il DEVICE_FONTTYPE valore nel FontType parametro DWORD della funzione di callback. Quasi tutti i tipi di carattere che vengono consegnati alla funzione di callback con questo valore impostato sono tipi di carattere del dispositivo per il contesto del dispositivo della stampante (ad eccezione dei tipi di carattere Adobe).

Nel codice di esempio, la PrinterDeviceFontEnum funzione di callback viene chiamata dalla seconda enumerazione per ogni tipo di carattere distinto nella famiglia di tipi di carattere. La PrinterDeviceFontEnum funzione di callback esegue tre attività:

  • Usa nuovamente i criteri del tipo di carattere del dispositivo per assicurarsi che la funzione elabori solo i tipi di carattere riconosciuti come tipi di carattere del dispositivo.

  • Cerca il tipo di carattere usando un'altra enumerazione per verificare se il tipo di carattere del dispositivo viene usato anche nel contesto del dispositivo dello schermo del sistema.

  • Stampa un esempio del tipo di carattere nel processo di stampa che viene creato per illustrare l'uso del tipo di carattere. Questa funzione di callback usa una funzione denominata IsSystemFont, che fa parte del codice di esempio seguente:

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;
}

Questa funzione rileva quando un tipo di carattere contrassegnato come tipo di carattere del dispositivo ma non è un vero tipo di carattere del dispositivo (in base alla definizione in questo articolo). Ciò si verifica quando i tipi di carattere Adobe vengono installati nel sistema tramite Adobe Type Manager o tramite il rasterizzatore Adobe nativo presente in Windows 2000 o Windows XP.

In questo caso, il tipo di carattere è in realtà un tipo di carattere fornito dal sistema scaricato nella stampante, che a volte si verifica con i tipi di carattere TrueType. Sfortunatamente, non esiste alcun flag che puoi usare in Windows 98, Windows Millennium Edition (Me), Windows 2000 e Windows XP che indica che il tipo di carattere è un carattere Adobe fornito dal sistema (a differenza dei tipi di carattere TrueType, che includono un flag). Esiste un'indicazione nel NEWTEXTMETRIC membro della ntmFlags struttura, ma è disponibile solo in Windows 2000 e versioni successive. Pertanto, il codice deve ricorrere a un processo di eliminazione. Il tipo di carattere viene rimosso quando IsSystemFontdetermines il tipo di carattere del dispositivo viene fornito sia dal contesto del dispositivo dello schermo che dal contesto del dispositivo della stampante.

Per evitare esempi ripetitivi di un tipo di carattere ridimensionato, il codice nota anche quando è già stato usato un tipo di carattere candidato. L'implementazione specifica di questo si basa sull'ordine di enumerazione dei tipi di carattere per vedere quando le enumerazioni sequenziali di un tipo di carattere sono lo stesso tipo di carattere, ma in una scala diversa. Per rimuovere i tipi di carattere che sono solo una scala diversa, il codice usa la CompareLogFontEx funzione .

Nota

La documentazione per la programmazione dei sistemi operativi Windows non indica che le istanze dei tipi di carattere che differiscono solo per scala verranno enumerate in sequenza. L'esempio di codice usa questa tecnica perché l'enumerazione funziona in questo modo e la riduzione del numero di righe di esempio nella pagina stampata non è una funzionalità critica del codice dimostrativo. Se si vuole fare affidamento sull'eliminazione di scale diverse dello stesso tipo di carattere, è necessario mantenere una struttura di dati dei tipi di carattere del dispositivo usati. Il programma deve quindi controllare il tipo di carattere attualmente enumerato in base a tale struttura di dati.

Tipi di carattere scalabili e bitmap

Esistono due tipi di tipi di carattere del dispositivo che possono essere enumerati nelle stampanti:

  • Tipi di carattere bitmap o raster
  • Tipi di carattere scalabili

I tipi di carattere bitmap sono tipi di carattere con una definizione di glifo di caratteri di dimensioni fisse. I tipi di carattere scalabili sono tipi di carattere che hanno una definizione basata su matematica nella stampante in modo che possano essere disegnati a qualsiasi dimensione. In altre parole, le dimensioni vengono ridimensionate.

L'esempio classico di un tipo di carattere bitmap è Courier 10 caratteri per pollice (cpi). Come suggerisce il nome, questo tipo di carattere è un blocco dalla transizione dalle macchine da scrivere alle stampanti di tipo impatto. Viene chiamato tipo di carattere bitmap perché la definizione più comune del tipo di carattere si trovava in un'immagine bitmap rom di una stampante a matrice di punti.

Esempi di tipi di carattere scalabili residenti nella stampante sono disponibili nella maggior parte delle stampanti PostScript in cui è in genere presente un set standard di tipi di carattere PostScript, ad esempio Helvetica e Times.

I tipi di carattere del dispositivo non scalabili hanno un bit impostato nel FontType parametro della funzione di callback. Tale bit è rappresentato dal simbolo RASTER_FONTTYPE nell'SDK. Se il FontType parametro per la funzione di callback non ha il RASTER_FONTTYPEbit valore impostato, il tipo di carattere è un tipo di carattere scalabile. Per un esempio di come determinarlo, vedere la PrinterDeviceFontEnum funzione di callback del codice di esempio.

Disegnare i tipi di carattere del dispositivo

Dopo aver trovato i tipi di carattere che sono tipi di carattere del dispositivo, l'esempio li usa nel contesto del dispositivo della stampante in cui è stata eseguita l'enumerazione. I tipi di carattere del dispositivo vengono usati in modo analogo ad altri tipi di carattere creando una descrizione logica con la CreateFontIndirect funzione . Questa chiamata di funzione viene passata all'oggetto LOGFONT passato alla funzione di callback dell'enumerazione dei tipi di carattere. Dopo la HFONT creazione, viene usato nel contesto del dispositivo della stampante selezionandolo nel contesto del dispositivo con la chiamata di SelectObject funzione.

Le metriche per il tipo di carattere del dispositivo vengono ottenute tramite la chiamata di GetTextMetrics funzione. È consigliabile operare nei contesti del dispositivo della stampante usando la MM_TEXT modalità di mapping, ovvero la modalità di mapping predefinita per un contesto di dispositivo. Quando si usa la MM_TEXT modalità di mapping, si evitano errori matematici che possono verificarsi durante il processo di conversione delle unità di altre modalità di mapping.

Quando si usa un tipo di carattere del dispositivo in un contesto di dispositivo della stampante, è necessario prestare attenzione a non trasportare le metriche per il tipo di carattere e le stringhe in altri contesti di dispositivo. Questo vale in particolare per i contesti dei dispositivi di memoria. Per definizione, un contesto del dispositivo di memoria non è il processo di stampa, ma è un buffer di memoria temporaneo di grafica raster e pertanto non può usare un tipo di carattere del dispositivo.

C'è un'altra considerazione significativa quando si usano i tipi di carattere del dispositivo della stampante: non è possibile fornire un'anteprima del tipo What-You-See-Is-What-You-Get del processo di stampa. Chiaramente, i tipi di carattere che risiedono nell'hardware della stampante non possono essere disegnati sullo schermo. Il più vicino possibile per visualizzare in anteprima il processo di stampa è quello di trovare un tipo di carattere fornito dal sistema che abbia le caratteristiche generali di un tipo di carattere del dispositivo stampante e quindi disegnare i glifi di tale tipo di carattere sullo schermo usando la ExtTextOut funzione per simulare il posizionamento dei glifi carattere nella pagina stampata.

Problemi relativi all'uso dei tipi di carattere del dispositivo

È possibile che si verifichino i problemi seguenti quando si usano i tipi di carattere del dispositivo:

  • È presente un tipo di carattere del dispositivo, ma il driver della stampante non lo enumera.

    Esistono due motivi per cui non è possibile trovare un tipo di carattere del dispositivo enumerando i tipi di carattere disponibili per l'uso in un contesto di dispositivo stampante:

    • Il driver della stampante è stato scritto per escludere il tipo di carattere del dispositivo per qualche motivo.
    • Il driver della stampante enumera il tipo di carattere, ma il tipo di carattere non è contrassegnato correttamente nel FontType parametro come tipo di carattere del dispositivo.
  • Esistono tipi di carattere di sistema che sembrano enumerare come tipi di carattere del dispositivo.

    Questo problema si verifica quando un tipo di carattere fornito dal sistema viene scaricato in una stampante.

    Quando ciò si verifica con i tipi di carattere TrueType, la funzione di callback dell'enumerazione dei tipi di carattere riceve una chiamata con e TRUETYPE_FONTTYPE i DEVICE_FONTTYPE bit impostati sul FontType parametro . Questa operazione viene gestita nel codice di esempio, senza includere tipi di carattere che contengono queste combinazioni di bit.

    Ciò si verifica anche con i tipi di carattere Adobe PostScript installati nel sistema scaricati nella stampante. Un modo per differenziare questi tipi di carattere dagli altri tipi di carattere del dispositivo consiste nel cercarli sia nel contesto del dispositivo dello schermo del sistema che nel contesto del dispositivo della stampante. Se lo stesso tipo di carattere può essere enumerato in entrambi i contesti del dispositivo, è probabile che il tipo di carattere venga scaricato nella stampante quando viene usato nel contesto del dispositivo della stampante.

  • Il driver della stampante enumera diversi tipi di carattere del dispositivo scalabili, ma sembrano essere gli stessi tranne le dimensioni.

    Molti driver della stampante enumerano un tipo di carattere scalabile fornendo diverse istanze dello stesso tipo di carattere con dimensioni diverse. Questa operazione viene gestita nel codice di esempio confrontando le varie istanze dei tipi di carattere che si presume siano scalabili usando la CompareLogFontEx funzione .

    Nota

    Quando il FontType parametro per la funzione di callback è RASTER_FONTTYPEbit impostato, le più enumerazioni forniscono descrizioni di istanze specifiche dei tipi di carattere non scalabili per ogni dimensione. Ogni callback enumera le uniche dimensioni in cui tale tipo di carattere è disponibile.

  • Alcune stampanti sembrano non avere tipi di carattere del dispositivo.

    Questo è vero. Alcune stampanti, vale a dire stampanti a getto d'inchiostro, non forniscono tipi di carattere del dispositivo. Queste stampanti sono esclusivamente dispositivi raster e pertanto non hanno definizioni di carattere residenti nella stampante.