I am using OpenXML to insert an image into my document. The code provided by Microsoft works, but makes the image much smaller:
public static void InsertAPicture(string document, string fileName)
{
using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true))
{
MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart;
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
imagePart.FeedData(stream);
}
AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart));
}
}
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId)
{
// Define the reference of the image.
var element =
new Drawing(
new DW.Inline(
new DW.Extent() { Cx = 990000L, Cy = 792000L },
new DW.EffectExtent()
{
LeftEdge = 0L,
TopEdge = 0L,
RightEdge = 0L,
BottomEdge = 0L
},
new DW.DocProperties()
{
Id = (UInt32Value)1U,
Name = "Picture 1"
},
new DW.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks() { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new PIC.Picture(
new PIC.NonVisualPictureProperties(
new PIC.NonVisualDrawingProperties()
{
Id = (UInt32Value)0U,
Name = "New Bitmap Image.jpg"
},
new PIC.NonVisualPictureDrawingProperties()),
new PIC.BlipFill(
new A.Blip(
new A.BlipExtensionList(
new A.BlipExtension()
{
Uri =
"{28A0092B-C50C-407E-A947-70E740481C1C}"
})
)
{
Embed = relationshipId,
CompressionState = A.BlipCompressionValues.Print
},
new A.Stretch(
new A.FillRectangle())),
new PIC.ShapeProperties(
new A.Transform2D(
new A.Offset() { X = 0L, Y = 0L },
new A.Extents() { Cx = 990000L, Cy = 792000L }),
new A.PresetGeometry(
new A.AdjustValueList()
) { Preset = A.ShapeTypeValues.Rectangle }))
) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = (UInt32Value)0U,
DistanceFromBottom = (UInt32Value)0U,
DistanceFromLeft = (UInt32Value)0U,
DistanceFromRight = (UInt32Value)0U,
EditId = "50D07946"
});
// Append the reference to body, the element should be in a Run.
wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
}
I need to make the image its original size. How can I do this? (I have googled how to do this outside of this process, but that is not what I am looking for. I have to assume that there are some sort of size properties inside of the given code).
Edit: Updated Code (still not working)
public static void InsertAPicture(string document, string fileName)
{
using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true))
{
MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart;
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
imagePart.FeedData(stream);
}
AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart), fileName);
}
}
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId, string fileName)
{
var img = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute));
var widthPx = img.PixelWidth;
var heightPx = img.PixelHeight;
var horzRezDpi = img.DpiX;
var vertRezDpi = img.DpiY;
const int emusPerInch = 914400;
const int emusPerCm = 360000;
var maxWidthCm = 16.51;
var widthEmus = (long)(widthPx / horzRezDpi * emusPerInch);
var heightEmus = (long)(heightPx / vertRezDpi * emusPerInch);
var maxWidthEmus = (long)(maxWidthCm * emusPerCm);
if (widthEmus > maxWidthEmus)
{
var ratio = (heightEmus * 1.0m) / widthEmus;
widthEmus = maxWidthEmus;
heightEmus = (long)(widthEmus * ratio);
}
// Define the reference of the image.
var element =
new Drawing(
new DW.Inline(
new DW.Extent() { Cx = 990000L, Cy = 792000L },
new DW.EffectExtent()
{
LeftEdge = 0L,
TopEdge = 0L,
RightEdge = 0L,
BottomEdge = 0L
},
new DW.DocProperties()
{
Id = (UInt32Value)1U,
Name = "Picture 1"
},
new DW.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks() { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new PIC.Picture(
new PIC.NonVisualPictureProperties(
new PIC.NonVisualDrawingProperties()
{
Id = (UInt32Value)0U,
Name = "New Bitmap Image.jpg"
},
new PIC.NonVisualPictureDrawingProperties()),
new PIC.BlipFill(
new A.Blip(
new A.BlipExtensionList(
new A.BlipExtension()
{
Uri =
"{28A0092B-C50C-407E-A947-70E740481C1C}"
})
)
{
Embed = relationshipId,
CompressionState = A.BlipCompressionValues.Print
},
new A.Stretch(
new A.FillRectangle())),
new PIC.ShapeProperties(
new A.Transform2D(
new A.Offset() { X = 0L, Y = 0L },
new A.Extents() { Cx = widthEmus, Cy = heightEmus }),
new A.PresetGeometry(
new A.AdjustValueList()
) { Preset = A.ShapeTypeValues.Rectangle }))
) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = (UInt32Value)0U,
DistanceFromBottom = (UInt32Value)0U,
DistanceFromLeft = (UInt32Value)0U,
DistanceFromRight = (UInt32Value)0U,
EditId = "50D07946"
});
// Append the reference to body, the element should be in a Run.
wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
}
The sizes, in EMUs (English Metric Unit — read this for a good explanation), are set in the Extents (the Cx and Cy).
In order to get a pic into a DocX I usually do it like so:
If the image’s width in EMUs is greater than the max page width’s, I scale the image’s width and height so that the width of image is equal to that of the page (when I say page, I’m referring to the “usable” page, that is minus the margins):
var ratio = hEmu / wEmu;wEmu = maxPageWidthEmu;hEmu = wEmu * ratio;I then use the width as the value of Cx and height as the value of Cy, both in the
DW.Extentand in theA.Extents(of theA.Transform2Dof thePIC.ShapeProperties).Note that the emuPerInch value is 914400.
I have this running (in a service) but I don’t have the code with me right now.
UPDATE
This is the code I use:
In my case, my page’s measures are in cm, hence the emusPerCm you see above.
UPDATE 2 (to answer @andw)
To have the file locked during the minimum possible time, open it with a
FileStreamand pass the resulting stream to theStreamSourceproperty of theBitmapImage: