Теперь мы заметили, что возникают нежелательные поля, когда мы рисуем экспортированный метафайл в целевом объекте 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]
Мобильная версия