---------------------------------------------------------
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:CarlCourt@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:awatson@wctc.net
---------------------------------------------------------
