PDFExportUtils.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. using FastReport.Utils;
  2. using System;
  3. using System.Drawing;
  4. using System.IO;
  5. using System.Text;
  6. namespace FastReport.Export.Pdf
  7. {
  8. public partial class PDFExport : ExportBase
  9. {
  10. private float GetTop(float p)
  11. {
  12. return marginWoBottom - p * PDF_DIVIDER;
  13. }
  14. private float GetLeft(float p)
  15. {
  16. return marginLeft + p * PDF_DIVIDER;
  17. }
  18. private string FloatToString(double value)
  19. {
  20. return ExportUtils.FloatToString(value);
  21. }
  22. private string FloatToStringSmart(double value)
  23. {
  24. if (value > 1 || value < -1)
  25. return FloatToString(value);
  26. if (value > 0)
  27. {
  28. double testValue = value;
  29. int i;
  30. for (i = 0; i < 6; i++)
  31. if ((testValue *= 10) > 1)
  32. break;
  33. // prevent exponential format for near zero values
  34. if (testValue < 1)
  35. i = 0;
  36. return FloatToString(value, i + 2);
  37. }
  38. if (value < 0)
  39. {
  40. double testValue = -value;
  41. int i;
  42. for (i = 0; i < 6; i++)
  43. if ((testValue *= 10) > 1)
  44. break;
  45. // prevent exponential format for near zero values
  46. if (testValue < 1)
  47. i = 0;
  48. return FloatToString(value, i + 2);
  49. }
  50. return "0";
  51. }
  52. private string FloatToString(double value, int digits)
  53. {
  54. return ExportUtils.FloatToString(value, digits);
  55. }
  56. private string StringToPdfUnicode(string s)
  57. {
  58. StringBuilder sb = new StringBuilder(s.Length * 2 + 2);
  59. sb.Append((char)254).Append((char)255);
  60. foreach (char c in s)
  61. sb.Append((char)(c >> 8)).Append((char)(c & 0xFF));
  62. return sb.ToString();
  63. }
  64. private void PrepareString(string text, byte[] key, bool encode, long id, StringBuilder sb)
  65. {
  66. string s = encode ? RC4CryptString(StringToPdfUnicode(text), key, id) : StringToPdfUnicode(text);
  67. if (PdfCompliance == PdfStandard.PdfA_1a)
  68. {
  69. s = encode ? RC4CryptString(text, key, id) : text;
  70. }
  71. sb.Append("(");
  72. EscapeSpecialChar(s, sb);
  73. sb.Append(")");
  74. }
  75. private void Write(Stream stream, string value)
  76. {
  77. stream.Write(ExportUtils.StringToByteArray(value), 0, value.Length);
  78. }
  79. private void WriteLn(Stream stream, string value)
  80. {
  81. stream.Write(ExportUtils.StringToByteArray(value), 0, value.Length);
  82. stream.WriteByte(0x0d);
  83. stream.WriteByte(0x0a);
  84. }
  85. private void StrToUTF16(string str, StringBuilder sb)
  86. {
  87. if (!string.IsNullOrEmpty(str))
  88. {
  89. sb.Append("FEFF");
  90. foreach (char c in str)
  91. sb.Append(((int)c).ToString("X4"));
  92. }
  93. }
  94. private void EscapeSpecialChar(string input, StringBuilder sb)
  95. {
  96. for (int i = 0; i < input.Length; i++)
  97. {
  98. switch (input[i])
  99. {
  100. case '(':
  101. sb.Append(@"\(");
  102. break;
  103. case ')':
  104. sb.Append(@"\)");
  105. break;
  106. case '\\':
  107. sb.Append(@"\\");
  108. break;
  109. case '\r':
  110. sb.Append(@"\r");
  111. break;
  112. case '\n':
  113. sb.Append(@"\n");
  114. break;
  115. default:
  116. sb.Append(input[i]);
  117. break;
  118. }
  119. }
  120. }
  121. private float GetBaseline(Font f)
  122. {
  123. float baselineOffset = f.SizeInPoints / f.FontFamily.GetEmHeight(f.Style) * f.FontFamily.GetCellAscent(f.Style);
  124. return DrawUtils.ScreenDpi / 72f * baselineOffset;
  125. }
  126. private void GetPDFFillColor(Color color, StringBuilder sb)
  127. {
  128. GetPDFFillTransparent(color, sb);
  129. if (ColorSpace == PdfColorSpace.CMYK)
  130. {
  131. GetCMYKColor(color, sb);
  132. sb.AppendLine(" k");
  133. }
  134. else if (ColorSpace == PdfColorSpace.RGB)
  135. {
  136. GetPDFColor(color, sb);
  137. sb.AppendLine(" rg");
  138. }
  139. }
  140. private void GetPDFFillTransparent(Color color, StringBuilder sb)
  141. {
  142. string value = FloatToString((float)color.A / 255f);
  143. int i = trasparentStroke.IndexOf(value);
  144. if (i == -1)
  145. {
  146. trasparentStroke.Add(value);
  147. i = trasparentStroke.Count - 1;
  148. }
  149. sb.Append("/GS").Append(i).AppendLine("S gs");
  150. }
  151. private void GetPDFStrokeColor(Color color, StringBuilder sb)
  152. {
  153. GetPDFStrokeTransparent(color, sb);
  154. if (ColorSpace == PdfColorSpace.CMYK)
  155. {
  156. GetCMYKColor(color, sb);
  157. sb.AppendLine(" K");
  158. }
  159. else if (ColorSpace == PdfColorSpace.RGB)
  160. {
  161. GetPDFColor(color, sb);
  162. sb.AppendLine(" RG");
  163. }
  164. }
  165. private void GetPDFStrokeTransparent(Color color, StringBuilder sb)
  166. {
  167. string value = FloatToString((float)color.A / 255f);
  168. if (PdfCompliance == PdfStandard.PdfA_1a)
  169. {
  170. value = "1";
  171. }
  172. int i = trasparentFill.IndexOf(value);
  173. if (i == -1)
  174. {
  175. trasparentFill.Add(value);
  176. i = trasparentFill.Count - 1;
  177. }
  178. sb.Append("/GS").Append(i).AppendLine("F gs");
  179. }
  180. private void GetPDFColor(Color color, StringBuilder sb)
  181. {
  182. if (color == Color.Black)
  183. sb.Append("0 0 0");
  184. else if (color == Color.White)
  185. sb.Append("1 1 1");
  186. else
  187. {
  188. sb.Append(FloatToString((float)color.R / 255f, 3)).Append(" ").
  189. Append(FloatToString((float)color.G / 255f, 3)).Append(" ").
  190. Append(FloatToString((float)color.B / 255f, 3));
  191. }
  192. }
  193. private void GetCMYKColor(Color color, StringBuilder sb)
  194. {
  195. if (color == Color.Black)
  196. sb.Append("0 0 0 1");
  197. else if (color == Color.White)
  198. sb.Append("0 0 0 0");
  199. else
  200. {
  201. CMYKColor cmyk = new CMYKColor(color);
  202. sb.Append(FloatToString((float)cmyk.c / 100f, 3)).Append(" ").
  203. Append(FloatToString((float)cmyk.m / 100f, 3)).Append(" ").
  204. Append(FloatToString((float)cmyk.y / 100f, 3)).Append(" ").
  205. Append(FloatToString((float)cmyk.k / 100f, 3));
  206. }
  207. }
  208. private bool FontEquals(Font font1, Font font2)
  209. {
  210. // 20200415 - Underline and strikeout styles should not be considered as different fonts
  211. FontStyle style1 = font1.Style & (FontStyle.Regular | FontStyle.Bold | FontStyle.Italic);
  212. FontStyle style2 = font2.Style & (FontStyle.Regular | FontStyle.Bold | FontStyle.Italic);
  213. return (font1.Name == font2.Name) && style1.Equals(style2);
  214. }
  215. private string PrepXRefPos(long p)
  216. {
  217. string pos = p.ToString();
  218. return new string('0', 10 - pos.Length) + pos;
  219. }
  220. private string ObjNumber(long FNumber)
  221. {
  222. return String.Concat(FNumber.ToString(), " 0 obj");
  223. }
  224. private string ObjNumberRef(long FNumber)
  225. {
  226. return String.Concat(FNumber.ToString(), " 0 R");
  227. }
  228. private long UpdateXRef()
  229. {
  230. xRef.Add(pdf.Position);
  231. return xRef.Count;
  232. }
  233. /// <summary>
  234. /// Update stream position for object number, only for int value
  235. /// </summary>
  236. /// <param name="objectNumber">int value</param>
  237. private void UpdateXRef(long objectNumber)
  238. {
  239. xRef[(int)(objectNumber - 1)] = pdf.Position;
  240. }
  241. private void WritePDFStream(Stream target, Stream source, long id, bool compress, bool encrypt, bool startingBrackets, bool endingBrackets)
  242. {
  243. WritePDFStream(target, source, id, compress, encrypt, startingBrackets, endingBrackets, false);
  244. }
  245. private void WritePDFStream(Stream target, Stream source, long id, bool compress, bool encrypt, bool startingBrackets, bool endingBrackets, bool enableLength1)
  246. {
  247. MemoryStream tempStream;
  248. if (startingBrackets)
  249. WriteLn(target, "<<");
  250. using (tempStream = new MemoryStream())
  251. {
  252. if (compress)
  253. {
  254. ExportUtils.ZLibDeflate(source, tempStream);
  255. WriteLn(pdf, "/Filter /FlateDecode");
  256. }
  257. else
  258. {
  259. source.CopyTo(tempStream, (int)source.Length);
  260. tempStream.Position = 0;
  261. }
  262. WriteLn(pdf, "/Length " + tempStream.Length.ToString());
  263. if (enableLength1)
  264. WriteLn(pdf, "/Length1 " + source.Length.ToString());
  265. if (endingBrackets)
  266. WriteLn(target, ">>");
  267. else
  268. WriteLn(target, "");
  269. WriteLn(target, "stream");
  270. if (encrypt)
  271. RC4CryptStream(tempStream, target, encKey, id);
  272. else
  273. tempStream.WriteTo(target);
  274. target.WriteByte(0x0a);
  275. WriteLn(target, "endstream");
  276. WriteLn(target, "endobj");
  277. }
  278. }
  279. }
  280. }