ttfdump.lpr 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. program ttfdump;
  2. {$mode objfpc}{$H+}
  3. {$codepage utf8}
  4. uses
  5. {$ifdef unix}cwstring,{$endif} // required for UnicodeString handling.
  6. Classes,
  7. SysUtils,
  8. CustApp,
  9. fpparsettf,
  10. FPFontTextMapping,
  11. fpTTFSubsetter;
  12. type
  13. TMyApplication = class(TCustomApplication)
  14. private
  15. FFontFile: TTFFileInfo;
  16. procedure DumpGlyphIndex;
  17. function GetGlyphIndicesString(const AText: UnicodeString): AnsiString; overload;
  18. function GetGlyphIndices(const AText: UnicodeString): TTextMappingList; overload;
  19. procedure CreateSubsetFontFile(const AList: TTextMappingList);
  20. protected
  21. procedure DoRun; override;
  22. public
  23. constructor Create(TheOwner: TComponent); override;
  24. destructor Destroy; override;
  25. procedure WriteHelp; virtual;
  26. end;
  27. TFriendClass = class(TTFFileInfo)
  28. end;
  29. { TMyApplication }
  30. procedure TMyApplication.DumpGlyphIndex;
  31. procedure PrintGlyphWidth(const aIndex: UInt32);
  32. var
  33. lWidthIndex: integer;
  34. begin
  35. { NOTE: Monospaced fonts may not have a width for every glyph
  36. the last one is for subsequent glyphs. }
  37. if aIndex < FFontFile.HHead.numberOfHMetrics then
  38. lWidthIndex := FFontFile.Chars[aIndex]
  39. else
  40. lWidthIndex := FFontFile.HHead.numberOfHMetrics-1;
  41. Writeln(Format(' %3d = %d', [FFontFile.Chars[aIndex], TFriendClass(FFontFile).ToNatural(FFontFile.Widths[lWidthIndex].AdvanceWidth)]));
  42. end;
  43. begin
  44. Writeln('FHHead.numberOfHMetrics = ', FFontFile.HHead.numberOfHMetrics);
  45. Writeln('Length(Chars[]) = ', Length(FFontFile.Chars));
  46. writeln;
  47. writeln('Glyph Index values:');
  48. Writeln(' U+0020 (space) = ', Format('%d (%0:4.4x)', [FFontFile.Chars[$0020]]));
  49. Writeln(' U+0021 (!) = ', Format('%d (%0:4.4x)', [FFontFile.Chars[$0021]]));
  50. Writeln(' U+0048 (H) = ', Format('%d (%0:4.4x)', [FFontFile.Chars[$0048]]));
  51. writeln;
  52. Writeln('Glyph widths:');
  53. PrintGlyphWidth($0020);
  54. PrintGlyphWidth($0021);
  55. PrintGlyphWidth($0048);
  56. end;
  57. function TMyApplication.GetGlyphIndices(const AText: UnicodeString): TTextMappingList;
  58. var
  59. i: integer;
  60. c: uint16;
  61. begin
  62. if AText = '' then
  63. Exit;
  64. Result := TTextMappingList.Create;
  65. for i := 1 to Length(AText) do
  66. begin
  67. c := uint16(AText[i]);
  68. Result.Add(c, FFontFile.Chars[c]);
  69. end;
  70. end;
  71. procedure TMyApplication.CreateSubsetFontFile(const AList: TTextMappingList);
  72. var
  73. lSubset: TFontSubsetter;
  74. begin
  75. writeln;
  76. writeln('called CreateSubsetFontFile...');
  77. lSubset := TFontSubsetter.Create(FFontFile, AList);
  78. try
  79. lSubSet.SaveToFile(ExtractFileName(GetOptionValue('f'))+'.subset.ttf');
  80. finally
  81. FreeAndNil(lSubSet);
  82. end;
  83. end;
  84. function TMyApplication.GetGlyphIndicesString(const AText: UnicodeString): AnsiString;
  85. var
  86. i: integer;
  87. c: word;
  88. begin
  89. Result := '';
  90. for i := 1 to Length(AText) do
  91. begin
  92. c := Word(AText[i]);
  93. if i > 1 then
  94. Result := Result + ',';
  95. Result := Result + IntToHex(FFontFile.Chars[c], 4);
  96. end;
  97. end;
  98. procedure TMyApplication.DoRun;
  99. var
  100. ErrorMsg: String;
  101. s: UnicodeString;
  102. lst: TTextMappingList;
  103. i: integer;
  104. begin
  105. // quick check parameters
  106. ErrorMsg := CheckOptions('hf:s', 'help');
  107. if ErrorMsg <> '' then
  108. begin
  109. ShowException(Exception.Create(ErrorMsg));
  110. Terminate;
  111. Exit;
  112. end;
  113. // parse parameters
  114. if (ParamCount = 0) or HasOption('h', 'help') then
  115. begin
  116. WriteHelp;
  117. Terminate;
  118. Exit;
  119. end;
  120. FFontFile.LoadFromFile(self.GetOptionValue('f'));
  121. Writeln('Postscript.IsFixedPitch = ', BoolToStr(FFontFile.PostScript.isFixedPitch > 0, True));
  122. DumpGlyphIndex;
  123. // test #1
  124. // s := 'Hello, World!';
  125. // test #2
  126. s := 'Typography: “What’s wrong?”';
  127. Writeln('');
  128. lst := GetGlyphIndices(s);
  129. Writeln(Format('%d Glyph indices for: "%s"', [lst.Count, s]));
  130. writeln(#9'GID'#9'CharID');
  131. writeln(#9'---'#9'------');
  132. for i := 0 to lst.Count-1 do
  133. Writeln(Format(#9'%s'#9'%s'#9'%s', [IntToHex(lst[i].GlyphID, 4), IntToHex(lst[i].CharID, 4), Char(lst[i].CharID)]));
  134. if HasOption('s','') then
  135. CreateSubsetFontFile(lst);
  136. lst.Free;
  137. writeln;
  138. writeln;
  139. // stop program loop
  140. Terminate;
  141. end;
  142. constructor TMyApplication.Create(TheOwner: TComponent);
  143. begin
  144. inherited Create(TheOwner);
  145. StopOnException := True;
  146. FFontFile := TTFFileInfo.Create;
  147. end;
  148. destructor TMyApplication.Destroy;
  149. begin
  150. FFontFile.Free;
  151. inherited Destroy;
  152. end;
  153. procedure TMyApplication.WriteHelp;
  154. begin
  155. writeln('Usage: ', ExeName, ' -h');
  156. writeln(' -h Show this help.');
  157. writeln(' -f <ttf> Load TTF font file.');
  158. writeln(' -s Generate a subset TTF file.');
  159. end;
  160. var
  161. Application: TMyApplication;
  162. begin
  163. Application := TMyApplication.Create(nil);
  164. Application.Title := 'TTF Font Dump';
  165. Application.Run;
  166. Application.Free;
  167. end.