2017-02-20 59 views
1

我正在嘗試使用Windows GDI API進行打印,並且已經進行了一些試驗以試圖瞭解翻譯以及窗口和視口範圍的工作方式。如何使用SetViewportExtEx()和打印機確定設備單元中的水平和垂直範圍?

例子我發現使用GetDeviceCaps()得到HORZRES和VERTRES尺寸但它們除以二經GetDeviceCaps()返回的值(儘管衆所周知的事實,他們是不可靠和不準確的),然後使用這些值與SetViewportExtEx()

爲什麼cxpagecypage值減半了,我如何預測要使用的值和對打印輸出的影響?這是由於使用MM_ISOTROPIC作爲映射模式嗎?

例子使用類似下面的代碼:

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

在我的實際測試程序,我有以下功能時,我主要的Windows消息處理程序看到生成的消息IDM_PRINT當用戶從選擇打印,打印頁面測試應用程序的文件菜單。處理程序使用PrintDlg()獲取設備上下文(hDC)的句柄,然後調用此函數來執行打印。

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

當我修改的SetViewportExtEx()SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL);(下面的圖像中的右輸出)調用SetViewportExtEx(hDC, cxpage, cypage, NULL);打印文本似乎在高度和寬度幾乎雙(在左邊圖像中以下輸出)。

enter image description here

擴充上和其他注意事項映射模式

查爾斯Petzold的Windows程序設計第5版(第5章 - 繪畫基礎,第180頁)寫道:

公式還包括兩點指定「範圍」:點 (xWinExt,yWinExt)是邏輯座標中的窗口範圍; (xViewExt,yViewExt)是設備 座標中的視圖範圍。在大多數映射模式下,映射模式暗示範圍,並且不能更改。每個範圍本身並不意味着 本身,但視口範圍與窗口範圍的比率是用於將邏輯單元轉換爲設備單位的 比例因子。

例如,當設置了MM_LOENGLISH映射模式,視窗設定 xViewExt得到一定數目的像素和xWinExt是在由xViewExt像素所佔據百分之一英寸的長度。 比率爲您提供百分之一英寸的像素。出於性能原因,縮放因子 被表示爲整數的比率而不是浮點值 。

彼佐爾德然後繼續第187頁

剩下的兩個映射模式被命名爲MM_ISOTROPICMM_ANISOTROPIC上討論MM_ISOTROPICMM_ANISOTROPIC。這些是唯一的兩種映射模式,其中Windows允許您更改視口和窗口範圍,這意味着您可以更改Windows使用邏輯和設備座標翻譯 的縮放因子。單詞各向同性的意思是「相等於 各個方向」; 各向異性是相反的 - 「不等於」。像前面顯示的 度量映射模式一樣,MM_ISOTROPIC使用等比例的 軸。 x軸上的邏輯單位與y軸上的 邏輯單位具有相同的物理尺寸。當您需要創建圖像 時,這有助於保持正確的寬高比,而不管顯示設備的寬高比爲 。

MM_ISOTROPIC和所述度量的映射模式之間的差異是 與MM_ISOTROPIC可以控制 邏輯單元的物理尺寸。如果需要,可以根據客戶區域調整邏輯單元 的大小。這使您可以繪製包含在客戶區域中的圖像,總是 ,適當縮小並擴大 。第8章中的兩個時鐘程序具有各向同性的 圖像。當你調整窗口的大小時,時鐘的大小適當調整。

Windows程序可以通過調整窗口和視口範圍完全通過 來處理圖像的大小調整。然後程序可以在繪圖函數中使用相同的邏輯單元 ,而不管窗口的大小爲 。

+1

在我的(非常)有限的經驗中,不用猴'MM_ISOTROPIC'模式就可以了。由於預先知道紙張尺寸,我發現簡單地以毫米爲單位工作更容易(您可以輕鬆使用英寸)。這是第一次實施打印時與我合作的測試代碼的鏈接。它使用A4紙將頁面打印到PDF打印機'打印機'(我認爲這是因爲打印機的默認設置是A4,它已經很長時間了,我忘記了)。頁面的邊緣會出現紅色邊框,距離頁面邊緣還有10mm。該徽標是〜44x22毫米。 (無標尺) – enhzflep

+0

(續) 以下是鏈接:http://pastebin.com/tSLMJpSb - 44x22的大小與代碼報告的一樣。我目前無法使用打印機或尺子,儘管圖像看起來確實比從頁面邊緣到圖像邊緣的距離大約高10%,應該是20mm。 – enhzflep

+0

@enhzflep謝謝你的代碼示例。我沒有看到你在設置映射模式的位置,所以我假定它使用了一些默認值。你知道那是什麼嗎?您的測試程序似乎正在創建一系列繪製的矩形。使用我的測試程序只使用文本,也許我應該使用MM_TEXT的映射模式呢?但是,這需要計算設備像素,並且WinAPI基元似乎是爲邏輯單元設計的。也許MM_ISOTROPIC和MM_ANISOTROPIC是爲繪圖儀設計的? MM_TWIPS最適合文字嗎? –

回答

2

...爲什麼這麼多的例子使用SetViewportExtEx(hDC, cxpage/2, cypage/2, NULL);其中cxpage和cypage分別GetDeviceCaps(hDC, HORZRES)GetDeviceCaps(hDC, VERTRES) [?]

我懷疑MM_ISOTROPIC通常用於繪製圖表其中起點是在頁面的中心而不是角落。如果我們把你的代碼和調整它的起源移動到可打印區域的中心,就像這樣:

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

然後,你可以用繪製範圍從-1500到+1500邏輯座標。 (您可能還想要翻轉其中一個y範圍的符號以獲得正值「up」)。

對於文本輸出,我沒有看到將視口範圍減半的優勢,並且我會保留原點在左上方。

+0

是的,每個人似乎都用cxPage/2等來複制Petzold(例如,參見他的書中的圖13-6)。 –