BSAVE (graphics image format)

From Wikipedia, the free encyclopedia

Fig. 1 Typical IBM 4-Color CGA BSAVED Graphics Screen
Fig. 1 Typical IBM 4-Color CGA BSAVED Graphics Screen

Contents

[edit] Synopsis

A BSAVE Image (aka "BSAVED Image") as it is referenced in a graphics program is an image file format created usually by saving raw video memory to disk (sometimes but not always in a BASIC program using the BSAVE command).[1]

This format was in general use when the IBM PC was introduced. It was also in general use on the Apple II in the same time period. The Commodore 128 followed with the addition of the BSAVE and BLOAD Commands a short time later.

On the IBM, BSaved graphics and text images could be created for any video mode, with more complexity for the newer modes. On the Apple II and Commdore 128 BSaved Graphics were generally all that was used.

[edit] Typical file format

The BSAVED format is a device-dependent raster image format; the file header stores information about the display hardware address, and the size of the graphics data. The graphics data follows the header directly and is stored as raw data in the format of the native adapter's addressable memory.

There is no file compression, and therefore these load very quickly and without much programming when displayed in native mode.

No additional information such as (screen resolution, color depth and palette information, bit planes and so on) is stored. Video adapters were simple when this format was in wide use and the other information to load these could usually be inferred by programs that loaded these.

[edit] Origin

The BASIC programming language was shipped as part of the operating system on the first IBM PCs, Apple and Commodore 8-bit (like Commodore 64/128) computers. On computers that did not start up in BASIC, BASIC was loaded by running a program called an interpreter. The user could then type BASIC commands in "immediate mode" or by creating and/or running a numbered BASIC program within the interpreter.

One of the commands that early BASIC offered was BSAVE (Binary Save) and another (complementary) command was BLOAD (Binary Load). Using the BSAVE command, an addressable area and length of memory could be saved to disk as a named file (referred to as an "Image").[1] This "Image" of saved memory could then be reloaded from disk into addressable memory later with the BLOAD command.[2] If the BSAVEd image contained program code it could be executed, if data it could be used again, and if the BSAVEd image contained graphics it could be viewed. The video area of memory was addressable.

The PUT and GET commands were used in addition to the BSAVE and BLOAD commands on the IBM PC to allow "clips" of the screen (or the entire screen) to be pre-formatted for BSAVE and BLOAD. These commands added image height and width to the BSAVE format, and were later carried over into the C programming language by some compiler vendors for the MS-DOS platform as the putimage() and getimage() run-time library functions. PUT and GET allowed display modifier verbs which resembled functions in the Windows Graphical Device Interface (GDI) used by programmers later.

Microsoft evolved and produced the BASIC interpreters that were bundled with the IBM PC, Apple II, and Commodore 128, and included the ability to BSAVE and BLOAD RAM memory images on all 3 platforms. While it is not clear whether or not Microsoft and its founder Bill Gates originated the BSAVE format they can be clearly credited with providing continued support for the BSAVEd Graphics Image throughout the history of its use by making it accessible to all users of these platforms and by completely documenting its use.

The BSAVE format of that time can be compared to some intents and purposes to the Windows BMP and DIB that came later.

[edit] Historical Use

It was generally more common for computer users of the day (most who knew how to program in BASIC to some degree) to use the BLOAD command to load a graphics image that had been BSAVED than to load a BSAVED executable or data image.

Most early drawing programs allowed their graphics images to be BSAVED, making them easily available by an average user to be BLOADED back into video memory and viewed in a simple external program written in BASIC.

[edit] Recent Use IBM PC

Common use of BSAVED images in graphics programs continued well into the 1990s but their use was primarily limited to users of programs like the Freeware program PicEM and the Shareware program VGACAD (which saved the MCGA display to a BSAVED file format called BLD BLoaDablepicture), and by beginning programmers and enthusiasts.

With the passing of MS-DOS so did the use of DOS programs that saved in the BSAVED format. Their use by programmers has stopped because the BLOAD command is no longer supported in modern programming languages which discourage accessing video memory directly.

[edit] Specifications IBM PC

[edit] CGA Specification

CGA memory starts at memory segment B800h offset 0. Up to 16K of memory is available for video.

The amount of memory used for display depends on the video mode selected. A graphics screen requires 16000 bytes of memory and an 80 x 25 text screen requires 4000 bytes. A 40 x 25 text screen requires 2000 bytes.

The 3 common video modes are monochrome graphics, 4-color graphics or 80 column x 25 row color text.

A low-resolution 160 x 100 x 16 color graphics mode unofficially called "XCGA" and not supported in BIOS (interrupt 10h) also existed and had limited popularity amongst enthusiasts for a while. Technically this mode worked like color text mode. (see Color Graphics Adapter.)

40 column text mode was not generally used for BSAVED images.

[edit] Text

Fig. 2 Typical BSAVED Text Screen using Graphics Characters
Fig. 2 Typical BSAVED Text Screen using Graphics Characters

80 column text is stored in 4 pages of 4000 bytes each. Generally only page 1 was used for BSAVED text images. Each character in an 80 column x 25 row text screen is stored in a contiguous byte array of character, attribute pairs of 2 bytes per text character. The attribute byte stores the foregroung color in in the low nibble and the background color and blink attribute in the high nibble. The colors 0-16 correspond to the colors offered by the basic 16 color EGA.

These could be cross-loaded to a low-end monochrome text video display with only 4K of memory with varying degrees of success since the color attributes on monochrome displayed differently.

The file extension that became popular for the BSaved text screen format was .BSV.

In the BBS days before the Internet was widely used, many Sysops used a program called TheDraw© from TheSoft Programming Services in Fremont, CA as the tool-of-choice to design and build user interface screens. Programmers used TheDraw© to design text-based user interfaces, or to edit screens that had been captured from other text programs, and then often would display these edited screens in their own programs, or as slideshows for proof-of-concept and so-forth. TheDraw© saved in various formats including BSAVED with the default file extension of .BSV.

[edit] Header

The following C language source code documents the header and tailer in a BSAVED text image:

/* a Microsoft compatible bsaved memory text image format descriptor */
unsigned char BSV_header[7]={

    '\xfd',          /* ID Flag = file descriptor identifier bsaved file */

    '\x00', '\xb8',  /* base address     = LSB | MSB original segment    */
    '\x00', '\x00',  /* offset from base = LSB | MSB original offset     */

    '\xA0', '\x0F'   /* data size = LSB | MSB of bytes to be loaded +    */
    };

unsigned char BSV_image[4000];

unsigned char BSV_tailer[1]={
    '\x1A'                      /* traditionally used by BASIC */
    };                          /* as a terminator */

[edit] Example

By contrast the following tiny GWBASIC program demonstrates how easy it was to load these in BASIC.

1  DEF SEG=&HB800
2  KEY OFF
3  CLS
4  FILES "*.BSV"
5  INPUT"Enter Name of Image To Load. <Blank Ends> : ",A$
10 IF A$="" THEN SYSTEM
30 BLOAD A$,0
40 A$=INPUT$(1)
50 GOTO 3

[edit] Graphics

The CGA Video Card (and other IBM PC video cards which support CGA which until recently were almost all) has two interleafs when in monochrome or 4-color Graphics mode. Visible memory is 16000 bytes. There is 192 bytes of unused data between the first and second interleaf, and 192 bytes of unused data following the second interleaf. The byte array is identical for either mode.

[edit] Typical Variations

File Size 16392 bytes Header Size 7 bytes First Interleaf 8000 bytes Unused 192 Bytes Second Interleaf 8000 bytes Unused 192 Bytes Tailer Size 1 byte

Variations on the above include a smaller BSaved file format that does not load the unused memory after the second interleaf, nor the traditional trailer byte 0x1a (CPM EOF). This resulted in a slight saving of disk space.

File Size 16199 bytes Header Size 7 bytes First Interleaf 8000 bytes Unused 192 Bytes Second Interleaf 8000 bytes

A variation of the BSAVED CGA Image used by the earliest version of PCPaint stored a signature followed by a 2 byte palette index in the unused area directly following the first interleaf.

In the beginning BSAVED CGA Images were usually saved with either a .BAS or a .PIC extension. In the end, the .BAS extension was almost always used.

[edit] Pixel Data

Monochrome data is stored as 1 bit per pixel with pixel(0,0) (x,y) being the high bit in the first byte and pixel(0,7) being the low bit in the first byte. The horizontal resolution for a monochrome CGA image is 640 pixels.

Color data is stored as 2 bits per pixel with pixel(0,0) (x,y) being the 2 highest bits in the first byte and pixel(0,3) being the 2 lowest bit in the first byte. The horizontal resolution for a monochrome CGA image is 640 pixels. The nominal color values are either BLACK, CYAN, MAGENTA, WHITE or BLACK, GREEN, RED, and ORANGE in color order depending on which of the two palettes was selected, with variations on border color (color 0). A third palette was available on some cards as well with nominal values of BLACK, CYAN, RED, WHITE. The horizontal resolution for a monochrome CGA image is 320 pixels.

The interleaf breaks on 80 byte boundaries which means that byte[80] is displayed starting at pixel(2,0), and conversely byte[8192] is displayed starting at pixel(1,0), and so it goes. Both color and monochrome have a vertical resolution of 200 scanlines.

[edit] Cross-Loading


Fig. 3 4-Color BSAVED Graphics Screen displayed in Monochrome
Fig. 3 4-Color BSAVED Graphics Screen displayed in Monochrome


Because the monochrome and color images could be cross-loaded, a color image displayed in monochrome would be naturally dithered because of the bit alteration provided by the bit pairs in colors 1 and 2. Color 0 was still BLACK and color 3 was still WHITE. This dithering was fairly good for printouts of color images on the black and white printers of the day.

Fig. 4 Monochrome BSAVED Graphics Screen displayed in 4-Color CGA Mode
Fig. 4 Monochrome BSAVED Graphics Screen displayed in 4-Color CGA Mode


Monochrome images displayed in color didn't do so well. The aliasing of pixels that were not paired on bit boundaries created CYAN and MAGENTA anomalies which usually looked terrible.

[edit] Header

The following C language source code documents the header and tailer in a BSAVED graphics image:

/* a Microsoft compatible bsaved memory image format descriptor */
unsigned char PUT_header[7]={

    '\xfd',          /* ID Flag = file descriptor identifier bsaved file */

    /* BASIC will use original segment and offset information  */
    /* to reload a memory image unless "DEF SEG" has been used */
    /* and then an explicit offset is used as the second arg   */
    /* of the bload command.  If an offset is specified without*/
    /* first calling DEF SEG, The image will then be loaded to */
    /* the offset specified in the last segment pointed to     */
    /* by the last call to DEF SEG. DEF SEG without args returns */
    /* to DGROUP (the default data segment)                      */

    /* if loading a data array like an image fragment */
    /* we would first dimension the array as an integer array */
    /* which allocates memory just like malloc() and by the way */
    /* not like the Dim command works in VB.NET in 2007 */

    /* we would normally implement using an array in memory and */
    /* VARSEG and VARPTR to obtain the window for the array's   */
    /* memory location, i.e. override the defaults by windowing */
    /* to the array base using DEF SEG = VARSEG(arrayname(0)) then to    */
    /* fill the array we would use BLOAD arrayname, VARPTR(arrayname(0)) */
    /* using VARPTR to point to the offset from the memory base segment  */

    /* remember that this is intel byte order - unsigned short in win32  */
    '\x00', '\xb8',  /* base address     = LSB | MSB original segment    */
    '\x00', '\x00',  /* offset from base = LSB | MSB original offset     */

    '\x00', '\x40'   /* data size = LSB | MSB of bytes to be loaded +    */                    
    };

unsigned char PUT_image[16384];

unsigned char PUT_tailer[1]={
    '\x1A'                      /* traditionally used by BASIC */
    };                          /* as a terminator */

[edit] Example

The following GWBASIC program shows by how easy it was to load and save these in BASIC. It loads an existing image, draws a border around it and saves it.

10 INPUT"PICNAME : ", A$
20 INPUT"border color : ",B$
30 B%=VAL(B$)
40 SCREEN 1
50 DEF SEG=&HB800
55 BLOAD A$
60 LINE (0,0)-(319,199),B%,B
61 LINE (1,1)-(318,198),B%-1,B
62 LINE (2,2)-(317,197),B%,B
63 LINE (3,3)-(316,196),0,B
70 BSAVE A$,0, 16384
80 SYSTEM

[edit] XCGA Low Resolution Graphics

The Color Graphics Adapter page elsewhere on Wikipedia calls this mode "The 160×100 16 color mode".

XCGA mode as it was known as in the late 1980s enjoyed a brief notoriety amongst enthusiasts but never served any practical purpose because it was too coarse for even for the primitive graphics of the day.

Even so, computers equipped only with a CGA video adapter were still prevalent, with users who wanted to display graphics in more than the 4 color maximum that CGA graphics offered.

XCGA images were generally created by reducing images produced in higher resolution to a lower resolution facsimile by the use of file conversion software. This was generally done by enthusiasts as more of a novelty than for any real purpose.

BSAVED XCGA Images were usually saved with a .BAS or a .CGX extension.

[edit] Memory

The memory on XCGA was a contiguous byte array (just like MCGA mode) and was not interleaved like other CGA graphics modes. It started at memory segment B800 like all CGA video memory, and displaying the first 16000 bytes of the segment.

[edit] Header

The BSAVED image header was the same as the other CGA BSAVED headers, but the data length was 16000.

[edit] Pixel Data

Pixels were in a raw format, arranged in pixel pairs called "big pixels" with 2 bytes per each 2 pixel-color pair stored in a contiguous byte array of 8000 big pixels.

Since XCGA was technically a color text mode, the first byte in a big pixel was actually the top two scanlines of a "text graphics" character in video ROM. As in color text mode the second byte stored the foreground color in the low nibble and the background color in the high nibble. (see Color Graphics Adapter.)

The colors 0-16 corresponded to the colors offered by the basic 16 color EGA.

By selecting the appropriate 2 pixel text block graphics character from the video ROM, even though the technical resolution was 80 x 100, the effective resolution was 160 x 100. Fig. 2 above uses the same graphics character normally used in in an XCGA image to display a graphic in standard color text mode

Each scanline was 160 bytes long.

[edit] Example

The following QuickBasic source code shows how a low resolution BSAVED Image with 16 Colors was displayed. The commands are the same as displaying BSAVE images in standard CGA graphics or text modes with the addition of setting of registers on the CGA's MC6845 CRT controller.

CGXNAME$ = Command$:                    'get name from Command line
On Error GoTo NoFile

Open CGXNAME$ + ".CGX" For Input As 1:  'make sure it exists
Close

GoSub SetXCGA                           'trigger 160x100x16 mode
DEF SEG = &HB800                        'change DSEG to screen
BLOAD CGXNAME$ + ".CGX", 0              'dump picture to screen
a$ = INPUT$(1)
Screen 2: Screen 0: End                 'restore text mode and exit

NoFile: Beep:
        Print "Cannot find " + CGXNAME$
        End

SetXCGA:

'WARNING: Changing these registers settings may cause a CRASH !

DEF SEG = 0
POKE &H465, 0: OUT &H3D8, 0:
POKE &H466, 0: OUT &H3D9, 0
OUT &H3D4, 0: OUT &H3D5, 113
OUT &H3D4, 1: OUT &H3D5, 80
OUT &H3D4, 2: OUT &H3D5, 90
OUT &H3D4, 3: OUT &H3D5, 10
OUT &H3D4, 4: OUT &H3D5, 127
OUT &H3D4, 5: OUT &H3D5, 6
OUT &H3D4, 6: OUT &H3D5, 100
OUT &H3D4, 7: OUT &H3D5, 112
OUT &H3D4, 8: OUT &H3D5, 2
OUT &H3D4, 9: OUT &H3D5, 1
OUT &H3D4, 10: OUT &H3D5, 32
OUT &H3D4, 11: OUT &H3D5, 0
POKE &H465, 9: OUT &H3D8, 9
Return

[edit] EGA VGA Specification

BSAVE images using multiple color planes and color registers were not common but they did exist.

Additional program code was needed to save and display these which was more complicated than the average user of the day could easily write. By the time the EGA came out fewer users bothered with programming in BASIC so the use of these was primarily restricted to beginning programmers and enthusiasts[3] [4] who were unwilling or unable to work in more capable programming languages than BASIC, or who were unwilling or unable to decipher the more advanced graphics formats that had started to emerge with file compression and color palettes.

[edit] MCGA Specification

Fig. 5 Typical IBM 256-Color MCGA BSAVED Graphics Screen
Fig. 5 Typical IBM 256-Color MCGA BSAVED Graphics Screen

BSAVE images using 256 colors and color palettes were not common but they did exist. Additional program code was needed to save and display these which was more complicated than the average user of the day could easily write.

By the time the MCGA came out fewer users bothered with programming in BASIC so the use of these was primarily restricted to beginning programmers and enthusiasts[5] who were unwilling or unable to work in more capable programming languages than BASIC, or who were unwilling or unable to decipher the more advanced graphics formats that had started to emerge with file compression and color palettes.

Two MS-DOS based utilities, PICEm and VGACad, offered saving of BSAVE MCGA images, with the latter also offering a BSAVE-style palette save. VGACad used the file extensions .BLD (BLoaDablePicture) and .PLT.

The problem with saving and loading an MCGA BSaved image was less difficult than saving and loading an EGA Bsaved image. The MCGA was organized in one contiguous byte array of 64000 bytes each with a value of 0-255, and each representing a pixel.

Loading and saving these was virtually the same as the CGA Bsaved format with the difference being that there were too many colors to infer the color palette, and the color palette was not easily saved unless the BASIC programmer understood some assembly language. If the programmer did understand assembly language, it usually wasn't very long before that understanding extended to more capable languages than BASIC and more advanced graphics formats than the BSAVE format.

[edit] Example

The following QuickBASIC program shows by how hard it was to load these in BASIC, especially by comparison to the small amount of programming that the GCA equivalent required.


'This source code is herewith released by me into the Public Domain.
'Bill Buckels, May 23, 2007
'You have a royalty-free right to use, modify, reproduce and distribute this
'source code and the binaries that it produces in any way you find useful

'MCGVU.BAS by Bill Buckels 1991
'an MCGA image viewer
'revised to use VGACad file extensions 2007

'CALL ABSOLUTE Statement Programming Examples
'demonstrate the use of ML routines to implement MCGA mode
'and setting of VGA Palette Registers in QuickBASIC 4.5

'Must be compiled using BC.EXE and ON ERROR option

IF COMMAND$="" THEN
   PRINT "MCGVU(C) Copyright 1991 by Bill Buckels
   PRINT "USAGE IS MCGVU <filename> <no extension>
   END
END IF

ON ERROR GOTO ENDER

DIM PCOL(384)
DIM R(256), G(256), B(256)

'parse the file name

PROOT$=""
TARGET$ = COMMAND$
TARGET = LEN(TARGET$)

FOR I = 1 TO TARGET
           A$=MID$(TARGET$,I,1)
           IF A$ = "." OR A$=" " THEN
                       I = TARGET
           ELSE
               PROOT$ = PROOT$ + A$
           END IF
NEXT I

' The MCGA Image and the Palette were saved outside of here
' Both are in BSAVED format 
PCOLOR$=PROOT$ +".BLD"
PNAME$ =PROOT$ +".PLT"

'arrays to store machine language routines
DIM SETMCGA(5)
DIM SETDAC(10)
DIM CLEARDAC(14)

       ' Poke the machine-language program into the array.

       '---------------------- set MCGA Screen Mode ----------------
       RESTORE MCGABYTES
       READ NUMBYTES  'prepare assembler routine to set to MCGA mode
       DEF SEG=VARSEG(SETMCGA(0)) ' Window the segment.
       FOR J = 0 TO NUMBYTES-1
           READ VALUE
           POKE VARPTR(SETMCGA(0))+J,VALUE
       NEXT J
       CALL ABSOLUTE(VARPTR(SETMCGA(0)))
       DEF SEG   ' Restore the segment.

      '--------------------- set DAC REGISTERS --------------------
       RESTORE CLEARBYTES
       READ NUMBYTES  'prepare assembler routine to clear DAC regs
       DEF SEG=VARSEG(CLEARDAC(0)) ' Window the segment.
       FOR J = 0 TO NUMBYTES-1
           READ VALUE
           POKE VARPTR(CLEARDAC(0))+J,VALUE
       NEXT J
       DEF SEG   ' Restore the segment.

      '-------------------- load the ML routine ----------------
      RESTORE DACBYTES
      READ NUMBYTES  'load DAC registers
      DEF SEG=VARSEG(SETDAC(0)) ' Window the segment.
      FOR J = 0 TO NUMBYTES-1
             READ VALUE
             POKE VARPTR(SETDAC(0))+J,VALUE
      NEXT J

PALREAD:

    '--------------------- Read the palette File ----------------

    DEF SEG   'restore segment
    SEGMENT = VARSEG(PCOL(0))
    OFFSET  = VARPTR(PCOL(0))
    DEF SEG = SEGMENT
    BLOAD PCOLOR$,OFFSET

    '--------------------- load the color registers -------------

    FOR I = 0 TO 255
               R(I)  =PEEK(OFFSET)
               G(I)  =PEEK(OFFSET+1)
               B(I)  =PEEK(OFFSET+2)
               OFFSET=OFFSET+3
    NEXT I
   '-------------------- reset the DAC to 0 ----------------------
       DEF SEG=VARSEG(CLEARDAC(0)) ' Window the segment.
       CALL ABSOLUTE(VARPTR(CLEARDAC(0)))
       DEF SEG   ' Restore the segment.

   '------------------- load the image to the screen -------------

   DEF SEG= &HA000
   BLOAD PNAME$,0

   '----------------- initialize the registers ----------------

   FOR I = 0 TO 255
         IF NOT (R(I)+G(I)+B(I)) THEN        ' if the palette entry is used
            DEF SEG=VARSEG(SETDAC(0))        ' Window the segment
            POKE VARPTR(SETDAC(0))+4,I       ' register number
            POKE VARPTR(SETDAC(0))+6, R(I)   ' red gun value
            POKE VARPTR(SETDAC(0))+8, G(I)   ' green gun value
            POKE VARPTR(SETDAC(0))+10,B(I)   ' blue gun value
            CALL ABSOLUTE(VARPTR(SETDAC(0))) ' do an open ML call
         END IF
   NEXT I

  ' wait for key press

  DEF SEG
  A$=INPUT$(1)

ENDER:
  SCREEN 2
  SCREEN 0
  CLEAR
  END

  '-------------------- Machine Language Routines --------------------

MCGABYTES:
       'Set Video Mode to MCGA mode 13H
       DATA 9
       DATA &H55, &HB4, &H00, &HB0, &H13, &HCD, &H10, &H5D, &HCB

DACBYTES:
      'SET DAC REGISTERS
      'The following assembly language  routine has 4- null characters
      'Which are replaced with Register Number, Red, Green, And Blue
      DATA 19
      DATA &H55, &H33, &HDB, &HB3, &H00
      DATA &HB6, &H00
      DATA &HB5, &H00
      DATA &HB1, &H00
      DATA &HB4, &H10, &HB0, &H10, &HCD, &H10, &H5D, &HCB

CLEARBYTES:
     'Clear the DAC registers
     DATA 27
     DATA &H55, &H33, &HDB, &H8B, &HF3, &HB8, &H10, &H10, &H33, &HC9
     DATA &H33, &HD2, &HCD, &H10, &H8B, &HDE, &H81, &HFB, &HFF, &H00
     DATA &H74, &H03, &H46, &HEB, &HEC, &H5D, &HCB

[edit] IBM PC BSAVE Image Fragments

[edit] PUT

[edit] Example

'This source code is herewith released by me into the Public Domain.
'Bill Buckels, May 26, 2007
'You have a royalty-free right to use, modify, reproduce and distribute this
'source code and the binaries that it produces in any way you find useful

'BPIC.BAS by Bill Buckels 1991
'PUT loader routine
'Written in QuickBASIC Version 4.5

DEFINT A-Z

'check for a color card
CLS
DEF SEG=&HB800
BYTE=PEEK(0)
IF NOT BYTE = 32 THEN
         PRINT"Sorry... CGA compatible adapter required
         END
END IF
'switch back to default segment
DEF SEG

'allocate memory for picture buffer
DIM PIC(8002)
SCREEN 1
COLOR 17,1

'Menu Routine

DO
 IF COMMAND$="" THEN
    CLS
    PRINT"Image Fragment Load
    FILES"*.PUT
    INPUT "Enter pic name :", PICNAME$
  ELSE
    PICNAME$=COMMAND$
  END IF

  IF NOT PICNAME$ = ""  THEN
           CLS
           GOSUB LOADPIC
           KEYPRESS$=INPUT$(1)
  END IF
  IF NOT COMMAND$ = "" THEN
                       PICNAME$=""
  END IF
LOOP UNTIL PICNAME$ =""
END

[edit] GET

[edit] Example


'This source code is herewith released by me into the Public Domain.
'Bill Buckels, May 30, 2007
'You have a royalty-free right to use, modify, reproduce and distribute this
'source code and the binaries that it produces in any way you find useful

' This is a corrected and rewritten example based on the QBASIC manual
' Demonstrating GET, BSAVE, PUT and BLOAD.

' Both the GWBASIC manual and the QBASIC manual presented their
' examples in a confusing manner, with too much or too little information.
' The QBASIC manual further complicated the matter with incorrect calculations.

' Here's a less-confusing example with properly calculated values.

' A BASIC Screen Fragment is stored in a byte array
' Preceded with a header giving the image size.
' Header - 4 bytes
' X - width of image in bits - short integer (2 bytes)
' Y - height of image in rasters - short integer (2 bytes)
' Image data - Variable
' Image data is arranged in rasters. Each raster is byte-aligned.

' In the example below, CGA 4-color screen mode is used.
' Rasters are stored at 2 bits per pixel (4 pixels per byte).
' Since the Cube is 101 pixels wide, 26 bytes are required per raster.
' The last 6 bits (3 pixels) of each scanline are unused (padding)
' Since the Cube is 101 rasters high, image data is 26 bytes x 101 = 2626 bytes.
' The Header requires 4 bytes.
' The array size required to store the image is 2630 bytes.
' Since a short integer is 2 bytes in size and since an integer array is
' required to use the GET and PUT commands, an integer array size of 2630/2 =
' 1315 is required for this example.

' Allocate enough memory in an integer array to hold an image fragment
DIM fragment(1315)
fragmentSize = 2630
fragmentName$ = "MAGCUBE.PUT"
SCREEN 1

' Create an image fragment
GOSUB DRAWCUBE

' Transfer the image fragment into the integer array
GET (140, 25)-(240, 125), fragment

' BSAVE
' Point to the fragment array and BSAVE to disk.
DEF SEG = VARSEG(fragment(1))
BSAVE fragmentName$, VARPTR(fragment(1)), fragmentSize
DEF SEG                 ' Restore default BASIC segment.

LOCATE 1, 1: PRINT fragmentName$ + " Saved. Press a key to load."
KeyPress$ = INPUT$(1)
CLS

' BLOAD
' The image fragment's array size is BSaved
' so the BLoad command knows how to re-load it from disk
DEF SEG = VARSEG(fragment(1))
BLOAD fragmentName$, VARPTR(fragment(1))
DEF SEG               ' Restore default BASIC segment.

' Put the fragment on the screen.
' The fragment dimensions that the GET command stored are now in
' the array, so the PUT command knows the width and height to display
PUT (80, 10), fragment
LOCATE 1, 1: PRINT "Press a key to end..."
KeyPress$ = INPUT$(1)

SCREEN 2
SCREEN 0

END

DRAWCUBE:
' Draw a white box.
LINE (140, 25)-(140 + 100, 125), 3, B
' Draw the outline of a magenta cube inside the box.
DRAW "C2 BM140,50 M+50,-25 M+50,25 M-50,25"
DRAW "M-50,-25 M+0,50 M+50,25 M+50,-25 M+0,-50 BM190,75 M+0,50"
RETURN

[edit] Specifications Apple II

[edit] Graphics

The Apple II had 2 graphics modes; HGR and HGR2. HGR was a "mixed text and graphics" mode and only offered a partial display of a graphics image. HGR2 was most commonly used since it was a "pure" graphics mode. HGR2 ("page 2") started at memory address 4000 hex ($4000).

[edit] Resolution

The resolution of an Apple II Graphics screen was 280 pixels x 192 rasters and allowed up to 6 colors to be displayed simultaneously. However, the hardware was designed to interpret the colors based on "rules" of pixel arrangement in a raster line, and colors would "bleed" (artifact) into each other if the pixels were incompatibly arranged. This was a memory saving technique that allowed a 6 color image to be displayed in only 8K of video memory.

[edit] File Format

The size of an Apple II BSAVE image was 8K (the same size as the video memory) plus 4 byte header, and was interleaved in sections, and was not "linearized". Like all BIN (Binary) files on the Apple II, the file had a binary header of 4 bytes (2 integers) in addition to the 8K binary (image) data following the header.

The first integer gave the load address for the file, and the second gave the length in bytes.

The file extension was usually .BIN or .PIC, if a file extension was used at all.

[edit] Rasters (scanlines)

The rasters in an Apple II BSAVED image are not contiguous, nor are they in a simple sequential order. They match the video memory on the Apple II which was relatively complicated, and are arranged as follows:

Each scanline is 40 bytes long. There are 3 parent interleaves of 64 scanlines each. Starting at the beginning of the image file, scanlines are arranged in 128 byte blocks beginning with scanlines 0, 64, and 128 in the first block (see table below). 8 bytes at the end of each block are unused by the image.

Each parent interleaf has 8 child interleaves of 8 scanlines each, with a spacing of 1024 bytes (1K) between sequential scanlines in each of the 3 parent interleaves.

Starting at the beginning of the file and respective of the Apple II's interleaved display, the first 8 of the 128 byte blocks run as shown below. This also represents the first of 8 scanlines in each of the 24 child interleaves, and is effectively a block group. 8 of these block groups are stored in the file, with the scanlines in the table below being incremented by 1 for each subsequent block group sequence of 1024 bytes, totalling 8192 bytes (8K) of graphics image data.

First of 8 Sequential Scanline Block Groups in Apple II BSAVE Image
1024 Bytes (1K)
Block Leaf 1 - Offset 0
40 Bytes
Leaf 2 - Offset 40
40 Bytes
Leaf 3 - Offset 80
40 Bytes
Padding - Offset 120
8 Bytes
Scanlines 1 0 64 128 Unused
Scanlines 2 8 72 136 Unused
Scanlines 3 16 80 144 Unused
Scanlines 4 24 88 152 Unused
Scanlines 5 32 96 160 Unused
Scanlines 6 40 104 168 Unused
Scanlines 7 48 112 176 Unused
Scanlines 8 56 120 184 Unused

Because of the interleaved display and the slow processor speed of the Apple II, when these loaded, a visible "venetian blind" effect was produced creating a "wipe" (fade effect) of the previous graphic if any.

[edit] Pixels (colors)

The colors in an Apple II BSAVED image are Black, Green, Violet, Orange, Blue, and White. Pixel color is represented by 2 bits. Although the nominal resolution is 280 x 192, the effective resolution considering colors is really only 140 x 192.

In a 40 byte scanline pixels are stored in an bit array of 280 pixel positions referred to as "columns". The highest bit of each byte is used as a "palette" bit and is not considered a column. The lowest bit represents the first column in the byte. So a scan line beginning with $03 would have the first two pixel positions set as white (with the next 5 pixels black).

If the palette bit in a byte is set, the 4 colors available for the pixels in that byte are black, blue, orange, and white.

If the palette bit is not set, the 4 colors available for the pixels in that byte are black, violet, green, and white

Ignoring the 40 palette bits in in a 40 byte scanline, there are 280 columns (bits, pixel positions) but only 140 available pixels. So considering each pixel as being a column pair, with an even and odd column, from left to right starting at column 0, if even is set and odd is not set, the pixel is blue or violet. If even is not set and odd is set, the pixel is orange or green. Any two adjacent columns that are set will be white. This means that white pixels (and black pixels) can be positioned at more places than the other colors, but does not alter the fact that the effective resolution is really only 140 x 192 for an Apple II BSAVED image.


[edit] BLOAD Example

To BLOAD a previously BSAVED image, use the Apple DOS/ProDOS command:

BLOAD <filename>

The following AppleSoft BASIC program loads a BSAVED Apple II Graphics Screen under Apple DOS 3.3. First it clears the screen, lists a directory, waits for user input (the BSAVED screen name) and then loads the screen and waits for a keypress, and repeats until the user ends the program.

1 REM This source code is herewith released 
2 REM by me into the Public Domain.
3 REM Bill Buckels, May 31, 2007
10 TEXT
20 HOME
30 CALL - 1184: CALL 42350
40 PRINT "---------------------------------"
50 PRINT "ABINLOAD(C) APPLEII SCREEN LOADER" 
60 PRINT "COPYLEFT BILL BUCKELS 2006"
70 PRINT "ENTER BIN FILE OR BLANK TO END..."
80 PRINT "---------------------------------"
90 INPUT "?"
100 IF BIN$ = "" THEN GOTO 500
110 HGR2
120 PRINT CHR$(4)"BLOAD "BIN$",A$4000"
130 GET A$
140 GOTO 10
500 TEXT
510 CALL - 1184: CALL 42350
520 END

[edit] BSAVE Example

To BSAVE the HGR screen (starting at memory location $2000, for a length of $2000) use the Apple DOS/ProDOS command:

BSAVE <filename>,A$2000,L$2000

To BSAVE the HGR2 screen (starting at memory location $4000, for a length of $2000) use the Apple DOS/ProDOS command:

BSAVE <filename>,A$4000,L$2000

[edit] Specifications Commodore 64 and 128

Fig. 6 Typical Commodore 128 BSAVED Graphics Screen in HIRES (320 x 200 x 2 color cell) format
Fig. 6 Typical Commodore 128 BSAVED Graphics Screen in HIRES (320 x 200 x 2 color cell) format


Fig. 7 Typical Commodore 128 BSAVED Graphics Screen in Multi-Color (160 x 200 x 4 color cell) format
Fig. 7 Typical Commodore 128 BSAVED Graphics Screen in Multi-Color (160 x 200 x 4 color cell) format


The sample screens shown above were converted from the IBM CGA 320 x 200 x 4 Color BSAVED Image in Fig. 1. Due to the lower resolutions than the IBM-PC in both the Commodore's standard native graphics display modes, Fig. 6 sacrifices colors to black and white where needed during conversion resulting in color loss. The colors remain intact when converting to the lower resolution 4 color mode, but some detail is lost. Graphics layout on the C64 was quite restricted even when compared to the IBM-PC around the same time period but offered up to 16 colors which the IBM-PC did not and offered these in about half the RAM memory by comparison.

[edit] Graphics

Strictly speaking all the uncompressed Graphics File Formats on the Commodore 64 (C64) and 128 (C128) (and there were many) were in a variation of the BSAVE graphics image format because the Commodore stored all binary files (including Graphics) with a two-byte header which provided the file's originating load address. However, because most of these could not be BLoaded directly into the video areas of the C128 they really are a little too advanced to be considered as BSaved graphics images in the same context as on the IBM-PC and Apple II computers of the same vintage.

C64's did not provide a BSAVE nor a BLOAD command with their version of the Commodore BASIC language (Version 2). It wasn't until the release of Commodore BASIC 7 on the C128 that the BSAVE and BLOAD commands and the BSAVE graphics image format came into existence on the C128.

C64's BASIC did provide a LOAD command which was intended to LOAD both binary program images and BASIC programs but this command when used in a C64 BASIC program could not be used to load binary data files like BSAVE images. This was because C64 BASIC would clear the current program from memory and automatically attempt to run (chain to) the newly loaded binary data assuming that it was program code. While this was desired behaviour for programs, using the LOAD command in a BASIC program to load binary data files like BSAVE images would cause the C64 to execute invalid instructions and probably to hang.

This lack of support for loading binary data files from a BASIC program amounted to a very serious shortcoming in C64 BASIC Version 2 (later corrected by the C128's BLOAD command) which left the C64 user with the option of slowly reading binary data files one byte at a time, and then moving the data to memory one byte at a time with data conversion further slowing-down the process. The other option the C64 user had was to extend C64 BASIC using machine code and write their own version of the BLOAD command, which is beyond the skills of most users.

The C64 LOAD command could be typed-in interactively from the command line to BLOAD a BSAVE graphic image and would behave the same way as the BLOAD command on the C128, since the LOAD command did not automatically run the binary image unlike when used non-interactively in a C64 BASIC program, but graphics mode set-up commands were also required. A viewer program would need to be run after loading the BSAVE image, or all the graphic-mode set-up commands typed-in interactively resulting in a complicated procedure beyond the skills of many users.

Technically the standard HIRES graphics mode on the C128 was the same as on the C64 except that the default address in RAM where videoram (HIRES colors) are stored on the C128 directly preceded the default screen address (unlike the C64). This made loading a single BSAVE graphic file in either a monochrome or color format (of the uncompressed type produced by DOODLE) possible on the C128.

[edit] Resolution and Pixel Blocks

The two primary graphics mode resolutions that both the C64 and C128 shared were 320 x 200 (HIRES) and 160 x 200 (Multi-Color Mode). Both modes provided selection of colors from a standard built-in palette of colors.

In HIRES mode, the screen was broken-down in blocks of 8 pixels x 8 scanlines. Pixels of two colors from the 16 color palette could be displayed in each block.

In Multi-Color Mode, the screen was broken down in blocks of 4 pixels x 8 scanlines. Pixels of 4 colors from the 16 color palette could be displayed in each block.

However due to the fact that only 2 colors could be stored in the standard memory area shared by HIRES mode, a separate area of RAM was used to store the other two colors which was not contiguous with the default screen address and which was fixed (even the C128). This meant that a separate BSAVE file containing the remaining 2 colors was required to BSAVE and BLOAD these on the C128 (keeping in mind that the C64 did not support the BSaved format).

This is somewhat similar to the loading of multiple BSaved files on the IBM PC's EGA, VGA, and MCGA Modes discussed above.

[edit] File Format

The size of a HIRES Monochrome BSAVE image without the two byte header was 8000 bytes (the same size as visible screen memory), and was "linearized". The many file extensions possible included .HIR and .HBM, if a file extension was used at all.

The size of a HIRES Color BSAVE image (of the uncompressed type produced by DOODLE) was 9024 bytes (the same size as videoram plus visible screen memory) without the two byte header, and was "linearized". The file extension was .DD, if a file extension was used at all.

Other variations of HIRES and even Multi-Color BSaved formats could be produced from compatible graphics formats by splitting them into uncompressed pieces with BLoadable addresses. If a split graphics image was used it was generally split into an 8000 byte bitmap and 1000 byte videoram (2 colors) for HIRES mode, and with a third file, a 1000 byte colorram (2 colors), for Multi-Color Mode.

Like all BIN (Binary) files on the C64 and C128, the files had a binary header of 2 bytes (1 integer). The header gave the load address for the file, and the length was already known to BASIC 7. The default load addresses on the C128 were $2000, $1C00, and $D800 for bitmap, videoram, and colorram respectively.

Generally speaking, the popular uncompressed Multi-Color (4 Color) formats produced by the Paintbrush programs of the day could not be BLoaded without splitting them (in a separate program) and performing an additional operation of putting a background color which was stored elsewhere in the originating file into the 1000 high-nibbles of colorram.

Since the screen address on the C64 and C128 was relocatable, the screen address could be detected and used by the loader program when BLoading these split files.

[edit] Rasters (scanlines)

The rasters in a C128 BSAVED image are not contiguous, but are in a simple sequential order of pixel blocks (as noted above). They match the video memory on the C128 which in its standard modes was uncomplicated except for its pixel block orientation.

Because of the slow processor speed of the C128 combined with slow storage access, when a HIRES image loaded it was displayed in 25 passes of 40 chunks creating a choppy effect. If the HIRES image had colors it was often blurry and not recognizable since the colors loaded after the image was already being displayed leaving the user with nothing to do but wait until it was finished.

[edit] Pixels (colors)

The standard available colors in a C128 image are BLACK, WHITE, RED, CYAN, PURPLE, GREEN, BLUE, YELLOW, ORANGE, BROWN, LIGHT RED,DARK GREY,MEDIUM GREY,LIGHT GREEN, LIGHT BLUE,and LIGHT GREY. Pixel color is represented by 2 bits in HIRES mode and 4 bits in Multi Color Mode. But as indicated above, not all 16 Colors can be displayed in a pixel block.

[edit] BLOAD Example C64

The following Commodore BASIC 2 program loads a colored BSAVED HIRES Graphics Screen on the C64 from 2 separate BSaved Files (a split image), waits for a keypress and ends.

If BASIC 2 provided a BLOAD command, the load address in the 2 files of $2000 for bitmap and $400 for videoram respectively could have been used to read the files directly into the C64's RAM memory.

Compared to BASIC 7 on the C128 (see C128 examples also below), the C64's BASIC 2 was inefficient and less straight-forward.

1 REM This source code is herewith released 
2 REM by me into the Public Domain.
3 REM Bill Buckels, October 2, 2007
5 POKE 53272,PEEK(53272) OR 8
10 POKE 53265, PEEK(53265) OR 32
20 FOR I = 1024 TO 2047: POKE I,16 : NEXT I
50 OPEN 1,8,2,"ERINLOG.BHI"
51 B$ = CHR$(0)
52 FOR I=1 TO 2:GET #1,A$:NEXT I
54 FOR I=8192 TO 16191
55 GET #1,A$:POKE I,ASC(A$+B$)
56 NEXT I
57 CLOSE 1
60 OPEN 1,8,2,"ERINLOG.VHI"
61 B$ = CHR$(0)
62 FOR I=1 TO 2:GET #1,A$:NEXT I
64 FOR I=1024 TO 2047
65 GET #1,A$:POKE I,ASC(A$+B$)
66 NEXT I
67 CLOSE 1
100 K$=""
110 GET K$
120 IF K$ = "" THEN 110
125 FOR I=8192 TO 16191: POKE I,0: NEXT I
130 POKE 53265, PEEK(53265) AND 223
135 SYS 49152
140 END

[edit] BLOAD Examples C128

The following Commodore BASIC 7 program loads a BSAVED HIRES Monochrome Graphics Screen on the C128 then sets each of the colors for the 1000 pixel blocks to black and white, waits for a keypress and ends. No colors are stored in the image. The load address in the image is at the start of display memory at $2000.

1 REM This source code is herewith released 
2 REM by me into the Public Domain.
3 REM Bill Buckels, August 19, 2007
10 GRAPHIC 1,1
20 BLOAD "ERINLOG.HIR"
24 REM POKE I,16 will reverse video
25 FOR I = 7168 TO 8167:POKE I,1:NEXT I  
30 A$=""
40 GET A$
50 IF A$ = "" THEN 40
60 GRAPHIC 0,1
70 END

The following Commodore BASIC 7 program loads a BSAVED HIRES Colored Graphics Screen in DOODLE uncompressed format on the C128, waits for a keypress and ends. The load address in the image is at the start of C128 videoram at $1C00 directly before screen memory at $2000. No color setting is required since the colors are stored in the image and are loaded directly into the C128's HIRES color memory (videoram).

1 REM This source code is herewith released 
2 REM by me into the Public Domain.
3 REM Bill Buckels, August 19, 2007
10 GRAPHIC 1,1
20 BLOAD "ERINLOG.DD"
30 A$=""
40 GET A$
50 IF A$ = "" THEN 40
60 GRAPHIC 0,1
70 END

The following Commodore BASIC 7 program loads a BSAVED Multi-Colored 4 Color Graphics Screen in 3 separate BSaved Files (a split image) on the C128, waits for a keypress and ends. The load address in the 3 files are $2000 for bitmap, $1C00 for videoram, and $D800 for colorram respectively. No color setting is required since the colors are stored in the videoram and colorram and are loaded directly into the C128's RAM memory.

10 GRAPHIC 3,1             :REM  MULTICOLOR GRAPHIC MODE
20 A=PEEK(1): B=PEEK(216)  :REM  SAVE THESE
30 POKE 216,255            :REM  TELL IRQ TO GIVE US VIC CONTROL
40 POKE 1, A AND 252       :REM  SELECT PROCESSOR NYBBLE BANK
50 BLOAD "ERINLOG.BMC"     :REM  LOAD BIT MAP AT $2000
60 BLOAD "ERINLOG.VMC"     :REM  LOAD COLORS 01 AND 10 AT $1C00
70 BLOAD "ERINLOG.CMC"     :REM  LOAD COLORS 11 AT $D800
80 POKE 1,A                :REM  RESTORE SYSTEM NYBBLE BANK
90 POKE 216,B              :REM  RESTORE SYSTEM VIC CONTROL
100 K$ = ""                
110 GET K$                 :REM  WAIT FOR A KEYPRESS
120 IF K$ = "" THEN 110
130 GRAPHIC 0,1            :REM  TEXT MODE
140 END

[edit] Bitmap Converter Example

The following C language source code is part of a Windows Program written in Microsoft C and the WIN32 SDK. It demonstrates how a monochrome bitmap in a standard format can be reorganized to display as a BSaved Image on the Commodore 128 (C128).

Programs that convert bitmaps with colors to a C128 HIRES or Multi-Color compatible format use the same basic logic as the example below, with additional logic to organize the color map. Under Windows on the IBM PC these converted images can then be inserted into C128 "disk images" used by C128 emulators and loaded by programs similar to the C128 Basic 7 programs shown above.

// This source code is herewith released by me into the Public Domain.
// Bill Buckels, August 25, 2007
int SaveFragmentToC64(char *name,char *printshopbuffer)
{

    // creates a banded C64 image from an 88 x 52 monochrome bitmap
    // ("old printshop" graphic format) which can be bloaded on the C64
    // and centered relative to the default screen address at $2000
    // the image is padded by 4 scanlines on the bottom to adjust
    // for C64 block increments of 8 scanlines.
    // space is padded to both sides of the image to provide a contiguous load
    // and for consistency which results in an image of 320 x 56 in actual size.
    int fh;

    unsigned char header[2];
    unsigned char buffer[320];

    unsigned x, y, y1, idx, offset, inset;


    // create in subdirectory if possible
    _mkdir("c1541");
    _chdir("c1541");

#ifndef S_IWRITE
#define S_IWRITE    0000200     // write permission, owner
#endif

if((fh = _open(name,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IWRITE)) == -1) {
            _chdir("..");
        return FAILURE;
        }

    // create load address to center on C64 screen
    header[0] = 0x4E;  // offset into screen = 72 x 40 = 2880 + 14 + 8192 ($2000)
    header[1] = 0x2B;

     _write(fh,(char *)&header[0],2);

    // 14 + 11 + 15 = 40 byte scanline
    // bitmap picture height = 52 scanlines
    // C64 image height = 56 scanlines

    // 7 bands of 320 bytes instead of the usual 25
    // each band holds 8 scanlines from the original bitmap
    // except the last one which holds only 4
    for (y = 0; y < 7; y++) {
            // pad the band with blackspace
            for (idx = 0; idx < 320; idx++)buffer[idx] = 0;
            y1 = y * 8 * 11;
            inset = 8 * 14;
                for (x = 0; x < 11; x++) {
                     for (idx = 0; idx < 8; idx++) {
                        offset = y1 + (idx * 11) + x;  // down 8, across 11 times

                        if (y == 6 && idx > 3) {
                          // the last band only has 4 rasters
                          // skip reading the last 4
                          inset ++;
                          continue;
                        }
                        buffer[inset] = printshopbuffer[offset];
                        inset ++;

                     }
                }
                // band was created so write it out
                // clip the padding at the top and bottom of the C64 image
                // so it can be optionally loaded anywhere on C64 screen
                // including to top left or bottom right of C64 screen
                if (y == 0) _write(fh,(char *)&buffer[14],(320-14)); // top
                else if (y==6) _write(fh,(char *)&buffer[0],(320-15)); // bottom
                else _write(fh,(char *)&buffer[0],320);
        }

     _close(fh);
     _chdir("..");
     return SUCCESS;

}

[edit] See also

Wikibooks
Wikibooks has a book on the topic of

[edit] External links

[edit] References

  1. ^ a b Microsoft QuickBasic 4.5 Advisor: BSAVE. Microsoft (1990). Retrieved on 2007-07-17.
  2. ^ Microsoft QuickBasic 4.5 Advisor: BLOAD. Microsoft (1990). Retrieved on 2007-07-17.
  3. ^ How to BLOAD/BSAVE Multiple Screen Pages for EGA Screens 7-10
  4. ^ Complete Instructions to BLOAD and BSAVE EGA and VGA Screens
  5. ^ How to Save Color Registers After BSAVE of (PICEM) Graphics