Как сделать файл EMF dpi осведомленным - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь работать с файлами emf, которые поддерживают dpi в Windows.Основная проблема заключается в том, что они не обрабатывают текст в формате dpi.Например, независимо от того, какое разрешение экрана или внутренняя эдс, графический объект, полученный из эдс, всегда сообщает 96 dpi.Это делает невозможным правильную обработку текста.

В моем случае мне дают размер изображения в дюймах, и мне нужно, чтобы мой рисунок соответствовал этому размеру.Чертеж представляет собой график XY с легендой, названием и названиями осей.Я использую результаты MeasureString, чтобы установить переменную заполнения для макета.Тот факт, что эдс не возвращает правильное значение dpi для своего графического объекта, приводит к тому, что текст постепенно ухудшается по мере того, как масштабирование / разрешение смещается дальше от 96, а также изменяется компоновка, потому что отступы не совпадают.

Вот код:

Сначала вычислите масштабный коэффициент настройки отображения

    // Calculate the scale setting
    // Note: Changing the Display Settings scale changes the screen pixel resolution (HORZRES). 
    // The desktop res is the physical numbers of pixels, and the logical pixel is set at boot up and never changes.
    System.Drawing.Graphics pGFX = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
    IntPtr hemfDC = pGFX.GetHdc();
    int dtX = GetDeviceCaps(hemfDC, DeviceCap.DESKTOPHORZRES);
    int dtY = GetDeviceCaps(hemfDC, DeviceCap.DESKTOPVERTRES);
    int scX = GetDeviceCaps(hemfDC, DeviceCap.HORZRES);
    int scY = GetDeviceCaps(hemfDC, DeviceCap.VERTRES);
    int lpX = GetDeviceCaps(hemfDC, DeviceCap.LOGPIXELSX);
    int lpY = GetDeviceCaps(hemfDC, DeviceCap.LOGPIXELSY);
    pGFX.ReleaseHdc();
    int dpiX = (int)(((float)dtX / (float)scX) * lpX);
    int dpiY = (int)(((float)dtY / (float)scY) * lpY);
    float scaleX = ((((float)dtX / (float)scX) * lpX) / pGFX.DpiX);
    float scaleY = ((((float)dtY / (float)scY) * lpY) / pGFX.DpiY);

Затем создайте метафайл

    Metafile image = null;
    MetafileHeader mfh = null;
    SizeF emfSize = new SizeF(pageSize);

    using (MemoryStream stream = new MemoryStream())
    {
        IntPtr hDC = gfx.GetHdc();
        try
        {
            image = new Metafile(
                    stream,
                    hDC,
                    new RectangleF(new PointF(0, 0), emfSize),
                    MetafileFrameUnit.Inch,
                    EmfType.EmfPlusOnly);
        }
        finally
        {
            gfx.ReleaseHdc();
        }
    }

Наконец, вызовите код чертежа.Код чертежа принимает размер в пикселях, а не в дюймах.Обратите внимание, что размер файла в пикселях - это размер определяемого пользователем масштабного коэффициента, где 100% предполагается равным g.Dpi (т.е. 96).Это предположение оказалось верным для всех протестированных мною мониторов.

    if (image != null)
    {

        using (Graphics g = Graphics.FromImage(image))
        {
            mfh = image.GetMetafileHeader();
            emfSize.Width *= g.DpiX * scaleX;
            emfSize.Height *= g.DpiY * scaleY;

            g.PageUnit = GraphicsUnit.Pixel;
            g.ScaleTransform(mfh.DpiX / g.DpiX, mfh.DpiY / g.DpiY);

            DrawGraph(g, ref emfSize);
        }

    }

1 Ответ

0 голосов
/ 06 февраля 2019

Я обернул Graphic DrawString и MeasureString, чтобы временно масштабировать шрифт, используя рассчитанную шкалу настройки Display.Это не идеальный, но лучший компромисс, который я могу найти.

private void DrawString(Graphics g, string s, Font font, Brush brush, PointF point)
{
    Font f = new Font(font.FontFamily, font.SizeInPoints * Graph.FontScale, font.Style, GraphicsUnit.Point);
    g.DrawString(s, f, brush, point);
}
...