示例#1
0
        // Parses font's offset table and alters OffsetTable object appropriately.
        public OffsetTable ParseOffsetTable(byte[] fontContent)
        {
            OffsetTable offsetTable = new OffsetTable();

            uint offset = 0;

            offsetTable.tag           = ReadDataAndIncreaseIndex(fontContent, ref offset, TagLength);
            offsetTable.numTables     = ReadDataAndIncreaseIndex <ushort>(fontContent, ref offset, sizeof(ushort));
            offsetTable.searchRange   = ReadDataAndIncreaseIndex <ushort>(fontContent, ref offset, sizeof(ushort));
            offsetTable.entrySelector = ReadDataAndIncreaseIndex <ushort>(fontContent, ref offset, sizeof(ushort));
            offsetTable.rangeShift    = ReadDataAndIncreaseIndex <ushort>(fontContent, ref offset, sizeof(ushort));
            start = offset;

            return(offsetTable);
        }
示例#2
0
        // Updates OffsetTable object and the offset table in font to reflect a table being added.
        public OffsetTable UpdateOffsetTable(OffsetTable offsetTable, ref byte[] source)
        {
            OffsetTable newOffsetTable = offsetTable;

            newOffsetTable.numTables += 1;
            byte[] newNumTables = GetBytesBigEndian(offsetTable.numTables);
            int    offsetTableNumTablesOffset = TagLength;                                   // Advance past the initial tag of the offset table.

            Array.Copy(newNumTables, 0, source, offsetTableNumTablesOffset, sizeof(ushort)); // Overwrite numTables with numTables + 1.

            // Calculate searchRange, entrySelector and rangeShift as outlined in the Offset Table section of the OpenType spec.
            ushort searchRange = 1, entrySelector = 0;

            while ((searchRange << 1) < offsetTable.numTables)
            {
                searchRange <<= 1;
                entrySelector++;
            }
            searchRange <<= 4; // multiply by 16
            newOffsetTable.searchRange   = searchRange;
            newOffsetTable.entrySelector = entrySelector;
            newOffsetTable.rangeShift    = (ushort)((offsetTable.numTables * 16) - offsetTable.searchRange);
            byte[] newSearchRange   = GetBytesBigEndian(offsetTable.searchRange);
            byte[] newEntrySelector = GetBytesBigEndian(offsetTable.entrySelector);
            byte[] newRangeShift    = GetBytesBigEndian(offsetTable.rangeShift);

            // Write the newly calculated values of searchRange, entrySelector and rangeShift to source.
            int sourceIndex = sizeof(uint) + sizeof(ushort);

            Array.Copy(newSearchRange, 0, source, sourceIndex, sizeof(ushort));
            sourceIndex += sizeof(ushort);
            Array.Copy(newEntrySelector, 0, source, sourceIndex, sizeof(ushort));
            sourceIndex += sizeof(ushort);
            Array.Copy(newRangeShift, 0, source, sourceIndex, sizeof(ushort));
            return(newOffsetTable);
        }
示例#3
0
        public async Task LoadDataAsync(StorageFile file)
        {
            parser.Start   = 0;
            parser.Current = 0;

            FontFileName = file.Name;

            // Read contents of file and return a buffer.
            IBuffer buffer = await FileIO.ReadBufferAsync(file);

            source = new byte[buffer.Length];

            // Put buffer byte info into source.
            using (DataReader reader = DataReader.FromBuffer(buffer))
            {
                reader.ReadBytes(source);
            }

            offsetTable = parser.ParseOffsetTable(source);

            TableRecords = new TableRecord[offsetTable.numTables];

            for (int i = 0; i < TableRecords.Length; i++)
            {
                TableRecords[i] = parser.ReadTableRecord(source);
            }

            // Create a temporary list to contain the updated GlyphModel objects.
            List <GlyphModel> tempList = new List <GlyphModel>();

            foreach (TableRecord record in TableRecords)
            {
                if (record.tag == "cmap")
                {
                    // Only supports cmap tables of format 0 or format 4.
                    foreach (GlyphModel currentGlyph in parser.ParseCMap(record, source))
                    {
                        // If codepoint matches known whitespace, do not append to preview list.
                        uint codepoint = currentGlyph.CodePoint;
                        if (0x0 <= codepoint && codepoint <= 0x001F || 0x7F <= codepoint && codepoint <= 0xA0 || 0x2000 <= codepoint && codepoint <= 0x200F ||
                            codepoint == 0x202F || codepoint == 0x205F || codepoint == 0x3000 || codepoint == 0xFEFF || codepoint == 0x20)
                        {
                            continue;
                        }
                        else
                        {
                            tempList.Add(currentGlyph);
                        }
                    }
                }
                else if (record.tag == "name")
                {
                    FamilyName = parser.GetFamilyName(record, source);

                    // If no FamilyName is found, do not load the font.
                    if (FamilyName == null)
                    {
                        return;
                    }
                }
            }

            // Create local font saved in temp folder.
            LocalFont = "ms-appdata:///temp/" + FontFileName + "#" + FamilyName;

            // Assign local font to each GlyphModel.
            foreach (GlyphModel glyph in tempList)
            {
                glyph.FontFamily = LocalFont;
            }

            // Repopulate the list of all GlyphModel objects.
            AllGlyphs.Clear();
            foreach (GlyphModel glyph in tempList)
            {
                AllGlyphs.Add(glyph);
            }
        }
示例#4
0
        public async Task AddSvgAsync(ushort glyphID, StorageFile svgFile)
        {
            // Add SVG data into a buffer.
            IBuffer buffer = await FileIO.ReadBufferAsync(svgFile);

            byte[] svgContent = new byte[buffer.Length];

            // Read buffer into bytes in svgContent.
            using (DataReader reader = DataReader.FromBuffer(buffer))
            {
                reader.ReadBytes(svgContent);
            }

            // Tweak the SVG: Add glyph ID and adjust the X/Y origin in accordance with OpenType spec.
            ChangeSvgOriginID(ref svgContent, glyphID);

            for (int i = 0; i < TableRecords.Length; i++)
            {
                if (TableRecords[i].tag == "SVG ")
                {
                    parser.AssembleSvgContent(ref TableRecords[i], ref source, svgContent, glyphID, this);
                    break;
                }
                // Checks if SVG table is not present
                else if (String.Compare(TableRecords[i].tag, "SVG ", StringComparison.Ordinal) > 0)
                {
                    // Changes offset table to reflect the addition of a new table
                    offsetTable = parser.UpdateOffsetTable(offsetTable, ref source);
                    // Changes the offsets contained in all of the table records in order to reflect the addition of a table record
                    parser.ChangeTableRecOffsets(TableRecords, ref source, ((sizeof(uint) * 4) * -1), 0);
                    byte[] newSource = new byte[source.Length + (sizeof(uint) * 6) + (sizeof(ushort) * 2)];
                    // Copies from the beginning of the source array to the end of the table record preceeding the location of the new SVG table record
                    Array.Copy(source, 0, newSource, 0, (int)(TableRecords[i].offsetOfOffset - (sizeof(uint) * 2)));
                    string tag    = "SVG ";
                    byte[] svgTag = Encoding.ASCII.GetBytes((string)tag);
                    // Adds SVG tag for the table record
                    Array.Copy(svgTag, 0, newSource, (int)(TableRecords[i].offsetOfOffset - (sizeof(uint) * 2)), sizeof(uint));
                    byte[] checksum = BitConverter.GetBytes((uint)0);
                    Array.Reverse(checksum);
                    // Adds the checksum for the table record
                    Array.Copy(checksum, 0, newSource, (int)(TableRecords[i].offsetOfOffset - sizeof(uint)), sizeof(uint));
                    byte[] offset = BitConverter.GetBytes((uint)(source.Length + (sizeof(uint) * 4)));
                    Array.Reverse(offset);
                    // Adds the offset for the table record
                    Array.Copy(offset, 0, newSource, (int)(TableRecords[i].offsetOfOffset), sizeof(uint));
                    byte[] length = BitConverter.GetBytes((uint)((sizeof(ushort) + sizeof(uint)) * 2));
                    Array.Reverse(length);
                    // Adds the length for the table record
                    Array.Copy(length, 0, newSource, (int)(TableRecords[i].offsetOfOffset + sizeof(uint)), sizeof(uint));
                    // Copies from the beginning of the table record following the new SVG table record in the source array to the end of the source array
                    Array.Copy(source, (int)(TableRecords[i].offsetOfOffset - (sizeof(uint) * 2)), newSource, (int)(TableRecords[i].offsetOfOffset + (sizeof(uint) * 2)), (int)(source.Length - (TableRecords[i].offsetOfOffset - (sizeof(uint) * 2))));
                    byte[] version = BitConverter.GetBytes((ushort)0);
                    Array.Reverse(version);
                    // Adds the SVG table at the very end of the font file
                    // Copies the version number to the newSource array (0)
                    Array.Copy(version, 0, newSource, (int)(source.Length + (sizeof(uint) * 4)), sizeof(ushort));
                    byte[] svgDocIndexOffset = BitConverter.GetBytes((uint)(sizeof(ushort) + (sizeof(uint) * 2)));
                    Array.Reverse(svgDocIndexOffset);
                    // Copies the SVG Document Index Offset to the newSource array
                    Array.Copy(svgDocIndexOffset, 0, newSource, (int)(source.Length + (sizeof(uint) * 4) + sizeof(ushort)), sizeof(uint));
                    byte[] reserved = BitConverter.GetBytes((uint)0);
                    Array.Reverse(reserved);
                    // Copies reserved to th enewSource array
                    Array.Copy(reserved, 0, newSource, (int)(source.Length + (sizeof(uint) * 5) + sizeof(ushort)), sizeof(uint));
                    byte[] numEntries = BitConverter.GetBytes((ushort)0);
                    Array.Reverse(numEntries);
                    // Copies the number of SVG Document Index Entries to the newSource array (in this case just 0 because it is a new table)
                    Array.Copy(numEntries, 0, newSource, (int)(source.Length + (sizeof(uint) * 6) + sizeof(ushort)), sizeof(ushort));
                    TableRecord svg = new TableRecord();
                    svg.tag            = "SVG ";
                    svg.checksum       = 0;
                    svg.offsetOfOffset = TableRecords[i].offsetOfOffset;
                    svg.offset         = (uint)(source.Length + (sizeof(uint) * 4));
                    svg.length         = (uint)((sizeof(ushort) + sizeof(uint)) * 2);
                    source             = newSource;
                    parser.Start       = 12; // Start is 12 because the offset table is always before the table records and is always 12 bytes in length
                    parser.Current     = 12;

                    TableRecords = new TableRecord[offsetTable.numTables];
                    for (int j = 0; j < TableRecords.Length; j++)
                    {
                        TableRecords[j] = parser.ReadTableRecord(source);
                    }
                    parser.AssembleSvgContent(ref svg, ref source, svgContent, glyphID, this);
                    break;
                }
            }

            // Create an updated font file in temp folder.
            StorageFolder tempFolder  = ApplicationData.Current.TemporaryFolder;
            StorageFile   newFontFile = await tempFolder.CreateFileAsync(FontFileName, CreationCollisionOption.GenerateUniqueName);

            await FileIO.WriteBytesAsync(newFontFile, source);

            // Hang on to the new font file.
            temporaryFontFile = newFontFile;
        }