DPI Графика Разрешение экрана Пиксели WinForm PrintPageEventArgs

Как точки Dpi связаны с пикселями для любого дисплея, на котором работает мое приложение?

int points;
Screen primary;

public Form1() {
  InitializeComponent();
  points = -1;
  primary = null;
}

void OnPaint(object sender, PaintEventArgs e) {
  if (points < 0) {
    points = (int)(e.Graphics.DpiX / 72.0F); // There are 72 points per inch
  }
  if (primary == null) {
    primary = Screen.PrimaryScreen;
    Console.WriteLine(primary.WorkingArea.Height);
    Console.WriteLine(primary.WorkingArea.Width);
    Console.WriteLine(primary.BitsPerPixel);
  }
}

Имею ли я теперь всю необходимую информацию?

Могу ли я использовать любую из приведенной выше информации, чтобы узнать, какова длина 1200 пикселей?


person jp2code    schedule 25.02.2011    source источник
comment
Примечание. Как только я научусь отображать свою форму для всех, данные в этой форме будут отправлены на принтер — отсюда и PrintPageEventArgs в заголовке.   -  person jp2code    schedule 25.02.2011


Ответы (3)


DPI буквально означает «точки на дюйм», где точки == пиксели. Итак, чтобы определить длину 1200 пикселей:

int inchesLong = (1200 / e.Graphics.DpiX);
person John Arlen    schedule 25.02.2011
comment
Настройки видео dpi никогда не бывают точными. Они фиксируются на 96, 120 или 144 независимо от размера монитора. - person Hans Passant; 25.02.2011
comment
@ Ганс Неправда. Например, я тестировал свое приложение с разрешением 192DPI. Выглядит довольно прикольно, но масштабируется нормально! - person David Heffernan; 25.02.2011
comment
@ Дэвид, ты купил другой монитор, чтобы соответствовать этому параметру dpi? Требуется, чтобы получить то же самое измерение в дюймах. - person Hans Passant; 25.02.2011
comment
@Hans Я представил свое приложение как DPIAWARE, а потом подумал, что должен хотя бы подчеркнуть это! К сожалению, вы не можете купить панели с достаточным количеством пикселей, чтобы сделать эту настройку DPI жизнеспособной, но это выглядело бы великолепно, если бы вы могли. И я к этому готов!! - person David Heffernan; 25.02.2011

Я понимаю, что прошло несколько месяцев, но, читая книгу по WPF, я наткнулся на ответ:

При использовании стандартной настройки DPI Windows (96 dpi) каждая независимая от устройства единица соответствует одному реальному физическому пикселю.

[Physical Unit Size] = [Device-Independent Unit Size] x [System DPI]
                     = 1/96 inch x 96 dpi
                     = 1 pixel

Следовательно, 96 пикселей, чтобы сделать дюйм с помощью системных настроек DPI Windows.

Однако на самом деле это зависит от размера вашего дисплея.

Для 19-дюймового монитора LDC с разрешением 1600 x 1200 использование теоремы Пифагора помогает рассчитать плотность пикселей для монитора:

[Screen DPI] = Math.Sqrt(Math.Pow(1600, 2) + Math.Pow(1200, 2)) / 19

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

/// <summary>
/// Calculates the Screen Dots Per Inch of a Display Monitor
/// </summary>
/// <param name="monitorSize">Size, in inches</param>
/// <param name="resolutionWidth">width resolution, in pixels</param>
/// <param name="resolutionHeight">height resolution, in pixels</param>
/// <returns>double presision value indicating the Screen Dots Per Inch</returns>
public static double ScreenDPI(int monitorSize, int resolutionWidth, int resolutionHeight) {
  //int resolutionWidth = 1600;
  //int resolutionHeight = 1200;
  //int monitorSize = 19;
  if (0 < monitorSize) {
    double screenDpi = Math.Sqrt(Math.Pow(resolutionWidth, 2) + Math.Pow(resolutionHeight, 2)) / monitorSize;
    return screenDpi;
  }
  return 0;
}

Я надеюсь, что другие получат некоторую пользу от этого изящного маленького инструмента.

person jp2code    schedule 17.05.2011

Для экрана: пиксели = Graphics.DpiY * точки / 72

Для принтера, упомянутого в теме вашего вопроса, отображение по умолчанию составляет 1 пиксель == 0,010 дюйма. Это довольно близко к разрешению видео по умолчанию, равному 96 точкам на дюйм, что делает копию на бумаге примерно такого же размера, как то, что вы видите на мониторе.

Делать снимки экрана формы и распечатывать их — плохая идея. У принтеров гораздо более высокое разрешение, обычно 600 dpi. Распечатка будет выглядеть зернистой, так как каждый пиксель на экране станет пятном размером 6x6 на бумаге. Особенно заметно и незаметно для сглаженного текста.

person Hans Passant    schedule 25.02.2011
comment
На самом деле форма предназначена только для «предварительного просмотра» данных перед их отправкой на принтер. Проект должен отображать все данные в форме, поскольку они будут отправлены на принтер. Прозрачный как грязь? :) - person jp2code; 25.02.2011
comment
Но что появилось раньше, курица или яйцо? LOL - я должен нарисовать объект ЧТО-ТО, прежде чем я смогу использовать MS PrintPreviewDialog ... если я что-то не упустил. - person jp2code; 26.02.2011
comment
Эм, вы в конечном итоге хотите его распечатать. Как только вы это сделаете, вы получите предварительный просмотр бесплатно. Делать наоборот - пустая трата времени. Реализуйте обработчик событий PrintDocument.PrintPage. - person Hans Passant; 26.02.2011
comment
... ну, в этом случае мне пришлось бы создать собственный PrintPreview. Мое текущее событие рисования будет отправлять информацию на панель формы. Также будут кнопки «Добавить» и «Удалить», чтобы включить в список дополнительные «объекты» для печати. - person jp2code; 26.02.2011
comment
Вы рисуете в контексте устройства (System.Drawing.Graphics). В обработчике Paint или переопределении OnPaint DC был получен вызовом BeginPaint и является экранным DC. Когда вы печатаете, вам предоставляется DC печати. При использовании PrintDialog или PrintPreviewDialog вы предоставляете объект PrintDocument. Именно в событии PrintPage этого документа вы получаете контроллер домена печати для рисования. - person Tergiver; 26.02.2011