예제 #1
0
        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
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
        }
예제 #8
0
        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));
        }
예제 #9
0
        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);
        }