Constructing an OpenXmlElement from bitmap picture to append into a Run instance - c#

I have the following code:
string replaceValueString = parameterValue.ToString();
Run replaceRun = new Run();
replaceRun.Append(new Text(replaceValueString));
contentControl.InsertAfterSelf(replaceRun);
I need to add a similar logic, but instead of Text, I need to add Picture (or some other type of image instance), like that:
replaceRun.Append(new Picture(data));
I have a Bitmap class, I can also pass byte[] or Steam of the image. My only problem is, I found virtually no example how to construct this Picture class, inherited from OpenXmlCompositeElement.
Can someone provide me with some examples and guides, in order to convert from Bitmap/data[]/Steam image into DocumentFormat.OpenXml.Wordprocessing.Picture (or any other OpenXmlElement)?
So far I found only this example:
https://learn.microsoft.com/en-us/office/open-xml/how-to-insert-a-picture-into-a-word-processing-document
...it creates a Drawing class instead of a picture, and it uses some DW SDK, which I don't have access to.

The example you have provided can seem daunting at first but it is very useable if you work through it...
it uses some DW SDK, which I don't have access to.
The DW is simply just an alias to some namespaces that you will no doubt have access to already. Make sure you include the following at the top of your class file:
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
With that in mind. Let's start with your Bitmap. First, you want to use that to create an ImagePart. The following code may seem like it is adding an image straight to the main document, but it doesn't quite work like that. Don't worry, we will move it to your run later.
MainDocumentPart mainDocumentPart = wordDoc.MainDocumentPart;
ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Bmp);
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Position = 0;
imagePart.FeedData(stream);
}
We need to get the ID of the image part, so that we can use that when creating the Drawing object.
string imagePartId = mainDocumentPart.GetIdOfPart(imagePart);
Next, we need to use that code that you didn't like from here.
Let's just take everything we have so far and stick it into a function that will create a Drawing from a Bitmap.
static Drawing ConvertBitmapToDrawing(WordprocessingDocument wordDoc, System.Drawing.Bitmap image)
{
MainDocumentPart mainDocumentPart = wordDoc.MainDocumentPart;
ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Bmp);
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Position = 0;
imagePart.FeedData(stream);
}
string imagePartId = mainDocumentPart.GetIdOfPart(imagePart);
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 = imagePartId,
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" });
return element;
}
With this function, you can finally just do something like this:
Drawing drawing = ConvertBitmapToDrawing(wordProcessingDocument, myBitmap);
Run newRun = new Run(drawing);
contentControl.InsertAfterSelf(newRun);

Related

C# WordprocessingDocument - insert an image in a cell

I have a method that replaces the tags in the document specific text. How do I replace the label picture?
Here is a piece of code that looks for a cell with the text 'PersonMainPhoto' inside a table. The tabel-cell is cleared, and an image is inserted. Hopefully this can guide you in the right direction.
Inserting an image is a two part process:
Add image part to the document
Insert a reference to the image inside the body text - with all kinds of details regarding scaling, positioning etc.
The code for inserting the reference is taken from the brilliant OpenXML SDK documentation: https://msdn.microsoft.com/en-us/library/office/bb497430.aspx
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
namespace StackOverflow
{
class Program
{
static void Main(string[] args)
{
string file = #"c:\temp\mydoc.docx";
string imageFile = #"c:\temp\myimage.jpg";
string labelText = "PersonMainPhoto";
using (var document = WordprocessingDocument.Open(file, isEditable: true))
{
var mainPart = document.MainDocumentPart;
var table = mainPart.Document.Body.Descendants<Table>().First();
var pictureCell = table.Descendants<TableCell>().First(c => c.InnerText == labelText);
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
using (FileStream stream = new FileStream(imageFile, FileMode.Open))
{
imagePart.FeedData(stream);
}
pictureCell.RemoveAllChildren();
AddImageToCell(pictureCell, mainPart.GetIdOfPart(imagePart));
mainPart.Document.Save();
}
}
private static void AddImageToCell(TableCell cell, string relationshipId)
{
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
});
cell.Append(new Paragraph(new Run(element)));
}
}
}
how do the picture fit, just into tablecell!??
not to fix it .
Cx = 990000L, Cy = 792000L
like this?
TableCellProperties tableCellProperties1 = VARIABLE.GetFirstChild<TableCellProperties>();
TableCellWidth tableCellWidth1 = tableCellProperties1.GetFirstChild<TableCellWidth>();
int _width = Int32.Parse(tableCellWidth1.Width);
TableRowProperties tableRowProperties1 =
VARIABLE.Parent.GetFirstChild<TableRowProperties>();
TableRowHeight tableRowHeight1 =
tableRowProperties1.GetFirstChild<TableRowHeight>();
int _height = Int32.Parse(tableRowHeight1.Val);
document.MainDocumentPart.Document.Save();

How to replace bookmark in Word document (docx) with an image using Open XML SDK?

I need to take a template Word document with a set of bookmarks, and replace them with images (removing the bookmark itself). The examples of working with bookmarks I've seen are confusing and I'm not sure they apply to using an ImagePart, since it seems that things are different depending on content.
Could someone provide a straightforward example?
You can use the below method ReplaceBookmarksWithImage to replace all the bookmarks with a given image. The word template file path and image file path are parameters. You can extend the code if you need different images for each bookmarks.
private static void ReplaceBookmarksWithImage(string wordDocTempaltePath, string imageFilename)
{
WordprocessingDocument doc = WordprocessingDocument.Open(wordDocTempaltePath, true);
// Read all bookmarks from the word doc
foreach (BookmarkStart bookmarkStart in doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
{
// insert the image
InsertImageIntoBookmark(doc, bookmarkStart, imageFilename);
// remove the bookmark
bookmarkStart.Remove();
}
doc.Close();
}
public static void InsertImageIntoBookmark(WordprocessingDocument doc, BookmarkStart bookmarkStart, string imageFilename)
{
// Remove anything present inside the bookmark
OpenXmlElement elem = bookmarkStart.NextSibling();
while (elem != null && !(elem is BookmarkEnd))
{
OpenXmlElement nextElem = elem.NextSibling();
elem.Remove();
elem = nextElem;
}
// Create an imagepart
var imagePart = AddImagePart(doc.MainDocumentPart, imageFilename);
// insert the image part after the bookmark start
AddImageToBody(doc.MainDocumentPart.GetIdOfPart(imagePart), bookmarkStart);
}
public static ImagePart AddImagePart(MainDocumentPart mainPart, string imageFilename)
{
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
using (FileStream stream = new FileStream(imageFilename, FileMode.Open))
{
imagePart.FeedData(stream);
}
return imagePart;
}
private static void AddImageToBody(string relationshipId, BookmarkStart bookmarkStart)
{
// 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"
});
// add the image element to body, the element should be in a Run.
bookmarkStart.Parent.InsertAfter<Run>(new Run(element), bookmarkStart);
}
and here are the using statements
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using A = DocumentFormat.OpenXml.Drawing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
I'm trying to put in the word bookmark, the image in memory stream instead of image file. In the marker I get an image with an "X".
public static ImagePart AddStreamPart(MainDocumentPart mainPart, Stream ImageSignature)
{
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
imagePart.FeedData(ImageSignature);
return imagePart;
}

C# OpenXML image in center

I'm trying to generate a DocX document with an image in the center of the document, but i have tried several things but nothing has worked out. The image is showing but in the top left corner. The function addImageToBody is from the MS website (http://msdn.microsoft.com/en-us/library/office/bb497430(v=office.15).aspx). I've tried to use the HorizontalPosition Class (http://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.wordprocessing.horizontalposition(v=office.14).aspx) but is has not worked for me.
add image and call function:
MainDocumentPart mainPart = document.MainDocumentPart;
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Png);
using (FileStream stream = new FileStream(#"C:...\Logo.png", FileMode.Open))
{
imagePart.FeedData(stream);
}
AddImageToBody(document, mainPart.GetIdOfPart(imagePart));
and function:
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId)
{
int defX = 854;
int defY = 350;
int size = 3000;
// Define the reference of the image.
var element =
new DocumentFormat.OpenXml.Wordprocessing.Drawing(
new DW.Inline(
new DW.Extent() { Cx = defX * size, Cy = defY * size },
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 = 1000L, Y = 500L, },
new A.Extents() { Cx = defX * size, Cy = defY * size }),
new A.PresetGeometry(
new A.AdjustValueList()
) { Preset = A.ShapeTypeValues.Rectangle }))
) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = (UInt32Value)999999,
DistanceFromBottom = (UInt32Value)10000,
DistanceFromLeft = (UInt32Value)10000,
DistanceFromRight = (UInt32Value)10000,
EditId = "50D07946"
});
// Append the reference to body, the element should be in a Run.
wordDoc.MainDocumentPart.Document.Body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(new DocumentFormat.OpenXml.Wordprocessing.Run(element)));
}
You need to center the paragraph that is holding the image. You can do it using paragraph properties (last line of your code):
wordDoc.MainDocumentPart.Document.Body.AppendChild(
new DocumentFormat.OpenXml.Wordprocessing.Paragraph(new DocumentFormat.OpenXml.Wordprocessing.Run(element))
{
ParagraphProperties = new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties()
{
Justification = new DocumentFormat.OpenXml.Wordprocessing.Justification()
{
Val = DocumentFormat.OpenXml.Wordprocessing.JustificationValues.Center
}
}
});

Creating an ImagePart isn't saving the Relationship in OpenXML

--Updated to provide full working class example, with 2 sample documents--
www.sklinar.co.uk/wp-content/uploads/mydoc.docx - Original Document with a INCLUDETEXT instruction to merge in Footer.Docx
www.sklinar.co.uk/wp-content/uploads/footer.docx
I have added a ImagePart to my document as well as using FeedData() to supply it with streamed content.
But all I can get to appear in my document is a red box.
My initial code Creates a Run with a Drawing as it's child:
--For this example, I've used a hard-coded FileStream to weed out dodgy images--
Just to get this working, I am using the same footer each time, and this is currently hard-coded with the correct footer:
runToAmend.InsertAfterSelf(CreateImageRun(sourceDocument,run,target.MainDocumentPart.FooterParts.ElementAt(2)));
The runToAmend is taken from a run in the current document - which holds a field which is then removed and the picture (and other text taken from another document) placed in it's place.
public Run CreateImageRun(WordprocessingDocument sourceDoc, Run sourceRunFromOriginalDocument, FooterPart footerPart)
{
ImageData shape = sourceRun.Descendants<ImageData>().FirstOrDefault();
ImagePart p = sourceDoc.MainDocumentPart.GetPartById(shape.RelationshipId) as ImagePart;
ImagePart newPart = footerPart.AddImagePart(ImagePartType.Jpeg);
using (Stream stream = new FileStream(#"C:\Users\SAS\Desktop\IMG_20130803_104521.jpg",FileMode.Open,FileAccess.Read))
{
stream.Position = 0;
newPart.FeedData(stream);
}
string partId = footerPart.GetIdOfPart(newPart);
Drawing newImage = CreateImage(partId);
return new Run(newImage);
}
Code to Create Drawing
private Drawing CreateImage(string relationshipId)
{
// Define the reference of the image.
return 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"
});
}
The XML produced appears correct, and the image gets added to the /Media/ folder.
<w:r>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:editId="50D07946">
<wp:extent cx="990000" cy="792000" />
<wp:effectExtent l="0" t="0" r="0" b="0" />
<wp:docPr id="1" name="Picture 1" />
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="New Bitmap Image.jpg" />
<pic:cNvPicPr />
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="Raae77c5adb2e48f3" cstate="print">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}" />
</a:extLst>
</a:blip>
<a:stretch>
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr>
<a:xfrm>
<a:off x="0" y="0" />
<a:ext cx="990000" cy="792000" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
I've spent about 2 days now searching SO, Google MS's poor docs.
public class WordTest
{
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Vml;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
public void MethodName()
{
WordprocessingDocument mainDoc = WordprocessingDocument.Open("mydoc.docx", true);
foreach (var item in mainDoc.MainDocumentPart.FooterParts)
{
ProcessParaIncludeTextMerge(item, item.Footer.Descendants<Run>(), mainDoc);
item.Footer.Save();
}
mainDoc.MainDocumentPart.Document.Save();
}
private void ProcessParaIncludeTextMerge(OpenXmlPart part, IEnumerable<Run> runs, WordprocessingDocument originalDocument)
{
List<Run> paraRuns = runs.ToList();
int runCount = paraRuns.Count();
for (int i = 0; i < runCount; i++)
{
Run r = paraRuns.ElementAt(i);
// check if this is a simple Merge Field
if (r.HasChildren && r.Descendants<FieldCode>().Any())
{
FieldCode code = r.Descendants<FieldCode>().First();
// we check the first fieldcode is a merge field - but we can't *just* use that one, as for
// some stupid reason, the fieldcodes can be split across runs.... :/
if (code.Text.Trim().IndexOf("INCLUDETEXT", StringComparison.InvariantCultureIgnoreCase) > -1) //this is actually piss-poor, but as a merge field can go across n runs, we simply check for the M and let the other function figure it out..
{
MergeIncludeText(i, paraRuns, originalDocument);
}
}
}
}
public Run CreateImageRun(WordprocessingDocument sourceDoc, Run sourceRun, WordprocessingDocument target, FooterPart footerPart)
{
ImagePart newPart = footerPart.AddImagePart(ImagePartType.Png);
ImageData shape = sourceRun.Descendants<ImageData>().FirstOrDefault();
ImagePart p = sourceDoc.MainDocumentPart.GetPartById(shape.RelationshipId) as ImagePart;
Bitmap image = new Bitmap(p.GetStream());
using (Stream s = p.GetStream())
{
s.Position = 0;
newPart.FeedData(s);
}
string partId = footerPart.GetIdOfPart(newPart);
Drawing newImage = CreateImage(partId);
return new Run(newImage);
}
private Drawing CreateImage(string relationshipId)
{
// Define the reference of the image.
return 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"
});
}
private void ReplaceRunsWithRuns(IEnumerable<Run> fieldRuns, IEnumerable<Run> value, WordprocessingDocument source, WordprocessingDocument target)
{
FooterPart f = target.MainDocumentPart.FooterParts.ElementAt(1);
f.Footer.RemoveAllChildren();
Paragraph p = new Paragraph();
//the run has no value to merge into, remove the field.
if (value != null)
{
foreach (var item in value)
{
if (!item.Descendants<Picture>().Any()) //pictures are processed differently - they're an absolute s**t storm to code...
{
p.Append(item.CloneNode(true));
}
else
{
p.Append(CreateImageRun(source, item, target, f));
}
}
}
else
{
}
f.Footer.Append(p);
}
private void MergeIncludeText(int curRunIdx, List<Run> runs, WordprocessingDocument originalDoc)
{
int startRun = GetBeginRun(runs, curRunIdx);
if (startRun == -1)
{
return;
}
int endRun = GetEndRun(runs, startRun);
if (endRun == -1)
{
return;
}
IEnumerable<Run> fieldRuns = WordMLHelpers.GetRunsBetweenTwoPoints(runs, startRun, endRun);
IEnumerable<FieldCode> fieldCodes = fieldRuns.SelectMany(x => x.Descendants<FieldCode>());
string mergeField = string.Concat(fieldCodes.Select(x => x.Text));
string field = GetIncludeTextFilePath(mergeField);
MemoryStream ms = LoadDocumentStream(field);
WordprocessingDocument includeDoc = LoadDocumentFromStream(ms);
IEnumerable<Run> includedRuns = includeDoc.MainDocumentPart.Document.Descendants<Run>();
ReplaceRunsWithRuns(fieldRuns, includedRuns, includeDoc, originalDoc);
}
private string GetIncludeTextFilePath(string mergeFieldText)
{
int quoteStart = mergeFieldText.IndexOf('"') + 1;
int quoteEnd = mergeFieldText.IndexOf('"', quoteStart);
return mergeFieldText.Substring(quoteStart, quoteEnd - quoteStart);
}
private WordprocessingDocument LoadDocumentFromStream(Stream stream)
{
return WordprocessingDocument.Open(stream, true);
}
#region helpers
public static int GetBeginRun(IEnumerable<Run> runs, int curIdx)
{
for (int i = curIdx; i < runs.Count(); i--)
{
if (i == -1)
{
return -1;
}
Run run = runs.ElementAt(i);
if (run.HasChildren && run.ChildElements.OfType<FieldChar>().Count() > 0
&& (run.ChildElements.OfType<FieldChar>().First().FieldCharType == FieldCharValues.Begin))
{
return i;
}
}
throw new Exception("Begin not found");
}
/// <summary>
/// Get the first End Run in a <see cref="List"/>(<see cref="Run"/>)
/// </summary>
/// <param name="runs">The runs.</param>
/// <param name="curIdx">The cur idx.</param>
/// <returns></returns>
/// <exception cref="System.Exception">End not found</exception>
public static int GetEndRun(IEnumerable<Run> runs, int curIdx)
{
//runs.FirstOrDefault(x => x.HasChildren && x.Descendants<FieldChar>().Count > 0 && (x.Descendants<FieldChar>().First().FieldCharType & FieldCharValues.End) == FieldCharValues.End);
for (int i = curIdx; i < runs.Count(); i++)
{
if (i == -1)
{
return -1;
}
Run run = runs.ElementAt(i);
if (run.HasChildren && run.Descendants<FieldChar>().Any()
&& (run.Descendants<FieldChar>().First().FieldCharType == FieldCharValues.End))
{
return i;
}
}
return -1;
}
public static MemoryStream LoadDocumentStream(string template)
{
using (FileStream fs = File.Open(template, FileMode.Open, FileAccess.Read, FileShare.Read))
{
// first read document in as stream
MemoryStream ms = new MemoryStream();
fs.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
#endregion
}
I've analyzed your word document. There are a few issues with your word document:
If I try to open your word document in the MS productivity toolkit I get the error
message "Root element is missing".
If I open your document as a zip file (renaming to mergedfooter.zip) then
in the footer2.xml.rels file the relationship for your image is missing.
I think that's the reason you get the "red box".
To further analyze your problem I need the complete code (how do you get the FooterPart)?
Below you will find an example of how to insert an image into the footer of a word document.
Please note, that the example below assumes that your word document already contains a footer and your footer contains a paragraph element.
using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open("mydoc.docx", true))
{
MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart;
// Search for your footer part here.
// Just for the sake of simplicity I take the second footer part.
FooterPart fp = mainPart.FooterParts.ToList()[2];
// Create new image part.
ImagePart ip = fp.AddImagePart(ImagePartType.Jpeg);
using (FileStream fs = File.Open("mypicture.jpg", FileMode.Open))
{
ip.FeedData(fs);
}
string relationshipId = fp.GetIdOfPart(ip);
// Create the image element using your function.
Drawing img = CreateImage(relationshipId);
Run r = new Run(img);
Paragraph para = fp.RootElement.Descendants<Paragraph>().FirstOrDefault();
if(para != null)
{
para.Append(r);
}
else
{
Console.WriteLine("paragraph is null...");
}
}
EDIT:
After analyzing your newly provided documents:
The reason the releationship for your image is not saved is
because you do not Dispose() or Close() your word document.
So, just add a using statement:
using (WordprocessingDocument mainDoc = WordprocessingDocument.Open("mydoc.docx", true))
{
foreach (var item in mainDoc.MainDocumentPart.FooterParts)
{
ProcessParaIncludeTextMerge(item, item.Footer.Descendants<Run>(), mainDoc);
item.Footer.Save();
}
mainDoc.MainDocumentPart.Document.Save();
}
Furthermore in your ReplaceRunsWithRuns() method you must use
PIC.Picture to reference the correct Picture class:
foreach (var item in value)
{
if (!item.Descendants<PIC.Picture>().Any())
{
p.Append(item.CloneNode(true));
}
else
{
p.Append(CreateImageRun(source, item, target, f));
}
}
By the same token in your CreateImageRun() method I've changed
the first three code lines:
ImagePart newPart = footerPart.AddImagePart(ImagePartType.Jpeg);
A.Blip shape = sourceRun.Descendants<A.Blip>().FirstOrDefault();
ImagePart p = sourceDoc.MainDocumentPart.GetPartById(shape.Embed.Value) as ImagePart;
With theses changes the image appears in the mydoc.docx word document.
As an addition to the accepted answer - I write it as separate answer, because it's important and includes code samples:
Our WordDocumentManager class was inheriting from an abstract class, which in turn implements IDisposable. The Dispose method was overriden like so:
public override void Dispose()
{
document.Close();
document.Dispose();
}
That code executes when the using statement finishes:
using (var manager = new WordDocumentManager()){}
To my surprise, this means that document disposal does not count, so your image relationships will not be saved. If you run into such an issue - please keep in mind that might be the cause.
I resolved that issue with a hack that I wouldn't propose, you might decide on some other solution.

ITextSharp: How to get an image embedded resource

I'm parsing an HTML with some images inside this.
This images are stored as embedded resource, not in the filesystem.
as I know, i need to set a custom image provider in HtmlPipelineContext, and this provider need to retrieve the image path or the itextsharp image.
The question is, somebody know which method of Abstract Image Provider i need to implement? and how?
this is my code:
var list = new List<string> { text };
byte[] renderedBuffer;
using (var outputMemoryStream = new MemoryStream())
{
using (
var pdfDocument = new Document(PageSize.A4, 30, 30, 30, 30))
{
var pdfWriter = PdfWriter.GetInstance(pdfDocument, outputMemoryStream);
pdfWriter.CloseStream = false;
pdfDocument.Open();
HtmlPipelineContext htmlContext = new HtmlPipelineContext(new CssAppliersImpl());
htmlContext.SetImageProvider(new MyImageProvider());
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
ICSSResolver cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true);
CssResolverPipeline pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(pdfDocument, pdfWriter)));
XMLWorker worker = new XMLWorker(pipeline, true);
XMLParser p = new XMLParser(worker);
foreach (var htmlText in list)
{
using (var htmlViewReader = new StringReader(htmlText))
{
p.Parse(htmlViewReader);
}
}
}
renderedBuffer = new byte[outputMemoryStream.Position];
outputMemoryStream.Position = 0;
outputMemoryStream.Read(renderedBuffer, 0, renderedBuffer.Length);
}
Thanks in advance.
Using a custom Image Provider it doesn't seem to be supported. The only thing it really supports is changing root paths.
However, here's one solution to the problem:
Create a new html tag, called <resimg src="{resource name}"/>, and write a custom tag processor for it.
Here's the implementation:
/// <summary>
/// Our custom HTML Tag to add an IElement.
/// </summary>
public class ResourceImageHtmlTagProcessor : AbstractTagProcessor
{
public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
{
var src = tag.Attributes["src"];
var bitmap = (Bitmap)Resources.ResourceManager.GetObject(src);
if (bitmap == null)
throw new RuntimeWorkerException("No resource with the name: " + src);
var converter = new ImageConverter();
var image = Image.GetInstance((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
HtmlPipelineContext htmlPipelineContext = this.GetHtmlPipelineContext(ctx);
return new List<IElement>(1)
{
this.GetCssAppliers().Apply(
new Chunk((Image)this.GetCssAppliers().Apply(image, tag, htmlPipelineContext), 0f, 0f, true),
tag,
htmlPipelineContext)
};
}
}
To configure your new processor replace the line where you specify the TagFactory with the following:
var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
tagProcessorFactory.AddProcessor(new ResourceImageHtmlTagProcessor(), new[] { "resimg" });
htmlContext.SetTagFactory(tagProcessorFactory);

Categories

Resources