Вопрос

У меня есть приложение, которое генерирует метафилы (EMF). Он использует эталонное устройство (он же экран) для отображения этих метафилей, поэтому DPI метафильного изменяется в зависимости от того, на какой машине работает код.

Скажем так

  • rclframe {0, 0, 21590, 27940} (измерения метафила, в тысятах мм)
  • S -Sldevice {1440, 900} (размеры эталонного устройства, в пикселях)
  • Szlmillimeters {416, 260} (размеры эталонного устройства, в мм)

Итак, Rclframe говорит мне, что размер ЭДС должен быть

  • 21590/2540 = 8,5 в широком
  • 27940 /2540 = 11 в высоких

Право на. Используя эту информацию, мы также можем определить физический DPI моего монитора, если моя математика верна:

  • (1440 * 25,4) / 416 = 87,9231 Горизонтальный DPI
  • (900 * 25,4) / 260 = 87,9231 Вертикальный DPI

Проблема

Все, что воспроизводит этот метафил-преобразование EMF в PDF, страница «Сводка», когда щелкните правой кнопкой мыши на EMF в Windows Explorer и т. Д.-Стремительно усечь рассчитанное значение DPI, отображая 87 вместо 87,9231 (даже 88 будет хорошо).

Это приводит к странице, которая имеет физический размер как 8,48 в x 10,98 в (с использованием 87 dpi) вместо 8,5 в x 11 в (с использованием 88 dpi), когда метафил воспроизводится.

  • Можно ли изменить DPI эталонного устройства, чтобы информация, хранящаяся в метафиле, используемой для расчета DPI, выходила на хорошее целое число?
  • Могу ли я создать контекст моего собственного устройства и указать его DPI? Или мне действительно нужно использовать принтер для этого?

Спасибо за какое -либо понимание.

Это было полезно?

Решение

Мне любопытно, как Windows знает физический размер вашего монитора. Вы, должно быть, где -нибудь изменили конфигурацию? Возможно, вы можете изменить его на более удобные ценности, которые хорошо разделились.

Как подразумевается имя, «контекст устройства» должен быть подключен к системному устройству. Однако это не обязательно должен быть аппаратный драйвер, это может быть эмулятор устройства, такой как драйвер печати писателя PDF. Я видел хотя бы один, который позволяет вам установить произвольный DPI.

Другие советы

Теперь я узнал больше, чем я заботился о метафилях.

1. Некоторые из Metafile Перегрузки конструктора класса работают плохо и будут работать на усеченном значении DPI.

Рассмотрим следующее:

protected Graphics GetNextPage(SizeF pageSize)
{
    IntPtr deviceContextHandle;
    Graphics offScreenBufferGraphics;
    Graphics metafileGraphics;
    MetafileHeader metafileHeader;

    this.currentStream = new MemoryStream();
    using (offScreenBufferGraphics = Graphics.FromHwnd(IntPtr.Zero))
    {
        deviceContextHandle = offScreenBufferGraphics.GetHdc();
        this.currentMetafile = new Metafile(
            this.currentStream,
            deviceContextHandle,
            new RectangleF(0, 0, pageSize.Width, pageSize.Height),
            MetafileFrameUnit.Inch,
            EmfType.EmfOnly);

        metafileGraphics = Graphics.FromImage(this.currentMetafile);

        offScreenBufferGraphics.ReleaseHdc();
    }

    return metafileGraphics;
}

Если вы прошли в SizeF {8.5, 11}, вы можете ожидать Metafile это имеет rclFrame {21590, 27940}. В конце концов, преобразование дюймов в миллиметры не сложно. Но вы, вероятно, не будете. В зависимости от вашего разрешения, GDI+, похоже, будет использовать усеченное значение DPI при преобразовании параметра дюймов. Чтобы сделать это правильно, я должен сделать это сам в сотнях миллиметра, который GDI+ проходит, так как это то, как он изначально хранится в заголовке метафилов:

this.currentMetafile = new Metafile(
    this.currentStream,
    deviceContextHandle,
    new RectangleF(0, 0, pageSize.Width * 2540, pageSize.Height * 2540),
    MetafileFrameUnit.GdiCompatible,
    EmfType.EmfOnly);

Ошибка округления № 1 решена- rclFrame моего метафиля теперь верна.

2. DPI на Graphics Запись экземпляра в Metafile всегда неправильно.

Видеть, что metafileGraphics переменная, которую я установил, позвонив Graphics.FromImage() на метафиле? Ну, кажется, что Graphics Пример всегда будет иметь DPI 96 DPI. (Если бы мне пришлось догадаться, это всегда установлено логичный DPI, а не физический один.)

Вы можете представить, что веселье, которое следует, когда вы рисуете Graphics экземпляр, который работает под 96 DPI и записывает в Metafile экземпляр, который имеет 87,9231 DPI «записан» в его заголовке. (Я говорю «записано», потому что он рассчитывается по другим значениям.) «Пиксели» метафила (помните, команды GDI, хранящиеся в метафиле, указаны в пиксели) больше, и поэтому вы проклинаете и бормотите, почему ваш призыв нарисовать что-то в длину один дюйм в конечном итоге оказался в дюймах в одном и с чем-то.

Решение состоит в том, чтобы уменьшить Graphics пример:


metafileGraphics = Graphics.FromImage(this.currentMetafile);
metafileHeader = this.currentMetafile.GetMetafileHeader();
metafileGraphics.ScaleTransform(
    metafileHeader.DpiX / metafileGraphics.DpiX,
    metafileHeader.DpiY / metafileGraphics.DpiY);

Разве это не крик? Но, кажется, работает.

«Закругление» ошибка № 2 Решена-Когда я говорю, нарисуйте что-то в «1 дюйм» на 88 dpi, что пиксель лучше быть $%$^! Записано как Pixel #88.

3. szlMillimeters может отличаться дико; Удаленный рабочий стол приносит много удовольствия.

Итак, мы обнаружили (по ответу Марка), что иногда Windows запрашивает edid вашего монитора и на самом деле знает, насколько он велик физически. GDI+ полезно использует это (HORZSIZE и т.д.) при заполнении в szlMillimeters имущество.

А теперь представьте, что вы идете домой, чтобы отлаживать этот код удаленного рабочего стола. Допустим, у вашего домашнего компьютера есть широкоэкранный монитор 16: 9.

Очевидно, что Windows не может запрашивать edid удаленного дисплея. Таким образом, он использует вековой дефолт 320 x 240 мм, что было бы хорошо, за исключением того, что это является соотношение сторон 4: 3, и теперь тот же код генерирует метафил на дисплее, на котором предположительно не есть не Квадратные физические пиксели: горизонтальный DPI и вертикальный DPI разные, и я не могу вспомнить в последний раз, когда я видел это.

На данный момент мой обходной путь: «Ну, не запускайте его под удаленным рабочим столом».

4. Инструмент EMF-TO-PDF, который я использовал, имел ошибку округления при просмотре на rclFrame заголовок.

Это была основная причина моей проблемы, которая вызвала этот вопрос. Моя метафиль была «правильной» на все время (ну, правильно после того, как я исправил первые два выпуска), и весь этот поиск для создания метафил «высокого разрешения» была красной сельдью. Это правда, что некоторая верность теряется при записи метафил на дисплеевом устройстве с низким разрешением; Это потому, что команды GDI, указанные в метафиле, указаны в пикселях. Неважно, что это векторный формат и может масштабировать или вниз, некоторая информация теряется Во время фактической записи Когда GDI+ решает, какой «пиксель» привязать операцию.

Я связался с продавцом, и они дали мне исправленную версию.

Ошибка округления № 3 решена.

5. Панель «Сводка» в Windows Explorer просто так, как и усеть значения при отображении рассчитанного DPI.

Так получилось, что это усеченное значение представляло такое же ошибочное значение, которое использовал инструмент EMF-TO-PDF. Кроме того, эта причуда не вносит ничего значимого для обсуждения.

Выводы

Поскольку мой вопрос был о Futzing с DPI в контекстах устройства, Mark's - хороший ответ.

Обратите внимание, что я работаю с 120 DPI на WXP все время (большие шрифты), что означает, что метафилеграфика. DPIX будет возвращать 120.

Файл EMF, по -видимому, не записывает то, что DPI был справочным контекстом (120 в данном случае, 96 для большинства других людей).

Чтобы сделать вещи более интересными, можно создать ЭДС с помощью рисунка на растровом карте в памяти, на котором было установлено SetResolution (), скажем, 300DPI. В этом случае я считаю, что коэффициент масштабирования должен быть 300, а не то, что может использовать монитор (86.x) или Windows (120).

Похоже, что значения на Сводной странице неверны. Они рассчитаны как:

Size = round(precize_size)+1
Resolution = trunc(precize_resolution)

Где точные значения рассчитываются без округления или усечения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top