The QBNews Page 11 Volume 2, Number 3 September 15, 1991 ---------------------------------------------------------------------- G r a p h i c a l l y S p e a k i n g ---------------------------------------------------------------------- Fonts in a Can by Larry Stone You know how it goes - in the process of creating a nifty program, you get side tracked on an even more nifty subprogram. Eventually, this nifty subprogram turns into an extrodinary piece of work. Such is the story behind PrintROMtable - a routine to produce a library of graphics fonts without a font library! The original PrintROMtable was developed for FUSION (published in this issue). Based upon code published by PC Magazine, PrintROMtable was limited in it's scope. Because my time, like most of us, is limited, I made an early release of the code on the Quik_BAS internation echo, and asked others to join in it's development. The responce was outstanding. Rob Smetana immediately jumped into it with code to create italics. Francois Roy supplied code to elongate char- acters for a bold appearance. Bill Beasley supplied code to create tall characters, inspiring Mike Kelly to offer code that creates fonts that are 8, 14, 16, 28, or 32 pixel points in height. Both Rob and Mike supplied code to allow CGA systems access to the extended ASCII set (characters 128 through 255). Of course, my contribution continued with left-handed italics, underlined characters, inverse and backward characters, strike through, stencil characters, double wide and even condensed characters, and, not least of all, intergrating the various code supplied by the other, aforementioned contributors, into the one highly useful and variable module. You know how it goes - while in the process of creating a nifty program, it goes on and on and on... Before we get much further, you should know that PrintROM is run from a test program called, ROMtest.bas, and, although ROMtest traps and sets the screen to your highest resolution, the pixel positioning is coded for SCREEN 12. This means that if your computer monitor can't handle this resolution then you will see only some of the nifty things displayed or, in some cases, some of the diplay will be outside of the monitor's graphic boundaries (you can always tweek the xAxis and yAxis locations coded in the ROMtest program to place any string into your system's view area). So, what's so special about PrintROMtable? Plenty! It is a huge library of fonts without needing external libraries! The external libs supplied provide extended ASCII set 128 through 255. These are not necessary to the program unless your system is CGA and passes a string containing a high ASCII character to PrintROMtable. Even if your pro- gram runs on EGA or VGA, you may wish to include one or more of these font files for the special characters they provide, such as the copy- right and registered trade mark symbols (more on this subject later!) PrintROMtable compiles to around a 13K object file - as small or smal- ler than most "standard" font libraries! As small as this is, you are provided fonts ranging from 8 to 64 pixels tall in condensed, normal, bold, or double wide sizes; characters can be underlined, shadowed, italic (slanted left or right), inverted, backwards, stenciled, or The QBNews Page 12 Volume 2, Number 3 September 15, 1991 contain a strike through mark. Furthermore, you can print from left to right, right to left, top-down, bottom-up, or even at an angle! PrintROMtable has limitations. CGA systems can only use characters 8 pixels tall - this can be expanded to 16 by setting PR.Tall = True. EGA systems cannot access sizes 16, 32. However, EGA can have size 8 expanded to 16 by setting PR.Tall = True. If you try to have an EGA system use font size 16 or 32, PrintROMtable will reset the size to 14 or 28, respectively. This means that using PR.Height = 32 and PR.Tall equals True on EGA systems will produce a font 56 pixels high, not 64 as intended. Only VGA has the entire range of 8, 14, 16, 28, 32, 56 and 64 height characters. The heart of PrintROMtable is it's code to access the where-abouts of the ROM BIOS segment containing the character shape table. Once PrintROMtable has the pointer into the ROM segment that con- taining the character shape tables, it loops through the passed-in string, once for each character in the string. If a background color is called for, it uses LINE with a box and fill (BF) argument to paint a background color. If a background color is not requested then the background color is transparent. The code then loops 4, 8, 14, 16, 28 32, 56, or 64 times for each scan line of the character (depending on such factors as PR.Height, PR.Condesned, and PR.Tall). The 1st item of business is to determine what value, based upon the font size, need to be loaded into the BX register so that a subsequent call to BIOS interrupt 10h, function 1130h can point us to the correct memory address containing our scan lines: SELECT CASE PR.Height CASE 8 ' 8x8 font reg.bx = &H300 CASE 14, 28 ' 8x14 font or 8x14 font double high reg.bx = &H200 CASE 16, 32 ' 8x16 font or 8x16 font double high reg.bx = &H600 CASE ELSE CLS : PRINT "Invalid Character Size": END END SELECT Having determined the BX value, PrintROMtable then sets AX = &H1130 before it calls BIOS Video Service, &H10: reg.ax = &H1130 InterruptX &H10, reg, reg ofst& = reg.bp sgmt& = reg.es For those with inquiring minds, function AX = 1130h is called with AX and BX set as follows: AX = 1130h BX = pointer specifier The QBNews Page 13 Volume 2, Number 3 September 15, 1991 &H0 INT 1Fh pointer &H100 INT 44h pointer &H200 ROM 8 by 14 character font pointer &H300 ROM 8 by 8 double dot font pointer &H400 ROM 8 by 8 DD font (top half) &H500 ROM alpha alternate (9 by 14) pointer &H600 ROM alpha alternate (9 by 16) pointer On return, the ROM BIOS function supplies: ES:BP = specified pointer CX = bytes/character DL = character rows on screen Even though PrintROMtable has the appropriate segment and offset to the character shape table, they may not be correct! The above call to the BIOS is only good for EGA, MCGA, or VGA systems. If PR.ScreenMode is less than 7 or, if you tell PrintROMtable to force the CGA address then PrintROMtable sets the character shape table's segment to &HFFA6. IF PR.ForceAddress OR PR.ScreenMode < 7 THEN sgmt& = &HFFA6 Segment &HFFA6 contains the character table but, unlike our INT 10h table pointer, this table only goes to the first 127 ASCII characters. This means that if PR.ScreenMode is 1, 2, or 3 (same as SCREEN 1, 2, or 3) or, if you instruct PrintROMtable to force the address then, you cannot access the upper ASCII set without defining a disk font file. Since the objective of all of the contributors to this program was to create a self-contained, linkable module, we wanted to avoid asking users to have to have, or load, a 3rd-party file just to access the upper ASCII character set. Several people answered our call for ideas. Mike Kelly was 1st to supply code to accomplish this aim. Although his code was self-contained, it required 4k of memory to use the data. Cornel Huth described an approach similar to the one eventually taken with PrintROMtable: to use Int 1Fh to point to an array containing the high characters. Similar approaches were suggested by Bill Beeler and Dave Cleary. The final approach developed was by Rob Smetana and is similar in operation to the DOS program, Graftabl. Unlike Graftabl, Rob's approach does not require a TSR and it uses a meager 1024 bytes of memory. It does, however, use small, 1024 byte external files. External fonts are loaded by the routine with one GET statement: j% = FREEFILE 'Get a handle OPEN FontFile$ FOR BINARY AS #j% 'Open with this handle font$ = SPACE$(1024) 'Our fonts need just 1024 bytes (128 * 8). GET #1, , font$: CLOSE #j% 'Close file with handle j% PrintROMtable is supplied with four disk font files that access the characters used in international, U.S., Portuguese, and French-Canada ASCII sets. There can be additional 1024 font files added to the list by altering the appropriate area of the PrintROMtable routine. To add The QBNews Page 14 Volume 2, Number 3 September 15, 1991 a new font file, search PrintROMtable for: '**** You could create your own 1024 byte The code is self-expanatory and you should not have any trouble adding to the list. If your program is to access one or more of these font files, you might want to establish a default file to use (if you don't designate a default file then the routine sets the default to number 1 -- inter- national). To set a default font file, before you make any calls to PrintROMtable, LET PR.DefaultFile = ? Where ? is the number of the file to use (presently, 1 through 4). Whether a default font file is established or not, you can, at any time, instruct the routine to load any of the font files. First, you should reset the current font file: PR.ReadHiAscFile = -1 CALL PrintROMtable(a$, PR) Then, to set the new file, simply: PR.ReadHiAscFile = 2 (or 3, or 4, etc.) The next call to PrintROMtable will then read and use the new fonts. If your font files are not located in the default path, before you you make your first call to PRINTROMtable, you need to inform it where to look. This, too, is a simple instruction: LSET PR.DiskFontLoc = "C:\OFF\IN\URANUS" Many QB programmers set their SCREEN mode by using literals, ie., they use code similar to, SCREEN 9. PrintROMtable needs to know what screen you are using. To inform it which screen mode is in use, do something like: PR.ScreenMode = 12 SCREEN PR.ScreenMode Putting it all together, your program should look something like: REM $INCLUDE: 'printrom.bi' LSET PR.DiskFontLoc = "D:\SNAZZY\FONT\AREA\" PR.DefaultFile = 1 PR.ScreenMode = 9 SCREEN PR.ScreenMode PR.Height = 8: PR.xAxis = 20: PR.yAxis = 30 PR.StepX = 9: PR.CharClr = 15: PR.Shadow = -1 PrintROMtable "Hello there, my name is", PR The QBNews Page 15 Volume 2, Number 3 September 15, 1991 PR.Tall = -1: PR.xAxis = 20: PR.yAxis = 48 PrintROMtable "John Doe", PR When working from within the QB environment, you need to load QB by typing, "QB /Lqb". The sample program that demonstrates how to use PrintROMtable is named, "ROMTEST.BAS". It is in the file, PRINTROM.ZIP along with PRINTROM.BI, and ROMTEST.MAK. Run QB with the "/Lqb" switch then open the file RomTest.Bas. That's all you have to do. One final note. PrintROMtable can do a great deal of fancy work to your strings. The fancier your output, the more time required to per- form the work. One saving grace is that all of the fancy manipulation performed by PrintROMtable is considerably faster once compiled as an EXE file. However, compiled or not, expect certain processes, such as PR.Elongate = 2 (double wide) to be slower than the simpler processes like 8 pixel high, normal character writes. [EDITOR'S NOTE] All code for this article can be found in PRINTROM.ZIP ********************************************************************** Larry Stone is President of LSRGroup and is involved in writing instructional and large data base application systems for business and institutional clients. He is also the author of SERVICES, a shareware application program rated a trophy by "Public Brand Software". He can be reached at LSRGroup, 2945 "A" Street, North Bend, OR 97459, or in care of this newsletter. **********************************************************************