I am using below code to highlight text in power point presentation (.pptx) using openxml but below code for pptx - it corrupts the file and ask to repair while opening pptx and after opening it highlights the word but it does not preserves the formatting. So total 2 problems:
1. File gets corrupted
2. Formatting is not preserved
But it highlights the text which i want (but it does not preserve formatting)
I have debuged my code line by line and problem is at below line, but i am not able to figure out what is the problem.
highlightRun.InsertAt(runPro, 0);
I have used openxml productivity tool to compare two files of pptx one with highlighting one without highlighting: The difference i see is as below : i am not using two times RunProperties but it is showing 2 times :
Corrupted file :
public Run GenerateRun()
{
Run run1 = new Run();
RunProperties runProperties1 = new RunProperties(){ Language = "en-US", Dirty = false };
runProperties1.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));
SolidFill solidFill1 = new SolidFill();
RgbColorModelHex rgbColorModelHex1 = new RgbColorModelHex(){ Val = "FFF000" };
solidFill1.Append(rgbColorModelHex1);
runProperties1.Append(solidFill1);
RunProperties runProperties2 = new RunProperties(){ Language = "en-US", Dirty = false };
runProperties2.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));
SolidFill solidFill2 = new SolidFill();
RgbColorModelHex rgbColorModelHex2 = new RgbColorModelHex(){ Val = "FFFF00" };
solidFill2.Append(rgbColorModelHex2);
runProperties2.Append(solidFill2);
Text text1 = new Text();
text1.Text = "gaits";
run1.Append(runProperties1);
run1.Append(runProperties2);
run1.Append(text1);
return run1;
}
<a:r xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:rPr lang="en-US" dirty="0" smtClean="0">
<a:solidFill>
<a:srgbClr val="FFF000" />
</a:solidFill>
</a:rPr>
<a:rPr lang="en-US" dirty="0" smtClean="0">
<a:solidFill>
<a:srgbClr val="FFFF00" />
</a:solidFill>
</a:rPr>
<a:t>gaits</a:t>
</a:r>
Correct file :
public class GeneratedClass
{
// Creates an Run instance and adds its children.
public Run GenerateRun()
{
Run run1 = new Run();
RunProperties runProperties1 = new RunProperties(){ Language = "en-US", Dirty = false };
runProperties1.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));
SolidFill solidFill1 = new SolidFill();
RgbColorModelHex rgbColorModelHex1 = new RgbColorModelHex(){ Val = "FFFF00" };
solidFill1.Append(rgbColorModelHex1);
runProperties1.Append(solidFill1);
Text text1 = new Text();
text1.Text = "gaits";
run1.Append(runProperties1);
run1.Append(text1);
return run1;
}
<a:r xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:rPr lang="en-US" dirty="0" smtClean="0">
<a:solidFill>
<a:srgbClr val="FFFF00" />
</a:solidFill>
</a:rPr>
<a:t>gaits</a:t>
</a:r>
What i am missing ? My complete code is as below :
using OpenXmlDrawing = DocumentFormat.OpenXml.Drawing;
private void HighLightTextPresentation(OpenXmlDrawing.Paragraph paragraph, string text)
{
var found = paragraph
.Descendants<OpenXmlDrawing.Run>()
.Where(r => !string.IsNullOrEmpty(r.InnerText) && r.InnerText != "\\s")
.Select(r =>
{
var runText = r.GetFirstChild<OpenXmlDrawing.Text>();
int index = runText.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase);
// 'Run' is a reference to the text run we found,
// TextNode is a reference to the run's Text object,
// 'TokenIndex` is the index of the search string in run's text
return new { Run = r, TextNode = runText, TokenIndex = index };
})
.FirstOrDefault(o => o.TokenIndex >= 0);
// Nothing found -- escape
if (found == null)
{
return;
}
// Create a node for highlighted text as a clone (to preserve formatting etc)
var highlightRun = found.Run.CloneNode(true);
// Add the highlight node after the found text run and set up the highlighting
paragraph.InsertAfter(highlightRun, found.Run);
highlightRun.GetFirstChild<OpenXmlDrawing.Text>().Text = text;
DocumentFormat.OpenXml.Drawing.RunProperties runPro = new DocumentFormat.OpenXml.Drawing.RunProperties() { Language = "en-US", Dirty = false };
runPro.SetAttribute(new OpenXmlAttribute("", "smtClean", "", "0"));
//Apply color to searched text
DocumentFormat.OpenXml.Drawing.SolidFill solidFill1 = new DocumentFormat.OpenXml.Drawing.SolidFill();
DocumentFormat.OpenXml.Drawing.RgbColorModelHex rgbColorModelHex1 = new DocumentFormat.OpenXml.Drawing.RgbColorModelHex() { Val = "FFF000" };//Set Font-Color to Green (Hex "00B050").
solidFill1.Append(rgbColorModelHex1);
runPro.Append(solidFill1);
highlightRun.InsertAt(runPro, 0);
// Check if there's some text in the text run *after* the found text
int remainderLength = found.TextNode.Text.Length - found.TokenIndex - text.Length;
if (remainderLength > 0)
{
// There is some text after the highlighted section --
// insert it in a separate text run after the highlighted text run
var remainderRun = found.Run.CloneNode(true);
paragraph.InsertAfter(remainderRun, highlightRun);
OpenXmlDrawing.Text textNode = remainderRun.GetFirstChild<OpenXmlDrawing.Text>();
textNode.Text = found.TextNode.Text.Substring(found.TokenIndex + text.Length);
// We need to set up this to preserve the spaces between text runs
//textNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
}
// Check if there's some text *before* the found text
if (found.TokenIndex > 0)
{
// Something is left before the highlighted text,
// so make the original text run contain only that portion
found.TextNode.Text = found.TextNode.Text.Remove(found.TokenIndex);
// We need to set up this to preserve the spaces between text runs
//found.TextNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
}
else
{
// There's nothing before the highlighted text -- remove the unneeded text run
paragraph.RemoveChild(found.Run);
}
}
RunPropertiesinstance and insert that into aRun, without checking if there is already an existingRunPropertieselement in it. And IIRC only 1RunPropertiesis allowed perRun. Have you tried checking for an existing one to replace or update before trying to add a new one? - bassfader