#define USE_POSTSCRIPT_NAME using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.IO; using FastReport.Export.TTF; using FastReport.Fonts; using System.Threading.Tasks; using System.Linq; namespace FastReport.Export.Pdf { public partial class PDFExport : ExportBase { private List fonts; private List pageFonts; private bool skipCurrentFont; private void AppendFont(StringBuilder Result, int fontNumber, float fontSize, Color fontColor) { if (!textInCurves) { ExportTTFFont pdffont = pageFonts[fontNumber]; Result.Append(pdffont.Name).Append(" ").Append(FloatToString(fontSize)).AppendLine(" Tf"); GetPDFFillColor(fontColor, Result); } } private void AppendFontAcroForm(StringBuilder Result, int fontNumber, float fontSize, Color fontColor) { ExportTTFFont pdffont = fonts[fontNumber]; Result.Append(pdffont.Name).Append(" ").Append(FloatToString(fontSize)).AppendLine(" Tf"); GetPDFFillColor(fontColor, Result); } private int GetObjFontNumber(Font font) { int i; for (i = 0; i < pageFonts.Count; i++) if (FontEquals(font, pageFonts[i].SourceFont)) break; if (i < pageFonts.Count) return i; else { pageFonts.Add(GetGlobalFont(font)); return pageFonts.Count - 1; } } private int GetObjFontNumberAcroForm(Font font) { int i; for (i = 0; i < fonts.Count; i++) if (FontEquals(font, fonts[i].SourceFont)) break; if (i < fonts.Count) return i; else { GetGlobalFont(font); return fonts.Count - 1; } } private ExportTTFFont GetGlobalFont(Font font) { int i; for (i = 0; i < fonts.Count; i++) if (FontEquals(font, fonts[i].SourceFont)) break; if (i < fonts.Count) return fonts[i]; else { ExportTTFFont fontitem; fontitem = new ExportTTFFont(font); fontitem.FillOutlineTextMetrix(); fontitem.FillEmulate(); //// 20180604 //bool his_italic = fontitem.TextMetric.otmItalicAngle != 0; //bool his_bold = fontitem.TextMetric.otmTextMetrics.tmWeight > 550; //if (font.Bold != his_bold) // fontitem.NeedSimulateBold = true; //if (font.Italic != his_italic) // fontitem.NeedSimulateItalic = true; fonts.Add(fontitem); fontitem.Name = "/F" + (fonts.Count - 1).ToString(); return fontitem; } } private string GetToUnicode(ExportTTFFont pdfFont) { StringBuilder toUnicode = new StringBuilder(2048); toUnicode.AppendLine("/CIDInit /ProcSet findresource begin"); toUnicode.AppendLine("12 dict begin"); toUnicode.AppendLine("begincmap"); toUnicode.AppendLine("/CIDSystemInfo"); toUnicode.AppendLine("<< /Registry (Adobe)"); toUnicode.AppendLine("/Ordering (UCS)"); toUnicode.AppendLine("/Ordering (Identity)"); toUnicode.AppendLine("/Supplement 0"); toUnicode.AppendLine(">> def"); toUnicode.Append("/CMapName /").Append(pdfFont.GetEnglishFontName().Replace(',', '+')).AppendLine(" def"); toUnicode.AppendLine("/CMapType 2 def"); toUnicode.AppendLine("1 begincodespacerange"); toUnicode.AppendLine("<0000> "); toUnicode.AppendLine("endcodespacerange"); int charCount = 0; foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars) { if (glyphChar.GlyphType == GlyphType.Character || glyphChar.GlyphType == GlyphType.None) charCount++; } int stringCount = 0; foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars) { if (glyphChar.GlyphType == GlyphType.String) stringCount++; } if (charCount > 0) { toUnicode.Append(charCount).AppendLine(" beginbfchar"); foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars) { if (glyphChar.GlyphType == GlyphType.Character) { toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> "); toUnicode.Append("<").Append(((ushort)glyphChar.Character).ToString("X4")).AppendLine(">"); } else if (glyphChar.GlyphType == GlyphType.None) { toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> "); toUnicode.AppendLine("<0000>"); } } toUnicode.AppendLine("endbfchar"); } if (stringCount > 0) { toUnicode.Append(stringCount.ToString()).AppendLine(" beginbfrange"); foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars) { if (glyphChar.GlyphType == GlyphType.String) { toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> "); toUnicode.Append("<").Append(glyphChar.Glyph.ToString("X4")).Append("> "); toUnicode.Append("[<"); foreach (char c in glyphChar.String) toUnicode.Append(((ushort)c).ToString("X4")); toUnicode.AppendLine(">]"); } } toUnicode.AppendLine("endbfrange"); } toUnicode.AppendLine("endcmap"); toUnicode.AppendLine("CMapName currentdict /CMap defineresource pop"); toUnicode.AppendLine("end"); toUnicode.AppendLine("end"); return toUnicode.ToString(); } private void WriteFont(ExportTTFFont pdfFont) { long fontFileId = 0; #if USE_POSTSCRIPT_NAME string fontName = pdfFont.PostscriptName; #else string fontName = pdfFont.GetEnglishFontName(); #endif // embedded font if (embeddingFonts) { if (interactiveForms && pdfFont.Editable) { if (interactiveFormsFontSetPattern.Length == 0) { List tasks = new List(); for (int i = 0; i < 1024; i++) { int index = i; tasks.Add(Task.Run(() => { StringBuilder sb = new StringBuilder(64); for (int j = 0; j < 64; j++) sb.Append((char)(64 * index + j)); foreach (ExportTTFFont.RunInfo run in pdfFont.GetFontRuns(sb.ToString(), false)) pdfFont.AddUsedGlyphs(run); })); } Task.WaitAll(tasks.ToArray()); } else { foreach (ExportTTFFont.RunInfo run in pdfFont.GetPatternRuns(interactiveFormsFontSetPattern, false)) pdfFont.AddUsedGlyphs(run); } } byte[] fontfile = pdfFont.GetFontData(true); if (fontfile != null) { skipCurrentFont = false; fontFileId = UpdateXRef(); WriteLn(pdf, ObjNumber(fontFileId)); MemoryStream fontFileStream = new MemoryStream(); fontFileStream.Write(fontfile, 0, fontfile.Length); fontFileStream.Seek(0, SeekOrigin.Begin); WritePDFStream(pdf, fontFileStream, fontFileId, compressed, encrypted, true, true); } else { // If font cannot be embedded by some reason, for example license rights, then disable embedding skipCurrentFont = true; } } // descriptor long descriptorId = UpdateXRef(); WriteLn(pdf, ObjNumber(descriptorId)); WriteLn(pdf, "<<"); WriteLn(pdf, "/Type /FontDescriptor"); WriteLn(pdf, "/FontName /" + fontName); //WriteLn(pdf, "/FontFamily /" + fontName); WriteLn(pdf, "/Flags 32"); WriteLn(pdf, "/FontBBox [" + pdfFont.TextMetric.otmrcFontBox.left.ToString() + " " + pdfFont.TextMetric.otmrcFontBox.bottom.ToString() + " " + pdfFont.TextMetric.otmrcFontBox.right.ToString() + " " + pdfFont.TextMetric.otmrcFontBox.top.ToString() + " ]"); //WriteLn(pdf, "/Style << /Panose <" + pdfFont.GetPANOSE() + "> >>"); int ItalicAnggle = pdfFont.TextMetric.otmItalicAngle; if (pdfFont.NeedSimulateItalic && ItalicAnggle == 0) WriteLn(pdf, "/ItalicAngle " + 16); else WriteLn(pdf, "/ItalicAngle " + pdfFont.TextMetric.otmItalicAngle.ToString()); #if !WITHOUT_UNISCRIBE WriteLn(pdf, "/Ascent " + pdfFont.TextMetric.otmAscent.ToString()); WriteLn(pdf, "/Descent " + pdfFont.TextMetric.otmDescent.ToString()); WriteLn(pdf, "/CapHeight " + pdfFont.TextMetric.otmTextMetrics.tmHeight.ToString()); #else WriteLn(pdf, "/Ascent " + ((int)(pdfFont.TextMetric.otmAscent / 2.05)).ToString()); WriteLn(pdf, "/Descent " + ((int)(pdfFont.TextMetric.otmDescent / 2.05)).ToString()); WriteLn(pdf, "/CapHeight " + ((int)(pdfFont.TextMetric.otmTextMetrics.tmHeight / 2.05)).ToString()); #endif WriteLn(pdf, "/Leading " + pdfFont.TextMetric.otmTextMetrics.tmInternalLeading.ToString()); WriteLn(pdf, "/StemV " + (50 + Math.Round(Math.Sqrt((float)pdfFont.TextMetric.otmTextMetrics.tmWeight / 65f))).ToString()); WriteLn(pdf, "/AvgWidth " + pdfFont.TextMetric.otmTextMetrics.tmAveCharWidth.ToString()); WriteLn(pdf, "/MxWidth " + pdfFont.TextMetric.otmTextMetrics.tmMaxCharWidth.ToString()); WriteLn(pdf, "/MissingWidth " + pdfFont.TextMetric.otmTextMetrics.tmAveCharWidth.ToString()); if (embeddingFonts && !skipCurrentFont) WriteLn(pdf, "/FontFile2 " + ObjNumberRef(fontFileId)); WriteLn(pdf, ">>"); WriteLn(pdf, "endobj"); // ToUnicode long toUnicodeId = UpdateXRef(); WriteLn(pdf, ObjNumber(toUnicodeId)); MemoryStream tounicodeStream = new MemoryStream(); Write(tounicodeStream, GetToUnicode(pdfFont)); tounicodeStream.Position = 0; WritePDFStream(pdf, tounicodeStream, toUnicodeId, compressed, encrypted, true, true); //CIDSystemInfo long cIDSystemInfoId = UpdateXRef(); WriteLn(pdf, ObjNumber(cIDSystemInfoId)); WriteLn(pdf, "<<"); WriteLn(pdf, "/Registry (Adobe) /Ordering (Identity) /Supplement 0"); WriteLn(pdf, ">>"); WriteLn(pdf, "endobj"); //DescendantFonts long descendantFontId = UpdateXRef(); WriteLn(pdf, ObjNumber(descendantFontId)); WriteLn(pdf, "<<"); WriteLn(pdf, "/Type /Font"); WriteLn(pdf, "/Subtype /CIDFontType2"); WriteLn(pdf, "/BaseFont /" + fontName); WriteLn(pdf, "/CIDToGIDMap /Identity"); WriteLn(pdf, "/CIDSystemInfo " + ObjNumberRef(cIDSystemInfoId)); WriteLn(pdf, "/FontDescriptor " + ObjNumberRef(descriptorId)); Write(pdf, "/W [ "); foreach (GlyphChar glyphChar in pdfFont.UsedGlyphChars) Write(pdf, glyphChar.Glyph.ToString() + " [" + FloatToString(glyphChar.Width) + "] "); WriteLn(pdf, "]"); WriteLn(pdf, ">>"); WriteLn(pdf, "endobj"); // main xRef[(int)(pdfFont.Reference - 1)] = pdf.Position; WriteLn(pdf, ObjNumber(pdfFont.Reference)); WriteLn(pdf, "<<"); WriteLn(pdf, "/Type /Font"); WriteLn(pdf, "/Subtype /Type0"); WriteLn(pdf, "/BaseFont /" + fontName); WriteLn(pdf, "/Encoding /Identity-H"); WriteLn(pdf, "/DescendantFonts [" + ObjNumberRef(descendantFontId) + "]"); WriteLn(pdf, "/ToUnicode " + ObjNumberRef(toUnicodeId)); WriteLn(pdf, ">>"); WriteLn(pdf, "endobj"); } } }