О совместимости GDI / GDI + координат? - PullRequest
17 голосов
/ 22 февраля 2010

У меня проблема при рисовании как с GDI, так и с GDI + взаимозаменяемо.Преобразование страницы - в частности масштабирование - кажется, немного между этими двумя.Какие свойства контекста GDI влияют на масштабирование вывода, отличное от SetViewportExt и SetWindowExt?

Код использует почти исключительно GDI для рисования, но использует GDI + в некоторых случаях, когда его функции (полупрозрачность) необходимы.Он использует SetViewportExt, SetWindowExt и SetViewportOrg для включения масштабирования и прокрутки.

Когда требуется GDI +, я создаю объект Gdiplus::Graphics вокруг HDC и выполняю рисование.Я предполагаю, что это заставляет графический контекст обернуть контекст устройства и передать его рендеринг контексту устройства.Если я извлекаю матрицу преобразования графического контекста GDI +, я вижу, что это матрица идентичности, поэтому масштабирование выполняется в другом месте (в контексте устройства, я думаю).

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

CRect rect = ...;

// Draw the rectangle using GDI
CPen cpen(PS_DASH, 0, RGB(0,0,255));
pDC->SelectObject(&cpen);
pDC->Rectangle(rect);

{
    // Draw the rectangle using GDI+
    Gdiplus::Graphics graphics(pDC->m_hDC);

    Gdiplus::Pen pen(Gdiplus::Color(180,180,180));
    graphics.DrawRectangle(
        &pen,
        Gdiplus::Rect(rect.left, rect.top, rect.Width(), rect.Height()));
}

И вот результат: (синяя пунктирная линия нарисована GDI, а серая - GDI +)

Result drawn by code

Я ясно вижу, что две системы координат разные.Я ожидал некоторых ошибок округления, но не ошибки масштабирования, как показано здесь.Кроме того, когда я изменяю коэффициент масштабирования, GDI + перемещается в пределах ± 4 пикселя в обоих направлениях в зависимости от масштаба.Это также показано на скриншоте, так как прямоугольник GDI + имеет положительное смещение по оси X и отрицательное смещение по оси Y по сравнению с прямоугольником GDI.

  • Кто-нибудь знает, чточто здесь происходит?

  • Как мне заняться расследованием / отладкой этого?Это происходит в недрах окон, поэтому я, к сожалению, не могу его отладить.

Для справки, вот как выглядит мой viewport / window org / ext:

Window Ext: (134000, 80500)
Window Org: (0, 0)
Viewport Ext: (1452 872)
Viewport Org: (35 35)

Обновление:

Я исправил проблему, но это не красиво.Основной подход:

  1. Возьмите две координаты (начальную и вторую подходящую точку) в пространстве экрана и преобразуйте их в логические координаты, используя GDI (функция DPtoLP).

  2. Сброс преобразования GDI на MM_TEXT.

  3. Используйте преобразованные точки для построения матрицы преобразования для GDI +, представляющей то же преобразование

  4. И, наконец, используйте эту матрицу для построения контекста GDI + с правильным преобразованием.

Это что-то вроде хака, но это работает.Я до сих пор не знаю, почему между ними есть разница.По крайней мере, это показывает, что возможно иметь контекст GDI +, имитирующий преобразование GDI.

Ответы [ 4 ]

5 голосов
/ 14 апреля 2015

Краткий ответ: звонок graphics.SetPageUnit(Gdiplus::UnitPixel)

У меня была та же проблема, что и https://stackoverflow.com/a/4894969/700027: при печати, координаты для GDI + (Gdiplus :: Graphics) не совпадали с координатами из GDI (HDC).

graphics.GetPageUnit() возвращался UnitDisplay. Документация UnitDisplay:

Указывает единицы отображения. Например, если устройство отображения представляет собой монитор, то его размер составляет 1 пиксель.

Я ошибочно предположил, что для принтера UnitDisplay будет использовать точки принтера. После долгой борьбы я наконец узнал, что на самом деле он использует 1/100 дюйма по неизвестной причине. Если я использую Gdiplus :: UnitPixel, то координаты GDI + совпадают с координатами GDI.

2 голосов
/ 04 февраля 2011

У нас была такая же проблема.

(Справочная информация: GDI отлично работает практически для всего, и, кажется, намного быстрее для наших дисплеев в виде электронных таблиц с тысячами ячеек текста, которые необходимо визуализировать. Однако нам нужен GDI + для отображения .jpg.)

GDI + масштабирование показалось правильным при отображении материала на экране. У нас есть функция предварительного просмотра, которая использует преобразование координат, чтобы приложение отображало координаты принтера, но появлялось на экране. Все работало нормально, пока мы не отправили его на настоящий принтер (или пишущий инструмент PDF), когда масштабирование закончилось.

После трудозатрат, потраченных на человека в неделю (и получения от вас подсказки с вашим решением), это наше понимание:

В GDI + существует ошибка, которая возникает при вызове: «Графика (HDC)» (создание объекта «Графика» из контекста устройства GDI), когда HDC поступает с принтера или программного принтера, например, с помощью. Разрешение 6000 x 4000 пикселей, тогда GDI + игнорирует тот факт, что HDC работает с этим большим разрешением, и вместо этого он применяет свое собственное разрешение около 1000 x 800 пикселей.

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

Наше решение аналогично, но немного отличается на том основании, что мы на самом деле не хотим никаких преобразований координат:

        graphics.GetVisibleClipBounds(&rect);
        double deltaY = (double)GetPrinterH()/(double)rect.Height;
        double deltaX = (double)GetPrinterW()/(double)rect.Width;
        x1=x1/deltaX;
        x2=x2/deltaX;
        y1=y1/deltaY;
        y2=y2/deltaY;
        graphics.DrawImage(jpeg->image, x1,y1,x2-x1,y2-y1);

Эти коэффициенты масштабирования очень похожи на '6' во многих драйверах принтера.

0 голосов
/ 08 января 2014

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

Установка единиц измерения страницы в дюймах, а затем преобразование координат в дюймы, похоже, решает проблемы с рисованием без особой дополнительной работы. Протестировано с постоянным током дисплея и принтера при различных значениях DPI (от 72 до 4000).

Gdiplus::Graphics graphics(..);
Gdiplus::RectF    rect(0.0f, 0.0f, 1.0f, 1.0f);
Gdiplus::REAL     dpiX = graphics.getDpiX();
Gdiplus::REAL     dpiY = graphics.getDpiY();

/* Logical coordinates to inches. In this example, the window extents are
   equal to the DC's DPI. You will have to convert to inches based on your
   specific configuration. */
rect.X      /= dpiX;
rect.Y      /= dpiY;
rect.Width  /= dpiX;
rect.Height /= dpiY;

graphics.SetPageUnit(Gdiplus::UnitInch);
graphics.FillRectangle(.., rect);
0 голосов
/ 24 марта 2010

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

Попробуйте вручную установить несколько пикселей с помощью GDI + и GDI и посмотрите, отличаются ли они.

Возможно, способ преобразования координат вашей конкретной видеокарты отличается от того, как это происходит в GDI +

...