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

  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 
	


Newsletter written by: Alyce. Comments, requests or corrections

mailto:brosc-@orac.net.au  

mailto:awatso-@wctc.net

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