Печать формы с более высоким разрешением, чем разрешение экрана

Проблема:

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

Для печати «Что видишь, то и получаешь» мы просто брали красиво оформленное окно и печатали его (отключая полосы прокрутки, кнопки и тому подобное). Это прекрасно работает, ЗА ИСКЛЮЧЕНИЕМ одного: разрешение экрана составляет 96 или 120 точек на дюйм (независимо от разрешения экрана)… любое из этих значений выглядит зернистым и непрофессиональным (наши клиенты жалуются). И хотя он такой же читаемый, как и на экране, вы ожидаете, что печатные документы будут БОЛЕЕ читаемы, чем на экране… вы ожидаете, что сможете увидеть дополнительные детали, сможете прочитать меньший текст и т. д.

Рассматриваемые альтернативы:

Учитывая, что у нас прекрасно работает автоматическое масштабирование, так что наше окно выглядит хорошо при разрешении 96 dpi, 120 dpi, 144 dpi и т. д., мы надеялись, что сможем просто нарисовать наше окно с разрешением 600 dpi, а затем распечатать его.

ИЛИ, мы рассмотрели рисование окна за пределами экрана в 5-6 раз больше, чем обычно, чтобы у нас было то же количество пикселей, что и при разрешении 600 точек на дюйм, но с разрешением 96 или 120 точек на дюйм… но затем рисование этого гигантского окна на печатной странице с разрешением 300 или 600 точек на дюйм. dpi (независимо от принтера).

Если вы можете рассказать нам, как сделать любой из этих вариантов, ИЛИ если вы можете дать нам другой способ достижения нашей цели, мы будем очень признательны.

Текущий код:

В случае, если это имеет значение, наша форма состоит из FlowLayoutPanel, укладывающего другие меньшие FlowLayoutPanels в столбцы, эти меньшие FlowLayoutPanels размещают один столбец TextBox, RichTextBox, стороннего RichTextEditor, PictureBox и DataGridView. Мы используем класс, производный от PrintDocument, реализующий OnBeginPrint, OnPrintPage и OnEndPrint. В OnPrintPage он манипулирует нашим обычным окном за пределами экрана (ниже и справа от фактических экранов), чтобы соответствовать размеру страницы, затем запрашивает нашу главную панель (верхнюю FlowLayoutPanel) для DrawToBitmap, затем использует объект Graphics, переданный в PrintEventArgs, для DrawImage это растровое изображение. Мы также используем Graphics.DrawString для применения нижнего колонтитула к каждой странице. Основной код:

                    using (Bitmap bm = new Bitmap(sz.Width, sz.Height))
                    {
                        Rectangle rect = new Rectangle(0, 0, sz.Width, sz.Height);
                        mp.DrawToBitmap(bm, rect);
                        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; // so footer is anti-aliased
                        e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;  // so when we scale up, we smooth out the jaggies somewhat
                        e.Graphics.DrawImage(bm, this.MarginBounds, rect, GraphicsUnit.Pixel);
                        if (this.Footer != null)
                            e.Graphics.DrawImage(this.Footer, this.FooterLocation);
                        if (!string.IsNullOrEmpty(pageNumber))
                        {
                            e.Graphics.DrawString(pageNumber, KBStyle.Normal.Font, Brushes.Black,
                                                  this.MarginBounds.X, this.FooterLocation.Y + FooterOffset);
                        }
                    }

Как мы должны это сделать, чтобы получить 600 dpi на печатной странице? (Или даже 300 dpi было бы здорово!)

Когда мы печатаем это, оно выглядит намного лучше при печати на машине с разрешением 120 точек на дюйм, чем при печати на машине с разрешением 96 точек на дюйм, поэтому мы знаем, что это печатается с разрешением экрана. Но также заставляет нас задаться вопросом, есть ли какой-нибудь простой способ сказать ей, что «эта форма должна рисоваться с разрешением 600 dpi», и тогда весь остальной код выше просто работает.

Примечание: если мы возьмем EMF (расширенный метафайл) и распечатаем его на принтере в приведенном выше коде, этот EMF выйдет с разрешением 600 точек на дюйм. К сожалению, мы не нашли метод DrawToEMF, который можно было бы вызывать для FlowLayoutPanel вместо DrawToBitmap. Изменение растрового изображения на 600 dpi не помогает… метод DrawToBitmap по-прежнему рисует растровое изображение с разрешением экрана.

Спасибо!!


person Brian Kennedy    schedule 29.02.2016    source источник
comment
Вы не можете преобразовать представление экрана FlowLayoutPanel в представление для печати. Вам нужно будет создать собственную процедуру рисования в событии PrintPage, используя метод DrawString. Нет бесплатного обеда.   -  person LarsTech    schedule 29.02.2016
comment
@LarsTech, не уверен, что понимаю ваш комментарий ... DrawToBitmap отлично работает на FlowLayoutPanel ... это, так сказать, бесплатный обед ... было довольно легко сделать его пригодным для печати (мы используем это сейчас, успешно) . В приведенном выше коде mp — это FlowLayoutPanel. Единственная проблема в том, что он делает это при разрешении экрана. И даже если размер окна больше (соответствует пикселям на странице), мы все равно, кажется, получаем только разрешение экрана.   -  person Brian Kennedy    schedule 01.03.2016
comment
У принтеров гораздо лучшее разрешение. Если вы хотите, чтобы он хорошо выглядел при разрешении принтера, вам придется отказаться от процедуры DrawToBitmap, где задействован текст, и начать использовать процедуры Printer DrawString.   -  person LarsTech    schedule 01.03.2016


Ответы (2)


Хорошо, я понял это... и это прекрасно работает!

Я до сих пор не знаю, как создать форму с разрешением 300 dpi и использовать функцию автомасштабирования.

НО…

Я доказал, что если вы создаете окно в 3,125 раза больше, чем необходимо, с разрешением 96 точек на дюйм, и увеличиваете шрифт в 3,125 раза и т. имеет разрешение 96 dpi, то вы можете использовать обычную функциональность Control.DrawToBitmap(), чтобы превратить его в растровое изображение, а затем вы можете использовать GDI Graphics.DrawImage(thatGiantBitmap, giganSrcRect, pageSizeDestRect) для объекта Graphics принтера, и он будет отображать эти гигантские пиксели с разрешением 96 точек на дюйм к пикселям размера страницы 300 точек на дюйм, что дает вам печать с разрешением 300 точек на дюйм. Идеально.

Для любого из наших окон, которые поддерживают изменение размера и позволяют нашим пользователям произвольно масштабировать содержимое, распечатать «Что видишь, то и получаешь» легко:

В OnBeginPrint вашего PrintDocument выполните:

(1) При желании дублируйте форму, чтобы не путаться с тем, на что смотрит пользователь

(2) Переместите форму, которую вы хотите напечатать, за пределы экрана (ниже и правее всех ваших экранов).

(3) Настройте форму так, чтобы она могла увеличиваться больше размера экрана (по умолчанию WinForms не будет увеличиваться больше размера экрана)

(4) Разделите 300 dpi на разрешение экрана, чтобы получить коэффициент роста.

(5) Развивайте свою форму с помощью фактора роста

(6) Масштабируйте его содержимое с помощью коэффициента роста (если они не масштабируются автоматически / автоматически масштабируются с размером формы)

В OnPrintPage вашего PrintDocument выполните:

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

(8) В e.Graphics выполните DrawImage(thatGiantBitmap, giganSrcRect, pageSizeDestRect)

Этот вызов DrawImage будет рисовать с разрешением принтера, если у вас есть столько пикселей в вашем thatGiantBitmap. В этом случае я вычислил растровое изображение, чтобы получить количество пикселей, необходимое для 300 dpi, поэтому я получу распечатки с разрешением 300 dpi, даже если принтер имеет разрешение 600 dpi. Если вам нужно полное разрешение 600 dpi, просто используйте 600 dpi в расчете шага 4.

person Brian Kennedy    schedule 12.03.2016

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

@media print {
  * {
    transform: scale(2000px,2000px);
  }
}
person Miriam Salzer    schedule 29.02.2016
comment
OP запрашивает решение winforms, которое не использует css - person JanR; 29.02.2016