private PdfFontDescriptor MakeFontDescriptor(string fontName, IFontMetric metrics) { IFontDescriptor descriptor = metrics.Descriptor; PdfFontDescriptor pdfDescriptor = new PdfFontDescriptor( fontName, NextObjectId()); pdfDescriptor.Ascent = new PdfNumeric(metrics.Ascender); pdfDescriptor.CapHeight = new PdfNumeric(metrics.CapHeight); pdfDescriptor.Descent = new PdfNumeric(metrics.Descender); pdfDescriptor.Flags = new PdfNumeric(descriptor.Flags); pdfDescriptor.ItalicAngle = new PdfNumeric(descriptor.ItalicAngle); pdfDescriptor.StemV = new PdfNumeric(descriptor.StemV); PdfArray array = new PdfArray(); array.AddArray(descriptor.FontBBox); pdfDescriptor.FontBBox = array; return pdfDescriptor; }
public async Task SaveAsync(Stream stream) { var pdfDocumentCatalog = new PdfDocumentCatalog(); var pdfPageTree = new PdfPageTree(); pdfDocumentCatalog.PagesReference = pdfPageTree.Reference; var pdfFonts = new List <PdfFont>(); var pdfFontDescriptors = new List <PdfFontDescriptor>(); var pdfCharWidthsObjects = new List <PdfCharWidths>(); var pdfFontStreams = new List <PdfFontStream>(); var fontToPdfFont = new Dictionary <Font, PdfFont>(); foreach (var font in Fonts) { var fontStream = new PdfFontStream(); fontStream.Filter = PdfStreamFilter.FlateDecode; fontStream.Stream = new PdfStream(File.ReadAllBytes(font.FileName)); pdfFontStreams.Add(fontStream); var fontInfo = font.FontInfo; var factor = 1000.0 / fontInfo.HeadTable.UnitsPerEm; var charWidths = new int[129]; for (int i = 0; i < 129; i++) { fontInfo.CharacterMapTable.Encodings.Last().Value.TryGetGlyphId(i, out var glyphIndex); charWidths[i] = fontInfo.HorizontalMetricsTable.HMetrics[glyphIndex].AdvanceWidth; // Don't normalize //fontInfo.CharacterMapTable.Encodings.Last().Value.TryGetGlyphId(i, out var glyphIndex); //var blockLocation = fontInfo.IndexLocationTable.GetLocation(glyphIndex); //var glyphHeader = fontInfo.GlyphTable.ReadHeader(blockLocation); //charWidths[i] = glyphHeader.XMax - glyphHeader.XMin; } var pdfCharWidths = new PdfCharWidths { Widths = new PdfArray(charWidths.Select(x => (PdfObject) new PdfReal(Normalize(x, factor))).ToList()) }; pdfCharWidthsObjects.Add(pdfCharWidths); var pdfFontDescriptor = new PdfFontDescriptor { Ascent = new PdfInteger(Normalize(fontInfo.HorizontalHeaderTable.Ascender, factor)), Descent = new PdfInteger(Normalize(fontInfo.HorizontalHeaderTable.Descender, factor)), FontName = new PdfName(font.Name), FontBBox = new PdfRectangle(Normalize(fontInfo.HeadTable.XMin, factor), Normalize(fontInfo.HeadTable.YMin, factor), Normalize(fontInfo.HeadTable.XMax, factor), Normalize(fontInfo.HeadTable.YMax, factor)), FontWeight = new PdfInteger(fontInfo.Os2Table.UsWeightClass), AvgWidth = new PdfInteger(Normalize(fontInfo.Os2Table.XAvgCharWidth, factor)), CapHeight = new PdfInteger(Normalize(fontInfo.Os2Table.SCapHeight, factor)), ItalicAngle = new PdfReal(Normalize((double)fontInfo.PostScriptTable.ItalicAngle, factor)), // MaxWidth = new PdfInteger(0), // TODO // XHeight = new PdfInteger(0), // TODO StemV = new PdfInteger(50), // TODO Flags = new PdfInteger(32), // TODO FontFile2 = new PdfIndirectObjectReference(fontStream) }; pdfFontDescriptors.Add(pdfFontDescriptor); var pdfFont = new PdfFont { Subtype = new PdfName(font.Type), BaseFont = new PdfName(font.Name), Encoding = new PdfName(font.Encoding.ToString()), FontDescriptor = pdfFontDescriptor.Reference, Widths = pdfCharWidths.Reference, FirstChar = new PdfInteger(0), LastChar = new PdfInteger(127) }; pdfFonts.Add(pdfFont); fontToPdfFont[font] = pdfFont; } pdfPageTree.MediaBox = new PdfRectangle(0, 0, DefaultPageWidth, DefaultPageHeight); pdfPageTree.Resources = new PdfResources { Fonts = new PdfFontResources() }; foreach (var font in Fonts) { pdfPageTree.Resources.Fonts.Add($"F{_nextFontId++}", fontToPdfFont[font].Reference); } var pdfContentStreams = new List <PdfContentStream>(); var pdfPages = new List <PdfPage>(); foreach (var page in Pages) { var pdfPage = new PdfPage(); pdfPages.Add(pdfPage); pdfPage.Parent = pdfPageTree.Reference; if (page.Unit != 1.0) { pdfPage.UserUnit = new PdfReal(page.Unit); } if (page.Width != DefaultPageWidth || page.Height != DefaultPageHeight) { pdfPage.MediaBox = new PdfRectangle(0, 0, page.Width, page.Height); } var instructions = page.Paint(); if (!string.IsNullOrWhiteSpace(instructions)) { var pdfContentStream = new PdfContentStream { Stream = new PdfStream(Encoding.ASCII.GetBytes(instructions)), // Filter = PdfStreamFilter.FlateDecode // Temporarily no using. Uncomment after development complete }; pdfContentStreams.Add(pdfContentStream); pdfPage.Contents = pdfContentStream.Reference; } } pdfPageTree.Kids = pdfPages.Select(x => x.Reference).ToList(); var writer = new PdfWriter(stream); await writer.WriteAsync(pdfDocumentCatalog); await writer.WriteAsync(pdfPageTree); foreach (var pdfFont in pdfFonts) { await writer.WriteAsync(pdfFont); } foreach (var pdfFontDescriptor in pdfFontDescriptors) { await writer.WriteAsync(pdfFontDescriptor); } foreach (var pdfCharWidths in pdfCharWidthsObjects) { await writer.WriteAsync(pdfCharWidths); } foreach (var pdfFontStream in pdfFontStreams) { await writer.WriteAsync(pdfFontStream); } foreach (var pdfPage in pdfPages) { await writer.WriteAsync(pdfPage); } foreach (var pdfContentStream in pdfContentStreams) { await writer.WriteAsync(pdfContentStream); } await writer.CloseAsync(pdfDocumentCatalog, null); }