| history | TOP |
2004/06/16:作成
| overview | TOP |
CodeGuru: Retrieving the Font Name from a TTF FileにあるコードをDelphiに翻訳します。それだけです。いや、この時点では翻訳し終わってます。次に示すのがそうですが、意味を理解せずに訳しています。なのでコメントも英語のままだったり。
実際のところ、ソースを掲載する必要はないんですが、「あーDelphiで書き直したいのにできないよー」という人が稀に発生することを期待しています。で、構造体の名前とかで検索してこのページが引っかかったり引っかからなかったり。
誰かのあるいは自分の役に立ちますように。
| 参考サイト | TOP |
| code | TOP |
(*
CodeGuru: Retrieving the Font Name from a TTF File
http://www.codeguru.com/Cpp/G-M/gdi/fonthandlinganddetection/article.php/c3659/
*)
unit CodeGuruC3659;
interface
uses
Windows, SysUtils, Classes;
function GetFontNameFromFile(lpszFilePath: string): string;
implementation
type
USHORT = Word;
ULONG = Longword;
type
// -----------------------------------------
// This is the TTF file header
TT_OFFSET_TABLE = packed record
uMajorVersion : USHORT;
uMinorVersion : USHORT;
uNumOfTables : USHORT;
uSearchRange : USHORT;
uEntrySelector: USHORT;
uRangeShift : USHORT;
end;
// -----------------------------------------
// Tables in the TTF file and their placement and name (tag)
TT_TABLE_DIRECTORY = packed record
szTag : array[0..3] of char; // table name
uCheckSum : ULONG; // Check sum
uOffset : ULONG; // Offset from beginning of file
uLength : ULONG; // length of the table in bytes
end;
// -----------------------------------------
// Header of the names table
TT_NAME_TABLE_HEADER = packed record
uFSelector : USHORT; // format selector. Always 0
uNRCount : USHORT; // Name Records count
uStorageOffset: USHORT; // Offset for strings storage, from start of the table
end;
// -----------------------------------------
// Records in the names table
TT_NAME_RECORD = packed record
uPlatformID : USHORT;
uEncodingID : USHORT;
uLanguageID : USHORT;
uNameID : USHORT;
uStringLength : USHORT;
uStringOffset : USHORT; // from start of storage area
end;
// ---------------------------------------------------------------------------
// #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
function SWAPWORD(x: Word): Word;
begin
Result := MakeWord(HiByte(x), LoByte(x));
end;
// ---------------------------------------------------------------------------
// #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)),SWAPWORD(LOWORD(x)))
function SWAPLONG(x: Cardinal): Cardinal;
begin
Result := MakeLong(SWAPWORD(HiWord(x)), SWAPWORD(LoWord(x)));
end;
// ---------------------------------------------------------------------------
function GetFontNameFromFile(lpszFilePath: string): string;
var
F: TFileStream;
csRetVal: string;
ttOffsetTable: TT_OFFSET_TABLE;
Version: integer;
tblDir: TT_TABLE_DIRECTORY;
bFound: Boolean;
i: integer;
csTemp: string;
ttNTHeader: TT_NAME_TABLE_HEADER;
ttRecord: TT_NAME_RECORD;
nPos: integer;
Buf: array[0..1024] of char; // 結局...
begin
// lpszFilePath is the path to our font file
F := TFileStream.Create(lpszFilePath, fmOpenRead or fmShareDenyWrite);
try
F.Read(ttOffsetTable, SizeOf(TT_OFFSET_TABLE));
// remember to rearrange bytes in the field you're going to use
ttOffsetTable.uNumOfTables := SWAPWORD(ttOffsetTable.uNumOfTables);
ttOffsetTable.uMajorVersion := SWAPWORD(ttOffsetTable.uMajorVersion);
ttOffsetTable.uMinorVersion := SWAPWORD(ttOffsetTable.uMinorVersion);
// check is this is a true type font and the version is 1.0
Version := ttOffsetTable.uMajorVersion * 10 + ttOffsetTable.uMinorVersion;
if (Version = 10) then
begin
bFound := false;
for i := 0 to ttOffsetTable.uNumOfTables - 1 do
begin
// the table's tag cannot exceed 4 characters
F.Read(tblDir, SizeOf(TT_TABLE_DIRECTORY));
csTemp := string(tblDir.szTag);
if (LowerCase(csTemp) = 'name') then
begin
// we found our table. Rearrange order and quit the loop
bFound := true;
tblDir.uLength := SWAPLONG(tblDir.uLength);
tblDir.uOffset := SWAPLONG(tblDir.uOffset);
break;
end;
end;
if (bFound) then
begin
// move to offset we got from Offsets Table
F.Seek(tblDir.uOffset, soFromBeginning);
F.Read(ttNTHeader, SizeOf(TT_NAME_TABLE_HEADER));
// again, don't forget to swap bytes!
ttNTHeader.uNRCount := SWAPWORD(ttNTHeader.uNRCount);
ttNTHeader.uStorageOffset := SWAPWORD(ttNTHeader.uStorageOffset);
for i := 0 to ttNTHeader.uNRCount - 1 do
begin
F.Read(ttRecord, SizeOf(TT_NAME_RECORD));
ttRecord.uNameID := SWAPWORD(ttRecord.uNameID);
// 1 says that this is the font name. 0, for example,
// determines copyright info
if (ttRecord.uNameID = 1) then
begin
ttRecord.uStringLength := SWAPWORD(ttRecord.uStringLength);
ttRecord.uStringOffset := SWAPWORD(ttRecord.uStringOffset);
// save file position so we can return to continue with search
nPos := F.Position;
F.Seek(tblDir.uOffset
+ ttRecord.uStringOffset
+ ttNTHeader.uStorageOffset,
soFromBeginning);
FillChar(Buf, SizeOf(Buf), 0);
F.Read(Buf, ttRecord.uStringLength);
csTemp := string(Buf);
// yes, still need to check if the font name is not empty
// if it is, continue the search
if (csTemp <> '') then
begin
csRetVal := csTemp;
break;
end;
F.Seek(nPos, soFromBeginning);
end;
end;
end;
end;
finally
F.Free;
end;
Result := csRetVal;
end;
end.
| sample | TOP |
ソースコードと実行ファイルです。
20040616fontstudy.zip(4,765ytes)
フォルダ選択ボタンで適当にTrueTypeFontが入っている場所を選択すると、サブフォルダを適当に掘って.ttfファイルを列挙し、「取り出したフォント名 << ファイル名」の形でTMemoに追加していきます。
WindowsのFontsフォルダを試してみるとアルファベットフォントについては大体動いているようですが、日本語フォントは一切無視してるようです。というかこの関数を呼ぶ前の、フォントの列挙すらできてません。
それはそれとして(Screen.Fontsとかでできるし)、この関数のすばらしさはインストールしていなくてもフォントファイルさえあれば、フォント名を取得できるという点にあります。ずっとこういうのを探してたんですが、やっとみつけました。
あ、最後になりましたが、動いています。正しいかどうかは別として。
| EOF | TOP |