ODFExport.cs 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. using FastReport.Utils;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.Globalization;
  7. using System.IO;
  8. using System.Text;
  9. using System.Windows.Forms;
  10. namespace FastReport.Export.Odf
  11. {
  12. /// <summary>
  13. /// Base class for any ODF exports.
  14. /// </summary>
  15. public partial class ODFExport : ExportBase
  16. {
  17. #region Constants
  18. private const float odfDivider = 37.82f;
  19. private const float odfMargDiv = 10f;
  20. private const float odfPageDiv = 10f;
  21. #endregion Constants
  22. /// <summary>
  23. /// Enum of OpenOffice formats.
  24. /// </summary>
  25. public enum OpenOfficeFormat
  26. {
  27. /// <summary>
  28. /// OpenOffice Spreadsheet format.
  29. /// </summary>
  30. Spreadsheet,
  31. /// <summary>
  32. /// OpenOffice Writer format.
  33. /// </summary>
  34. Writer
  35. }
  36. /// <summary>
  37. /// Standard of ODF format.
  38. /// </summary>
  39. public enum OdfStandard
  40. {
  41. /// <summary>
  42. /// ODF 1.0/1.1
  43. /// </summary>
  44. None = 0,
  45. /// <summary>
  46. /// ODF 1.2
  47. /// </summary>
  48. Odf1_2 = 1,
  49. /// <summary>
  50. /// XODF 1.0/1.1
  51. /// </summary>
  52. Xodf1_1 = 2,
  53. /// <summary>
  54. /// XODF 1.2
  55. /// </summary>
  56. Xodf1_2 = 3
  57. }
  58. #region Private fields
  59. private string creator;
  60. private OpenOfficeFormat exportType;
  61. private bool firstPage;
  62. private ExportMatrix matrix;
  63. private float pageBottom;
  64. private bool pageBreaks;
  65. private float pageHeight;
  66. private bool pageLandscape;
  67. private float pageLeft;
  68. private float pageRight;
  69. private float pageTop;
  70. private float pageWidth;
  71. private bool wysiwyg;
  72. private OdfStandard odfCompliance = OdfStandard.None;
  73. private bool isXODT = false;
  74. private bool useTagText = false;
  75. private bool writeVersion = false;
  76. private bool extendedStyles = false;
  77. private bool writeRdf = false;
  78. private CultureInfo localization;
  79. private bool exportLocale;
  80. #endregion Private fields
  81. #region Properties
  82. /// <summary>
  83. /// Creator of the document
  84. /// </summary>
  85. public string Creator
  86. {
  87. get { return creator; }
  88. set { creator = value; }
  89. }
  90. /// <summary>
  91. /// Is XODT format
  92. /// </summary>
  93. public bool IsXOTD
  94. {
  95. get { return isXODT; }
  96. set { isXODT = value; }
  97. }
  98. /// <summary>
  99. /// Switch of page breaks
  100. /// </summary>
  101. public bool PageBreaks
  102. {
  103. get { return pageBreaks; }
  104. set { pageBreaks = value; }
  105. }
  106. /// <summary>
  107. /// Wysiwyg mode, set for better results
  108. /// </summary>
  109. public bool Wysiwyg
  110. {
  111. get { return wysiwyg; }
  112. set { wysiwyg = value; }
  113. }
  114. /// <summary>
  115. /// Gets or sets locale for all document.
  116. /// </summary>
  117. public CultureInfo Locale
  118. {
  119. get { return localization; }
  120. set { localization = value; }
  121. }
  122. /// <summary>
  123. /// Gets or sets a value indicating that locale export are enabled.
  124. /// </summary>
  125. public bool ExportLocale
  126. {
  127. get { return exportLocale; }
  128. set { exportLocale = value; }
  129. }
  130. internal OpenOfficeFormat ExportType
  131. {
  132. get { return exportType; }
  133. set { exportType = value; }
  134. }
  135. /// <summary>
  136. /// Gets or sets ODF Compliance standard.
  137. /// </summary>
  138. public OdfStandard OdfCompliance
  139. {
  140. get
  141. {
  142. return odfCompliance;
  143. }
  144. set
  145. {
  146. odfCompliance = value;
  147. switch (odfCompliance)
  148. {
  149. case OdfStandard.Xodf1_1:
  150. useTagText = true;
  151. isXODT = true;
  152. writeVersion = false;
  153. extendedStyles = false;
  154. writeRdf = false;
  155. break;
  156. case OdfStandard.None:
  157. writeVersion = false;
  158. extendedStyles = false;
  159. writeRdf = false;
  160. break;
  161. case OdfStandard.Xodf1_2:
  162. useTagText = true;
  163. isXODT = true;
  164. writeVersion = true;
  165. extendedStyles = true;
  166. writeRdf = true;
  167. break;
  168. case OdfStandard.Odf1_2:
  169. writeVersion = true;
  170. extendedStyles = true;
  171. writeRdf = true;
  172. break;
  173. }
  174. }
  175. }
  176. #endregion Properties
  177. #region Private Methods
  178. private string GetOdfVersion()
  179. {
  180. switch (OdfCompliance)
  181. {
  182. case OdfStandard.Xodf1_2:
  183. case OdfStandard.Odf1_2:
  184. return "1.2";
  185. case OdfStandard.Xodf1_1:
  186. case OdfStandard.None:
  187. default:
  188. return "1.0";
  189. }
  190. }
  191. private int ExportCell(Stream file, ZipArchive zip, ExportIEMObject obj, int dx, int dy, ref int picCount)
  192. {
  193. Write(file, String.Format("<table:table-cell table:style-name=\"ce{0}\" office:value-type=\"string\" ",
  194. obj.StyleIndex.ToString()));
  195. if (dx > 1 || dy > 1)
  196. {
  197. Write(file, String.Format("table:number-columns-spanned=\"{0}\" ", dx.ToString()));
  198. Write(file, String.Format("table:number-rows-spanned=\"{0}\" ", dy.ToString()));
  199. }
  200. WriteLine(file, ">");
  201. if (obj.IsText)
  202. {
  203. // text
  204. ExportText(file, obj);
  205. }
  206. else if (obj.Width > 0)
  207. {
  208. // picture
  209. ExportPicture(file, zip, obj, ++picCount);
  210. }
  211. WriteLine(file, "</table:table-cell>");
  212. return picCount;
  213. }
  214. private void ExportODF(Stream stream)
  215. {
  216. ZipArchive zip = new ZipArchive();
  217. string ExportMime = exportType == OpenOfficeFormat.Spreadsheet ? "spreadsheet" : "text";
  218. OdfCreateMime(zip, "mimetype", ExportMime);
  219. OdfMakeDocStyles(zip, "styles.xml");
  220. #region Content.xml
  221. MemoryStream file = new MemoryStream();
  222. WriteLine(file, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  223. Write(file, "<office:document-content ");
  224. Write(file, OdfMakeXmlHeader());
  225. if (writeVersion) Write(file, $" office:version=\"{GetOdfVersion()}\"");
  226. WriteLine(file, ">");
  227. WriteLine(file, "<office:scripts/>");
  228. OdfFontFaceDecals(file);
  229. OdfAutomaticStyles(file);
  230. // body
  231. WriteLine(file, "<office:body>");
  232. if (!useTagText)
  233. WriteLine(file, "<office:spreadsheet>");
  234. else
  235. WriteLine(file, "<office:text>");
  236. TableBegin(file, 1);
  237. // rows
  238. int picCount = OdfRows(file, zip);
  239. TableEnd(file);
  240. if (!useTagText)
  241. WriteLine(file, "</office:spreadsheet>");
  242. else
  243. WriteLine(file, "</office:text>");
  244. WriteLine(file, "</office:body>");
  245. WriteLine(file, "</office:document-content>");
  246. zip.AddStream("content.xml", file);
  247. #endregion Content.xml
  248. OdfCreateManifest(zip, "META-INF/manifest.xml", picCount, ExportMime);
  249. OdfCreateMeta(zip, "meta.xml", Creator);
  250. if (writeRdf) OdfCreateRDF(zip, "manifest.rdf");
  251. zip.SaveToStream(Stream);
  252. zip.Clear();
  253. }
  254. private void ExportPicture(Stream file, ZipArchive zip, ExportIEMObject obj, int picCount)
  255. {
  256. string picName = picCount.ToString() + ".png";
  257. zip.AddStream("Pictures/Pic" + picName, obj.PictureStream);
  258. if (exportType == OpenOfficeFormat.Writer)
  259. Write(file, "<text:p>");
  260. Write(file,
  261. String.Format("<draw:frame text:anchor-type=\"frame\" draw:z-index=\"{0}\" draw:name=\"Pictures{1}\" draw:style-name=\"gr1\" svg:width=\"{2}cm\" svg:height=\"{3}cm\" svg:x=\"0cm\" svg:y=\"0cm\">",
  262. (picCount - 1).ToString(),
  263. picCount.ToString(),
  264. GetStringValue(obj.Width),
  265. GetStringValue(obj.Height)
  266. ));
  267. Write(file,
  268. String.Format("<draw:image xlink:href=\"Pictures/Pic{0}\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>",
  269. picName
  270. ));
  271. Write(file, "</draw:frame>");
  272. if (exportType == OpenOfficeFormat.Writer)
  273. WriteLine(file, "</text:p>");
  274. }
  275. private void ExportText(Stream file, ExportIEMObject obj)
  276. {
  277. Write(file, "<text:p");
  278. if (exportType == OpenOfficeFormat.Writer)
  279. Write(file,
  280. String.Format(" text:style-name=\"P{0}\"", obj.StyleIndex.ToString()));
  281. Write(file, ">");
  282. WriteLine(file,
  283. String.Format("{0}</text:p>",
  284. ExportUtils.OdtString(obj.Text, obj.TextRenderType)));
  285. }
  286. private string GetBorderLineStyle(BorderLine line, string name)
  287. {
  288. return String.Format("fo:border-{0}=\"{1}cm {2} {3}\" ",
  289. name,
  290. GetStringValue(line.Width),
  291. OdfGetFrameName(line.Style),
  292. ExportUtils.HTMLColorCode(line.Color));
  293. }
  294. private string GetStringValue(float value)
  295. {
  296. return ExportUtils.FloatToString(value / odfDivider);
  297. }
  298. private void HorizAlignStyle(Stream file, HorzAlign hAlign)
  299. {
  300. if (hAlign == HorzAlign.Left)
  301. Write(file, "fo:text-align=\"start\" ");
  302. else if (hAlign == HorzAlign.Center)
  303. Write(file, "fo:text-align=\"center\" ");
  304. else if (hAlign == HorzAlign.Right)
  305. Write(file, "fo:text-align=\"end\" ");
  306. else if (hAlign == HorzAlign.Justify)
  307. Write(file, "fo:text-align=\"justify\" ");
  308. }
  309. private void MarginStyle(Stream file, Padding padding)
  310. {
  311. if (padding.Left > 0)
  312. Write(file,
  313. String.Format("fo:margin-left=\"{0}cm\" ",
  314. GetStringValue(padding.Left)));
  315. if (padding.Right > 0)
  316. Write(file,
  317. String.Format("fo:margin-right=\"{0}cm\" ",
  318. GetStringValue(padding.Right)));
  319. if (padding.Top > 0)
  320. Write(file,
  321. String.Format("fo:margin-top=\"{0}cm\" ",
  322. GetStringValue(padding.Top)));
  323. if (padding.Bottom > 0)
  324. Write(file,
  325. String.Format("fo:margin-bottom=\"{0}cm\" ",
  326. GetStringValue(padding.Bottom)));
  327. }
  328. private void OdfAutomaticStyles(Stream file)
  329. {
  330. WriteLine(file, "<office:automatic-styles>");
  331. OdfColumnStyles(file);
  332. OdfRowStyles(file);
  333. OdfStyles(file);
  334. if (exportType == OpenOfficeFormat.Writer)
  335. {
  336. WriterStyles(file);
  337. }
  338. WriteLine(file, "<style:style style:name=\"gr1\" style:family=\"graphic\">");
  339. Write(file, "<style:graphic-properties draw:stroke=\"none\" " +
  340. "draw:fill=\"none\" draw:textarea-horizontal-align=\"left\" " +
  341. "draw:textarea-vertical-align=\"top\" draw:color-mode=\"standard\" " +
  342. "draw:luminance=\"0%\" draw:contrast=\"0%\" draw:gamma=\"100%\" " +
  343. "draw:red=\"0%\" draw:green=\"0%\" draw:blue=\"0%\" " +
  344. "fo:clip=\"rect(0cm, 0cm, 0cm, 0cm)\" draw:image-opacity=\"100%\" " +
  345. "style:mirror=\"none\"");
  346. if (extendedStyles) Write(file, " style:run-through=\"background\" style:vertical-pos=\"from-top\" " +
  347. "style:horizontal-pos=\"from-left\" style:horizontal-rel=\"paragraph\" " +
  348. "draw:wrap-influence-on-position=\"once-concurrent\" " +
  349. "style:flow-with-text=\"false\"");
  350. WriteLine(file, "/>");
  351. WriteLine(file, "</style:style>");
  352. WriteLine(file, "</office:automatic-styles>");
  353. }
  354. private void OdfColumns(Stream file)
  355. {
  356. for (int x = 1; x < matrix.Width; x++)
  357. WriteLine(file,
  358. String.Format("<table:table-column table:style-name=\"co{0}\"/>",
  359. GetStringValue((matrix.XPosById(x) - matrix.XPosById(x - 1)))
  360. ));
  361. }
  362. private void OdfColumnStyles(Stream file)
  363. {
  364. List<string> fList = new List<string>();
  365. for (int i = 1; i < matrix.Width; i++)
  366. {
  367. string s = GetStringValue((matrix.XPosById(i) - matrix.XPosById(i - 1)));
  368. if (fList.IndexOf(s) == -1)
  369. fList.Add(s);
  370. }
  371. fList.Sort();
  372. for (int i = 0; i < fList.Count; i++)
  373. {
  374. WriteLine(file,
  375. String.Format(
  376. "<style:style style:name=\"co{0}\" style:family=\"table-column\">",
  377. fList[i]
  378. ));
  379. WriteLine(file,
  380. String.Format(
  381. "<style:table-column-properties fo:break-before=\"auto\" style:column-width=\"{0}cm\"/></style:style>",
  382. fList[i]));
  383. }
  384. }
  385. private void OdfCreateManifest(ZipArchive zip, string fileName, int PicCount, string MValue)
  386. {
  387. MemoryStream file = new MemoryStream();
  388. WriteLine(file, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  389. Write(file, "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"");
  390. if (writeVersion) Write(file, $" manifest:version=\"{GetOdfVersion()}\"");
  391. WriteLine(file, ">");
  392. WriteLine(file, String.Format(" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.{0}\" manifest:full-path=\"/\"/>", MValue));
  393. WriteLine(file, " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>");
  394. WriteLine(file, " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>");
  395. if (writeRdf) WriteLine(file, " <manifest:file-entry manifest:media-type=\"application/rdf+xml\" manifest:full-path=\"manifest.rdf\"/>");
  396. WriteLine(file, " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>");
  397. for (int i = 1; i <= PicCount; i++)
  398. WriteLine(file, String.Format(" <manifest:file-entry manifest:media-type=\"image/png\" manifest:full-path=\"Pictures/Pic{0}.png\"/>", i.ToString()));
  399. WriteLine(file, "</manifest:manifest>");
  400. zip.AddStream(fileName, file);
  401. }
  402. private void OdfCreateMeta(ZipArchive zip, string fileName, string Creator)
  403. {
  404. StringBuilder sb = new StringBuilder(570);
  405. sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  406. sb.Append("<office:document-meta xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" ").
  407. Append("xmlns:xlink=\"http://www.w3.org/1999/xlink\" ").
  408. Append("xmlns:dc=\"http://purl.org/dc/elements/1.1/\" ").
  409. Append("xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"");
  410. if (writeVersion) sb.Append($" office:version=\"{GetOdfVersion()}\"");
  411. sb.AppendLine(">");
  412. sb.AppendLine(" <office:meta>");
  413. sb.Append(" <meta:generator>fast-report.com/Fast Report.NET/build:").Append(Config.Version).AppendLine("</meta:generator>");
  414. sb.Append(" <meta:initial-creator>").Append(ExportUtils.XmlString(Creator, TextRenderType.Default)).AppendLine("</meta:initial-creator>");
  415. sb.Append(" <meta:creation-date>").Append(SystemFake.DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss")).AppendLine("</meta:creation-date>");
  416. sb.AppendLine(" </office:meta>");
  417. sb.AppendLine("</office:document-meta>");
  418. MemoryStream file = new MemoryStream();
  419. Write(file, sb.ToString());
  420. zip.AddStream(fileName, file);
  421. }
  422. private void OdfCreateRDF(ZipArchive zip, string fileName)
  423. {
  424. MemoryStream file = new MemoryStream();
  425. WriteLine(file, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  426. WriteLine(file, "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">");
  427. WriteLine(file, " <rdf:Description rdf:about=\"styles.xml\">");
  428. WriteLine(file, " <rdf:type rdf:resource=\"http://docs.oasis-open.org/ns/office/1.2/meta/odf#StylesFile\"/>");
  429. WriteLine(file, " </rdf:Description>");
  430. WriteLine(file, " <rdf:Description rdf:about=\"\">");
  431. WriteLine(file, " <ns0:hasPart xmlns:ns0=\"http://docs.oasis-open.org/ns/office/1.2/meta/pkg#\" rdf:resource=\"styles.xml\"/>");
  432. WriteLine(file, " </rdf:Description>");
  433. WriteLine(file, " <rdf:Description rdf:about=\"content.xml\">");
  434. WriteLine(file, " <rdf:type rdf:resource=\"http://docs.oasis-open.org/ns/office/1.2/meta/odf#ContentFile\"/>");
  435. WriteLine(file, " </rdf:Description>");
  436. WriteLine(file, " <rdf:Description rdf:about=\"\">");
  437. WriteLine(file, " <ns0:hasPart xmlns:ns0=\"http://docs.oasis-open.org/ns/office/1.2/meta/pkg#\" rdf:resource=\"content.xml\"/>");
  438. WriteLine(file, " </rdf:Description>");
  439. WriteLine(file, " <rdf:Description rdf:about=\"\">");
  440. WriteLine(file, " <rdf:type rdf:resource=\"http://docs.oasis-open.org/ns/office/1.2/meta/pkg#Document\"/>");
  441. WriteLine(file, " </rdf:Description>");
  442. WriteLine(file, "</rdf:RDF>");
  443. zip.AddStream(fileName, file);
  444. }
  445. private void OdfCreateMime(ZipArchive zip, string fileName, string MValue)
  446. {
  447. MemoryStream file = new MemoryStream();
  448. Write(file, String.Concat("application/vnd.oasis.opendocument.", MValue));
  449. zip.AddStream(fileName, file);
  450. }
  451. private void OdfFontFaceDecals(Stream file)
  452. {
  453. List<string> fList = new List<string>();
  454. for (int i = 0; i < matrix.StylesCount; i++)
  455. {
  456. ExportIEMStyle style = matrix.StyleById(i);
  457. if ((style.Font != null) && (fList.IndexOf(style.Font.Name) == -1))
  458. fList.Add(style.Font.Name);
  459. }
  460. WriteLine(file, "<office:font-face-decls>");
  461. fList.Sort();
  462. for (int i = 0; i < fList.Count; i++)
  463. {
  464. WriteLine(file,
  465. String.Format(
  466. "<style:font-face style:name=\"{0}\" svg:font-family=\"&apos;{0}&apos;\" style:font-pitch=\"variable\"/>",
  467. fList[i]
  468. ));
  469. }
  470. WriteLine(file, "</office:font-face-decls>");
  471. }
  472. private string OdfGetFrameName(LineStyle style)
  473. {
  474. switch (style)
  475. {
  476. case LineStyle.Dash:
  477. case LineStyle.DashDot:
  478. case LineStyle.DashDotDot:
  479. case LineStyle.Dot:
  480. return "solid";
  481. case LineStyle.Double:
  482. return "double";
  483. default:
  484. return "solid";
  485. }
  486. }
  487. private void OdfMakeDocStyles(ZipArchive zip, string fileName)
  488. {
  489. MemoryStream file = new MemoryStream();
  490. WriteLine(file, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  491. Write(file, "<office:document-styles ");
  492. Write(file, OdfMakeXmlHeader());
  493. if (writeVersion) Write(file, $" office:version=\"{GetOdfVersion()}\"");
  494. WriteLine(file, ">");
  495. WriteLine(file, "<office:automatic-styles>");
  496. WriteLine(file, "<style:page-layout style:name=\"pm1\">");
  497. WriteLine(file,
  498. String.Format("<style:page-layout-properties fo:page-width=\"{0}cm\" fo:page-height=\"{1}cm\" fo:margin-top=\"{2}cm\" fo:margin-bottom=\"{3}cm\" fo:margin-left=\"{4}cm\" fo:margin-right=\"{5}cm\"/>",
  499. ExportUtils.FloatToString(pageWidth / odfPageDiv),
  500. ExportUtils.FloatToString(pageHeight / odfPageDiv),
  501. ExportUtils.FloatToString(pageTop / odfMargDiv),
  502. ExportUtils.FloatToString(pageBottom / odfMargDiv),
  503. ExportUtils.FloatToString(pageLeft / odfMargDiv),
  504. ExportUtils.FloatToString(pageRight / odfMargDiv)
  505. ));
  506. WriteLine(file, "</style:page-layout>");
  507. WriteLine(file, "</office:automatic-styles>");
  508. WriteLine(file, "<office:master-styles>");
  509. WriteLine(file, "<style:master-page style:name=\"PageDef\" style:page-layout-name=\"pm1\">");
  510. WriteLine(file, "</style:master-page>");
  511. WriteLine(file, "</office:master-styles>");
  512. WriteLine(file, "</office:document-styles>");
  513. zip.AddStream(fileName, file);
  514. }
  515. private string OdfMakeXmlHeader()
  516. {
  517. return " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
  518. " xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"" +
  519. " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" +
  520. " xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" +
  521. " xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"" +
  522. " xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"" +
  523. " xmlns:xlink=\"http://www.w3.org/1999/xlink\"" +
  524. " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" +
  525. " xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"" +
  526. " xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"" +
  527. " xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"" +
  528. " xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"" +
  529. " xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"" +
  530. " xmlns:math=\"http://www.w3.org/1998/Math/MathML\"" +
  531. " xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"" +
  532. " xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"" +
  533. " xmlns:dom=\"http://www.w3.org/2001/xml-events\"" +
  534. " xmlns:xforms=\"http://www.w3.org/2002/xforms\"" +
  535. " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
  536. " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
  537. }
  538. private int OdfRows(Stream file, ZipArchive zip)
  539. {
  540. int picCount = 0;
  541. int page = 0;
  542. for (int y = 0; y < matrix.Height - 1; y++)
  543. {
  544. string pageB = String.Empty;
  545. if ((pageBreaks) && (matrix.YPosById(y) >= matrix.PageBreak(page)))
  546. {
  547. page++;
  548. pageB = "pb";
  549. TableEnd(file);
  550. TableBegin(file, page + 1);
  551. }
  552. WriteLine(file,
  553. String.Format("<table:table-row table:style-name=\"ro{0}{1}\">",
  554. GetStringValue((matrix.YPosById(y + 1) - matrix.YPosById(y))),
  555. pageB));
  556. for (int x = 0; x < matrix.Width - 1; x++)
  557. {
  558. int i = matrix.Cell(x, y);
  559. if (i != -1)
  560. {
  561. ExportIEMObject obj = matrix.ObjectById(i);
  562. if (obj.Counter == 0)
  563. {
  564. obj.Counter = 1;
  565. int fx, fy, dx, dy;
  566. matrix.ObjectPos(i, out fx, out fy, out dx, out dy);
  567. ExportCell(file, zip, obj, dx, dy, ref picCount);
  568. }
  569. else
  570. {
  571. Write(file, "<table:covered-table-cell/>");
  572. }
  573. }
  574. else
  575. {
  576. Write(file, "<table:table-cell");
  577. if (exportType == OpenOfficeFormat.Writer)
  578. WriteLine(file, "><text:p text:style-name=\"PB\"/></table:table-cell>");
  579. else
  580. WriteLine(file, "/>");
  581. }
  582. }
  583. WriteLine(file, "</table:table-row>");
  584. }
  585. return picCount;
  586. }
  587. private void OdfRowStyles(Stream file)
  588. {
  589. List<KeyValuePair<float, bool>> positions = new List<KeyValuePair<float, bool>>();
  590. int page = 0;
  591. for (int i = 0; i < matrix.Height - 1; i++)
  592. {
  593. bool breakValue = false;
  594. if ((pageBreaks) && (matrix.YPosById(i) >= matrix.PageBreak(page)))
  595. {
  596. page++;
  597. breakValue = true;
  598. }
  599. KeyValuePair<float, bool> value =
  600. new KeyValuePair<float, bool>(matrix.YPosById(i + 1) - matrix.YPosById(i), breakValue);
  601. if (positions.IndexOf(value) == -1)
  602. {
  603. positions.Add(value);
  604. }
  605. }
  606. for (int i = 0; i < positions.Count; i++)
  607. {
  608. string rowPos = GetStringValue(positions[i].Key);
  609. string pageB = positions[i].Value ? "pb" : String.Empty;
  610. WriteLine(file,
  611. String.Format(
  612. "<style:style style:name=\"ro{0}{1}\" style:family=\"table-row\">",
  613. rowPos,
  614. pageB));
  615. string pageAuto = positions[i].Value ? "page" : "auto";
  616. WriteLine(file,
  617. String.Format(
  618. "<style:table-row-properties fo:break-before=\"{0}\" style:row-height=\"{1}cm\"/>",
  619. pageAuto,
  620. rowPos));
  621. WriteLine(file, "</style:style>");
  622. }
  623. WriteLine(file, "<style:style style:name=\"ta1\" style:family=\"table\" style:master-page-name=\"PageDef\">");
  624. WriteLine(file, "<style:table-properties table:display=\"true\" style:writing-mode=\"lr-tb\"/>");
  625. WriteLine(file, "</style:style>");
  626. WriteLine(file, "<style:style style:name=\"ceb\" style:family=\"table-cell\" />");
  627. }
  628. private void OdfStyles(Stream file)
  629. {
  630. for (int i = 0; i < matrix.StylesCount; i++)
  631. {
  632. ExportIEMStyle style = matrix.StyleById(i);
  633. WriteLine(file,
  634. String.Format("<style:style style:name=\"ce{0}\" style:family=\"table-cell\" >",
  635. i.ToString()));
  636. OdfTableCellStyles(file, style);
  637. if (exportType == OpenOfficeFormat.Spreadsheet)
  638. {
  639. ParagraphStyle(file, style);
  640. TextPropertiesStyle(file, style);
  641. }
  642. WriteLine(file, "</style:style>");
  643. }
  644. }
  645. private void OdfTableCellStyles(Stream file, ExportIEMStyle style)
  646. {
  647. Write(file,
  648. String.Format("<style:table-cell-properties fo:background-color=\"{0}\" style:repeat-content=\"false\" fo:wrap-option=\"wrap\" ",
  649. ExportUtils.HTMLColorCode(style.FillColor)));
  650. if (style.Angle > 0)
  651. {
  652. Write(file,
  653. String.Format("style:rotation-angle=\"{0}\" style:rotation-align=\"none\" ",
  654. (360 - style.Angle).ToString()));
  655. }
  656. if (style.VAlign == VertAlign.Center)
  657. Write(file, "style:vertical-align=\"middle\" ");
  658. if (style.VAlign == VertAlign.Top)
  659. Write(file, "style:vertical-align=\"top\" ");
  660. if (style.VAlign == VertAlign.Bottom)
  661. Write(file, "style:vertical-align=\"bottom\" ");
  662. if ((style.Border.Lines & BorderLines.Left) > 0)
  663. Write(file, GetBorderLineStyle(style.Border.LeftLine, "left"));
  664. if ((style.Border.Lines & BorderLines.Right) > 0)
  665. Write(file, GetBorderLineStyle(style.Border.RightLine, "right"));
  666. if ((style.Border.Lines & BorderLines.Top) > 0)
  667. Write(file, GetBorderLineStyle(style.Border.TopLine, "top"));
  668. if ((style.Border.Lines & BorderLines.Bottom) > 0)
  669. Write(file, GetBorderLineStyle(style.Border.BottomLine, "bottom"));
  670. Write(file, "/>");
  671. }
  672. private void ParagraphStyle(Stream file, ExportIEMStyle style)
  673. {
  674. Write(file, "<style:paragraph-properties ");
  675. HorizAlignStyle(file, style.HAlign);
  676. MarginStyle(file, style.Padding);
  677. WriteLine(file, "/>");
  678. }
  679. private void TableBegin(Stream file, int tableNumber)
  680. {
  681. // table
  682. WriteLine(file,
  683. String.Format("<table:table table:name=\"Table{0}\" table:style-name=\"ta1\" table:print=\"false\">", tableNumber));
  684. // columns
  685. OdfColumns(file);
  686. }
  687. private void TableEnd(Stream file)
  688. {
  689. WriteLine(file, "</table:table>");
  690. }
  691. private void TextPropertiesStyle(Stream file, ExportIEMStyle style)
  692. {
  693. Write(file,
  694. String.Format("<style:text-properties style:font-name=\"{0}\" fo:font-size=\"{1}pt\" ",
  695. style.Font.Name, ExportUtils.FloatToString(style.Font.Size)));
  696. if (localization != null && exportLocale)
  697. {
  698. if (localization.Name.Contains("-"))
  699. Write(file, $" fo:language=\"{localization.Name.Split('-')[0]}\" fo:country=\"{localization.Name.Split('-')[1]}\" ");
  700. else
  701. Write(file, $" fo:language=\"{localization.Name}\" ");
  702. }
  703. else if (localization == null && exportLocale)
  704. {
  705. string lcale = CultureInfo.GetCultureInfoByIetfLanguageTag(Res.LocaleName.Substring(0, 2)).Name;
  706. if (lcale.Contains("-"))
  707. Write(file, $" fo:language=\"{lcale.Split('-')[0]}\" fo:country=\"{lcale.Split('-')[1]}\" ");
  708. else
  709. Write(file, $" fo:language=\"{lcale}\" ");
  710. }
  711. if ((style.Font.Style & FontStyle.Underline) > 0)
  712. Write(file, " style:text-underline-style=\"solid\" " +
  713. "style:text-underline-width=\"auto\" " +
  714. "style:text-underline-color=\"font-color\" ");
  715. if ((style.Font.Style & FontStyle.Italic) > 0)
  716. Write(file, " style:font-style=\"italic\" ");
  717. if ((style.Font.Style & FontStyle.Bold) > 0)
  718. Write(file,
  719. " fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"");
  720. WriteLine(file, String.Format(" fo:color=\"{0}\"/>",
  721. ExportUtils.HTMLColorCode(style.TextColor)));
  722. }
  723. private void Write(Stream stream, string value)
  724. {
  725. byte[] buf = Encoding.UTF8.GetBytes(value);
  726. stream.Write(buf, 0, buf.Length);
  727. }
  728. private void WriteLine(Stream stream, string value)
  729. {
  730. byte[] buf = Encoding.UTF8.GetBytes(value);
  731. stream.Write(buf, 0, buf.Length);
  732. stream.WriteByte(13);
  733. stream.WriteByte(10);
  734. }
  735. private void WriterStyles(Stream file)
  736. {
  737. for (int i = 0; i < matrix.StylesCount; i++)
  738. {
  739. ExportIEMStyle style = matrix.StyleById(i);
  740. WriteLine(file,
  741. String.Format("<style:style style:name=\"P{0}\" style:family=\"paragraph\" >",
  742. i.ToString()));
  743. ParagraphStyle(file, style);
  744. TextPropertiesStyle(file, style);
  745. WriteLine(file, "</style:style>");
  746. }
  747. }
  748. #endregion Private Methods
  749. #region Protected Methods
  750. /// <inheritdoc/>
  751. protected override void ExportBand(BandBase band)
  752. {
  753. base.ExportBand(band);
  754. matrix.AddBand(band, this);
  755. }
  756. /// <inheritdoc/>
  757. protected override void ExportPageBegin(ReportPage page)
  758. {
  759. base.ExportPageBegin(page);
  760. matrix.AddPageBegin(page);
  761. }
  762. /// <inheritdoc/>
  763. protected override void ExportPageEnd(ReportPage page)
  764. {
  765. matrix.AddPageEnd(page);
  766. if (firstPage)
  767. {
  768. pageBottom = page.BottomMargin;
  769. pageLeft = page.LeftMargin;
  770. pageRight = page.RightMargin;
  771. pageTop = page.TopMargin;
  772. pageWidth = ExportUtils.GetPageWidth(page);
  773. pageHeight = ExportUtils.GetPageHeight(page);
  774. pageLandscape = page.Landscape;
  775. firstPage = false;
  776. }
  777. }
  778. /// <inheritdoc/>
  779. protected override void Finish()
  780. {
  781. matrix.Prepare();
  782. ExportODF(Stream);
  783. }
  784. /// <inheritdoc/>
  785. protected override void Start()
  786. {
  787. base.Start();
  788. matrix = new ExportMatrix();
  789. if (wysiwyg)
  790. matrix.Inaccuracy = 0.5f;
  791. else
  792. matrix.Inaccuracy = 10;
  793. matrix.RotatedAsImage = true;
  794. matrix.PlainRich = true;
  795. matrix.AreaFill = true;
  796. matrix.Report = Report;
  797. matrix.MaxCellHeight = 400;
  798. matrix.Images = true;
  799. matrix.ImageFormat = ImageFormat.Png;
  800. matrix.ShowProgress = ShowProgress;
  801. firstPage = true;
  802. }
  803. #endregion Protected Methods
  804. #region Public Constructors
  805. /// <summary>
  806. /// Initializes a new instance of the <see cref="ODFExport"/> class.
  807. /// </summary>
  808. public ODFExport()
  809. {
  810. exportType = OpenOfficeFormat.Spreadsheet;
  811. ExportLocale = false;
  812. pageBreaks = true;
  813. wysiwyg = true;
  814. creator = "FastReport .NET";
  815. }
  816. #endregion Public Constructors
  817. #region Public Methods
  818. /// <inheritdoc/>
  819. public override void Serialize(FRWriter writer)
  820. {
  821. base.Serialize(writer);
  822. writer.WriteBool("Wysiwyg", Wysiwyg);
  823. writer.WriteBool("PageBreaks", PageBreaks);
  824. writer.WriteBool("ExportLocale", ExportLocale);
  825. writer.WriteValue("Locale", Locale);
  826. }
  827. #endregion Public Methods
  828. }
  829. /// <summary>
  830. /// Open Document Spreadsheet export (Open Office Calc).
  831. /// </summary>
  832. public class ODSExport : ODFExport
  833. {
  834. #region Public Constructors
  835. /// <summary>
  836. /// Initializes a new instance of the <see cref="ODSExport"/> class.
  837. /// </summary>
  838. public ODSExport()
  839. {
  840. ExportType = OpenOfficeFormat.Spreadsheet;
  841. }
  842. #endregion Public Constructors
  843. #region Protected Methods
  844. /// <inheritdoc/>
  845. protected override string GetFileFilter()
  846. {
  847. if (IsXOTD)
  848. return new MyRes("FileFilters").Get("XodsFile");
  849. return new MyRes("FileFilters").Get("OdsFile");
  850. }
  851. #endregion Protected Methods
  852. }
  853. /// <summary>
  854. /// Open Document Text export (Open Office Writer).
  855. /// </summary>
  856. public class ODTExport : ODFExport
  857. {
  858. #region Public Constructors
  859. /// <summary>
  860. /// Initializes a new instance of the <see cref="ODTExport"/> class.
  861. /// </summary>
  862. public ODTExport()
  863. {
  864. ExportType = OpenOfficeFormat.Writer;
  865. }
  866. #endregion Public Constructors
  867. #region Protected Methods
  868. /// <inheritdoc/>
  869. protected override string GetFileFilter()
  870. {
  871. if (IsXOTD)
  872. return new MyRes("FileFilters").Get("XodtFile");
  873. return new MyRes("FileFilters").Get("OdtFile");
  874. }
  875. #endregion Protected Methods
  876. }
  877. }