Uns ist jetzt aufgefallen, dass es unerwünschte Ränder gibt, wenn wir die exportierte Metadatei auf ein millimeterbasiertes Zielgrafikobjekt zeichnen (das beim Drucken verwendet wird). Es scheint, dass GDI zu viel Inhalt aus der Quellmetadatei übernimmt. Wir legen daher ein Quellrechteck fest und setzen GraphicsUnit auf Pixel, wenn wir das Bild zum Ziel zeichnen. Dies hat dazu geführt, dass die oberen und linken Ränder verschwunden sind, aber die Ränder unten und rechts werden immer noch angezeigt.
Ich möchte betonen, dass wir viel mehr Rand erhalten als das übliche 1-Pixel-Interpolationsproblem, das Leute, die mit GDI zu tun haben, oft quält. Die üblichen Tricks mit Interpolation und Pixel-Offset-Einstellungen haben nicht geholfen.
Ich habe ein kurzes Programm geschrieben, das das Problem veranschaulicht. Entschuldigung für den langen Beitrag, aber ich werde Sie Schritt für Schritt durch den Artikel führen.
Den vollständigen Code finden Sie hier: https://dotnetfiddle.net/mpF0in
Quellgröße
Das Quellbild wird in Pixeln mit einer Abmessung von 500 x 250 generiert.
Code: Select all
const int SrcWidthPx = 500;
const int SrcHeightPx = 250;
var srcRectPx = new Rectangle(0, 0, SrcWidthPx, SrcHeightPx);
Ich erzeuge eine Metadatei mit der angegebenen Quellgröße als Rahmenrechteck und Pixeln als Einheit und zeichne ein Bild darauf.
Code: Select all
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);
}
}
Zum Vergleich erzeuge ich auch eine Bitmap mit der angegebenen Quellgröße und zeichne das gleiche Bild darauf.
Code: Select all
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);
}
Ich erstelle dann eine PNG-Datei für jedes Quellbild mit einem millimeterbasierten Grafikobjekt und zeichne das Quellbild in das Ziel. Die Einheit und Größe des Ziels ist unterschiedlich, aber das Seitenverhältnis ist dasselbe wie das der Quelle.
Ich lösche den PNG-Hintergrund in Orange. Wenn die Quelle das gesamte Ziel ausfüllt, sollte kein Pixel orange sein.
Code: Select all
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; //
Mobile version