123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- using DocumentFormat.OpenXml;
- using DocumentFormat.OpenXml.Drawing;
- using DocumentFormat.OpenXml.Drawing.Diagrams;
- using DocumentFormat.OpenXml.Packaging;
- using DocumentFormat.OpenXml.Presentation;
- using HTEXLib.Helpers.ShapeHelpers;
- using HTEXLib.Models.Inner;
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- namespace HTEXLib.Models.HTEX
- {
- public class HtexTable: HtexElement
- {
- public HtexTable(string id, double rot, double width, double height,
- double top, double left, bool invisible,
- bool animatable, int index, DocumentFormat.OpenXml.Drawing.Table table, PPTSlide slide, string partForm, string timingId)
- {
- base.sid = timingId;
- base.slide = slide;
- this.rot = rot;
- this.Table = table;
- base.id = id;
- base.top = top;
- base.left = left;
- base.width = width;
- base.height = height;
- base.invisible = invisible;
- base.animatable = animatable;
- base.index = index;
- base.type = "Table";
- base.partForm = partForm;
- }
- public override List<Item> DrawElement() {
- Position position = new Position { cx = width, cy = height, x = left, y = top, rot = rot };
- TbStyle tbStyle = PPTXHelper.DoTableProperties(Table.TableProperties, slide, type, partForm);
- List<GridColumn> columns = Table.TableGrid.Elements<GridColumn>().ToList();
- tbStyle.ColumnWidth = columns.Select(x => x.Width * Globals.px96 * 1.0 / Globals.px914400).ToList();
- List<TableRow> rows = Table.Elements<TableRow>().ToList();
- var trs = DoTableRow(rows, slide, type, partForm);
- Table table = new Table() { sid = sid,id = this.id, tr = trs, style = tbStyle, type =type, index = index, animatable = animatable, invisible = invisible };
- table.style.position = position;
- var elmt = new List<Item>();
- elmt.Add(table);
- return elmt;
- }
- public DocumentFormat.OpenXml.Drawing.Table Table { get; set; }
- public List<Tr> DoTableRow(List<TableRow> rows, PPTSlide slide, string type, string partForm)
- {
- List<Tr> trs = new List<Tr>();
- foreach (TableRow row in rows)
- {
- Tr tr = new Tr { height = row.Height * Globals.px96 * 1.0 / Globals.px914400 };
- var r = row.Elements<TableCell>();
- foreach (TableCell cell in r)
- {
- CellStyle cellStyle = PPTXHelper.DoTableCellProperties(cell.TableCellProperties, slide, type, partForm);
- Td td = new Td();
- if (cell != null)
- {
- if (cell.RowSpan != null)
- {
- td.rowspan = cell.RowSpan;
- }
- if (cell.GridSpan != null)
- {
- td.colspan = cell.GridSpan;
- }
- if (cell.HorizontalMerge != null)
- {
- td.hmerge = cell.HorizontalMerge;
- }
- if (cell.VerticalMerge != null)
- {
- td.vmerge = cell.VerticalMerge;
- }
- }
- td.style = cellStyle;
- LinkedList<PPTParagraph> PPTParagraphs = DoTextBody(cell.TextBody, slide.SlidePart, slide.shapeListStyleMaster, slide.shapeListStyleLayout);
- List<Paragraph> paragraphs = DrawText(PPTParagraphs);
- td.paragraphs = paragraphs;
- tr.td.Add(td);
- }
- trs.Add(tr);
- }
- return trs;
- }
- public List<Paragraph> DrawText(LinkedList<PPTParagraph> Texts)
- {
- List<Paragraph> Paragraphs = new List<Paragraph>();
- foreach (var par in Texts)
- {
- double paragraphTop = par.getSpaceBeforePoints();
- Paragraph paragraph = new HTEXLib.Paragraph { animatable = par.Animatable, invisible = par.Invisible };
- paragraph.style.hori = par.Align;
- if (par.bullet != null)
- {
- var bullet = par.bullet;
- paragraph.buChar = new BuChar
- {
- type = bullet.BulletType,
- left = bullet.Left,
- buchar = bullet.Text,
- color = bullet.FontColor,
- typeface = bullet.FontFamily,
- size = bullet.FontSize,
- };
- }
- int newTop = par.getSpaceBeforePoints();
- int left = 0;
- List<HtexText> textElements = new List<HtexText>();
- List<Text> texts = new List<Text>();
- if (par.RunPropList == null || par.RunPropList.Count == 0 && par.defaultRunProperties != null) //Only paragraph!
- {
- float points = float.Parse(par.defaultRunProperties.FontSize.ToString()) * 72.0F / 96.0F;
- System.Drawing.Font font = new System.Drawing.Font(par.defaultRunProperties.FontFamily.ToString(), points);
- newTop = font.Height;
- }
- List<HtexText> processedElements = new List<HtexText>();
- IEnumerable<PPTRunProperties> pPTRunProperties = breakTextsToShape(par);
- foreach (var text in pPTRunProperties)
- {
- float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
- System.Drawing.Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
- if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
- else if (text.Italic)
- font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
- else if (text.Underline != null && text.Underline.Equals("Single"))
- font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
- newTop = font.Height > newTop ? font.Height : newTop;
- newTop = par.getLineSpacingInPointsFromFont(newTop);
- if (text.isBreak)
- {
- top += newTop;
- left = 0;
- fixLeftSpacingForAlignment(processedElements, par, font);
- processedElements.Clear();
- continue;
- }
- String currentString = text.Text.TrimEnd() + getStringFromTextElements(processedElements);
- HtexText t1 = new HtexText(left: left,
- top: top,
- fontFamily: text.FontFamily,
- fontColor: text.FontColor,
- fontSize: text.FontSize,
- isBullet: text.isBullet,
- bold: text.Bold,
- italic: text.Italic,
- underline: text.Underline,
- id: id,
- slideIndex: slide.slideIndex)
- {
- Rotate = this.rot
- };
- t1.width = MeasureString(text.Text, font);
- if (text.isBullet && text.Text != null && text.Text.Contains("rId"))
- {
- t1.PictureBullet = true;
- t1.width = text.bulletSize;
- t1.bulletSize = text.bulletSize;
- newTop = text.bulletSize;
- }
- t1.Text = text.Text;
- textElements.Add(t1);
- texts.Add(new Text
- {
- content = t1.Text,
- link = text.link,
- linkType = text.linkType,
- style = new FontStyle
- {
- align = par.FontAlign,
- spacing = par.defTabSize,
- color = text.FontColor,
- family = text.FontFamily,
- top = top,
- left = left,
- size = text.FontSize,
- isBullet = text.isBullet,
- underline = t1.underline,
- italic = text.Italic,
- bold = text.Bold,
- rot = this.rot,
- width = t1.width,
- pictureBullet = t1.PictureBullet,
- bulletSize = t1.bulletSize
- }
- });
- processedElements.Add(t1);
- }
- fixLeftSpacingForAlignment(processedElements, par);
- HtexText lastTxt = null;
- List<HtexText> mergedTextElements = new List<HtexText>();
- foreach (HtexText textElement in textElements)
- {
- if (lastTxt == null || !lastTxt.sameProps(textElement))
- mergedTextElements.Add(textElement);
- else
- mergedTextElements[mergedTextElements.Count - 1].Text += textElement.Text;
- lastTxt = textElement;
- }
- //foreach (HtexText textElement in mergedTextElements) {
- // shapeBuilder.Append(textElement.DrawElement());
- //}
- top += newTop;
- top += par.getSpaceAfterPoints(newTop);
- top += par.getSpaceBeforePoints(newTop);
- paragraph.texts = texts;
- Paragraphs.Add(paragraph);
- }
- return Paragraphs;
- }
- private String getStringFromTextElements(List<HtexText> elements)
- {
- if (elements == null || elements.Count == 0)
- return "";
- StringBuilder result = new StringBuilder();
- foreach (HtexText el in elements)
- {
- result.Append(el.Text);
- }
- return result.ToString();
- }
- //We have two similar methods - this one is better because it measures the whole string with the font.
- private void fixLeftSpacingForAlignment(List<HtexText> textElements, PPTParagraph par, System.Drawing.Font font)
- {
- int combinedWidth = 0;
- StringBuilder combinedText = new StringBuilder();
- foreach (HtexText textElement in textElements)
- {
- if (textElement.PictureBullet)
- combinedWidth += textElement.bulletSize;
- else
- combinedText.Append(textElement.Text);
- }
- int bulletOffset = 0;
- if (par.bullet != null && textElements.Count > 0 && !textElements[0].isBullet)
- {
- bulletOffset = par.bullet.bulletSize;
- combinedWidth += par.bullet.bulletSize;
- }
- combinedWidth += MeasureString(combinedText.ToString(), font);
- double firstLeft = 0;
- if ("Center".Equals(par.Align))
- firstLeft = ((this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight) - combinedWidth) / 2;
- else if ("Right".Equals(par.Align))
- firstLeft = (this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight) - combinedWidth;
- combinedText = new StringBuilder();
- combinedWidth = 0; //Now used only for picture bullets!
- foreach (HtexText textElement in textElements)
- {
- textElement.setLeft(firstLeft + par.Indent + bulletOffset + par.marginLeft + combinedWidth + MeasureString(combinedText.ToString(), font));
- if (textElement.PictureBullet)
- combinedWidth += textElement.bulletSize;
- else
- combinedText.Append(textElement.Text);
- }
- }
- //We have two similar methods. This is worse because it uses the Width property of each element instead of measuring the whole string.
- //There is mistake in the calculations coming from that and the difference is bigger when there are more elements.
- private void fixLeftSpacingForAlignment(List<HtexText> textElements, PPTParagraph par)
- {
- int combinedWidth = 0;
- foreach (HtexText textElement in textElements)
- combinedWidth += textElement.width;
- int bulletOffset = 0;
- if (par.bullet != null && textElements.Count > 0 && !textElements[0].isBullet)
- {
- combinedWidth += par.bullet.bulletSize;
- bulletOffset = par.bullet.bulletSize;
- }
- double currentLeft = 0;
- if ("Center".Equals(par.Align))
- currentLeft = ((this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight) - combinedWidth) / 2;
- else if ("Right".Equals(par.Align))
- currentLeft = (this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight) - combinedWidth;
- foreach (HtexText textElement in textElements)
- {
- textElement.setLeft(currentLeft + par.Indent + bulletOffset + par.marginLeft);
- currentLeft += textElement.width;
- }
- }
- private IEnumerable<PPTRunProperties> breakTextsToShape(PPTParagraph par)
- {
- List<PPTRunProperties> list = par.RunPropList;
- List<PPTRunProperties> result = new List<PPTRunProperties>();
- String previousToken = null;
- int bulletSize = 0;
- foreach (var text in list)
- {
- float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
- System.Drawing.Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
- if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
- else if (text.Italic) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
- else if (text.Underline != null && text.Underline.Equals("Single"))
- font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
- int size = 0;
- if (text.isBullet && text.Text != null && text.Text.Contains("rId"))
- bulletSize = text.bulletSize;
- else
- size = MeasureString((previousToken == null ? "" : previousToken + " ") + text.Text, font);
- if (text.isBreak || size + bulletSize < this.width - par.Indent - par.marginLeft - par.marginRight)//- Shape.LeftInset - Shape.RightInset)
- {
- if (text.Text != null && text.Text.Trim() != "" && !(text.isBullet && text.Text.Contains("rId")))
- {
- previousToken = (previousToken == null ? "" : previousToken) + text.Text;
- }
- if (text.isBreak)
- previousToken = null;
- result.Add(text);
- continue;
- }
- // previousToken = null;
- string[] tokens = text.Text.Split(' ');
- int index = 0;
- foreach (string token in tokens)
- {
- index++;
- int combinedSize = MeasureString((previousToken == null ? "" : previousToken + " ") + token, font);
- if (combinedSize + bulletSize > this.width - par.Indent - par.marginLeft - par.marginRight)//- Shape.LeftInset - Shape.RightInset)
- {
- PPTRunProperties temp = new PPTRunProperties(text);
- temp.Text = "";
- temp.isBreak = true;
- result.Add(temp);
- temp = new PPTRunProperties(text);
- temp.Text = index < tokens.Length ? token + " " : token;
- result.Add(temp);
- previousToken = token;
- }
- else
- {
- PPTRunProperties temp = new PPTRunProperties(text);
- temp.Text = index < tokens.Length ? token + " " : token;
- result.Add(temp);
- previousToken = (previousToken == null ? "" : previousToken + " ") + token;
- }
- }
- }
- return result;
- }
- public static int MeasureString(string s, System.Drawing.Font font)
- {
- s = s.Replace("\t", "aaaa");//TODO the replace is dirty hack for measuring tabulations
- StringFormat stringFormat = new StringFormat(StringFormat.GenericTypographic);
- CharacterRange[] rng = { new CharacterRange(0, s.Length) };
- stringFormat.SetMeasurableCharacterRanges(rng);
- Graphics g = Graphics.FromImage(new Bitmap(100, 100));
- //Use measure character ranges with a big box because we used this for measurement only
- //Later we might better use this for drawing the text.
- Region[] regions = g.MeasureCharacterRanges(s, font, new System.Drawing.Rectangle(0, 0, 10000, 3000), stringFormat);
- foreach (Region region in regions)
- {
- RectangleF rect = region.GetBounds(g);
- return (int)System.Math.Round(rect.Width);
- }
- return 0;
- //
- // SizeF result;
- // using (var image = new Bitmap(1, 1))
- // {
- // using (var g = Graphics.FromImage(image))
- // {
- // result = g.MeasureString(s, font);
- // }
- // }
- //
- // return result.ToSize();
- }
- public LinkedList<PPTParagraph> DoTextBody(DocumentFormat.OpenXml.Drawing.TextBody TextBody, OpenXmlPart slidePart, ListStyle shapeListStyleMaster, ListStyle shapeListStyleLayout)
- {
- LinkedList<PPTParagraph> Texts = new LinkedList<PPTParagraph>();
- bool IsText = true;
- int fontScale = 100000;
- if (TextBody == null)
- {
- IsText = false;
- return null;
- }
- if (TextBody.BodyProperties != null)
- {
- if (TextBody.BodyProperties.Anchor != null)
- {
- DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues VerticalAlign = TextBody.BodyProperties.Anchor;
- }
- if (TextBody.BodyProperties.GetFirstChild<NormalAutoFit>() != null &&
- TextBody.BodyProperties.GetFirstChild<NormalAutoFit>().FontScale != null)
- {
- fontScale = TextBody.BodyProperties.GetFirstChild<NormalAutoFit>().FontScale.Value;
- }
- }
- int index = 0;
- foreach (var paragraph in TextBody.Descendants<DocumentFormat.OpenXml.Drawing.Paragraph>())
- {
- PlaceholderShape placeholder = null;
- var par = new PPTParagraph(slide, placeholder,partForm)
- {
- Paragraph = index++
- };
- if (paragraph.ParagraphProperties != null)
- {
- int level = paragraph.ParagraphProperties.Level == null ?
- -1 : paragraph.ParagraphProperties.Level.Value;
- par.Level = level;
- }
- par.SetParagraphProperties(paragraph, slidePart,
- shapeListStyleMaster, shapeListStyleLayout);
- bool hasText = false;
- foreach (var obj in paragraph.ChildElements)
- {
- hasText = GetParagraphChildElements(TextBody, par, hasText, obj, fontScale);
- }
- //This is because when we set paragraph properties we add the bullet to the text runs.
- //If we don't have text it still outputs the bullet character.
- if (par.bullet != null && hasText)
- {
- par.RunPropList.Insert(0, par.bullet);
- }
- Texts.AddLast(par);
- }
- return Texts;
- }
- private bool GetParagraphChildElements(DocumentFormat.OpenXml.Drawing.TextBody shape, PPTParagraph par, bool hasText, OpenXmlElement obj, int fontScale)
- {
- LinkedList<string> effectShapes = new LinkedList<string>();
- if (obj is Run)
- {
- Run run = (Run)obj;
- hasText = true;
- PPTRunProperties runProp = new PPTRunProperties(par.defaultRunProperties);
- runProp.Text = run.Text.Text;
- runProp.SetRunProperties(run.RunProperties, shape, ref effectShapes);
- runProp.FontSize = System.Math.Round(fontScale * runProp.FontSize / Globals.PercentageConstant);
- par.RunPropList.Add(runProp);
- }
- else if (obj is Field)
- {
- Field run = (Field)obj;
- hasText = true;
- PPTRunProperties runProp = new PPTRunProperties(par.defaultRunProperties);
- runProp.Text = run.Text.Text;
- runProp.SetRunProperties(run.RunProperties, shape, ref effectShapes);
- runProp.FontSize = System.Math.Round(fontScale * runProp.FontSize / Globals.PercentageConstant);
- par.RunPropList.Add(runProp);
- }
- else if (obj is Break)
- {
- Break aBreak = (Break)obj;
- PPTRunProperties runProp = new PPTRunProperties(par.defaultRunProperties);
- runProp.SetRunProperties(aBreak.RunProperties, shape, ref effectShapes);
- runProp.FontSize = System.Math.Round(fontScale * runProp.FontSize / Globals.PercentageConstant);
- runProp.isBreak = true;
- par.RunPropList.Add(runProp);
- }
- return hasText;
- }
- }
- }
|