/// <summary> /// Reads indexed string data. /// </summary> private static string[] ReadStringIndex(CompactFontFormatData data) { var index = CompactFontFormatIndexReader.ReadIndex(data); if (index.Length == 0) { return(EmptyArray <string> .Instance); } var count = index.Length - 1; var result = new string[count]; for (var i = 0; i < count; i++) { var length = index[i + 1] - index[i]; if (length < 0) { throw new InvalidOperationException($"Negative object length {length} at {i}. Current position: {data.Position}."); } result[i] = data.ReadString(length, OtherEncodings.Iso88591); } return(result); }
public static CompactFontFormatIndex ReadDictionaryData(CompactFontFormatData data) { var index = ReadIndex(data); if (index.Length == 0) { return(new CompactFontFormatIndex(null)); } var count = index.Length - 1; var results = new byte[count][]; for (var i = 0; i < count; i++) { var length = index[i + 1] - index[i]; if (length < 0) { throw new InvalidOperationException($"Negative object length {length} at {i}. Current position: {data.Position}."); } if (length > data.Length) { throw new InvalidOperationException($"Attempted to read data of length {length} in data array of length {data.Length}."); } results[i] = data.ReadBytes(length); } return(new CompactFontFormatIndex(results)); }
private static CompactFontFormatFormat1Encoding ReadFormat1Encoding(CompactFontFormatData data, ICompactFontFormatCharset charset, IReadOnlyList <string> stringIndex, byte format) { var numberOfRanges = data.ReadCard8(); var fromRanges = new List <(int code, int sid, string str)>(); var gid = 1; for (var i = 0; i < numberOfRanges; i++) { int rangeFirst = data.ReadCard8(); int rangeLeft = data.ReadCard8(); for (var j = 0; j < 1 + rangeLeft; j++) { var sid = charset.GetStringIdByGlyphId(gid); var code = rangeFirst + j; var str = ReadString(sid, stringIndex); fromRanges.Add((code, sid, str)); gid++; } } IReadOnlyList <CompactFontFormatBuiltInEncoding.Supplement> supplements = new List <CompactFontFormatBuiltInEncoding.Supplement>(); if (HasSupplement(format)) { supplements = ReadSupplement(data, stringIndex); } return(new CompactFontFormatFormat1Encoding(numberOfRanges, fromRanges, supplements)); }
public static Encoding ReadEncoding(CompactFontFormatData data, ICompactFontFormatCharset charset, IReadOnlyList <string> stringIndex) { if (data == null) { throw new ArgumentNullException(nameof(data)); } var format = data.ReadCard8(); // A few fonts have multiply encoded glyphs which are indicated by setting the high order bit of the format byte. // To get the real format out & with 0111 1111 (0x7f). var baseFormat = format & 0x7f; switch (baseFormat) { case 0: return(ReadFormat0Encoding(data, charset, stringIndex, format)); case 1: return(ReadFormat1Encoding(data, charset, stringIndex, format)); default: throw new InvalidFontFormatException($"The provided format {format} for this Compact Font Format encoding was invalid."); } }
public void Parse(CompactFontFormatData data, string name, byte[] topDictionaryIndex, string[] stringIndex) { var individualData = new CompactFontFormatData(topDictionaryIndex); var dictionary = topLevelDictionaryReader.Read(individualData, stringIndex); var privateDictionary = new CompactFontFormatPrivateDictionary(); if (dictionary.PrivateDictionarySizeAndOffset.Item2 >= 0) { data.Seek(dictionary.PrivateDictionarySizeAndOffset.Item2); privateDictionary = privateDictionaryReader.Read(data, stringIndex); } if (dictionary.CharSetOffset >= 0) { } if (dictionary.CharStringsOffset >= 0) { data.Seek(dictionary.CharStringsOffset); var index = indexReader.ReadDictionaryData(data); } }
private static CompactFontFormatHeader ReadHeader(CompactFontFormatData data) { var major = data.ReadCard8(); var minor = data.ReadCard8(); var headerSize = data.ReadCard8(); var offsetSize = data.ReadOffsize(); return(new CompactFontFormatHeader(major, minor, headerSize, offsetSize)); }
private static ICompactFontFormatCharset ReadCharset(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topDictionary, CompactFontFormatIndex charStringIndex, IReadOnlyList <string> stringIndex) { data.Seek(topDictionary.CharSetOffset); var format = data.ReadCard8(); switch (format) { case 0: { var glyphToNamesAndStringId = new List <(int glyphId, int stringId, string name)>(); for (var glyphId = 1; glyphId < charStringIndex.Count; glyphId++) { var stringId = data.ReadSid(); glyphToNamesAndStringId.Add((glyphId, stringId, ReadString(stringId, stringIndex))); } return(new CompactFontFormatFormat0Charset(glyphToNamesAndStringId)); } case 1: case 2: { var glyphToNamesAndStringId = new List <(int glyphId, int stringId, string name)>(); for (var glyphId = 1; glyphId < charStringIndex.Count; glyphId++) { var firstSid = data.ReadSid(); var numberInRange = format == 1 ? data.ReadCard8() : data.ReadCard16(); glyphToNamesAndStringId.Add((glyphId, firstSid, ReadString(firstSid, stringIndex))); for (var i = 0; i < numberInRange; i++) { glyphId++; var sid = firstSid + i + 1; glyphToNamesAndStringId.Add((glyphId, sid, ReadString(sid, stringIndex))); } } if (format == 1) { return(new CompactFontFormatFormat1Charset(glyphToNamesAndStringId)); } return(new CompactFontFormatFormat2Charset(glyphToNamesAndStringId)); } default: throw new InvalidOperationException($"Unrecognized format for the Charset table in a CFF font. Got: {format}."); } }
private static CompactFontFormat0FdSelect ReadFormat0FdSelect(CompactFontFormatData data, int numberOfGlyphs, RegistryOrderingSupplement registryOrderingSupplement) { var dictionaries = new int[numberOfGlyphs]; for (var i = 0; i < numberOfGlyphs; i++) { dictionaries[i] = data.ReadCard8(); } return(new CompactFontFormat0FdSelect(registryOrderingSupplement, dictionaries)); }
public int[] ReadIndex(CompactFontFormatData data) { var count = data.ReadCard16(); var offsetSize = data.ReadOffsize(); var offsets = new int[count + 1]; for (var i = 0; i < offsets.Length; i++) { offsets[i] = data.ReadOffset(offsetSize); } return(offsets); }
private static CompactFontFormat3FdSelect ReadFormat3FdSelect(CompactFontFormatData data, RegistryOrderingSupplement registryOrderingSupplement) { var numberOfRanges = data.ReadCard16(); var ranges = new CompactFontFormat3FdSelect.Range3[numberOfRanges]; for (var i = 0; i < numberOfRanges; i++) { var first = data.ReadCard16(); var dictionary = data.ReadCard8(); ranges[i] = new CompactFontFormat3FdSelect.Range3(first, dictionary); } var sentinel = data.ReadCard16(); return(new CompactFontFormat3FdSelect(registryOrderingSupplement, ranges, sentinel)); }
/// <summary> /// Read the Compact Font Format font from the input data. /// </summary> public static CompactFontFormatFontCollection Parse(CompactFontFormatData data) { var tag = ReadTag(data); switch (tag) { // An OpenType font containing CFF data. case TagOtto: throw new NotSupportedException("Currently tagged CFF data is not supported."); case TagTtcf: throw new NotSupportedException("True Type Collection fonts are not currently supported."); case TagTtfonly: throw new NotSupportedException("OpenType fonts containing a true type font are not currently supported."); default: data.Seek(0); break; } var header = ReadHeader(data); var fontNames = ReadStringIndex(data); var topLevelDictionaryIndex = CompactFontFormatIndexReader.ReadDictionaryData(data); var stringIndex = ReadStringIndex(data); var globalSubroutineIndex = CompactFontFormatIndexReader.ReadDictionaryData(data); var fonts = new Dictionary <string, CompactFontFormatFont>(); var individualFontParser = new CompactFontFormatIndividualFontParser(new CompactFontFormatTopLevelDictionaryReader(), new CompactFontFormatPrivateDictionaryReader()); for (var i = 0; i < fontNames.Length; i++) { var fontName = fontNames[i]; fonts[fontName] = individualFontParser.Parse(data, fontName, topLevelDictionaryIndex[i], stringIndex, globalSubroutineIndex); } return(new CompactFontFormatFontCollection(header, fonts)); }
private static Type2CharStrings ReadCharStrings(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topDictionary, CompactFontFormatIndex charStringIndex, CompactFontFormatSubroutinesSelector subroutinesSelector, ICompactFontFormatCharset charset) { data.Seek(topDictionary.CharStringsOffset); switch (topDictionary.CharStringType) { case CompactFontFormatCharStringType.Type1: throw new NotImplementedException("Type 1 CharStrings are not currently supported in CFF font."); case CompactFontFormatCharStringType.Type2: return(Type2CharStringParser.Parse(charStringIndex, subroutinesSelector, charset)); default: throw new ArgumentOutOfRangeException($"Unexpected CharString type in CFF font: {topDictionary.CharStringType}."); } }
public static int[] ReadIndex(CompactFontFormatData data) { var count = data.ReadCard16(); if (count == 0) { return(EmptyArray <int> .Instance); } var offsetSize = data.ReadOffsize(); var offsets = new int[count + 1]; for (var i = 0; i < offsets.Length; i++) { offsets[i] = data.ReadOffset(offsetSize); } return(offsets); }
public byte[][] ReadDictionaryData(CompactFontFormatData data) { var index = ReadIndex(data); var count = index.Length - 1; var results = new byte[count][]; for (var i = 0; i < count; i++) { var length = index[i + 1] - index[i]; if (length < 0) { throw new InvalidOperationException($"Negative object length {length} at {i}. Current position: {data.Position}."); } results[i] = data.ReadBytes(length); } return(results); }
private static CompactFontFormatFormat0Encoding ReadFormat0Encoding(CompactFontFormatData data, ICompactFontFormatCharset charset, IReadOnlyList <string> stringIndex, byte format) { var numberOfCodes = data.ReadCard8(); var values = new List <(int code, int sid, string str)>(); for (var i = 1; i <= numberOfCodes; i++) { var code = data.ReadCard8(); var sid = charset.GetStringIdByGlyphId(i); var str = ReadString(sid, stringIndex); values.Add((code, sid, str)); } IReadOnlyList <CompactFontFormatBuiltInEncoding.Supplement> supplements = new List <CompactFontFormatBuiltInEncoding.Supplement>(); if (HasSupplement(format)) { supplements = ReadSupplement(data, stringIndex); } return(new CompactFontFormatFormat0Encoding(values, supplements)); }
public void Parse(CompactFontFormatData data) { var tag = ReadTag(data); switch (tag) { case TagOtto: throw new NotImplementedException("Currently tagged CFF data is not supported."); case TagTtcf: throw new NotSupportedException("True Type Collection fonts are not supported."); case TagTtfonly: throw new NotSupportedException("OpenType fonts containing a true type font are not supported."); default: data.Seek(0); break; } var header = ReadHeader(data); var fontNames = ReadStringIndex(data); var topLevelDict = indexReader.ReadDictionaryData(data); var stringIndex = ReadStringIndex(data); var globalSubroutineIndex = indexReader.ReadDictionaryData(data); for (var i = 0; i < fontNames.Length; i++) { var fontName = fontNames[i]; individualFontParser.Parse(data, fontName, topLevelDict[i], stringIndex); } }
public CompactFontFormatFont Parse(CompactFontFormatData data, string name, IReadOnlyList <byte> topDictionaryIndex, IReadOnlyList <string> stringIndex, CompactFontFormatIndex globalSubroutineIndex) { var individualData = new CompactFontFormatData(topDictionaryIndex.ToArray()); var topDictionary = topLevelDictionaryReader.Read(individualData, stringIndex); var privateDictionary = CompactFontFormatPrivateDictionary.GetDefault(); if (topDictionary.PrivateDictionaryLocation.HasValue && topDictionary.PrivateDictionaryLocation.Value.Size > 0) { var privateDictionaryBytes = data.SnapshotPortion(topDictionary.PrivateDictionaryLocation.Value.Offset, topDictionary.PrivateDictionaryLocation.Value.Size); privateDictionary = privateDictionaryReader.Read(privateDictionaryBytes, stringIndex); } if (topDictionary.CharStringsOffset < 0) { throw new InvalidOperationException("Expected CFF to contain a CharString offset."); } var localSubroutines = CompactFontFormatIndex.None; if (privateDictionary.LocalSubroutineOffset.HasValue && topDictionary.PrivateDictionaryLocation.HasValue) { data.Seek(privateDictionary.LocalSubroutineOffset.Value + topDictionary.PrivateDictionaryLocation.Value.Offset); localSubroutines = CompactFontFormatIndexReader.ReadDictionaryData(data); } data.Seek(topDictionary.CharStringsOffset); var charStringIndex = CompactFontFormatIndexReader.ReadDictionaryData(data); ICompactFontFormatCharset charset; if (topDictionary.CharSetOffset >= 0) { var charsetId = topDictionary.CharSetOffset; if (!topDictionary.IsCidFont && charsetId == 0) { charset = CompactFontFormatIsoAdobeCharset.Value; } else if (!topDictionary.IsCidFont && charsetId == 1) { charset = CompactFontFormatExpertCharset.Value; } else if (!topDictionary.IsCidFont && charsetId == 2) { charset = CompactFontFormatExpertSubsetCharset.Value; } else { charset = ReadCharset(data, topDictionary, charStringIndex, stringIndex); } } else { if (topDictionary.IsCidFont) { // a CID font with no charset does not default to any predefined charset charset = new CompactFontFormatEmptyCharset(charStringIndex.Count); } else { charset = CompactFontFormatIsoAdobeCharset.Value; } } if (topDictionary.IsCidFont) { return(ReadCidFont(data, topDictionary, charStringIndex.Count, stringIndex, privateDictionary, charset, globalSubroutineIndex, localSubroutines, charStringIndex)); } var encoding = topDictionary.EncodingOffset; Encoding fontEncoding = null; if (encoding != CompactFontFormatTopLevelDictionary.UnsetOffset) { if (encoding == 0) { fontEncoding = CompactFontFormatStandardEncoding.Instance; } else if (encoding == 1) { fontEncoding = CompactFontFormatExpertEncoding.Instance; } else { data.Seek(encoding); fontEncoding = CompactFontFormatEncodingReader.ReadEncoding(data, charset, stringIndex); } } var subroutineSelector = new CompactFontFormatSubroutinesSelector(globalSubroutineIndex, localSubroutines); var charStrings = ReadCharStrings(data, topDictionary, charStringIndex, subroutineSelector, charset); return(new CompactFontFormatFont(topDictionary, privateDictionary, charset, Union <Type1CharStrings, Type2CharStrings> .Two(charStrings), fontEncoding)); }
private CompactFontFormatCidFont ReadCidFont(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topLevelDictionary, int numberOfGlyphs, IReadOnlyList <string> stringIndex, CompactFontFormatPrivateDictionary privateDictionary, ICompactFontFormatCharset charset, CompactFontFormatIndex globalSubroutines, CompactFontFormatIndex localSubroutinesTop, CompactFontFormatIndex charStringIndex) { var offset = topLevelDictionary.CidFontOperators.FontDictionaryArray; data.Seek(offset); var fontDict = CompactFontFormatIndexReader.ReadDictionaryData(data); var privateDictionaries = new List <CompactFontFormatPrivateDictionary>(); var fontDictionaries = new List <CompactFontFormatTopLevelDictionary>(); var fontLocalSubroutines = new List <CompactFontFormatIndex>(); foreach (var index in fontDict) { var topLevelDictionaryCid = topLevelDictionaryReader.Read(new CompactFontFormatData(index), stringIndex); if (!topLevelDictionaryCid.PrivateDictionaryLocation.HasValue) { throw new InvalidFontFormatException("The CID keyed Compact Font Format font did not contain a private dictionary for the font dictionary."); } var privateDictionaryBytes = data.SnapshotPortion(topLevelDictionaryCid.PrivateDictionaryLocation.Value.Offset, topLevelDictionaryCid.PrivateDictionaryLocation.Value.Size); var privateDictionaryCid = privateDictionaryReader.Read(privateDictionaryBytes, stringIndex); // CFFParser.java line 625 - read the local subroutines. if (privateDictionaryCid.LocalSubroutineOffset.HasValue && privateDictionaryCid.LocalSubroutineOffset.Value > 0) { data.Seek(topLevelDictionaryCid.PrivateDictionaryLocation.Value.Offset + privateDictionaryCid.LocalSubroutineOffset.Value); var localSubroutines = CompactFontFormatIndexReader.ReadDictionaryData(data); fontLocalSubroutines.Add(localSubroutines); } else { fontLocalSubroutines.Add(null); } fontDictionaries.Add(topLevelDictionaryCid); privateDictionaries.Add(privateDictionaryCid); } data.Seek(topLevelDictionary.CidFontOperators.FontDictionarySelect); var format = data.ReadCard8(); ICompactFontFormatFdSelect fdSelect; switch (format) { case 0: { fdSelect = ReadFormat0FdSelect(data, numberOfGlyphs, topLevelDictionary.CidFontOperators.Ros); break; } case 3: { fdSelect = ReadFormat3FdSelect(data, topLevelDictionary.CidFontOperators.Ros); break; } default: throw new InvalidFontFormatException($"Invalid Font Dictionary Select format: {format}."); } var subroutineSelector = new CompactFontFormatSubroutinesSelector(globalSubroutines, localSubroutinesTop, fdSelect, fontLocalSubroutines); var charStrings = ReadCharStrings(data, topLevelDictionary, charStringIndex, subroutineSelector, charset); var union = Union <Type1CharStrings, Type2CharStrings> .Two(charStrings); return(new CompactFontFormatCidFont(topLevelDictionary, privateDictionary, charset, union, fontDictionaries, privateDictionaries, fdSelect)); }
private static IReadOnlyList <CompactFontFormatBuiltInEncoding.Supplement> ReadSupplement(CompactFontFormatData dataInput, IReadOnlyList <string> stringIndex) { var numberOfSupplements = dataInput.ReadCard8(); var supplements = new CompactFontFormatBuiltInEncoding.Supplement[numberOfSupplements]; for (var i = 0; i < supplements.Length; i++) { var code = dataInput.ReadCard8(); var sid = dataInput.ReadSid(); var name = ReadString(sid, stringIndex); supplements[i] = new CompactFontFormatBuiltInEncoding.Supplement(code, sid, name); } return(supplements); }
public CompactFontFormatFont Parse(CompactFontFormatData data, string name, IReadOnlyList <byte> topDictionaryIndex, IReadOnlyList <string> stringIndex, CompactFontFormatIndex globalSubroutineIndex) { var individualData = new CompactFontFormatData(topDictionaryIndex.ToArray()); var topDictionary = topLevelDictionaryReader.Read(individualData, stringIndex); var privateDictionary = CompactFontFormatPrivateDictionary.GetDefault(); if (topDictionary.PrivateDictionaryLocation.HasValue) { var privateDictionaryBytes = data.SnapshotPortion(topDictionary.PrivateDictionaryLocation.Value.Offset, topDictionary.PrivateDictionaryLocation.Value.Size); privateDictionary = privateDictionaryReader.Read(privateDictionaryBytes, stringIndex); } if (topDictionary.CharStringsOffset < 0) { throw new InvalidOperationException("Expected CFF to contain a CharString offset."); } var localSubroutines = CompactFontFormatIndex.None; if (privateDictionary.LocalSubroutineOffset.HasValue && topDictionary.PrivateDictionaryLocation.HasValue) { data.Seek(privateDictionary.LocalSubroutineOffset.Value + topDictionary.PrivateDictionaryLocation.Value.Offset); localSubroutines = indexReader.ReadDictionaryData(data); } data.Seek(topDictionary.CharStringsOffset); var charStringIndex = indexReader.ReadDictionaryData(data); ICompactFontFormatCharset charset = null; if (topDictionary.IsCidFont && topDictionary.CharSetOffset >= 0 && topDictionary.CharSetOffset <= 2) { switch (topDictionary.CharSetOffset) { case 0: charset = CompactFontFormatIsoAdobeCharset.Value; break; case 1: charset = CompactFontFormatExpertCharset.Value; break; case 2: charset = CompactFontFormatExpertSubsetCharset.Value; break; } } else { data.Seek(topDictionary.CharSetOffset); var format = data.ReadCard8(); switch (format) { case 0: { var glyphToNamesAndStringId = new List <(int glyphId, int stringId, string name)>(); for (var glyphId = 1; glyphId < charStringIndex.Count; glyphId++) { var stringId = data.ReadSid(); glyphToNamesAndStringId.Add((glyphId, stringId, ReadString(stringId, stringIndex))); } charset = new CompactFontFormatFormat0Charset(glyphToNamesAndStringId); break; } case 1: case 2: { var glyphToNamesAndStringId = new List <(int glyphId, int stringId, string name)>(); for (var glyphId = 1; glyphId < charStringIndex.Count; glyphId++) { var firstSid = data.ReadSid(); var numberInRange = format == 1 ? data.ReadCard8() : data.ReadCard16(); glyphToNamesAndStringId.Add((glyphId, firstSid, ReadString(firstSid, stringIndex))); for (var i = 0; i < numberInRange; i++) { glyphId++; var sid = firstSid + i + 1; glyphToNamesAndStringId.Add((glyphId, sid, ReadString(sid, stringIndex))); } } if (format == 1) { charset = new CompactFontFormatFormat1Charset(glyphToNamesAndStringId); } else { charset = new CompactFontFormatFormat2Charset(glyphToNamesAndStringId); } break; } default: throw new InvalidOperationException($"Unrecognized format for the Charset table in a CFF font. Got: {format}."); } } data.Seek(topDictionary.CharStringsOffset); Type2CharStrings charStrings; switch (topDictionary.CharStringType) { case CompactFontFormatCharStringType.Type1: throw new NotImplementedException(); case CompactFontFormatCharStringType.Type2: charStrings = Type2CharStringParser.Parse(charStringIndex, localSubroutines, globalSubroutineIndex, charset); break; default: throw new ArgumentOutOfRangeException($"Unexpected CharString type in CFF font: {topDictionary.CharStringType}."); } return(new CompactFontFormatFont(topDictionary, privateDictionary, charset, Union <Type1CharStrings, Type2CharStrings> .Two(charStrings))); }
private static string ReadTag(CompactFontFormatData data) { var tag = data.ReadString(4, OtherEncodings.Iso88591); return(tag); }