使用印表機裝置字型

印表機中的字型有時候很有用,且難於用於應用程式程式碼。 本文說明如何決定 Win32 印表機裝置內容中可使用的印表機駐留裝置字型。 本文也說明當您嘗試在應用程式程式碼中使用這些印表機字型時,可能會發生的幾個問題。

原始產品版本:  Win32 印表機裝置
原始 KB 編號:  201978

摘要

在大多數情況下,軟體發展人員會以作業系統為例,提供要用於繪圖的字型。 若要這麼做,您可以透過應用程式設計介面(API)或透過一般的 [選擇字型] 對話方塊,選取作業系統提供的字型。 不過,該應用程式通常不會關注所使用的特定字型,只會符合特定的需求,而且使用者喜歡使用字型。 這些需求包括:

  • 字型必須是特定大小。
  • 字型必須包含字元(也稱為標誌符號)。
  • 字型必須具有特定的樣式。

一般來說,當應用程式列印檔案時,就會在印表機上使用字型(或類似的字型),而不需要應用程式的任何特定動作。 這通常是應用程式的正確結果,而這會以合理的速度產生良好的列印結果。

不過,有時應用程式開發人員可能必須只從目標印表機選取特定字型。 從過去的角度來看,對影響類型的印表機(例如點陣印表機)進行必要的,以取得某些格式設定或加快列印速度。

目前,大部分的印表機都是以光柵裝置設計,而且可以在紙張的任何部分上繪製點(一個圖元),就像所有字元標誌符號一樣有效率。 在大多數的應用程式中,不論字元字型是從印表機駐留定義中繪製成整個格式,還是以作業系統所提供的圖元集合形式繪製,都不是問題。 不過,您可能還是只想要使用印表機所提供的字型。 例如,這可能是因為字型是唯一的,而且在作業系統中沒有類似的替代品,也可能是因為您想要避免將字型定義下載至印表機的額外負荷。

裝置字型

在本文的目的中,裝置字型是指任何定義存在於印表機記憶體中的任何字型。 這些裝置字型提供一種字元字型定義,可由印表機的頁面光柵器硬體針對每個字元來處理,以手寫顯示紙上的圖形。

裝置字型可以分為下列三種基本類型:

  • True 是裝置字型。 在本文的目的中,這些是僅供印表機硬體提供,而且只能在印表機上使用的字體。

  • 裝置字型替代。 存在於作業系統中的字體和印表機硬體也提供的字型。 在此情況下,印表機硬體可以取代作業系統的字體。

  • 可下載的字體。 作業系統所提供但其定義可以下載至印表機,並在印表機上使用的字型,如同印表機硬體直接提供字型。

可下載的字體

作業系統提供可下載的字型,也稱為軟字體。 當您列印檔案時,字型的定義會提供列印工作的一部分。 當印表機處理列印工作時,字型定義會安裝在印表機記憶體中,使字型定義可以 inked 至檔的列印頁面。

有些原因是印表機正在繪製字型的字元字型,這些字型是裝置字型。 不過,當字型定義下載時,或在透過點陣圖將字型繪製至印表機時,只會儲存一些額外負荷或列印工作線軸大小。 此程式會對應用程式透明地進行,如此一來,您就可以在螢幕上和印表機上使用作業系統中的字型。 因為本文著重于如何使用只有印表機提供的裝置字型,所以本文不會說明如何使用可下載的字型。

裝置字型替換

當有兩個不同的字型定義時,就會發生裝置字型替代:一種是作業系統使用的,另一種則是印表機使用。 也就是說,應用程式會在螢幕上的檔中,選取作業系統中的文字,並使用該文字。 當您列印檔案時,列印輸出會使用印表機所提供的類似定義的字型來繪製。 因此,作業系統中的字型已以印表機定義的字型在印表機上取代。

這通常會在使用通用 Windows TrueType 字型時 PostScript 印表機上發生。 例如,使用大部分 PostScript 裝置上的 Arial 字型 PostScript 字型定義,通常列印的 TrueType Arial 字型。 這是使用字型名稱不同的類似字型來替代的範例。 在此情況下,您通常可以直接找到並使用此類似的字型定義,因為類似的字型定義也會公開為 true 裝置字型。 本文稍後將討論這一項。

當印表機上的字型與作業系統所提供的字型同名時,也會發生裝置字型替代。 這通常發生在印表機上,例如 Hewlett-Packard LaserJet 印表機。 這些印表機一般都有自己的 Windows 核心字型版本,例如 Arial 和 Times New Roman。 雖然您通常可以透過尋找實際的裝置字型來找到這些字型,但由於印表機驅動程式經常自行自行選取,或透過使用者設定來選擇是否要改用作業系統所提供的字型,所以無法保證其使用。

True 裝置字型

True 裝置字型是指只在印表機上具有定義的設備字型。 應用程式可以使用這些字型的唯一方式是讓應用程式特別識別字型,並建立它以用於印表機裝置內容。

如果您知道有關裝置的足夠資訊,可以在 LOGFONT 會導致裝置字型實現的結構中建立邏輯字型描述。 尤其重要的是,請務必為 lfFacename member、member 及字型的字元集提供正確的資訊 lfHeight 。 此外,該 lfOutPrecision 成員應該包含一個 OUT_DEVICE_PRECIS 旗標,可影響字型對應程式,以選擇裝置字型,而不是類似命名的系統字型。

如果不知道字型的描述,您可以列舉字型來探索裝置字型。 若要取得印表機所支援的裝置字型清單,請使用下列其中一種字型列舉功能 EnumFontFamiliesEx 。 放入回呼函數中的應用程式程式碼可檢查傳遞給回呼函數的資料,以判斷哪些字型實例會描述裝置字型。

使用真實的裝置字型

在印表機裝置內容中使用裝置字型的程式,遵循下列一般步驟:

  1. 透過在印表機裝置內容中列舉字型,識別真實的裝置字型。
  2. 選取 [僅限裝置的字體],如 FontType 旗標和清除程式所指示。
  3. 使用對應模式中印表機特有 MM_TEXT 的計量,以精確放置使用裝置字型繪製的文字。

列舉印表機裝置內容的字體

若要列舉裝置內容中所有可用的字型,您可以使用 callback 函數和 EnumFontFamiliesEx Win32 應用程式設計介面(API)中的函數。 若要列舉裝置內容的所有字型,您必須呼叫 EnumFontFamiliesEx 兩次:第一次取得字型系列的清單,第二次是取得字型系列的所有不同字型。

若要在印表機裝置內容中尋找所有裝置字型,您必須列舉印表機裝置內容的所有字型。 當每個字型都傳遞給回撥函數時,會檢查字型,以判斷其是否為裝置字型。 PrinterDeviceFontEnum PrinterDeviceFontFamiliesEnum 下列範例程式碼中的 and 回呼函數會執行此作業。

// 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 參數中尋找值。 幾乎所有透過此值設定的回撥函式的字型,都是印表機裝置內容的裝置字型(除了 Adobe 字型)。

在範例程式碼中, PrinterDeviceFontEnum callback 函數是由字型系列中每個不同字型的第二個列舉呼叫。 回撥函式會 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;
}

此函數會偵測到標記為裝置字型,但不是 true 裝置字型的字型(根據本文中的定義)。 當 Adobe 字型是透過 Adobe 類型管理員或是 Windows 2000 或 Windows XP 中的原生 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 字型,例如,Helvetica 和時間。

不具縮放功能的裝置字型,在回呼函式的參數中所設定的位 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 ,多個列舉會針對每個大小的非縮放字型,提供特定實例的描述。 每個回撥會列舉唯一可以使用該字型的大小。

  • 有些印表機似乎不具備裝置字型。

    這是 true。 有些印表機(亦即噴墨類型印表機)不會提供裝置字型。 這些印表機為嚴格的等距裝置,因此沒有印表機內建的字型定義。