Пример #1
0
        static char DecodeChar(FontHeader header, Dictionary <char, char> charMap, int charIndex)
        {
            int  charValue = (header.FirstAscii + charIndex);
            char fontChar  = (char)charValue;

            char actualChar;

            if (charValue > 0x100)
            {
                if (!charMap.ContainsKey(fontChar))
                {
                    //throw new Exception("Couldn't find char in charlist to decode!");
                    actualChar = fontChar;
                }
                else
                {
                    actualChar = charMap[fontChar];
                }
            }
            else
            {
                if (!charMap.ContainsKey(fontChar))
                {
                    actualChar = fontChar;
                }
                else
                {
                    actualChar = charMap[fontChar];
                }
            }

            return(actualChar);
        }
        public static TTFStringMeasurer Create(TrueTypeFile forfont, CMapEncoding encoding, TypeMeasureOptions options)
        {
            HorizontalMetrics table = forfont.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = forfont.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = forfont.Directories["OS/2"].Table as OS2Table;
            FontHeader        head  = forfont.Directories["head"].Table as FontHeader;
            HorizontalHeader  hhead = forfont.Directories["hhea"].Table as HorizontalHeader;

            CMAPSubTable map = cmap.GetOffsetTable(encoding);

            if (map == null)
            {
                encoding = CMapEncoding.Unicode_20;
                map      = cmap.GetOffsetTable(CMapEncoding.Unicode_20);
            }

            if (map == null)
            {
                encoding = CMapEncoding.MacRoman;
                map      = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }



            return(new TTFStringMeasurer(head.UnitsPerEm, map, os2, hhead, table.HMetrics, forfont, encoding, options));
        }
Пример #3
0
        public static object Read(Stream stream)
        {
            // read the header
            FontHeader hdr = stream.ReadStruct <FontHeader>();

            if (hdr.sig0 != 0x0500 || hdr.sig1 != 0x000E)
            {
                throw new Exception("Invalid font file");
            }

            // allocate the buffers
            var nchars = 1 + hdr.nchars;
            var cofs   = new ushort[nchars];
            var glyphs = new byte[256][];
            var gdata  = new GlyphData[256];

            // glyph offsets
            stream.Seek(hdr.cofs, SeekOrigin.Begin);
            stream.ReadStructs <ushort>(cofs, nchars);

            // widths
            stream.Seek(hdr.wpos, SeekOrigin.Begin);
            for (var i = 0; i < nchars; i++)
            {
                gdata[i].width = (byte)stream.ReadByte();
            }

            // heights
            stream.Seek(hdr.hpos, SeekOrigin.Begin);
            for (var i = 0; i < nchars; i++)
            {
                gdata[i].yoffset = (byte)stream.ReadByte();
                gdata[i].height  = (byte)stream.ReadByte();
            }

            // glyphs
            var glyphsz = hdr.wmax * hdr.hmax;
            var stride  = hdr.wmax;

            for (var i = 0; i < nchars; i++)
            {
                stream.Seek(cofs[i], SeekOrigin.Begin);
                var w = gdata[i].width;
                var h = gdata[i].height;
                glyphs[i] = new byte[glyphsz];
                DecodeGlyph4bpp(stream, w, h, glyphs[i], stride);
            }

            // fill up to 256 glyphs
            for (var i = nchars; i < 256; i++)
            {
                glyphs[i] = glyphs[0];
                gdata[i]  = gdata[0];
            }

            return(new FntFile(glyphs, hdr.wmax, hdr.hmax, gdata));
        }
        private TrueTypeFontTable ReadFontHeader(uint length, TrueTypeTableEntryList list, BigEndianReader reader)
        {
            FontHeader fh = new FontHeader(reader.Position);

            fh.TableVersion       = reader.ReadFixedVersion();
            fh.FontRevision       = reader.ReadFixedVersion();
            fh.ChecksumAdjustment = reader.ReadUInt32();
            fh.MagicNumber        = reader.ReadUInt32();
            fh.FontFlags          = (FontHeaderFlags)reader.ReadUInt16();
            fh.UnitsPerEm         = reader.ReadUInt16();
            fh.Created            = reader.ReadDateTime();
            fh.Modified           = reader.ReadDateTime();
            fh.XMin                  = reader.ReadInt16();
            fh.YMin                  = reader.ReadInt16();
            fh.XMax                  = reader.ReadInt16();
            fh.YMax                  = reader.ReadInt16();
            fh.MacStyle              = (FontStyleFlags)reader.ReadUInt16();
            fh.SmallestScreenFont    = reader.ReadUInt16();
            fh.DirectionHints        = (FontDirectionFlags)reader.ReadInt16();
            fh.IndexToLocationFormat = (FontIndexLocationFormat)reader.ReadInt16();
            fh.GlyphDataFormat       = (GlyphDataFormat)reader.ReadInt16();
            return(fh);
        }
Пример #5
0
        //------------------------------------------------------------------------------------------xx.02.2005
        /// <summary>Reads the font data from the file.</summary>
        /// <param name="openTypeReader">Open Type Reader</param>
        private void ReadFontDataFromFile(OpenTypeReader openTypeReader)
        {
            #region TrueType Collection
            if (bTrueTypeCollection)
            {
                String sTTCTag = openTypeReader.sReadTag();
                if (sTTCTag != "ttcf")
                {
                    throw new ReportException("'" + sFontName + " is not a valid TTC font file.");
                }
                UInt32 uVersion  = openTypeReader.uReadULONG();
                Int32  iNumFonts = (Int32)openTypeReader.uReadULONG();
                if (iTrueTypeCollectionIndex >= iNumFonts)
                {
                    throw new ReportException("'" + sFontName + " has invalid TrueType collection index.");
                }
                openTypeReader.Skip(iTrueTypeCollectionIndex * 4);
                Int32 iOffset = (Int32)openTypeReader.uReadULONG();
                openTypeReader.Seek(iOffset);
            }
            #endregion

            #region Offset Table
            UInt32 uSfntVersion = openTypeReader.uReadULONG();
            if (uSfntVersion == 0x4F54544F /* 'OTTO' */)
            {
                fontDataType = FontDataType.CFFdata;
            }
      #if DEBUG
            else if (uSfntVersion == 0x00010000 /* Version 1.0 */)
            {
                fontDataType = FontDataType.TrueTypeOutlines;
            }
            else
            {
                throw new ReportException("'" + sFontName + " is not a valid TTF, OTF or TTC font file.");
            }
      #endif

            iNumTables     = (Int32)openTypeReader.iReadUSHORT();
            iSearchRange   = (Int32)openTypeReader.iReadUSHORT();
            iEntrySelector = (Int32)openTypeReader.iReadUSHORT();
            iRangeShift    = (Int32)openTypeReader.iReadUSHORT();
            #endregion

            #region Table Directory
            for (Int32 iTable = 0; iTable < iNumTables; iTable++)
            {
                TableDirectory tableDirectory_New = new TableDirectory();
                tableDirectory_New.sTag      = openTypeReader.sReadTag();
                tableDirectory_New.uCheckSum = openTypeReader.uReadULONG();
                tableDirectory_New.iOffset   = (Int32)openTypeReader.uReadULONG();
                tableDirectory_New.iLength   = (Int32)openTypeReader.uReadULONG();
                dict_TableDirectory.Add(tableDirectory_New.sTag, tableDirectory_New);
            }
            Boolean bCFF = dict_TableDirectory.ContainsKey("CFF");
            if ((bCFF && fontDataType == FontDataType.TrueTypeOutlines) || (!bCFF && fontDataType == FontDataType.CFFdata))
            {
                throw new ReportException("'" + sFontName + " is not a valid TTC font file.");
            }
            #endregion

            #region Font Header
            TableDirectory tableDirectory = dict_TableDirectory["head"];
            fontHeader = new FontHeader();
            openTypeReader.Seek(tableDirectory.iOffset);
            fontHeader.uTableVersionNumber = openTypeReader.uReadULONG();
            Debug.Assert(fontHeader.uTableVersionNumber == 0x00010000 /* Version 1.0 */);
            openTypeReader.Skip(12);
            fontHeader.iFlags      = openTypeReader.iReadUSHORT();
            fontHeader.iUnitsPerEm = openTypeReader.iReadUSHORT();
            openTypeReader.Skip(16);
            fontHeader.iXMin              = openTypeReader.int16_ReadSHORT();
            fontHeader.iYMin              = openTypeReader.int16_ReadSHORT();
            fontHeader.iXMax              = openTypeReader.int16_ReadSHORT();
            fontHeader.iYMax              = openTypeReader.int16_ReadSHORT();
            fontHeader.iMacStyle          = openTypeReader.iReadUSHORT();
            fontHeader.iLowestRecPPEM     = openTypeReader.iReadUSHORT();
            fontHeader.iFontDirectionHint = openTypeReader.int16_ReadSHORT();
            fontHeader.iIndexToLocFormat  = openTypeReader.int16_ReadSHORT();
            fontHeader.iGlyphDataFormat   = openTypeReader.int16_ReadSHORT();
            #endregion

            #region Horizontal Header
            tableDirectory   = dict_TableDirectory["hhea"];
            horizontalHeader = new HorizontalHeader();
            openTypeReader.Seek(tableDirectory.iOffset);
            horizontalHeader.uTableVersionNumber = openTypeReader.uReadULONG();
            Debug.Assert(horizontalHeader.uTableVersionNumber == 0x00010000 /* Version 1.0 */);
            horizontalHeader.iAscender            = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iDescender           = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iLineGap             = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iAdvanceWidthMax     = openTypeReader.iReadUFWORD();
            horizontalHeader.iMinLeftSideBearing  = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iMinRightSideBearing = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iXMaxExtent          = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iCaretSlopeRise      = openTypeReader.int16_ReadSHORT();
            horizontalHeader.iCaretSlopeRun       = openTypeReader.int16_ReadSHORT();
            horizontalHeader.iCaretOffset         = openTypeReader.int16_ReadSHORT();
            openTypeReader.Skip(10);
            horizontalHeader.iNumberOfHMetrics = openTypeReader.iReadUSHORT();
            #endregion

            #region Windows Metrics (OS/2)
            tableDirectory = dict_TableDirectory["OS/2"];
            winMetrics     = new WinMetrics();
            openTypeReader.Seek(tableDirectory.iOffset);
            winMetrics.iVersion             = openTypeReader.iReadUSHORT();
            winMetrics.iXAvgCharWidth       = openTypeReader.int16_ReadSHORT();
            winMetrics.iUsWeightClass       = openTypeReader.iReadUSHORT();
            winMetrics.iUsWidthClass        = openTypeReader.iReadUSHORT();
            winMetrics.iFsType              = openTypeReader.iReadUSHORT();
            winMetrics.iYSubscriptXSize     = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSubscriptYSize     = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSubscriptXOffset   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSubscriptYOffset   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptXSize   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptYSize   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptXOffset = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptYOffset = openTypeReader.int16_ReadSHORT();
            winMetrics.iYStrikeoutSize      = openTypeReader.int16_ReadSHORT();
            winMetrics.iYStrikeoutPosition  = openTypeReader.int16_ReadSHORT();
            winMetrics.iSFamilyClass        = openTypeReader.int16_ReadSHORT();
            winMetrics.aByte_Panose         = openTypeReader.aByte_ReadBYTE(10);
            if (winMetrics.iVersion == 0)
            {
                openTypeReader.Skip(4); // skip ulCharRange
            }
            else
            {
                winMetrics.uUlUnicodeRange1 = openTypeReader.uReadULONG();
                winMetrics.uUlUnicodeRange2 = openTypeReader.uReadULONG();
                winMetrics.uUlUnicodeRange3 = openTypeReader.uReadULONG();
                winMetrics.uUlUnicodeRange4 = openTypeReader.uReadULONG();
            }
            winMetrics.sAchVendID        = openTypeReader.sReadTag();
            winMetrics.iFsSelection      = openTypeReader.iReadUSHORT();
            winMetrics.iUsFirstCharIndex = openTypeReader.iReadUSHORT();
            winMetrics.iUsLastCharIndex  = openTypeReader.iReadUSHORT();
            winMetrics.iSTypoAscender    = openTypeReader.int16_ReadSHORT();
            winMetrics.iSTypoDescender   = openTypeReader.int16_ReadSHORT();
            winMetrics.iSTypoLineGap     = openTypeReader.int16_ReadSHORT();
            winMetrics.iUsWinAscent      = openTypeReader.iReadUSHORT();
            winMetrics.iUsWinDescent     = openTypeReader.iReadUSHORT();
            if (winMetrics.iVersion > 0)
            {
                winMetrics.iUlCodePageRange1 = openTypeReader.uReadULONG();
                winMetrics.iUlCodePageRange2 = openTypeReader.uReadULONG();
                if (winMetrics.iVersion > 1)
                {
                    winMetrics.iSXHeight      = openTypeReader.int16_ReadSHORT();
                    winMetrics.iSCapHeight    = openTypeReader.int16_ReadSHORT();
                    winMetrics.uUsDefaultChar = openTypeReader.uReadULONG();
                    winMetrics.uUsBreakChar   = openTypeReader.uReadULONG();
                    winMetrics.uUsMaxContext  = openTypeReader.uReadULONG();
                }
            }
            #endregion

            #region Post
            tableDirectory = dict_TableDirectory["post"];
            openTypeReader.Seek(tableDirectory.iOffset + 4);
            Double r1 = openTypeReader.int16_ReadSHORT();
            Double r0 = openTypeReader.iReadUSHORT();
            rItalicAngle        = r1 + r0 / 16384.0;
            iUnderlinePosition  = openTypeReader.int16_ReadFWORD();
            iUnderlineThickness = openTypeReader.int16_ReadFWORD();
            bFixedPitch         = (openTypeReader.uReadULONG() != 0);
            #endregion

            ReadTable_name(openTypeReader);
            ReadTable_hmtx(openTypeReader);
        }
        protected double GetLineHeight(FontUnitType units, OS2Table os2, HorizontalHeader hhead, FontHeader header, double emsize)
        {
            double h;
            bool   useTypo;

            if (units == FontUnitType.UseFontPreference)
            {
                useTypo = (os2.Version >= OS2TableVersion.OpenType15) && ((os2.Selection & FontSelection.UseTypographicSizes) > 0);
            }
            else if (units == FontUnitType.UseHeadMetrics)
            {
                useTypo = false;
            }
            else if (null == os2)
            {
                useTypo = false;
            }
            else
            {
                useTypo = true;
            }

            if (useTypo)
            {
                h = ((double)(os2.TypoAscender - os2.TypoDescender + os2.TypoLineGap) / ((double)header.UnitsPerEm) * emsize);
            }
            else
            {
                h = ((double)(hhead.Ascender - hhead.Descender + hhead.LineGap) / ((double)header.UnitsPerEm) * emsize);
            }

            return(h);
        }
        public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double available, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference)
        {
            HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = this.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = this.Directories["OS/2"].Table as OS2Table;


            CMAPSubTable mac = cmap.GetOffsetTable(encoding);

            if (mac == null)
            {
                mac = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }

            HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader;
            FontHeader       head  = this.Directories["head"].Table as FontHeader;

            available = (available * head.UnitsPerEm) / emsize;

            double len           = 0.0;
            double lastwordlen   = 0.0;
            int    lastwordcount = 0;

            charsfitted = 0;


            for (int i = startOffset; i < s.Length; i++)
            {
                char c = s[i];
                if (char.IsWhiteSpace(c))
                {
                    lastwordlen   = len;
                    lastwordcount = charsfitted;
                }

                int moffset = (int)mac.GetCharacterGlyphOffset(c);
                //System.Diagnostics.Debug.WriteLine("Character '" + chars[i].ToString() + "' (" + ((byte)chars[i]).ToString() + ") has offset '" + moffset.ToString() + "' in mac encoding and '" + woffset + "' in windows encoding");

                if (moffset >= table.HMetrics.Count)
                {
                    moffset = table.HMetrics.Count - 1;
                }
                Scryber.OpenType.SubTables.HMetric metric;
                metric = table.HMetrics[moffset];
                if (i == 0)
                {
                    len = -metric.LeftSideBearing;
                }
                len += metric.AdvanceWidth;

                //check if we can fit more
                if (len > available)
                {
                    len -= metric.AdvanceWidth;
                    break;
                }
                charsfitted++;
            }

            bool isboundary = false;

            if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0)
            {
                len         = lastwordlen;
                charsfitted = lastwordcount;
                isboundary  = true;
            }

            len = len / (double)head.UnitsPerEm;
            len = len * emsize;
            double h = GetLineHeight(useUnits, os2, hhead, head, emsize);

            return(new LineSize((float)len, (float)h, charsfitted, startOffset, isboundary));
        }
        /// <summary>
        /// Measures the size of the provided string at the specified font size (starting at a specific offset),
        /// stopping when the available space is full and returning the number of characters fitted.
        /// </summary>
        /// <param name="encoding">The encoding to use to map the characters</param>
        /// <param name="s">The string to measure the size of</param>
        /// <param name="startOffset">The starting (zero based) offset in that string to start measuring from</param>
        /// <param name="emsize">The M size in font units</param>
        /// <param name="availablePts">The max width allowed for this string</param>
        /// <param name="wordspace">The spacing between words in font units. Default 0</param>
        /// <param name="charspace">The spacing between characters in font units. Default 0</param>
        /// <param name="hscale">The horizontal scaling of all characters. Default 100</param>
        /// <param name="vertical">If true then this is vertical writing</param>
        /// <param name="wordboundary">If True the measuring will stop at a boundary to a word rather than character.</param>
        /// <param name="charsfitted">Set to the number of characters that can be renered at this size within the width.</param>
        /// <returns></returns>
        public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double availablePts, double?wordspacePts, double charspacePts, double hscale, bool vertical, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference)
        {
            HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = this.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = this.Directories["OS/2"].Table as OS2Table;

            CMAPSubTable mac = cmap.GetOffsetTable(encoding);

            if (mac == null)
            {
                mac = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }

            HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader;
            FontHeader       head  = this.Directories["head"].Table as FontHeader;

            double availableFU = availablePts * ((double)head.UnitsPerEm / emsize);
            double charspaceFU = NoCharacterSpace;

            if (charspacePts != NoCharacterSpace)
            {
                charspaceFU = charspacePts * ((double)head.UnitsPerEm / emsize);
            }

            double wordspaceFU = NoWordSpace;

            if (wordspacePts.HasValue)
            {
                wordspaceFU = (wordspacePts.Value * ((double)head.UnitsPerEm / emsize));
            }
            else if (charspacePts != NoCharacterSpace)
            {
                //If we dont have explicit wordspacing then we use the character spacing
                wordspaceFU = charspaceFU;
            }


            double len           = 0.0;
            double lastwordlen   = 0.0;
            int    lastwordcount = 0;

            charsfitted = 0;


            for (int i = startOffset; i < s.Length; i++)
            {
                char c = s[i];
                if (char.IsWhiteSpace(c))
                {
                    lastwordlen   = len;
                    lastwordcount = charsfitted;
                }

                int moffset = (int)mac.GetCharacterGlyphOffset(c);

                if (moffset >= table.HMetrics.Count)
                {
                    moffset = table.HMetrics.Count - 1;
                }

                Scryber.OpenType.SubTables.HMetric metric;
                metric = table.HMetrics[moffset];
                double w = metric.AdvanceWidth;

                if (i == 0)
                {
                    w -= metric.LeftSideBearing;
                }

                if (c == ' ')
                {
                    if (wordspaceFU != NoWordSpace)
                    {
                        w += wordspaceFU;
                    }
                }
                else if (charspaceFU != NoCharacterSpace)
                {
                    w += charspaceFU;
                }



                if (hscale != NoHorizontalScale)
                {
                    w *= hscale;
                }

                len += w;

                //check if we can fit more
                if (len > availableFU)
                {
                    len -= w;
                    break;
                }
                charsfitted++;
            }
            bool isboundary = false;

            if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0)
            {
                len         = lastwordlen;
                charsfitted = lastwordcount;
                isboundary  = true;
            }

            len = len * emsize;
            len = len / (double)head.UnitsPerEm;
            double h = GetLineHeight(useUnits, os2, hhead, head, emsize);

            return(new LineSize(len, h, charsfitted, startOffset, isboundary));
        }