/// <summary> /// Gets the data of the specified glyph. /// </summary> public byte[] GetGlyphData(int glyph) { IndexToLocationTable loca = this.fontData.loca; int start = GetOffset(glyph); int next = GetOffset(glyph + 1); int count = next - start; byte[] bytes = new byte[count]; Buffer.BlockCopy(this.fontData.Data, start, bytes, 0, count); return(bytes); }
/// <summary> /// Creates a new font image that is a subset of this font image containing only the specified glyphs. /// </summary> public OpenTypeFontface CreateFontSubSet(Dictionary <int, object> glyphs, bool cidFont) { // Create new font image OpenTypeFontface fontData = new OpenTypeFontface(this); // Create new loca and glyf table IndexToLocationTable locaNew = new IndexToLocationTable(); locaNew.ShortIndex = loca.ShortIndex; GlyphDataTable glyfNew = new GlyphDataTable(); // Add all required tables //fontData.AddTable(os2); if (!cidFont) { fontData.AddTable(cmap); } if (cvt != null) { fontData.AddTable(cvt); } if (fpgm != null) { fontData.AddTable(fpgm); } fontData.AddTable(glyfNew); fontData.AddTable(head); fontData.AddTable(hhea); fontData.AddTable(hmtx); fontData.AddTable(locaNew); if (maxp != null) { fontData.AddTable(maxp); } //fontData.AddTable(name); if (prep != null) { fontData.AddTable(prep); } // Get closure of used glyphs. glyf.CompleteGlyphClosure(glyphs); // Create a sorted array of all used glyphs. int glyphCount = glyphs.Count; int[] glyphArray = new int[glyphCount]; glyphs.Keys.CopyTo(glyphArray, 0); Array.Sort(glyphArray); // Calculate new size of glyph table. int size = 0; for (int idx = 0; idx < glyphCount; idx++) { size += glyf.GetGlyphSize(glyphArray[idx]); } glyfNew.DirectoryEntry.Length = size; // Create new loca table int numGlyphs = maxp.numGlyphs; locaNew.LocaTable = new int[numGlyphs + 1]; // Create new glyf table glyfNew.GlyphTable = new byte[glyfNew.DirectoryEntry.PaddedLength]; // Fill new glyf and loca table int glyphOffset = 0; int glyphIndex = 0; for (int idx = 0; idx < numGlyphs; idx++) { locaNew.LocaTable[idx] = glyphOffset; if (glyphIndex < glyphCount && glyphArray[glyphIndex] == idx) { glyphIndex++; byte[] bytes = glyf.GetGlyphData(idx); int length = bytes.Length; if (length > 0) { Buffer.BlockCopy(bytes, 0, glyfNew.GlyphTable, glyphOffset, length); glyphOffset += length; } } } locaNew.LocaTable[numGlyphs] = glyphOffset; // Compile font tables into byte array fontData.Compile(); return(fontData); }
/// <summary> /// Reads all required tables from the font data. /// </summary> internal void Read() { // Determine font technology // ReSharper disable InconsistentNaming const uint OTTO = 0x4f54544f; // Adobe OpenType CFF data, tag: 'OTTO' const uint TTCF = 0x74746366; // TrueType Collection tag: 'ttcf' // ReSharper restore InconsistentNaming try { #if DEBUG_ if (Name == "Cambria") { Debug - Break.Break(); } #endif // Check if data is a TrueType collection font. uint startTag = ReadULong(); if (startTag == TTCF) { _fontTechnology = FontTechnology.TrueTypeCollection; throw new InvalidOperationException("TrueType collection fonts are not yet supported by PDFsharp."); } // Read offset table _offsetTable.Version = startTag; _offsetTable.TableCount = ReadUShort(); _offsetTable.SearchRange = ReadUShort(); _offsetTable.EntrySelector = ReadUShort(); _offsetTable.RangeShift = ReadUShort(); // Move to table dictionary at position 12 Debug.Assert(_pos == 12); //tableDictionary = (offsetTable.TableCount); if (_offsetTable.Version == OTTO) { _fontTechnology = FontTechnology.PostscriptOutlines; } else { _fontTechnology = FontTechnology.TrueTypeOutlines; } for (int idx = 0; idx < _offsetTable.TableCount; idx++) { TableDirectoryEntry entry = TableDirectoryEntry.ReadFrom(this); TableDictionary.Add(entry.Tag, entry); #if VERBOSE Debug.WriteLine(String.Format("Font table: {0}", entry.Tag)); #endif } // PDFlib checks this, but it is not part of the OpenType spec anymore if (TableDictionary.ContainsKey("bhed")) { throw new NotSupportedException("Bitmap fonts are not supported by PDFsharp."); } // Read required tables if (Seek(CMapTable.Tag) != -1) { cmap = new CMapTable(this); } if (Seek(ControlValueTable.Tag) != -1) { cvt = new ControlValueTable(this); } if (Seek(FontProgram.Tag) != -1) { fpgm = new FontProgram(this); } if (Seek(MaximumProfileTable.Tag) != -1) { maxp = new MaximumProfileTable(this); } if (Seek(NameTable.Tag) != -1) { name = new NameTable(this); } if (Seek(FontHeaderTable.Tag) != -1) { head = new FontHeaderTable(this); } if (Seek(HorizontalHeaderTable.Tag) != -1) { hhea = new HorizontalHeaderTable(this); } if (Seek(HorizontalMetricsTable.Tag) != -1) { hmtx = new HorizontalMetricsTable(this); } if (Seek(OS2Table.Tag) != -1) { os2 = new OS2Table(this); } if (Seek(PostScriptTable.Tag) != -1) { post = new PostScriptTable(this); } if (Seek(GlyphDataTable.Tag) != -1) { glyf = new GlyphDataTable(this); } if (Seek(IndexToLocationTable.Tag) != -1) { loca = new IndexToLocationTable(this); } if (Seek(GlyphSubstitutionTable.Tag) != -1) { gsub = new GlyphSubstitutionTable(this); } if (Seek(ControlValueProgram.Tag) != -1) { prep = new ControlValueProgram(this); } } catch (Exception) { GetType(); throw; } }
/// <summary> /// Adds the specified table to this font image. /// </summary> public void AddTable(OpenTypeFontTable fontTable) { if (!CanWrite) { throw new InvalidOperationException("Font image cannot be modified."); } if (fontTable == null) { throw new ArgumentNullException("fontTable"); } if (fontTable._fontData == null) { fontTable._fontData = this; } else { Debug.Assert(fontTable._fontData.CanRead); // Create a reference to this font table fontTable = new IRefFontTable(this, fontTable); } //Debug.Assert(fontTable.FontData == null); //fontTable.fontData = this; TableDictionary[fontTable.DirectoryEntry.Tag] = fontTable.DirectoryEntry; switch (fontTable.DirectoryEntry.Tag) { case TableTagNames.CMap: cmap = fontTable as CMapTable; break; case TableTagNames.Cvt: cvt = fontTable as ControlValueTable; break; case TableTagNames.Fpgm: fpgm = fontTable as FontProgram; break; case TableTagNames.MaxP: maxp = fontTable as MaximumProfileTable; break; case TableTagNames.Name: name = fontTable as NameTable; break; case TableTagNames.Head: head = fontTable as FontHeaderTable; break; case TableTagNames.HHea: hhea = fontTable as HorizontalHeaderTable; break; case TableTagNames.HMtx: hmtx = fontTable as HorizontalMetricsTable; break; case TableTagNames.OS2: os2 = fontTable as OS2Table; break; case TableTagNames.Post: post = fontTable as PostScriptTable; break; case TableTagNames.Glyf: glyf = fontTable as GlyphDataTable; break; case TableTagNames.Loca: loca = fontTable as IndexToLocationTable; break; case TableTagNames.GSUB: gsub = fontTable as GlyphSubstitutionTable; break; case TableTagNames.Prep: prep = fontTable as ControlValueProgram; break; } }
/// <summary> /// Gets the size of the byte array that defines the glyph. /// </summary> public int GetGlyphSize(int glyph) { IndexToLocationTable loca = this.fontData.loca; return(GetOffset(glyph + 1) - GetOffset(glyph)); }
/// <summary> /// Creates a new font image that is a subset of this font image containing only the specified glyphs. /// </summary> public FontData CreateFontSubSet(Dictionary<int, object> glyphs, bool cidFont) { // Create new font image FontData fontData = new FontData(this); // Create new loca and glyf table IndexToLocationTable loca = new IndexToLocationTable(); loca.ShortIndex = this.loca.ShortIndex; GlyphDataTable glyf = new GlyphDataTable(); // Add all required tables //fontData.AddTable(this.os2); if (!cidFont) fontData.AddTable(this.cmap); if (this.cvt != null) fontData.AddTable(this.cvt); if (this.fpgm != null) fontData.AddTable(this.fpgm); fontData.AddTable(glyf); fontData.AddTable(this.head); fontData.AddTable(this.hhea); fontData.AddTable(this.hmtx); fontData.AddTable(loca); if (this.maxp != null) fontData.AddTable(this.maxp); //fontData.AddTable(this.name); if (this.prep != null) fontData.AddTable(this.prep); // Get closure of used glyphs this.glyf.CompleteGlyphClosure(glyphs); // Create a sorted array of all used glyphs int glyphCount = glyphs.Count; int[] glyphArray = new int[glyphCount]; glyphs.Keys.CopyTo(glyphArray, 0); Array.Sort<int>(glyphArray); // Calculate new size of glyph table. int size = 0; for (int idx = 0; idx < glyphCount; idx++) size += this.glyf.GetGlyphSize(glyphArray[idx]); glyf.DirectoryEntry.Length = size; // Create new loca table int numGlyphs = this.maxp.numGlyphs; loca.locaTable = new int[numGlyphs + 1]; // Create new glyf table glyf.glyphTable = new byte[glyf.DirectoryEntry.PaddedLength]; // Fill new glyf and loca table int glyphOffset = 0; int glyphIndex = 0; for (int idx = 0; idx < numGlyphs; idx++) { loca.locaTable[idx] = glyphOffset; if (glyphIndex < glyphCount && glyphArray[glyphIndex] == idx) { glyphIndex++; byte[] bytes = this.glyf.GetGlyphData(idx); int length = bytes.Length; if (length > 0) { Buffer.BlockCopy(bytes, 0, glyf.glyphTable, glyphOffset, length); glyphOffset += length; } } } loca.locaTable[numGlyphs] = glyphOffset; // Compile font tables into byte array fontData.Compile(); return fontData; }
/// <summary> /// Reads all required tables from the font data. /// </summary> internal void Read() { try { // Read offset table this.offsetTable.Version = ReadULong(); this.offsetTable.TableCount = ReadUShort(); this.offsetTable.SearchRange = ReadUShort(); this.offsetTable.EntrySelector = ReadUShort(); this.offsetTable.RangeShift = ReadUShort(); // Move to table dictionary at position 12 Debug.Assert(this.pos == 12); //this.tableDictionary = (this.offsetTable.TableCount); // ReSharper disable InconsistentNaming // Determine font technology const uint OTTO = 0x4f54544f; // Adobe OpenType CFF data, tag: 'OTTO' const uint TTCF = 0x74746366; // TrueType Collection tag: 'ttcf' // ReSharper restore InconsistentNaming if (this.offsetTable.Version == TTCF) { this.fontTechnology = FontTechnology.TrueTypeCollection; throw new InvalidOperationException("TrueType collection fonts are not supported by PDFsharp."); } else if (this.offsetTable.Version == OTTO) this.fontTechnology = FontTechnology.PostscriptOutlines; else this.fontTechnology = FontTechnology.TrueTypeOutlines; for (int idx = 0; idx < this.offsetTable.TableCount; idx++) { TableDirectoryEntry entry = TableDirectoryEntry.ReadFrom(this); this.tableDictionary.Add(entry.Tag, entry); #if VERBOSE Debug.WriteLine(String.Format("Font table: {0}", entry.Tag)); #endif } // PDFlib checks this, but it is not part of the OpenType spec anymore if (this.tableDictionary.ContainsKey("bhed")) throw new NotSupportedException("Bitmap fonts are not supported by PDFsharp."); // Read required tables if (Seek(CMapTable.Tag) != -1) this.cmap = new CMapTable(this); if (Seek(ControlValueTable.Tag) != -1) this.cvt = new ControlValueTable(this); if (Seek(FontProgram.Tag) != -1) this.fpgm = new FontProgram(this); if (Seek(MaximumProfileTable.Tag) != -1) this.maxp = new MaximumProfileTable(this); if (Seek(NameTable.Tag) != -1) this.name = new NameTable(this); if (Seek(FontHeaderTable.Tag) != -1) this.head = new FontHeaderTable(this); if (Seek(HorizontalHeaderTable.Tag) != -1) this.hhea = new HorizontalHeaderTable(this); if (Seek(HorizontalMetricsTable.Tag) != -1) this.hmtx = new HorizontalMetricsTable(this); if (Seek(OS2Table.Tag) != -1) this.os2 = new OS2Table(this); if (Seek(PostScriptTable.Tag) != -1) this.post = new PostScriptTable(this); if (Seek(GlyphDataTable.Tag) != -1) this.glyf = new GlyphDataTable(this); if (Seek(IndexToLocationTable.Tag) != -1) this.loca = new IndexToLocationTable(this); if (Seek(GlyphSubstitutionTable.Tag) != -1) this.gsub = new GlyphSubstitutionTable(this); if (Seek(ControlValueProgram.Tag) != -1) this.prep = new ControlValueProgram(this); } catch (Exception) { GetType(); throw; } }
/// <summary> /// Adds the specified table to this font image. /// </summary> public void AddTable(OpenTypeFontTable fontTable) { if (!CanWrite) throw new InvalidOperationException("Font image cannot be modified."); if (fontTable == null) throw new ArgumentNullException("fontTable"); if (fontTable.fontData == null) { fontTable.fontData = this; } else { Debug.Assert(fontTable.fontData.CanRead); // Create a reference to this font table fontTable = new IRefFontTable(this, fontTable); } //Debug.Assert(fontTable.FontData == null); //fontTable.fontData = this; this.tableDictionary[fontTable.DirectoryEntry.Tag] = fontTable.DirectoryEntry; switch (fontTable.DirectoryEntry.Tag) { case TableTagNames.CMap: this.cmap = fontTable as CMapTable; break; case TableTagNames.Cvt: this.cvt = fontTable as ControlValueTable; break; case TableTagNames.Fpgm: this.fpgm = fontTable as FontProgram; break; case TableTagNames.MaxP: this.maxp = fontTable as MaximumProfileTable; break; case TableTagNames.Name: this.name = fontTable as NameTable; break; case TableTagNames.Head: this.head = fontTable as FontHeaderTable; break; case TableTagNames.HHea: this.hhea = fontTable as HorizontalHeaderTable; break; case TableTagNames.HMtx: this.hmtx = fontTable as HorizontalMetricsTable; break; case TableTagNames.OS2: this.os2 = fontTable as OS2Table; break; case TableTagNames.Post: this.post = fontTable as PostScriptTable; break; case TableTagNames.Glyf: this.glyf = fontTable as GlyphDataTable; break; case TableTagNames.Loca: this.loca = fontTable as IndexToLocationTable; break; case TableTagNames.GSUB: this.gsub = fontTable as GlyphSubstitutionTable; break; case TableTagNames.Prep: this.prep = fontTable as ControlValueProgram; break; } }