---------------------------------------------------------
Brosco's Liberty Basic Newsletter - Issue #14 - July 98
---------------------------------------------------------


Loading and Displaying Images in Liberty BASIC
---------------------------------------------------------
1.  Liberty BASIC Functions
2.  GIFTOBMP.DLL
3.  NVIEWL16.DLL


---------------------------------------------------------
1.  Liberty BASIC Functions

The easiest way to load and display images is to
use LB's loadbmp command for loading and the
drawbmp command to display the image.  The code
looks like this:

   loadbmp "picture","picture.bmp"

The bitmap can be chosen by the user of your program,
with a filedialog like this:

   filedialog "Open bitmap...", "*.BMP", file$

   loadbmp "picture",file$

Once the bitmap has been loaded into memory, it can
be displayed in a window of type-graphics or in a 
graphicbox that is contained in another window.
The drawbmp command would look like this:

   print #grahics, "drawbmp picture X Y"

Where X and Y are the coordinates of the upper left
corner of the bitmap.


Did you ever get an error message when trying to load
a bitmap?  It was probably caused when you tried to
load a bitmap of more than 256 colors.  You can make 
certain that all of the bitmaps associated with your
program are 256 colors or less by checking them in your
Windows Paint program, and reducing the number of colors,
if necessary.  But, if you allow a user to choose a bitmap,
and it has too many colors, you can get a program crash!

There is a solution to this problem, brought to us by
helpful LBers Rick Griffiths and Tom Record.  You need
only open the bitmap file and read the file header after
the user has chosen a bitmap.  If it has too many colors,
your code can trap that before it attempts to load the
bitmap.

Here is the code:

   filedialog "Open bitmap...", "*.BMP", file$

       open file$ for input as #pic
       pic$=input$(#pic,29)
       close #pic

       picDepth=asc(right$(pic$,1))
       picCols=2^picDepth

	if picCols>256 then 
		notice "Error, too many colors!"
		goto [loop]
	end if

   loadbmp "picture",file$
 
   print #grahics, "drawbmp picture X Y"

   goto [loop]


Note that if the bitmap has too many colors, the
program does not attempt to load it, but returns
instead to the input loop, after giving the user an
error message.  If the number of colors is 256 or
less, the program continues and will load and draw
the chosen bitmap.


The next version of Liberty BASIC, which is due for
release very soon, has an added function for bitmaps.
The HBMP function returns the handle Windows gives to
the bitmap.  The code:

   loadbmp "picture",file$

   hPic=hbmp("picture")


This function is incredibly handy when manipulating
images in memory, which is done in sprite animation.
It also allows us to get information about our bitmap
with a call to GDI.exe, a Windows Dynamic Link Library
(DLL).

To get the information, we must first build a STRUCT to
hold it.  Here is the proper struct for a BITMAP:

	struct BITMAP,_ '14 bytes
		bmType as short,_
		bmWidth As short,_
		bmHeight As short,_
		bmWidthBytes As short,_
		bmPlanes as ptr,_
		bmBitsPixel as ptr,_
		bmBits as Long

With our struct defined, we can load our bitmap and 
retrieve its handle:

   loadbmp "picture",file$

   hPic=hbmp("picture")

Next, we open the dll for use and make the call to GetObject.  
The first parameter in the call is the handle of the bitmap
(hPic).  The second parameter is the number of bytes we have 
in the STRUCT (14).  The third parameter is the name of the 
STRUCT, itself (BITMAP)  The function returns the number of
bytes retrieved, or null, on error:

	open "gdi" for dll as #gdi
		calldll #gdi, "GetObject",_
		hPic as word,_ 
		14 as short,_
		BITMAP as struct,_
		results as short
	close #gdi

We can get the values from the struct by assigning them to
variable names.  The most useful ones are the width and
height of the bitmap.  Here is the retrieval code:

	type=BITMAP.bmType.struct
	width=BITMAP.bmWidth.struct
	height=BITMAP.bmHeight.struct
	wbytes=BITMAP.bmWidthBytes.struct
	bplanes=BITMAP.bmPlanes.struct


---------------------------------------------------------
The drawbacks here are that LB only supports BMPs
of 256 or fewer colors, and that BMP files can
be quite large.  Some third party DLL's can be
used with LB to get around these limitations.
Although there are a number of expensive DLL's
available, we'll focus on two that are freeware,
the GIFTOBMP.DLL and the NVIEWL16.DLL.


---------------------------------------------------------
2.  GIFTOBMP.DLL


The file size of some bitmaps can be quite large.
A GIF file of the same image can be much smaller.
LB does not directly support the loading and
displaying of GIFs, but it can be done with the
giftobmp.dll.  The DLL itself is only 8 KB.  It
converts a GIF file to a BMP file on disk, which LB 
can then easily load and display.  The resulting
BMP file may be kept, or deleted at the end of the
program.  It appears to be limited to GIFs of type
87a - noninterlaced.

It is available at Alyce's Restaurant:
http://www.wctc.net/~awatson/liberty.html


The call to the DLL is as follows:

	Open "giftobmp.dll"for DLL as #gb

	calldll #gb, "GIFToBMP",_
	    lpstrGIF$ AS ptr,_
	    lpstrBMP$ AS ptr,_
	    RESULT AS short
	Close #gb

The paramater lpstrGIF$ is the filename of the GIF.
The parameter lpstrBMP$ is the filename of the 
new BMP.

As used in a program, it might look like this:

	Open "giftobmp.dll"for DLL as #gb

	calldll #gb, "GIFToBMP",_
	    "rocket.gif" AS ptr,_
	    "ship.bmp" AS ptr,_
	    RESULT AS short
	Close #gb

	loadbmp "ship", "ship.bmp"
	print #graphics, "drawbmp ship 0 0; flush"

	kill "ship.bmp"  'this line is optional

In this example, the file "rocket.gif" is changed 
into a Windows bitmap by the giftobmp.dll and is 
written to the disk with the filename "ship.bmp."
It is then loaded into memory with LB's LOADBMP
command, and drawn in the graphics window with the
DRAWBMP command.  Notice that we don't need to check
for the number of colors, because the GIF format 
supports only 256 colors, so it is automatically
compatible with LB.  We have a command at the end
of the routine to delete the created ship.bmp file.
This line is optional.  If, for some reason, you
want to retain the image as a bitmap on disk, do not 
use the KILL command.


---------------------------------------------------------
3.  NVIEWL16.DLL

The nviewl16.dll is a freeware product that
will convert images in several popular formats,
including GIF and JPG and load them into memory.

This allows LB users to load and display images that
are as much as 24-bit (16 million) colors - much
more than the 256 color limitation imposed by
Liberty BASIC's loadbmp command.  The other big
advantage is that GIF and JPG files are much
smaller than their BMP counterparts.

It was written by K. Nishita and is available at:
http://einstein.ae.eng.ua.edu/nishita/Download.htm

It is also available at Alyce's Restaurant:
http://www.wctc.net/~awatson/liberty.html

Brosco's Liberty BASIC Resource Centre:
http://users.orac.net.au/~brosco


There are two drawbacks to using this DLL.  The 
first is that it requires quite a bit of extra
code.  The second, more serious drawback is the 
way memory is handled.  If only a few images are
loaded this way, there is no problem.  If many
images are loaded this way, a huge swap file is
created on the hard drive and it is only cleaned
out when Liberty BASIC quits running. 

The call to the dll is as follows:

file$ is the name of the image file to be loaded.
pBar=1 shows a progress bar while loading.
pBar=0 does not show a progress bar.
hBitmap is the handle of the newly created
bitmap in memory that is returned by the DLL. 

    open "NViewL16.dll"for DLL as #nv
	calldll #nv, "NViewLibLoad",_
	    file$ AS ptr,_
	    pBar AS short,_
	    hBitmap AS short
	close #nv


In a program, the code might look like this:

    open "NViewL16.dll"for DLL as #nv
	calldll #nv, "NViewLibLoad",_
	    "scene1.jpg" AS ptr,_
	    1 AS short,_
	    hScene AS short
	close #nv

Now the image is loaded into memory as a bitmap.
It takes some further code to get it onto the
screen.

1.  GetDC to get the device context of the window.
2.  CreateCompatibleDC to create a memory device
    context to handle the image in memory.
3.  SelectObject to select the bitmap into the
    device context in memory.
4.  BitBlt to transfer the bitmap to the screen.
5.  ReleaseDC to release the window's device
    context.
6.  DeleteDC to remove the created device context.
7.  DeleteObject to remove the bitmap from memory.


It seems pretty complicated, so here is the code
for a simple image viewer, using the nviewl16.dll:


nomainwin

a = 1  'enable progress bar   0 disables progress bar

    UpperLeftX = 1 
    UpperLeftY = 1
    WindowWidth = 640
    WindowHeight = 480
    graphicbox #1.g, 0, 0, 630, 433

MENU #1, "Menu", "Choose Image", [choose.image], "Exit", [quit]
open "Liberty BASIC Image Viewer" for window as #1

print #1,"trapclose [quit]"
print #1.g, "fill lightgray;flush;discard;redraw"

[startup]
    open "NViewL16.dll"for DLL as #nv
    open "gdi" for dll as #gdi
    open "user" for dll as #user

h = hwnd(#1.g) 'handle of graphicbox

      calldll  #user ,"GetDC",_   'get a device context--DC
        h as word,_               'for the graphicbox
        hdc as word

' create a device context (DC) for our new image in memory
    calldll #gdi,"CreateCompatibleDC",_
    hdc as word,_         'the dc of the window
    hdcdib as word        'create dc for memory image

	struct BITMAP,_ '14 bytes
		bmType as short,_
		bmWidth As short,_
		bmHeight As short,_
		bmWidthBytes As short,_
		bmPlanes as ptr,_
		bmBitsPixel as ptr,_
		bmBits as Long

[loop]
input r$
    goto [loop]

[choose.image]

type$="*.JPG;*.JIF;*.GIF;*.BMP;*.DIB;*.RLE;*.TGA;*.PCX"
filedialog "Open image file", type$, file$


[newpic]
print #1.g, "fill lightgray"

calldll #nv, "NViewLibLoad",_
    file$ AS ptr,_
    a AS short,_
    handib AS short

[get.dimensions]
	calldll #gdi, "GetObject",_
	handib as word,_ 
	14 as short,_
	BITMAP as struct,_
	results as short

	width=BITMAP.bmWidth.struct
	height=BITMAP.bmHeight.struct


[display.new.image]
'transfer completed new image to screen
    calldll #gdi,"SelectObject",_
    hdcdib as word,_     'dc of memory image
    handib as word,_     'handle of bitmap in memory
    ro as word

    calldll #gdi,"BitBlt",_
    hdc as word,_          'destination is display window
    0 as word,_            'x location to place image
    0 as word,_            'y location to place image
    width as word, _       'width
    height as word,_       'height
    hdcdib as word, _      'source to copy from is newmemory
    0 as word, _           'x location in memory
    0 as word, _           'y location in memory
    13369376   as long, _  'constant for srccopy
    r as ushort
goto [loop]

[quit]
    calldll #gdi,"DeleteObject",handib as word,r as ushort
    calldll #gdi,"deleteDC",hdcdib as word,r as ushort
    calldll#user,"ReleaseDC",h as word,hdc as word,result as ushort

close #nv
close #1
close #user
close #gdi

end


--------------------------------------------------------------
 Newsletter written by: Alyce.
 Comments, requests or corrections mailto:brosco@orac.net.au
    				      mailto:awatson@wctc.net

 Translated from American to English by an Australian:
 Cliff Bros -  Chief Editor.  Thanks Cliff.

-----------------------------------------------------------------

