使用打印机设备字体

打印机中的字体有时可能很有用且难以在应用程序代码中使用。 本文介绍如何确定哪些打印机驻留设备字体可用于 Win32 打印机设备上下文。 本文还介绍尝试在应用程序代码中使用这些打印机字体时可能发生的一些问题。

原始产品版本:   Win32 打印机设备
原始 KB 编号:   201978

摘要

在大多数情况下,软件开发人员依赖操作系统来提供将用于绘图的字体。 为此,可以通过 API 应用程序编程接口或通用"选择字体" () 操作系统提供的字体。 但是,应用程序通常并不关注使用的特定字体,只有它满足特定要求,并且用户首选该字体。 这些要求包括:

  • 字体必须为特定大小。
  • 字体必须包含字符 (也称为字形) 。
  • 字体必须具有特定样式。

通常,当应用程序打印文档时,字体 (或类似于) 的字体在打印机上使用,无需应用程序执行任何特定操作。 这通常是应用程序的正确结果,并且以合理的速度产生良好的打印结果。

但是,有时应用程序开发人员可能只需要从目标打印机中专门选择特定字体。 过去,这对影响类型的打印机 (例如,点阵打印机) 获取特定格式或加快打印速度。

如今,大多数打印机基本都设计为光栅设备,可在纸张的任何部分上绘制一个点 (像素) ,就像所有字符字形一样高效。 对于大多数应用程序,从打印机驻留定义中将字符字形绘制为整个窗体,还是作为操作系统提供的像素集合进行绘制并不是问题。 但是,您可能仍希望使用仅打印机提供的字体。 例如,这可能是因为字体是唯一的,在操作系统中没有相似的替代项,或者可能因为您想要避免将字体定义下载到打印机的开销。

设备字体

对于本文,设备字体是定义永久或暂时存在于打印机内存中的任何字体。 这些设备字体提供字符字形定义,打印机的页面光栅器硬件可以按字符对字符进行寻址,以将形状墨迹书写到纸张上。

设备字体可以分为三种基本类型:

  • 真正的设备字体。 对于本文,这些字体仅由打印机硬件提供,并且只能在打印机上使用。

  • 设备字体替换。 操作系统中以及打印机硬件也提供的字体。 在这种情况下,打印机硬件可以替代操作系统的字体。

  • 可下载字体。 操作系统提供但定义可以下载到打印机并用于打印机的字体,就像打印机硬件直接提供字体一样。

可下载字体

操作系统提供可下载字体,也称为软字体。 打印文档时,字体的定义作为打印作业的一部分提供。 打印机处理打印作业时,字体定义安装在打印机内存中,以便字体定义可以墨迹书写到文档的打印页上。

一些人认为,由于打印机正在绘制字体的字符字形,因此这些字体是设备字体。 但是,下载字体定义或通过位图将字形绘制到打印机上时,只会保存一些开销或打印作业后台打印大小。 此过程对应用程序透明进行,以便可以在屏幕和打印机上使用操作系统中的字体。 由于本文重点介绍了如何使用仅打印机提供的设备字体,因此本文不介绍如何使用可下载字体。

设备字体替换

当存在两个不同的字体定义时,将发生设备字体替换:一种是操作系统使用的,另一种是打印机使用的。 也就是说,应用程序在屏幕上的文档中选择并使用操作系统中的字体。 打印文档时,打印输出使用打印机提供的类似定义字体绘制。 因此,操作系统中的字体在打印机上已替换为打印机定义的字体。

在使用常用 TrueType PostScript,这Windows在打印机上发生。 例如,TrueType Arial 字体通常在大多数设备上使用 Helvetica 字体的 PostScript 字体定义进行打印PostScript打印。 这是一个通过使用字体名称不同的类似字体进行替换的示例。 在这种情况下,通常可以直接查找和使用这种类似的字体定义,因为类似的字体定义也会公开为真正的设备字体。 本文稍后将对此进行讨论。

当打印机上的字体与操作系统提供的字体同名时,也会发生设备字体替换。 这通常发生在打印机上,例如Hewlett-Packard LaserJet 打印机。 这些打印机通常拥有自己的核心字体版本Windows如 Arial 和 Times New Roman。 虽然通过查找真实的设备字体通常也可以找到这些字体,但有时无法保证它们的使用,因为打印机驱动程序经常自行选择,或者通过用户设置选择是否改为使用操作系统提供的字体。

真正的设备字体

真正的设备字体是仅在打印机上具有定义的字体。 应用程序使用这些字体的唯一方式就是让应用程序专门标识字体并创建字体以在打印机设备上下文中使用。

如果你知道有关设备的足够信息,可以在结构内创建逻辑字体说明,该结构将导致设备 LOGFONT 字体的显示。 特别是,为成员、成员和字体的字符集 lfFacename lfHeight 提供正确的信息非常重要。 此外,成员应包含一个标志以影响字体映射过程,以 lfOutPrecision OUT_DEVICE_PRECIS 选择设备字体,而不是命名类似的系统字体。

如果字体说明未知,可以枚举字体以发现设备字体。 若要获取打印机支持的设备字体列表,请使用字体枚举函数之一,例如 EnumFontFamiliesEx 。 放入回调函数中的应用程序代码可以检查已交给回调函数的数据,以确定哪些字体实例描述设备字体。

使用真正的设备字体

在打印机设备上下文中使用设备字体的过程遵循以下常规步骤:

  1. 通过枚举打印机设备上下文中的字体来标识真正的设备字体。
  2. 按标志和消除过程选择仅设备 FontType 字体。
  3. 在映射模式中使用特定于打印机的指标,以精确放置使用 MM_TEXT 设备字体绘制的文本。

枚举打印机设备上下文的字体

若要枚举设备上下文中提供的所有字体,可以使用 Win32 应用程序编程接口中的回调函数和 函数 (EnumFontFamiliesEx API) 。 若要枚举设备上下文的所有字体,必须调用两次:第一次调用获取字体系列列表,第二次调用获取每个字体系列中所有不同 EnumFontFamiliesEx 字体。

若要在打印机设备上下文中查找所有设备字体,必须枚举打印机设备上下文的所有字体。 将每种字体传递给回调函数时,将检查字体以确定该字体是否为设备字体。 以下示例 PrinterDeviceFontEnum 代码中的 和 PrinterDeviceFontFamiliesEnum 回调函数执行此操作。

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

可以在示例代码中看到函数 EnumFontFamiliesEx 被调用两次。 在 函数中执行第一个 PrintDeviceFontList 调用。 第二个调用位于 PrinterDeviceFontFamiliesEnum 回调函数中。

PrintDeviceFontList 是顶级函数。 PrintDeviceFontList 通过启动打印机设备上下文上的打印作业,然后调用第一个调用以 EnumFontFamiliesEx 启动字体枚举过程,执行两个任务。 根据 Platform Software Development Kit (SDK) 文档,当您将结构的成员设置为值时,枚举所有 LOGFONT lfCharSet DEFAULT_CHARSET EnumFontFamiliesEx 字体系列。 字体枚举完成后,代码通过调用 方法完成打印作业管理 EndDoc 任务。

PrinterDeviceFontFamiliesEnum 函数将针对每个字体系列调用回调 EnumFontFamiliesEx 函数。 在回调函数中,代码最初筛选字体系列,以仅查找由 参数标记的设备 FontType 字体。 它还会筛选掉标记为 的任何字体,因为这些 TrueType 字体可能是可下载的字体。 对于被视为设备字体的字体系列,会再次调用 函数,但会传递回调函数 EnumFontFamiliesEx ENUMLOGFONTEX 接收的结构。 使用 callback 参数作为第二个枚举函数调用的输入参数会导致第二个枚举列出该字体系列中所有不同的字体。

选择设备字体

可以使用打印机设备字体的某些条件来区分这些字体和枚举的其他任何字体。 具体来说,在 DEVICE_FONTTYPE 回调函数的 FontType DWORD 参数中查找值。 向设置了此值的回调函数的几乎所有字体都是打印机设备上下文设置的设备字体 (Adobe 字体除外) 。

在示例代码中,回调函数由字体系列中每个不同字体的第 PrinterDeviceFontEnum 二个枚举调用。 回调 PrinterDeviceFontEnum 函数执行三个任务:

  • 再次使用设备字体条件,以确保该函数仅处理被识别为设备字体的字体。

  • 使用另一个字体枚举搜索字体,以查看设备字体是否也用于系统的屏幕设备上下文。

  • 将字体示例打印到要创建的打印作业中,以演示字体的使用。 此回调函数使用名为 的函数 IsSystemFont ,它是以下示例代码的一部分:

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

此函数根据本文中的定义检测标记为设备字体但不是真正的设备字体 (字体何时) 。 当 Adobe 字体通过 Adobe 类型管理器或 Windows 2000 或 Windows XP 中的本机 Adobe 光栅器安装到系统中时,会发生此情况。

发生这种情况时,字体实际上就是系统提供的字体,下载到打印机,有时使用 TrueType 字体进行下载。 遗憾的是,没有可用于 Windows 98、Windows、Me (Me) 、Windows 2000 和 Windows XP 的标志,指示字体是系统提供的 Adobe 字体 (与 TrueType 字体不同,TrueType 字体包括标志) 。 结构成员中指示,但仅在 NEWTEXTMETRIC ntmFlags Windows 2000 及更高版本中可用。 因此,代码必须采用消除过程。 当屏幕设备上下文和打印机设备上下文同时提供设备字体时 IsSystemFontdetermines ,将删除字体。

为了避免缩放的字体的重复示例,代码还会记录已使用候选字体时。 具体实现依赖于字体的枚举顺序,以查看字体的顺序枚举何时相同,但大小不同。 若要删除只是不同比例的字体,代码将使用 CompareLogFontEx 函数。

备注

有关在Windows编程的文档未规定将按顺序枚举仅与比例不同的字体实例。 该代码示例使用此技术的原因是,枚举以这种方式工作,并且打印页上示例行数的减少不是演示代码的关键功能。 如果要依赖消除相同字体的不同缩放比例,则必须保留所使用的设备字体的数据结构。 然后,程序必须针对该数据结构检查当前枚举的字体。

可扩展与位图字体

可以在打印机上枚举两种类型的设备字体:

  • 位图或栅格字体
  • 可缩放字体

位图字体是具有固定大小的字符字形定义的字体。 可缩放字体是打印机中基于数学的定义的字体,因此可以按任意大小绘制它们。 换句话说,它们的大小会缩放。

位图字体的经典示例是 Courier 10 个字符/英寸 (cpi) 。 正如名称所示,此字体是从类型打印机转换到影响类型打印机的保留。 它被称为位图字体,因为最常见的字体定义位于点阵打印机的 ROM 位图图像中。

在通常具有一组标准字体(如 Helvetica 和 Times)的 PostScript 打印机中,可缩放的驻留打印机字体示例PostScript打印机。

无法缩放的设备字体的位在回调函数的 参数 FontType 中设置。 该位由 SDK 中的 RASTER_FONTTYPE 符号表示。 如果回调函数的参数没有设置,则 FontType RASTER_FONTTYPEbit 字体是可缩放的字体。 若要了解如何确定这一点,请参阅示例 PrinterDeviceFontEnum 代码的回调函数。

绘制设备字体

找到作为设备字体的字体后,该示例在已执行枚举的打印机设备上下文中使用它们。 设备字体的使用方式与其他字体非常类似,即使用 函数创建逻辑 CreateFontIndirect 说明。 此函数调用将传递给字体枚举 LOGFONT 回调函数的 。 创建 后,它将通过函数调用选择到设备上下文中,在打印机 HFONT 设备 SelectObject 上下文中使用。

通过函数调用获取设备字体 GetTextMetrics 的指标。 最好使用映射模式(设备上下文的默认映射模式)在打印机 MM_TEXT 设备上下文中进行操作。 使用映射模式时,可以避免在其他映射模式的单位转换过程中可能发生 MM_TEXT 数学错误。

在打印机设备上下文中使用设备字体时,必须小心不要将字体和字符串的指标传输给其他设备上下文。 这尤其适用于内存设备上下文。 根据定义,内存设备上下文不是打印作业,而是一个临时的内存缓冲区,包含栅格图形,因此不能使用设备字体。

使用打印机设备字体时还有另一个需要考虑的重要事项:无法提供打印作业的 What-You-See-Is-What-You-Get 类型预览。 显然,驻留在打印机硬件中的字体无法绘制到屏幕上。 最接近预览打印作业的是查找系统提供的字体,该字体具有打印机设备字体的一般特征,然后使用 函数模拟打印页上的字符字形的位置,在屏幕上绘制该字体的字形。 ExtTextOut

使用设备字体时出现问题

使用设备字体时可能会遇到以下问题:

  • 存在设备字体,但打印机驱动程序不枚举它。

    无法通过枚举可用于打印机设备上下文的字体来查找设备字体的原因有两个:

    • 出于某种原因,编写打印机驱动程序以排除该设备字体。
    • 打印机驱动程序枚举字体,但字体未在 参数中正确 FontType 标记为设备字体。
  • 有些系统字体似乎枚举为设备字体。

    将系统提供的字体下载到打印机时会出现此问题。

    当 TrueType 字体出现此情况时,字体枚举回调函数会收到一个调用,该调用包含 在 参数上设置的 和 TRUETYPE_FONTTYPE DEVICE_FONTTYPE FontType 位。 在示例代码中处理此操作时,不会包含包含这些位组合的任何字体。

    在系统中安装的 Adobe PostScript字体也会出现这种情况,这些字体将下载到打印机。 区分这些字体与其他设备字体的一种方式是在系统屏幕设备上下文和打印机设备上下文中查找它们。 如果可以在两个设备上下文中枚举同一字体,则当在打印机设备上下文上使用该字体时,该字体可能会下载到打印机。

  • 我的打印机驱动程序枚举多个可缩放的设备字体,但它们看起来都相同,但大小除外。

    许多打印机驱动程序通过提供具有不同大小的同一字体的几个不同实例来枚举可缩放的字体。 在示例代码中,通过比较假定通过使用 函数可缩放的各种字体实例来对此 CompareLogFontEx 进行处理。

    备注

    当回调函数的参数已设置时,多个枚举会针对每种大小提供不可缩放字体 FontType RASTER_FONTTYPEbit 的特定实例的说明。 每个回调枚举该字体可用的唯一大小。

  • 某些打印机似乎没有设备字体。

    正确。 某些打印机(即墨迹 jet 类型的打印机)不提供设备字体。 这些打印机严格是栅格式设备,因此没有打印机驻留字体定义。