program ttfdump; {$mode objfpc}{$H+} {$codepage utf8} uses {$ifdef unix}cwstring,{$endif} // required for UnicodeString handling. Classes, SysUtils, CustApp, fpparsettf, FPFontTextMapping, fpTTFSubsetter; type TMyApplication = class(TCustomApplication) private FFontFile: TTFFileInfo; procedure DumpGlyphIndex; function GetGlyphIndicesString(const AText: UnicodeString): AnsiString; overload; function GetGlyphIndices(const AText: UnicodeString): TTextMappingList; overload; procedure CreateSubsetFontFile(const AList: TTextMappingList); protected procedure DoRun; override; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure WriteHelp; virtual; end; TFriendClass = class(TTFFileInfo) end; { TMyApplication } procedure TMyApplication.DumpGlyphIndex; procedure PrintGlyphWidth(const aIndex: UInt32); var lWidthIndex: integer; begin { NOTE: Monospaced fonts may not have a width for every glyph the last one is for subsequent glyphs. } if aIndex < FFontFile.HHead.numberOfHMetrics then lWidthIndex := FFontFile.Chars[aIndex] else lWidthIndex := FFontFile.HHead.numberOfHMetrics-1; Writeln(Format(' %3d = %d', [FFontFile.Chars[aIndex], TFriendClass(FFontFile).ToNatural(FFontFile.Widths[lWidthIndex].AdvanceWidth)])); end; begin Writeln('FHHead.numberOfHMetrics = ', FFontFile.HHead.numberOfHMetrics); Writeln('Length(Chars[]) = ', Length(FFontFile.Chars)); writeln; writeln('Glyph Index values:'); Writeln(' U+0020 (space) = ', Format('%d (%0:4.4x)', [FFontFile.Chars[$0020]])); Writeln(' U+0021 (!) = ', Format('%d (%0:4.4x)', [FFontFile.Chars[$0021]])); Writeln(' U+0048 (H) = ', Format('%d (%0:4.4x)', [FFontFile.Chars[$0048]])); writeln; Writeln('Glyph widths:'); PrintGlyphWidth($0020); PrintGlyphWidth($0021); PrintGlyphWidth($0048); end; function TMyApplication.GetGlyphIndices(const AText: UnicodeString): TTextMappingList; var i: integer; c: uint16; begin if AText = '' then Exit; Result := TTextMappingList.Create; for i := 1 to Length(AText) do begin c := uint16(AText[i]); Result.Add(c, FFontFile.Chars[c]); end; end; procedure TMyApplication.CreateSubsetFontFile(const AList: TTextMappingList); var lSubset: TFontSubsetter; begin writeln; writeln('called CreateSubsetFontFile...'); lSubset := TFontSubsetter.Create(FFontFile, AList); try lSubSet.SaveToFile(ExtractFileName(GetOptionValue('f'))+'.subset.ttf'); finally FreeAndNil(lSubSet); end; end; function TMyApplication.GetGlyphIndicesString(const AText: UnicodeString): AnsiString; var i: integer; c: word; begin Result := ''; for i := 1 to Length(AText) do begin c := Word(AText[i]); if i > 1 then Result := Result + ','; Result := Result + IntToHex(FFontFile.Chars[c], 4); end; end; procedure TMyApplication.DoRun; var ErrorMsg: String; s: UnicodeString; lst: TTextMappingList; i: integer; begin // quick check parameters ErrorMsg := CheckOptions('hf:s', 'help'); if ErrorMsg <> '' then begin ShowException(Exception.Create(ErrorMsg)); Terminate; Exit; end; // parse parameters if (ParamCount = 0) or HasOption('h', 'help') then begin WriteHelp; Terminate; Exit; end; FFontFile.LoadFromFile(self.GetOptionValue('f')); Writeln('Postscript.IsFixedPitch = ', BoolToStr(FFontFile.PostScript.isFixedPitch > 0, True)); DumpGlyphIndex; // test #1 // s := 'Hello, World!'; // test #2 s := 'Typography: “What’s wrong?”'; Writeln(''); lst := GetGlyphIndices(s); Writeln(Format('%d Glyph indices for: "%s"', [lst.Count, s])); writeln(#9'GID'#9'CharID'); writeln(#9'---'#9'------'); for i := 0 to lst.Count-1 do Writeln(Format(#9'%s'#9'%s'#9'%s', [IntToHex(lst[i].GlyphID, 4), IntToHex(lst[i].CharID, 4), Char(lst[i].CharID)])); if HasOption('s','') then CreateSubsetFontFile(lst); lst.Free; writeln; writeln; // stop program loop Terminate; end; constructor TMyApplication.Create(TheOwner: TComponent); begin inherited Create(TheOwner); StopOnException := True; FFontFile := TTFFileInfo.Create; end; destructor TMyApplication.Destroy; begin FFontFile.Free; inherited Destroy; end; procedure TMyApplication.WriteHelp; begin writeln('Usage: ', ExeName, ' -h'); writeln(' -h Show this help.'); writeln(' -f <ttf> Load TTF font file.'); writeln(' -s Generate a subset TTF file.'); end; var Application: TMyApplication; begin Application := TMyApplication.Create(nil); Application.Title := 'TTF Font Dump'; Application.Run; Application.Free; end.