使用打印机设备字体

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

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

摘要

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

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

通常情况下,当应用程序打印文档时,在没有应用程序的任何特定操作的情况下,将在打印机上使用字体(或类似的字体)。 这通常是应用程序的正确结果,这将以合理的速度生成较好的打印结果。

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

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

设备字体

在本文中,设备字体是指任何在打印机内存中永久或 transiently 定义的字体。 这些设备字体提供了一个字符标志符号定义,该定义可由打印机的页面光栅程序硬件为每个字符寻址,以将形状的墨迹放在纸上。

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

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

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

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

可下载字体

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

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

设备字体替换

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

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

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

真正的设备字体

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

如果您知道有关某个设备的足够信息,则可以在 LOGFONT 将导致设备字体实现的结构中创建逻辑字体说明。 特别是,请务必为 lfFacename member、 lfHeight member 和字体字符集提供正确的信息。 此外,该 lfOutPrecision 成员还应包含一个 OUT_DEVICE_PRECIS 标志,以影响字体映射过程以选择设备字体,而不是使用类似的名称系统字体。

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

使用真正的设备字体

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

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

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

若要枚举设备上下文中可用的所有字体,可以使用回调函数和 EnumFontFamiliesEx Win32 应用程序编程接口(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)文档,当您将 LOGFONT 结构的 lfCharSet 成员设置为 DEFAULT_CHARSET 值时,将 EnumFontFamiliesEx 枚举所有字体系列。 完成字体枚举后,代码通过调用方法完成打印作业管理任务 EndDoc

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

选择设备字体

您可以使用打印机设备字体的一定条件将这些字体与枚举的任何其他字体区分开来。 具体来说,请 DEVICE_FONTTYPEFontType 回调函数的 DWORD 参数中查找值。 几乎所有通过此值设置传递给 callback 函数的字体都是打印机设备上下文的设备字体(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 类型管理器或通过 Windows 2000 或 Windows XP 中存在的本机 Adobe 光栅器将 Adobe 字体安装到系统中时,会发生这种情况。

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

为了避免可缩放的字体的重复示例,该代码还说明了使用候选字体的情况。 此过程的具体实现依赖于字体的枚举顺序,以查看字体的顺序枚举是否为相同的字体,但比例不同。 若要删除仅有不同比例的字体,代码使用 CompareLogFontEx 函数。

备注

Windows 操作系统编程文档不会声明仅按比例区分的字体实例将按顺序枚举。 此代码示例使用此技术,因为发现枚举以这样方式工作,并且在打印页面上的取样行数的减少并不是演示代码的关键功能。 如果要依赖于消除相同字体的不同比例,则必须保留所使用的设备字体的数据结构。 然后,该程序必须检查当前枚举的字体是否符合该数据结构。

可扩展的与位图字体

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

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

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

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

在大多数 PostScript 打印机中,可以找到可扩展、打印机驻留字体的示例,其中通常有一组标准的 PostScript 字体,如黑体和时间。

不可扩展的设备字体在回调函数的参数中设置了一个位 FontType 。 该位由 SDK 中的符号表示 RASTER_FONTTYPE 。 如果 FontType 回调函数的参数没有 RASTER_FONTTYPEbit 设置,则字体是可缩放的字体。 有关如何确定此操作的示例,请参阅 PrinterDeviceFontEnum 示例代码的回调函数。

绘制设备字体

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

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

在打印机设备上下文中使用设备字体时,必须注意不要将字体和字符串的指标传输到其他设备上下文。 这一点尤其适用的是内存设备上下文。 根据定义,内存设备上下文不是打印作业,而是光栅图形的临时内存缓冲区,因此无法使用设备字体。

在使用打印机设备字体时,还有另一个重要的注意事项:您无法提供打印作业的 "查看内容" 类型预览。 显然,不能在屏幕上绘制位于打印机硬件中的字体。 在预览打印作业时,最接近的方法是查找系统提供的字体,该字体具有打印机设备字体的常规特征,然后通过使用 ExtTextOut 函数模拟打印页面上的字符标志符号的位置,在屏幕上绘制该字体的字型。

使用设备字体的问题

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

  • 有一种设备字体,但打印机驱动程序不会对其进行枚举。

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

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

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

    在 TrueType 字体发生这种情况时,字体枚举回调函数接收带有 TRUETYPE_FONTTYPE 参数上设置的和的位的调用 DEVICE_FONTTYPE FontType 。 通过不包含任何包含这些位组合的字体,在示例代码中对此进行了处理。

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

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

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

    备注

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

  • 有些打印机看起来不具有设备字体。

    这是真的。 有些打印机(即喷墨类型打印机)不提供设备字体。 这些打印机是严格的光栅设备,因此没有打印机驻留的字体定义。