PDFExportFonts.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #define USE_POSTSCRIPT_NAME
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Drawing;
  6. using System.IO;
  7. using FastReport.Export.TTF;
  8. using FastReport.Fonts;
  9. using System.Threading.Tasks;
  10. using System.Linq;
  11. namespace FastReport.Export.Pdf
  12. {
  13. public partial class PDFExport : ExportBase
  14. {
  15. private List<ExportTTFFont> fonts;
  16. private List<ExportTTFFont> pageFonts;
  17. private bool skipCurrentFont;
  18. private void AppendFont(StringBuilder Result, int fontNumber, float fontSize, Color fontColor)
  19. {
  20. if (!textInCurves)
  21. {
  22. ExportTTFFont pdffont = pageFonts[fontNumber];
  23. Result.Append(pdffont.Name).Append(" ").Append(FloatToString(fontSize)).AppendLine(" Tf");
  24. GetPDFFillColor(fontColor, Result);
  25. }
  26. }
  27. private void AppendFontAcroForm(StringBuilder Result, int fontNumber, float fontSize, Color fontColor)
  28. {
  29. ExportTTFFont pdffont = fonts[fontNumber];
  30. Result.Append(pdffont.Name).Append(" ").Append(FloatToString(fontSize)).AppendLine(" Tf");
  31. GetPDFFillColor(fontColor, Result);
  32. }
  33. private int GetObjFontNumber(Font font)
  34. {
  35. int i;
  36. for (i = 0; i < pageFonts.Count; i++)
  37. if (FontEquals(font, pageFonts[i].SourceFont))
  38. break;
  39. if (i < pageFonts.Count)
  40. return i;
  41. else
  42. {
  43. pageFonts.Add(GetGlobalFont(font));
  44. return pageFonts.Count - 1;
  45. }
  46. }
  47. private int GetObjFontNumberAcroForm(Font font)
  48. {
  49. int i;
  50. for (i = 0; i < fonts.Count; i++)
  51. if (FontEquals(font, fonts[i].SourceFont))
  52. break;
  53. if (i < fonts.Count)
  54. return i;
  55. else
  56. {
  57. GetGlobalFont(font);
  58. return fonts.Count - 1;
  59. }
  60. }
  61. private ExportTTFFont GetGlobalFont(Font font)
  62. {
  63. int i;
  64. for (i = 0; i < fonts.Count; i++)
  65. if (FontEquals(font, fonts[i].SourceFont))
  66. break;
  67. if (i < fonts.Count)
  68. return fonts[i];
  69. else
  70. {
  71. ExportTTFFont fontitem;
  72. fontitem = new ExportTTFFont(font);
  73. fontitem.FillOutlineTextMetrix();
  74. fontitem.FillEmulate();
  75. //// 20180604
  76. //bool his_italic = fontitem.TextMetric.otmItalicAngle != 0;
  77. //bool his_bold = fontitem.TextMetric.otmTextMetrics.tmWeight > 550;
  78. //if (font.Bold != his_bold)
  79. // fontitem.NeedSimulateBold = true;
  80. //if (font.Italic != his_italic)
  81. // fontitem.NeedSimulateItalic = true;
  82. fonts.Add(fontitem);
  83. fontitem.Name = "/F" + (fonts.Count - 1).ToString();
  84. return fontitem;
  85. }
  86. }
  87. private string GetToUnicode(ExportTTFFont pdfFont)
  88. {
  89. StringBuilder toUnicode = new StringBuilder(2048);
  90. toUnicode.AppendLine("/CIDInit /ProcSet findresource begin");
  91. toUnicode.AppendLine("12 dict begin");
  92. toUnicode.AppendLine("begincmap");
  93. toUnicode.AppendLine("/CIDSystemInfo");
  94. toUnicode.AppendLine("<< /Registry (Adobe)");
  95. toUnicode.AppendLine("/Ordering (UCS)");
  96. toUnicode.AppendLine("/Ordering (Identity)");
  97. toUnicode.AppendLine("/Supplement 0");
  98. toUnicode.AppendLine(">> def");
  99. toUnicode.Append("/CMapName /").Append(pdfFont.GetEnglishFontName().Replace(',', '+')).AppendLine(" def");
  100. toUnicode.AppendLine("/CMapType 2 def");
  101. toUnicode.AppendLine("1 begincodespacerange");
  102. toUnicode.AppendLine("<0000> <FFFF>");
  103. toUnicode.AppendLine("endcodespacerange");
  104. int charCount = 0;
  105. foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars)
  106. {
  107. if (glyphChar.GlyphType == GlyphType.Character ||
  108. glyphChar.GlyphType == GlyphType.None)
  109. charCount++;
  110. }
  111. int stringCount = 0;
  112. foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars)
  113. {
  114. if (glyphChar.GlyphType == GlyphType.String)
  115. stringCount++;
  116. }
  117. if (charCount > 0)
  118. {
  119. toUnicode.Append(charCount).AppendLine(" beginbfchar");
  120. foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars)
  121. {
  122. if (glyphChar.GlyphType == GlyphType.Character)
  123. {
  124. toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> ");
  125. toUnicode.Append("<").Append(((ushort)glyphChar.Character).ToString("X4")).AppendLine(">");
  126. }
  127. else if (glyphChar.GlyphType == GlyphType.None)
  128. {
  129. toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> ");
  130. toUnicode.AppendLine("<0000>");
  131. }
  132. }
  133. toUnicode.AppendLine("endbfchar");
  134. }
  135. if (stringCount > 0)
  136. {
  137. toUnicode.Append(stringCount.ToString()).AppendLine(" beginbfrange");
  138. foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars)
  139. {
  140. if (glyphChar.GlyphType == GlyphType.String)
  141. {
  142. toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> ");
  143. toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> ");
  144. toUnicode.Append("[<");
  145. foreach (char c in glyphChar.String)
  146. toUnicode.Append(((ushort)c).ToString("X4"));
  147. toUnicode.AppendLine(">]");
  148. }
  149. }
  150. toUnicode.AppendLine("endbfrange");
  151. }
  152. toUnicode.AppendLine("endcmap");
  153. toUnicode.AppendLine("CMapName currentdict /CMap defineresource pop");
  154. toUnicode.AppendLine("end");
  155. toUnicode.AppendLine("end");
  156. return toUnicode.ToString();
  157. }
  158. private void WriteFont(ExportTTFFont pdfFont)
  159. {
  160. long fontFileId = 0;
  161. #if USE_POSTSCRIPT_NAME
  162. string fontName = pdfFont.PostscriptName;
  163. #else
  164. string fontName = pdfFont.GetEnglishFontName();
  165. #endif
  166. // embedded font
  167. if (embeddingFonts)
  168. {
  169. if (interactiveForms && pdfFont.Editable)
  170. {
  171. if (interactiveFormsFontSetPattern.Length == 0)
  172. {
  173. List<Task> tasks = new List<Task>();
  174. for (int i = 0; i < 1024; i++)
  175. {
  176. int index = i;
  177. tasks.Add(Task.Run(() =>
  178. {
  179. StringBuilder sb = new StringBuilder(64);
  180. for (int j = 0; j < 64; j++)
  181. sb.Append((char)(64 * index + j));
  182. foreach (ExportTTFFont.RunInfo run in pdfFont.GetFontRuns(sb.ToString(), false))
  183. pdfFont.AddUsedGlyphs(run);
  184. }));
  185. }
  186. Task.WaitAll(tasks.ToArray());
  187. }
  188. else
  189. {
  190. foreach (ExportTTFFont.RunInfo run in pdfFont.GetPatternRuns(interactiveFormsFontSetPattern, false))
  191. pdfFont.AddUsedGlyphs(run);
  192. }
  193. }
  194. byte[] fontfile = pdfFont.GetFontData(true);
  195. if (fontfile != null)
  196. {
  197. skipCurrentFont = false;
  198. fontFileId = UpdateXRef();
  199. WriteLn(pdf, ObjNumber(fontFileId));
  200. MemoryStream fontFileStream = new MemoryStream();
  201. fontFileStream.Write(fontfile, 0, fontfile.Length);
  202. fontFileStream.Seek(0, SeekOrigin.Begin);
  203. WritePDFStream(pdf, fontFileStream, fontFileId, compressed, encrypted, true, true);
  204. }
  205. else
  206. {
  207. // If font cannot be embedded by some reason, for example license rights, then disable embedding
  208. skipCurrentFont = true;
  209. }
  210. }
  211. // descriptor
  212. long descriptorId = UpdateXRef();
  213. WriteLn(pdf, ObjNumber(descriptorId));
  214. WriteLn(pdf, "<<");
  215. WriteLn(pdf, "/Type /FontDescriptor");
  216. WriteLn(pdf, "/FontName /" + fontName);
  217. //WriteLn(pdf, "/FontFamily /" + fontName);
  218. WriteLn(pdf, "/Flags 32");
  219. WriteLn(pdf, "/FontBBox [" + pdfFont.TextMetric.otmrcFontBox.left.ToString() + " " +
  220. pdfFont.TextMetric.otmrcFontBox.bottom.ToString() + " " +
  221. pdfFont.TextMetric.otmrcFontBox.right.ToString() + " " +
  222. pdfFont.TextMetric.otmrcFontBox.top.ToString() + " ]");
  223. //WriteLn(pdf, "/Style << /Panose <" + pdfFont.GetPANOSE() + "> >>");
  224. int ItalicAnggle = pdfFont.TextMetric.otmItalicAngle;
  225. if (pdfFont.NeedSimulateItalic && ItalicAnggle == 0)
  226. WriteLn(pdf, "/ItalicAngle " + 16);
  227. else
  228. WriteLn(pdf, "/ItalicAngle " + pdfFont.TextMetric.otmItalicAngle.ToString());
  229. #if !WITHOUT_UNISCRIBE
  230. WriteLn(pdf, "/Ascent " + pdfFont.TextMetric.otmAscent.ToString());
  231. WriteLn(pdf, "/Descent " + pdfFont.TextMetric.otmDescent.ToString());
  232. WriteLn(pdf, "/CapHeight " + pdfFont.TextMetric.otmTextMetrics.tmHeight.ToString());
  233. #else
  234. WriteLn(pdf, "/Ascent " + ((int)(pdfFont.TextMetric.otmAscent / 2.05)).ToString());
  235. WriteLn(pdf, "/Descent " + ((int)(pdfFont.TextMetric.otmDescent / 2.05)).ToString());
  236. WriteLn(pdf, "/CapHeight " + ((int)(pdfFont.TextMetric.otmTextMetrics.tmHeight / 2.05)).ToString());
  237. #endif
  238. WriteLn(pdf, "/Leading " + pdfFont.TextMetric.otmTextMetrics.tmInternalLeading.ToString());
  239. WriteLn(pdf, "/StemV " + (50 + Math.Round(Math.Sqrt((float)pdfFont.TextMetric.otmTextMetrics.tmWeight / 65f))).ToString());
  240. WriteLn(pdf, "/AvgWidth " + pdfFont.TextMetric.otmTextMetrics.tmAveCharWidth.ToString());
  241. WriteLn(pdf, "/MxWidth " + pdfFont.TextMetric.otmTextMetrics.tmMaxCharWidth.ToString());
  242. WriteLn(pdf, "/MissingWidth " + pdfFont.TextMetric.otmTextMetrics.tmAveCharWidth.ToString());
  243. if (embeddingFonts && !skipCurrentFont)
  244. WriteLn(pdf, "/FontFile2 " + ObjNumberRef(fontFileId));
  245. WriteLn(pdf, ">>");
  246. WriteLn(pdf, "endobj");
  247. // ToUnicode
  248. long toUnicodeId = UpdateXRef();
  249. WriteLn(pdf, ObjNumber(toUnicodeId));
  250. MemoryStream tounicodeStream = new MemoryStream();
  251. Write(tounicodeStream, GetToUnicode(pdfFont));
  252. tounicodeStream.Position = 0;
  253. WritePDFStream(pdf, tounicodeStream, toUnicodeId, compressed, encrypted, true, true);
  254. //CIDSystemInfo
  255. long cIDSystemInfoId = UpdateXRef();
  256. WriteLn(pdf, ObjNumber(cIDSystemInfoId));
  257. WriteLn(pdf, "<<");
  258. WriteLn(pdf, "/Registry (Adobe) /Ordering (Identity) /Supplement 0");
  259. WriteLn(pdf, ">>");
  260. WriteLn(pdf, "endobj");
  261. //DescendantFonts
  262. long descendantFontId = UpdateXRef();
  263. WriteLn(pdf, ObjNumber(descendantFontId));
  264. WriteLn(pdf, "<<");
  265. WriteLn(pdf, "/Type /Font");
  266. WriteLn(pdf, "/Subtype /CIDFontType2");
  267. WriteLn(pdf, "/BaseFont /" + fontName);
  268. WriteLn(pdf, "/CIDToGIDMap /Identity");
  269. WriteLn(pdf, "/CIDSystemInfo " + ObjNumberRef(cIDSystemInfoId));
  270. WriteLn(pdf, "/FontDescriptor " + ObjNumberRef(descriptorId));
  271. Write(pdf, "/W [ ");
  272. foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars)
  273. Write(pdf, glyphChar.Glyph.ToString() + " [" + FloatToString(glyphChar.Width) + "] ");
  274. WriteLn(pdf, "]");
  275. WriteLn(pdf, ">>");
  276. WriteLn(pdf, "endobj");
  277. // main
  278. xRef[(int)(pdfFont.Reference - 1)] = pdf.Position;
  279. WriteLn(pdf, ObjNumber(pdfFont.Reference));
  280. WriteLn(pdf, "<<");
  281. WriteLn(pdf, "/Type /Font");
  282. WriteLn(pdf, "/Subtype /Type0");
  283. WriteLn(pdf, "/BaseFont /" + fontName);
  284. WriteLn(pdf, "/Encoding /Identity-H");
  285. WriteLn(pdf, "/DescendantFonts [" + ObjNumberRef(descendantFontId) + "]");
  286. WriteLn(pdf, "/ToUnicode " + ObjNumberRef(toUnicodeId));
  287. WriteLn(pdf, ">>");
  288. WriteLn(pdf, "endobj");
  289. }
  290. }
  291. }