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 #62 - JAN 2000

© 2000, Cliff Bros and Alyce Watson - All Rights Reserved

 


Brosco and Alyce have written a Book for Liberty BASIC, which is available in electronic form on a CDROM. For details: http://alyce.50megs.com/sss/cd.htm

In this issue:

  1. Version checking
  2. Reading a file header
  3. Loading and displaying bitmaps in the open source editor - part five
  4. Copy and move any file
  5. BITMAP preview code

In future issues:


As always, comments, questions, requests and corrections are most welcome. We learn through discussion, and by helping one another!

1. VERSION CHECKING

Since Carl Gundel has made the alpha for Liberty BASIC version 2.0 available to us, we need to take care about version checking in our programs. Really, we should have been doing this all along, because new versions of LB provided functions not available in previous versions, so often programs would not run in older versions of LB.

The open source editor will not work properly in LB v2.0. The way that the fonts are sized has changed, probably permanently, so font commands will not be backwards compatible.

According to Carl: "The font sizing is based on point size. LB v1.x uses pixels. I'm not sure what to do with that, but I'll do my best to make it compatible. Backwards compatibility is important to me, but I may need to make some compromises."

In our editor, this means that the font size we have chosen that makes small button captions in v1.42, makes much larger characters and the captions no longer fit on the buttons when used in v2.0. The new font sizing is actually better in keeping with the way fonts are sized in other Windows applications, such as word processors.

In versions up to v1.42, we needed to list a graphicbox command first before we listed other controls in our window setup. If a graphicbox was listed after a button, but in the same location, the graphicbox would obscure the button.

This is not true in v2.0, AND listing the graphicbox first makes the button unusable! For v2.0 programs we MAY need to make a change, and list the graphicbox after the other controls. (Remember, everything is subject to change in version 2.0 -- it is still in its alpha stage!)

Version$ contains the version of Liberty BASIC being run.

print Version$ would produce: 1.42

If we want to insure that Version$ is ONLY 1.42:

if Version$="1.42" then {BASIC code}

Version$ is a string variable. To evaluate it, you may need to use the val() function, as in this example:

if val(Version$) < 2 then {BASIC code}

We'll try to remember to do a version check in our programs from now on. I suspect we will devote a newsletter to updating programs to be v2.0 compliant, when v2.0 goes into beta release. Here's the version check. If the version of LB is greater than 1.42, the program execution is aborted:

 
'** this program will not work in LBv2.0!
    if val(Version$)>1.42 then
        notice "This program will not work in LBv2.0!"
        end
    end if
 


2. READING A FILE HEADER

 

The first section of a bitmap file contains information about the bitmap. Try opening a bitmap file in Notepad. The first two caracters will be "BM". This will be followed by a bunch of characters; some of them will be recognizable, some will be odd-looking, and many will be unprintable.

These characters are evaluated according to their ascii values. Try this little routine, being sure the path and filename are valid on your system. It reads the ascii values of the first 29 characters of a bmp file and prints them in the main window.

 
open "c:\lb142w\bmp\copy.bmp" for input as #b
b$=input$(#b, 29)
close #b 
 
for i=1 to len(b$)
print asc(mid$(b$,i,1))
next i
 

You will get a list that begins like this:

66
77
242
1
0
0
0
0
0
0
118
0
0
0
40
0
0
0
25
0
0
0
25
0
0
0
1
0
4
 

Look at the first two characters. 66 is the ascii value for "B" and 77 is the one for "M". We can read part of this file (the first 29 bytes will be enough) to retrieve information about this bitmap.

The width of the bitmap is contained in characters 19 & 20. Together, they form a "word" value that can be interpreted by Windows programs. We can make sense of this by evaluating the ascii values for characters 19 & 20 in the proper way.

Character 20 will be the "hibyte" when used by api calls. A "word" value consists of a "hibyte" and a "lowbyte". The hibyte portion of a "word" is evaluated by multiplying it by 256. Character 19 will be the "lobyte" part of the "word" value. The two values are added together to get a value for the bitmap width. Pseudo code:

asc(char 19) + {asc(char 20) * 256} = width
 

In our sample, above, the values are

char 19 = 25
char 20 = 0
25 + (0*256) = 25

Our little bitmap has a width of 25 pixels. If instead,

char 19 = 10 
char 20 = 2

then the bitmap width would be:

10 + (2*256) = 522

Height is evaluated in exactly the same way, but using characters 23 and 24, in pseudo code: asc(char23) + {asc(char 24) * 256} = height

In our sample above:

char 23 = 25
char 24 = 0
bitmap height = 25 + (0*256) = 25
 

In our editor, we will add a bitmap previewer tool. When the user chooses a bitmap file, we'll read the header to determine information about the bitmap. Here is the routine we'll use to get the bitmap dimensions. We'll open the file and read in the first 29 bytes. To get a value for character 19, we'll use the mid$() function, reading the header string, pic$ at char 19, for a length of 1:

asc(mid$(pic$,19,1))

We'll get a value for characters, 20, 23 and 24 in the same way. Here it is:

 
[openbmp]
    filedialog "Open Bitmap","*.bmp", picFile$
 
    open picFile$ for input as #pic
    pic$=input$(#pic,29)
    close #pic
 
    bmpwidth = asc(mid$(pic$,19,1)) + (asc(mid$(pic$,20,1)) * 256)
    bmpheight = asc(mid$(pic$,23,1)) + (asc(mid$(pic$,24,1)) * 256)

3. LOADING AND DISPLAYING BITMAPS IN THE OPEN SOURCE EDITOR

 

We have an even more important bit of information to check, though. Since LB v1.42 and below can load bitmaps that have 256 or fewer colors, we will have a program crash if we try to load 16,000,000 color bitmaps. We can find out how many colors are in the bitmap format by checking the color depth from the file header, as we did for the width and height. The color depth will be contained in character 29, so we can get its value like this:

picDepth=asc(right$(pic$,1))
 

In our earlier sample, this value is 4. To determine the number of colors in a bitmap from its depth, we take 2 to a power of picDepth:

    picColors=2^picDepth

In our sample

picColors = 2 ^ 4 = 16
 

Our bitmap is in 16-color format. Liberty BASIC 1.42 can load bitmaps that have 256 or fewer colors. The color depth that corresponds to 256 colors is 8. In our bitmap previewer, if the depth is greater than 8, that means that there are more than 256 colors in the bitmap, and Liberty BASIC cannot load it. If that is the case, we'll give the user the chance to load it and view it in PaintBrush. To run PaintBrush with a bitmap loaded:

run "pbrush "+picFile$ 
 

The complete code for the bitmap previewer is at the end of this newsletter. The complete code for the updated Open Source Editor is attached to the newsletter, since it is getting to be quite lengthy. Here is a routine that traps bitmaps that are formatted to more than 256 colors:

if picColors > 256 then
message$="The chosen bitmap has more than 256 colors, "+_
"so Liberty BASIC cannot load it.  Would you like to "+_
"view it with Paintbrush?"
confirm message$;answer$
 
if answer$="yes" then
run "pbrush "+picFile$
picFile$=""
end if
end if
 

If we find that the bitmap can be loaded in Liberty BASIC, then we load and display it. We will want to set a flag if we have loaded a bitmap, so we can call UNLOADBMP and free the memory consumed by the previous bitmap. Let's call the flag bmploaded, and set it to 1 when we have loaded a bmp:

bmploaded=1

If a bmp was loaded previously, let's unload it, then load the bmp that was chosen (picFile$) as "tempPicture".

if bmploaded=1 then unloadbmp "tempPicture"
loadbmp "tempPicture", picFile$

Since we know the bitmap width and height, we can center it within our graphicbox. Our graphicbox has been created with a width of 410 and a height of 200:

graphicbox #bit.box1, 20,100,410,200

To get the x location to draw the bmp centered, let's check the difference between the width of the graphicbox and the width of the bitmap. Since we want equal parts of the graphicbox to show on both sides of our bmp to center it, we'll divide the difference by 2. We'll do the same thing with the height values for the bmp and the graphicbox to determine the proper y location for the upper left corner of the bmp. Then we'll DRAWBMP at that X, Y location. Remember that variables must be placed outside of quote marks in commands:

 
    xbmp=int((410-bmpwidth)/2)
    ybmp=int((200-bmpheight)/2)
 
    print #bit.box1, "cls"
    print #bit.box1, "drawbmp tempPicture ";xbmp;" ";ybmp
    print #bit.box1, "flush"
    goto [loop]

Notice that we first cleared the screen with CLS. This accomplished two things. It freed the memory from any previous FLUSH commands, and it removed any previous bitmaps from the graphicbox display, so that only the current bitmap will show. Then, we issue a FLUSH command, so that the bitmap will be redrawn if the window is obscured and restored.

We'll set up our bitmap previewer code by listing some new variables to use in the bmp routines, and by adding a Bitmap Preview item to the Tools Menu.

 
'picFile$           filename for opened bitmap
'pic$               string to hold bitmap file header
'savebmpfile$       name to save bmp AS
'picDepth           color depth of bitmap
'picCols            number of colors in bitmap
'bmpwidth           width of bitmap
'bmpheight          height of bitmap
'xbmp               x location to draw bitmap in graphibox
'ybmp               y location to draw bitmap in graphibox
'bmploaded          flag to set when a bitmap is loaded
'message$           string variable to hold notice and confirm messages
 
menu #1, "&Tools",_
    "&Branch Labels",[branchlabels],_
    "Bit&map Preview",[bmp]

When the routine is called, we'll open a window that contains a graphicbox to display the bitmap, some buttons for user interaction, and a textbox to display the bitmap name, and another textbox to display the bitmap dimensions.

[bmp] '** BITMAP PREVIEWER
    WindowWidth=451:WindowHeight=350
 
    button #bit.open, "Open",   [openbmp],  UL,350,5,80,26
    button #bit.save, "Save As",[savebmp],  UL,350,35,80,26
    button #bit.exit, "Exit",   [closebit], UL,350,65,80,26
 
    textbox #bit.t1, 20,35,300,26
    textbox #bit.t2, 20,65,300,26
 
    statictext #bit.s, "Bitmap File:",20,5,150,20
    open "Bitmap Preview" for dialog_modal as #bit
    print #bit, "trapclose [closebit]"

We are using the ctl3d.dll (see Newsletter #61) to make our dialog windows look better, so let's go the extra distance and issue font commands to our controls to make them look a bit better.

print #bit.t1,   "!font Times_New_Roman 0 16"
print #bit.t2,   "!font Times_New_Roman 0 16"
print #bit.save, "!font Times_New_Roman 0 16"
print #bit.open, "!font Times_New_Roman 0 16"
print #bit.exit, "!font Times_New_Roman 0 16"
print #bit.s,    "!font Times_New_Roman 0 16"

When we close our bitmap previewer, we should free the memory used, by issuing CLS and by unloading the current bitmap. We also need to set the flag that indicates a bitmap is loaded back to 0, since the user may want to call on the bitmap previewer again.

[closebit]
    print #bit.box1, "cls"
    close #bit
    if bmploaded=1 then unloadbmp "tempPicture"
    bmploaded=0
    goto [loop]
 


4. COPY AND MOVE ANY FILE

 

Did you notice that we included a button called SAVE AS?

 
    button #bit.save, "Save As",[savebmp],  UL,350,35,80,26
 

We can copy any type of file, by opening it for INPUT, reading it into a string variable, then closing the file. We then open a file with a different name for OUTPUT and write the string to that file. Voila, we have copied and moved a file!

open picFile$ for input as #pf
pic$=input$(#pf, lof(#pf))
close #pf
 
    filedialog "Save As..","*.bmp",savebmpfile$ 
    if savebmpfile$="" then [loop]

In the routine above, we've opened picFile$ for INPUT, and read the contents into the string variable pic$. Then we've closed the file. Next, we get a name from the user to save the file AS. If the user doesn't specify a name, we abort the procedure and goto [loop]

If there is a valid name for the saved file, we open it for OUTPUT, write the string pic$ to the file, then close it.

open savebmpfile$ for output as #bpf
print #bpf, pic$
close #bpf
 


5. BITMAP PREVIEW CODE:

 
'** NEW **
[bmp] '** BITMAP PREVIEWER
    WindowWidth=451:WindowHeight=350
 
    button #bit.open, "Open",   [openbmp],  UL,350,5,80,26
    button #bit.save, "Save As",[savebmp],  UL,350,35,80,26
    button #bit.exit, "Exit",   [closebit], UL,350,65,80,26
 
    textbox #bit.t1, 20,35,300,26
    textbox #bit.t2, 20,65,300,26
 
    graphicbox #bit.box1, 20,100,410,200
    statictext #bit.s, "Bitmap File:",20,5,150,20
    open "Bitmap Preview" for dialog_modal as #bit
    print #bit, "trapclose [closebit]"
 
    print #bit.t1,   "!font Times_New_Roman 0 16"
    print #bit.t2,   "!font Times_New_Roman 0 16"
    print #bit.save, "!font Times_New_Roman 0 16"
    print #bit.open, "!font Times_New_Roman 0 16"
    print #bit.exit, "!font Times_New_Roman 0 16"
    print #bit.s,    "!font Times_New_Roman 0 16"
 
 
    goto [loop]
 
[closebit]
    print #bit.box1, "cls"
    close #bit
    if bmploaded=1 then unloadbmp "tempPicture"
    bmploaded=0
    goto [loop]
 
[savebmp]
    if picFile$="" then
        notice "It is not possible to SAVE.  No Bitmap has been chosen."
        goto [loop]
    end if
 
    open picFile$ for input as #pf
        pic$=input$(#pf, lof(#pf))
    close #pf
 
    filedialog "Save As..","*.bmp",savebmpfile$ 
    if savebmpfile$="" then [loop]
 
    cursor hourglass
    open savebmpfile$ for output as #bpf
        print #bpf, pic$
    close #bpf
    cursor normal
    notice "Bitmap saved as "+savebmpfile$ 
    goto [loop]
 
 
[openbmp]
    filedialog "Open Bitmap","*.bmp", picFile$
    if picFile$ = "" then [loop]
 
    print #bit.t1, picFile$
 
    open picFile$ for input as #pic
    pic$=input$(#pic,29)
    close #pic
    picDepth=asc(right$(pic$,1))
    picColors=2^picDepth
 
    bmpwidth = asc(mid$(pic$,19,1)) + (asc(mid$(pic$,20,1)) * 256)
    bmpheight = asc(mid$(pic$,23,1)) + (asc(mid$(pic$,24,1)) * 256)
 
    if picColors > 256 then
        print #bit.t2, ""
        print #bit.t1, ""
        print #bit.box1, "cls"
        message$="The chosen bitmap has more than 256 colors, "+_
            "so Liberty BASIC cannot load it.  Would you like to "+_
            "view it with Paintbrush?"
        confirm message$;answer$
        if answer$="yes" then
            run "pbrush "+picFile$ 
            picFile$=""
            goto [closebit]
            else
            picFile$=""
            goto [loop]
          end if
    end if
 
    if bmploaded=1 then unloadbmp "tempPicture"
    loadbmp "tempPicture", picFile$
    bmploaded=1
 
    print #bit.t2, "Width:  ";bmpwidth;"    Height:  ";bmpheight;""
 
    xbmp=int((410-bmpwidth)/2)
    ybmp=int((200-bmpheight)/2)
 
    print #bit.box1, "cls"
    print #bit.box1, "drawbmp tempPicture ";xbmp;" ";ybmp
    print #bit.box1, "flush"
    goto [loop]

Newsletter compiled and edited by: Brosco and Alyce. Comments, requests or corrections: Hit 'REPLY' now! mailto:brosc-@orac.net.au or mailto:awatso-@wctc.net