user1211286
user1211286

Reputation: 759

Scaling bitmap into EMF via System.Drawing with specific width im millimeters?

I have a couple of bitmaps/pngs (screenshots), which I would like to "wrap" in EMFs having a specific width in millimeters (and a proportional height). Ideally, I would also want to add some overlays (text & rectangles).

Creating and saving an EMF seems to generally work fine, but I am unable to get any of the scaling right.

Here is my code:

var sourceBitmap = Image.FromFile(@"C:\temp\example.png");
Metafile metafile;
var aspectRatio = (float)sourceBitmap.Height / (float)sourceBitmap.Width;
var size = new Size(200, (int) (200*aspectRatio));
using (var stream = new MemoryStream())
{
    using (var offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))
    {
        IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();
        metafile = new Metafile(stream, deviceContextHandle, new RectangleF(0, 0, size.Width, size.Height), MetafileFrameUnit.Millimeter, EmfType.EmfPlusOnly); // this allocates one gdi object
        offScreenBufferGraphics.ReleaseHdc();
        using (var graphics = Graphics.FromImage(metafile))
        {
            graphics.PageUnit = GraphicsUnit.Millimeter;

            // may need to do something with ScaleTransform here??
            var metafileHeader = metafile.GetMetafileHeader();
            float sx = metafileHeader.DpiX / graphics.DpiX;
            float sy = metafileHeader.DpiY / graphics.DpiY;
            graphics.ScaleTransform(sx, sy);

            graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), new Rectangle(0, 0, size.Width, size.Height), GraphicsUnit.Pixel);

            var pen1 = new Pen(new SolidBrush(Color.Blue));
            var pen2 = new Pen(new SolidBrush(Color.Red));
            graphics.DrawRectangle(pen1, 0, 0, size.Width, size.Height);
            graphics.DrawLine(pen2, 0, 0, size.Width, size.Height);
            graphics.DrawLine(pen2, 0, size.Height, size.Width, 0);

            graphics.Dispose();
        }
    }
}


// save as a metafile
IntPtr metafileHandle = metafile.GetHenhmetafile();
var result = Gdi32.CopyEnhMetaFile(metafileHandle, @"C:\temp\example.emf");
if (result.ToInt32() == 0)
{
    var error = Marshal.GetLastWin32Error();
    throw new Win32Exception(error);
}
Gdi32.DeleteEnhMetaFile(result);
Gdi32.DeleteEnhMetaFile(metafileHandle);

Neither are the rectangle and diagonal lines correct, nor is the source bitmap correctly filled into the EMF. What am I doing wrong here?

The final EMF should be embedded into a Word document - hence the specific width. Note that I do not want to downsize the bitmaps and include these directly, since I would likely loose quality this way. Also note that I do not want to include the full bitmap in Word and have it adjust/scale the image, as I need to use {includepicture} which does not seem to reliably work with scaling.

Upvotes: 1

Views: 569

Answers (1)

Dallon Xu
Dallon Xu

Reputation: 80

I tried your code, the rectangle and diagonal lines are correct.

After changed(swaped param destRect and srcRect) the following code

graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), new Rectangle(0, 0, size.Width, size.Height), GraphicsUnit.Pixel);

to

graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, size.Width, size.Height), new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), GraphicsUnit.Pixel);

The source bitmap correctly filled into the EMF.

Upvotes: 1

Related Questions