/// <summary> /// Sets a background picture for a table cell (a:tc). /// </summary> /// <remarks> /// <![CDATA[ /// <a:tc> /// <a:txBody> /// <a:bodyPr/> /// <a:lstStyle/> /// <a:p> /// <a:endParaRPr lang="fr-FR" dirty="0"/> /// </a:p> /// </a:txBody> /// <a:tcPr> (TableCellProperties) /// <a:blipFill dpi="0" rotWithShape="1"> /// <a:blip r:embed="rId2"/> /// <a:srcRect/> /// <a:stretch> /// <a:fillRect b="12000" r="90000" t="14000"/> /// </a:stretch> /// </a:blipFill> /// </a:tcPr> /// </a:tc> /// ]]> /// </remarks> private static void SetTableCellPropertiesWithBackgroundPicture(PptxSlide slide, A.TableCellProperties tcPr, Cell.BackgroundPicture backgroundPicture) { if (backgroundPicture.Content == null) { return; } ImagePart imagePart = slide.AddPicture(backgroundPicture.Content, backgroundPicture.ContentType); A.BlipFill blipFill = new A.BlipFill(); A.Blip blip = new A.Blip() { Embed = slide.GetIdOfImagePart(imagePart) }; A.SourceRectangle srcRect = new A.SourceRectangle(); A.Stretch stretch = new A.Stretch(); A.FillRectangle fillRect = new A.FillRectangle() { Top = backgroundPicture.Top, Right = backgroundPicture.Right, Bottom = backgroundPicture.Bottom, Left = backgroundPicture.Left }; stretch.AppendChild(fillRect); blipFill.AppendChild(blip); blipFill.AppendChild(srcRect); blipFill.AppendChild(stretch); tcPr.AppendChild(blipFill); }
/// <summary> /// Replaces the cells from the table (tbl). /// </summary> /// <returns>The list of remaining rows that could not be inserted, you will have to create a new slide.</returns> public List <Cell[]> SetRows(IList <Cell[]> rows) { PptxSlide slide = this.slideTemplate; A.Table tbl = slide.FindTable(this.tblId); int tblRowsCount = RowsCount(tbl); // done starts at 1 instead of 0 because we don't care about the first row // The first row contains the titles for the columns int done = 1; for (int i = 0; i < rows.Count(); i++) { Cell[] row = rows[i]; if (done < tblRowsCount) { // a:tr A.TableRow tr = GetRow(tbl, done); // a:tc foreach (A.TableCell tc in tr.Descendants <A.TableCell>()) { foreach (Cell cell in row) { ReplaceTag(slide, tc, cell); } } done++; } else { break; } } // Remove the last remaining rows if any for (int row = tblRowsCount - 1; row >= done; row--) { A.TableRow tr = GetRow(tbl, row); tr.Remove(); } // Save the latest slide // Mandatory otherwise the next time SetRows() is run (on a different table) // the rows from the previous tables will not contained the right data (from PptxParagraph.ReplaceTag()) slide.Save(); // Computes the remaining rows if any List <Cell[]> remainingRows = new List <Cell[]>(); for (int row = done - 1; row < rows.Count; row++) { remainingRows.Add(rows[row]); } return(remainingRows); }
/// <summary> /// Inserts this slide after a given target slide. /// </summary> /// <param name="newSlide">The new slide to insert.</param> /// <param name="prevSlide">The previous slide.</param> /// <remarks> /// This slide will be inserted after the slide specified as a parameter. /// <see href="http://startbigthinksmall.wordpress.com/2011/05/17/cloning-a-slide-using-open-xml-sdk-2-0/">Cloning a Slide using Open Xml SDK 2.0</see> /// </remarks> public static void InsertAfter(PptxSlide newSlide, PptxSlide prevSlide) { // Find the presentationPart var presentationPart = prevSlide.presentationPart; SlideIdList slideIdList = presentationPart.Presentation.SlideIdList; // Find the slide id where to insert our slide SlideId prevSlideId = null; foreach (SlideId slideId in slideIdList.ChildElements) { // See http://openxmldeveloper.org/discussions/development_tools/f/17/p/5302/158602.aspx if (slideId.RelationshipId == presentationPart.GetIdOfPart(prevSlide.slidePart)) { prevSlideId = slideId; break; } } // Find the highest id uint maxSlideId = slideIdList.ChildElements.Cast <SlideId>().Max(x => x.Id.Value); // public override T InsertAfter<T>(T newChild, DocumentFormat.OpenXml.OpenXmlElement refChild) // Inserts the specified element immediately after the specified reference element. SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId); newSlideId.Id = maxSlideId + 1; newSlideId.RelationshipId = presentationPart.GetIdOfPart(newSlide.slidePart); }
/// <summary> /// Inserts this slide after a given target slide. /// </summary> /// <param name="newSlide">The new slide to insert.</param> /// <param name="prevSlide">The previous slide.</param> /// <remarks> /// This slide will be inserted after the slide specified as a parameter. /// <see href="http://startbigthinksmall.wordpress.com/2011/05/17/cloning-a-slide-using-open-xml-sdk-2-0/">Cloning a Slide using Open Xml SDK 2.0</see> /// </remarks> public static void InsertAfter(PptxSlide newSlide, PptxSlide prevSlide) { // Find the presentationPart var presentationPart = prevSlide.presentationPart; SlideIdList slideIdList = presentationPart.Presentation.SlideIdList; // Find the slide id where to insert our slide SlideId prevSlideId = null; foreach (SlideId slideId in slideIdList.ChildElements) { // See http://openxmldeveloper.org/discussions/development_tools/f/17/p/5302/158602.aspx if (slideId.RelationshipId == presentationPart.GetIdOfPart(prevSlide.slidePart)) { prevSlideId = slideId; break; } } // Find the highest id uint maxSlideId = slideIdList.ChildElements.Cast<SlideId>().Max(x => x.Id.Value); // public override T InsertAfter<T>(T newChild, DocumentFormat.OpenXml.OpenXmlElement refChild) // Inserts the specified element immediately after the specified reference element. SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId); newSlideId.Id = maxSlideId + 1; newSlideId.RelationshipId = presentationPart.GetIdOfPart(newSlide.slidePart); }
/// <summary> /// Replaces the cells from a table (tbl). /// Algorithm for a slide template containing multiple tables. /// </summary> /// <param name="slideTemplate">The slide template that contains the table(s).</param> /// <param name="tableTemplate">The table (tbl) to use, should be inside the slide template.</param> /// <param name="rows">The rows to replace the table's cells.</param> /// <param name="existingSlides">Existing slides created for the other tables inside the slide template.</param> /// <returns>The newly created slides if any.</returns> public static IEnumerable <PptxSlide> ReplaceTable_Multiple(PptxSlide slideTemplate, PptxTable tableTemplate, IList <PptxTable.Cell[]> rows, List <PptxSlide> existingSlides) { List <PptxSlide> slidesCreated = new List <PptxSlide>(); string tag = tableTemplate.Title; PptxSlide lastSlide = slideTemplate; if (existingSlides.Count > 0) { lastSlide = existingSlides.Last(); } PptxSlide lastSlideTemplate = lastSlide.Clone(); foreach (PptxSlide slide in existingSlides) { PptxTable table = slide.FindTables(tag).First(); List <PptxTable.Cell[]> remainingRows = table.SetRows(rows); rows = remainingRows; } // Force SetRows() at least once if there is no existingSlides // this means we are being called by ReplaceTable_One() bool loopOnce = existingSlides.Count == 0; while (loopOnce || rows.Count > 0) { PptxSlide newSlide = lastSlideTemplate.Clone(); PptxTable table = newSlide.FindTables(tag).First(); List <PptxTable.Cell[]> remainingRows = table.SetRows(rows); rows = remainingRows; PptxSlide.InsertAfter(newSlide, lastSlide); lastSlide = newSlide; slidesCreated.Add(newSlide); if (loopOnce) { loopOnce = false; } } lastSlideTemplate.Remove(); return(slidesCreated); }
/// <summary> /// Finds the slides matching a given note. /// </summary> /// <param name="note">Note to match the slide with.</param> /// <returns>The matching slides.</returns> public IEnumerable <PptxSlide> FindSlides(string note) { List <PptxSlide> slides = new List <PptxSlide>(); for (int i = 0; i < this.SlidesCount(); i++) { PptxSlide slide = this.GetSlide(i); IEnumerable <string> notes = slide.GetNotes(); foreach (string tmp in notes) { if (tmp.Contains(note)) { slides.Add(slide); break; } } } return(slides); }
/// <summary> /// Replaces a tag inside a given table cell (a:tc). /// </summary> /// <param name="slide">The PptxSlide.</param> /// <param name="tc">The table cell (a:tc).</param> /// <param name="cell">Contains the tag, the new text and a picture.</param> /// <returns><c>true</c> if a tag has been found and replaced, <c>false</c> otherwise.</returns> private static bool ReplaceTag(PptxSlide slide, A.TableCell tc, Cell cell) { bool replacedAtLeastOnce = false; // a:p foreach (A.Paragraph p in tc.Descendants <A.Paragraph>()) { bool replaced = PptxParagraph.ReplaceTag(p, cell.Tag, cell.NewText); if (replaced) { replacedAtLeastOnce = true; // a:tcPr if (cell.Picture != null) { A.TableCellProperties tcPr = tc.GetFirstChild <A.TableCellProperties>(); SetTableCellPropertiesWithBackgroundPicture(slide, tcPr, cell.Picture); } } } return(replacedAtLeastOnce); }
/// <summary> /// Replaces a tag inside the table (a:tbl). /// </summary> /// <param name="cell">Contains the tag, the new text and a pciture.</param> /// <returns><c>true</c> if a tag has been found and replaced, <c>false</c> otherwise.</returns> public bool ReplaceTag(Cell cell) { bool replacedAtLeastOnce = false; PptxSlide slide = this.slideTemplate; A.Table tbl = slide.FindTable(this.tblId); // a:tr foreach (A.TableRow tr in tbl.Descendants <A.TableRow>()) { // a:tc foreach (A.TableCell tc in tr.Descendants <A.TableCell>()) { bool replaced = ReplaceTag(slide, tc, cell); if (replaced) { replacedAtLeastOnce = true; } } } return(replacedAtLeastOnce); }
/// <summary> /// Replaces the cells from a table (tbl). /// Algorithm for a slide template containing one table. /// </summary> public static IEnumerable <PptxSlide> ReplaceTable_One(PptxSlide slideTemplate, PptxTable tableTemplate, IList <PptxTable.Cell[]> rows) { return(ReplaceTable_Multiple(slideTemplate, tableTemplate, rows, new List <PptxSlide>())); }
internal PptxTable(PptxSlide slideTemplate, int tblId, string title) { this.slideTemplate = slideTemplate; this.tblId = tblId; this.Title = title; }
/// <summary> /// Replaces a tag inside a paragraph (a:p) with parsed HTML /// </summary> /// <param name="p">The paragraph (a:p).</param> /// <param name="tag">The tag to replace by newText, if null or empty do nothing; tag is a regex string.</param> /// <param name="newText">The new text to replace the tag with, if null replaced by empty string and not visible.</param> /// <param name="fontName">Font name</param> /// <param name="fontSize">Font size. E.g. 800 is 8pt (small) font. If value is less than 100 it will be multiplied by 100 to keep up with PPT notation.</param> /// <param name="hyperlinks">URL Relationships dictionary. Relationship has to be defined on slide level.</param> /// <returns><c>true</c> if a tag has been found and replaced, <c>false</c> otherwise.</returns> internal static bool ReplaceTagWithHtml(A.Paragraph p, string tag, string newText, string fontName = null, int fontSize = 0, IDictionary <string, string> hyperlinks = null) { newText = CorrectUnhandledHtmlTags(newText); // e.g. deal with ul/li html tags bool isFirstLine = true; // avoiding unintentional empty line at the begining of the text bool replaced = false; string[] closingTags = new string[] { "div", "p" }; // tags that force line break in PPTX paragraph if (string.IsNullOrEmpty(tag)) { return(replaced); } if (newText == null) { newText = string.Empty; } newText = RemoveInvalidXMLChars(newText); while (true) { // Search for the tag Match match = Regex.Match(GetTexts(p), tag); if (!match.Success) { break; } p.RemoveAllChildren(); // // remove exisitng children then add new HtmlParser hp = new HtmlParser(newText); MariGold.HtmlParser.IHtmlNode nodes = null; try { nodes = hp.FindBodyOrFirstElement(); } catch { Console.WriteLine(String.Format("WARNING: HTML is empty or HTML schema has errors. Parsed HTML[]: [{0}]", newText)); } while (nodes != null) { foreach (var item in nodes.Children) { bool skipLineBreak = false; A.Run r = new A.Run(); r.RunProperties = new A.RunProperties(); if (item.Html.Contains("<b>") || item.Html.Contains("<strong>")) { r.RunProperties.Bold = new DocumentFormat.OpenXml.BooleanValue(true); } if (item.Html.Contains("<i>") || item.Html.Contains("<em>")) { r.RunProperties.Italic = new DocumentFormat.OpenXml.BooleanValue(true); } if (item.Html.Contains("<u>") || item.Html.Contains("text-decoration: underline")) { r.RunProperties.Underline = new DocumentFormat.OpenXml.EnumValue <A.TextUnderlineValues>(A.TextUnderlineValues.Dash); } if (item.Html.Contains("<a")) { string uriId = null; try { string url = PptxSlide.ParseHttpUrls(item.Html).First().Value; uriId = hyperlinks.Where(q => q.Value == url).FirstOrDefault().Key; } catch (Exception ex) { Console.WriteLine("URL is no available"); } if (uriId != null) { A.HyperlinkOnClick link = new A.HyperlinkOnClick() { Id = uriId }; r.RunProperties.AppendChild(link); } } A.Text at = new A.Text(PptxTemplater.TextTransformationHelper.HtmlToPlainTxt(item.InnerHtml) + " "); // clear not interpreted html tags if (at.InnerText.Trim() == "" && isFirstLine) { at = new A.Text(); // avoid excessive new lines isFirstLine = false; } r.AppendChild(at); p.Append(r); // LINE BREAK -- if outer tag is div add line break if (closingTags.Contains(item.Parent.Tag) && skipLineBreak == false) { p.Append(new A.Break()); } } // remove parsed html part newText = newText.Substring(nodes.Html.Length); if (newText.Trim() == "") { break; } hp = new HtmlParser(newText); nodes = hp.FindBodyOrFirstElement(); } var run = p.Descendants <A.Run>(); foreach (var item in run) { if (fontName != null) { item.RunProperties.RemoveAllChildren <A.LatinFont>(); var latinFont = new A.LatinFont(); latinFont.Typeface = fontName; item.RunProperties.AppendChild(latinFont); } if (fontSize > 0) { item.RunProperties.FontSize = (fontSize > 99) ? fontSize : fontSize * 100; // e.g. translate value 8 (Power Point UI font size) to 800 for API } } replaced = true; } return(replaced); }
/// <summary> /// Replaces the cells from a table (tbl). /// Algorithm for a slide template containing multiple tables. /// </summary> /// <param name="slideTemplate">The slide template that contains the table(s).</param> /// <param name="tableTemplate">The table (tbl) to use, should be inside the slide template.</param> /// <param name="rows">The rows to replace the table's cells.</param> /// <param name="existingSlides">Existing slides created for the other tables inside the slide template.</param> /// <returns>The newly created slides if any.</returns> public static IEnumerable<PptxSlide> ReplaceTable_Multiple(PptxSlide slideTemplate, PptxTable tableTemplate, IList<PptxTable.Cell[]> rows, List<PptxSlide> existingSlides) { List<PptxSlide> slidesCreated = new List<PptxSlide>(); string tag = tableTemplate.Title; PptxSlide lastSlide = slideTemplate; if (existingSlides.Count > 0) { lastSlide = existingSlides.Last(); } PptxSlide lastSlideTemplate = lastSlide.Clone(); foreach (PptxSlide slide in existingSlides) { PptxTable table = slide.FindTables(tag).First(); List<PptxTable.Cell[]> remainingRows = table.SetRows(rows); rows = remainingRows; } // Force SetRows() at least once if there is no existingSlides // this means we are being called by ReplaceTable_One() bool loopOnce = existingSlides.Count == 0; while (loopOnce || rows.Count > 0) { PptxSlide newSlide = lastSlideTemplate.Clone(); PptxTable table = newSlide.FindTables(tag).First(); List<PptxTable.Cell[]> remainingRows = table.SetRows(rows); rows = remainingRows; PptxSlide.InsertAfter(newSlide, lastSlide); lastSlide = newSlide; slidesCreated.Add(newSlide); if (loopOnce) loopOnce = false; } lastSlideTemplate.Remove(); return slidesCreated; }
/// <summary> /// Replaces the cells from a table (tbl). /// Algorithm for a slide template containing one table. /// </summary> public static IEnumerable<PptxSlide> ReplaceTable_One(PptxSlide slideTemplate, PptxTable tableTemplate, IList<PptxTable.Cell[]> rows) { return ReplaceTable_Multiple(slideTemplate, tableTemplate, rows, new List<PptxSlide>()); }
/// <summary> /// Replaces a tag inside a given table cell (a:tc). /// </summary> /// <param name="slide">The PptxSlide.</param> /// <param name="tc">The table cell (a:tc).</param> /// <param name="cell">Contains the tag, the new text and a picture.</param> /// <returns><c>true</c> if a tag has been found and replaced, <c>false</c> otherwise.</returns> private static bool ReplaceTag(PptxSlide slide, A.TableCell tc, Cell cell) { bool replacedAtLeastOnce = false; // a:p foreach (A.Paragraph p in tc.Descendants<A.Paragraph>()) { bool replaced = PptxParagraph.ReplaceTag(p, cell.Tag, cell.NewText); if (replaced) { replacedAtLeastOnce = true; // a:tcPr if (cell.Picture != null) { A.TableCellProperties tcPr = tc.GetFirstChild<A.TableCellProperties>(); SetTableCellPropertiesWithBackgroundPicture(slide, tcPr, cell.Picture); } } } return replacedAtLeastOnce; }