private static void ReadSimpleGlyph(TrueTypeDataBytes data, int numberOfContours) { bool HasFlag(SimpleGlyphFlags flags, SimpleGlyphFlags value) { return((flags & value) != 0); } if (numberOfContours == 0) { return; } var endPointsOfContours = new ushort[numberOfContours]; for (var i = 0; i < numberOfContours; i++) { endPointsOfContours[i] = data.ReadUnsignedShort(); } var instructionLength = data.ReadUnsignedShort(); var instructions = new byte[instructionLength]; for (var i = 0; i < instructionLength; i++) { instructions[i] = data.ReadByte(); } var lastPointIndex = endPointsOfContours[numberOfContours - 1]; var pointCount = lastPointIndex + 1; var perPointFlags = new SimpleGlyphFlags[pointCount]; for (var i = 0; i < pointCount; i++) { var flags = (SimpleGlyphFlags)data.ReadByte(); perPointFlags[i] = flags; if (!HasFlag(flags, SimpleGlyphFlags.Repeat)) { continue; } var numberOfRepeats = data.ReadByte(); for (var r = 0; r < numberOfRepeats; r++) { i++; perPointFlags[i] = flags; } } // ReSharper disable UnusedVariable var xCoordinates = ReadCoordinates(perPointFlags, data, SimpleGlyphFlags.XSingleByte, SimpleGlyphFlags.ThisXIsTheSame); var yCoordinates = ReadCoordinates(perPointFlags, data, SimpleGlyphFlags.YSingleByte, SimpleGlyphFlags.ThisYIsTheSame); // ReSharper restore UnusedVariable }
private static IReadOnlyList <CompositeGlyphIndexReference> ReadCompositeGlyph(TrueTypeDataBytes data) { bool HasFlag(CompositeGlyphFlags actual, CompositeGlyphFlags value) { return((actual & value) != 0); } var glyphIndices = new List <CompositeGlyphIndexReference>(); CompositeGlyphFlags flags; do { flags = (CompositeGlyphFlags)data.ReadUnsignedShort(); var indexOffset = data.Position; var glyphIndex = data.ReadUnsignedShort(); glyphIndices.Add(new CompositeGlyphIndexReference(glyphIndex, (uint)indexOffset)); if (HasFlag(flags, CompositeGlyphFlags.Args1And2AreWords)) { data.ReadSignedShort(); data.ReadSignedShort(); } else { data.ReadByte(); data.ReadByte(); } if (HasFlag(flags, CompositeGlyphFlags.WeHaveAScale)) { data.ReadSignedShort(); } else if (HasFlag(flags, CompositeGlyphFlags.WeHaveAnXAndYScale)) { data.ReadSignedShort(); data.ReadSignedShort(); } else if (HasFlag(flags, CompositeGlyphFlags.WeHaveATwoByTwo)) { data.ReadSignedShort(); data.ReadSignedShort(); data.ReadSignedShort(); data.ReadSignedShort(); } } while (HasFlag(flags, CompositeGlyphFlags.MoreComponents)); // TODO: Read hinting instructions (PDFBox GlyfCompositeDescript.java line 76). return(glyphIndices); }
private static short[] ReadCoordinates(TrueTypeDataBytes data, int pointCount, SimpleGlyphFlags[] flags, SimpleGlyphFlags isByte, SimpleGlyphFlags signOrSame) { var xs = new short[pointCount]; var x = 0; for (var i = 0; i < pointCount; i++) { int dx; if (flags[i].HasFlag(isByte)) { var b = data.ReadByte(); dx = flags[i].HasFlag(signOrSame) ? b : -b; } else { if (flags[i].HasFlag(signOrSame)) { dx = 0; } else { dx = data.ReadSignedShort(); } } x += dx; xs[i] = (short)x; } return(xs); }
private static SimpleGlyphFlags[] ReadFlags(TrueTypeDataBytes data, int pointCount) { var result = new SimpleGlyphFlags[pointCount]; for (var i = 0; i < pointCount; i++) { result[i] = (SimpleGlyphFlags)data.ReadByte(); } return(result); }
private static short[] ReadCoordinates(SimpleGlyphFlags[] flags, TrueTypeDataBytes data, SimpleGlyphFlags isSingleByte, SimpleGlyphFlags isTheSameAsPrevious) { bool HasFlag(SimpleGlyphFlags set, SimpleGlyphFlags f) { return((set & f) != 0); } var coordinates = new short[flags.Length]; var value = 0; for (var i = 0; i < flags.Length; i++) { var flag = flags[i]; if (HasFlag(flag, isSingleByte)) { var b = data.ReadByte(); // If SingleByte is set, the IsTheSame flag describes the sign of the value, // with a value of 1 equalling positive and a zero value negative. if (HasFlag(flag, isTheSameAsPrevious)) { value += b; } else { value -= b; } } else { short delta; // If this flag is set, then the current coordinate is the same as the previous coordinate. if (HasFlag(flag, isTheSameAsPrevious)) { delta = 0; } else { // If the IsTheSame flag is not set, the current coordinate is a signed 16-bit delta vector. delta = data.ReadSignedShort(); } value += delta; } coordinates[i] = (short)value; } return(coordinates); }
private static SimpleGlyphFlags[] ReadFlags(TrueTypeDataBytes data, int pointCount) { var result = new SimpleGlyphFlags[pointCount]; for (var i = 0; i < pointCount; i++) { result[i] = (SimpleGlyphFlags)data.ReadByte(); if (result[i].HasFlag(SimpleGlyphFlags.Repeat)) { var numberOfRepeats = data.ReadByte(); for (int j = 0; j < numberOfRepeats; j++) { result[i + j + 1] = result[i]; } i += numberOfRepeats; } } return(result); }
private static short[] ReadCoordinates(TrueTypeDataBytes data, int pointCount, SimpleGlyphFlags[] flags, SimpleGlyphFlags isByte, SimpleGlyphFlags signOrSame) { bool HasFlag(SimpleGlyphFlags value, SimpleGlyphFlags target) { return((value & target) == target); } var xs = new short[pointCount]; var x = 0; for (var i = 0; i < pointCount; i++) { var flag = flags[i]; int dx; if (HasFlag(flag, isByte)) { var b = data.ReadByte(); dx = HasFlag(flag, signOrSame) ? b : -b; } else { if (HasFlag(flag, signOrSame)) { dx = 0; } else { dx = data.ReadSignedShort(); } } x += dx; xs[i] = (short)x; } return(xs); }
private static IGlyphDescription ReadCompositeGlyph(TrueTypeDataBytes data, TemporaryCompositeLocation compositeLocation, Dictionary <int, TemporaryCompositeLocation> compositeLocations, IGlyphDescription[] glyphs, IGlyphDescription emptyGlyph) { bool HasFlag(CompositeGlyphFlags value, CompositeGlyphFlags target) { return((value & target) == target); } data.Seek(compositeLocation.Position); var components = new List <CompositeComponent>(); // First recursively find all components and ensure they are available. CompositeGlyphFlags flags; do { flags = (CompositeGlyphFlags)data.ReadUnsignedShort(); var glyphIndex = data.ReadUnsignedShort(); var childGlyph = glyphs[glyphIndex]; if (childGlyph == null) { if (!compositeLocations.TryGetValue(glyphIndex, out var missingComposite)) { throw new InvalidOperationException($"The composite glyph required a contour at index {glyphIndex} but there was no simple or composite glyph at this location."); } var position = data.Position; childGlyph = ReadCompositeGlyph(data, missingComposite, compositeLocations, glyphs, emptyGlyph); data.Seek(position); glyphs[glyphIndex] = childGlyph; } short arg1, arg2; if (HasFlag(flags, CompositeGlyphFlags.Args1And2AreWords)) { arg1 = data.ReadSignedShort(); arg2 = data.ReadSignedShort(); } else { arg1 = data.ReadByte(); arg2 = data.ReadByte(); } decimal xscale = 1; decimal scale01 = 0; decimal scale10 = 0; decimal yscale = 1; if (HasFlag(flags, CompositeGlyphFlags.WeHaveAScale)) { xscale = ReadTwoFourteenFormat(data); yscale = xscale; } else if (HasFlag(flags, CompositeGlyphFlags.WeHaveAnXAndYScale)) { xscale = ReadTwoFourteenFormat(data); yscale = ReadTwoFourteenFormat(data); } else if (HasFlag(flags, CompositeGlyphFlags.WeHaveATwoByTwo)) { xscale = ReadTwoFourteenFormat(data); scale01 = ReadTwoFourteenFormat(data); scale10 = ReadTwoFourteenFormat(data); yscale = ReadTwoFourteenFormat(data); } if (HasFlag(flags, CompositeGlyphFlags.ArgsAreXAndYValues)) { components.Add(new CompositeComponent(glyphIndex, new PdfMatrix3By2(xscale, scale01, scale10, yscale, arg1, arg2))); } else { // TODO: Not implemented, it is unclear how to do this. } } while (HasFlag(flags, CompositeGlyphFlags.MoreComponents)); // Now build the final glyph from the components. IGlyphDescription builderGlyph = null; foreach (var component in components) { var glyph = glyphs[component.Index]; var transformed = glyph.Transform(component.Transformation); if (builderGlyph == null) { builderGlyph = transformed; } else { builderGlyph = builderGlyph.Merge(transformed); } } builderGlyph = builderGlyph ?? emptyGlyph; return(new Glyph(false, builderGlyph.Instructions, builderGlyph.EndPointsOfContours, builderGlyph.Points, compositeLocation.Bounds)); }
private static string[] GetFormat2GlyphNames(TrueTypeDataBytes data) { const int reservedIndexStart = 32768; var numberOfGlyphs = data.ReadUnsignedShort(); var glyphNameIndex = new int[numberOfGlyphs]; var glyphNames = new string[numberOfGlyphs]; var maxIndex = int.MinValue; for (var i = 0; i < numberOfGlyphs; i++) { var index = data.ReadUnsignedShort(); glyphNameIndex[i] = index; if (index < reservedIndexStart) { maxIndex = Math.Max(maxIndex, index); } } var nameArray = default(string[]); if (maxIndex >= WindowsGlyphList4.NumberOfMacGlyphs) { var namesLength = maxIndex - WindowsGlyphList4.NumberOfMacGlyphs + 1; nameArray = new string[namesLength]; for (var i = 0; i < namesLength; i++) { var numberOfCharacters = data.ReadByte(); nameArray[i] = data.ReadString(numberOfCharacters, Encoding.UTF8); } } for (int i = 0; i < numberOfGlyphs; i++) { var index = glyphNameIndex[i]; if (index < WindowsGlyphList4.NumberOfMacGlyphs) { glyphNames[i] = WindowsGlyphList4.MacGlyphNames[index]; } else if (index >= WindowsGlyphList4.NumberOfMacGlyphs && index < reservedIndexStart) { if (nameArray == null) { throw new InvalidOperationException("The name array was null despite the number of glyphs exceeding the maximum Mac Glyphs."); } glyphNames[i] = nameArray[index - WindowsGlyphList4.NumberOfMacGlyphs]; } else { glyphNames[i] = ".undefined"; } } return(glyphNames); }