ttfdump.lpr 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. program ttfdump;
  2. {$mode objfpc}{$H+}
  3. uses
  4. {$IFDEF UNIX}{$IFDEF UseCThreads}
  5. cwstrings,
  6. {$ENDIF}{$ENDIF}
  7. Classes, SysUtils, CustApp,
  8. fpparsettf, contnrs;
  9. type
  10. // forward declarations
  11. TTextMapping = class;
  12. TTextMappingList = class(TObject)
  13. private
  14. FList: TFPObjectList;
  15. function GetCount: Integer;
  16. protected
  17. function GetItem(AIndex: Integer): TTextMapping; reintroduce;
  18. procedure SetItem(AIndex: Integer; AValue: TTextMapping); reintroduce;
  19. public
  20. constructor Create;
  21. destructor Destroy; override;
  22. function Add(AObject: TTextMapping): Integer; overload;
  23. function Add(const ACharID, AGlyphID: uint16): Integer; overload;
  24. property Count: Integer read GetCount;
  25. property Items[Index: Integer]: TTextMapping read GetItem write SetItem; default;
  26. end;
  27. TTextMapping = class(TObject)
  28. private
  29. FCharID: uint16;
  30. FGlyphID: uint16;
  31. public
  32. class function NewTextMap(const ACharID, AGlyphID: uint16): TTextMapping;
  33. property CharID: uint16 read FCharID write FCharID;
  34. property GlyphID: uint16 read FGlyphID write FGlyphID;
  35. end;
  36. TMyApplication = class(TCustomApplication)
  37. private
  38. FFontFile: TTFFileInfo;
  39. procedure DumpGlyphIndex;
  40. function GetGlyphIndicesString(const AText: UnicodeString): AnsiString; overload;
  41. function GetGlyphIndices(const AText: UnicodeString): TTextMappingList; overload;
  42. protected
  43. procedure DoRun; override;
  44. public
  45. constructor Create(TheOwner: TComponent); override;
  46. destructor Destroy; override;
  47. procedure WriteHelp; virtual;
  48. end;
  49. TFriendClass = class(TTFFileInfo)
  50. end;
  51. { TTextMappingList }
  52. function TTextMappingList.GetCount: Integer;
  53. begin
  54. Result := FList.Count;
  55. end;
  56. function TTextMappingList.GetItem(AIndex: Integer): TTextMapping;
  57. begin
  58. Result := TTextMapping(FList.Items[AIndex]);
  59. end;
  60. procedure TTextMappingList.SetItem(AIndex: Integer; AValue: TTextMapping);
  61. begin
  62. FList.Items[AIndex] := AValue;
  63. end;
  64. constructor TTextMappingList.Create;
  65. begin
  66. FList := TFPObjectList.Create;
  67. end;
  68. destructor TTextMappingList.Destroy;
  69. begin
  70. FList.Free;
  71. inherited Destroy;
  72. end;
  73. function TTextMappingList.Add(AObject: TTextMapping): Integer;
  74. var
  75. i: integer;
  76. begin
  77. Result := -1;
  78. for i := 0 to FList.Count-1 do
  79. begin
  80. if TTextMapping(FList.Items[i]).CharID = AObject.CharID then
  81. Exit; // mapping already exists
  82. end;
  83. Result := FList.Add(AObject);
  84. end;
  85. function TTextMappingList.Add(const ACharID, AGlyphID: uint16): Integer;
  86. var
  87. o: TTextMapping;
  88. begin
  89. o := TTextMapping.Create;
  90. o.CharID := ACharID;
  91. o.GlyphID := AGlyphID;
  92. Result := Add(o);
  93. if Result = -1 then
  94. o.Free;
  95. end;
  96. { TTextMapping }
  97. class function TTextMapping.NewTextMap(const ACharID, AGlyphID: uint16): TTextMapping;
  98. begin
  99. Result := TTextMapping.Create;
  100. Result.CharID := ACharID;
  101. Result.GlyphID := AGlyphID;
  102. end;
  103. { TMyApplication }
  104. procedure TMyApplication.DumpGlyphIndex;
  105. begin
  106. Writeln('FHHead.numberOfHMetrics = ', FFontFile.HHead.numberOfHMetrics);
  107. Writeln('Length(Chars[]) = ', Length(FFontFile.Chars));
  108. writeln('Glyph Index values:');
  109. Writeln('U+0020 (space) = ', FFontFile.Chars[$0020]);
  110. Writeln('U+0021 (!) = ', FFontFile.Chars[$0021]);
  111. Writeln('U+0048 (H) = ', FFontFile.Chars[$0048]);
  112. Writeln('Glyph widths:');
  113. Writeln('3 = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0020]].AdvanceWidth));
  114. Writeln('4 = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0021]].AdvanceWidth));
  115. Writeln('H = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0048]].AdvanceWidth));
  116. end;
  117. function TMyApplication.GetGlyphIndices(const AText: UnicodeString): TTextMappingList;
  118. var
  119. i: integer;
  120. c: uint16;
  121. begin
  122. if AText = '' then
  123. Exit;
  124. Result := TTextMappingList.Create;
  125. for i := 1 to Length(AText) do
  126. begin
  127. c := uint16(AText[i]);
  128. Result.Add(c, FFontFile.Chars[c]);
  129. end;
  130. end;
  131. function TMyApplication.GetGlyphIndicesString(const AText: UnicodeString): AnsiString;
  132. var
  133. i: integer;
  134. c: word;
  135. begin
  136. Result := '';
  137. for i := 1 to Length(AText) do
  138. begin
  139. c := Word(AText[i]);
  140. if i > 1 then
  141. Result := Result + ',';
  142. Result := Result + IntToHex(FFontFile.Chars[c], 4);
  143. end;
  144. end;
  145. procedure TMyApplication.DoRun;
  146. var
  147. ErrorMsg: String;
  148. s: UnicodeString;
  149. lst: TTextMappingList;
  150. i: integer;
  151. begin
  152. // quick check parameters
  153. ErrorMsg := CheckOptions('hf:', 'help');
  154. if ErrorMsg <> '' then
  155. begin
  156. ShowException(Exception.Create(ErrorMsg));
  157. Terminate;
  158. Exit;
  159. end;
  160. // parse parameters
  161. if (ParamCount = 0) or HasOption('h', 'help') then
  162. begin
  163. WriteHelp;
  164. Terminate;
  165. Exit;
  166. end;
  167. FFontFile.LoadFromFile(self.GetOptionValue('f'));
  168. DumpGlyphIndex;
  169. s := 'Hello, World!';
  170. Writeln('');
  171. lst := GetGlyphIndices(s);
  172. Writeln(Format('%d Glyph indices for: "%s"', [lst.Count, s]));
  173. for i := 0 to lst.Count-1 do
  174. Writeln(Format(#9'%s'#9'%s', [IntToHex(lst[i].GlyphID, 4), IntToHex(lst[i].CharID, 4)]));
  175. // stop program loop
  176. Terminate;
  177. end;
  178. constructor TMyApplication.Create(TheOwner: TComponent);
  179. begin
  180. inherited Create(TheOwner);
  181. StopOnException := True;
  182. FFontFile := TTFFileInfo.Create;
  183. end;
  184. destructor TMyApplication.Destroy;
  185. begin
  186. FFontFile.Free;
  187. inherited Destroy;
  188. end;
  189. procedure TMyApplication.WriteHelp;
  190. begin
  191. writeln('Usage: ', ExeName, ' -h');
  192. writeln(' -h Show this help.');
  193. writeln(' -f <ttf> Load TTF font file.');
  194. end;
  195. var
  196. Application: TMyApplication;
  197. begin
  198. Application := TMyApplication.Create(nil);
  199. Application.Title := 'TTF Font Dump';
  200. Application.Run;
  201. Application.Free;
  202. end.