Jump to content

How to Read Font Title from File Property


Go to solution Solved by UEZ,

Recommended Posts

Posted

I only had to use this once before but you need _WinAPI_GetFontResourceInfo() to read font name directly from a font file properties.

Example:

#include <WinAPIGdi.au3>

Example()

Func Example()
    Local $sFile = "C:\Windows\Fonts\segoeui.ttf"

    ConsoleWrite(_WinAPI_GetFontResourceInfo($sFile, True) & @CRLF)
    ConsoleWrite(@CRLF)

    FontGetInfoFromFile($sFile, 0, "Copyright")
    FontGetInfoFromFile($sFile, 1, "Font Family name")
    FontGetInfoFromFile($sFile, 2, "Font SubFamily name")
    FontGetInfoFromFile($sFile, 3, "Unique font identifier")
    FontGetInfoFromFile($sFile, 4, "Font full name")
    FontGetInfoFromFile($sFile, 5, "Version string")
    FontGetInfoFromFile($sFile, 6, "Postscript name")
    FontGetInfoFromFile($sFile, 7, "Trademark")
    FontGetInfoFromFile($sFile, 8, "Manufacturer Name")
    FontGetInfoFromFile($sFile, 9, "Designer")
    FontGetInfoFromFile($sFile, 10, "Description")
    FontGetInfoFromFile($sFile, 11, "URL Vendor")
    FontGetInfoFromFile($sFile, 16, "Preferred Family (Windows only)")
    FontGetInfoFromFile($sFile, 17, "Preferred SubFamily (Windows only)")
    FontGetInfoFromFile($sFile, 18, "Compatible Full (Mac OS only)")
    FontGetInfoFromFile($sFile, 19, "Sample text")
    FontGetInfoFromFile($sFile, 20, "PostScript CID findfont name")

    FontGetInfoFromFile($sFile, 256, "Font-specific names")

EndFunc   ;==>Example

Func FontGetInfoFromFile($sFile, $n, $sElement)
    Local $s = _WinAPI_GetFontResourceInfo($sFile, Default, $n)
    If Not @error And $s Then ConsoleWrite($sElement & " = " & $s & @CRLF)
EndFunc   ;==>FontGetInfoFromFile

 

Posted

The following script, shared by @BrewManNH and has a few authors listed in the script, can get the Title from a font file. But what I've noticed is that it will not get the Title when it's located in C:\Windows\Fonts directory. If you check the same font in any other directory, it shows the Title. I even tried adding #RequireAdmin hoping that it would  work there but it does not. So this script will work for you as long as it's not within C:\Windows\Fonts

I've adapted the script to copy the file from C:\Windows\Fonts to a Temp folder if folder (if it's located in C:\Windows\Fonts)

#include <FileConstants.au3>
#include <File.au3>

Global $sFontLocation = "C:\Windows\Fonts\MonaspaceNeon-Italic.otf"
Global $sDrive = "", $sDir = "", $sFileName = "", $sExtension = ""
Global $aPathSplit = _PathSplit($sFontLocation, $sDrive, $sDir, $sFileName, $sExtension)

If StringInStr($sFontLocation, "C:\Windows\Fonts") Then
    FileCopy($sFontLocation, @TempDir & "\" & $aPathSplit[3] & $aPathSplit[4], $FC_OVERWRITE)
    $sFontLocation = @TempDir & "\" & $aPathSplit[3] & $aPathSplit[4]
EndIf

Global $sTitle = _FileGetProperty($sFontLocation, "Title")

ConsoleWrite("Font Title: " & $sTitle & @CRLF)


;===============================================================================
; Function Name.....: _FileGetProperty
; Description.......: Returns a property or all properties for a file.
; Version...........: 1.0.2
; Change Date.......: 05-16-2012
; AutoIt Version....: 3.2.12.1+
; Parameter(s)......: $FGP_Path - String containing the file path to return the property from.
;                     $FGP_PROPERTY - [optional] String containing the name of the property to return. (default = "")
;                     $iPropertyCount - [optional] The number of properties to search through for $FGP_PROPERTY, or the number of items
;                                       returned in the array if $FGP_PROPERTY is blank. (default = 300)
; Requirements(s)...: None
; Return Value(s)...: Success: Returns a string containing the property value.
;                     If $FGP_PROPERTY is blank, a two-dimensional array is returned:
;                         $av_array[0][0] = Number of properties.
;                         $av_array[1][0] = 1st property name.
;                         $as_array[1][1] = 1st property value.
;                         $av_array[n][0] = nth property name.
;                         $as_array[n][1] = nth property value.
;                     Failure: Returns an empty string and sets @error to:
;                       1 = The folder $FGP_Path does not exist.
;                       2 = The property $FGP_PROPERTY does not exist or the array could not be created.
;                       3 = Unable to create the "Shell.Application" object $objShell.
; Author(s).........: - Simucal <Simucal@gmail.com>
;                     - Modified by: Sean Hart <autoit@hartmail.ca>
;                     - Modified by: teh_hahn <sPiTsHiT@gmx.de>
;                     - Modified by: BrewManNH
; URL...............: http://www.autoitscript.com/forum/topic/34732-udf-getfileproperty/page__view__findpost__p__557571
; Note(s)...........: Modified the script that teh_hahn posted at the above link to include the properties that
;                     Vista and Win 7 include that Windows XP doesn't. Also removed the ReDims for the $av_ret array and
;                     replaced it with a single ReDim after it has found all the properties, this should speed things up.
;                     I further updated the code so there's a single point of return except for any errors encountered.
;                     $iPropertyCount is now a function parameter instead of being hardcoded in the function itself.
;===============================================================================
Func _FileGetProperty($FGP_Path, $FGP_PROPERTY = "", $iPropertyCount = 500)
    If $FGP_PROPERTY = Default Then $FGP_PROPERTY = ""
    $FGP_Path = StringRegExpReplace($FGP_Path, '["'']', "") ; strip the quotes, if any from the incoming string
    If Not FileExists($FGP_Path) Then Return SetError(1, 0, "") ; path not found
    Local Const $objShell = ObjCreate("Shell.Application")
    If @error Then Return SetError(3, 0, "")
    Local Const $FGP_File = StringTrimLeft($FGP_Path, StringInStr($FGP_Path, "\", 0, -1))
    Local Const $FGP_Dir = StringTrimRight($FGP_Path, StringLen($FGP_File) + 1)
    Local Const $objFolder = $objShell.NameSpace($FGP_Dir)
    Local Const $objFolderItem = $objFolder.Parsename($FGP_File)
    Local $Return = "", $iError = 0
    If $FGP_PROPERTY Then
        For $I = 0 To $iPropertyCount
            If $objFolder.GetDetailsOf($objFolder.Items, $I) = $FGP_PROPERTY Then
                $Return = $objFolder.GetDetailsOf($objFolderItem, $I)
            EndIf
        Next
        If $Return = "" Then
            $iError = 2
        EndIf
    Else
        Local $av_ret[$iPropertyCount + 1][2] = [[0]]
        For $I = 1 To $iPropertyCount
            If $objFolder.GetDetailsOf($objFolder.Items, $I) Then
                $av_ret[$I][0] = $objFolder.GetDetailsOf($objFolder.Items, $I - 1)
                $av_ret[$I][1] = $objFolder.GetDetailsOf($objFolderItem, $I - 1)
;~              $av_ret[0][0] += 1
                $av_ret[0][0] = $I
            EndIf
        Next
        ReDim $av_ret[$av_ret[0][0] + 1][2]
        If Not $av_ret[1][0] Then
            $iError = 2
            $av_ret = $Return
        Else
            $Return = $av_ret
        EndIf
    EndIf
    Return SetError($iError, 0, $Return)
EndFunc   ;==>_FileGetProperty

 

  • Solution
Posted (edited)

Does this work?

;Coded by UEZ build 2025-10-07
#include <WinAPIGdi.au3>

Local $sFontFile = FileOpenDialog("Select a font", "", "Fonts (*.ttf)")
If $sFontFile = "" Or @error Then Exit

ConsoleWrite("Title: " & _WinAPI_GetFontTitle($sFontFile) & @CRLF)

Func _WinAPI_GetFontTitle($sFont)
    If Not _WinAPI_AddFontResourceEx($sFontFile, $FR_PRIVATE) Then Return SetError(1, 0, 0)

    Local $tFont = DllStructCreate("wchar title[4096]")
    Local $aRet = DllCall("gdi32.dll", "bool", "GetFontResourceInfoW", "wstr", $sFontFile, "dword*", DllStructGetSize($tFont), "struct*", $tFont, "dword", 1)
    If @error Or Not $aRet[0] Then
        _WinAPI_RemoveFontResourceEx($sFontFile, $FR_PRIVATE)
        Return SetError(2, 0, 0)
    EndIf
    _WinAPI_RemoveFontResourceEx($sFontFile, $FR_PRIVATE)
    Return $tFont.title
EndFunc

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted (edited)

Although some of them show really long Title which does not show on Properties - Details tab:

Title: Monaspace Argon Var ExtraLight Wide Italic & Monaspace Argon Var Light Wide Italic & Monaspace Argon Var Wide Italic & Monaspace Argon Var Medium Wide Italic & Monaspace Argon Var SemiBold Wide Italic & Monaspace Argon Var Bold Wide Italic & Monaspace Argon Var ExtraBold Wide Italic & Monaspace Argon Var ExtraLight Italic & Monaspace Argon Var Light Italic & Monaspace Argon Var Italic & Monaspace Argon Var Medium Italic & Monaspace Argon Var SemiBold Italic & Monaspace Argon Var Bold Italic & Monaspace Argon Var ExtraBold Italic & Monaspace Argon Var ExtraLight SemiWide Wide Italic & Monaspace Argon Var Light SemiWide Wide Italic & Monaspace Argon Var SemiWide Wide Italic & Monaspace Argon Var Medium SemiWide Wide Italic & Monaspace Argon Var SemiBold SemiWide Wide Italic & Monaspace Argon Var Bold SemiWide Wide Italic & Monaspace Argon Var ExtraBold SemiWide Wide Italic & Monaspace Argon Var ExtraLight SemiWide Italic & Monaspace Argon Var Light SemiWide Italic & Monaspace Argon Var SemiWide Italic & Monaspace Argon Var Medium SemiWide Italic & Monaspace Argon Var SemiBold SemiWide Italic & Monaspace Argon Var Bold SemiWide Italic & Monaspace Argon Var ExtraBold SemiWide Italic & Monaspace Argon Var ExtraLight Wide Wide Italic & Monaspace Argon Var Light Wide Wide Italic & Monaspace Argon Var Wide Wide Italic & Monaspace Argon Var Medium Wide Wide Italic & Monaspace Argon Var SemiBold Wide Wide Italic & Monaspace Argon Var Bold Wide Wide Italic & Monaspace Argon Var ExtraBold Wide Wide Italic & Monaspace Argon Var ExtraLight Wide Italic & Monaspace Argon Var Light Wide Italic & Monaspace Argon Var Wide Italic & Monaspace Argon Var Medium Wide Italic & Monaspace Argon Var SemiBold Wide Italic & Monaspace Argon Var Bold Wide Italic & Monaspace Argon Var ExtraBold Wide Italic

 

EDIT: Now that I think of it, though, I think that yours is probably more accurate than what MS shows in Explorer's Properties - Details tab. MS seems to just cut it off at a certain amount of characters, I can only assume.

Edited by WildByDesign
Posted (edited)

UEZ's solution is better - but I did the work so... Technically it'll be in the ttf/otf itself in the name table ;)

#include <AutoitConstants.au3>
#include <FileConstants.au3>

Local $hFontFile = FileOpen("C:\Windows\Fonts\wingding.ttf", $FO_BINARY)
Local $tagTTCHeader = "align 4; uint sfntVersion; ushort numTables; ushort searchRange; ushort entrySelector; ushort rangeShift"
Local $tTTCHeader = DllStructCreate($tagTTCHeader)
Local $iTTCHeaderLen = DllStructGetSize($tTTCHeader)
Local $tTTCHeaderBuff = DllStructCreate(StringFormat("byte data[%d]", $iTTCHeaderLen), DllStructGetPtr($tTTCHeader))
$tTTCHeaderBuff.Data = FileRead($hFontFile, $iTTCHeaderLen)
Local $iNumTables = _ByteSwap($tTTCHeader.numTables, 16)

Local $tagTableRecord = "align 4; char tag[4]; uint checksum; uint offset; uint length"
Local $tTableRecord = DllStructCreate($tagTableRecord)
Local $iTableRecordLen = DllStructGetSize($tTableRecord)
Local $tTableRecordBuff = DllStructCreate(StringFormat("byte data[%d]", $iTableRecordLen), DllStructGetPtr($tTableRecord))

Local $iNameTabOffset, $iNameTabTotalLen
For $i = 1 To $iNumTables
    $tTableRecordBuff.Data = FileRead($hFontFile, $iTableRecordLen)

    ConsoleWrite(StringFormat("table: %s Offset: %08x Length: %08x\r\n", _
        $tTableRecord.tag, _ByteSwap($tTableRecord.Offset), _ByteSwap($tTableRecord.Length)))

    If $tTableRecord.tag = "name" Then
        $iNameTabOffset =  _ByteSwap($tTableRecord.Offset)
        $iNameTabLen = _ByteSwap($tTableRecord.Length)
        ExitLoop
    EndIf
Next

FileSetPos($hFontFile, $iNameTabOffset, $FILE_BEGIN)
Local $tagNameTable = "align 4; ushort version; ushort count; ushort storageOffset"
Local $tNameTable = DllStructCreate($tagNameTable)
Local $iNameTabLen  = DllStructGetSize($tNameTable)
Local $tNameTableBuff = DllStructCreate(StringFormat("byte data[%d]", $iNameTabLen), DllStructGetPtr($tNameTable))
$tNameTableBuff.data = FileRead($hFontFile, $iNameTabLen)
Local $iNameRecordCount = _ByteSwap($tNameTable.count, 16)
Local $iNameStorageOffset = _ByteSwap($tNameTable.storageOffset, 16)

Local $tagNameRecord = "align 4; ushort platformID; ushort encodingID; ushort languageID; ushort nameID; ushort length; ushort stringOffset;"

Local $tNameRecord = DllStructCreate($tagNameRecord)
Local $iNameRecordLen = DllStructGetSize($tNameRecord)
Local $tNameRecordBuff = DllStructCreate(StringFormat("byte data[%d]", $iNameRecordLen), DllStructGetPtr($tNameRecord))

Local $iFontFamilyNameOffset, $iFontFamilyNameLen
For $i = 1 To $iNameRecordCount
    $tNameRecordBuff.data = FileRead($hFontFile, $iNameRecordLen)
    ConsoleWrite(StringFormat("NameRecord: nameID: %04x length %04x offset %04x", _
        _ByteSwap($tNameRecord.nameID, 16),  _ByteSwap($tNameRecord.length, 16), _ByteSwap($tNameRecord.stringOffset, 16)) & @CRLF)

    If _ByteSwap($tNameRecord.nameID, 16) = 1 Then ; Font Family name.
        $iFontFamilyNameLen = _ByteSwap($tNameRecord.length, 16)
        $iFontFamilyNameOffset =  _ByteSwap($tNameRecord.stringOffset, 16)
        ExitLoop
    EndIf
Next

FileSetPos($hFontFile, $iNameTabOffset + $iNameStorageOffset + $iFontFamilyNameOffset, $FILE_BEGIN)

Local $tFontFamilyName = DllStructCreate(StringFormat("char Name[%d]", $iFontFamilyNameLen))
Local $tFontFamilyNameBuff = DllStructCreate(StringFormat("byte data[%d]", $iFontFamilyNameLen), DllStructGetPtr($tFontFamilyName))
$tFontFamilyNameBuff.Data = FileRead($hFontFile, $iFontFamilyNameLen)

MsgBox(0, "Font Family Name", $tFontFamilyName.Name)

FileClose($hFontFile)

Func _ByteSwap($iInt, $iSize = 32)
    Switch $iSize
        Case 16
            Return BitAND(0xFFFF, BitOR(BitAND(0xFF00, BitShift($iInt, -8)), BitShift($iInt, 8)))

        Case 32
            Local $tBuff = DllStructCreate("byte[4]")
            For $i = 1 To 4
                DllStructSetData($tBuff, 1, BitAND($iInt, 0xFF), 5-$i)
                $iInt = BitShift($iInt, 8)
            Next

            Local $tInt = DllStructCreate("int", DllStructGetPtr($tBuff))
            Return DllStructGetData($tInt, 1)
    EndSwitch
EndFunc

 

Edited by MattyD
tidy
Posted

some observations

#include <WinAPIGdi.au3>

;Coded by WildByDesign 1st post
Local $sFontFile = "C:\Windows\Fonts\Rubik-VariableFont_wght.ttf"
ConsoleWrite("Title: " & _WinAPI_GetFontResourceInfo($sFontFile, True) & @CRLF)
ConsoleWrite(@CRLF)


;Coded by UEZ build 2025-10-07
;~ Local $sFontFile = FileOpenDialog("Select a font", "", "Fonts (*.ttf)")
If $sFontFile = "" Or @error Then Exit

ConsoleWrite("Title: " & _WinAPI_GetFontTitle($sFontFile) & @CRLF)

Func _WinAPI_GetFontTitle($sFont)
    If Not _WinAPI_AddFontResourceEx($sFontFile, $FR_PRIVATE) Then Return SetError(1, 0, 0)

    Local $tFont = DllStructCreate("wchar title[4096]")
    Local $aRet = DllCall("gdi32.dll", "bool", "GetFontResourceInfoW", "wstr", $sFontFile, "dword*", DllStructGetSize($tFont), "struct*", $tFont, "dword", 1)
    If @error Or Not $aRet[0] Then
        _WinAPI_RemoveFontResourceEx($sFontFile, $FR_PRIVATE)
        Return SetError(2, 0, 0)
    EndIf
    _WinAPI_RemoveFontResourceEx($sFontFile, $FR_PRIVATE)
    Return $tFont.title
EndFunc

 

From what I understand, Parsix  is looking for this,
which WildByDesign already published in the 1st post

;Coded by WildByDesign 1st post
#include <WinAPIGdi.au3>

Local $sFontFile = "C:\Windows\Fonts\Rubik-VariableFont_wght.ttf"

FontGetInfoFromFile($sFontFile, 1, "Font Family name")
FontGetInfoFromFile($sFontFile, 4, "Font full name")

Func FontGetInfoFromFile($sFile, $n, $sElement)
    Local $s = _WinAPI_GetFontResourceInfo($sFile, Default, $n)
    If Not @error And $s Then ConsoleWrite($sElement & " = " & $s & @CRLF)
EndFunc   ;==>FontGetInfoFromFile

 

WildByDesign the only thing that confused me is  the 256

FontGetInfoFromFile($sFile, 256, "Font-specific names")

since  _WinAPI_GetFontMemoryResourceInfo  only shows up to 20 (maybe  undocumented)?

I know that I know nothing

Posted
2 minutes ago, ioa747 said:

From what I understand, Parsix  is looking for this,

I agree, the title generally should be equal to the information pulled from that first function. Although I have not checked too many fonts to compare.

3 minutes ago, ioa747 said:

the only thing that confused me is  the 256

Probably undocumented, not sure. I got that from the _WinAPI_GetFontResourceInfo docs, Example 3.

Posted

 

17 hours ago, WildByDesign said:

I agree, the title generally should be equal to the information pulled from that first function. Although I have not checked too many fonts to compare.

Probably undocumented, not sure. I got that from the _WinAPI_GetFontResourceInfo docs, Example 3.

thanks all

I was also skeptical due to the discrepancy in the features. On the other hand, the file attribute indicated something else.

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...