Printerapparaatlettertypen gebruiken

De lettertypen in printers kunnen soms nuttig en moeilijk te gebruiken zijn in toepassingsprogrammacode. In dit artikel wordt beschreven hoe u kunt bepalen welke printer-resident apparaatlettertypen beschikbaar zijn voor gebruik in een Win32-printerapparaatcontext. In het artikel worden ook verschillende problemen beschreven die kunnen optreden wanneer u deze printerlettertypen in toepassingscode probeert te gebruiken.

Oorspronkelijke productversie: Win32-printerapparaat
Origineel KB-nummer: 201978

Samenvatting

In de meeste gevallen is een softwareontwikkelaar afhankelijk van het besturingssysteem om de lettertypen op te geven die voor de tekening worden gebruikt. Hiervoor kunt u een door het besturingssysteem opgegeven lettertype selecteren via de API (Application Programming Interface) of via het algemene dialoogvenster Lettertype kiezen . De toepassing houdt zich echter meestal niet bezig met het specifieke lettertype dat wordt gebruikt, maar voldoet aan bepaalde vereisten en de gebruiker geeft de voorkeur aan het lettertype. Deze vereisten omvatten:

  • Lettertype moet een bepaalde grootte hebben.
  • Het lettertype moet tekens bevatten (ook wel glyphs genoemd).
  • Lettertype moet een bepaalde stijl hebben.

Wanneer de toepassing het document afdrukt, wordt het lettertype (of een lettertype dat er op lijkt) doorgaans op de printer gebruikt zonder dat de toepassing een bepaalde actie hoeft uit te voeren. Dit is over het algemeen het juiste resultaat voor de toepassing en dit levert goede afdrukresultaten op redelijke snelheden op.

Soms hoeft een toepassingsontwikkelaar echter alleen een bepaald lettertype specifiek van een doelprinter te selecteren. In het verleden was dit nodig voor impactprinters (bijvoorbeeld puntmatrixprinters) om bepaalde opmaak te verkrijgen of om het afdrukken te versnellen.

Tegenwoordig zijn de meeste printers fundamenteel ontworpen als rasterapparaten en kunnen ze net zo efficiënt een punt (een pixel) op elk deel van het papier tekenen als alle tekentekens. Voor de meeste toepassingen is het geen probleem of een tekentekenteken als een hele vorm wordt getekend vanuit een definitie van de printer resident of wordt getekend als een verzameling pixels die het besturingssysteem biedt. U kunt echter nog steeds een lettertype gebruiken dat alleen door de printer wordt geleverd. Dit kan bijvoorbeeld gebeuren omdat het lettertype uniek is en geen vergelijkbare vervanging heeft in het besturingssysteem of omdat u de overhead van het downloaden van een lettertypedefinitie naar de printer wilt voorkomen.

Apparaatlettertypen

Voor de doeleinden van dit artikel zijn apparaatlettertypen alle lettertypen waarvan de definitie permanent of tijdelijk in het printergeheugen aanwezig is. Deze apparaatlettertypen bieden een tekenglyph-definitie die per teken kan worden geadresseerd door de hardware voor paginarasterizer van de printer om de vorm op papier te inkten.

Apparaatlettertypen kunnen worden onderverdeeld in drie basistypen:

  • Echte apparaatlettertypen. Voor de doeleinden van dit artikel zijn dit lettertypen die alleen door de printerhardware worden geleverd en die u alleen op de printer kunt gebruiken.

  • Vervanging van apparaatlettertype. Lettertypen die aanwezig zijn in het besturingssysteem en die ook door de printerhardware worden geleverd. In dit geval kan de printerhardware de lettertypen van het besturingssysteem vervangen.

  • Downloadbare lettertypen. Lettertypen die door het besturingssysteem worden verstrekt, maar waarvan de definitie naar de printer kan worden gedownload en op de printer kan worden gebruikt alsof de printerhardware de lettertypen rechtstreeks levert.

Downloadbare lettertypen

Het besturingssysteem biedt downloadbare lettertypen, die ook wel zachte lettertypen worden genoemd. Wanneer u een document afdrukt, wordt de definitie voor het lettertype opgegeven als onderdeel van de afdruktaak. Wanneer de printer de afdruktaak verwerkt, wordt de lettertypedefinitie in het printergeheugen geïnstalleerd, zodat de lettertypedefinitie op de afgedrukte pagina van het document kan worden geschreven.

Sommigen beweren dat omdat de printer de tekentekens van het lettertype tekent, deze lettertypen apparaatlettertypen zijn. Wanneer echter een lettertypedefinitie wordt gedownload of wanneer een teksttekst via een bitmap op de printer wordt getekend, wordt alleen een bepaalde overhead- of afdruktaakspoolgrootte opgeslagen. Dit proces vindt transparant plaats voor de toepassing, zodat het lettertype in het besturingssysteem kan worden gebruikt op het scherm en op de printer. Omdat dit artikel zich richt op het gebruik van apparaatlettertypen die alleen door de printer worden geleverd, wordt in dit artikel niet beschreven hoe u downloadbare lettertypen gebruikt.

Apparaatlettertype vervangen

Vervanging van apparaatlettertype vindt plaats wanneer er twee verschillende lettertypedefinities zijn: een die door het besturingssysteem wordt gebruikt en één die door de printer wordt gebruikt. Dat wil gezegd, een toepassing selecteert en gebruikt een lettertype in het besturingssysteem in een document op het scherm. Wanneer u het document afdrukt, wordt de afgedrukte uitvoer getekend met behulp van het lettertype dat de printer opgeeft. Daarom is het lettertype in het besturingssysteem op de printer vervangen door het door de printer gedefinieerde lettertype.

Dit gebeurt meestal op PostScript-printers wanneer een algemeen Windows TrueType-lettertype wordt gebruikt. Een voorbeeld hiervan is het TrueType Arial-lettertype dat op de meeste PostScript-apparaten doorgaans wordt afgedrukt met behulp van de PostScript-lettertypedefinitie voor het lettertype Helvetica. Dit is een voorbeeld van een vervanging door gebruik te maken van een vergelijkbaar lettertype waarvan de lettertypenaam anders is. In dit geval kunt u deze vergelijkbare lettertypedefinitie meestal rechtstreeks vinden en gebruiken, omdat de vergelijkbare lettertypedefinitie ook wordt weergegeven als een echt apparaatlettertype. Dit wordt verderop in dit artikel besproken.

Vervanging van apparaatlettertype treedt ook op wanneer het lettertype op de printer dezelfde naam heeft als het lettertype dat het besturingssysteem biedt. Dit gebeurt meestal op printers zoals Hewlett-Packard LaserJet-printers. Deze printers hebben meestal hun eigen versies van de Windows-kernlettertypen, zoals Arial en Times New Roman. Hoewel deze lettertypen meestal ook kunnen worden gevonden door te zoeken naar echte apparaatlettertypen, kan het gebruik ervan soms niet worden gegarandeerd omdat de printerstuurprogramma's vaak zelf of via de gebruikersinstellingen selecteren of ze het lettertype willen gebruiken dat het besturingssysteem biedt.

Echte apparaatlettertypen

Echte apparaatlettertypen zijn lettertypen die alleen een definitie op de printer hebben. De enige manier waarop een toepassing deze lettertypen kan gebruiken, is dat de toepassing het lettertype specifiek identificeert en maakt voor gebruik in de context van het printerapparaat.

Als u voldoende informatie over een apparaat weet, kunt u een logische lettertypebeschrijving maken in een LOGFONT structuur die resulteert in de realisatie van het apparaatlettertype. Het is met name belangrijk om de juiste informatie op te geven voor het lfFacename lid, het lfHeight lid en de tekenset van het lettertype. lfOutPrecision Het lid moet ook een OUT_DEVICE_PRECIS vlag bevatten om het proces voor lettertypetoewijzing te beïnvloeden om apparaatlettertypen te kiezen in plaats van systeemlettertypen met een vergelijkbare naam.

Als de beschrijving van het lettertype niet bekend is, kunt u lettertypen opsommen om apparaatlettertypen te detecteren. Als u een lijst met apparaatlettertypen wilt ophalen die door de printer worden ondersteund, gebruikt u een van de opsommingsfuncties voor lettertypen, zoals EnumFontFamiliesEx. Toepassingscode die in de callback-functie wordt geplaatst, kan de gegevens onderzoeken die worden overgedragen aan de callback-functie om te bepalen welke lettertype-exemplaren een apparaatlettertype beschrijven.

Echte apparaatlettertypen gebruiken

Het gebruik van een apparaatlettertype in de context van een printerapparaat volgt deze algemene stappen:

  1. Identificeer de werkelijke apparaatlettertypen door de lettertypen in de context van een printerapparaat op te sommen.
  2. Selecteer lettertypen die alleen apparaat zijn, zoals wordt aangegeven door de FontType vlaggen en door het verwijderingsproces.
  3. Gebruik printerspecifieke metrische gegevens in de MM_TEXT toewijzingsmodus om de tekst die wordt getekend met behulp van het apparaatlettertype nauwkeurig te plaatsen.

De lettertypen van een printerapparaatcontext opsommen

Als u alle lettertypen wilt opsommen die beschikbaar zijn in een apparaatcontext, kunt u callback-functies en de EnumFontFamiliesEx functie van de Win32 Application Programming Interface (API) gebruiken. Als u alle lettertypen voor een apparaatcontext wilt opsommen, moet u twee keer bellen EnumFontFamiliesEx : eerst om een lijst met lettertypefamilies op te halen en een tweede keer om alle afzonderlijke lettertypen in elke lettertypefamilie op te halen.

Als u alle apparaatlettertypen wilt vinden in de context van een printerapparaat, moet u alle lettertypen van de context van het printerapparaat opsommen. Wanneer elk lettertype wordt doorgegeven aan de callback-functies, wordt het lettertype onderzocht om te bepalen of het een apparaatlettertype is. De PrinterDeviceFontEnum functies en PrinterDeviceFontFamiliesEnum callback in de volgende voorbeeldcode voeren deze bewerking uit.

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

U kunt in de voorbeeldcode zien waar de EnumFontFamiliesEx functie twee keer wordt aangeroepen. De eerste aanroep wordt uitgevoerd in de PrintDeviceFontList functie. De tweede aanroep bevindt zich in de PrinterDeviceFontFamiliesEnum callback-functie.

PrintDeviceFontList is de functie op het hoogste niveau. PrintDeviceFontList voert twee taken uit door een afdruktaak te starten in de context van het printerapparaat en vervolgens de eerste aanroep aan te roepen om EnumFontFamiliesEx het opsommingsproces voor lettertypen te starten. Volgens de sdk-documentatie (Platform Software Development Kit) worden alle lettertypefamilies opgesomd wanneer u het lid van lfCharSet de LOGFONT structuur instelt op de DEFAULT_CHARSET waardeEnumFontFamiliesEx. Nadat de opsomming van het lettertype is voltooid, voltooit de code de taak voor afdruktaakbeheer door de methode aan te EndDoc roepen.

De PrinterDeviceFontFamiliesEnum functie callback wordt voor elke lettertypefamilie aangeroepen door de EnumFontFamiliesEx functie. In die callback-functie wordt met de code in eerste instantie de lettertypefamilies gescreend om alleen de apparaatlettertypen te vinden die zijn gemarkeerd met de FontType parameter. Ook worden alle lettertypen die zijn gemarkeerd als TrueType weergegeven, uitgelicht, omdat deze lettertypen waarschijnlijk te downloaden lettertypen zijn. Voor de lettertypefamilies die als apparaatlettertypen worden beschouwd, wordt de EnumFontFamiliesEx functie opnieuw aangeroepen, maar wordt de ENUMLOGFONTEX structuur doorgegeven die de callback-functie heeft ontvangen. Het gebruik van de callback-parameter als invoerparameter voor de tweede opsommingsfunctieaanroep zorgt ervoor dat de tweede opsomming alle afzonderlijke lettertypen in die lettertypefamilie weergeeft.

Apparaatlettertypen selecteren

U kunt bepaalde criteria van printerapparaatlettertypen gebruiken om deze lettertypen te onderscheiden van elk ander lettertype dat is geïnventariseerd. Zoek met name naar de DEVICE_FONTTYPE waarde in de DWORD-parameter van de FontType callback-functie. Bijna alle lettertypen die met deze waardeset aan de callback-functie worden overgedragen, zijn apparaatlettertypen voor de printerapparaatcontext (behalve met Adobe-lettertypen).

In de voorbeeldcode wordt de PrinterDeviceFontEnum callback-functie aangeroepen door de tweede opsomming voor elk afzonderlijk lettertype in de lettertypefamilie. De PrinterDeviceFontEnum callback-functie voert drie taken uit:

  • Gebruikt opnieuw de apparaatlettertypecriteria om ervoor te zorgen dat de functie alleen lettertypen verwerkt die worden herkend als apparaatlettertypen.

  • Hiermee zoekt u naar het lettertype met behulp van een andere opsomming van lettertypen om te zien of het apparaatlettertype ook wordt gebruikt in de context van het schermapparaat van het systeem.

  • Hiermee wordt een voorbeeld van het lettertype afgedrukt in de afdruktaak die wordt gemaakt om het gebruik van het lettertype te demonstreren. Deze callback-functie maakt gebruik van een functie met de naam IsSystemFont, die deel uitmaakt van de volgende voorbeeldcode:

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

Deze functie detecteert wanneer een lettertype dat is gemarkeerd als apparaatlettertype, maar geen echt apparaatlettertype is (volgens de definitie in dit artikel). Dit gebeurt wanneer Adobe-lettertypen in het systeem worden geïnstalleerd via Adobe Type Manager of via de systeemeigen Adobe-rasterizer die aanwezig is in Windows 2000 of Windows XP.

Wanneer dit gebeurt, is het lettertype in feite een door het systeem geleverd lettertype dat wordt gedownload naar de printer, wat soms voorkomt met TrueType-lettertypen. Helaas is er geen vlag die u kunt gebruiken in Windows 98, Windows Millennium Edition (Me), Windows 2000 en Windows XP die aangeeft dat het lettertype een Adobe-lettertype is dat het systeem biedt (in tegenstelling tot TrueType-lettertypen, die een vlag bevatten). Er is een indicatie in het lid van ntmFlags de NEWTEXTMETRIC structuur, maar deze is alleen beschikbaar in Windows 2000 en hoger. Daarom moet de code zijn toevlucht nemen tot een verwijderingsproces. Het lettertype wordt verwijderd wanneer IsSystemFontdetermines het apparaatlettertype wordt geleverd door zowel de schermcontext van het apparaat als de context van het printerapparaat.

Om herhalingsvoorbeelden van een lettertype dat wordt geschaald te voorkomen, wordt in de code ook vermeld wanneer een kandidaatlettertype al is gebruikt. De specifieke implementatie hiervan is afhankelijk van de opsommingsvolgorde van de lettertypen om te zien wanneer opeenvolgende opsommingen van een lettertype hetzelfde lettertype zijn, maar in een andere schaal. Als u lettertypen wilt verwijderen die alleen een andere schaal hebben, gebruikt de code de CompareLogFontEx functie.

Opmerking

In de documentatie voor het programmeren van Windows-besturingssystemen wordt niet vermeld dat lettertype-exemplaren die alleen op schaal verschillen, opeenvolgend worden geïnventariseerd. Het codevoorbeeld maakt gebruik van deze techniek omdat de opsomming op deze manier werkt en het verminderen van het aantal voorbeeldregels op de afgedrukte pagina geen essentieel kenmerk is van de demonstratiecode. Als u wilt vertrouwen op het elimineren van verschillende schalen van hetzelfde lettertype, moet u een gegevensstructuur behouden van de apparaatlettertypen die worden gebruikt. Vervolgens moet het programma het momenteel opgesomde lettertype controleren op basis van die gegevensstructuur.

Schaalbare versus bitmaplettertypen

Er zijn twee typen apparaatlettertypen die kunnen worden opgesomd op printers:

  • Bitmap- of rasterlettertypen
  • Schaalbare lettertypen

Bitmaplettertypen zijn lettertypen met een definitie van een teken met een vaste grootte. Schaalbare lettertypen zijn lettertypen met een definitie op basis van wiskunde in de printer, zodat ze op elke grootte kunnen worden getekend. Met andere woorden, hun grootte wordt geschaald.

Het klassieke voorbeeld van een bitmaplettertype is Courier 10 tekens per inch (cpi). Zoals de naam al aangeeft, is dit lettertype een overslag van de overgang van typemachines naar impact-typeprinters. Dit wordt een bitmaplettertype genoemd omdat de meest voorkomende definitie van het lettertype zich bevond in een ROM-bitmapafbeelding van een dot-matrixprinter.

Voorbeelden van schaalbare, printer-resident lettertypen zijn te vinden in de meeste PostScript-printers waar meestal een standaardset PostScript-lettertypen is, zoals Helvetica en Times.

Apparaatlettertypen die niet schaalbaar zijn, hebben een bit die is ingesteld in de FontType parameter van de callback-functie. Die bit wordt vertegenwoordigd door het symbool RASTER_FONTTYPE in de SDK. Als de FontType parameter voor de callback-functie niet is RASTER_FONTTYPEbit ingesteld, is het lettertype een schaalbaar lettertype. Zie de callback-functie van de PrinterDeviceFontEnum voorbeeldcode voor een voorbeeld van hoe u dit kunt bepalen.

De apparaatlettertypen tekenen

Nadat lettertypen die apparaatlettertypen zijn gevonden, worden deze in het voorbeeld gebruikt in de context van het printerapparaat waarop de opsomming is uitgevoerd. Apparaatlettertypen worden net als andere lettertypen gebruikt door een logische beschrijving te maken met de CreateFontIndirect functie. Deze functieaanroep wordt doorgegeven aan de LOGFONT die is doorgegeven aan de callback-functie voor de opsomming van lettertypen. Nadat de HFONT is gemaakt, wordt deze gebruikt in de context van het printerapparaat door deze te selecteren in de apparaatcontext met de SelectObject functie-aanroep.

Metrische gegevens voor het apparaatlettertype worden verkregen via de GetTextMetrics functie-aanroep. U kunt het beste werken op printerapparaatcontexten met behulp van de MM_TEXT toewijzingsmodus. Dit is de standaardtoewijzingsmodus voor een apparaatcontext. Wanneer u de MM_TEXT toewijzingsmodus gebruikt, voorkomt u wiskundige fouten die kunnen optreden tijdens het conversieproces van andere toewijzingsmodi.

Wanneer u een apparaatlettertype gebruikt in de context van een printerapparaat, moet u ervoor oppassen dat u de metrische gegevens voor het lettertype en de tekenreeksen niet naar andere apparaatcontexten transporteert. Dit geldt met name voor contexten van geheugenapparaten. Een context van een geheugenapparaat is per definitie niet de afdruktaak, maar is een tijdelijke geheugenbuffer van rasterafbeeldingen en kan daarom geen apparaatlettertype gebruiken.

Er is nog een belangrijke overweging wanneer u printerapparaatlettertypen gebruikt: u kunt geen voorbeeld van het type What-You-See-Is-What-You-Get van de afdruktaak opgeven. Het is duidelijk dat lettertypen die zich in de printerhardware bevinden, niet op het scherm kunnen worden getekend. U kunt het beste een voorbeeld van de afdruktaak bekijken door een door het systeem opgegeven lettertype te zoeken met de algemene kenmerken van het lettertype van een printerapparaat en vervolgens de glyphs van dat lettertype op het scherm te tekenen met behulp van de ExtTextOut functie om de plaatsing van de tekentekens op de afgedrukte pagina te simuleren.

Problemen met het gebruik van apparaatlettertypen

U kunt de volgende problemen ondervinden wanneer u apparaatlettertypen gebruikt:

  • Er is een apparaatlettertype, maar het printerstuurprogramma inventariseert dit niet.

    Er zijn twee redenen waarom u een apparaatlettertype niet kunt vinden door de lettertypen op te sommen die beschikbaar zijn voor gebruik in de context van een printerapparaat:

    • Het printerstuurprogramma is om een of andere reden geschreven om dat apparaatlettertype uit te sluiten.
    • Het printerstuurprogramma inventariseert het lettertype, maar het lettertype is niet juist gemarkeerd in de FontType parameter als apparaatlettertype.
  • Er zijn systeemlettertypen die lijken te worden opgesomd als apparaatlettertypen.

    Dit probleem treedt op wanneer een door het systeem geleverd lettertype wordt gedownload naar een printer.

    Wanneer dit gebeurt met TrueType-lettertypen, ontvangt de callback-functie voor de opsomming van lettertypen een aanroep met de TRUETYPE_FONTTYPE en de DEVICE_FONTTYPE bits die zijn ingesteld op de FontType parameter. Dit wordt verwerkt in de voorbeeldcode door geen lettertypen op te nemen die deze combinaties van bits bevatten.

    Dit gebeurt ook met Adobe PostScript-lettertypen die in het systeem zijn geïnstalleerd en die naar de printer worden gedownload. Een manier om deze lettertypen te onderscheiden van de andere apparaatlettertypen is ze te zoeken in zowel de apparaatcontext van het systeemscherm als de context van het printerapparaat. Als hetzelfde lettertype kan worden geïnventariseerd in beide apparaatcontexten, wordt het lettertype waarschijnlijk gedownload naar de printer wanneer het wordt gebruikt in de context van het printerapparaat.

  • Mijn printerstuurprogramma somt verschillende schaalbare apparaatlettertypen op, maar deze lijken hetzelfde te zijn, behalve de grootten.

    Veel printerstuurprogramma's inventariseren een schaalbaar lettertype door verschillende exemplaren van hetzelfde lettertype met verschillende grootten op te geven. Dit wordt verwerkt in de voorbeeldcode door de verschillende exemplaren van de lettertypen te vergelijken waarvan wordt aangenomen dat ze schaalbaar zijn met behulp van de CompareLogFontEx functie.

    Opmerking

    Wanneer de FontType parameter voor de callback-functie is RASTER_FONTTYPEbit ingesteld, bevatten de meerdere opsommingen beschrijvingen van specifieke exemplaren van de niet-schaalbare lettertypen voor elke grootte. Elke callback somt de enige grootten op waarin dat lettertype beschikbaar is.

  • Sommige printers lijken geen apparaatlettertypen te hebben.

    Dit is waar. Sommige printers, namelijk inktstraalprinters, bieden geen apparaatlettertypen. Deze printers zijn strikt rasterapparaten en hebben daarom geen lettertypedefinities voor de printer.