PNGcustomfont Manual
by notthecheatr
PNGcustomfont v1.1 by notthecheatr, based on code by Lachie Dazdarian (which can be downloaded from his site at http://lachie.phatcode.net/Downloads/customfont_ver2.zip)
PNGcustomfont is a simple custom font library for FreeBasic, made because the only alternative was Draw String which is limited and seems too weird to be usable.
To be fair there is now another alternative, though with far fewer features and no included fonts. It's called fbfont, and it's written by sir_mud. Compared to my library it's somewhat limited, but it has two features which make it very interesting and useful: (a)It's compatible with the fbgfx command Draw String, and (b)It uses quicklz to compress the font files when they aren't in use. If you are interested you can take a look here; the library can be downloaded from here.
This is actually based on Lachie's code (as mentioned above) but I made a LOT of useful changes. In fact, if you compare the code you'll recognize some similarities but my code is indeed quite different. There are also a lot of new features, though they are mostly pretty basic and could easily be implemented separately if, for example, you'd rather use Lachie's customfont_ver2.
Note: PNGcustomfont uses the great fbpng library for loading PNGs. If you don't have it, you have two options: either disable PNG loading by #defining NO_PNG, or download fbpng from You can get fbpng at http://www.streetcds.co.uk/fbpng_v1_8_4.tar.gz. If the link ever dies, e-mail me and I'll send it to you.
- Home
- Features
- Usage Guide
- Function Reference
- Type Reference
- The Default Font
- File Format Reference
- Error Handling
- Credits
- Contact Information
Features
- Fonts may be stored either in BMP or in PNG. Alpha or transparency is supported.
- All font information is stored in a text file generated by a useful helper program.
- Fonts are loaded character-by-character into off-screen buffers, taking only the memory needed to store the font (space is only allocated for the characters defined in the font, and each character is stored in an image buffer of the exact size specified in the font file, and no larger).
- Strings may be printed directly to the screen or to a buffer.
- Printed strings may be clipped inside a window.
- Printed strings may be justified in the screen or within a window. Center, left, right, top, and bottom justification are all supported and may be combined, yielding a total of nine possible locations on the screen, ignoring the coordinates.
- A cursor system is implemented. Strings may be printed at the cursor, which is updated each time.
Usage Guide
PNGcustomfont is not hard to use. You will need some fonts, and they should be in PNG format. You might be able to find some online - I have also provided an example font I made by delicately placing Arial characters on a grid and then deleting the grid (that's font1.ini/png) and another which also came with Lachie's original customfont_ver2, which I have modified slightly so it looks better. Lachie's original customfont_ver2 comes with several fonts you may be able to use; if you want to add alpha blending, use a program like GIMP or Paint.NET to delete the background colour and the grid, then use the Feather tool (most image editing programs have it) to blur the alpha around the edges. You can create your own fonts this way, too.
Note: 8-bit colour depth is also supported and tested. There are a few limitations:
I have not tested 8-bit colour depth very extensively because I won't be using it and I don't know of any way to get PNGs in 8-bits. As far as I can tell, it should work (all code has been modified so it supports different colour depths) but I haven't spent a lot of time making sure every little feature works. I don't think there are any bugs but I don't know for sure. Because most people are likely to use 24/32-bit fonts anyways, the rest of this manual is written with that assumption in mind. Just remember the above factors and for the most part it's the same. Note that one example is given for 8-bit fonts, and that is the example given below. All the other examples use 24/32-bit printing, in order to save space (since BMPs cannot be compressed). Note that for safety reasons the library will not allow 8-bit font to be loaded in 32-bit mode (or vice-versa). This should not be a problem since there's no point in doing that, but you could change that by removing the following lines from LoadFont():
If cold <> fdepth Then
ImportFont.Loaded = FONT_ERROR_WRONGDEPTH
Exit Sub
End If
Note: If you don't have fbpng installed or otherwise don't want or need PNG support, you can disable it by defining NO_PNG:
#define NO_PNG
Of course, if you do this you will be unable to load fonts stored in PNG format.
Note: There is also the special font, %DEFAULT%. If you do pass this as a filename to LoadFont, you will have a "font" which can be passed to any of the routines as a font, but unlike a normal font this font is simply the font used by Draw String. The main reason this might be useful is that you can choose a colour for it. Other fonts use a drawing mode, but since %DEFAULT% does not have a drawing mode it's drawing mode is treated as a regular RGB colour value. Since this is a custom font library, I don't talk much about %DEFAULT% here, but in the reference section mention of it is made whenever a Sub has different behaviour when a %DEFAULT% font is passed to it.
Like customfont_ver2, PNGcustomfont requires the characters in a custom font to be ASCII, but shifts the characters down by 32, though, so your first character would be the space, the second the exclamation mark, and so on. PNGcustomfont has a variable shift, defined in the file, so you can choose what the first character in your set is. This could allow you to, for example, define special characters before the actual ASCII characters. The default, however, is 32, and all the example fonts included start at 32. The PNGcf_gencfg program allows you to enter a value for this, however, so if you create your own fonts they may start anywhere. What the first character is doesn't really affect the way the font layout is - it really just controls the mapping between an ASCII string and the characters defined, allowing you define fewer characters (and store in memory fewer characters) than the full ASCII (especially since some ASCII characters are control characters and can't really be displayed anyways). It won't change your font to change this value, but you will need to add new character entries or remove some if you want the ASCII values to match up.
Once you have a font image, you need to create the INI file which is needed to load the font into memory. If your font is on a grid, then this will be very easy - simply use the program PNGcf_gencfg. This program generates all the data for the INI file from the input you give it. If your font is not on a grid, it will be quite a bit more complicated to generate this INI, so I really recommend making it on a grid. If just a few characters are not on a grid, just create the INI and then edit the resulting text file to place the characters in the appropriate locations. You can examine the INI file to understand how it works; all INI files generated by PNGcf_gencfg are commented. There is also a section that covers the INI format thoroughly; click here to skip forwards to it.
The first step in your code is to declare the font, then load it font into memory, using LoadFont. You need to declare a variable As FontType:
Dim As FontType Font1
Then load it into memory like this:
LoadFont (fn As String, font1 As FontType)
Where fn is the name of the INI file and font1 is the font you declared. The INI file contains the name of the image file which contains the characters. Note that the image file may be either BMP or PNG, but if it is a BMP the filename MUST END WITH ".bmp" or a case-variant thereof. A filename ending with anything else will be assumed to be a PNG. Thus, make sure you name your BMPs with a ".bmp" as the ending, and make sure none of your PNGs end with ".bmp" - otherwise your program will probably crash.
If you want to load a different font into the FontType variable, you must first execute an UnloadFont. Because LoadFont allocates memory, you must deallocate that memory by using UnloadFont:
UnloadFont (font1 As FontType)
Only then can you load a different font (or even the same font) into your FontType. Of course, you can also just declare more than one FontType, or even an array of fonts.
PNGcustomfont uses a context to control the drawing. You don't need to use one, as the default one will suffice, but if you want to harness the full power of this you must create one (or else change the default one). Dim a variable as DrawContext, then call InitContext with two arguments: the context itself, and the font you wish to use by default on that context. For the PrintFontx routines you pass a context to the procedure directly, but if you use the cursor system you'll need to call SetCurrentDC to make FPrint use your context. Contexts have a number of variables you will probably want to change - x, y, w, and h are the x and y coordinates on the screen where the context begins and the width and height of the context. There is also a justify, meaning you can cause any text drawn in a context to be centered, right-justified, left-justified, or something else. Of course you can also pass your own coordinates. You can at any time use the default context, which I do not recommend you change. The default context is called defaultDC and is initialized at the beginning for your use.
Please remember that contexts do not really do anything special with your fonts. They display the text on the screen, possibly with clipping but they do not do anything special. If you change the height of a context, for example, it will not change anything you've already drawn in that context. It will only affect the screen in that whatever you next draw in that context will be drawn differently. It's actually just a simple way to package a lot of information in one UDT so you don't have to pass a whole lot of parameters to PrintFont.
Just like customfont_ver2, there are a couple of different drawing routines, but the central and most important routine is PrintFont:
PrintFont (x As Integer, y As Integer,
s As String, f As FontType,
drawmode As Integer,
drawDC As DrawContext)
where:
x, y = x and y coordinates of the upper-left corner
where the string is to be printed.
s = string to be printed.
f = font to use in printing (which must be loaded
using LoadFont)
drawmode = mode to use when drawing each character
(FONT_TRANS, FONT_PSET, or FONT_ALPHA)
drawDC = Context to draw the font in. You can use
the default context (defaultDC) here, but
any other context you use should be
initialized first (the printing routines
will initialize it identically to the
default context if you don't.)
drawmode indicates whether you wish to draw using RGB(255,0,255) as transparent and everything else as opaque, or using no transparency at all, or using an alpha value for each pixel to blend nicely with the background. Since PNGs support alpha blending, you'll probably want to use FONT_ALPHA. If you pass FONT_DEFAULT (which is 0) the default blending mode will be used. This is FONT_ALPHA for PNGs and FONT_TRANS for BMPs, but for any font it can be changed with a call to FSetDefaultMode(f As FontType, mode As Integer):
FSetDefaultMode ( font1, FONT_TRANS )
Which sets the default drawing mode for a particular font. This way, you can set some fonts to transparency and some to alpha, for example.
customfont_ver2 had a drawing routine that uses a global alpha value, called PrintAlphaFont. This has been changed to PrintUAlphaFont (the U is for Uniform) and there is also a PrintFAlphaFont (F for Full) which is really just a stub for PrintFont ,,,,,FONT_ALPHA, (in fact it has the same parameters, except it doesn't have the drawing mode, since that is always Alpha). PrintUAlphaFont lacks the drawing mode parameter also, but it has a blending value instead. This uses PUT (,),,Alpha,blendingval - it blends each pixel using the same alpha value. This is nice, especially since you can still use the bright-pink for transparency. Therefore, if you want to have a font with variable translucency make the background bright pink (RGB 255, 0, 255 or &hff00ff). Otherwise, use an alpha channel in the font image and don't bother with PrintUAlphaFont.
Then there is the cursor system, which attempts to emulate the original QBasic cursor system. You have FPrint, which prints the characters and updates the cursor - then there is FLocate and FSetCursor (the one takes coordinates in terms of characters, the other in terms of pixels), FSetSpacing (which sets the default spacing of the characters), and FSetFontDimen (which sets the dimensions of the characters, which basically controls the behaviour of FLocate, and also how far down the cursor moves each time you call FPrint). To use these, you must first call FSetFont to set the default font. This sets the font that will be used each time you call FPrint. This way, FPrint only takes one argument, which is the string to be printed. Of course, you can change the font at any time, so this is a nice convenient way not to have to worry about all those different parameters to PrintFont. FCls() clears the screen and resets the cursor, FResetCursor does the same without clearing the screen. FLocateStep and FSetCursorStep are the same as their counterparts which do not have the word "Step" on the end, except that their parameters are given relatively instead of absolutely.
Then there are a couple of routines that might be useful if you're trying to save the screen before you print text so you can restore it afterwards. I was originally going to write these routines built-in to the library, but I was having trouble with the pointers, so at last I gave up on that idea. FGetWidth and FGetHeight each take two parameters, a String and a FontType (in that order), and FGetWidth has a third parameter, an Integer. They calculate the width and height in pixels of the string if the string is rendered in the given font. The width is calculated by adding the widths of each character in the string plus the spacing value (the integer passed to it). The height returned by FGetHeight is simply the tallest character in the string. If you know where you will be printing the string, then the screen area that needs to be saved is the rectangle from (x,y) to (x+width,y+height).
And now an example, so minimalist it's not really useful, but it does allow you to see the power and simplicity of the library. Following is the image testfont.png, the font file testfont.ini, and the program fonttest.bas.

#Minimal example font - this font doesn't even have any #more characters than those needed for the example. #Note also that this is the only example that uses an 8-bit font. #----testfont.ini # Version: 1 # Font Image: testfont.bmp #Font format: bmp #Font colour depth: 8 #Default drawing mode: Trans # Number of characters in the font: 3 # Number of lines per character (always 4 when version is 0): 4 # The first character in the set (ASCII number - normally 32) 65 # Character #0 (= 'A'): (x1, y1)-(x2, y2)= #ACTUALLY "H" 0 8 54 78 # Character #1 (= 'B'): (x1, y1)-(x2, y2)= #ACTUALLY "i" 56 8 72 78 # Character #2 (= 'C'): (x1, y1)-(x2, y2)= #ACTUALLY "!" 74 8 94 78
' 'Minimal PNGcustomfont example... '----fonttest.bas ' 'Includes: #Include "fbgfx.bi" Using FB 'We don't need PNG support since it's 8-bit, so leave PNG support out. #Define NO_PNG #Include "..\Include\PNGcustomfont.bi" #Include Once "\fbpng\fbpng.bi" #Include Once "\fbpng\png_image.bi" Dim Shared As FontType Font1 'Set screen mode to 1024x768x32 Screen 20,8,2 'Cover the screen in white... Paint (0,0), 53 'Use drawing pages... ScreenSet 1,0 'Load the font... ChDir ExePath() LoadFont "testfont.ini", Font1 ScreenSet 0,1 'Specify it as the current font so we can use the cursor system FSetFont(Font1) 'Locate the cursor a little ways out... FLocate(0,0) 'Print the text - actually "Hi!" FPrint "ABC" FPrint "ABC" FPrint "ABC" ScreenCopy 'Note: I would NOT use a font like this in a real program, 'it's too confusing to understand when the code is like this. Sleep
Advanced features not covered here which you may wish to read about in the reference below:
- DrawContext
- Clipping
- FBufferCreate, FBufferDestroy and buffered drawing
- FPrintAttribute
Function Reference
Note: To make it easier to find everything, I have removed the "Declare Sub" from each entry. There are only two functions at this time, and both are labelled as such.
- Home
- Features
- Usage Guide
- Function Reference
- LoadFont (fontfile As String, ByRef ImportFont As FontType)
- UnloadFont(ByRef FontT As FontType)
- FSetFont (ByRef DefFont As FontType)
- PrintFont (xx As Integer, yy As Integer, CT As String, ByRef PrintSFont As FontType, PMode As Integer, ByRef drawDC As DrawContext)
- PrintFAlphaFont (xx As Integer, yy As Integer, CT As String, ByRef PrintSFont As FontType, ByRef drawDC As DrawContext)
- PrintUAlphaFont (xx As Integer, yy As Integer, CText As String, ByRef PrintTFont As FontType, pblender As Integer, ByRef drawDC As DrawContext)
- FSetDefaultMode (ByRef Fontt As FontType, mode As Integer)
- FPrint (CText As String)
- FPrintAttribute (CText As String, attrib As Integer)
- FLocate (x As Integer, y As Integer)
- FLocateStep (x As Integer, y As Integer)
- FGetLocate (ByRef x As Integer, ByRef y As Integer)
- FSetCursor (x As Integer, y As Integer)
- FSetCursorStep (x As Integer, y As Integer)
- FGetCursor (ByRef x As Integer, ByRef y As Integer)
- FSetSpacing (spac As Integer)
- FSetFontDimen (fw As Integer, fh As Integer)
- FCls ( )
- FResetCursor ( )
- FSetCurrentDC (ByRef cdc As DrawContext)
- FInitContext (ByRef tdc As DrawContext, ByRef dfnt As FontType)
- FSetClipping (x As Integer, y As Integer, w As Integer, h As Integer)
- FClippingOn()
- FClippingOff()
- FGetWidth (CText As String, ByRef tfont As FontType, s1 As Integer) As Integer
- FGetHeight (CText As String, ByRef tfont As FontType) As Integer
- FBufferCreate (ByRef drawDC As DrawContext, w As Integer, h As Integer, fval As Integer)
- FBufferDestroy (ByRef drawDC As DrawContext)
- Type Reference
- File Format Reference
- Error Handling
- Credits
- Contact Information
LoadFont (fontfile As String, ByRef ImportFont As FontType)
Loads a font into memory. The fontfile is a text file created using the program
PNGcf_gencfg or something similar. ImportFont is a FontType variable to load
the font into. Note that the current directory must be the directory containing
the font images (PNGs or BMPs) or else the relative or absolute path must be
set in the INI file. I prefer to ChDir to the correct directory when loading the fonts,
but there might be better ways of doing this.
When a font is loaded, the exact amount of memory needed to store the font and
all it's characters (and no more than necessary) is allocated. For this reason, do
not attempt to re-use a FontType variable (by loading another font into it, or even
the same font again) unless you first execute an UnloadFont. LoadFont makes sure
you do this by checking ImportFont.loaded. After loading the font, this is set to 1.
After unloading, it is reset to 0.
The format of the font (PNG or BMP) is indicated in the INI file.
There is also the special mode. If ImportFont.loaded is set to -1, then regardless
of the contents of the font all printing routines will automatically use Draw String
to draw the characters (using the default font from fbgfx). Furthermore, in these
instances the drawing mode (in PrintFont) or the alpha blending value (in
PrintUAlphaFont) is interpreted as a colour rather than their usual interpretation.
This allows you to print a string using colours and spacing options, the only
downside being that this only works with the default font. ImportFont.loaded
can be set to -1 manually, or using LoadFont with the filename "%DEFAULT". It
is probably best only to do this after UnloadFont, though you could also just set
the variable back to 0 when you're done with it.
Note that using the special mode will NOT store the characters of the font into
the ImportFont.FontChars[].CImage buffers. It does not change the font itself
at all, but it merely modifies the behaviour of the printing routines.
Back to Top
UnloadFont(ByRef FontT As FontType)
Unloads a font. If you need to reuse a FontType variable, you must first
make a call to UnloadFont to unload the font already loaded into it. If you
do not do this, FontLoad will refuse to load any other font into the file.
If the font is in the special mode (see LoadFont for details) then UnloadFont
merely changes FontT.loaded to 0 and exits.
Back to Top
FSetFont (ByRef DefFont As FontType)
Set the font used by the cursor system. PNGcustomfont implements a simple
cursor system that acts similarly to that of QBasic (with the differences that
the cursor is not visible and the page does not scroll when the cursor hits the
bottom). The sub FPrint requires a font to be created for this purpose; if
no default font is defined, then FPrint will use the %DEFAULT% font (see
LoadFont for more information).
Back to Top
PrintFont (xx As Integer, yy As Integer, CText As String,
ByRef PrintSFont As FontType, PMode As Integer,
ByRef drawDC As DrawContext)
Print a string (CText) using a font. Note that the font must be loaded or the string
can't print. spacing is the number of pixels horizontally to space between each
character - fonts often have built-in spacing, so this is usually just set to 0. PMode
is the drawing mode: FONT_TRANS, which simply replaces the colour
RGB(255,0,255) with transparency, FONT_PSET, which does not use transparency,
and FONT_ALPHA, which uses the alpha channel to draw the characters. When a
font is loaded, the default drawing mode is set, FONT_ALPHA for PNGs or
FONT_TRANS for BMPs. If PMode is FONT_DEFAULT then the default mode will be
used.
For a %DEFAULT% font, PMode is interpreted as a colour instead of a drawing
mode, and Draw String is used to display the text.
spacing between the characters is determined by the variable in the font
"defspacing." Normally this is 0, though a user might play with it. It can be
negative, which would yield a pretty interesting effect, or positive.
Linefeed or carriage feed (Chr 10 and 13) are both used as newline characters;
vertical spacing is equal to the internal variable Font.fheight plus
Context.vertspacing (the latter can be set with FSetVerticalSpacing).
Back to Top
PrintFAlphaFont (xx As Integer, yy As Integer,
CText As String, ByRef PrintSFont As FontType,
ByRef drawDC As DrawContext)
Print a string using the alpha channel. This is really just a stub for PrintFont
with PMode = FONT_ALPHA, and as a result has one less parameter. Other than
that, it is identical to PrintFont and behaves exactly the same.
Back to Top
PrintUAlphaFont (xx As Integer, yy As Integer,
CText As String, ByRef PrintTFont As FontType,
pblender As Integer, ByRef drawDC As DrawContext)
Print a string using an alpha value. This uses pblender as an alpha value
to blend each pixel with the same value. The nice thing about this is that even
with the alpha blending you still have Trans support, meaning that RGB(255,0,255)
is treated as transparency no matter what. This means that you can have a font with
variable translucency. The only downside is that you won't have alpha mapping in
the font itself, but that's not really that important.
To add the pink to any font with alpha, just do a fill. Don't bother putting it
on a layer behind, because then the anti-aliasing will have pink. Just do a fill
with threshold a little high so it completely removes the anti-aliasing. Then
save it, preferably as PNG since it will have better compression but really,
you can use either BMP or PNG since you have removed the alpha.
Back to Top
FSetDefaultMode (ByRef Fontt As FontType, mode As Integer)
Set the default drawing mode for a font. The default drawing mode is normally
set when the font is loaded, but if it needs to be changed it can be. Once again
the options are FONT_ALPHA, FONT_TRANS, or FONT_PSET. If FONT_DEFAULT
is used, the mode will not be changed.
If, however, the font is a %DEFAULT% font then the default mode is used as a
colour instead of a drawing mode, and any colour may be set.
Back to Top
FPrint (CText As String)
Print a string using the cursor system. A cursor system is implemented that
imitates that of QBasic. You must first set a default font using FSetFont, and
you may wish to place the cursor using FSetCursor or FLocate.
FPrint uses the default drawing mode of the font, so you may wish to set that
using FSetDefaultMode. FPrint is identical in behaviour to PrintFont, because
it is really a glorified stub for PrintFont.
If FSetFont has not been called yet, FPrint will still print, since the default font
is initialized to defaultFont, which is a %DEFAULT% font.
FPrint moves the cursor down by the value fheight (normally the height of the
tallest character in the font, but may be changed with a call to FSetFontDimen),
leaving the x coordinate at 0+defspacing (the default spacing of the font, which
may be set by FSetSpacing).
FPrintUAlpha is the same as FPrint but has a second parameter, pblender, and
calls to PrintUAlphaFont instead of PrintFont. The important thing to remember
is that it updates the cursor just the same as FPrint, so don't expect different
cursors.
Remember that FPrint and FPrintUAlpha can also be used with buffers - simply
set (*currentDC).buffer to 1. If you'd like to create your own buffer, you should also
call FBufferCreate at this point. Then call FPrint/FPrintUAlpha. This allows you to
use buffer printing with the cursor; just remember that you can only print to a buffer
once; to print to a buffer again (without changing context) you should call
FBufferDestroy first.
Back to Top
FLocate (x As Integer, y As Integer)
Move the cursor. FLocate imitates LOCATE, meaning that the cursor moves
by character-widths and character-heights, rather than by pixels. The widths and
heights used are simply those of the widest and tallest characters in the font, though
these values may be changed with a call to FSetFontDimen.
FSetCursor is far more precise, but moves the cursor by pixel instead of
character.
Back to Top
FLocateStep (x As Integer, y As Integer)
Locate the cursor relative to it's current location. Same as FLocate, except that
the coordinates are relative rather than absolute.
Back to Top
FGetLocate (ByRef x As Integer, ByRef y As Integer)
Get the cursor location in terms of characters. This is imprecise, but
it allows the user to play around with the cursor a bit more than would
normally be possible.
Back to Top
FSetCursor (x As Integer, y As Integer)
Set the coordinates of the cursor, with x and y given in pixels.
FPrint prints a string with the upper-left corner of the first character in the
precise location of the cursor.
Back to Top
FSetCursorStep (x As Integer, y As Integer)
Set the cursor relatively. This is the same as FSetCursor, except that x and
y are relative (and thus may be positive or negative). Note that no bounds
checking is done; if you push the cursor off the screen, then subsequent
FPrint calls will not affect the screen in any way.
Back to Top
FGetCursor (ByRef x As Integer, ByRef y As Integer)
Get the exact coordinates of the cursor. This might be useful to graphics
routines that interact with the font, etc.
Back to Top
FSetSpacing (spac As Integer)
Set the spacing used by FPrint. Many fonts have spacing as part of each
character, but this may not be the case. To add spacing, set this to a positive
value. To clump the characters together, set it to a negative value. This could
be used for all kinds of interesting effects - or not. Note that spacing even
affects %DEFAULT% fonts.
Back to Top
FSetFontDimen (fw As Integer, fh As Integer)
This sets the dimensions of an average character in a font, basically controlling
the behaviour of FLocate, FLocateStep, and FGetLocate. These are internal
values normally set to the width and height of the widest and tallest characters
in the font; however, the user may wish to modify them for some reason, so that
is provided here.
Back to Top
FSetVerticalSpacing (vs As Integer)
Set vertical spacing. Normally the internal variable Font.fheight is used to
determine spacing, but Context.vertspacing is added to that. Normally
this is 0, but it may be modified just as horizontal spacing may be.
Back to Top
FSetJustify (justify As Integer)
This is the quick way to change justification within the cursor system. justify can use all the constants defined, of course:
FSetJustify(FONT_NONE) FSetJustify(FONT_LEFT) FSetJustify(FONT_RIGHT) FSetJustify(FONT_CENTER)
The constants are: FONT_NONE, FONT_LEFT, FONT_RIGHT, FONT_CENTERXONLY,
FONT_TOP, FONT_BOTTOM, FONT_CENTERYONLY, and FONT_CENTER.
Constants may be combined by ORing them, for example
(FONT_TOP Or FONT_RIGHT) will justify text in the top right corner of the screen or buffer.
Back to Top
FSetClipping (x As Integer, y As Integer, w As Integer,
h As Integer)
Change the clipping window coordinates and size. This sets the clipping
window for the current context to the given coordinates and width/height.
It also turns on the clipping variable, assuming that you wouldn't bother
to change clipping if you don't want clipping on.
Back to Top
FClippingOn ()
Turns clipping for the current context on. This is the default setting anyways,
but may need to be changed if the user turned it off in order to setup their
own clipping (using View Screen (x1,y1)-(x2,y2)).
Back to Top
FClippingOff ()
Turns clipping off for the current context. This means that clipping is essentially
bounded by screensize (or buffersize, if buffered printing is used) rather than by
a clipping window. The default clipping window is the screensize anyways, but
a user might change this. For this reason, FClippingOn() and FClippingOff() are
defined. With FClippingOff the user may also set their own clipping using
View Screen (x1,y1)-(x2,y2).
Back to Top
FCls ( )
Clears the screen, resetting the cursor to (0,0). This is only very interesting/useful
if you are using the cursor system. Note that the regular CLS does not affect the
cursor at all.
Back to Top
FResetCursor ( )
This resets the cursor to (0,0) (like FCls, but without clearing the screen).
Back to Top
FSetCurrentDC (ByRef cdc As DrawContext)
Sets the DC to be used by FPrint (normally defaultDC is used, but like everything
else in the cursor system it can be changed).
Back to Top
FInitContext (ByRef tdc As DrawContext, ByRef dfnt As FontType)
Initializes a drawing context for use. tdc is the context to initialize, dfnt is the
default font to use for that context (which of course changes when FSetFont() is
called). All other variables in the context are set the same as the default context.
Back to Top
FGetWidth (CText As String, ByRef tfont As FontType,
s1 As Integer) As Integer
Returns the exact width in pixels of the string given when the string is rendered
in the given font, using s1 for spacing. This may be useful for example to save a
copy of the screen so the text can be erased after it is displayed. The other way
you might use this is for centering the text. This is demonstrated in the example
program, it's quite easy to do really, the only reason I haven't implemented it in
PNGcustomfont is that for the moment, PNGcustomfont doesn't have any idea what
the screen resolution is.
(This is a function.)
Back to Top
FGetHeight (CText As String, ByRef tfont As FontType) As Integer
Returns the height in pixels of the string given when rendered in the given font
(by finding the tallest character in the string). This may be useful for example
to save a copy of the screen so the text can be erased after it is displayed.
(This is a function.)
Back to Top
FPrintAttribute (CText As String, attrib As Integer)
Identical to FPrint, except that you may specify a special attribute to use.
At this point only two attribute (other than FONT_NONE) exist: FONT_BOLD
and FONT_3D. There are a bunch of attributes defined, but none of them
have any affect except for BOLD and 3d. At this point I'm not sure whether I'll ever
'finish' the attribute system or not.
FONT_BOLD simply prints the string over itself several times, with slightly different
positions. This yields a bold - duh? - effect.
FONT_3D does something similar, but diagonally so the font looks 3d. It doesn't
work on all fonts, but on some it looks pretty good. It especially looks cool on the
%DEFAULT% font, because it has a special mode in which the duplications fade.
A demonstration of this is in the example program.
Back to Top
FBufferCreate (ByRef drawDC As DrawContext, w As Integer,
h As Integer, fval As Integer)
Create the buffer used in buffered drawing. Each context can have a buffer
associated with it that is normally created by the printing function, but if the
user prefers they can create it beforehand using this function. This allows
the user to draw things in the buffer that will be shown underneath the font.
It is recommended to use this rather than ImageCreate.
Back to Top
FBufferDestroy (ByRef drawDC As DrawContext)
Destroy the buffer associated with the given drawing context. This may be used to destroy a buffer no longer needed, to save memory or replace it with a new buffer in the same context. This destroys the image and sets the flag that the buffer is invalid. It is recommended to use this rather than ImageDestroy.
Type Reference
Jump down to Drawing Context referenceFontType reference
FontType has a number of variables, most of which are only used internally.
cdepth - This is the colour depth of the font, must always be the same as the colour depth of the current screen mode or the font will not print.
NChars - Number of characters in the font. When printing a string the first character in the font (StartChar) is subtracted from this number, and the upper and lower bounds of the font are then StartChar and NChars-StartChar. Characters outside this range will simply not be printed.
StartChar - This is the ASCII of the first character in the font.
Ver - Version number of the font, not strictly necessary or important but there.
Imgfilename - Name of the image from which this font was loaded.
Cfgfilename - Name of the INI file from which this font was loaded.
fheight, fwidth - Width of widest character and height of tallest character in the font. Used to determine the cursor position when FLocate is used, these may be modified by the Sub FSetFontDimen().
defspacing - The spacing between each character in the font when a string is printed. Changing this can make the font appear to be stretched out or compressed together.
drawmode - Default drawing mode used to draw font if FONT_DEFAULT is passed as the drawing mode to PrintFont. For %DEFAULT% fonts, which may only be drawn using the Trans method, this instead controls the colour of the font.
loaded - This is used to indicate if the font is loaded properly or not. After LoadFont this will contain one of a number of values; see the Error Handling reference for more on this.
DrawContext reference
DrawContext really isn't anything special, just a collection of variables used to control how text is drawn on the screen at a given time. DefaultContext, the context normally used, is created automatically and fills the entire screen. However, the user may wish to create their own contexts for their own purposes. Contexts are very useful as they control clipping and justification. The following variables are part of the DrawContext structure:
x, y - These are the coordinates on the screen where the upper-left corner of the context begins. Normally 0,0.
w, h - These are the width and height, respectively, of the context. Default is 1024 and 768.
csrx, csry - Location of the cursor. When you call FSetCurrentDC, your cursor location is stored in the drawing context before the new context is loaded. When the new context is loaded, the csrx and csry in it are used as the current cursor. Of course, if you want you can change either the DrawContext Ptr currentDC or the global variables csrx, csry, to avoid storing and loading the cursor location - though neither is recommended. Normally initialized to 0, 0.
wrapped - This is an internal variable set by PrintFont or PrintUAlphaFont to notify the caller how many lines were printed; this is incremented by wordwrapping, encounter of either newline character (10 or 13), and once after the entire string has been printed. Generally this can be ignored, as it is mainly used by FPrint with the cursor system. If you wished to implement your own cursor system, however, you would need to check this variable. Setting this variable before calling FPrint could have some interesting/strange results; however, in the interest of clean code, it is preferable not to touch this one.
vertspacing - How much spacing to put between each line of text printed. This is, of course, in addition to the Font.fheight variable; vertspacing can also be negative, to reduce that spacing without changing the variable. The default is 0.
CurFont - A FontType ptr. Like csrx and csry, this is loaded whenever you switch contexts. Note that the old one isn't saved - CurFont only changes with a call to FSetFont. This allows you to change the current font yourself (by modifying the FontType ptr CurrentFont) without changing the font normally used in the context you are using. Why you would wish to do this I'm not sure, but the possibility is there.
justify - This is the justification used to display anything Printed to the context. There is FONT_LEFT, FONT_RIGHT, FONT_TOP, FONT_BOTTOM, FONT_CENTERXONLY, FONT_CENTERYONLY, and FONT_CENTER. Anyone who has ever used a standard wordprocessor can figure these out pretty easily. You can OR them together to combine them (note: if you combine LEFT and RIGHT you get CENTERXONLY, if you combine TOP and BOTTOM you get CENTERYONLY, and if you combine CENTERXONLY and CENTERYONLY you get CENTER... a useful thing to remember). Except for FONT_CENTER, each thing only affects one dimension, unless you combine some. The default, of course, is FONT_NONE, which does not affect either dimension.
wordwrap - This is the wordwrapping mode. I haven't got wrapping working yet and probably won't try but it's here, just in case.
clipping - This is on by default, but if turned off then clipping is not done even if the printed text leaves the window set in the DrawContext. Of course, in the default DrawContext this has virtually no effect since the window is the entire screen. In a user DrawContext, however, turning this off allows the user to setup their own clipping window (using the View command) beforehand instead of using the default one. This is not recommended, but it is possible. (Note: if you setup your own viewing window use Screen coordinates, i.e., use the first syntax following rather than the second:
View Screen (x1,y1)-(x2,y2) 'Do it this way View (x1,y1)-(x2,y2) 'Don't do it this way
) -1 is the ON setting, 0 the OFF. FONT_CLIPPING and FONT_NOCLIPPING are defined for this purpose.
buffered - Normally 0, this is set to 1 to enable buffered printing, or printing to a FB.IMAGE buffer rather than directly to the screen. Note that clipping does not have any affect during buffered drawing; what fits into the buffer is drawn, what doesn't fit is not drawn.
Note: it is recommended that you use FBufferCreate and FBufferDestroy rather than ImageCreate and ImageDestroy. This is because if you forget to update buffercreated, you'll have problems.
buffercreated - Normally 0, this is set to 1 to indicate that the buffer has already been created using ImageCreate, and so does not need to be created by the printing function. If 0, the printing function creates the smallest possible buffer that the font can fit into. A user might set this to 1 if they want a buffer larger or smaller than the exact size required, or if they wish to draw something behind first. If the printing function creates the buffer, it is automatically filled with either Clear Alpha (&h00000000) or Transparency (&hffff00ff), depending on the drawing mode. Since Clear Alpha is also black, it is used in mode FONT_PSET as well as FONT_ALPHA. The text is drawn over whatever is filled in.
buffer - An FB.IMAGE Ptr which is ImageCreat'd either by the user or by the printing function. If buffered is 1 then everything is printed to the buffer instead of the screen.
The Default Font
There are two 'default' fonts to remember. First there is the %DEFAULT% font, a font which allows you to use the default font included with fbgfx (the same font used by Draw String) through the same interface as all other PNGcustomfont fonts you might use; the other is the font created by the library defaultFont. The second is what this short section is about. The way this is implemented is *slightly* inconsistent with the rest of the library, which is why I want to discuss it here in it's own section.
The font defaultFont is created by the library before anything else; it is used by FPrint if you don't call FSetFont first. The whole purpose is to allow you to print text to the screen without setting anything up at all. That is, no need to set any variables, make any function calls, or anything - FPrint can be the first call you make after the screenmode change, and you'll get text on the screen. Unfortunately, due to the fact that both 8-bit and 32-bit screenmodes are supported, this presents a slight problem: what should the default colour for the font be?
The easiest solution is to make it black - this is consistent in either mode, it's always 0. On the other hand, the screen is normally initialized to black, meaning the user would need some special setup to use it properly. Thus, it's best to use white. The problem is, white is 15 in 8-bit colour mode and &hffffff in 32-bit or 24-bit colour mode. We can't detect the screenmode when the library is first loaded, because at that point it probably hasn't been set yet and will be returned as 32 regardless of what it actually is.
To address this, there's a hack. This hack brings in some inconsistencies, but they are very small and only apply to defaultFont. The hack is that if the current font is defaultFont when FPrint is called, then FPrint checks if the colour is 0 and if so changes it depending on what the screenmode is. This is only done once.
The result is that FPrint may be used without any other initialization whatsoever. This is not the case with PrintFont, PrintUAlphaFont, or PrintFAlphaFont; for those you need to pass a colour anyways. Only FPrint has this hack. The hack seems nice, but there is one thing to be aware of - that there is no checking whatsoever if you WANT it to do that. If, for example, you want the text you print to be black on white, rather than white on black, you might fill the screen with white. Unfortunately, because of the hack, FPrint will set the font colour to white and you won't be able to see the text. In 32-bit mode, you could set the colour to something CLOSE to black, such as &h000001, but if you ever set it to black it would automatically be reset to white.
The best solution to this case is to set defaultFont.Ver equal to any number other than -1. This is the value checked by FPrint to see if it needs to change the colour - because FPrint only adjusts the colour once, when you first call it at the beginning. Thus, if you set Ver to anything other than -1 (preferably 1, as that is the version for all other fonts), FPrint will not touch the colour. The other solution would be to create a font variable and load it with %DEFAULT% - this way, it will use the same font as defaultFont but the colour will not change. The one drawback is it will take more setup, but you may need to have a font other than defaultFont anyways.
Another solution would be to remove the lines entirely from the include. The lines are there for convenience, so FPrint can be used without any setup, but if it this creates more inconvenience than convenience for you, you may remove them. They are clearly marked, and only present in FPrint() (no need to worry about PrintFont or the others). You can delete or comment them out - no problems should be caused by this, except that FPrint() won't work properly without setup now.
My final solution if you don't want to use the hack is to #define NO_DEFAULT_FONT_HACK. This is checked by the compiler and if it is defined then the hack will not be compiled. This is probably the easiest solution.
File Format Reference
The INI file each font must have has a very simple format. I will explain that format here; it might be helpful to have one of the example fonts open at the same time so you can see what I'm talking about. Blank lines or lines beginning with the comment character ("#") are ignored; thus when I refer to the nth line I really mean the nth line that is not blank and does not begin with "#".
The first line is the version number of the format; this is not really important, but it is checked by the code anyways. It should always be 1. Note that it is an integer, and if any changes were made to the format all new versions must be integers as well.
The second line is the name of the file containing the font characters. This can be anything you want; now that the format is stored in the INI file, you could have a BMP ending with a ".png" extension... not sure why you'd want to do this, but it's possible. You can have a full path here if you like, though relative paths are always preferable. Note that it will be relative to the current directory of the program, not the INI file itself, so your program may need to ChDir() in order to load the fonts properly.
The third line is the format of the font - png or bmp. You could also put %DEFAULT% either here or in the filename if you wanted to load a %DEFAULT% font, though I'm not sure why this would be any more useful than loading it using the regular method (passing "%DEFAULT%" to the LoadFont as the filename for the "INI file"). So far only PNG or BMP are supported, and if this is anything else then the font won't load.
Line 4 is the colour depth of the font - because 8-bit and 16-bit fonts are supported just as well as 24/32-bit fonts, you must specify the colour depth. If the colour depth specified in a font is different from the one the screen is currently in, LoadFont will refuse to load the font. Note that 8-bit fonts must use BMPs; 8-bit PNGs may not be used (I'm not even sure if they exist, actually).
Line 5 is the default drawing mode; if you're using PNGs this would normally be Alpha, though to make the image smaller you might remove the alpha channel and put pink in instead, in which case it would be Trans. BMPs are almost always Trans, but if you don't need any transparency at all you may also specify PSet. You may specify either the name of the drawing mode or the number - if you specify 0 Alpha is chosen by default. Note that the default blending mode of a font may be chosen at run-time; and in fact, if you use PrintFont (not FPrint) you may specify a different blending mode to override the default mode.
Line 6 is the default spacing between each character. When a string is printed, each character in the string is displayed one at a time. While some fonts have the spacing completely built-in to them, there is nonetheless an extra value added to the x cursor position after each character; this is the horizontal spacing. You may change this at run-time, but it's useful to set it in the file so you don't have to worry about it later. If you come up with a spacing that looks good, you can put it here. Note that spacing may also be negative - if you put a negative number, the characters will actually get closer together rather than further apart. This could make for some interesting effects.
Line 7 gives the number of characters in the font; note that if this number is greater than the actual number of character entries in the file, the font will load successfully, though the loaded variable (see FontType reference) will be FONT_ERROR_EOF.
Line 8 is the number of lines in each character entry. At this point this should always be 4, as the code does not even pay any attention to this value. Later versions might use this though, so it's here, but never add more than four lines to your character entries unless you make the corresponding changes to the library itself.
Line 9 is the ASCII of the first character in the set. Normally you would not bother to add all the control characters to your font, so the first character of your font would usually be 32 (&h20) which is the space character. This may not be the case though, as you may add more characters or not need some characters. Thus, you may use this. Note that this really does not affect the font itself in any way; it merely affects the way strings are printed. So long as you have enough character entries, the letter "A" in a string will still print "A". If you don't have enough entries, then you'll have to setup your strings differently, which can be a real pain except in very small fonts with only a few characters in them.
After line 9 come the character entries. Each character entry currently consists of 4 lines; once again these may be separated by blank lines or comments, and all such things will be ignored. PNGcf_gencfg makes a nice little comment for each character entry showing which character is represented by that entry, so when you have problems with your font (such as one character overlapping another) it is extremely easy to find the character that needs to be fixed. The first line in a character entry is x1, the next is y1, then x2 and y2. These are basically the coordinates of the upper-left and lower-right corners of the box containing the character, and the coordinates are relative to the top-left of the image (which is (0,0)).
Though generally it's very easy to create a font using PNGcf_gencfg, there is one editing task in particular that you'll almost always end up making: changing the width of certain characters so they don't overlap into other character's spaces (as this causes nasty artifacts to show up on the screen), or so they are wide enough to display the entire character (sometimes the grid given is not wide enough for certain characters, and such characters will be chopped off). This is done by changing the third line of the character entry, the x2 component.
Error Handling
PNGcustomfont does not do a great deal of really in-depth error handling, but there are some things it does to detect and report errors. Errors mainly occur while loading fonts; any other errors are not detected and will only be detected by the programmer when he attempts to display his font. Errors that occur while loading the font are noted in the FontType.loaded variable (see FontType Reference).
Normally this number is 0 if the font is not loaded, 1 if the font is loaded, and -1 if the font is a %DEFAULT% font. Here are the constants defined for this variable:
| Constant Name | Value | Description |
| FONT_LOADED | 1 | Indicates successful loading of the font. |
| FONT_NOTLOADED | 0 | Indicates that the font has not yet been loaded. |
| FONT_LOADEDDEFAULT | -1 | Indicates that the font is a %DEFAULT% font. |
| FONT_ERROR_WRONGDEPTH | -2 | Indicates that the font is the wrong colour depth for the current screenmode, and thus could not be loaded. |
| FONT_ERROR_NO_PNGSUPPORT | -3 | This error occurs if the programmer attempts to load a PNG font after removing PNG support from the library by #defining NO_PNG. |
| FONT_ERROR_NOCHARS | -4 | This indicates that the font given does not have any characters in it. |
| FONT_ERROR_EOF | -5 | This indicates that the end of the file was reached before the font was entirely loaded - that is, there are less character entries in the file than specified. This error will not prevent a string from printing, though any characters in the string that were not loaded will simply not print. |
| FONT_ERROR_UNKNOWNFORMAT | -6 | This error occurs when the font INI file specifies a format other than PNG, BMP, or %DEFAULT%. As these are the only supported formats, anything else will cause this error. |
Last Words and Credits
I made this because the Draw String custom font system is weird. I guess it's fine if you have nothing else to work with, but it was too difficult to get it working with PNGs. Lachie created customfont_ver2 (download at: http://lachie.phatcode.net/Downloads/customfont_ver2.zip) but it didn't support PNGs. Adding PNG support was easy, but I decided to add a lot of other things. I also wanted it to be more memory efficient. There's a trade-off, in the fact that in order to be memory-efficient it uses a weird configuration file system, but I think it's worth it. (RANDOM NOTE: I use a very similar system for tilesets in the tile engine I'm writing) I also added the cursor system - trying to make it similar to the old cursor system everyone knows and loves. Or doesn't. And I added the ability to unload a font, which is very useful indeed.
Then there's buffered printing, drawing contexts, clipping, justification, and many other new features you didn't see in Lachie's library. Adding even more features shouldn't be too difficult, either. So enjoy!
I'm not sure I'm done adding stuff, but I'm going to release it as it is now. If anyone requests a feature I might be willing to add something else, depending on how difficult it would be, of course.
In any case, if you like the program tell me!
Credits
All the FreeBasic development team - you guys rock. Really.
Lachie Dazdarian, who started the whole thing, tested PNGcustomfont and gave suggestions.
Simon Nash, creator of fbpng (the PNG library used by PNGcustomfont).
Pritchard, who wrote a tutorial which helped me understand FB.Image better.
Deleter - Several of the fonts provided were "stolen" from his FFNT library.
QBasic Express - Because they rock and also because I stole their CSS for this doc since I'm too lazy to write any CSS myself XD
Myself - Hey, I gotta give myself credit somewhere, right? I'm the one who created this whole big huge piece of (something).
And anyone else I have inadvertently used or stolen from without remembering to give credit. I can't think of anyone, but you never know...
Contact Information
Please contact me for comments, suggestions, insults, or whatever else you'd like to give me! Although if you sign me up for spam I will find and murder you.
On the FreeBasic Official forum, cha0s's c0de board, and the qbasicnews.com forum, I am notthecheatr.
I have two e-mail addresses:
TheMysteriousStrangerFromMars@yahoo.com
notthecheatr@nerdshack.com
(I am more likely to check the former, so it would be best to send to that one, unless you are a spambot in which case I am more likely to check the other one.)
It's not up yet (as of August 29, 2007) but I'm planning to setup my site at http://notthecheatr.phatcode.net/ so you might check there sometime if you want to see anything else I've made or done (admittedly, not a whole lot recently).