2017-02-20 39 views
1

Я экспериментирую с использованием Windows GDI API для печати и делаю несколько экспериментов, чтобы попытаться понять перевод и как работают окна и размеры видовых экранов.Как определить горизонтальные и вертикальные экстенты в устройствах с помощью SetViewportExtEx() и принтера?

Примеры, которые я нашел используют GetDeviceCaps(), чтобы получить HORZRES и размеры VERTRES (несмотря на известный факт, что они могут быть ненадежными и неточно), а затем использовать эти значения с SetViewportExtEx() однако они разделяют ценности, возвращаемые GetDeviceCaps() на два.

Почему значения cxpage и cypage уменьшены в два раза и как я могу предсказать используемые значения и эффект на распечатанном выходе? Это связано с использованием 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 генерируется, когда пользователь выбирает 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

Дополнительные замечания по экстентов и режимы отображения

Чарльз Петцольд Программирование для Windows 5th Edition (Глава 5 - Основные Drawing, страница 180) пишет:

формулы также включают две точки, которые указывают «экстенты»: точка (xWinExt, yWinExt) - размер окна в логических координатах; (xViewExt, yViewExt) - это длина вида в устройстве . В большинстве режимов отображения экстенты подразумеваются режимом отображения и не могут быть изменены. Каждая степень не означает ничего сама по себе , но отношение размера окна просмотра к размеру окна составляет коэффициент масштабирования для преобразования логических единиц в единицы устройства.

Например, при установке режима отображения MM_LOENGLISH, Windows устанавливает xViewExt быть определенное количество пикселей и xWinExt быть длиной в сотых долях дюйма, занимаемого xViewExt пикселей. Коэффициент дает вам пиксели на сотые доли дюйма. Масштабирующие коэффициенты выражены как коэффициенты целых чисел, а не значения с плавающей запятой по соображениям эффективности.

Петцольд затем переходит к обсуждению MM_ISOTROPIC и MM_ANISOTROPIC на странице 187.

Два оставшихся режимы отображения названы MM_ISOTROPIC и MM_ANISOTROPIC. Это только два режима отображения, для которых Windows позволяет изменять размер окна просмотра и окна, что означает , что вы можете изменить коэффициент масштабирования, который использует Windows для перевода логических и координатных координат устройства . Слово изотропное означает «равное по всем направлениям»; анизотропное - противоположное - «не равное». Как и , режим отображения метрики, показанный ранее, MM_ISOTROPIC использует одинаково масштабированные оси . Логические единицы по оси X имеют те же физические размеры, что и логические единицы по оси y . Это помогает, когда вам нужно создавать изображения , которые сохраняют правильное соотношение сторон независимо от формата изображения устройства отображения.

Разница между MM_ISOTROPIC и метрическими режимами отображения является , что с MM_ISOTROPIC вы можете контролировать физический размер логической единицы. Если вы хотите, вы можете настроить размер логического блока на основе клиентской области. Это позволяет вам нарисовать изображения, которые всегда содержат , содержащиеся в клиентской области, соответственно сокращая и расширяя . Две программы синхронизации в главе 8 имеют изотропные изображения . По мере того, как вы изменяете размер окна, часы изменяются соответствующим образом.

Программа Windows может обрабатывать изменение размера изображения полностью через , изменяя размеры окна и области просмотра. Затем программа может использовать одни и те же логические единицы в функциях рисования независимо от размера окна .

+1

В моем (очень) ограниченном опыте гораздо проще не обезьянствовать с режимом 'MM_ISOTROPIC'. Поскольку размеры бумаги известны заранее, мне гораздо проще просто работать в миллиметрах (вы можете так же легко использовать дюймы). Вот ссылка на тестовый код, с которым я работал, при первом запуске печати. Он печатает страницу на «принтер» для письма PDF, используя бумагу формата А4 (я думаю, это связано с тем, что по умолчанию принтер - A4, это было долгое время, и я забыл).На самом краю страницы появляется красная рамка, а на краю страницы находится еще 10 мм. Логотип составляет ~ 44x22 мм. (нет линейки) – enhzflep

+0

(продолжение) Вот ссылка: http://pastebin.com/tSLMJpSb - Размер 44x22 соответствует указанному кодом. В настоящее время у меня нет доступа к принтеру или линейке, хотя изображение действительно оказывается на 10% выше расстояния от края страницы до края изображения, которое должно быть 20 мм. – 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-экстентов, чтобы получить положительный «вверх».)

Для текстового вывода я не вижу никакого преимущества, чтобы уменьшить половину размеров окна просмотра, и я бы сохранил начало координат в левом верхнем углу.

+0

Да, все, кажется, копируют Петцольда с cxPage/2 и т. Д. (См. Рисунок 13-6 в своей книге). –