Usar fontes de dispositivo de impressora

As fontes que estão em impressoras às vezes podem ser úteis e difíceis de usar no código do programa de aplicativo. Este artigo descreve como determinar quais fontes de dispositivo residentes na impressora estão disponíveis para uso em um contexto de dispositivo de impressora Win32. O artigo também descreve vários problemas que podem acontecer quando você tenta usar essas fontes de impressora no código do aplicativo.

Versão original do produto: Dispositivo de impressora Win32
Número de KB original: 201978

Resumo

Na maioria dos casos, um desenvolvedor de software depende do sistema operacional para fornecer as fontes que serão usadas para seu desenho. Para fazer isso, você pode selecionar uma fonte fornecida pelo sistema operacional por meio da API (interface de programação do aplicativo) ou por meio da caixa de diálogo Escolher Fonte comum. No entanto, o aplicativo normalmente não está preocupado com a fonte específica que é usada, apenas atende a determinados requisitos e o usuário prefere a fonte. Esses requisitos incluem:

  • A fonte deve ter um determinado tamanho.
  • A fonte deve conter caracteres (também conhecidos como glifos).
  • A fonte deve ter um determinado estilo.

Normalmente, quando o aplicativo imprime o documento, a fonte (ou uma fonte semelhante a ela) é usada na impressora sem qualquer ação específica do aplicativo. Esse é geralmente o resultado correto para o aplicativo, e isso produz bons resultados impressos em velocidades razoáveis.

No entanto, às vezes, um desenvolvedor de aplicativos pode ter que selecionar apenas uma determinada fonte especificamente em uma impressora de destino. Historicamente, isso era necessário em impressoras de tipo de impacto (por exemplo, impressoras de matriz de pontos) para obter determinada formatação ou acelerar a impressão.

Hoje, a maioria das impressoras é fundamentalmente projetada como dispositivos raster e pode desenhar um ponto (um pixel) em qualquer parte do papel de forma tão eficiente quanto todo um glifo de caractere. Para a maioria dos aplicativos, não é um problema se um glifo de caractere é desenhado como um formulário inteiro de uma definição de residente de impressora ou é desenhado como uma coleção de pixels que o sistema operacional fornece. No entanto, talvez você ainda queira usar uma fonte que só a impressora fornece. Por exemplo, isso pode ocorrer porque a fonte é exclusiva e não tem nenhum substituto semelhante no sistema operacional ou talvez porque você deseja evitar a sobrecarga de baixar uma definição de fonte para a impressora.

Fontes de dispositivo

Para as finalidades deste artigo, as fontes de dispositivo são fontes cuja definição existe permanente ou transitóriamente na memória da impressora. Essas fontes de dispositivo fornecem uma definição de glifo de caractere que pode ser endereçada por caractere pelo hardware de rasterizador de página da impressora para pintar a forma no papel.

As fontes do dispositivo podem ser categorizadas em três tipos básicos:

  • Fontes de dispositivo verdadeiras. Para fins deste artigo, estas são fontes que somente o hardware da impressora fornece e que você só pode usar na impressora.

  • Substituição de fonte de dispositivo. Fontes que existem no sistema operacional e que o hardware da impressora também fornece. Nesse caso, o hardware da impressora pode substituir as fontes do sistema operacional.

  • Fontes para download. Fontes que o sistema operacional fornece, mas cuja definição pode ser baixada para a impressora e usada na impressora como se o hardware da impressora fornecesse as fontes diretamente.

Fontes para download

O sistema operacional fornece fontes para download, que também são conhecidas como fontes suaves. Quando você imprime um documento, a definição da fonte é fornecida como parte do trabalho de impressão. Quando a impressora processa o trabalho de impressão, a definição da fonte é instalada na memória da impressora para que a definição da fonte possa ser tatuada na página impressa do documento.

Alguns argumentam que, como a impressora está desenhando os glifos de caractere da fonte, essas fontes são fontes de dispositivo. No entanto, quando uma definição de fonte é baixada ou quando um glifo é desenhado na impressora por meio de um bitmap, apenas algum tamanho de carretel de trabalho de sobrecarga ou impressão é salvo. Esse processo ocorre de forma transparente para o aplicativo para que a fonte no sistema operacional possa ser usada na tela e na impressora. Como este artigo se concentra em como usar fontes de dispositivo que somente a impressora fornece, este artigo não descreve como usar fontes para download.

Substituição de fonte de dispositivo

A substituição da fonte do dispositivo ocorre quando há duas definições de fonte distintas: uma que o sistema operacional usa e outra que a impressora usa. Ou seja, um aplicativo seleciona e usa uma fonte no sistema operacional em um documento na tela. Quando você imprime o documento, a saída impressa é desenhada usando a fonte definida da mesma forma que a impressora fornece. Portanto, a fonte no sistema operacional foi substituída na impressora pela fonte definida pela impressora.

Normalmente, isso ocorre em impressoras PostScript quando uma fonte TrueType comum do Windows é usada. Um exemplo disso é a fonte TrueType Arial que normalmente é impressa usando a definição de fonte PostScript para a fonte Helvetica na maioria dos dispositivos PostScript. Este é um exemplo de substituição usando uma fonte semelhante cujo nome de fonte é diferente. Nesse caso, normalmente você pode encontrar e usar essa definição de fonte semelhante diretamente porque a definição de fonte semelhante também é exposta como uma fonte de dispositivo verdadeira. Isso é discutido posteriormente neste artigo.

A substituição da fonte do dispositivo também ocorre quando a fonte na impressora tem o mesmo nome que a fonte que o sistema operacional fornece. Normalmente, isso ocorre em impressoras como Hewlett-Packard impressoras LaserJet. Essas impressoras normalmente têm suas próprias versões das fontes principais do Windows, como Arial e Times New Roman. Embora essas fontes também possam normalmente ser encontradas procurando fontes de dispositivo verdadeiras, seu uso às vezes não pode ser garantido porque os drivers de impressora frequentemente selecionam por conta própria ou selecionam por meio das configurações do usuário se devem usar a fonte que o sistema operacional fornece.

Fontes de dispositivo true

Fontes de dispositivo true são aquelas que têm apenas uma definição na impressora. A única maneira que um aplicativo pode usar essas fontes é que o aplicativo identifique especificamente a fonte e crie-a para uso no contexto do dispositivo de impressora.

Se você souber informações suficientes sobre um dispositivo, poderá criar uma descrição de fonte lógica em uma LOGFONT estrutura que resultará na realização da fonte do dispositivo. Em particular, é importante fornecer as informações corretas para o lfFacename membro, o lfHeight membro e o conjunto de caracteres da fonte. Além disso, o lfOutPrecision membro deve conter um OUT_DEVICE_PRECIS sinalizador para influenciar o processo de mapeamento de fontes para escolher fontes de dispositivo em vez de fontes de sistema nomeadas da mesma forma.

Se a descrição da fonte não for conhecida, você poderá enumerar fontes para descobrir fontes de dispositivo. Para obter uma lista de fontes de dispositivo compatíveis com a impressora, use uma das funções de enumeração de fonte, como EnumFontFamiliesEx. O código do aplicativo que é colocado na função de retorno de chamada pode examinar os dados que são entregues à função de retorno de chamada para determinar quais instâncias de fonte descrevem uma fonte de dispositivo.

Usar fontes de dispositivo verdadeiras

O processo de uso de uma fonte de dispositivo em um contexto de dispositivo de impressora segue estas etapas gerais:

  1. Identifique as fontes de dispositivo verdadeiras por enumeração das fontes em um contexto de dispositivo de impressora.
  2. Selecione fontes que são somente dispositivo, conforme indicado pelos FontType sinalizadores e por processo de eliminação.
  3. Use métricas específicas da impressora no MM_TEXT modo de mapeamento para colocar com precisão o texto desenhado usando a fonte do dispositivo.

Enumerar as fontes de um contexto de dispositivo de impressora

Para enumerar todas as fontes disponíveis em um contexto de dispositivo, você pode usar funções de retorno de chamada e a EnumFontFamiliesEx função da API (interface de programação do aplicativo Win32). Para enumerar todas as fontes para um contexto de dispositivo, você deve chamar EnumFontFamiliesEx duas vezes: primeiro para obter uma lista de famílias de fontes e uma segunda vez para obter todas as fontes distintas que estão em cada família de fontes.

Para localizar todas as fontes do dispositivo em um contexto de dispositivo de impressora, você deve enumerar todas as fontes do contexto do dispositivo de impressora. Quando cada fonte é passada para as funções de retorno de chamada, a fonte é examinada para determinar se é uma fonte de dispositivo. As PrinterDeviceFontEnum funções de retorno de chamada e PrinterDeviceFontFamiliesEnum no código de exemplo a seguir executam essa operação.

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

Você pode ver no código de exemplo em que a EnumFontFamiliesEx função é chamada duas vezes. A primeira chamada é feita na PrintDeviceFontList função. A segunda chamada está na PrinterDeviceFontFamiliesEnum função de retorno de chamada.

PrintDeviceFontList é a função de nível superior. PrintDeviceFontList executa duas tarefas iniciando um trabalho de impressão no contexto do dispositivo da impressora e invocando a primeira chamada para EnumFontFamiliesEx iniciar o processo de enumeração de fonte. De acordo com a documentação do SDK (Platform Software Development Kit), ao definir o LOGFONT membro da lfCharSet estrutura como o DEFAULT_CHARSET valor, EnumFontFamiliesEx enumera todas as famílias de fontes. Depois que a enumeração de fonte é concluída, o código conclui a tarefa de gerenciamento de trabalho de impressão chamando o EndDoc método.

A PrinterDeviceFontFamiliesEnum função de retorno de chamada é chamada para cada família de fontes pela EnumFontFamiliesEx função. Nessa função de retorno de chamada, o código inicialmente examina as famílias de fontes para localizar apenas as fontes do dispositivo marcadas pelo FontType parâmetro. Ele também exibe todas as fontes marcadas como TrueType porque essas fontes provavelmente serão fontes para download. Para as famílias de fontes consideradas fontes de dispositivo, a EnumFontFamiliesEx função é chamada novamente, mas é passada a ENUMLOGFONTEX estrutura que a função de retorno de chamada recebeu. O uso do parâmetro de retorno de chamada como parâmetro de entrada para a segunda chamada de função de enumeração faz com que a segunda enumeração liste todas as fontes distintas nessa família de fontes.

Selecionar fontes de dispositivo

Você pode usar determinados critérios de fontes de dispositivo de impressora para distinguir essas fontes de qualquer outra fonte enumerada. Especificamente, procure o DEVICE_FONTTYPE valor no FontType parâmetro DWORD da função de retorno de chamada. Quase todas as fontes entregues à função de retorno de chamada com esse conjunto de valores são fontes de dispositivo para o contexto do dispositivo de impressora (exceto com fontes do Adobe).

No código de exemplo, a PrinterDeviceFontEnum função de retorno de chamada é chamada pela segunda enumeração para cada fonte distinta na família de fontes. A PrinterDeviceFontEnum função de retorno de chamada executa três tarefas:

  • Usa novamente os critérios de fonte do dispositivo para garantir que a função processe apenas fontes reconhecidas como fontes de dispositivo.

  • Pesquisa a fonte usando outra enumeração de fonte para ver se a fonte do dispositivo também é usada no contexto do dispositivo de tela do sistema.

  • Imprime um exemplo da fonte no trabalho de impressão que está sendo criado para demonstrar o uso da fonte. Essa função de retorno de chamada usa uma função chamada IsSystemFont, que faz parte do seguinte código de exemplo:

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

Essa função detecta quando uma fonte que é marcada como uma fonte de dispositivo, mas não é uma fonte de dispositivo verdadeira (de acordo com a definição neste artigo). Isso ocorre quando fontes do Adobe são instaladas no sistema por meio do Adobe Type Manager ou por meio do rasterizador nativo do Adobe que está presente no Windows 2000 ou no Windows XP.

Quando isso ocorre, a fonte é realmente uma fonte fornecida pelo sistema que é baixada para a impressora, que às vezes ocorre com fontes TrueType. Infelizmente, não há nenhum sinalizador que você possa usar entre Windows 98, Windows Millennium Edition (Me), Windows 2000 e Windows XP que indica que a fonte é uma fonte Adobe que o sistema fornece (ao contrário das fontes TrueType, que incluem um sinalizador). Há uma indicação no NEWTEXTMETRIC membro da ntmFlags estrutura, mas isso só está disponível no Windows 2000 e posterior. Portanto, o código deve recorrer a um processo de eliminação. A fonte é removida quando IsSystemFontdetermines a fonte do dispositivo é fornecida pelo contexto do dispositivo de tela e pelo contexto do dispositivo da impressora.

Para evitar exemplos repetitivos de uma fonte que é dimensionada, o código também observa quando uma fonte candidata já foi usada. A implementação específica disso depende da ordem de enumeração das fontes para ver quando enumerações sequenciais de uma fonte são a mesma fonte, mas em uma escala diferente. Para remover fontes que são apenas uma escala diferente, o código usa a CompareLogFontEx função.

Observação

A documentação para programação de sistemas operacionais Windows não indica que as instâncias de fonte que diferem apenas por escala serão enumeradas sequencialmente. O exemplo de código usa essa técnica porque a enumeração foi vista para funcionar dessa forma, e a redução do número de linhas de exemplo na página impressa não é um recurso crítico do código de demonstração. Se você quiser confiar na eliminação de diferentes escalas da mesma fonte, você deve manter uma estrutura de dados das fontes de dispositivo usadas. Em seguida, o programa deve marcar a fonte enumerada no momento em relação a essa estrutura de dados.

Fontes escalonáveis vs. Bitmap

Há dois tipos de fontes de dispositivo que podem ser enumeradas em impressoras:

  • Fontes bitmap ou raster
  • Fontes escalonáveis

Fontes bitmap são fontes que têm uma definição de glifo de caractere de um tamanho fixo. Fontes escalonáveis são fontes que têm uma definição baseada em matemática na impressora para que possam ser desenhadas em qualquer tamanho. Em outras palavras, seu tamanho é dimensionado.

O exemplo clássico de uma fonte bitmap é Courier 10 caracteres por polegada (cpi). Como o nome indica, essa fonte é uma retenção da transição de máquinas de escrever para impressoras do tipo de impacto. Ela é chamada de fonte bitmap porque a definição mais comum da fonte estava localizada em uma imagem de bitmap ROM de uma impressora de matriz de pontos.

Exemplos de fontes escalonáveis e residentes em impressoras podem ser encontrados na maioria das impressoras PostScript em que normalmente há um conjunto padrão de fontes PostScript, como Helvetica e Times.

As fontes de dispositivo que não são escalonáveis têm um bit definido no FontType parâmetro da função de retorno de chamada. Esse bit é representado pelo símbolo RASTER_FONTTYPE no SDK. Se o FontType parâmetro para a função de retorno de chamada não tiver o RASTER_FONTTYPEbit conjunto, a fonte será uma fonte escalonável. Para obter um exemplo de como determinar isso, consulte a PrinterDeviceFontEnum função de retorno de chamada do código de exemplo.

Desenhar as fontes do dispositivo

Depois que fontes que são fontes de dispositivo são encontradas, o exemplo as usa no contexto do dispositivo de impressora no qual a enumeração foi feita. As fontes de dispositivo são usadas muito semelhantes a outras fontes criando uma descrição lógica com a CreateFontIndirect função. Essa chamada de função é passada para a LOGFONT função de retorno de chamada de enumeração de fonte. Depois que o HFONT é criado, ele é usado no contexto do dispositivo da impressora selecionando-o no contexto do dispositivo com a chamada de SelectObject função.

As métricas para a fonte do dispositivo são obtidas por meio da chamada de GetTextMetrics função. É melhor operar em contextos de dispositivo de impressora usando o MM_TEXT modo de mapeamento, que é o modo de mapeamento padrão para um contexto de dispositivo. Ao usar o MM_TEXT modo de mapeamento, você evita erros matemáticos que podem ocorrer durante o processo de conversão de unidade de outros modos de mapeamento.

Ao usar uma fonte de dispositivo em um contexto de dispositivo de impressora, você deve ter cuidado para não transportar as métricas para a fonte e as cadeias de caracteres para outros contextos de dispositivo. Isso é verdade, particularmente, dos contextos do dispositivo de memória. Por definição, um contexto de dispositivo de memória não é o trabalho de impressão, mas é um buffer de memória temporário de gráficos raster e, portanto, não pode usar uma fonte de dispositivo.

Há outra consideração significativa quando você usa fontes de dispositivo de impressora: não é possível fornecer uma versão prévia do tipo What-You-See-Is-What-You-Get do trabalho de impressão. Claramente, as fontes que residem no hardware da impressora não podem ser desenhadas na tela. O mais próximo que você pode chegar de visualizar o trabalho de impressão é encontrar uma fonte fornecida pelo sistema que tenha as características gerais de uma fonte de dispositivo de impressora e, em seguida, desenhar os glifos dessa fonte na tela usando a ExtTextOut função para simular a colocação dos glifos de caractere na página impressa.

Problemas ao usar fontes de dispositivo

Você pode ter os seguintes problemas ao usar fontes de dispositivo:

  • Há uma fonte de dispositivo, mas o driver da impressora não a enumera.

    Há dois motivos pelos quais você não consegue encontrar uma fonte de dispositivo enumerando as fontes disponíveis para uso em um contexto de dispositivo de impressora:

    • O driver da impressora foi gravado para excluir a fonte do dispositivo por algum motivo.
    • O driver da impressora enumera a fonte, mas a fonte não está marcada corretamente no parâmetro como uma fonte de FontType dispositivo.
  • Há fontes do sistema que parecem enumerar como fontes de dispositivo.

    Esse problema ocorre quando uma fonte fornecida pelo sistema é baixada em uma impressora.

    Quando isso ocorre com fontes TrueType, a função de retorno de chamada de enumeração de fonte recebe uma chamada com o TRUETYPE_FONTTYPE e os DEVICE_FONTTYPE bits definidos no FontType parâmetro. Isso é manipulado no código de exemplo por não incluir nenhuma fonte que contenha essas combinações de bits.

    Isso também ocorre com fontes do Adobe PostScript instaladas no sistema que são baixadas na impressora. Uma maneira de diferenciar essas fontes das outras fontes de dispositivo é procurá-las em um contexto de dispositivo de tela do sistema e no contexto do dispositivo de impressora. Se a mesma fonte puder ser enumerada em ambos os contextos do dispositivo, a fonte provavelmente será baixada para a impressora quando for usada no contexto do dispositivo de impressora.

  • Meu driver de impressora enumera várias fontes de dispositivo escalonáveis, mas elas parecem ser as mesmas, exceto para seus tamanhos.

    Muitos drivers de impressora enumeram uma fonte escalonável fornecendo várias instâncias diferentes da mesma fonte com tamanhos diferentes. Isso é manipulado no código de exemplo comparando as várias instâncias dessas fontes que supostamente são escalonáveis usando a CompareLogFontEx função.

    Observação

    Quando o FontType parâmetro para a função de retorno de chamada tem o RASTER_FONTTYPEbit conjunto, as várias enumerações fornecem descrições de instâncias específicas das fontes não escalonáveis para cada tamanho. Cada retorno de chamada enumera os únicos tamanhos em que essa fonte está disponível.

  • Algumas impressoras parecem não ter fontes de dispositivo.

    Isso é verdade. Algumas impressoras, ou seja, impressoras do tipo jato de tinta, não fornecem fontes de dispositivo. Essas impressoras são dispositivos estritamente raster e, portanto, não têm definições de fonte residentes na impressora.