Приветствую!
Программирую на обычном C++, без MFC. Разрабатываю DLL-ку "Printer", которая присоединяется к основной программе. Хочу научиться грамотно выводить на печать картинку (из файла или из HBITMAP - не важно) с возможностью автоматического масштабирования по ширине страницы. И, конечно же, хочется это делать с минимальными усилиями с моей стороны :-)
Для этого я воспользовался возможностями GDI+. Вот фрагмент кода функции непосредственно печати (только убрал загромождающие проверки ошибок, чтобы было читабельнее):
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
// Initialize GDI+
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
DWORD size;
HDC hdcPrint;
DOCINFO docInfo;
ZeroMemory(&docInfo, sizeof(docInfo));
docInfo.cbSize = sizeof(docInfo);
docInfo.lpszDocName = "GdiplusPrint";
// Get the size of the default printer name.
GetDefaultPrinter(NULL, &size);
// Allocate a buffer large enough to hold the printer name.
TCHAR* buffer = new TCHAR[size];
// Get the printer name.
if(!GetDefaultPrinter(buffer, &size)) {
UtilsR1_ShowLastErrorMessage("Printing");
}
else {
// Get a device context for the printer.
hdcPrint = CreateDC(NULL, buffer, NULL, NULL);
StartDoc(hdcPrint, &docInfo);
Graphics* graphics;
Bitmap* img = new Bitmap(CT2CW(img_file), FALSE);
img->SetResolution((float)GetDeviceCaps(hdcPrint, LOGPIXELSX), (float)GetDeviceCaps(hdcPrint, LOGPIXELSY));
StartPage(hdcPrint);
graphics = new Graphics(hdcPrint);
graphics->SetInterpolationMode(InterpolationModeHighQualityBicubic);
graphics->DrawImage(img, 0, 0); // (img, 0, 0, 0, 0, img->GetWidth(), img->GetHeight(), UnitPixel);
delete graphics;
EndPage(hdcPrint);
EndDoc(hdcPrint);
DeleteDC(hdcPrint);
}
delete buffer;
GdiplusShutdown(gdiplusToken);
Переменная "img_file" - параметр функции, имя файла картинки. Размер - 1024 х 768 пикселей. Метод "SetResolution" необходим из-за того, что иначе размер печати совершенно неправильный (естественно, т.к. картинка получена с экрана, 96 dpi).
Можно предположить, что это, по всей видимости, минимальный по размерам вариант кода. Это - хорошо.
Печатаю на термопринтере (ширина бумаги 105 мм, принтер по умолчанию), все нормально. Изменяю принтер по умолчанию на лазерный с обычной бумагой А4, печатаю, получаю малюсенькую картинку в верхнем левом углу. Что за черт? Смотрю в свойства обеих принтеров. И, конечно, у термопринтера есть включенная опция "Fit to page", а у лазерника этой опции вообще нет. Похоже на то, что нужно масштабировать картинку вручную. Использовать "StretchBlt" как-то не очень хочется... Во-первых, некачественно (я использую, конечно, "SetStretchBltMode", но все равно - не то). Во-вторых, интерполяция методом "InterpolationModeHighQualityBicubic" по-любому качественнее.
Думал, думал - ничего лучше (и проще) соответствующей коррекции параметров метода "SetResolution" не придумал. Правда, вроде работает нормально. Вот фрагмент добавленного кода (строка с "zoom_coef"):
Bitmap* img = new Bitmap(CT2CW(img_file), FALSE);
float zoom_coef = float(img->GetWidth()) / float(GetDeviceCaps(hdcPrint, HORZRES));
img->SetResolution(float(GetDeviceCaps(hdcPrint, LOGPIXELSX))*zoom_coef, float(GetDeviceCaps(hdcPrint, LOGPIXELSY))*zoom_coef);
Подскажите, пожалуйста, как такую печать по-грамотнее сделать? Правильно ли я выкрутился с разрешением картинки? Чему учит нас Партия в этом животрепещущем вопросе?
Спасибо!
P.S. Система Win XP, среда Visual Studio 2008.