RTF_DocumentSaver.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. //using System.Linq;
  5. using System.Text;
  6. using System.Drawing.Imaging;
  7. namespace FastReport.RichTextParser
  8. {
  9. #pragma warning disable 1591
  10. /// <summary>
  11. /// Save RTF document to text stream
  12. /// </summary>
  13. public class RTF_DocumentSaver : IDisposable
  14. {
  15. const int PIC_BUFF_SIZE = 512;
  16. internal const string XCONV = "0123456789ABCDEF";
  17. private RichDocument doc;
  18. private ParagraphFormat.HorizontalAlign prev_align = ParagraphFormat.HorizontalAlign.Left;
  19. RunFormat current_format;
  20. public ImageFormat imageFormat;
  21. public bool DomesticCodepage = false;
  22. public RTF_DocumentSaver(RichDocument doc)
  23. {
  24. this.doc = doc;
  25. imageFormat = ImageFormat.Png;
  26. }
  27. private void SaveFontTable(StringBuilder s)
  28. {
  29. if (doc.font_list != null)
  30. {
  31. s.Append("{\\fonttbl");
  32. foreach (RFont f in doc.font_list)
  33. s.AppendFormat("\n{{\\f{0}\\{1}\\fcharset{2} {3};}}", f.font_id, FamilyName(f), f.charset, f.FontName);
  34. s.Append("}\n");
  35. }
  36. }
  37. private void SaveColorTable(StringBuilder s)
  38. {
  39. if (doc.color_list != null)
  40. {
  41. s.Append("{\\colortbl;");
  42. foreach (System.Drawing.Color c in doc.color_list)
  43. s.AppendFormat("\\red{0}\\green{1}\\blue{2};", c.R, c.G, c.B);
  44. s.Append("}\n");
  45. }
  46. }
  47. private void SaveStyles(StringBuilder s)
  48. {
  49. if (doc.style_list != null)
  50. {
  51. ParagraphFormat default_style = new ParagraphFormat();
  52. s.Append("{\\stylesheet");
  53. foreach (Style style in doc.style_list)
  54. {
  55. s.Append("{\\s").Append(style.styledef);
  56. SaveParagraphFormat(s, style.paragraph_style, default_style);
  57. s.Append(" ").Append(style.stylename).Append('}');
  58. }
  59. s.Append("}\n");
  60. }
  61. }
  62. internal void SaveHeader(StringBuilder s)
  63. {
  64. s.Append("\\rtf1\\ansi");
  65. if (doc.codepage != 0)
  66. s.AppendFormat("\\ansicpg{0}", doc.codepage);
  67. if (doc.default_font != 0)
  68. s.AppendFormat("\\deff{0}", doc.default_font);
  69. if (doc.default_lang != 0)
  70. s.AppendFormat("\\deflang{0}", doc.default_lang);
  71. SaveFontTable(s);
  72. SaveColorTable(s);
  73. SaveStyles(s);
  74. }
  75. private string FamilyName(RFont font)
  76. {
  77. switch (font.family)
  78. {
  79. case RFont.Family.Nil:
  80. return "fnil";
  81. case RFont.Family.Rroman:
  82. return "froman";
  83. case RFont.Family.Swiss:
  84. return "fswiss";
  85. case RFont.Family.Modern:
  86. return "fmodern";
  87. case RFont.Family.Script:
  88. return "fscript";
  89. case RFont.Family.Decor:
  90. return "fdecor";
  91. case RFont.Family.Tech:
  92. return "ftech";
  93. case RFont.Family.Bidi:
  94. return "fbidi";
  95. default:
  96. return "froman";
  97. }
  98. }
  99. internal void SaveDocumentBody(StringBuilder s)
  100. {
  101. s.AppendFormat("\\paperw{0}\\paperh{1}\\margl{2}\\margt{3}\\margr{4}\\margb{5}\\deftab{6}\n",
  102. doc.paper_width, doc.paper_height,
  103. doc.global_margin_left, doc.global_margin_top, doc.global_margin_right, doc.global_margin_bottom,
  104. doc.default_tab_width);
  105. if (doc.pages != null)
  106. foreach (Page p in doc.pages)
  107. SavePage(s, p, false);
  108. }
  109. private void SavePage(StringBuilder s, Page page, bool v)
  110. {
  111. if (page.page_width != 0)
  112. s.AppendFormat(@"\pgwsxn{0}", page.page_width);
  113. if (page.page_heigh != 0)
  114. s.AppendFormat(@"\pghsxn{0}", page.page_heigh);
  115. if(page.margin_left != 0)
  116. s.AppendFormat(@"\marglsxn{0}", page.margin_left);
  117. if (page.margin_right != 0)
  118. s.AppendFormat(@"\margrsxn{0}", page.margin_right);
  119. if (page.margin_top != 0)
  120. s.AppendFormat(@"\margtsxn{0}", page.margin_top);
  121. if (page.margin_bottom != 0)
  122. s.AppendFormat(@"\margbsxn{0}", page.margin_bottom);
  123. SaveSequence(s, page.sequence, false);
  124. }
  125. private string HorizontalAlignCode(ParagraphFormat.HorizontalAlign align)
  126. {
  127. switch (align)
  128. {
  129. case ParagraphFormat.HorizontalAlign.Centered: return "\\qc";
  130. case ParagraphFormat.HorizontalAlign.Left: return "\\ql";
  131. case ParagraphFormat.HorizontalAlign.Right: return "\\qr";
  132. case ParagraphFormat.HorizontalAlign.Justified: return "\\qj";
  133. case ParagraphFormat.HorizontalAlign.Distributed: return "\\qd";
  134. case ParagraphFormat.HorizontalAlign.Kashida: return "\\qk";
  135. case ParagraphFormat.HorizontalAlign.Thai: return "\\qt";
  136. default: return "";
  137. }
  138. }
  139. private string VerticalAlignCode(Column.VertAlign valign)
  140. {
  141. switch (valign)
  142. {
  143. case Column.VertAlign.Top: return "\\clvertalt";
  144. case Column.VertAlign.Center: return "\\clvertalc";
  145. case Column.VertAlign.Bottom: return "\\clvertalb";
  146. default: return "";
  147. }
  148. }
  149. private void SaveParagraphFormat(StringBuilder sb, ParagraphFormat format, ParagraphFormat prev_format)
  150. {
  151. if (format.align != prev_format.align)
  152. sb.Append(HorizontalAlignCode(format.align));
  153. if (format.line_spacing != prev_format.line_spacing)
  154. sb.Append("\\sl").Append(format.line_spacing);
  155. if (format.space_before != prev_format.space_before)
  156. sb.Append("\\sb").Append(format.space_before);
  157. if (format.space_after != prev_format.space_after)
  158. sb.Append("\\sa").Append(format.space_after);
  159. if (format.left_indent != prev_format.left_indent)
  160. sb.Append("\\li").Append(format.left_indent);
  161. if (format.right_indent != prev_format.right_indent)
  162. sb.Append("\\fi").Append(format.right_indent);
  163. if (format.first_line_indent != prev_format.first_line_indent)
  164. sb.Append("\\fi").Append(format.first_line_indent);
  165. if (format.lnspcmult != prev_format.lnspcmult)
  166. sb.Append("\\slmult").Append(format.lnspcmult);
  167. }
  168. private void SavePargraph(StringBuilder sb, Paragraph par, bool InTable)
  169. {
  170. if (par.runs.Count == 0)
  171. {
  172. if (!InTable)
  173. sb.Append("\\pard\\par\n");
  174. else
  175. sb.Append("\\pard\\intbl\\cell\n");
  176. }
  177. else
  178. {
  179. if (InTable)
  180. sb.Append("\\intbl\n");
  181. if (par.format.align != prev_align)
  182. {
  183. sb.AppendFormat("{0} ", HorizontalAlignCode(par.format.align));
  184. prev_align = par.format.align;
  185. }
  186. sb.Append("\\sl").Append(par.format.line_spacing);
  187. sb.Append("\\sb").Append(par.format.space_before);
  188. sb.Append("\\sa").Append(par.format.space_after);
  189. sb.Append("\\li").Append(par.format.left_indent);
  190. sb.Append("\\fi").Append(par.format.right_indent);
  191. sb.Append("\\fi").Append(par.format.first_line_indent);
  192. sb.Append("\\slmult").Append(par.format.lnspcmult);
  193. foreach (Run r in par.runs)
  194. {
  195. RunFormat fmt = r.format;
  196. if (current_format.bold != fmt.bold)
  197. {
  198. sb.Append(fmt.bold ? "\\b" : "\\b0");
  199. current_format.bold = fmt.bold;
  200. }
  201. if (current_format.underline != fmt.underline)
  202. {
  203. sb.Append(fmt.underline ? "\\ul" : "\\ulnone");
  204. current_format.underline = fmt.underline;
  205. }
  206. if (current_format.italic != fmt.italic)
  207. {
  208. sb.Append(fmt.italic ? "\\i" : "\\i0");
  209. current_format.italic = fmt.italic;
  210. }
  211. int curr_color_idx = doc.color_list.IndexOf(current_format.color);
  212. int fmt_color_idx = doc.color_list.IndexOf(fmt.color);
  213. if(fmt_color_idx == -1)
  214. {
  215. fmt_color_idx = doc.color_list.Count;
  216. doc.color_list.Add(fmt.color);
  217. }
  218. if (curr_color_idx != fmt_color_idx)
  219. {
  220. sb.AppendFormat("\\cf{0}", fmt_color_idx);
  221. current_format.color = fmt.color;
  222. }
  223. if (current_format.font_size != fmt.font_size)
  224. {
  225. sb.AppendFormat("\\fs{0}", fmt.font_size);
  226. current_format.font_size = fmt.font_size;
  227. }
  228. if (current_format.font_idx != fmt.font_idx)
  229. {
  230. sb.AppendFormat("\\f{0}", fmt.font_idx);
  231. current_format.font_idx = fmt.font_idx;
  232. }
  233. sb.Append(" ");
  234. if (r.text.Length == 0)
  235. sb.Append("\\tab ");
  236. else
  237. #if true
  238. foreach (char ch in r.text)
  239. {
  240. if (ch < 128 || DomesticCodepage)
  241. sb.Append(ch);
  242. else
  243. {
  244. sb.Append("\\u" + Convert.ToUInt32(ch) + "?");
  245. }
  246. }
  247. #else
  248. s.Append(r.text);
  249. #endif
  250. }
  251. if (!InTable)
  252. sb.Append("\\par\n");
  253. else
  254. sb.Append("\\cell\n");
  255. }
  256. }
  257. private void SavePicture(StringBuilder CellsStream, Picture pic, bool InTable)
  258. {
  259. CellsStream.Append("\\sb0\\li0\\sl0\\slmult0\\qc\\clvertalc {");
  260. float dx = (int)pic.width;
  261. float dy = (int)pic.height;
  262. CellsStream.Append("\\pict\\picw").Append(dx.ToString());
  263. CellsStream.Append("\\pich").Append(dy.ToString());
  264. CellsStream.Append("\\picwgoal").Append(pic.desired_width);
  265. CellsStream.Append("\\pichgoal").Append(pic.desired_height);
  266. CellsStream.Append("\\picscalex").Append(pic.scalex);
  267. CellsStream.Append("\\picscaley").Append(pic.scaley);
  268. if (imageFormat == System.Drawing.Imaging.ImageFormat.Jpeg)
  269. {
  270. CellsStream.Append("\\jpegblip\r\n");
  271. }
  272. else
  273. {
  274. CellsStream.Append("\\pngblip\r\n");
  275. imageFormat = System.Drawing.Imaging.ImageFormat.Png;
  276. }
  277. int n;
  278. byte[] picbuff = new Byte[PIC_BUFF_SIZE];
  279. MemoryStream pic_stream = new MemoryStream();
  280. pic.image.Save(pic_stream, imageFormat);
  281. pic_stream.Position = 0;
  282. do
  283. {
  284. n = pic_stream.Read(picbuff, 0, PIC_BUFF_SIZE);
  285. for (int z = 0; z < n; z++)
  286. {
  287. CellsStream.Append(XCONV[picbuff[z] >> 4]);
  288. CellsStream.Append(XCONV[picbuff[z] & 0xF]);
  289. }
  290. CellsStream.Append("\r\n");
  291. }
  292. while (n == PIC_BUFF_SIZE);
  293. CellsStream.Append("}");
  294. }
  295. private void SaveTable(StringBuilder s, Table tbl, bool InTable)
  296. {
  297. s.Append("\\trowd");
  298. foreach (Column col in tbl.columns)
  299. SaveColumn(s, col);
  300. foreach (TableRow row in tbl.rows)
  301. SaveRow(s, row);
  302. }
  303. private void SaveColumn(StringBuilder s, Column col)
  304. {
  305. // "clcbpat" - background color
  306. s.AppendFormat("{0}\\cellx{1}", VerticalAlignCode(col.valign), col.Width);
  307. }
  308. private void SaveRow(StringBuilder s, TableRow row)
  309. {
  310. s.AppendFormat("\\trgaph{0}\\trrh{1}\\trpaddl{2}\\trpaddr{3}",
  311. row.trgaph, row.height, row.default_pad_left, row.default_pad_right);
  312. foreach (RichObjectSequence seq in row.cells)
  313. {
  314. SaveSequence(s, seq, true);
  315. s.AppendLine("\\cell");
  316. }
  317. s.Append("\\row");
  318. }
  319. private void SaveSequence(StringBuilder s, RichObjectSequence seq, bool InTable)
  320. {
  321. foreach (RichObject robj in seq.objects)
  322. {
  323. switch (robj.type)
  324. {
  325. case RichObject.Type.Paragraph:
  326. SavePargraph(s, robj.pargraph, InTable);
  327. break;
  328. case RichObject.Type.Picture:
  329. SavePicture(s, robj.picture, InTable);
  330. break;
  331. case RichObject.Type.Table:
  332. SaveTable(s, robj.table, InTable);
  333. break;
  334. }
  335. }
  336. }
  337. public void Save(Stream stream)
  338. {
  339. StringBuilder s = new StringBuilder();
  340. stream.WriteByte((byte)'{');
  341. SaveHeader(s);
  342. SaveDocumentBody(s);
  343. ExportUtils.Write(stream, s.ToString());
  344. stream.WriteByte((byte)'}');
  345. }
  346. public string RichText
  347. {
  348. get
  349. {
  350. StringBuilder s = new StringBuilder();
  351. s.Append('{');
  352. SaveHeader(s);
  353. SaveDocumentBody(s);
  354. s.Append('}');
  355. return s.ToString();
  356. }
  357. }
  358. public void Dispose()
  359. {
  360. // Perhaps that everything clean
  361. }
  362. }
  363. #pragma warning restore 1591
  364. }