2017-02-20 3 views
1

J'expérimente l'utilisation de l'API Windows GDI pour l'impression et j'ai fait quelques expériences pour essayer de comprendre la traduction et comment fonctionnent les extensions de fenêtre et de viewport.Comment déterminer les extensions horizontales et verticales dans les unités de périphérique avec SetViewportExtEx() et l'imprimante?

Les exemples que j'ai trouvé utilisent GetDeviceCaps() pour obtenir les HORZRES et les dimensions VERTRES (en dépit du fait connu qu'ils peuvent être peu fiables et imprécises) et l'utilisation de ces valeurs avec SetViewportExtEx() mais ils partagent les valeurs renvoyées par GetDeviceCaps() par deux.

Pourquoi les valeurs cxpage et cypage sont-elles divisées par deux et comment puis-je prédire les valeurs à utiliser et l'effet sur la sortie imprimée? Est-ce dû à l'utilisation de MM_ISOTROPIC comme mode de mappage?

exemples utilisent quelque chose comme le code suivant:

int cxpage = GetDeviceCaps (hDC, HORZRES); 
int cypage = GetDeviceCaps (hDC, VERTRES); 
SetMapMode (hDC, MM_ISOTROPIC); 
SetWindowExtEx(hDC, 1500, 1500, NULL); 
SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL); 
SetViewportOrgEx(hDC, 0, 0, NULL); 

Dans mon programme de test réel que j'ai la fonction suivante pour imprimer une page quand mon principal gestionnaire de message Windows voit le message IDM_PRINT généré lorsque l'utilisateur sélectionne Imprimer de le menu Fichier de l'application de test. Le gestionnaire utilise PrintDlg() pour obtenir un handle à un contexte de périphérique (hDC) puis appelle cette fonction pour exercer l'impression.

int PrintMyPages (HDC hDC) 
{ 
    int cxpage = GetDeviceCaps (hDC, HORZRES); 
    int cypage = GetDeviceCaps (hDC, VERTRES); 

    // When MM_ISOTROPIC mode is set, an application must call the 
    // SetWindowExtEx function before it calls SetViewportExtEx. Note that 
    // for the MM_ISOTROPIC mode certain portions of a nonsquare screen may 
    // not be available for display because the logical units on both axes 
    // represent equal physical distances. 
    SetMapMode (hDC, MM_ISOTROPIC); 

    // Since mapping mode is MM_ISOTROPIC we need to specify the extents of the 
    // window and the viewport we are using to see the window in order to establish 
    // the proper translation between window and viewport coordinates. 
    SetWindowExtEx(hDC, 1500, 1500, NULL); 
    SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL); 
    SetViewportOrgEx(hDC, 0, 0, NULL); 

    // figure out the page size in logical units for the loop that is printing 
    // out the pages of output. we must do this after setting up our window and 
    // viewport extents so Windows will calculate the DPtoLP() for the specified 
    // translation correctly. 
    RECT pageRect = {0}; 
    pageRect.right = GetDeviceCaps (hDC, HORZRES); 
    pageRect.bottom = GetDeviceCaps (hDC, VERTRES); 
    DPtoLP(hDC, (LPPOINT)&pageRect, 2); 

    // create my font for drawing the text to be printed and select it into the DC for printing. 
    HFONT DisplayFont = CreateFont (166, 0, 0, 0, FW_DONTCARE, false, false, false, DEFAULT_CHARSET, 
             OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 
             DEFAULT_PITCH | FF_DONTCARE, _T("Arial Rounded MT Bold")); 
    HGDIOBJ hSave = SelectObject (hDC, DisplayFont); 

    POINT ptLine = {300, 200}; // our printer line cursor for where printing should start. 

    static DOCINFO di = { sizeof (DOCINFO), TEXT ("INVOICE TABLE : Printing...")}; 
    StartDoc (hDC, &di); 
    StartPage (hDC); 

    for (int i = 1; i < 30; i++) { 
     TCHAR xBuff[256] = {0}; 
     swprintf (xBuff, 255, _T("This is line %d of my text."), i); 
     TextOut (hDC, ptLine.x, ptLine.y, xBuff, _tcslen(xBuff)); 
     // get the dimensions of the text string in logical units so we can bump cursor to next line. 
     SIZE lineSize = {0}; 
     GetTextExtentPoint32(hDC, xBuff, _tcslen(xBuff), &lineSize); 
     ptLine.y += lineSize.cy; // bump the cursor down to the next line of the printer. X coordinate stays the same. 
     if (ptLine.y + lineSize.cy > pageRect.bottom) { 
      // reached the end of this page so lets start another. 
      EndPage (hDC); 
      StartPage (hDC); 
      ptLine.y = 200; 
     } 
    } 

    // end the final page and then end the document so that physical printing will start. 
    EndPage (hDC); 
    EndDoc (hDC); 

    // Release the font object that we no longer need. 
    SelectObject (hDC, hSave); 
    DeleteObject (DisplayFont); 

    return 1; 
} 

Lorsque je modifie l'appel de SetViewportExtEx() de SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL); (sortie à droite dans l'image ci-dessous) à SetViewportExtEx(hDC, cxpage, cypage, NULL); (sortie sur la gauche dans l'image ci-dessous) le texte imprimé semble presque le double en hauteur et en largeur.

enter image description here

Remarques supplémentaires sur Étendues et modes de cartographie

Charles Petzold programmation Windows 5ème édition (Chapitre 5 - Dessin de base, à la page 180) écrit:

Les formules comprennent également deux points qui spécifient «étendues»: le point (xWinExt, yWinExt) est l'étendue de la fenêtre en coordonnées logiques; (xViewExt, yViewExt) correspond à l'étendue de la vue dans les coordonnées du périphérique . Dans la plupart des modes de mappage, les extensions sont impliquées par le mode de mappage et ne peuvent pas être modifiées. Chaque extension ne signifie rien par elle-même, mais le rapport entre l'étendue de la fenêtre et l'étendue de la fenêtre est un facteur de mise à l'échelle pour convertir les unités logiques en unités de périphérique.

Par exemple, lorsque vous définissez le mode de mappage de MM_LOENGLISH, Windows définit xViewExt être un certain nombre de pixels et xWinExt être la longueur en centièmes de pouce occupée par xViewExt pixels. Le ratio vous donne des pixels par centième de pouce. Les facteurs d'échelle sont exprimés en tant que rapports d'entiers plutôt que de valeurs en virgule flottante pour des raisons de performance.

Petzold va ensuite discuter MM_ISOTROPIC et MM_ANISOTROPIC à la page 187.

Les deux modes de mappage restants sont nommés MM_ISOTROPIC et MM_ANISOTROPIC. Ce sont les deux seuls modes de mappage pour lesquels Windows vous permet de modifier la fenêtre et l'étendue de la fenêtre, ce qui signifie que vous pouvez modifier le facteur d'échelle utilisé par Windows pour traduire les coordonnées logiques et de périphérique . Le mot isotrope signifie "égal à toutes directions"; anisotrope est le contraire - "pas égal." Comme les modes de mappage métrique montrés précédemment, MM_ISOTROPIC utilise des axes également mis à l'échelle. Les unités logiques sur l'axe des abscisses ont les mêmes dimensions physiques que unités logiques sur l'axe des ordonnées. Cela aide lorsque vous avez besoin de créer des images qui conservent les proportions correctes quel que soit le rapport d'aspect du périphérique d'affichage.

La différence entre MM_ISOTROPIC et les modes de mappage métrique est qu'avec MM_ISOTROPIC vous pouvez contrôler la taille physique de l'unité logique . Si vous le souhaitez, vous pouvez ajuster la taille de l'unité logique en fonction de la zone client. Cela vous permet de dessiner des images qui sont toujours contenues dans la zone client, en réduisant et en développant correctement . Les deux programmes d'horloge du chapitre 8 comportent des images isotropiques . Lorsque vous dimensionnez la fenêtre, les horloges sont redimensionnées de manière appropriée.

Un programme Windows peut gérer le redimensionnement d'une image entièrement via en ajustant la fenêtre et les extensions de la fenêtre. Le programme peut alors utiliser les mêmes unités logiques dans les fonctions de dessin indépendamment de la taille de la fenêtre.

+1

Dans mon expérience (très) limitée, il est beaucoup plus facile de ne pas faire de singe avec le mode MM_ISOTROPIC. Comme les formats de papier sont connus à l'avance, je trouve qu'il est beaucoup plus simple de travailler en millimètres (vous pouvez tout aussi bien utiliser des pouces). Voici un lien vers le code de test avec lequel j'ai travaillé lors de l'implémentation de l'impression pour la première fois. Il imprime une page à une 'imprimante' d'écriture de pdf, en utilisant du papier A4 (je pense que c'est parce que l'imprimante par défaut est A4, il a été longtemps et j'oublie).Le bord de la page reçoit une bordure rouge et il y a un autre 10mm à partir du bord de la page. Le logo est ~ 44x22 mm. (pas de règle) – enhzflep

+0

(suite) Voici le lien: http://pastebin.com/tSLMJpSb - La taille de 44x22 est telle que rapportée par le code. Je n'ai pas accès à une imprimante ou une règle à l'heure actuelle, bien que l'image semble en effet être environ 10% plus élevée que la distance entre le bord de la page et le bord de l'image, qui devrait être 20mm. – enhzflep

+0

@enhzflep merci pour l'exemple de code. Je ne vois pas où vous définissez le mode de cartographie, donc je suppose qu'il utilise un peu par défaut. Sais-tu ce que c'est? Votre programme de test semble créer une série de rectangles dessinés. Avec mon programme de test utilisant uniquement du texte, peut-être que je devrais utiliser un mode de mappage de MM_TEXT à la place? Cependant, cela nécessiterait de compter les pixels de l'appareil et les primitives WinAPI semblent être conçues pour les unités logiques. Peut-être MM_ISOTROPIC et MM_ANISOTROPIC sont-ils destinés aux traceurs? MM_TWIPS serait-il le meilleur pour le texte? –

Répondre

2

... pourquoi tant d'exemples utilisent SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL); où cxpage et cypage sont GetDeviceCaps(hDC, HORZRES) et GetDeviceCaps(hDC, VERTRES) respectivement [?]

Je soupçonne MM_ISOTROPIC est souvent utilisé pour tracer des graphiques où l'origine serait dans le centre de la page plutôt que dans le coin. Si nous avons pris votre code et peaufiné pour déplacer l'origine au centre de la zone imprimable, comme ceci:

SetWindowExtEx(hDC, 1500, 1500, NULL); 
SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL); 
SetViewportOrgEx(hDC, cxpage/2, cypage/2, NULL); 

Ensuite, vous pouvez tracer en utilisant les coordonnées logiques qui vont -1500 à 1500. (Vous pourriez également vouloir retourner le signe de l'une des extensions y pour obtenir un résultat positif.)

Pour la sortie textuelle, je ne vois aucun avantage à réduire de moitié l'étendue de la fenêtre et je garderais l'origine en haut à gauche.

+0

Oui, tout le monde semble copier Petzold avec cxPage/2 etc (par exemple voir la figure 13-6 dans son livre.) –