HtexShape.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. using DocumentFormat.OpenXml.Drawing;
  2. using HTEXLib.Helpers.ShapeHelpers;
  3. using HTEXLib.Models.Inner;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.Text;
  9. namespace HTEXLib.Models.HTEX
  10. {
  11. public class HtexShape : HtexElement
  12. {
  13. public PPTShape Shape { get; set; }
  14. // public double Rotate { get; set; }
  15. public string HyperLink { get; set; }
  16. private int slideIndex;
  17. public HtexShape(string id, double rot, double width, double height,
  18. double top, double left, bool invisible,
  19. bool animatable, int slideIndex, int index, PPTShape shape, PPTSlide slide, string partForm)
  20. {
  21. base.slide = slide;
  22. this.rot = rot;
  23. this.Shape = shape;
  24. base.id = id;
  25. base.top = top;
  26. base.left = left;
  27. base.width = width;
  28. base.height = height;
  29. base.invisible = invisible;
  30. base.animatable = animatable;
  31. this.slideIndex = slideIndex;
  32. base.index = index;
  33. base.type = "Sp";
  34. base.partForm = partForm;
  35. }
  36. public override List<Item> DrawElement()
  37. {
  38. if (Shape.placeholder != null && partForm== "layout") {
  39. return null;
  40. }
  41. // string style = invisible ? "DC0" : "DC1";
  42. Position position = new Position { cx= width, cy= height, x=left,y=top,rot=rot};
  43. var ShapeStyle =PPTXHelper.DoShapeProperties(Shape.element.ShapeProperties, slide,type,partForm);
  44. //position = position ,mediaType = "image",type = type,index = index,animatable = animatable ,invisible = invisible
  45. Shape shape = new Shape() { paragraph = DrawText() ,type=type,index=index,animatable=animatable,invisible=invisible };
  46. shape.style.position = position;
  47. var shapeTypeNode = Shape.element.ShapeProperties.GetFirstChild<PresetGeometry>();
  48. var shapeTypeCustom = Shape.element.ShapeProperties.GetFirstChild<CustomGeometry>();
  49. SlideColor slideColor = PPTXHelper.DoShapeStyle(Shape.element.ShapeStyle, slide,type);
  50. //从ShapeProperties 获取 p:spPr
  51. //再从 ShapeStyle 获取 p:spPr
  52. if (ShapeStyle.border == null || ShapeStyle.border.color == null || ShapeStyle.border.color.type == -1)
  53. {
  54. if (slideColor != null)
  55. {
  56. shape.style.border.color.solidFill = slideColor.LineColor;
  57. shape.style.border.color.type = 2;
  58. }
  59. }
  60. else {
  61. shape.style.border = ShapeStyle.border;
  62. }
  63. if (ShapeStyle.fill == null || ShapeStyle.fill.type == -1)
  64. {
  65. if (slideColor != null)
  66. {
  67. shape.style.fill.solidFill = slideColor.FillColor;
  68. shape.style.fill.type = 2;
  69. }
  70. }
  71. else {
  72. shape.style.fill = ShapeStyle.fill;
  73. }
  74. if (shape.paragraph != null) {
  75. shape.paragraph.ForEach(x => {
  76. if (x.texts != null) {
  77. x.texts.ForEach(y => {
  78. if (y.style.color == null) {
  79. if (slideColor != null && slideColor.FontColor != null)
  80. {
  81. y.style.color = slideColor.FontColor;
  82. }
  83. else {
  84. y.style.color = "#000000";
  85. }
  86. }
  87. });
  88. }
  89. });
  90. }
  91. if (shapeTypeNode != null && shapeTypeNode.Preset!=null && !string.IsNullOrEmpty(shapeTypeNode.Preset.InnerText)) {
  92. var shapeType = shapeTypeNode.Preset.InnerText;
  93. Svg svg = PPTXSvg.GenShapeSvg(Shape.element, index, shapeType, position, shape.style.border);
  94. shape.svg = svg;
  95. shape.shapeType = shapeType;
  96. }
  97. if (shapeTypeCustom!=null) {
  98. var pathlist= shapeTypeCustom.GetFirstChild<PathList>();
  99. var path= pathlist.GetFirstChild<DocumentFormat.OpenXml.Drawing.Path>();
  100. var pathChildren = path.ChildElements;
  101. if (pathChildren != null) {
  102. var start= pathChildren.Where(x =>x is MoveTo).FirstOrDefault();
  103. var close= pathChildren.Where(x => x is CloseShapePath).FirstOrDefault();
  104. var spX = 96.0;
  105. var spY = 96.0;
  106. if (start != null) {
  107. var point = start.GetFirstChild<DocumentFormat.OpenXml.Drawing.Point>();
  108. spX = System.Math.Round(double.Parse(point.X.Value )* Globals.px96 *1.0/ Globals.px914400, Globals. degree);
  109. spY = System.Math.Round(double.Parse(point.Y.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  110. }
  111. var d = "M" + spX + "," + spY;
  112. foreach (var child in pathChildren) {
  113. if (child is LineTo lineTo) {
  114. var elm= lineTo.GetFirstChild<DocumentFormat.OpenXml.Drawing.Point>();
  115. if (elm != null) {
  116. var Lx = System.Math.Round(double.Parse(elm.X.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  117. var Ly = System.Math.Round(double.Parse(elm.Y.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  118. d += " L" + Lx + "," + Ly;
  119. }
  120. }
  121. if (child is ArcTo arcTo)
  122. {
  123. var WidthRadius = arcTo.WidthRadius;
  124. var HeightRadius = arcTo.HeightRadius;
  125. var StartAngle = arcTo.StartAngle;
  126. var SwingAngle = arcTo.SwingAngle;
  127. var wR= System.Math.Round(double.Parse(WidthRadius.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  128. var hR = System.Math.Round(double.Parse(HeightRadius.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  129. var stAng = System.Math.Round(double.Parse(StartAngle.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  130. var swAng = System.Math.Round(double.Parse(SwingAngle.Value) * Globals.px96 * 1.0 / Globals.px914400, Globals.degree);
  131. var endAng = stAng + swAng;
  132. d +=PPTXSvg .ShapeArc(wR, hR, wR, hR, stAng, endAng, false);
  133. }
  134. if (child is QuadraticBezierCurveTo quadraticBezierCurveTo)
  135. {
  136. var elms= quadraticBezierCurveTo.Elements<DocumentFormat.OpenXml.Drawing.Point>();
  137. if (elms != null) {
  138. var list = elms.ToList();
  139. var Cx1 = double.Parse(list[0].X.Value) * Globals.px96 * 1.0 / Globals.px914400;
  140. var Cy1 = double.Parse(list[0].Y.Value) * Globals.px96 * 1.0 / Globals.px914400;
  141. var Cx2 = double.Parse(list[1].X.Value) * Globals.px96 * 1.0 / Globals.px914400;
  142. var Cy2 = double.Parse(list[1].Y.Value) * Globals.px96 * 1.0 / Globals.px914400;
  143. var Cx3 = double.Parse(list[2].X.Value) * Globals.px96 * 1.0 / Globals.px914400;
  144. var Cy3 = double.Parse(list[2].Y.Value) * Globals.px96 * 1.0 / Globals.px914400;
  145. d += " C" + System.Math.Round(Cx1, Globals.degree) + "," + System.Math.Round(Cy1, Globals.degree) + " " + System.Math.Round(Cx2, Globals.degree) + "," + System.Math.Round(Cy2, Globals.degree) + " " + System.Math.Round(Cx3, Globals.degree) + "," + System.Math.Round(Cy3, Globals.degree);
  146. }
  147. }
  148. if (child is CubicBezierCurveTo cubicBezierCurveTo)
  149. {
  150. var elms = cubicBezierCurveTo.Elements<DocumentFormat.OpenXml.Drawing.Point>();
  151. if (elms != null)
  152. {
  153. var list = elms.ToList();
  154. var Cx1 = double.Parse(list[0].X.Value) * Globals.px96 * 1.0 / Globals.px914400;
  155. var Cy1 = double.Parse(list[0].Y.Value) * Globals.px96 * 1.0 / Globals.px914400;
  156. var Cx2 = double.Parse(list[1].X.Value) * Globals.px96 * 1.0 / Globals.px914400;
  157. var Cy2 = double.Parse(list[1].Y.Value) * Globals.px96 * 1.0 / Globals.px914400;
  158. d += " Q" + System.Math.Round(Cx1, Globals.degree) + "," + System.Math.Round(Cy1, Globals.degree) + " " + System.Math.Round(Cx2, Globals.degree) + "," + System.Math.Round(Cy2, Globals.degree);
  159. }
  160. }
  161. }
  162. //是否关闭svg
  163. if (close != null)
  164. {
  165. d += " z";
  166. }
  167. List<SvgShape> shapes = new List<SvgShape>() {
  168. new SvgPath {
  169. type = "path",
  170. // Fill = (!imgFillFlg ? (grndFillFlg ? "url(#linGrd_" + order + ")" : Fill.Color) : "url(#imgPtrn_" + order + ")"),
  171. //Stroke = "#" + shapeBorder.Color,
  172. //StrokeWidth = shapeBorder.Width + "",
  173. //StrokeDasharray = shapeBorder.Stroke,
  174. d=d,
  175. start=shape.style.border.headEnd!=null?shape.style.border.headEnd:null,
  176. end=shape.style.border.tailEnd!=null?shape.style.border.tailEnd:null,
  177. }
  178. };
  179. shape.svg = new Svg {
  180. id=index+"",
  181. svgShape=shapes
  182. };
  183. shape.shapeType = "custom";
  184. }
  185. }
  186. var elmt = new List<Item> ();
  187. shape.uid = Shape.suid;
  188. elmt.Add(shape);
  189. return elmt;
  190. }
  191. public List<Paragraph> DrawText() {
  192. double top = getTopForCurrentAnchoring(this.Shape.VerticalAlign, this.Shape.Texts);
  193. List<Paragraph> Paragraphs = new List<Paragraph>();
  194. foreach (var par in Shape.Texts)
  195. {
  196. double paragraphTop = this.top + (this.Shape.VerticalAlign.Equals(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues.Top) ? par.getSpaceBeforePoints() : 0);
  197. Paragraph paragraph= new HTEXLib.Paragraph { animatable = par.Animatable ,invisible=par.Invisible};
  198. paragraph.style.position.y = paragraphTop;
  199. paragraph.style.position.x =this.left;
  200. paragraph.style.position.cx = width;
  201. paragraph.style.position.cy = height;
  202. paragraph.style.position.rot = rot;
  203. paragraph.style.vert = this.Shape.VerticalAlign.ToString();
  204. paragraph.style.hori = par.Align;
  205. paragraph.style.writing = Shape.WritingMode;
  206. if (par.bullet != null) {
  207. var bullet = par.bullet;
  208. paragraph.buChar = new BuChar
  209. {
  210. type = bullet.BulletType,
  211. left = bullet.Left ,
  212. buchar=bullet.Text,
  213. color=bullet.FontColor,
  214. typeface=bullet.FontFamily,
  215. size=bullet.FontSize,
  216. };
  217. }
  218. int newTop = par.getSpaceBeforePoints();
  219. int left = 0;
  220. List<HtexText> textElements = new List<HtexText>();
  221. if (par.RunPropList == null || par.RunPropList.Count == 0 && par.defaultRunProperties != null) //Only paragraph!
  222. {
  223. float points = float.Parse(par.defaultRunProperties.FontSize.ToString()) * 72.0F / 96.0F;
  224. Font font = new System.Drawing.Font(par.defaultRunProperties.FontFamily.ToString(), points);
  225. newTop = font.Height;
  226. }
  227. List<HtexText> processedElements = new List<HtexText>();
  228. List<Text> texts = new List<Text>();
  229. IEnumerable<PPTRunProperties> pPTRunProperties = breakTextsToShape(par);
  230. foreach (var text in pPTRunProperties)
  231. {
  232. float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
  233. Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
  234. if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
  235. else if (text.Italic)
  236. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
  237. else if (text.Underline != null && text.Underline.Equals("Single"))
  238. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
  239. newTop = font.Height > newTop ? font.Height : newTop;
  240. newTop = par.getLineSpacingInPointsFromFont(newTop);
  241. if (text.isBreak)
  242. {
  243. top += newTop;
  244. left = 0;
  245. fixLeftSpacingForAlignment(processedElements, par, font);
  246. processedElements.Clear();
  247. continue;
  248. }
  249. String currentString = text.Text.TrimEnd() + getStringFromTextElements(processedElements);
  250. //Text must already be broken to lines
  251. //Size size = MeasureString(currentString, font);
  252. // if (size.Width > this.width - par.Indent - par.marginLeft - par.marginRight)
  253. // {
  254. // top += newTop;
  255. // left = 0;
  256. // fixLeftSpacingForAlignment(processedElements, par, font);
  257. // processedElements.Clear();
  258. // }
  259. HtexText t1 = new HtexText(left: left,
  260. top: top,
  261. fontFamily: text.FontFamily,
  262. fontColor: text.FontColor,
  263. fontSize: text.FontSize,
  264. isBullet: text.isBullet,
  265. bold: text.Bold,
  266. italic: text.Italic,
  267. underline: text.Underline,
  268. id: id,
  269. slideIndex: slideIndex)
  270. {
  271. Rotate = this.rot
  272. };
  273. t1.width = MeasureString(text.Text, font);
  274. if (text.isBullet && text.Text != null && text.Text.Contains("rId"))
  275. {
  276. t1.PictureBullet = true;
  277. t1.width = text.bulletSize;
  278. t1.bulletSize = text.bulletSize;
  279. newTop = text.bulletSize;
  280. }
  281. t1.Text = text.Text;
  282. textElements.Add(t1);
  283. texts.Add(new Text
  284. {
  285. content = t1.Text,
  286. link = text.link,
  287. linkType = text.linkType,
  288. style = new FontStyle
  289. {
  290. align=par.FontAlign,
  291. spacing=par.defTabSize,
  292. color = text.FontColor,
  293. family = text.FontFamily,
  294. top = top,
  295. left = left,
  296. size = text.FontSize,
  297. isBullet = text.isBullet,
  298. underline = t1.underline,
  299. italic = text.Italic,
  300. bold = text.Bold,
  301. rot = this.rot,
  302. width = t1.width,
  303. pictureBullet = t1.PictureBullet,
  304. bulletSize = t1.bulletSize
  305. }
  306. });
  307. processedElements.Add(t1);
  308. }
  309. fixLeftSpacingForAlignment(processedElements, par);
  310. HtexText lastTxt = null;
  311. List<HtexText> mergedTextElements = new List<HtexText>();
  312. foreach (HtexText textElement in textElements)
  313. {
  314. if (lastTxt == null || !lastTxt.sameProps(textElement))
  315. mergedTextElements.Add(textElement);
  316. else
  317. mergedTextElements[mergedTextElements.Count - 1].Text += textElement.Text;
  318. lastTxt = textElement;
  319. }
  320. //foreach (HtexText textElement in mergedTextElements) {
  321. // shapeBuilder.Append(textElement.DrawElement());
  322. //}
  323. top += newTop;
  324. top += par.getSpaceAfterPoints(newTop);
  325. top += par.getSpaceBeforePoints(newTop);
  326. paragraph.texts = texts;
  327. Paragraphs.Add(paragraph);
  328. }
  329. return Paragraphs;
  330. }
  331. private String getStringFromTextElements(List<HtexText> elements)
  332. {
  333. if (elements == null || elements.Count == 0)
  334. return "";
  335. StringBuilder result = new StringBuilder();
  336. foreach (HtexText el in elements)
  337. {
  338. result.Append(el.Text);
  339. }
  340. return result.ToString();
  341. }
  342. //We have two similar methods. This is worse because it uses the Width property of each element instead of measuring the whole string.
  343. //There is mistake in the calculations coming from that and the difference is bigger when there are more elements.
  344. private void fixLeftSpacingForAlignment(List<HtexText> textElements, PPTParagraph par)
  345. {
  346. int combinedWidth = 0;
  347. foreach (HtexText textElement in textElements)
  348. combinedWidth += textElement.width;
  349. int bulletOffset = 0;
  350. if (par.bullet != null && textElements.Count > 0 && !textElements[0].isBullet)
  351. {
  352. combinedWidth += par.bullet.bulletSize;
  353. bulletOffset = par.bullet.bulletSize;
  354. }
  355. double currentLeft = 0;
  356. if ("Center".Equals(par.Align))
  357. currentLeft = ((this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth) / 2;
  358. else if ("Right".Equals(par.Align))
  359. currentLeft = (this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth;
  360. foreach (HtexText textElement in textElements)
  361. {
  362. textElement.setLeft(currentLeft + par.Indent + bulletOffset + par.marginLeft + Shape.LeftInset);
  363. currentLeft += textElement.width;
  364. }
  365. }
  366. //We have two similar methods - this one is better because it measures the whole string with the font.
  367. private void fixLeftSpacingForAlignment(List<HtexText> textElements, PPTParagraph par, Font font)
  368. {
  369. int combinedWidth = 0;
  370. StringBuilder combinedText = new StringBuilder();
  371. foreach (HtexText textElement in textElements)
  372. {
  373. if (textElement.PictureBullet)
  374. combinedWidth += textElement.bulletSize;
  375. else
  376. combinedText.Append(textElement.Text);
  377. }
  378. int bulletOffset = 0;
  379. if (par.bullet != null && textElements.Count > 0 && !textElements[0].isBullet)
  380. {
  381. bulletOffset = par.bullet.bulletSize;
  382. combinedWidth += par.bullet.bulletSize;
  383. }
  384. combinedWidth += MeasureString(combinedText.ToString(), font);
  385. double firstLeft = 0;
  386. if ("Center".Equals(par.Align))
  387. firstLeft = ((this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth) / 2;
  388. else if ("Right".Equals(par.Align))
  389. firstLeft = (this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth;
  390. combinedText = new StringBuilder();
  391. combinedWidth = 0; //Now used only for picture bullets!
  392. foreach (HtexText textElement in textElements)
  393. {
  394. textElement.setLeft(firstLeft + par.Indent + bulletOffset + par.marginLeft + combinedWidth + Shape.LeftInset + MeasureString(combinedText.ToString(), font));
  395. if (textElement.PictureBullet)
  396. combinedWidth += textElement.bulletSize;
  397. else
  398. combinedText.Append(textElement.Text);
  399. }
  400. }
  401. private double getTopForCurrentAnchoring(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues anchoring, LinkedList<PPTParagraph> paragraphList)
  402. {
  403. if (anchoring.Equals(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues.Top))
  404. return Shape.TopInset;
  405. double combinedHeight = 0;
  406. foreach (PPTParagraph par in paragraphList)
  407. {
  408. int newTop = 0;
  409. IEnumerable<PPTRunProperties> splitText = breakTextsToShape(par);
  410. foreach (var text in splitText)
  411. {
  412. float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
  413. Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
  414. if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
  415. else if (text.Italic) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
  416. else if (text.Underline != null && text.Underline.Equals("Single"))
  417. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
  418. if (text.isBreak)
  419. {
  420. combinedHeight += newTop;
  421. newTop = font.Height;
  422. continue;
  423. }
  424. newTop = font.Height > newTop ? font.Height : newTop;
  425. }
  426. combinedHeight += par.getLineSpacingInPointsFromFont(newTop);
  427. combinedHeight += par.getSpaceBeforePoints(newTop);
  428. combinedHeight += par.getSpaceAfterPoints(newTop);
  429. }
  430. combinedHeight += Shape.TopInset + Shape.BottomInset;
  431. if (anchoring.Equals(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues.Bottom))
  432. return this.height - combinedHeight;
  433. return (this.height - combinedHeight) / 2; //Center align
  434. }
  435. private IEnumerable<PPTRunProperties> breakTextsToShape(PPTParagraph par)
  436. {
  437. List<PPTRunProperties> list = par.RunPropList;
  438. List<PPTRunProperties> result = new List<PPTRunProperties>();
  439. String previousToken = null;
  440. int bulletSize = 0;
  441. foreach (var text in list)
  442. {
  443. float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
  444. Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
  445. if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
  446. else if (text.Italic) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
  447. else if (text.Underline != null && text.Underline.Equals("Single"))
  448. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
  449. int size = 0;
  450. if (text.isBullet && text.Text != null && text.Text.Contains("rId"))
  451. bulletSize = text.bulletSize;
  452. else
  453. size = MeasureString((previousToken == null ? "" : previousToken + " ") + text.Text, font);
  454. if (text.isBreak || size + bulletSize < this.width - par.Indent - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset)
  455. {
  456. if (text.Text != null && text.Text.Trim() != "" && !(text.isBullet && text.Text.Contains("rId")))
  457. {
  458. previousToken = (previousToken == null ? "" : previousToken) + text.Text;
  459. }
  460. if (text.isBreak)
  461. previousToken = null;
  462. result.Add(text);
  463. continue;
  464. }
  465. // previousToken = null;
  466. string[] tokens = text.Text.Split(' ');
  467. int index = 0;
  468. foreach (string token in tokens)
  469. {
  470. index++;
  471. int combinedSize = MeasureString((previousToken == null ? "" : previousToken + " ") + token, font);
  472. if (combinedSize + bulletSize > this.width - par.Indent - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset)
  473. {
  474. PPTRunProperties temp = new PPTRunProperties(text);
  475. temp.Text = "";
  476. temp.isBreak = true;
  477. result.Add(temp);
  478. temp = new PPTRunProperties(text);
  479. temp.Text = index < tokens.Length ? token + " " : token;
  480. result.Add(temp);
  481. previousToken = token;
  482. }
  483. else
  484. {
  485. PPTRunProperties temp = new PPTRunProperties(text);
  486. temp.Text = index < tokens.Length ? token + " " : token;
  487. result.Add(temp);
  488. previousToken = (previousToken == null ? "" : previousToken + " ") + token;
  489. }
  490. }
  491. }
  492. return result;
  493. }
  494. public static int MeasureString(string s, Font font)
  495. {
  496. s = s.Replace("\t", "aaaa");//TODO the replace is dirty hack for measuring tabulations
  497. StringFormat stringFormat = new StringFormat(StringFormat.GenericTypographic);
  498. CharacterRange[] rng = { new CharacterRange(0, s.Length) };
  499. stringFormat.SetMeasurableCharacterRanges(rng);
  500. Graphics g = Graphics.FromImage(new Bitmap(100, 100));
  501. //Use measure character ranges with a big box because we used this for measurement only
  502. //Later we might better use this for drawing the text.
  503. Region[] regions = g.MeasureCharacterRanges(s, font, new System.Drawing.Rectangle(0, 0, 10000, 3000), stringFormat);
  504. foreach (Region region in regions)
  505. {
  506. RectangleF rect = region.GetBounds(g);
  507. return (int)System.Math.Round(rect.Width);
  508. }
  509. return 0;
  510. //
  511. // SizeF result;
  512. // using (var image = new Bitmap(1, 1))
  513. // {
  514. // using (var g = Graphics.FromImage(image))
  515. // {
  516. // result = g.MeasureString(s, font);
  517. // }
  518. // }
  519. //
  520. // return result.ToSize();
  521. }
  522. }
  523. }