Я экспериментирую с использованием 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);
(выход слева на изображении ниже) печатный текст, кажется, почти в два раза по высоте и ширине.
Дополнительные замечания по экстентов и режимы отображения
Чарльз Петцольд Программирование для 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 может обрабатывать изменение размера изображения полностью через , изменяя размеры окна и области просмотра. Затем программа может использовать одни и те же логические единицы в функциях рисования независимо от размера окна .
В моем (очень) ограниченном опыте гораздо проще не обезьянствовать с режимом 'MM_ISOTROPIC'. Поскольку размеры бумаги известны заранее, мне гораздо проще просто работать в миллиметрах (вы можете так же легко использовать дюймы). Вот ссылка на тестовый код, с которым я работал, при первом запуске печати. Он печатает страницу на «принтер» для письма PDF, используя бумагу формата А4 (я думаю, это связано с тем, что по умолчанию принтер - A4, это было долгое время, и я забыл).На самом краю страницы появляется красная рамка, а на краю страницы находится еще 10 мм. Логотип составляет ~ 44x22 мм. (нет линейки) – enhzflep
(продолжение) Вот ссылка: http://pastebin.com/tSLMJpSb - Размер 44x22 соответствует указанному кодом. В настоящее время у меня нет доступа к принтеру или линейке, хотя изображение действительно оказывается на 10% выше расстояния от края страницы до края изображения, которое должно быть 20 мм. – enhzflep
@enhzflep благодарим вас за пример кода. Я не вижу, где вы устанавливаете режим отображения, поэтому я предполагаю, что он использует некоторые значения по умолчанию. Вы знаете, что это? Кажется, что ваша тестовая программа создает серию рисованных прямоугольников. С моей тестовой программой, использующей только текст, возможно, я должен использовать режим отображения MM_TEXT? Однако это потребует подсчета пикселов устройства, а примитивы WinAPI, по-видимому, предназначены для логических блоков. Возможно, MM_ISOTROPIC и MM_ANISOTROPIC предназначены для плоттеров? Будет ли MM_TWIPS лучше всего подходит для текста? –