Rich2Docx.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. using FastReport.RichTextParser;
  2. using FastReport.Utils;
  3. using System;
  4. using System.Drawing;
  5. using System.Text;
  6. namespace FastReport.Export.OoXML
  7. {
  8. /// <summary>
  9. /// Save
  10. /// </summary>
  11. public class RTF_ToDocX : IDisposable
  12. {
  13. private RichDocument doc;
  14. private Rectangle ext_padding = new Rectangle();
  15. #region Private methods
  16. private string Quoted(long p)
  17. {
  18. return String.Concat("\"", p.ToString(), "\" ");
  19. }
  20. private string Quoted(string p)
  21. {
  22. return String.Concat("\"", p, "\" ");
  23. }
  24. private string GetRGBString(Color c)
  25. {
  26. return "\"#" + /*ExportUtils.ByteToHex(c.A) +*/ ExportUtils.ByteToHex(c.R) + ExportUtils.ByteToHex(c.G) + ExportUtils.ByteToHex(c.B) + "\"";
  27. }
  28. private string TranslateText(string text)
  29. {
  30. StringBuilder TextStrings = new StringBuilder();
  31. int start_idx = 0;
  32. while (true)
  33. {
  34. int idx = text.IndexOfAny("&<>".ToCharArray(), start_idx);
  35. if (idx != -1)
  36. {
  37. TextStrings.Append(text.Substring(start_idx, idx - start_idx));
  38. switch (text[idx])
  39. {
  40. case '&': TextStrings.Append("&amp;"); break;
  41. case '<': TextStrings.Append("&lt;"); break;
  42. case '>': TextStrings.Append("&gt;"); break;
  43. }
  44. start_idx = ++idx;
  45. continue;
  46. }
  47. TextStrings.Append(text.Substring(start_idx));
  48. break;
  49. }
  50. return TextStrings.ToString();
  51. }
  52. #endregion
  53. /// <inheritdoc/>
  54. public void Dispose()
  55. {
  56. }
  57. /// <inheritdoc/>
  58. public RTF_ToDocX(RichDocument doc)
  59. {
  60. this.doc = doc;
  61. }
  62. private void SaveDocumentBody(StringBuilder s)
  63. {
  64. foreach (Page p in doc.pages)
  65. SavePage(s, p, false);
  66. }
  67. private void SavePage(StringBuilder s, Page page, bool v)
  68. {
  69. SaveSequence(s, page.sequence, false);
  70. }
  71. private string GetFontName(RunFormat format)
  72. {
  73. string Name = "Arial";
  74. int font_idx = (int)format.font_idx;
  75. if (font_idx < doc.font_list.Count)
  76. {
  77. RFont rf = doc.font_list[font_idx];
  78. Name = rf.FontName;
  79. }
  80. return Name;
  81. }
  82. private void SaveRun(StringBuilder s, Run r)
  83. {
  84. s.Append("<w:r><w:rPr>");
  85. string FontName = GetFontName(r.format);
  86. s.Append("<w:rFonts w:ascii=" + Quoted(FontName) + " w:hAnsi=" + Quoted(FontName) + " w:cs=" + Quoted(FontName) + " /> ");
  87. if (r.format.bold)
  88. s.Append("<w:b />");
  89. if (r.format.strike)
  90. s.Append("<w:strike />");
  91. if (r.format.italic)
  92. s.Append("<w:i />");
  93. if (r.format.underline)
  94. s.Append("<w:u w:val=" + Quoted("single") + "/>");
  95. s.Append("<w:color w:val=" + GetRGBString(r.format.color) + " />");
  96. s.Append("<w:sz w:val=" + Quoted(r.format.font_size) + " />");
  97. s.Append("<w:szCs w:val=" + Quoted(r.format.font_size) + " />");
  98. s.Append("</w:rPr>");
  99. s.Append("<w:t xml:space=\"preserve\">").Append(this.TranslateText(r.text)).Append("</w:t>");
  100. s.Append("</w:r>");
  101. }
  102. private void SavePargraph(StringBuilder s, RichTextParser.Paragraph par, bool InTable)
  103. {
  104. s.AppendLine("<w:p>");
  105. string halign = "";
  106. switch (par.format.align)
  107. {
  108. case RichTextParser.ParagraphFormat.HorizontalAlign.Left: halign = "left"; break;
  109. case RichTextParser.ParagraphFormat.HorizontalAlign.Right: halign = "right"; break;
  110. case RichTextParser.ParagraphFormat.HorizontalAlign.Centered: halign = "center"; break;
  111. case RichTextParser.ParagraphFormat.HorizontalAlign.Justified:
  112. default:
  113. halign = "both";
  114. break;
  115. }
  116. //switch (par.format.Valign)
  117. //{
  118. // case RichTextParser.ParagraphFormat.VerticalAlign.Top: halign = "top"; break;
  119. // case RichTextParser.ParagraphFormat.VerticalAlign.Center: halign = "center"; break;
  120. // case RichTextParser.ParagraphFormat.VerticalAlign.Bottom: halign = "bottom"; break;
  121. // default:
  122. // halign = "top";
  123. // break;
  124. //}
  125. s.Append("<w:pPr><w:jc w:val=").Append(Quoted(halign)).Append(" />");
  126. if (par.format.first_line_indent > 0)
  127. s.Append("<w:ind w:firstLine=").Append(Quoted(par.format.first_line_indent)).Append("/>");
  128. #region Paragraph spacing
  129. int before_space = par.format.space_before + ext_padding.Top;
  130. int after_space = par.format.space_after + ext_padding.Bottom;
  131. s.Append("<w:spacing ");
  132. if (before_space != 0)
  133. {
  134. s.Append("w:before=").Append(Quoted(before_space));
  135. ext_padding.Y = 0;
  136. }
  137. if (after_space != 0)
  138. {
  139. s.Append(" w:after=").Append(Quoted(after_space));
  140. }
  141. s.Append(" w:line=");
  142. int spacing;
  143. if (par.format.line_spacing != 0)
  144. spacing = (int)(par.format.line_spacing) * 10;
  145. else
  146. spacing = 0;
  147. switch (par.format.lnspcmult)
  148. {
  149. //case LineSpacingType.Single:
  150. // sb.Append(Quoted(238));
  151. // sb.Append(" w:lineRule=\"auto\"");
  152. // break;
  153. case RichTextParser.ParagraphFormat.LnSpcMult.Multiply:
  154. s.Append(Quoted(spacing));
  155. s.Append(" w:lineRule=\"auto\"");
  156. break;
  157. //case LineSpacingType.AtLeast:
  158. // sb.Append(Quoted((int)(20 * htmlTextRenderer.ParagraphFormat.LineSpacing * 0.75f)));
  159. // sb.Append(" w:lineRule=\"atLeast\"");
  160. // break;
  161. case RichTextParser.ParagraphFormat.LnSpcMult.Exactly:
  162. s.Append(Quoted(spacing));
  163. s.Append(" w:lineRule=\"exact\"");
  164. break;
  165. }
  166. s.Append(" w:beforeAutospacing=\"0\" w:afterAutospacing=\"0\" />");
  167. #endregion
  168. #region Paragraph indent
  169. if (ext_padding.Right + ext_padding.Left != 0)
  170. {
  171. s.Append("<w:ind");
  172. if (ext_padding.Right != 0)
  173. s.Append(" w:right=" + Quoted(ext_padding.Right));
  174. if (ext_padding.Left != 0)
  175. s.Append(" w:left=" + Quoted(ext_padding.Left));
  176. s.Append(" />");
  177. }
  178. #endregion
  179. s.Append("</w:pPr>"); ;
  180. foreach (Run r in par.runs)
  181. SaveRun(s, r);
  182. s.AppendLine("</w:p>");
  183. }
  184. private void SaveTable(StringBuilder s, RichTextParser.Table tbl, bool InTable)
  185. {
  186. s.Append("<w:tbl>");
  187. // Table properties
  188. s.Append("<w:tblPr>");
  189. s.Append("<w:tblW w:w=\"0\" w:type=\"auto\" />");
  190. s.Append("<w:tblCellMar><w:left w:w=\"0\" w:type=\"dxa\"/><w:right w:w=\"0\" w:type=\"dxa\"/></w:tblCellMar>");
  191. s.Append("<w:tblBorders>");
  192. s.Append("<w:top w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\" />");
  193. s.Append("<w:left w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\" />");
  194. s.Append("<w:bottom w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\" />");
  195. s.Append("<w:right w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\" />");
  196. s.Append("<w:insideH w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\" />");
  197. s.Append("<w:insideV w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\" />");
  198. s.Append("</w:tblBorders>");
  199. s.Append("</w:tblPr>");
  200. // Table grid
  201. s.Append("<w:tblGrid>");
  202. foreach (Column column in tbl.columns)
  203. {
  204. s.Append("<w:gridCol w:w=" + Quoted(column.Width) + " />");
  205. }
  206. s.Append("</w:tblGrid>");
  207. foreach (TableRow row in tbl.rows)
  208. SaveRow(s, row);
  209. s.Append("</w:tbl>");
  210. }
  211. private void SaveRow(StringBuilder s, TableRow row)
  212. {
  213. s.Append("<w:tr><w:trPr>");
  214. s.Append("<w:trHeight w:hRule=\"").Append("exact").
  215. Append("\" w:val=").Append(Quoted(row.height)).Append("/></w:trPr>");
  216. foreach (RichObjectSequence seq in row.cells)
  217. {
  218. s.Append("<w:tc><w:tcPr>");
  219. s.Append("<w:tcW w:w=").Append(Quoted(9237)).Append(" w:type=\"dxa\"/>"); // Fix cell width
  220. s.AppendLine("</w:tcPr><w:p>");
  221. SaveSequence(s, seq, true);
  222. s.AppendLine("</w:p></w:tc>");
  223. }
  224. s.AppendLine("</w:tr>");
  225. }
  226. private void SaveSequence(StringBuilder s, RichObjectSequence seq, bool InTable)
  227. {
  228. foreach (RichTextParser.RichObject robj in seq.objects)
  229. {
  230. switch (robj.type)
  231. {
  232. case RichTextParser.RichObject.Type.Paragraph:
  233. SavePargraph(s, robj.paragraph, InTable);
  234. break;
  235. case RichTextParser.RichObject.Type.Picture:
  236. // SkipPicture
  237. break;
  238. case RichTextParser.RichObject.Type.Table:
  239. SaveTable(s, robj.table, InTable);
  240. break;
  241. }
  242. }
  243. }
  244. /// <summary>
  245. /// Padding over ridh object
  246. /// </summary>
  247. public Rectangle Padding
  248. {
  249. get { return ext_padding; }
  250. set { ext_padding = value; }
  251. }
  252. /// <summary>
  253. /// This prperty keep RTF to DOC translation result, i.e. DOCX XML fragment
  254. /// </summary>
  255. public string DocX
  256. {
  257. get
  258. {
  259. StringBuilder s = new StringBuilder();
  260. SaveDocumentBody(s);
  261. return s.ToString();
  262. }
  263. }
  264. }
  265. }