Liberty Basic is develeopped by Carl Gundel
Original Newsletter compiled by Alyce Watson and Brosco
Translation to HTML: Raymond Roumeas

The Liberty Basic Newsletter - Issue #54 - NOV 99

© 1999, Alyce Watson All Rights Reserved

In this issue:

BMPpacking Technique - courtesy of Carl Courtney


A short time ago, Carl Courtney shared a new technique with us. He was looking at dozens of little bitmaps that were used in his program, and wondering if there were some way to place them all into a single data file. Not only would that make a much cleaner program directory, but it would also make it less likely that bitmap files would get lost or corrupt, making his application unusable.

The method he used is quite clever and innovative -- and it works! Here are the steps he uses:

  1. Place the data for the needed bitmaps into a data file, with each bitmap occupying one line of the file.
  2. Within the program, open the data file for input.
  3. Read the next line of data into a string variable using the LINE INPUT command.
  4. Open a new file for output, with BMP extension.
  5. Print the string to the output file.
  6. Close the output file.
  7. Repeat lines 3 - 7 until the end of the file is reached.
  8. Close the data file.
  9. Use the LOADBMP command to load all of the bitmaps from the newly created files.
  10. Issue DRAWBMP commands whenever neede in the program.
  11. After using LOADBMP, all of the new bitmap files may be killed. The user will never even see them!
  12. Unload bmps when the program closes.

This method works with 16-color bitmaps only. There are some bitmaps that will not work. Any bitmap with a width or height of 13 pixels will fail. Some bitmaps include a chr$(13) within their data and will also fail. The chr$(13) is read as the end of a line by the LINE INPUT command, corrupting the current bitmap and all that follow.

Carl has shared a couple of methods with us earlier, showing us how to pack the bitmaps into a data file, using Liberty BASIC, of course! He has also shared his unpacking and loading methods. There are any number of ways that this data could be handled. The bitmap names can be in a separate data file, which is opened and read into an array by your program. The bitmap data itself would be in the same order as the names in the data file. Another method would be to hardcode the bitmap names into the program. Yet another method would be to include the bitmap names in the bitmap data file, with one line containing a name, and the next line in the file containing the data for that bitmap.

Here is a little utility that allows you to create or open a data file, and add as many as 100 bitmaps. It has error- checking to insure that the bitmaps you try to load have only 16 colors. It also checks for the inclusion of chr$(13). When you exit the bmppacker, it generates code for you to use in your program. You may also use the bmppacker to view the bitmaps contained in a bmp-data file.

If you use this technique in a program, it would be very nice indeed if you would give credit to Carl Courtney. It would also be great if you would send him a message, telling him that you appreciate the technique.

Carl Courtney

mailto:carlcour-@aol.com


'utility to pack bmps into a single data file for distribution
dim bn$(100)
addnum=1
nomainwin
notice "Bitmap Packer"+chr$(13)+chr$(169)+" Carl Courtney"+chr$(13)+_
"Use this utility to load 16-color bitmaps"+chr$(13)+_
"into one data file for distribution."
UpperLeftX=50:UpperLeftY=20
WindowWidth=400:WindowHeight=300
button #1.create,"Create New",[create],UL,10,10,160,26
button #1.open,"Open Data",[open],UL,10,40,160,26
button #1.add,"Add Bmp",[add],UL,10,70,160,26
button #1.finish,"Exit/Make Code",[finish],UL,10,100,160,26
listbox #1.list,bn$(,[showthis],180,10,200,230
graphicbox #1.g, 10,140,160,100
open "Bitmap Packer"for window as #1
print #1, "trapclose [quit]"
print #1.g, "cls;fill lightgray"
print #1.create, "!font Courier_New 0 18"
print #1.open, "!font Courier_New 0 18"
print #1.add, "!font Courier_New 0 18"
print #1.finish, "!font Courier_New 0 18"
print #1.list, "font Courier_New 0 18"
print #1.list, "singleclickselect"
 
[loop]
 
input a$
 
 
 
[quit]
confirm "Would you like to create unpacking code?";answer$
if answer$="yes" then
goto [finish]
else
close #1:end
end if
goto [loop] 'why did I put this here?
 
 
[create]
filedialog "Name data file:","*.dat",datafile$
open datafile$ for append as #d
lenfile=lof(#d)
close #d
if lenfile>1 then
confirm "This file already exists. Overwrite it?";answer$
if answer$="no" then [loop]
end if
 
 
'erase oldfile
open datafile$ for output as #k
close #k
goto [loop]
 
 
 
[open]
addnum=1
filedialog "Open data file:","*.dat",datafile$
if datafile$="" then
notice "Not a valid file."
goto [loop]
end if
open datafile$ for input as #td
while eof(#td)=0
line input #td, tempname$
line input #td, dum$
bn$(addnum)=tempname$
open tempname$ for output as #z
print #z, dum$
close #z
addnum=addnum+1
wend
close #td
print #1.list, "reload"
goto [loop]
 
 
[add] 'add bmp name and data to end of file
if addnum>=100 then
notice "This program is set up for files of no more than 100 bmps."
goto [loop]
end if
 
 
if datafile$="" then
notice "You must create a data file, or open an existing data file."
goto [loop]
end if
 
 
filedialog "Open Bmp..","*.bmp",bmpfile$
if bmpfile$="" then [loop]
 
 
 
open bmpfile$ for input as #pic
pic$=input$(#pic,29)
close #pic
 
 
 
' ** check for number of colors:
picDepth=asc(right$(pic$,1))
if picDepth > 4 then
notice "The chosen bitmap has more than 16 colors, so it may not be used."
goto [loop]
end if
 
 
' ** check for width and height:
loadbmp bmpfile$,bmpfile$
hBitmap=hbmp(bmpfile$)
struct BITMAP,bmType as short,bmWidth As short,bmHeight As short,_
bmWidthBytes As short,bmPlanes as ptr,bmBitsPixel as ptr,bmBits as Long
 
 
open "gdi" for dll as #gdi
calldll #gdi, "GetObject",hBitmap as word,14 as short,BITMAP as struct,results as short
close #gdi
 
 
 
width=BITMAP.bmWidth.struct
height=BITMAP.bmHeight.struct
unloadbmp bmpfile$
if width=13 or height=13 then
notice "Bitmaps that are 13 pixels wide or high may not be packed."
goto [loop]
end if
 
 
 
open bmpfile$ for input as #bmp
bmp$=input$(#bmp,lof(#bmp))
close #bmp
 
 
 
' ** check for stray chr$(13):
if instr(bmp$,chr$(13))>0 then
notice "This bitmap file is goofy and may not be packed."
goto [loop]
end if
 
gosub [makebmpname]
 
 
 
open datafile$ for append as #df
print #df, bmpname$
print #df, bmp$
close #df
 
 
open bmpname$ for output as #z
print #z, bmp$
close #z
 
 
bn$(addnum)=bmpname$
addnum=addnum+1
print #1.list, "reload"
 
 
 
loadbmp "test",bmpname$
print #1.g, "cls;fill lightgray"
print #1.g, "drawbmp test 10 10"
unloadbmp "test"
goto [loop]
 
 
[showthis] 'finds name clicked on list, displays bmp
print #1.list, "selection?"
input #1.list, bmpchosen$
if bmpchosen$="" then [loop]
 
 
 
open datafile$ for input as #df
guess$=""
while eof(#df)=0 and guess$<>bmpchosen$
line input #df, guess$
wend
 
 
line input #df, ab$
close #df
open bmpchosen$ for output as #test
print #test, ab$
close #test
 
 
loadbmp "test",bmpchosen$
print #1.g, "cls;fill lightgray"
print #1.g, "drawbmp test 10 10"
unloadbmp "test"
goto [loop]
 
 
[makebmpname] 'makes new bmpname
bmpname$=bmpfile$
i=len(bmpname$)
while mid$(bmpname$,i,1)<>"\"
i=i-1
wend
bmpname$=mid$(bmpname$,i+1)
bmpname$=left$(bmpname$,len(bmpname$)-3)
bmpname$=bmpname$+"btm" 'makes filename different to avoid errors
return
 
 
[finish]
if datafile$="" then
confirm "There is no datafile selected. Do you want to quit?";answer$
if answer$="yes" then
close #1
end
else
goto [loop]
end if :end if
 
close #1
 
 
 
[killbitmaps]
for i = 1 to addnum-1
kill bn$(i)
next i
redim bn$(0) 'release memory
 
 
WindowWidth=640:WindowHeight=480
open "Bmp Unpacking Code" for text as #q
print #q, "!trapclose [quitcode]"
 
 
 
print #q, "'********************************************************************"
print #q, "'** Copy and paste this unpacking code routine into your program. **"
print #q, "'** **"
print #q, "'** BMPpacking technique by Carl Courtney, 1999 **"
print #q, "'********************************************************************"
print #q, "DIM bitmapname$(100)"
print #q, "DIM bitmapdata$(100)"
print #q, "OPEN "+chr$(34)+datafile$+chr$(34)+" for input as #data"
print #q, "index=0 '** counter for number of bitmaps"
print #q, "WHILE EOF(#data)=0 '** while not at end of file"
print #q, " index = index + 1"
print #q, " LINE INPUT #data, tempname$"
print #q, " bitmapname$(index) = tempname$"
print #q, " LINE INPUT #data, tempdata$"
print #q, " bitmapdata$(index) = tempdata$"
print #q, "WEND"
print #q, "CLOSE #data"
print #q, ""
print #q, "FOR counter = 1 to index 'this writes a bmp file on disk"
print #q, " open bitmapname$(counter) for output as #bz"
print #q, " print #bz, bitmapdata$(counter)"
print #q, " close #bz"
print #q, "NEXT counter"
print #q, ""
print #q, "FOR counter = 1 to index 'this loads all of the new bmp files"
print #q, " LOADBMP bitmapname$(counter), bitmapname$(counter)"
print #q, " print bitmapname$(counter) 'use this line to print bmp names in mainwindow"
print #q, "NEXT counter"
print #q, ""
print #q, ""
print #q, "'** you may use the bmps as bmpbuttons"
print #q, "BMPBUTTON #example.b, "+chr$(34)+bn$(1)+chr$(34)+", [exampleloop], UL, 10, 10"
print #q, "OPEN "+chr$(34)+"Example Window"+chr$(34)+" for graphics as #example"
print #q, ""
print #q, "'** you may now draw any bmps in your program with the DRAWBMP command"
print #q, " print #example, "+chr$(34)+"DRAWBMP "+chr$(34)+";bitmapname$(index);"+chr$(34)+" 10 100"+chr$(34)
print #q, " print #example, "+chr$(34)+"trapclose [examplequit]"+chr$(34)
print #q, ""
print #q, "[exampleloop]"
print #q, " beep"
print #q, " input aVar$"
print #q, ""
print #q, "[examplequit]"
print #q, "FOR counter = 1 to index"
print #q, " KILL bitmapname$(counter) 'use this to kill files after they are loaded"
print #q, " UNLOADBMP bitmapname$(counter) 'use this to unload bmps from memory"
print #q, "NEXT counter"
print #q, ""
print #q, "REDIM bitmapname$(0) 'release memory for this array"
print #q, "REDIM bitmapdata$(0) 'release memory for this array"
print #q, ""
print #q, "close #example:end"
print #q, ""
print #q, "'** Copy and paste this unpacking code routine into your program"
print #q, "!origin 1 1";
 
goto [loop]
 
 
[quitcode]
 
close #q:end


mailto:awatso-@wctc.net