2010-02-10 6 views
9

У меня есть функция рисования, которая просто принимает HDC. Но мне нужно показать ТОЧНУЮ масштабированную версию того, что будет печатать.Как сделать предварительный просмотр в win32 C++?

В настоящее время я использую CreateCompatibleDC() с принтером HDC и CreateCompatibleBitmap() с HDC принтера.

Я полагаю, что DC будет иметь точную ширину и высоту принтера. И когда я выбираю шрифты в этот HDC, текст будет масштабироваться точно так же, как принтер.

К сожалению, я не могу использовать StretchBlt(), чтобы скопировать пиксели HDC на HDC управления, поскольку они относятся к различным типам HDC, я думаю.

Если я создаю «холст памяти» из окна HDC с же W, H, как страницы принтера, шрифты выходят WAY маленькие, так как они масштабируются для экрана, а не страницы ...

Должен ли я CreateCompatibleDC() из DC окна и CreateCompatibleBitmap() из DC принтера или что-то в этом роде?

Если кто-то может объяснить ПРАВИЛЬНЫЙ способ сделать это. (И все еще есть что-то, что выглядит ТОЧНО, как это было бы на принтере) ...

Ну, я был бы признателен!

... Стив

+0

Я не слишком горжусь тем маршрутом, который я решил ...:/Получить информацию о DC принтера - ширину, высоту и логпиксели. CreateCompatibleDC, Bitmap из DC окна предварительного просмотра печати, но с шириной и высотой принтера (растровое изображение с размером памяти размером с mondo). Когда я создаю CreateFont, я использую - :: MulDiv (point, logPxlY, 72) для высоты (используя logPxlY из dc принтера). Soooooo, я надеюсь вернуться к этому не очень оптимальному решению, но у меня есть другая функциональность, чтобы добавить сначала ...:/http://pianocheater.com fyi :) –

+0

Argh !! Это нехорошее решение (тот, которым я не горжусь). На моей машине Vista с RAM 4 Gigs я не могу создать CreateCompatibleBitmap совместимого с экраном растрового изображения с w, h принтера - вне памяти - возможно, количество памяти графической карты, поскольку я уверен, что это поместилось бы в 4 гигабайта регулярная память. Вернуться к чертежной доске ... –

+0

Я знаю, что это было давно, но пытались ли вы создать растровое изображение из совместимого с принтером DC, а затем отменив его выбор и выбрав его в новый совместимый с DC DC для StretchBlt? Также вы можете просто разделить размеры и координаты растрового изображения на 2, чтобы он соответствовал, не рискуя слишком большим искажением. –

ответ

10

В зависимости от того, насколько вы точны быть точным, это может стать затруднительным.

Существует много подходов. Похоже, вы пытаетесь рисовать растровое изображение с размером принтера, а затем сжимаете его. Шаги для этого:

  1. Создайте DC (или, еще лучше, информационный контекст IC) для принтера.
  2. Запросить принтер DC, чтобы узнать разрешение, размер страницы, физические смещения и т. Д.
  3. Создайте DC для окна/экрана.
  4. Создайте совместимый DC (DC).
  5. Создайте совместимое растровое изображение для окна/экрана, но размер должен быть размером пикселя на странице принтера. (Проблема с этим подходом заключается в том, что это ОГРОМНОЕ растровое изображение, и он может выйти из строя.)
  6. Выберите совместимое растровое изображение в память DC.
  7. Нарисуйте память DC, используя те же координаты, которые вы использовали бы при рисовании на самом принтере.(Когда вы выбираете шрифты, убедитесь, что вы масштабируете их на логический дюйм принтера, а не на логический дюйм экрана.)
  8. StretchBlt Память DC к окну, которая уменьшит изображение целиком. Возможно, вам захочется поэкспериментировать с режимом растяжения, чтобы увидеть, что лучше всего подходит для изображения, которое вы собираетесь отображать.
  9. Освободить все ресурсы.

Но прежде чем вы направляетесь в этом направлении, рассмотрите альтернативы. Этот подход предполагает выделение ОГРОМНОГО экранного растрового изображения. Это может привести к сбою на компьютерах с ограниченными ресурсами. Даже если это не так, вы можете голодать на другие приложения.

Подход метафайлов, приведенный в другом ответе, является хорошим выбором для многих приложений. Я бы начал с этого.

Другой подход - выяснить все размеры в каком-то вымышленном устройстве с высоким разрешением. Например, предположим, что все находится в 1000-х дюймах. Затем ваши процедуры рисования масштабируют эту воображаемую единицу до фактических dpi, используемых целевым устройством.

Проблема с этим последним подходом (и, возможно, метафайлом) заключается в том, что шрифты GDI не масштабируются совершенно линейно. Ширины отдельных символов изменяются в зависимости от целевого разрешения. На устройстве с высоким разрешением (например, с лазерным принтером на 300 точек на дюйм) эта настройка минимальна. Но на экране с разрешением 96 точек на дюйм настройки могут содержать значительную ошибку по длине строки. Таким образом, текст в окне предварительного просмотра может оказаться несогласованным (обычно шире), чем на печатной странице.

Таким образом, хардкорный подход состоит в том, чтобы измерять текст в контексте принтера и снова измерять контекст экрана и корректировать несоответствие. Например, с использованием сделанных цифр вы можете измерить ширину текста в контексте принтера, и он будет отображаться до 900 пикселей принтера. Предположим, что отношение пикселей принтера к пикселям экрана равно 3: 1. Вы ожидали, что тот же текст на экране будет иметь ширину экрана 300 пикселей. Но вы измеряете в контексте экрана, и получаете значение, равное 325 пикселям экрана. Когда вы рисуете на экране, вам придется как-то сделать текст на 25 пикселей более узким. Вы можете спрятать символы ближе друг к другу или выбрать немного меньший шрифт, а затем растянуть их.

Хардкорный подход предполагает большую сложность. Например, вы можете попытаться обнаружить замены шрифтов, сделанные драйвером принтера, и сопоставить их так близко, как вы можете, с доступными экранными шрифтами.

Мне повезло с гибридом большого растрового изображения и хардкорными подходами. Вместо того, чтобы создавать гигантские растровые изображения для всей страницы, я делаю один достаточно большой для текста. Затем я рисую на размер принтера на заставку растрового изображения и StretchBlt до размера экрана. Это устраняет проблему несоответствия размера при небольшом ухудшении качества шрифта. Он подходит для фактического предварительного просмотра, но вы не хотите создавать такой редактор WYSIWYG. Однострочный растровый рисунок достаточно мал, чтобы сделать это практичным.

Хорошей новостью является только текст. Все остальные чертежи - это простое масштабирование координат и размеров.

Я не использовал GDI + много, но я думаю, что он покончил с нелинейным масштабированием шрифтов. Поэтому, если вы используете GDI +, вам просто нужно масштабировать координаты. Недостатком является то, что я не думаю, что качество шрифта на GDI + так же хорошо.

И, наконец, если вы являетесь родным приложением в Vista или более поздней версии, убедитесь, что вы отметили свой процесс как «DPI-aware». В противном случае, если пользователь находится на экране с высоким разрешением DPI, Windows будет лгать вам и утверждать, что разрешение составляет всего 96 точек на дюйм, а затем делает нечеткое масштабирование того, что вы рисуете.Это ухудшает качество изображения и может еще более усложнить отладку вашего предварительного просмотра. Так как многие программы плохо адаптируются к более высоким экранам DPI, Microsoft добавила «высокое масштабирование DPI» по умолчанию, начиная с Vista.

Edited добавить

Еще один нюанс: если вы выбираете HFONT в память с помощью принтера размера растрового изображения, это возможный, что вы получите другой шрифт, чем то, что бы получить при выборе тот же HFONT в фактический принтер DC. Это связано с тем, что некоторые драйверы принтеров заменят обычные шрифты в памяти. Например, некоторые PostScript-принтеры заменят внутренний шрифт PostScript для некоторых распространенных шрифтов TrueType.

Вы можете сначала выбрать HFONT в принтер IC, а затем использовать функции GDI, как GetTextFace, GetTextMetrics, и, возможно, GetOutlineTextMetrics, чтобы узнать о действительном выбранном шрифте. Затем вы можете создать новый LOGFONT, чтобы попытаться более точно сопоставить то, что будет использовать принтер, превратить его в HFONT и выбрать его в память DC. Это признак действительно хорошей реализации.

+0

Святой гуакамоле. Спасибо за все детали. Указывая на кого-то в правильном направлении, недостаточно хорошего для тебя, а? Gotta проложить землю с кирпичами и песком em smooth ... :) Похоже, у меня есть немало вещей, чтобы проверить. Большое спасибо! –

+0

GDI +, возможно, не лучший выбор для выхода, но он обеспечивает отличное масштабирование - гораздо лучшие результаты, чем StretchBlt, я думаю. –

+0

@MarkRansom: при масштабировании для предварительного просмотра печати четкость текста на экране обычно не является наивысшим приоритетом. –

2

Ну это не будет выглядеть так же, потому что у вас есть более высокое разрешение в принтере постоянного тока, так что вы должны написать функцию преобразования сортов. Я бы пошел с методом, который вам нужно, но текст был слишком мал и просто умножал каждый размер позиции/шрифта на ширину окна принтера и делился на ширину окна источника.

+0

Это была моя первоначальная мысль. но, похоже, я получил намного больше сейчас :) –

3

Одна вещь, которую стоит попробовать - создать расширенный метафайл DC, нарисовать его как обычно, а затем масштабировать этот метафайл с использованием показателей принтера. Это подход, используемый образцом BmpView . Я не знаю, насколько это будет точно, но, возможно, стоит посмотреть (должно быть легко переносить соответствующие классы на Win32, но WTL - отличная замена для программирования Win32, поэтому может стоить использовать.)

+0

Жаль, что я не могу выбрать 2 ответа:/ Я обязательно буду пытаться использовать этот подход (тоже). Большое спасибо! –