mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-07 06:28:55 +02:00
197 lines
4.7 KiB
ObjectPascal
197 lines
4.7 KiB
ObjectPascal
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.
|
||
|