Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Печать картинки во всю страницу  (Прочитано 10650 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
jur
Помогающий

lt
Offline Offline

« : 01-12-2011 08:37 » 

Приветствую!

Программирую на обычном 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.
Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #1 : 01-12-2011 09:26 » 

Не уверен, но возможно качественнее будет, если использовать SetTransform
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #2 : 01-12-2011 10:55 » 

Не уверен, но возможно качественнее будет, если использовать SetTransform

Че-то не понял я... Ведь эта "SetTransform" на матрицу умножает, наверное, навроде как DirectX с вершинами манипулирует. А мне нужно просто картинку отмасштабировать. Картинка в виде BMP-изображения (скриншот экрана).
Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #3 : 01-12-2011 11:47 » new

Так же как в GDI функция SetWorldTransform
Цитата
The SetWorldTransform function sets a two-dimensional linear transformation between world space and page space for the specified device context. This transformation can be used to scale, rotate, shear, or translate graphics output.
аналогичный функционал у GDI+ метода Graphics::SetTransform.
Более частный случай использования Graphics::SetTransform, что вполне подходит для твоей задачи - метод Graphics::ScaleTransform или еще лучше Graphics::SetPageScale.
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #4 : 01-12-2011 12:25 » 

Более частный случай использования Graphics::SetTransform, что вполне подходит для твоей задачи - метод Graphics::ScaleTransform или еще лучше Graphics::SetPageScale.

Переделал код так:

Код:
        Graphics* graphics;
        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);
*/
        StartPage(hdcPrint);
          graphics = new Graphics(hdcPrint);
          graphics->SetInterpolationMode(InterpolationModeHighQualityBicubic);
          graphics->SetPageUnit(UnitPixel);
          graphics->SetPageScale(2.0f); //(0.5f);
//        graphics->DrawImage(img, 0, 0);
          graphics->DrawImage(img, 0, 0, 0, 0, img->GetWidth(), img->GetHeight(), UnitPixel);
          delete graphics;
        EndPage(hdcPrint);

Результат - нулевой. Печатает точно так же, как раньше, без "SetResolution". Параметр метода "SetPageScale" что 0.5, что 2.0 - все едино. Как правильно применить этот "SetPageScale"?
Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #5 : 01-12-2011 13:23 » 

Попробуй так:
Код:
Graphics* graphics;
        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);
*/
        StartPage(hdcPrint);
          graphics = new Graphics(hdcPrint);
          graphics->SetInterpolationMode(InterpolationModeHighQualityBicubic);
          graphics->SetPageUnit(UnitPixel);
          graphics->SetPageScale(2.0f); //(0.5f);
          graphics->DrawImage(img, 0, 0, img->GetWidth(), img->GetHeight());
          delete graphics;
        EndPage(hdcPrint);
Сразу увидишь разницу.
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #6 : 01-12-2011 14:42 » 

Попробуй так:
...
Сразу увидишь разницу.

Да, картинка стала поменьше. Но если раньше на страницу помещалось чуть больше половины картинки, и ее размер не зависел от установок принтера, то теперь помещается она или нет - зависит от установленных в принтере DPI. Это - плохо. Хотелось бы печатать принтеронезависимо.

Наверное теперь следует поиграться параметром метода "SetPageScale", верно? Как обеспечить правильную печать независимо от того, какие DPI установлены в принтере и какой формат страницы в нем задан? Т.е. чтобы было так, как в случае использования "SetResolution": не зависит ни от принтера, ни от DPI, ни от размера страницы.

P.S. Или, может быть, в этой "SetResolution" и есть сермяжная правда? Может и не надо дергаться? Развейте сомнения, друзья! :-)
« Последнее редактирование: 01-12-2011 15:58 от jur » Записан

MPEG-4 - в массы!
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines