HtexShape.cs 29 KB

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