BMPSHOW.BAS

bmpshow_bitmaps.zip

This module is part of the original MMBasic library. It is reproduced here with kind permission of Hugh Buckle and Geoff Graham. Be aware it may reference functionality which has changed or is deprecated in the latest versions of MMBasic.

10 ' BMPSHOW: displays a 1-bit BMP image
20 ' from Bruce Mitchell <brucepython@gmail.com> 
30 '
40 ' BMP is a format with many variations and vagaries.
50 ' Don't be surprised if some images appear inverted, negative or
60 ' otherwise weird. 
70 ' See en.wikipedia.ord/wiki/BMP_file_format for basic info and some 
80 ' useful references.
90 ' Max image size displayed is 480 wide x 432 high.
100 'Larger images might load OK but only a corner will be shown.
110 'It's slow!
120 '
130 'Possible enhancements might include choices to display the image as:
140 ' * inverted
150 ' * negative
160 ' * flipped horizontally
170 ' * located at x,y rather than top left.
180 '
190 INPUT "BMP file to load: "; f$
200 IF UCASE$(RIGHT$(f$,4))<>".BMP" THEN f$=f$+".BMP"
210 OPEN f$ FOR input AS #1
220 '
230 boundary=4 : ' BMP line data comes in 4 byte chunks.
240 FOR ptr=0 TO 9:a$=INPUT$(1,#1):NEXT: ' Skip the signature field.
250 '
260 'Get data offset.
270 GOSUB 770: offset = byte-1
280 FOR ptr=ptr TO ptr+5:a$=INPUT$(1,#1):NEXT
290 '
300 GOSUB 770:width=byte
310 FOR ptr=ptr TO ptr+1:a$=INPUT$(1,#1):NEXT
320 GOSUB 770:height=byte
330 ptr=ptr+8
340 '
350 ' Get colour depth in bits from &1C.
360 FOR ptr=ptr TO ptr+3:a$=INPUT$(1,#1)
370 NEXT
380 GOSUB 770: depth=byte
390 '
400 IF depth<>1 THEN PRINT "Only 1-bit BMP images are supported.":END
410 '
420 REM PRINT "Height=";height:' Remove REM if you need to check the image size.
430 REM PRINT "Width =";width:'  See above.
440 '
450 CLOSE #1: OPEN f$ FOR input AS #1:' Reset to start of file.
460 FOR ptr=0 TO offset:a$=INPUT$(1,#1):NEXT:' ptr points to start of bitmap.
470 '
480 'Copy the bitmap to the screen.
490 CLS
500 FOR y=height-1 TO 0 STEP -1
510  'Clear the flag that signals the final byte(s) in the row.
520   endbyte=false
530  'Plot the row.
540   FOR x=0 TO width-8 STEP 8
550     GOSUB 820
560   NEXT x
570  ' Are we at a 4-byte boundary?
580   IF x < width THEN
590     endbyte = true
600     ' Padding to the nearest 4-byte boundary exists. 
610     ' Count the pixels to be drawn and draw them, then skip the padding.
620     n=width-x : ' There are n pixels left in the row.
630     IF n>=8 THEN GOSUB 820 : x=x+8 : GOTO 630:'Display eight bits.
640     byte=ASC(INPUT$(1,#1))
650   ENDIF
660   DO WHILE (x MOD boundary)>0
670     a$=INPUT$(1,#1):x=x+1
680   LOOP
690 NEXT y
700 '
710 'Indicate job is done and wait for a keypress.
720 SOUND 440,100
730 IF INKEY$="" THEN GOTO 730
740 END
750 '
760 '============ SUBROUTINES ===============
770 ' Get next two bytes from ptr, return as 'byte', then inc file ptr.
780 lsb=ASC(INPUT$(1,#1)):msb=ASC(INPUT$(1,#1))
790 byte=(msb * 256) + lsb
800 RETURN
810 '
820 ' Display next 8 pixels in the row.
830 byte=ASC(INPUT$(1,#1))
840 IF endbyte=true THEN GOTO 870: 'Short cuts can spill past the edge.
850 IF byte=&hFF THEN RETURN:' Nothing to draw.
860 IF byte=0 THEN LINE(x,y)-(x+8,y),1:RETURN:'Drawing a line is faster.
870 FOR bit=7 TO 0 STEP -1
880   PIXEL(x+7-bit,y)=NOT(byte AND 2^bit)
890 NEXT bit
900 RETURN