使用打印机设备字体

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

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

摘要

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

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

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

但是,有时应用程序开发人员可能只需从目标打印机中选择特定字体。 从历史上看,这在影响型打印机 (例如,点阵打印机) 获取特定格式或加快打印速度时是必需的。

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

设备字体

就本文而言,设备字体是其定义永久或暂时存在于打印机内存中的任何字体。 这些设备字体提供字符字形定义,打印机的页面光栅器硬件可以为每个字符寻址该字形,以便将形状墨迹书写在纸上。

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

  • 真实设备字体。 就本文而言,这些字体仅供打印机硬件提供,并且只能在打印机上使用。

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

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

可下载字体

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

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

设备字体替换

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

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

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

True 设备字体

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

如果了解有关设备的足够信息,则可以在结构中创建 LOGFONT 逻辑字体说明,从而实现设备字体。 特别是,为字体的成员、lfHeight成员和字符集提供正确的信息lfFacename非常重要。 此外,该 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 以启动字体枚举过程。 根据平台软件开发工具包 (SDK) 文档,将 结构lfCharSet的成员设置为 LOGFONTDEFAULT_CHARSET 值时,EnumFontFamiliesEx枚举所有字体系列。 字体枚举完成后,代码通过调用 EndDoc 方法完成打印作业管理任务。

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

选择设备字体

可以使用打印机设备字体的某些条件将这些字体与枚举的任何其他字体区分开来。 具体而言,请在回调函数的 DWORD 参数中FontType查找DEVICE_FONTTYPE值。 将此值设置为回调函数的几乎所有字体都是打印机设备上下文 (除 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 Millennium Edition ( () 、Windows 2000 和 Windows XP 中,没有标志指示该字体是系统提供的 Adobe 字体,与 TrueType 字体(包括标志) )不同 (。 结构ntmFlags的成员中有NEWTEXTMETRIC一个指示,但这仅适用于 Windows 2000 及更高版本。 因此,代码必须采用消除过程。 当设备字体由屏幕设备上下文和打印机设备上下文提供时 IsSystemFontdetermines ,将删除字体。

为了避免缩放字体的重复示例,代码还会在已使用候选字体时进行注释。 此的具体实现依赖于字体的枚举顺序来查看字体的顺序枚举是否为相同字体但采用不同比例。 若要删除只是不同比例的字体,代码使用 CompareLogFontEx 函数。

注意

Windows 操作系统编程文档未说明将按比例而有所不同的字体实例将按顺序枚举。 代码示例使用此技术,因为可以看到枚举以这种方式工作,并且减少打印页上的示例行数并不是演示代码的一个关键功能。 如果要依赖于消除相同字体的不同比例,则必须保留所用设备字体的数据结构。 然后,程序必须针对该数据结构检查当前枚举的字体。

可缩放与位图字体

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

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

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

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

可在大多数 PostScript 打印机中找到可缩放的、位于打印机的字体示例,其中通常有一组标准的 PostScript 字体,例如 Helvetica 和 Times。

不可缩放的设备字体具有在回调函数的 参数中 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 字体中发生这种情况时,字体枚举回调函数将接收调用,DEVICE_FONTTYPE并在 TRUETYPE_FONTTYPE 参数上FontType设置位。 在示例代码中,通过不包含任何包含这些位组合的字体来处理此问题。

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

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

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

    注意

    FontType当回调函数的参数具有 RASTER_FONTTYPEbit 集时,多个枚举会为每个大小提供不可缩放字体的特定实例的说明。 每个回调枚举该字体的唯一可用大小。

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

    正确。 某些打印机(即喷墨式打印机)不提供设备字体。 这些打印机严格是光栅设备,因此没有打印机常驻字体定义。