PDFExportAnnotation.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Drawing;
  5. using System.IO;
  6. using FastReport.Utils;
  7. using FastReport.Export;
  8. using FastReport.Preview;
  9. using FastReport.Export.TTF;
  10. using System.Text.RegularExpressions;
  11. namespace FastReport.Export.Pdf
  12. {
  13. internal class PDFExportAnnotation
  14. {
  15. public long reference;
  16. public string rect;
  17. public string hyperlink;
  18. public int destPage;
  19. public int destY;
  20. }
  21. public partial class PDFExport : ExportBase
  22. {
  23. private List<PDFExportAnnotation> annots;
  24. private StringBuilder pageAnnots;
  25. private string GetPageAnnots()
  26. {
  27. return "/Annots [ " + pageAnnots.ToString() + "]";
  28. }
  29. private void WriteAnnots()
  30. {
  31. foreach (PDFExportAnnotation annot in annots)
  32. {
  33. xRef[(int)annot.reference - 1] = pdf.Position;
  34. WriteLn(pdf, ObjNumber(annot.reference));
  35. WriteLn(pdf, "<<");
  36. WriteLn(pdf, "/Type /Annot");
  37. WriteLn(pdf, "/Subtype /Link");
  38. if (isPdfA())
  39. WriteLn(pdf, "/F 4");
  40. WriteLn(pdf, "/Rect [" + annot.rect + "]");
  41. if (!isPdfX() && !String.IsNullOrEmpty(annot.hyperlink))
  42. {
  43. WriteLn(pdf, "/BS << /W 0 >>");
  44. WriteLn(pdf, "/A <<");
  45. WriteLn(pdf, "/URI (" + annot.hyperlink + ")");
  46. WriteLn(pdf, "/Type /Action");
  47. WriteLn(pdf, "/S /URI");
  48. WriteLn(pdf, ">>");
  49. }
  50. else
  51. {
  52. WriteLn(pdf, "/Border [16 16 0]");
  53. if (annot.destPage < pagesRef.Count)
  54. {
  55. WriteLn(pdf, "/Dest [" + pagesRef[annot.destPage].ToString() +
  56. " 0 R /XYZ null " + ((int)(pagesHeights[annot.destPage] - annot.destY)).ToString() + " null]");
  57. }
  58. }
  59. WriteLn(pdf, ">>");
  60. WriteLn(pdf, "endobj");
  61. }
  62. }
  63. private void AddAnnot(ReportComponentBase obj)
  64. {
  65. if (obj is TextObject textObject && Regex.IsMatch(textObject.Text, @"\bhttps?://\S+"))
  66. obj.Hyperlink.Value = Regex.Replace(textObject.Text, "<.*?>", string.Empty);
  67. if ((obj.Hyperlink.Kind == HyperlinkKind.Bookmark ||
  68. obj.Hyperlink.Kind == HyperlinkKind.PageNumber ||
  69. obj.Hyperlink.Kind == HyperlinkKind.URL) && !String.IsNullOrEmpty(obj.Hyperlink.Value))
  70. {
  71. string Left = FloatToString(GetLeft(obj.AbsLeft));
  72. string Top = FloatToString(GetTop(obj.AbsTop));
  73. string Right = FloatToString(GetLeft(obj.AbsLeft + obj.Width));
  74. string Bottom = FloatToString(GetTop(obj.AbsTop + obj.Height));
  75. string rect = Left + " " + Bottom + " " + Right + " " + Top;
  76. long reference = UpdateXRef();
  77. pageAnnots.Append(ObjNumberRef(reference)).Append(" ");
  78. PDFExportAnnotation annot = new PDFExportAnnotation();
  79. annot.reference = reference;
  80. annot.rect = rect;
  81. annots.Add(annot);
  82. switch (obj.Hyperlink.Kind)
  83. {
  84. case HyperlinkKind.URL:
  85. try
  86. {
  87. Uri uri = new Uri(obj.Hyperlink.Value);
  88. annot.hyperlink = uri.AbsoluteUri;
  89. }
  90. catch (Exception)
  91. { }
  92. //annot.hyperlink = obj.Hyperlink.Value.Replace("\\", "\\\\");
  93. break;
  94. case HyperlinkKind.Bookmark:
  95. Bookmarks.BookmarkItem bookmark = Report.PreparedPages.Bookmarks.Find(obj.Hyperlink.Value);
  96. if (bookmark != null)
  97. {
  98. annot.destPage = bookmark.pageNo;
  99. annot.destY = (int)(bookmark.offsetY * PDF_DIVIDER);
  100. }
  101. break;
  102. case HyperlinkKind.PageNumber:
  103. annot.destPage = int.Parse(obj.Hyperlink.Value) - 1;
  104. annot.destY = 0;
  105. break;
  106. }
  107. }
  108. }
  109. private void AddTextField(TextObject obj, long defaultValueXref)
  110. {
  111. StringBuilder sb = new StringBuilder();
  112. string Left = FloatToString(GetLeft(obj.AbsLeft + obj.Padding.Left));
  113. string Top = FloatToString(GetTop(obj.AbsTop + obj.Padding.Top));
  114. string Right = FloatToString(GetLeft(obj.AbsLeft + obj.Width - obj.Padding.Right));
  115. string Bottom = FloatToString(GetTop(obj.AbsTop + obj.Height - obj.Padding.Bottom));
  116. int ObjectFontNumber = GetObjFontNumberAcroForm(obj.Font);
  117. ExportTTFFont pdffont = fonts[ObjectFontNumber];
  118. pdffont.Editable = true;
  119. AppendFontAcroForm(sb, ObjectFontNumber, obj.Font.Size, obj.TextColor);
  120. if (!acroFormsFonts.Contains(ObjectFontNumber))
  121. acroFormsFonts.Add(ObjectFontNumber);
  122. long xref = UpdateXRef();
  123. //FAcroFormsAnnotsRefs.Add(xref);
  124. acroFormsRefs.Add(xref);
  125. pageAnnots.Append(ObjNumberRef(xref)).Append(" ");
  126. WriteLn(pdf, ObjNumber(xref));
  127. WriteLn(pdf, "<<");
  128. WriteLn(pdf, "/Type /Annot /Subtype /Widget /F 4");
  129. Write(pdf, "/FT /Tx " + (obj.VertAlign != VertAlign.Center ? "/Ff 4096 " : "") + "/H /N ");// /MK << >> ");
  130. if (defaultValueXref >= 0)
  131. {
  132. Write(pdf, "/AP << /N " + ObjNumberRef(defaultValueXref) + " >>");
  133. }
  134. StringBuilder text = new StringBuilder(obj.Text.Length);
  135. StrToUTF16(obj.Text, text);
  136. string align = "0";
  137. if (obj.HorzAlign == HorzAlign.Center) align = "1";
  138. else if (obj.HorzAlign == HorzAlign.Right) align = "2";
  139. Write(pdf, " /DA ( " + sb.ToString() + " ) /Q " + align + " /Rect [ " + Left + " " + Bottom + " " + Right + " " + Top + " ] /T (" + obj.Name + acroFormsRefs.Count + ") /V <" + text.ToString() + "> ");
  140. WriteLn(pdf, ">>");
  141. WriteLn(pdf, "endobj");
  142. //<< /AP << /N 10 0 R >> /DA (/Helv 8.64 Tf 0 g) /F 4 /FT /Tx /MK << >> /P 8 0 R /Q 0 /Rect [ 123.12 691.2 284.4 726.48 ] /Subtype /Widget /T (untitled1) >>
  143. }
  144. private void AddCheckBoxField(CheckBoxObject obj)
  145. {
  146. bool chk = obj.Checked;
  147. string Left = FloatToString(GetLeft(obj.AbsLeft));
  148. string Top = FloatToString(GetTop(obj.AbsTop));
  149. string Right = FloatToString(GetLeft(obj.AbsLeft + obj.Width));
  150. string Bottom = FloatToString(GetTop(obj.AbsTop + obj.Height));
  151. obj.Checked = true;
  152. long yesXRef1 = AddCheckBox(obj);
  153. obj.Checked = false;
  154. long offXRef1 = AddCheckBox(obj);
  155. obj.Checked = chk;
  156. //ExportTTFFont font;
  157. ////TODO font kludge
  158. //if (FFonts.Count == 0)
  159. //{
  160. // font = GetGlobalFont(new Font(FontFamily.GenericSansSerif, 12));
  161. // font.Reference = UpdateXRef();
  162. // font.Saved = true;
  163. //}
  164. //else
  165. // font = FFonts[0];
  166. long xref = UpdateXRef();
  167. //FAcroFormsAnnotsRefs.Add(xref);
  168. acroFormsRefs.Add(xref);
  169. pageAnnots.Append(ObjNumberRef(xref)).Append(" ");
  170. WriteLn(pdf, ObjNumber(xref));
  171. WriteLn(pdf, "<<");
  172. WriteLn(pdf, "/Type /Annot /Subtype /Widget /F 4");
  173. WriteLn(pdf, "/AP << /N << /Off " + ObjNumberRef(offXRef1) + " /Yes " + ObjNumberRef(yesXRef1) + " >>" /*+" /D << /Off " + ObjNumberRef(offXRef1) + " /Yes " + ObjNumberRef(yesXRef2) + " >>"*/ + " >> ");
  174. Write(pdf, "/FT /Btn /H /N ");// /DA (" + font.Name + " " + FloatToString(12) + " Tf 0 g)");
  175. Write(pdf, " " + (chk ? "/AS /Yes" : "/AS /Off") + " /Rect [ " + Left + " " + Bottom + " " + Right + " " + Top + " ] /T (" + obj.Name + acroFormsRefs.Count + ") " + (chk ? "/V /Yes" : "/V /Off"));
  176. WriteLn(pdf, ">>");
  177. WriteLn(pdf, "endobj");
  178. // /F 4 /FT /Btn /H /P /MK << /CA (4) >> >>
  179. }
  180. const string mark = "\u2714";
  181. private long AddCheckBox(CheckBoxObject obj)
  182. {
  183. StringBuilder sb_in = new StringBuilder();
  184. long imageIndex = AddPictureObject(obj, true, jpegQuality, sb_in, true);
  185. string Width = FloatToString(obj.Width * PDF_DIVIDER);
  186. string Height = FloatToString(obj.Height * PDF_DIVIDER);
  187. long xref = UpdateXRef();
  188. WriteLn(pdf, ObjNumber(xref));
  189. WriteLn(pdf, "<< /BBox [ 0 0 " + Width + " " + Height + " ] /Resources << /XObject << " + (imageIndex < 0 ? "" : "/Im" + imageIndex + " " + ObjNumberRef(imageIndex)) + " >> /ProcSet [ /PDF /Text /ImageC /ImageI /ImageB ] >> /Subtype /Form /Type /XObject ");
  190. using (MemoryStream ms = new MemoryStream(ExportUtils.StringToByteArray(sb_in.ToString())))
  191. WritePDFStream(pdf, ms, 0, false, false, false, true);
  192. //<< /BBox [ 0 0 163.44002 101.51996 ] /Resources << /Font << /Verdana,Bold 6 0 R >> /ProcSet [ /PDF /Text ] >> /Subtype /Form /Type /XObject /Length 98 >>
  193. return xref;
  194. }
  195. private long AddTextDefaultValueForEditable(TextObject obj)
  196. {
  197. if (!String.IsNullOrEmpty(obj.Text))
  198. {
  199. //TODO for forms
  200. if (obj.VertAlign != VertAlign.Center)
  201. obj.VertAlign = VertAlign.Top;
  202. obj.Angle = 0;
  203. string Width = FloatToString(obj.Width * PDF_DIVIDER);
  204. string Height = FloatToString(obj.Height * PDF_DIVIDER);
  205. StringBuilder sb = new StringBuilder();
  206. int ObjectFontNumber = GetObjFontNumber(obj.Font);
  207. RectangleF textRect = new RectangleF(
  208. 0,
  209. 0,
  210. obj.Width - obj.Padding.Horizontal,
  211. obj.Height - obj.Padding.Vertical);
  212. if (!pageFonts[ObjectFontNumber].Saved)
  213. {
  214. pageFonts[ObjectFontNumber].Reference = UpdateXRef();
  215. pageFonts[ObjectFontNumber].Saved = true;
  216. }
  217. sb.AppendLine("/Tx BMC");
  218. if (!obj.HasHtmlTags)
  219. AppendFont(sb, ObjectFontNumber, obj.Font.Size, obj.TextColor);
  220. AddTextObjectInternal(obj, textRect, false, sb, true);
  221. sb.AppendLine("EMC");
  222. long xref = UpdateXRef();
  223. WriteLn(pdf, ObjNumber(xref));
  224. int fontnumber = GetObjFontNumberAcroForm(obj.Font);
  225. ExportTTFFont font = fonts[fontnumber];
  226. //todo make BBOX without fill page
  227. WriteLn(pdf, "<< /BBox [ 0 0 " + Width + " " + Height + " ] /Resources << /Font << " + font.Name + " " + ObjNumberRef(font.Reference) + " >> /ProcSet [ /PDF /Text ] >> /Subtype /Form /Type /XObject ");
  228. using (MemoryStream ms = new MemoryStream(ExportUtils.StringToByteArray(sb.ToString())))
  229. WritePDFStream(pdf, ms, 0, false, false, false, true);
  230. //<< /BBox [ 0 0 163.44002 101.51996 ] /Resources << /Font << /Verdana,Bold 6 0 R >> /ProcSet [ /PDF /Text ] >> /Subtype /Form /Type /XObject /Length 98 >>
  231. return xref;
  232. }
  233. return -1;
  234. }
  235. private long AddAcroForm()
  236. {
  237. if (acroFormsRefs.Count > 0)
  238. {
  239. long acroForm = UpdateXRef();
  240. WriteLn(pdf, ObjNumber(acroForm));
  241. Write(pdf, "<< /SigFlags 3 /DR << /Font <<");
  242. foreach (int fontnumber in acroFormsFonts)
  243. {
  244. ExportTTFFont font = fonts[fontnumber];
  245. Write(pdf, font.Name + " " + ObjNumberRef(font.Reference) + " ");
  246. }
  247. Write(pdf, ">> >> /Fields [ ");
  248. foreach (long val in acroFormsRefs)
  249. {
  250. Write(pdf, ObjNumberRef(val));
  251. Write(pdf, " ");
  252. }
  253. WriteLn(pdf, "] >>");
  254. WriteLn(pdf, "endobj");
  255. //<< /DR << /Font << /Verdana,Bold 6 0 R >> >> << /Font << /Helv 6 0 R >> >> /Fields [ 7 0 R ] >>
  256. return acroForm;
  257. }
  258. return -1;
  259. }
  260. }
  261. }