HtexShape.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  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. elmt.Add(shape);
  188. return elmt;
  189. }
  190. public List<Paragraph> DrawText() {
  191. double top = getTopForCurrentAnchoring(this.Shape.VerticalAlign, this.Shape.Texts);
  192. List<Paragraph> Paragraphs = new List<Paragraph>();
  193. foreach (var par in Shape.Texts)
  194. {
  195. double paragraphTop = this.top + (this.Shape.VerticalAlign.Equals(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues.Top) ? par.getSpaceBeforePoints() : 0);
  196. Paragraph paragraph= new HTEXLib.Paragraph { animatable = par.Animatable ,invisible=par.Invisible};
  197. paragraph.style.position.y = paragraphTop;
  198. paragraph.style.position.x =this.left;
  199. paragraph.style.position.cx = width;
  200. paragraph.style.position.cy = height;
  201. paragraph.style.position.rot = rot;
  202. paragraph.style.vert = this.Shape.VerticalAlign.ToString();
  203. paragraph.style.hori = par.Align;
  204. paragraph.style.writing = Shape.WritingMode;
  205. if (par.bullet != null) {
  206. var bullet = par.bullet;
  207. paragraph.buChar = new BuChar
  208. {
  209. type = bullet.BulletType,
  210. left = bullet.Left ,
  211. buchar=bullet.Text,
  212. color=bullet.FontColor,
  213. typeface=bullet.FontFamily,
  214. size=bullet.FontSize,
  215. };
  216. }
  217. int newTop = par.getSpaceBeforePoints();
  218. int left = 0;
  219. List<HtexText> textElements = new List<HtexText>();
  220. if (par.RunPropList == null || par.RunPropList.Count == 0 && par.defaultRunProperties != null) //Only paragraph!
  221. {
  222. float points = float.Parse(par.defaultRunProperties.FontSize.ToString()) * 72.0F / 96.0F;
  223. Font font = new System.Drawing.Font(par.defaultRunProperties.FontFamily.ToString(), points);
  224. newTop = font.Height;
  225. }
  226. List<HtexText> processedElements = new List<HtexText>();
  227. List<Text> texts = new List<Text>();
  228. IEnumerable<PPTRunProperties> pPTRunProperties = breakTextsToShape(par);
  229. foreach (var text in pPTRunProperties)
  230. {
  231. float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
  232. Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
  233. if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
  234. else if (text.Italic)
  235. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
  236. else if (text.Underline != null && text.Underline.Equals("Single"))
  237. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
  238. newTop = font.Height > newTop ? font.Height : newTop;
  239. newTop = par.getLineSpacingInPointsFromFont(newTop);
  240. if (text.isBreak)
  241. {
  242. top += newTop;
  243. left = 0;
  244. fixLeftSpacingForAlignment(processedElements, par, font);
  245. processedElements.Clear();
  246. continue;
  247. }
  248. String currentString = text.Text.TrimEnd() + getStringFromTextElements(processedElements);
  249. //Text must already be broken to lines
  250. //Size size = MeasureString(currentString, font);
  251. // if (size.Width > this.width - par.Indent - par.marginLeft - par.marginRight)
  252. // {
  253. // top += newTop;
  254. // left = 0;
  255. // fixLeftSpacingForAlignment(processedElements, par, font);
  256. // processedElements.Clear();
  257. // }
  258. HtexText t1 = new HtexText(left: left,
  259. top: top,
  260. fontFamily: text.FontFamily,
  261. fontColor: text.FontColor,
  262. fontSize: text.FontSize,
  263. isBullet: text.isBullet,
  264. bold: text.Bold,
  265. italic: text.Italic,
  266. underline: text.Underline,
  267. id: id,
  268. slideIndex: slideIndex)
  269. {
  270. Rotate = this.rot
  271. };
  272. t1.width = MeasureString(text.Text, font);
  273. if (text.isBullet && text.Text != null && text.Text.Contains("rId"))
  274. {
  275. t1.PictureBullet = true;
  276. t1.width = text.bulletSize;
  277. t1.bulletSize = text.bulletSize;
  278. newTop = text.bulletSize;
  279. }
  280. t1.Text = text.Text;
  281. textElements.Add(t1);
  282. texts.Add(new Text
  283. {
  284. content = t1.Text,
  285. link = text.link,
  286. linkType = text.linkType,
  287. style = new FontStyle
  288. {
  289. align=par.FontAlign,
  290. spacing=par.defTabSize,
  291. color = text.FontColor,
  292. family = text.FontFamily,
  293. top = top,
  294. left = left,
  295. size = text.FontSize,
  296. isBullet = text.isBullet,
  297. underline = t1.underline,
  298. italic = text.Italic,
  299. bold = text.Bold,
  300. rot = this.rot,
  301. width = t1.width,
  302. pictureBullet = t1.PictureBullet,
  303. bulletSize = t1.bulletSize
  304. }
  305. });
  306. processedElements.Add(t1);
  307. }
  308. fixLeftSpacingForAlignment(processedElements, par);
  309. HtexText lastTxt = null;
  310. List<HtexText> mergedTextElements = new List<HtexText>();
  311. foreach (HtexText textElement in textElements)
  312. {
  313. if (lastTxt == null || !lastTxt.sameProps(textElement))
  314. mergedTextElements.Add(textElement);
  315. else
  316. mergedTextElements[mergedTextElements.Count - 1].Text += textElement.Text;
  317. lastTxt = textElement;
  318. }
  319. //foreach (HtexText textElement in mergedTextElements) {
  320. // shapeBuilder.Append(textElement.DrawElement());
  321. //}
  322. top += newTop;
  323. top += par.getSpaceAfterPoints(newTop);
  324. top += par.getSpaceBeforePoints(newTop);
  325. paragraph.texts = texts;
  326. Paragraphs.Add(paragraph);
  327. }
  328. return Paragraphs;
  329. }
  330. private String getStringFromTextElements(List<HtexText> elements)
  331. {
  332. if (elements == null || elements.Count == 0)
  333. return "";
  334. StringBuilder result = new StringBuilder();
  335. foreach (HtexText el in elements)
  336. {
  337. result.Append(el.Text);
  338. }
  339. return result.ToString();
  340. }
  341. //We have two similar methods. This is worse because it uses the Width property of each element instead of measuring the whole string.
  342. //There is mistake in the calculations coming from that and the difference is bigger when there are more elements.
  343. private void fixLeftSpacingForAlignment(List<HtexText> textElements, PPTParagraph par)
  344. {
  345. int combinedWidth = 0;
  346. foreach (HtexText textElement in textElements)
  347. combinedWidth += textElement.width;
  348. int bulletOffset = 0;
  349. if (par.bullet != null && textElements.Count > 0 && !textElements[0].isBullet)
  350. {
  351. combinedWidth += par.bullet.bulletSize;
  352. bulletOffset = par.bullet.bulletSize;
  353. }
  354. double currentLeft = 0;
  355. if ("Center".Equals(par.Align))
  356. currentLeft = ((this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth) / 2;
  357. else if ("Right".Equals(par.Align))
  358. currentLeft = (this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth;
  359. foreach (HtexText textElement in textElements)
  360. {
  361. textElement.setLeft(currentLeft + par.Indent + bulletOffset + par.marginLeft + Shape.LeftInset);
  362. currentLeft += textElement.width;
  363. }
  364. }
  365. //We have two similar methods - this one is better because it measures the whole string with the font.
  366. private void fixLeftSpacingForAlignment(List<HtexText> textElements, PPTParagraph par, Font font)
  367. {
  368. int combinedWidth = 0;
  369. StringBuilder combinedText = new StringBuilder();
  370. foreach (HtexText textElement in textElements)
  371. {
  372. if (textElement.PictureBullet)
  373. combinedWidth += textElement.bulletSize;
  374. else
  375. combinedText.Append(textElement.Text);
  376. }
  377. int bulletOffset = 0;
  378. if (par.bullet != null && textElements.Count > 0 && !textElements[0].isBullet)
  379. {
  380. bulletOffset = par.bullet.bulletSize;
  381. combinedWidth += par.bullet.bulletSize;
  382. }
  383. combinedWidth += MeasureString(combinedText.ToString(), font);
  384. double firstLeft = 0;
  385. if ("Center".Equals(par.Align))
  386. firstLeft = ((this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth) / 2;
  387. else if ("Right".Equals(par.Align))
  388. firstLeft = (this.width - par.Indent - bulletOffset - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset) - combinedWidth;
  389. combinedText = new StringBuilder();
  390. combinedWidth = 0; //Now used only for picture bullets!
  391. foreach (HtexText textElement in textElements)
  392. {
  393. textElement.setLeft(firstLeft + par.Indent + bulletOffset + par.marginLeft + combinedWidth + Shape.LeftInset + MeasureString(combinedText.ToString(), font));
  394. if (textElement.PictureBullet)
  395. combinedWidth += textElement.bulletSize;
  396. else
  397. combinedText.Append(textElement.Text);
  398. }
  399. }
  400. private double getTopForCurrentAnchoring(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues anchoring, LinkedList<PPTParagraph> paragraphList)
  401. {
  402. if (anchoring.Equals(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues.Top))
  403. return Shape.TopInset;
  404. double combinedHeight = 0;
  405. foreach (PPTParagraph par in paragraphList)
  406. {
  407. int newTop = 0;
  408. IEnumerable<PPTRunProperties> splitText = breakTextsToShape(par);
  409. foreach (var text in splitText)
  410. {
  411. float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
  412. Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
  413. if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
  414. else if (text.Italic) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
  415. else if (text.Underline != null && text.Underline.Equals("Single"))
  416. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
  417. if (text.isBreak)
  418. {
  419. combinedHeight += newTop;
  420. newTop = font.Height;
  421. continue;
  422. }
  423. newTop = font.Height > newTop ? font.Height : newTop;
  424. }
  425. combinedHeight += par.getLineSpacingInPointsFromFont(newTop);
  426. combinedHeight += par.getSpaceBeforePoints(newTop);
  427. combinedHeight += par.getSpaceAfterPoints(newTop);
  428. }
  429. combinedHeight += Shape.TopInset + Shape.BottomInset;
  430. if (anchoring.Equals(DocumentFormat.OpenXml.Drawing.TextAnchoringTypeValues.Bottom))
  431. return this.height - combinedHeight;
  432. return (this.height - combinedHeight) / 2; //Center align
  433. }
  434. private IEnumerable<PPTRunProperties> breakTextsToShape(PPTParagraph par)
  435. {
  436. List<PPTRunProperties> list = par.RunPropList;
  437. List<PPTRunProperties> result = new List<PPTRunProperties>();
  438. String previousToken = null;
  439. int bulletSize = 0;
  440. foreach (var text in list)
  441. {
  442. float points = float.Parse(text.FontSize.ToString()) * 72.0F / 96.0F;
  443. Font font = new System.Drawing.Font(text.FontFamily.ToString(), points);
  444. if (text.Bold) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Bold);
  445. else if (text.Italic) font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Italic);
  446. else if (text.Underline != null && text.Underline.Equals("Single"))
  447. font = new System.Drawing.Font(text.FontFamily.ToString(), points, System.Drawing.FontStyle.Underline);
  448. int size = 0;
  449. if (text.isBullet && text.Text != null && text.Text.Contains("rId"))
  450. bulletSize = text.bulletSize;
  451. else
  452. size = MeasureString((previousToken == null ? "" : previousToken + " ") + text.Text, font);
  453. if (text.isBreak || size + bulletSize < this.width - par.Indent - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset)
  454. {
  455. if (text.Text != null && text.Text.Trim() != "" && !(text.isBullet && text.Text.Contains("rId")))
  456. {
  457. previousToken = (previousToken == null ? "" : previousToken) + text.Text;
  458. }
  459. if (text.isBreak)
  460. previousToken = null;
  461. result.Add(text);
  462. continue;
  463. }
  464. // previousToken = null;
  465. string[] tokens = text.Text.Split(' ');
  466. int index = 0;
  467. foreach (string token in tokens)
  468. {
  469. index++;
  470. int combinedSize = MeasureString((previousToken == null ? "" : previousToken + " ") + token, font);
  471. if (combinedSize + bulletSize > this.width - par.Indent - par.marginLeft - par.marginRight - Shape.LeftInset - Shape.RightInset)
  472. {
  473. PPTRunProperties temp = new PPTRunProperties(text);
  474. temp.Text = "";
  475. temp.isBreak = true;
  476. result.Add(temp);
  477. temp = new PPTRunProperties(text);
  478. temp.Text = index < tokens.Length ? token + " " : token;
  479. result.Add(temp);
  480. previousToken = token;
  481. }
  482. else
  483. {
  484. PPTRunProperties temp = new PPTRunProperties(text);
  485. temp.Text = index < tokens.Length ? token + " " : token;
  486. result.Add(temp);
  487. previousToken = (previousToken == null ? "" : previousToken + " ") + token;
  488. }
  489. }
  490. }
  491. return result;
  492. }
  493. public static int MeasureString(string s, Font font)
  494. {
  495. s = s.Replace("\t", "aaaa");//TODO the replace is dirty hack for measuring tabulations
  496. StringFormat stringFormat = new StringFormat(StringFormat.GenericTypographic);
  497. CharacterRange[] rng = { new CharacterRange(0, s.Length) };
  498. stringFormat.SetMeasurableCharacterRanges(rng);
  499. Graphics g = Graphics.FromImage(new Bitmap(100, 100));
  500. //Use measure character ranges with a big box because we used this for measurement only
  501. //Later we might better use this for drawing the text.
  502. Region[] regions = g.MeasureCharacterRanges(s, font, new System.Drawing.Rectangle(0, 0, 10000, 3000), stringFormat);
  503. foreach (Region region in regions)
  504. {
  505. RectangleF rect = region.GetBounds(g);
  506. return (int)System.Math.Round(rect.Width);
  507. }
  508. return 0;
  509. //
  510. // SizeF result;
  511. // using (var image = new Bitmap(1, 1))
  512. // {
  513. // using (var g = Graphics.FromImage(image))
  514. // {
  515. // result = g.MeasureString(s, font);
  516. // }
  517. // }
  518. //
  519. // return result.ToSize();
  520. }
  521. }
  522. }