Рисование метафайла в графике с преобразованием единиц измерения игнорирует границыC#

Место общения программистов C#
Ответить
Anonymous
 Рисование метафайла в графике с преобразованием единиц измерения игнорирует границы

Сообщение Anonymous »

Мы используем FastReports и его ImageExporter в приложении .NET 8/C# WinForms для создания изображений, которые затем печатаются в определенных местах PrintDocument. Мы используем Metafile в качестве формата изображения, чтобы все было эффективно. FastReports использует некоторые трюки с масштабированием растровых изображений для создания метафайла, но при экспорте метафайла в пиксельный PNG мы получаем именно тот результат, который нам нужен.
Теперь мы заметили, что возникают нежелательные поля, когда мы рисуем экспортированный метафайл в целевом объекте Graphics размером в миллиметры (используемом во время печати). Кажется, GDI берет слишком много контента из исходного метафайла. Поэтому мы устанавливаем исходный прямоугольник и устанавливаем для GraphicsUnit значение пикселя при рисовании изображения в пункт назначения. Это привело к исчезновению верхнего и левого полей, но поля внизу и справа все еще видны.
Я хочу подчеркнуть, что мы получаем гораздо больше полей, чем обычная проблема интерполяции в 1 пиксель, которая часто преследует людей, имеющих дело с GDI. Обычные трюки с интерполяцией и настройками смещения пикселей не помогли.
Я написал короткую программу, иллюстрирующую проблему. Извините за длинный пост, но я расскажу вам об этом шаг за шагом.
Полный код можно найти здесь: https://dotnetfiddle.net/mpF0in
Размер источника
Исходное изображение генерируется в пикселях размером 500x250.

Код: Выделить всё

const int SrcWidthPx = 500;
const int SrcHeightPx = 250;

var srcRectPx = new Rectangle(0, 0, SrcWidthPx, SrcHeightPx);
Генерация исходного метафайла
Я генерирую метафайл с заданным исходным размером в качестве прямоугольника кадра и пикселями в качестве единицы измерения и рисую в него изображение.

Код: Выделить всё

const string MetaFileName = "metafile.emf";

using (var referenceGraphics = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr hdc = referenceGraphics.GetHdc();
try
{
using var metafile = new Metafile(MetaFileName,
hdc,
srcRectPx,
MetafileFrameUnit.Pixel,
EmfType.EmfPlusDual);

using var g = Graphics.FromImage(metafile);

DrawImage(g, srcRectPx);
}
finally
{
referenceGraphics.ReleaseHdc(hdc);
}
}
Создание исходного растрового изображения
Для сравнения я также создаю растровое изображение с заданным исходным размером и рисую в нем то же изображение.

Код: Выделить всё

const string BitmapFileName = "bitmap.bmp";

using (var bitmap = new Bitmap(srcRectPx.Width, srcRectPx.Height))
{
using var g = Graphics.FromImage(bitmap);

DrawImage(g, srcRectPx);

bitmap.Save(BitmapFileName, ImageFormat.Bmp);
}
Рисование окончательного изображения
Затем я приступаю к созданию PNG-файла для каждого исходного изображения с использованием объекта Graphics, размер которого составляет миллиметры, и рисую исходное изображение в месте назначения. Единицы измерения и размер места назначения отличаются, но соотношение сторон такое же, как у источника.
Я очищаю фон PNG в оранжевом цвете. Если источник заполняет все место назначения, ни один пиксель не должен быть оранжевым.

Код: Выделить всё

const int DestWidthMm = 20;
const int DestHeightMm = 10;
const float Dpi = 300f;

var destRectMm = new RectangleF(0, 0, DestWidthMm, DestHeightMm);
var destRectPx = new Rectangle(0, 0, (int)Math.Floor(DestWidthMm / 25.4f * Dpi), (int)Math.Floor(DestHeightMm / 25.4f * Dpi));

foreach (var fileName in new[] { MetaFileName, BitmapFileName })
{
using var srcImage = Image.FromFile(fileName);

using var destImage = new Bitmap(destRectPx.Width, destRectPx.Height, PixelFormat.Format32bppArgb);
destImage.SetResolution(Dpi, Dpi);

using (var gDest = Graphics.FromImage(destImage))
{
gDest.PageUnit = GraphicsUnit.Millimeter; // 

Подробнее здесь: [url]https://stackoverflow.com/questions/79817491/drawing-metafile-to-graphics-with-unit-conversion-ignores-boundaries[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»