Как сделать предварительный просмотр в Win32 C ++? - PullRequest
9 голосов
/ 10 февраля 2010

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

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

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

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

Если я создаю «холст памяти» из окна HDC с тем же w, h, что и у страницы принтера, Шрифты выходят ПУСТО, потому что они масштабируются для экрана, а не для страницы ...

Должен ли я создатьCompatibleDC () из DC окна и CreateCompatibleBitmap () из DC принтера или что-то ??

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

Хорошо, я был бы признателен !!

... Steve

Ответы [ 3 ]

10 голосов
/ 11 февраля 2010

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

Есть много подходов. Звучит так, будто вы пытаетесь нарисовать растровое изображение размером с принтер, а затем уменьшить его. Шаги для этого:

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

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

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

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

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

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

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

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

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

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

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

Отредактировано для добавления

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

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

3 голосов
/ 11 февраля 2010

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

2 голосов
/ 11 февраля 2010

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

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