KaFu

Extract the "Font Family Name" from a TrueType 1.0 font

8 posts in this topic

#1 ·  Posted (edited)

Hiho Forum :P,

after reading this excellent article on how to embed TrueType Fonts in your script by eukalyptus in the German Board I wondered how to acquire the font's name for the subsequent operations in the example file (setting the font). It seems there is no solution available for that up to now (except the manual way by opening the font file with a respective viewer and note down the name :x ).

#include <WinApi.au3>

$sFile = FileOpenDialog("Select True Type Font", @ScriptDir, "All (*.*)", 1)
If @error Then Exit

$sFontname = _TrueType_Font_Extract_FontFamilyName($sFile)
If @error Then
    ConsoleWrite(@CRLF & "! Function returned error: " & @error & @CRLF & @CRLF)
Else
    ConsoleWrite(@CRLF & "+ Fontname extracted: " & $sFontname & @CRLF & @CRLF)
EndIf


Func _TrueType_Font_Extract_FontFamilyName($sFile, $bDebug = False)
    ; ===============================================================================================================================
    ;
    ;   Function to extract the "Font Family Name" from a TrueType 1.0 font
    ;
    ;   References:
    ;       Based on this article:
    ;       http://www.codeproject.com/KB/GDI/fontnamefromfile.aspx
    ;
    ;       MS OpenType Font Specificatons:
    ;       http://www.microsoft.com/typography/otspec/default.htm
    ;       http://www.microsoft.com/typography/otspec/name.htm
    ;
    ;   Author: KaFu
    ;
    ; ===============================================================================================================================

    If Not FileExists($sFile) Then Return SetError(1, 0, 0)

    Local $hFile, $sFontname
    $hFile = FileOpen($sFile, 16)

    #cs
        typedef struct _tagTT_OFFSET_TABLE{
        USHORT uMajorVersion;
        USHORT uMinorVersion;
        USHORT uNumOfTables;
        USHORT uSearchRange;
        USHORT uEntrySelector;
        USHORT uRangeShift;
        }TT_OFFSET_TABLE;
    #ce
    If $bDebug Then ConsoleWrite("+ $str_TT_OFFSET_TABLE" & @CRLF & "=================" & @CRLF)
    Local $tag_TT_OFFSET_TABLE = "USHORT uMajorVersion;USHORT uMinorVersion;USHORT uNumOfTables;USHORT uSearchRange;USHORT uEntrySelector;USHORT uRangeShift;"
    Local $str_TT_OFFSET_TABLE = DllStructCreate($tag_TT_OFFSET_TABLE)

    DllStructSetData($str_TT_OFFSET_TABLE, "uMajorVersion", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_OFFSET_TABLE, "uMinorVersion", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_OFFSET_TABLE, "uNumOfTables", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_OFFSET_TABLE, "uSearchRange", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_OFFSET_TABLE, "uEntrySelector", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_OFFSET_TABLE, "uRangeShift", _SwapWord(FileRead($hFile, 2)))

    If $bDebug Then ConsoleWrite("uMajorVersion: " & DllStructGetData($str_TT_OFFSET_TABLE, "uMajorVersion") & @CRLF)
    If $bDebug Then ConsoleWrite("uMinorVersion :" & DllStructGetData($str_TT_OFFSET_TABLE, "uMinorVersion") & @CRLF)
    If $bDebug Then ConsoleWrite("uNumOfTables :" & DllStructGetData($str_TT_OFFSET_TABLE, "uNumOfTables") & @CRLF)
    If $bDebug Then ConsoleWrite("uSearchRange :" & DllStructGetData($str_TT_OFFSET_TABLE, "uSearchRange") & @CRLF)
    If $bDebug Then ConsoleWrite("uEntrySelector :" & DllStructGetData($str_TT_OFFSET_TABLE, "uEntrySelector") & @CRLF)
    If $bDebug Then ConsoleWrite("uRangeShift :" & DllStructGetData($str_TT_OFFSET_TABLE, "uRangeShift") & @CRLF & @CRLF)

    ; //check is this is a true type font and the version is 1.0
    If not ((DllStructGetData($str_TT_OFFSET_TABLE, "uMajorVersion") = 1) AND (DllStructGetData($str_TT_OFFSET_TABLE, "uMinorVersion") = 0)) Then
        FileClose($hFile)
        Return SetError(2, 0, 0)
    EndIf

    #cs
        typedef struct _tagTT_TABLE_DIRECTORY{
        char szTag[4]; //table name
        ULONG uCheckSum; //Check sum
        ULONG uOffset; //Offset from beginning of file
        ULONG uLength; //length of the table in bytes
        }TT_TABLE_DIRECTORY;
    #ce
    If $bDebug Then ConsoleWrite(@CRLF & "+ $str_TT_TABLE_DIRECTORY_Name" & @CRLF & "=================" & @CRLF)
    Local $tag_TT_TABLE_DIRECTORY = "char szTag[4];ULONG uChecksum;ULONG uOffset;ULONG uLength"
    Local $str_TT_TABLE_DIRECTORY_Name = DllStructCreate($tag_TT_TABLE_DIRECTORY)

    Local $a_TT_TABLE_DIRECTORY[DllStructGetData($str_TT_OFFSET_TABLE, "uNumOfTables")]

    For $i = 0 To DllStructGetData($str_TT_OFFSET_TABLE, "uNumOfTables") - 1
        $a_TT_TABLE_DIRECTORY[$i] = DllStructCreate($tag_TT_TABLE_DIRECTORY)
        DllStructSetData($a_TT_TABLE_DIRECTORY[$i], 1, BinaryToString(FileRead($hFile, 4)))
        If $bDebug Then ConsoleWrite("szTag: " & DllStructGetData($a_TT_TABLE_DIRECTORY[$i], 1) & @CRLF)
        If DllStructGetData($a_TT_TABLE_DIRECTORY[$i], 1) = "name" Then
            DllStructSetData($str_TT_TABLE_DIRECTORY_Name, "szTag", DllStructGetData($a_TT_TABLE_DIRECTORY[$i], 1))
            DllStructSetData($str_TT_TABLE_DIRECTORY_Name, "uChecksum", _WinAPI_SwapLong(FileRead($hFile, 4)))
            DllStructSetData($str_TT_TABLE_DIRECTORY_Name, "uOffset", _WinAPI_SwapLong(FileRead($hFile, 4)))
            DllStructSetData($str_TT_TABLE_DIRECTORY_Name, "uLength", _WinAPI_SwapLong(FileRead($hFile, 4)))
            $a_TT_TABLE_DIRECTORY[$i] = 0
            ExitLoop
        EndIf
        $a_TT_TABLE_DIRECTORY[$i] = 0
        FileRead($hFile, 12)
        #cs
            DllStructSetData($a_TT_TABLE_DIRECTORY[$i], 2, FileRead($hFile, 4))
            DllStructSetData($a_TT_TABLE_DIRECTORY[$i], 3, FileRead($hFile, 4))
            DllStructSetData($a_TT_TABLE_DIRECTORY[$i], 4, FileRead($hFile, 4))
        #ce
    Next
    $a_TT_TABLE_DIRECTORY = 0

    If $bDebug Then ConsoleWrite("szTag: " & DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "szTag") & @CRLF)
    If $bDebug Then ConsoleWrite("uChecksum: " & DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uChecksum") & @CRLF)
    If $bDebug Then ConsoleWrite("uOffset: " & DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uOffset") & @CRLF)
    If $bDebug Then ConsoleWrite("uLength: " & DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uLength") & @CRLF)

    #cs
        typedef struct _tagTT_NAME_TABLE_HEADER{
        USHORT uFSelector; //format selector. Always 0
        USHORT uNRCount; //Name Records count
        USHORT uStorageOffset; //Offset for strings storage,
        //from start of the table
        }TT_NAME_TABLE_HEADER;
    #ce
    If $bDebug Then ConsoleWrite(@CRLF & "+ $str_TT_NAME_TABLE_HEADER" & @CRLF & "=================" & @CRLF)
    Local $tag_TT_NAME_TABLE_HEADER = "USHORT uFSelector; USHORT uNRCount;USHORT uStorageOffset"
    Local $str_TT_NAME_TABLE_HEADER = DllStructCreate($tag_TT_NAME_TABLE_HEADER)

    FileSetPos($hFile, DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uOffset"), 0)

    DllStructSetData($str_TT_NAME_TABLE_HEADER, "uFSelector", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_NAME_TABLE_HEADER, "uNRCount", _SwapWord(FileRead($hFile, 2)))
    DllStructSetData($str_TT_NAME_TABLE_HEADER, "uStorageOffset", _SwapWord(FileRead($hFile, 2)))

    If $bDebug Then ConsoleWrite("uFSelector: " & DllStructGetData($str_TT_NAME_TABLE_HEADER, "uFSelector") & @CRLF)
    If $bDebug Then ConsoleWrite("uNRCount: " & DllStructGetData($str_TT_NAME_TABLE_HEADER, "uNRCount") & @CRLF)
    If $bDebug Then ConsoleWrite("uStorageOffset: " & DllStructGetData($str_TT_NAME_TABLE_HEADER, "uStorageOffset") & @CRLF)

    #cs
        typedef struct _tagTT_NAME_RECORD{
        USHORT uPlatformID;
        USHORT uEncodingID;
        USHORT uLanguageID;
        USHORT uNameID;
        USHORT uStringLength;
        USHORT uStringOffset; //from start of storage area
        }TT_NAME_RECORD;
    #ce
    Local $tag_TT_NAME_RECORD = "USHORT uPlatformID;USHORT uEncodingID;USHORT uLanguageID;USHORT uNameID;USHORT uStringLength;USHORT uStringOffset"

    For $i = 0 To DllStructGetData($str_TT_NAME_TABLE_HEADER, "uNRCount") - 1
        If $bDebug Then ConsoleWrite(@CRLF & "+ $str_TT_NAME_RECORD #" & $i + 1 & @CRLF & "=================" & @CRLF)
        $str_TT_NAME_RECORD = DllStructCreate($tag_TT_NAME_RECORD)
        DllStructSetData($str_TT_NAME_RECORD, "uPlatformID", _SwapWord(FileRead($hFile, 2)))
        DllStructSetData($str_TT_NAME_RECORD, "uEncodingID", _SwapWord(FileRead($hFile, 2)))
        DllStructSetData($str_TT_NAME_RECORD, "uLanguageID", _SwapWord(FileRead($hFile, 2)))
        DllStructSetData($str_TT_NAME_RECORD, "uNameID", _SwapWord(FileRead($hFile, 2)))
        DllStructSetData($str_TT_NAME_RECORD, "uStringLength", _SwapWord(FileRead($hFile, 2)))
        DllStructSetData($str_TT_NAME_RECORD, "uStringOffset", _SwapWord(FileRead($hFile, 2)))

        If $bDebug Then ConsoleWrite("uPlatformID: " & DllStructGetData($str_TT_NAME_RECORD, "uPlatformID") & @CRLF)
        If $bDebug Then ConsoleWrite("uEncodingID: " & DllStructGetData($str_TT_NAME_RECORD, "uEncodingID") & @CRLF)
        If $bDebug Then ConsoleWrite("uLanguageID: " & DllStructGetData($str_TT_NAME_RECORD, "uLanguageID") & @CRLF)
        If $bDebug Then ConsoleWrite("uNameID: " & DllStructGetData($str_TT_NAME_RECORD, "uNameID") & @CRLF)
        If $bDebug Then ConsoleWrite("uStringLength: " & DllStructGetData($str_TT_NAME_RECORD, "uStringLength") & @CRLF)
        If $bDebug Then ConsoleWrite("uStringOffset: " & DllStructGetData($str_TT_NAME_RECORD, "uStringOffset") & @CRLF & @CRLF)

        If DllStructGetData($str_TT_NAME_RECORD, "uNameID") = 1 Then ; Should contain the "Font Family name" => look under "Name IDs" at http://www.microsoft.com/typography/otspec/name.htm
            $iFileReadPosition_Save = FileGetPos($hFile)
            If $bDebug Then ConsoleWrite("- Offset #1: " & DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uOffset") & @CRLF)
            If $bDebug Then ConsoleWrite("- Offset #1: " & DllStructGetData($str_TT_NAME_TABLE_HEADER, "uStorageOffset") & @CRLF)
            If $bDebug Then ConsoleWrite("- Offset #1: " & DllStructGetData($str_TT_NAME_RECORD, "uStringOffset") & @CRLF)
            If $bDebug Then ConsoleWrite("! Offset Total: " & DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uOffset") + DllStructGetData($str_TT_NAME_TABLE_HEADER, "uStorageOffset") + DllStructGetData($str_TT_NAME_RECORD, "uStringOffset") & @CRLF)
            FileSetPos($hFile, DllStructGetData($str_TT_TABLE_DIRECTORY_Name, "uOffset") + DllStructGetData($str_TT_NAME_TABLE_HEADER, "uStorageOffset") + DllStructGetData($str_TT_NAME_RECORD, "uStringOffset"), 0)
            $sFontname = BinaryToString(FileRead($hFile, DllStructGetData($str_TT_NAME_RECORD, "uStringLength")), 4)
            If StringIsASCII($sFontname) Then
                If $bDebug Then ConsoleWrite(@CRLF & "+ sFontName found: " & $sFontname & @CRLF)
                If $bDebug Then ConsoleWrite(@CRLF)
                $str_TT_NAME_RECORD = 0
                ExitLoop ; according to the article the loop can be exited here... if the Fontname is found...
            EndIf
            $sFontname = ""
            FileSetPos($hFile, $iFileReadPosition_Save, 0)
        EndIf
        $str_TT_NAME_RECORD = 0
    Next
    FileClose($hFile)

    If $sFontname Then Return $sFontname
    Return SetError(3, 0, 0)

EndFunc   ;==>_TrueType_Font_Extract_FontFamilyName

; #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
Func _SwapWord($iValue)
    Return _MakeWord(BitShift($iValue, 8), BitAND($iValue, 0xFF))
EndFunc   ;==>_SwapWord

Func _MakeWord($LoByte, $HiByte)
    Return BitOR($LoByte, 0x100 * $HiByte)
EndFunc   ;==>_MakeWord

Func _WinAPI_SwapLong($iValue)
    ; #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
    Return _WinAPI_MakeLong(_SwapWord(_WinAPI_HiWord($iValue)), _SwapWord(_WinAPI_LoWord($iValue)))
EndFunc   ;==>_WinAPI_SwapLong

Edit: Corrected spelling typos

Regards

Edited by KaFu

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Why not use the API?

#Include <FontConstants.au3>
#Include <WinAPIEx.au3>

$sFile = FileOpenDialog('Browse Font File', @ScriptDir, 'Font Files (*.ttf;*.ttc;*.otf;*.otc;*.pfm;*.pfb)|All Files (*.*)', 1 + 2)
If Not $sFile Then
    Exit
EndIf

Switch StringRegExpReplace($sFile, '^.*\.', '')
    Case 'pfm', 'pfb'
        $sFile = StringRegExpReplace($sFile, '\.[^.]*\Z', '.pfm') & '|' & StringRegExpReplace($sFile, '\.[^.]*\Z', '.pfb')
    Case Else

EndSwitch

$sFont = _WinAPI_GetFontResourceInfo($sFile, 1)
If Not $sFont Then
    Exit
EndIf

_WinAPI_AddFontResourceEx($sFile, $FR_PRIVATE)
$hFont = _WinAPI_CreateFont(12, 0, 0, 0, $FW_NORMAL , 0, 0, 0, $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $ANTIALIASED_QUALITY, $DEFAULT_PITCH, $sFont)
$hDC = _WinAPI_GetDC(0)
$hSv = _WinAPI_SelectObject($hDC, $hFont)
$tOLTM = _WinAPI_GetOutlineTextMetrics($hDC)
_WinAPI_SelectObject($hDC, $hSv)
_WinAPI_ReleaseDC(0, $hDC)
_WinAPI_DeleteObject($hFont)
_WinAPI_RemoveFontResourceEx($sFile, $FR_PRIVATE)

ConsoleWrite('Family name:   ' & _otm($tOLTM, 'otmFamilyName') & @CR)
ConsoleWrite('Style name     ' & _otm($tOLTM, 'otmStyleName') & @CR)
ConsoleWrite('Typeface name: ' & _otm($tOLTM, 'otmFaceName') & @CR)
ConsoleWrite('Full name:     ' & _otm($tOLTM, 'otmFullName') & @CR)

ConsoleWrite('Nature:        ' & DllStructGetData($tOLTM, 'otmSelection') & @CR)
ConsoleWrite('License:       ' & DllStructGetData($tOLTM, 'otmType') & @CR)

Func _otm(ByRef $tOLTM, $sName)
    Return DllStructGetData(DllStructCreate('wchar[' & (_WinAPI_StrLen(DllStructGetPtr($tOLTM) + DllStructGetData($tOLTM, $sName)) + 1) & ']', DllStructGetPtr($tOLTM) + DllStructGetData($tOLTM, $sName)), 1)
EndFunc   ;==>_otm

Or

#Include <Array.au3>
#Include <File.au3>
#Include <WinAPIEx.au3>

Global $FileList = _FileListToArray(_WinAPI_ShellGetSpecialFolderPath($CSIDL_FONTS), '*.ttf', 1)
Global $FontList[UBound($FileList) - 1][2]

For $i = 1 To $FileList[0]
    $FontList[$i - 1][0] = $FileList[$i]
    $FontList[$i - 1][1] = _WinAPI_GetFontResourceInfo($FileList[$i], 1)
Next

_ArrayDisplay($FontList)

Edited by Yashied

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

Fonts were on my menu some time ago.

because it's just me showing off since KaFu you said "up to now".


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Fonts were on my menu some time ago.

because it's just me showing off since KaFu you said "up to now".

Seeing your name as the last respondent I would have bet to read a bitchy comment on "the hard way" :P... Okay, seems like I reinvented the wheel... again :x. But at least I've learned a lot doing it on my own :shifty:... and added some more useful tags for others to search for.

Share this post


Link to post
Share on other sites

But at least I've learned a lot doing it on my own :x

That's great thing.

You really hurt my feelings with that "bitchy" remark.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

No offense meant :P (well, at least no really offending offense :x), that's what my translator spat out for "bissig" > "acid-tongued"...

Share this post


Link to post
Share on other sites

Tell that to little angel who died because of you.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now