Bitmap Fonts - Speed up Trimming?
BlitzMax Forums/BlitzMax Programming/Bitmap Fonts - Speed up Trimming?
| ||
| I'm writing a bitmap font library. It's fully-functional, but it needs a lot of optimization, specifically in the trimming of space off the sides of the character images. How is this typically done? Currently I'm going through every pixel and finding the right- and left-most solid pixels in each image, then drawing the image to the backbuffer, then grabbing the image using the coordinates I found earlier. It works perfectly, but it's incredibly slow--it takes about 2 seconds to trim a font. Any suggestions? |
| ||
| If you are getting the font from a truetype and you are drawing the characters into images to create the bitmap font, which it kinda sounds like you are, then you can use the following blitzmax function to get the pixel width of the character. Just feed it one character at a time: Function TextWidth( text$ ) Returns the width, in pixels, of text based on the current image font. Description Get width of text Information This command is useful for calculating horizontal alignment of text when using the DrawText command. Its found in the Max2d module. |
| ||
| Unfortunately I'm not--I'm using the bitmap fonts found here. Basically my problem was trimming off the empty space on the sides of each character efficiently--however I've found a different method and I've managed to cut the trimming time down to about 20 ms, and I've cut the loading time down to about 15 ms. Anyways here's the finished library if anybody wants it: '***********************************************************************************************************************************
' B I T M A P F O N T L I B R A R Y
'***********************************************************************************************************************************
Rem
This library will allow you To draw bitmap fonts obtained from bitmap font image.
How To use it:
-First, Load a font like so:
Local Font:TBitmapFont = TBitmapFont.Load(FileName)
where FileName is the filename of a bitmap font image.
-Then draw text with the Draw() method:
Font.Draw("Hello, world!", 100, 100)
You can change the scale and rotation of the font as well, using SetScale() and SetAngle().
You can also change the spacing of the font using SetSpacing(). You may need to set the spacing
to a negative value in order to obtain the appearance you desire.
You can also change the handle of the font with SetHandle(). The handle of the font is the center
at which the font is rotated and scaled. Additionally you can center the font using SetCentered() and setting
it to 1, which will automatically set the handle in the center of any text you draw.
EndRem
''***********************************************************************************************************************************
Type TBitmapFont
Field Image:TImage
Field Offset:Int[190]
Field Spacing:Float
Field CellWidth:Int
Field CellHeight:Int
Field HandleX:Float
Field HandleY:Float
Field Angle:Float
Field ScaleX:Float
Field ScaleY:Float
Field Centered:Int
Method GetWidth:Int(Text:String)
Local CurIndex:Int
Local CurWidth:Int
For Local I:Int = 1 To Len(Text)
CurIndex = Asc(Mid(Text, I, 1)) - 32
CurWidth :+ (Offset[CurIndex * 2 + 1] - Offset[CurIndex * 2]) + Spacing
Next
Return CurWidth
EndMethod
Method GetHeight:Int()
Return ImageHeight(Image)
EndMethod
Method SetSpacing(Space:Float)
Spacing = Space
EndMethod
Method GetSpacing:Int()
Return Spacing
EndMethod
Method SetHandle(X:Float, Y:Float)
HandleX = X
HandleY = Y
EndMethod
Method GetHandle(X:Float Var, Y:Float Var)
X = HandleX
Y = HandleY
EndMethod
Method SetCentered(IsCentered:Int)
Centered = IsCentered
EndMethod
Method SetAngle(Ang:Float)
Angle = Ang
EndMethod
Method GetAngle:Float()
Return Angle
EndMethod
Method SetScale(X:Float, Y:Float)
ScaleX = X
ScaleY = Y
EndMethod
Method GetScale(X:Float Var, Y:Float Var)
X = ScaleX
Y = ScaleY
EndMethod
Method Draw(Text:String, X:Int, Y:Int)
SetTransform(Angle, ScaleX, ScaleY)
Local CurIndex:Int
Local OrigX:Int = X
Local OldHX:Float
Local OldHY:Float
If Centered
OldHX = HandleX
OldHY = HandleY
HandleX = GetWidth(Text) / 2
HandleY = GetHeight() / 2
EndIf
For Local I:Int = 1 To Len(Text)
CurIndex = Asc(Mid(Text, I, 1)) - 32
SetImageHandle(Image, -((X - Offset[CurIndex * 2]) - (OrigX + HandleX)), HandleY)
DrawImage(Image, OrigX, Y, CurIndex)
X :+ Offset[CurIndex * 2 + 1] - Offset[CurIndex * 2]
X :+ Spacing
Next
HandleX = OldHX
HandleY = OldHY
EndMethod
Method Trim()
Local Pixmap:TPixmap
For Local I:Int = 0 To 94
Pixmap = LockImage(Image, I)
Pixmap = Pixmap.Convert(PF_RGBA8888)
Local LeftMax:Int = CellHeight - 1
Local RightMax:Int = 0
For Local Y:Int = 0 To CellHeight - 1
For Local X:Int = 0 To CellWidth - 1
Local Color:Int = Pixmap.ReadPixel(X, Y)
If Color Shr 24 & $000000FF > 128
If X < LeftMax
LeftMax = X
EndIf
Exit
EndIf
Next
Next
For Local Y:Int = 0 To CellHeight - 1
For Local X:Int = CellWidth - 1 To 0 Step -1
Local Color:Int = Pixmap.ReadPixel(X, Y)
If Color Shr 24 & $000000FF > 128
If X > RightMax
RightMax = X
EndIf
Exit
EndIf
Next
Next
If RightMax = 0
RightMax = CellWidth - CellWidth / 3
EndIf
If LeftMax = CellWidth - 1
LeftMax = CellWidth / 3
EndIf
LeftMax = LeftMax - Spacing / 2
RightMax = RightMax + Spacing / 2
If RightMax > CellWidth - 1
RightMax = CellWidth - 1
EndIf
If LeftMax < 0
LeftMax = 0
EndIf
Offset[I * 2] = LeftMax
Offset[I * 2 + 1] = RightMax
UnlockImage(Image, I)
Next
EndMethod
Function Load:TBitmapFont(FileName:String)
Local Font:TBitmapFont = New TBitmapFont
Local FontImage:TImage = LoadImage(LoadBank(FileName))
Local CellWidth:Int = ImageWidth(FontImage) / 10
Local CellHeight:Int = ImageHeight(FontImage) / 10
FontImage = LoadAnimImage(LoadBank(FileName), CellWidth, CellHeight, 0, 95)
If Not FontImage
Notify("The bitmap font image you specified does not exist, or is not of a supported file format.", True)
End
EndIf
Font.Image = FontImage
Font.CellWidth = CellWidth
Font.CellHeight = CellHeight
Font.ScaleX = 1.0
Font.ScaleY = 1.0
Font.Trim()
Return Font
EndFunction
EndTypeHow To use it: -First, Load a font like so: Local Font:TBitmapFont = TBitmapFont.Load(FileName) where FileName is the filename of a bitmap font image. -Then draw text with the Draw() method: Font.Draw("Hello, world!", 100, 100)You can change the scale and rotation of the font as well, using Font.SetScale() and Font.SetAngle(). You can also change the spacing of the font using Font.SetSpacing(). You may need to set the spacing to a negative value in order to obtain the appearance you desire. You can also change the handle of the font with Font.SetHandle(). The handle of the font is the center at which the font is rotated and scaled. Additionally you can center the font using Font.SetCentered() and setting it to 1, which will automatically set the handle in the center of any text you draw. Here's a little example that demonstrates loading, centering, scaling, rotating, and drawing a font: SuperStrict
Include "TBitmapFont.bmx"
Graphics 1024, 768, 1
SetBlend(ALPHABLEND)
SetClsColor(0, 50, 200)
Local Font:TBitmapFont = TBitmapFont.Load("OrangeWithShadow.png")
Font.SetSpacing(-4)
Font.SetCentered(1)
Local Counter:Float
Local ScaleX:Float
Local ScaleY:Float
Local Ang:Float
Repeat
Cls
Font.SetAngle(0.0)
Font.SetScale(1.0, 1.0)
Font.Draw("Bitmap Font Library - Demo", GraphicsWidth() / 2, 20)
Counter :+ 1.0
ScaleX = Sin(Counter) * 3.0
Font.SetScale(ScaleX, 3.0)
Font.Draw("Hello, world!", MouseX(), MouseY())
ScaleY = Sin(Counter) * 3.0
Font.SetScale(3.0, ScaleY)
Font.Draw("Hello, world!", MouseX(), MouseY() - 90)
Ang = Sin(Counter) * 30.0
Font.SetScale(2.0, 2.0)
Font.SetAngle(Ang)
Font.Draw("Hello, world!", MouseX(), MouseY() + 90)
Flip
Until AppTerminate() Or KeyHit(KEY_ESCAPE)Note: You'll need the 'Orange' font found here to run the demo. |
| ||
| Are those bitmap fonts free to use? he mentions the games are free but i didn't see anything about the fonts |
| ||
| Yes, as he says here and here. :) |
| ||
you know you are not using this correctly:Pixmap.Convert(PF_RGBA8888) that is not going to convert the original pixmap "automatically". |
| ||
| Fontext can be used to make fonts for this code. |
| ||
| ? |
| ||
| Jesse - what is it that you don't understand? |
| ||
| this: Fontext can be used to make fonts for this code. I didn't know where you were comming from. I got it now. I just realized that you were the creator of Fontext.:) http://www.blitzbasic.com/Community/posts.php?topic=65909 |
| ||
| Jesse: Ahh, I see--is it just a matter of using the Pixmap returned by Convert() or is the their extra work involved? Beaker: Good to know. :) |
| ||
it needs to be like this pixmap = Pixmap.Convert(PF_RGBA8888) |
| ||
| Thank you, I've edited it. |