LoadImageFont from TStream - possible bug?

BlitzMax Forums/BlitzMax Programming/LoadImageFont from TStream - possible bug?

Ghost Dancer(Posted 2007) [#1]
I've been working on a a simple file packer which stores multiple data files in one external file. The app then extracts the required file(s) by loading them into a bank and then creating a BankStream.

Ths works fine with images & sound, but does not seem to work with fonts. To break it down to it's simplest form, try the following (replace "myfont.ttf" with any font you have available):

Strict

Graphics 1024, 768, 0
SetBlend ALPHABLEND

Local font1:TImageFont = LoadImageFont("myfont.ttf", 20)
SetImageFont font1
DrawText "Normal font load", 10, 10

Local fontStream:TStream = ReadFile("myfont.ttf")
Local font2:TImageFont = LoadImageFont(fontStream, 20)
SetImageFont font2
DrawText "Stream font load", 10, 40
fontStream.Close

Flip
WaitKey

End


The first line is drawn in the correct font as expected, but the second line uses the default blitz font indicating that it did not load the front from the Stream (even though technically it is the same file).

Is this a bug/limitation of Blitz Max, or is there a way of getting this to work? (e.g. loading a font from memory) I seem to recall a while ago that a similar problem occurred with incbining fonts - incbin fonts now work but I wonder if it is a related problem?

I have tried doing it so the font is extracted to a temp file which is then loaded, however, the temp file can not be deleted (I think LoadImageFont does not release the file?). Even if I could get this method to work, I would still prefer to load directly from memory.


grable(Posted 2007) [#2]
The problem is BRL.FreeTypeFont .. its loader only takes strings.
It should realy take streams/banks as the other stuff imho.

But you can easily fix that by adding your own loader.

I hacked this together for ya =) (ripped from BRL.FreeTypeLib)
Btw, dont forget to put the "AddFontLoader" line before any font loading.
Type TFreeTypeFontStream Extends TFreeTypeFont
	Function LoadStream:TFreeTypeFontStream( src:TStream,size,style )
		Global ft_lib:Byte Ptr
		
		If Not ft_lib
			If FT_Init_FreeType( Varptr ft_lib ) Return
		EndIf

		Local buf:Byte Ptr,buf_size
				
		Local ft_face:Byte Ptr
		
		
		buf_size=src.Size()
		If Not buf_size Return
		buf=MemAlloc( buf_size )
		src.ReadBytes( buf, buf_size)
		If FT_New_Memory_Face( ft_lib,buf,buf_size,0,Varptr ft_face )
			MemFree buf
			Return
		EndIf
		
		While size
			If Not FT_Set_Pixel_Sizes( ft_face,0,size ) Exit
			size:-1
		Wend
		If Not size 
			FT_Done_Face ft_face
			Return
		EndIf
		
		Local face:FTFace=New FTFace
		MemCopy face,ft_face,SizeOf face
		
		Local metrics:FTMetrics=New FTMetrics
		MemCopy metrics,face.metrics,SizeOf metrics
		
		Local font:TFreeTypeFontStream=New TFreeTypeFontStream
		font._face=face
		font._ft_face=ft_face
		font._style=style
		font._height=metrics.height Sar 6
		font._ascend=metrics.ascend Sar 6
		font._descend=metrics.descend Sar 6
		font._glyphs=New TFreeTypeGlyph[face.numglyphs]
		font._buf=buf
		font._buf_size=buf_size
		
		Return font	
	End Function

End Type

Type TFreeTypeFontLoaderStream Extends TFontLoader
	Method LoadFont:TFreeTypeFont( url:Object,size,style )
		If TStream(url) Then
			Return TFreeTypeFontStream.LoadStream( TStream(url), size, style)
		EndIf
	EndMethod
EndType

AddFontLoader New TFreeTypeFontLoaderStream


EDIT: Oh, i forgot to mention this reads the WHOLE stream. If you want to read sections of a stream, use banks instead so you can limit the amount to read.


Ghost Dancer(Posted 2007) [#3]
Nice one, thank you very much :-) I am using banks, so no problem there.