Как правильно масштабировать рисунок для EMF, используя gdi+

Моя программа Windows C++ создает EMF (расширенный формат метафайлов) для экспорта в буфер обмена, Word и Excel.

В следующем примере кода создается EMF-прямоугольник (ширина = высота =25), который составляет всего 12x12, а холст - 25x25 (примечание: разрешение экрана моего ноутбука составляет 3600x1800). При других разрешениях экрана возникают похожие аномалии масштабирования (слишком большие / слишком маленькие). Казалось бы, масштабирование графического рисунка должно быть установлено как функция разрешения. У меня явно есть пробел в моих знаниях здесь... любая помощь приветствуется.

HDC ref_dc = GetDC(NULL);
Rect r(0, 0, 25, 25);
Metafile* emf = new Metafile(ref_dc, r, MetafileFrameUnitPixel, EmfTypeEmfPlusDual, L"Drawing");//to HDC
Graphics* g = new Graphics(emf);

//draw a simple box
Gdiplus::Pen* pen = new Pen(Color(0, 255, 0), 1.0f);
pen->SetDashStyle(DashStyleSolid);
pen->SetLineCap(LineCapRound, LineCapRound, DashCapFlat);
g->DrawRectangle(pen, r);    // DrawMyObject(g);

// code here to put on clipboard

2 ответа

Хотя это не имеет отношения к вашей реальной проблеме, я чувствую себя очень вынужденным отметить, что ваш стиль программирования создания всех объектов в куче довольно странный. Нет причин использовать new как это. Просто создайте временные объекты в стеке. Это удерживает вас от утечки памяти и других ресурсов, таких как сито. В качестве иллюстрации, все, что вам нужно, это:

// Create Graphics object
Graphics g(emf);

// Draw a simple box
Gdiplus::Pen pen(Color(0, 255, 0), 1.0f);
pen.SetDashStyle(DashStyleSolid);
pen.SetLineCap(LineCapRound, LineCapRound, DashCapFlat);
g.DrawRectangle(pen, r);

// g and pen automatically go out of scope here, implicitly calling the destructor
// and freeing their resources. No need to call delete.

Что касается вашего реального вопроса, метафайлы не имеют фиксированного размера. Они в основном просто инкапсулируют серию инструкций рисования GDI, которые могут быть пересмотрены по желанию.

Обычный способ поместить расширенный метафайл в буфер обмена - это вызвать SetClipboardData функция, используя CF_ENHMETAFILE формат. Тип ручки, очевидно, будет HENHMETAFILE, Вам нужно получить GDI+, чтобы дать вам один из них, вероятно, с помощью Metafile::GetHENHMETAFILE метод после завершения загрузки / создания объекта метафайла.

За масштабирование / определение размера отвечает клиентский код, который получает ваш метафайл из буфера обмена и пытается его отобразить. Заголовок метафайла содержит запись, которая определяет его горизонтальное и вертикальное разрешение. Это можно затем масштабировать с точки зрения DPI дисплея. В GDI + что-то вроде:

Graphics g(...);

Metafile mf(L"MyFile.emf");
MetafileHeader mfh;
mf->GetMetafileHeader(&mfh);

REAL xScale = mfh->GetDpiX() / g.GetDpiX();
REAL yScale = mfh->GetDpiY() / g.GetDpiY();

g.ScaleTransform(xScale, yScale);

Самостоятельный ответ:

  1. Графика создается с "новым", потому что она должна быть уничтожена до того, как EMF будет "записано". В противном случае эдс не "записывает" шаги, выполняемые графическим объектом. Возможно, мы должны поставить дополнительный набор скобок, но это было бы одинаково неловко. Согласно документации: "Запись заканчивается, когда графический объект удаляется или выходит из области видимости". Отсюда явные new(s) и delete(s). EMF выталкивают в буфер обмена после уничтожения графики и до уничтожения EMF.

  2. * Ошибка / проблема, кажется, вызвана использованием конструктора для EMF, который включает структуру Rect в качестве аргумента. Измерения Rect, по-видимому, не имеют заметной связи с координатами объекта графов, используемыми для рисования, и, таким образом, он обрезает результирующую ЭДС непредсказуемым образом. Использование конструктора только с HDC или HDC и именем файла решает эту проблему, по крайней мере, в моих руках.

  3. Наконец, добавление строк кода

    REAL xScale = mfh->GetDpiX() / g.GetDpiX(); REAL yScale = mfh->GetDpiY() / g.GetDpiY(); g.ScaleTransform(xScale, yScale);

обеспечивает базовое масштабирование таким образом, что размер эдс более или менее одинаковый независимо от разрешения экрана. Это очень полезно, чтобы дать согласованный / разумный размер по умолчанию для экспорта на стороне пользователя.

Другие вопросы по тегам