CatchFont()

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

CatchFont()

Post by IdeasVacuum »

We have:
CatchImage
CatchMusic
CatchSound
CatchSprite
CatchXML
CatchJSON

So why not CatchFont() too? It is sometimes the case that only a specific Font is just right, and 1000s of OpenSource fonts are freely available.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Bisonte
Addict
Addict
Posts: 1305
Joined: Tue Oct 09, 2007 2:15 am

Re: CatchFont()

Post by Bisonte »

I agree since years ;)

+1
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: CatchFont()

Post by davido »

+1
Perhaps there's a Catch?
DE AA EB
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: CatchFont()

Post by Keya »

is it possible to load a font if it's not an on disk file (do the os api support that)? that might be the catch
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: CatchFont()

Post by IdeasVacuum »

It's certainly possible on WindowsOS and MAC.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: CatchFont()

Post by Danilo »

IdeasVacuum wrote:It's certainly possible on WindowsOS and MAC.
Example code?
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: CatchFont()

Post by Fred »

Seems not possible on Linux (just checked)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CatchFont()

Post by wilbert »

Danilo wrote:
IdeasVacuum wrote:It's certainly possible on WindowsOS and MAC.
Example code?
I have no code example but on OSX you can use ATSFontActivateFromMemory() or on OSX 10.8+ the combination of CGFontCreateWithDataProvider() with CTFontManagerRegisterGraphicsFont()
Windows (x64)
Raspberry Pi OS (Arm64)
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: CatchFont()

Post by IdeasVacuum »

For Windows see Rashad's example using AddFontMemResourceEx()
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: CatchFont()

Post by Danilo »

wilbert wrote:
Danilo wrote:
IdeasVacuum wrote:It's certainly possible on WindowsOS and MAC.
Example code?
I have no code example
Very helpful.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CatchFont()

Post by wilbert »

Danilo wrote:Very helpful.
Thanks :)

Here's also a code example; works for .ttf and .otf fonts.

Code: Select all

ImportC ""
  ATSFontActivateFromMemory(*data, length, context, format, reserved, options, *container)
  ATSFontDeactivate(container, refCon, options)
  ATSFontFindFromContainer(container, options, count, *oArray, *count)
  ATSFontGetPostScriptName(font, options, *name)
EndImport

Procedure CatchFont(Font, *MemoryAddress, Size, Height = 12)
  Protected.i result, container, count, atsfont, name
  ATSFontActivateFromMemory(*MemoryAddress, Size, 0, 0, 0, 0, @container)
  If container = 0
    ProcedureReturn 0
  EndIf
  ATSFontFindFromContainer(container, 0, 0, 0, @count)
  If count = 0
    ATSFontDeactivate(container, 0, 0)
    ProcedureReturn 0
  EndIf
  ATSFontFindFromContainer(container, 0, 1, @atsfont, 0)
  If atsfont = 0
    ATSFontDeactivate(container, 0, 0)
    ProcedureReturn 0
  Else
    ATSFontGetPostScriptName(atsfont, 0, @name)
    result = LoadFont(Font, PeekS(CocoaMessage(0, name, "UTF8String"), -1, #PB_UTF8), Height)
    CFRelease_(name)
    ProcedureReturn result
  EndIf
EndProcedure


DataSection
  FontStart:
  IncludeBinary "OpenSans-LightItalic.ttf"
  FontEnd:
EndDataSection

myFont = CatchFont(#PB_Any, ?FontStart, ?FontEnd - ?FontStart)
Debug myFont

End
Windows (x64)
Raspberry Pi OS (Arm64)
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: CatchFont()

Post by IdeasVacuum »

I really don't know anything about Linux OS. The following code can be used to extract the embedded font to the hard drive. On Windows OS, the Font Mapper is updated with function AddFontResource(). Does Linux have a similar mechanism? Could the drive be a small ram disc created via API?
http://www.fontsquirrel.com

Code: Select all

Enumeration
#Win
#Ed
#FontFile
#Font
EndEnumeration

Define  sThisApp.s = ProgramFilename()
Define     sPath.s = GetPathPart(sThisApp)  ;or other path specifically required by OS
Define sFontFile.s = sPath + "BRUSHSTP.ttf"

If OpenFile(#FontFile, sFontFile)

       WriteData(#FontFile, ?FontStart, (?FontEnd - ?FontStart))
       CloseFile(#FontFile)

       ;Windows API
       AddFontResource_(sFontFile)
           SendMessage_(#HWND_BROADCAST,#WM_FONTCHANGE, #Null, #Null)
EndIf

LoadFont(#Font, "Brushstroke Plain", 36, #PB_Font_HighQuality)

If OpenWindow(#Win, 0, 0, 400, 200, "Embedded Font", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

        EditorGadget(#Ed, 10, 10, 380, 180)
       SetGadgetFont(#Ed, FontID(#Font))

       SetGadgetText(#Ed, "Brushstroke Plain True Type Font")

       Repeat
       Until WaitWindowEvent(1) = #PB_Event_CloseWindow
EndIf

DataSection
FontStart:
  IncludeBinary "C:\OpenSourceFonts\BRUSHSTP.ttf"
FontEnd:
EndDataSection
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
tj1010
Enthusiast
Enthusiast
Posts: 716
Joined: Mon Feb 25, 2013 5:51 pm

Re: CatchFont()

Post by tj1010 »

Not without some format loaders and some weird licensing conflicts which fonts are long known for.

There is such thing as bitmap fonts though.
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: CatchFont()

Post by Danilo »

wilbert wrote:Here's also a code example; works for .ttf and .otf fonts.

Code: Select all

ImportC ""
  ATSFontActivateFromMemory(*data, length, context, format, reserved, options, *container)
  ATSFontDeactivate(container, refCon, options)
  ATSFontFindFromContainer(container, options, count, *oArray, *count)
  ATSFontGetPostScriptName(font, options, *name)
EndImport

Procedure CatchFont(Font, *MemoryAddress, Size, Height = 12)
  Protected.i result, container, count, atsfont, name
  ATSFontActivateFromMemory(*MemoryAddress, Size, 0, 0, 0, 0, @container)
  If container = 0
    ProcedureReturn 0
  EndIf
  ATSFontFindFromContainer(container, 0, 0, 0, @count)
  If count = 0
    ATSFontDeactivate(container, 0, 0)
    ProcedureReturn 0
  EndIf
  ATSFontFindFromContainer(container, 0, 1, @atsfont, 0)
  If atsfont = 0
    ATSFontDeactivate(container, 0, 0)
    ProcedureReturn 0
  Else
    ATSFontGetPostScriptName(atsfont, 0, @name)
    result = LoadFont(Font, PeekS(CocoaMessage(0, name, "UTF8String"), -1, #PB_UTF8), Height)
    CFRelease_(name)
    ProcedureReturn result
  EndIf
EndProcedure


DataSection
  FontStart:
  IncludeBinary "OpenSans-LightItalic.ttf"
  FontEnd:
EndDataSection

myFont = CatchFont(#PB_Any, ?FontStart, ?FontEnd - ?FontStart)
Debug myFont

End
Thanks, wilbert! Unfortunately it seems to have some (typical) problems with font names.
Example font: http://www.fontspace.com/allen-r-walden/crystal

ATSFontGetPostScriptName() returns "CrystalItalic-" and it does not work.
ATSFontGetName() returns "Crystal Italic" and it does not work.

In both cases a valid ID is returned, but the standard font is used instead.

If I change your procedure to use the string "Crystal" for LoadFont(), it's okay.
Maybe it's better to add a new parameter 'fontName.s' to CatchFont().
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: CatchFont()

Post by wilbert »

Danilo wrote:If I change your procedure to use the string "Crystal" for LoadFont(), it's okay.
Maybe it's better to add a new parameter 'fontName.s' to CatchFont().
I wanted to simulate the Catch procedure like other Catch procedures PB offers.
You are right it doesn't work with this font. :(
I also tried it with the OSX 10.8+ CTFontManagerRegisterGraphicsFont approach but same results.
Unfortunately I don't know what function Fred uses to load the font.
Adding a name to the procedure would be possible but in that case it's easier just to register the font and use LoadFont after that.
In that case the only required function would be ATSFontActivateFromMemory.
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply