替换 header 中的图像,OpenXML
replace image in header, OpenXML
我希望有人可以帮助解决这个问题。我正在使用 OpenXMl 搜索和替换 header、body 中的文本以及使用 Open XML 的 word 文档的页脚。文字工作正常。但是图像并没有像我期望的那样替换。图像 (@"C:\temp\pic\Logo.gif") 确实存在于源中。但是从来没有正确地出现在word文档中。您可以在下面的区域中看到 (#region "Modify Header Logo")
有人可以帮忙吗?谢谢!
Word Error
public void SearchAndReplace(string templateFileNameTemplate, string targetFileName, ProjectModel project)
{
//copy template file
if (File.Exists(targetFileName) == true)
{
File.Delete(targetFileName);
}
File.Copy(templateFileNameTemplate, targetFileName);
string searchText = "", replaceText = "", headerLogo = "", headerText = "";
bool replace = false;
//open file
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(targetFileName, true))
{
//Gets all the headers
foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
{
//Gets the text in headers
foreach (var currentText in headerPart.RootElement.Descendants<Text>())
{
replace = false;
switch (currentText.Text)
{
case "<COMPANY NAME>":
replace = true;
replaceText = project.ClientName;
searchText = currentText.Text;
break;
**case "<INSERT YOUR LOGO HERE>":
headerLogo = @"C:\temp\pic\Logo.gif";//project.ClientLogo;**
headerText = currentText.Text;
break;
case "<ISSUE DATE>":
replace = true;
replaceText = project.AssignedDate.ToShortDateString();
searchText = currentText.Text;
break;
case "<REVIEW DATE>":
replace = true;
replaceText = project.ClientDueDate.ToShortDateString();
searchText = currentText.Text;
break;
default:
break;
}
if(searchText.Length>0 && replace==true)
currentText.Text = currentText.Text.Replace(searchText, replaceText);
}
}
//Gets all the footers
foreach (var footerPart in wordDoc.MainDocumentPart.FooterParts)
{
//Gets the text in headers
foreach (var currentText in footerPart.RootElement.Descendants<Text>())
{
replace = false;
switch (currentText.Text)
{
case "<COMPANY NAME>":
replace = true;
replaceText = project.ClientName;
searchText = currentText.Text;
break;
default:
break;
}
if (searchText.Length > 0 && replace == true)
currentText.Text = currentText.Text.Replace(searchText, replaceText);
}
}
#region "Modify Header Logo"
if(headerLogo != string.Empty)
{
ImagePart imagePart = wordDoc.MainDocumentPart.AddImagePart(ImagePartType.Png);
using (FileStream stream = new FileStream(headerLogo, FileMode.Open))
{
imagePart.FeedData(stream);
}
searchText = headerText;
Text textPlaceHolder = null;
// Insert image (the image created with your function) after text place holder.
// Search for text holder
//Gets all the headers
foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
{
//Gets the text in headers
foreach (var currentText in headerPart.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
{
textPlaceHolder = headerPart.RootElement.Descendants<Text>()
.Where((x) => x.Text == searchText).First();
}
}
if (textPlaceHolder != null)
{
var parent = textPlaceHolder.Parent;
if (parent is Run) // Parent should be a run element.
{
//add image
Drawing imageElement = GetImageElement(
wordDoc.MainDocumentPart.GetIdOfPart(imagePart),
headerLogo,
"my image",
475,
245);
// Insert image (the image created with your function) after text place holder.
textPlaceHolder.Parent.InsertAfter<Drawing>(imageElement, textPlaceHolder);
// Remove text place holder.
textPlaceHolder.Remove();
}
}
}
#endregion
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
Regex regexText = new Regex("<COMPANY NAME>");
docText = regexText.Replace(docText, project.ClientName);
//regexText = new Regex("<COMPANY NAME>");
//docText = regexText.Replace(docText, project.ClientName);
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
//wordDoc.SaveAs(targetFileName).Close();
}
}
private static Drawing GetImageElement(
string imagePartId,
string fileName,
string pictureName,
double width,
double height)
{
double englishMetricUnitsPerInch = 914400;
double pixelsPerInch = 96;
//calculate size in emu
double emuWidth = width * englishMetricUnitsPerInch / pixelsPerInch;
double emuHeight = height * englishMetricUnitsPerInch / pixelsPerInch;
var element = new Drawing(
new A.Wordprocessing.Inline(
new A.Wordprocessing.Extent { Cx = (Int64Value)emuWidth, Cy = (Int64Value)emuHeight },
new A.Wordprocessing.EffectExtent { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
new A.Wordprocessing.DocProperties { Id = (UInt32Value)1U, Name = pictureName },
new A.Wordprocessing.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new A.Pictures.Picture(
new A.Pictures.NonVisualPictureProperties(
new A.Pictures.NonVisualDrawingProperties { Id = (UInt32Value)0U, Name = fileName },
new A.Pictures.NonVisualPictureDrawingProperties()),
new A.Pictures.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 A.Pictures.ShapeProperties(
new A.Transform2D(
new A.Offset { X = 0L, Y = 0L },
new A.Extents { Cx = (Int64Value)emuWidth, Cy = (Int64Value)emuHeight }),
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;
}
首先,这是我手动插入到 Word 文档中的图像标记 (Picture.png)。手动插入相同图像时,您是否检查过代码创建的标记与 Microsoft Word 创建的标记?这通常有助于发现标记中的错误(但并非总是如此,因为有多个 "ways to Rome" 并且同一事物通常可以用多种方式表达)。例如,您可以使用 Open XML Productivity Tool 比较这两个文档,并查看标记的差异以及创建正确标记所需的代码。
<w:r>
<w:rPr>
<w:noProof/>
</w:rPr>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="787F9556" wp14:editId="6F9F029A">
<wp:extent cx="4026107" cy="4019757"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="2" name="Picture 2" descr="A close up of a sign

Description automatically generated"/>
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
</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="2" name="Picture.png"/>
<pic:cNvPicPr/>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId1">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
</a:ext>
</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="4026107" cy="4019757"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
其次,下面的代码没有多大意义,因为您不需要 foreach
循环。该循环采用 w:hdr
的所有 w:t
个后代,但从不在循环的 body 中使用 currentText
。
foreach (var currentText in headerPart.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
{
textPlaceHolder = headerPart.RootElement.Descendants<Text>()
.Where((x) => x.Text == searchText).First();
}
循环的body就够了。我只是使用 FirstOrDefault
并检查是否为 null,除非您 100% 确定该文本将存在于所有 (!) headers.
中
我希望有人可以帮助解决这个问题。我正在使用 OpenXMl 搜索和替换 header、body 中的文本以及使用 Open XML 的 word 文档的页脚。文字工作正常。但是图像并没有像我期望的那样替换。图像 (@"C:\temp\pic\Logo.gif") 确实存在于源中。但是从来没有正确地出现在word文档中。您可以在下面的区域中看到 (#region "Modify Header Logo") 有人可以帮忙吗?谢谢!
Word Error
public void SearchAndReplace(string templateFileNameTemplate, string targetFileName, ProjectModel project)
{
//copy template file
if (File.Exists(targetFileName) == true)
{
File.Delete(targetFileName);
}
File.Copy(templateFileNameTemplate, targetFileName);
string searchText = "", replaceText = "", headerLogo = "", headerText = "";
bool replace = false;
//open file
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(targetFileName, true))
{
//Gets all the headers
foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
{
//Gets the text in headers
foreach (var currentText in headerPart.RootElement.Descendants<Text>())
{
replace = false;
switch (currentText.Text)
{
case "<COMPANY NAME>":
replace = true;
replaceText = project.ClientName;
searchText = currentText.Text;
break;
**case "<INSERT YOUR LOGO HERE>":
headerLogo = @"C:\temp\pic\Logo.gif";//project.ClientLogo;**
headerText = currentText.Text;
break;
case "<ISSUE DATE>":
replace = true;
replaceText = project.AssignedDate.ToShortDateString();
searchText = currentText.Text;
break;
case "<REVIEW DATE>":
replace = true;
replaceText = project.ClientDueDate.ToShortDateString();
searchText = currentText.Text;
break;
default:
break;
}
if(searchText.Length>0 && replace==true)
currentText.Text = currentText.Text.Replace(searchText, replaceText);
}
}
//Gets all the footers
foreach (var footerPart in wordDoc.MainDocumentPart.FooterParts)
{
//Gets the text in headers
foreach (var currentText in footerPart.RootElement.Descendants<Text>())
{
replace = false;
switch (currentText.Text)
{
case "<COMPANY NAME>":
replace = true;
replaceText = project.ClientName;
searchText = currentText.Text;
break;
default:
break;
}
if (searchText.Length > 0 && replace == true)
currentText.Text = currentText.Text.Replace(searchText, replaceText);
}
}
#region "Modify Header Logo"
if(headerLogo != string.Empty)
{
ImagePart imagePart = wordDoc.MainDocumentPart.AddImagePart(ImagePartType.Png);
using (FileStream stream = new FileStream(headerLogo, FileMode.Open))
{
imagePart.FeedData(stream);
}
searchText = headerText;
Text textPlaceHolder = null;
// Insert image (the image created with your function) after text place holder.
// Search for text holder
//Gets all the headers
foreach (var headerPart in wordDoc.MainDocumentPart.HeaderParts)
{
//Gets the text in headers
foreach (var currentText in headerPart.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
{
textPlaceHolder = headerPart.RootElement.Descendants<Text>()
.Where((x) => x.Text == searchText).First();
}
}
if (textPlaceHolder != null)
{
var parent = textPlaceHolder.Parent;
if (parent is Run) // Parent should be a run element.
{
//add image
Drawing imageElement = GetImageElement(
wordDoc.MainDocumentPart.GetIdOfPart(imagePart),
headerLogo,
"my image",
475,
245);
// Insert image (the image created with your function) after text place holder.
textPlaceHolder.Parent.InsertAfter<Drawing>(imageElement, textPlaceHolder);
// Remove text place holder.
textPlaceHolder.Remove();
}
}
}
#endregion
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
Regex regexText = new Regex("<COMPANY NAME>");
docText = regexText.Replace(docText, project.ClientName);
//regexText = new Regex("<COMPANY NAME>");
//docText = regexText.Replace(docText, project.ClientName);
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
//wordDoc.SaveAs(targetFileName).Close();
}
}
private static Drawing GetImageElement(
string imagePartId,
string fileName,
string pictureName,
double width,
double height)
{
double englishMetricUnitsPerInch = 914400;
double pixelsPerInch = 96;
//calculate size in emu
double emuWidth = width * englishMetricUnitsPerInch / pixelsPerInch;
double emuHeight = height * englishMetricUnitsPerInch / pixelsPerInch;
var element = new Drawing(
new A.Wordprocessing.Inline(
new A.Wordprocessing.Extent { Cx = (Int64Value)emuWidth, Cy = (Int64Value)emuHeight },
new A.Wordprocessing.EffectExtent { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
new A.Wordprocessing.DocProperties { Id = (UInt32Value)1U, Name = pictureName },
new A.Wordprocessing.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new A.Pictures.Picture(
new A.Pictures.NonVisualPictureProperties(
new A.Pictures.NonVisualDrawingProperties { Id = (UInt32Value)0U, Name = fileName },
new A.Pictures.NonVisualPictureDrawingProperties()),
new A.Pictures.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 A.Pictures.ShapeProperties(
new A.Transform2D(
new A.Offset { X = 0L, Y = 0L },
new A.Extents { Cx = (Int64Value)emuWidth, Cy = (Int64Value)emuHeight }),
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;
}
首先,这是我手动插入到 Word 文档中的图像标记 (Picture.png)。手动插入相同图像时,您是否检查过代码创建的标记与 Microsoft Word 创建的标记?这通常有助于发现标记中的错误(但并非总是如此,因为有多个 "ways to Rome" 并且同一事物通常可以用多种方式表达)。例如,您可以使用 Open XML Productivity Tool 比较这两个文档,并查看标记的差异以及创建正确标记所需的代码。
<w:r>
<w:rPr>
<w:noProof/>
</w:rPr>
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="787F9556" wp14:editId="6F9F029A">
<wp:extent cx="4026107" cy="4019757"/>
<wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="2" name="Picture 2" descr="A close up of a sign

Description automatically generated"/>
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
</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="2" name="Picture.png"/>
<pic:cNvPicPr/>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId1">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
</a:ext>
</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="4026107" cy="4019757"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
</w:r>
其次,下面的代码没有多大意义,因为您不需要 foreach
循环。该循环采用 w:hdr
的所有 w:t
个后代,但从不在循环的 body 中使用 currentText
。
foreach (var currentText in headerPart.RootElement.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
{
textPlaceHolder = headerPart.RootElement.Descendants<Text>()
.Where((x) => x.Text == searchText).First();
}
循环的body就够了。我只是使用 FirstOrDefault
并检查是否为 null,除非您 100% 确定该文本将存在于所有 (!) headers.