# Generalised Bitmap Module

## Introduction

The GBM package consists of a number of components :-

- A peice of code capable of loading and saving bitmap files in a variety of popular file formats. Programs may be written to use this code, and thus be able to access a variety of file formats without actually knowing what format the pictures are in, or any details about file format itself.
- Some peices of code that perform common operations on bitmap data. Such as reflection, X-Y transposition, rotation, cropping, scaling, halftoning, error-diffusing, palette mapping, and colour space mapping.
- Some sample command line programs which use the above code.

## Distributed packages

The GBM packages are best obtained via the links on my home page :-

- `http://www.interalpha.net/customer/nyangau/`

The basic GBMOS2 package contains all the OS/2 executables. Often GBMDOS32, GBMWIN, GBMAIX, GBMLINUX and other packages are available too.

The GBMSRC source package contains all the source code, which is 32 bit portable C. Makefiles for OS/2 (VisualAge C++), Win32 (Visual C++ 4.2, 5.0, 6.0), and UNIX (using xlc under AIX, and gcc under Linux) are included. See the source documentation

All the GBM source code is written using Andys Source Code Folding Editor, and this is also accessible via my home page. The source will look funny (have strange comments in it, etc.) when veiwed using a regular 'flat' editor.

There is a GBMOS2PM package, which contains programs specific to OS/2 and to OS/2 with Presentation Manager. These include GBMV, GBMV2, GBMVFSA and GBMLOGO. These used to be a part of the standard packages, but I have recently split them out as most people don't have or use OS/2. See the OS/2 extras documentation.

## JPEG support

The Independant JPEG Group have generously allowed others to use their source code to their JPEG handling library. The only condition of use is that the IJG must be credited for their work. Try looking for this library at :-

- `ftp://sun2.urz.uni-heidelberg.de/pub/simtel/graphics/jpegsr6a.zip`.
- `ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/jpegsr6a.zip`.
- `http://sunsite.doc.ic.ac.uk/computing/systems/ibmpc/simtel/msdos/graphics/jpegsr6a.zip`.

Martin Lisowski `<mlisowsk@aixterm1.urz.uni-heidelberg.de>` has generously donated his `gbmjpg.c` to GBM. This file allows GBM to use the IJG 6a library.

GBM may be compiled up either with or without JPEG support. If you use the JPEG enabled variety of GBM in your project, you must credit the IJG.

This code has been tested on OS/2, AIX, Linux and NT.

## Formats supported

GBM supports a variety of file formats, such as GIF, TIFF, PCX etc..

Normally, applications using GBM deduce the file format from the file extension. eg: `filename.gif` is a Compu$erve GIF file.

When specifying file names to programs written using GBM, it is usually possible to append a comma seperated list of format specific options. eg: you can say `webpiccy.gif,ilace`. In this case, the `ilace` is a cue to the code in GBM which writes GIF files, to tell it to write an interlaced GIF.

    Short name : Long name : File extensions
      Comments

    Bitmap : OS/2 1.1, 1.2, 2.0 / Windows 3.0 bitmap : .BMP .VGA .BGA .RLE .DIB .RL4 .RL8
      Reads any of the above if uncompressed or run-length compressed.
      Will not read CCITT G3 MH Fax compressed files.
      Will not read 24 bit RLE files.
      If input is an OS/2 bitmaparray file then which bitmap can be specified.
        Input options: index=# (default: 0)
      Can be made to write OS/2 1.1 or Windows 3.0 / OS/2 2.0 bitmaps
        Output options: 1.1,win,2.0 (default: 2.0, note win=2.0)
      The handling of 1bpp bitmaps is a little complicated.
      When reading 1bpp bitmaps, the palette is ignored.
      1's are considered foreground, and they are considered black.
      0's are considered background, and they are considered white.
      This agrees with WorkPlace Shell WPFolder background mode, and most PM
      programs, but notably disagrees with Windows PBrush.
      When writing 1bpp bitmaps, the actual 2 colours in the palette are
      ignored, and a fixed palette is written. This is so that the resulting
      bitmap will display 1's in black on 0's in white when displayed by
      WPFolder etc..
      Foreground and background colours in palette can be inverted on input.
        Input options: inv
      Foreground and background colours in palette can be inverted on output.
        Output options: inv
      Foreground and background colours in bits can be inverted on input.
        Input options: invb
      Foreground and background colours in bits can be inverted on output.
        Output options: invb
      The best option for writing 1bpp bitmaps is to write the darkest
      colour as the foreground. The resulting bitmap will have darkest
      colour as 1 bits, and lightest colour as 0 bits. When reloaded
      WPFolders and GBM will give a black 1's on white 0's picture.
        Output option: darkfg
      Also, there is an option for writing 1bpp bitmaps with the lightest
      colour as foreground. As WPFolder and GBM assume the foreground is
      black and the background is white on reloading, this will typically
      cause the image to be inverted.
        Output option: lightfg

    GIF : CompuServe Graphics Interchange Format : .GIF
      Reads 1, bit data files.
      Reads 2, 3 and 4 bit data files and presents them as 4 bit.
      Reads 5, 6, 7 and 8 bit data files and presents them as 8 bit.
      Writes 1, 4 and 8 bit data files.
      Reads "GIF87a" and "GIF89a" style files.
      Writes "GIF87a" style files.
      Will write "GIF89a" file, if the transcol= option is used.
      Should correctly handle deferred clear-code in LZW data stream.
      Will not generate output with deferred clear-code.
      ie: should not break older GIF readers.
      Can specify index of image within file on read.
        Input option: index=# (default 0)
      Can specify to return decoded data so far rather than error if corrupt.
        Input option: errok
      Can specify screen size to write in output screen descriptor.
        Output options: xscreen=#,yscreen=# (defaults: image size).
      Can specify background colour index to write in file BMHD header.
        Output option: background=# (default: 0)
      Can specify position information in output image descriptor.
        Output options: xpos=#,ypos=# (defaults: 0,0).
      Can specify transparent colour index (useful for HTML embedding).
        Output option: transcol=# (default is none).
      Can specify transparent colour index same as first pixel.
        Output option: transcol=edge
      Can write interlaced GIFs (good for HTML <IMG=SRC="x.gif">)
        Output option: ilace
      Extensively test on GIF files from a wide variety of sources.
      Compatibility tested with xloadimage and xv.

    PCX : ZSoft PC Paintbrush Image format : .PCX .PCC
      Reads and writes 1,4,8 and 24 bit colour files.
      Subset of plane/bits-per-plane combinations supported.
      Files are read and written using a run-length coding scheme.
      Tested using Zsoft originated .PCX files.
      Compressed runs of pixels are not supposed to straddle scan lines.
      GBM never does this, but some other applications violate this rule.
      By default, if GBM finds that a run of pixels is longer than the scan
      line, it will use the leftover pixels on the next scan line.
      Some images will not load properly, as they require the loading
      program to discard those pixels in the run that extend beyond the end
      of the scan line. This behaviour can be enabled in GBM.
        Input option: trunc

    TIFF : Microsoft/Aldus Tagged Image File Format support : .TIF .TIFF
      Reads and writes 1,4,8 and 24 bit colour files.
      Can almost read all TIFF 6.0 Baseline compliant files.
        Can read uncompressed and Packbits images.
        CCITT Modified huffman compression is the missing peice.
      Can read some files with extensions to Baseline.
        Can read 1bpp greyscale and palettised files.
        Can read Orientation==4 files.
        Can read PlanarConfiguration==2 files for RGB image data.
        Can read LZW compressed files too.
        Can also read CMYK 4 colour seperation files.
        No JPEG or Y-Cb-Cr support.
      Writes files that comply with TIFF 6.0 Baseline.
        Usually writes uncompressed files only.
        Data is written out as a single large strip.
      Can specify image within TIFF file with many images
        Input option: index=# (default: 0)
      Can write 1bpp as non-Baseline file preserving fg/bg cols
        Output option: pal1bpp
      Can ask for LZW compression.
        Output option: lzw
      Can specify informational tags to append on output.
        Output options: artist=,software=,make=,model=,host=,documentname=,pagename=,imagedescription=

    Targa : Truevision Targa/Vista bitmap : .TGA .VST .AFI
      Reads any uncompressed/run-length-compressed files.
      Reads 8 bit and 24 bit files.
      Can read 8 bit greyscale and 8 bit colour mapped files.
      Reads both yup and ydown files.
      Writes out as uncompressed 8 bit or 16,24,32 bit.
        Output options: 16,24,32 (default 24)
      8 bit data is always written out as a colour mapped file.
      Can be made to write yup and ydown files.
        Output options: ydown,yup (default: yup)

    ILBM : Amiga IFF / ILBM Interleaved bitmap format : .IFF .LBM
      Reads 1 bit palettised files.
      Reads 2,3 and 4 bit palettised files, returning them as 4 bit.
      Reads 5,6,7 and 8 bit palettised files, returning them as 8 bit.
      Reads 24 bit images and returns them as 24 bit.
      Reads HAM6, HAM8, SHAM and Extra-Halfbrite images.
      HAM6, HAM8 and SHAM returned as 24 bit data.
      Writes 1,4 and 8 bit palettised colour files.
      Writes 24 bit files normally, or by converting to HAM6 first.
      This loses quality but results are still better than 8 bit.
      Understands the RLE compression scheme used.
      Uses BMHD, CMAP, CAMG and BODY sections of file only.
      Only writes BMHD, CMAP, CAMG and BODY sections in output files.
      Can specify position information in file BHMD header.
        Output options: xpos=#,ypos=# (defaults: 0,0).
      Can specify transparent colour to write in file BMHD header.
        Output option: transcol=# (default: 0)
      Can specify aspect ratio to write in file BMHD header.
        Output options: xaspect=#,yaspect=# (defaults: 1,1).
      Can specify screen size to write in output BMHD header.
        Output options: xscreen=#,yscreen=# (defaults: image size).
      Can specify to write 24 bpp data in HAM6 format.
        Output option: ham6
      Note that when DeluxePaint etc. try to load an 8 bit IFF file, they
      switch to a 32 colour (5 bit mode) and only read the 5 least
      significant planes of the file - this generally looks yukky!
      Tested using DeluxePaint sample bitmaps.

    YUV12C : YUV12C M-Motion Frame Buffer : .VID
      Reads files and presents data as 24 bit data.
      Writes 24 bit data files by converting them into 12 bit YUV.
      VID files MUST be a multiple of 4 pixels wide.
      When writing a non-multiple of 4, the last 1, 2 or 3 pixels are lost.
      Can specify image origin information in YUV12C header.
        Output options: xpos=#,ypos=# (defaults: 0,0).
      Tested using M-Control Program 2.0, Browser sample application.

    Greymap : Portable Greyscale-map (binary P5 type) : .PGM
      Credit for file format to Jef Poskancer.
      No palette present in file format.
      Reads 8 bit grey scale files.
      Writes red, green, blue plane or greyscale equivelent of 8 bit image.
        Output options: r,g,b,k (default: k)

    Pixmap : Portable Pixel-map (binary P6 type) : .PPM
      Credit for file format to Jef Poskancer.
      Reads and writes 24 bit unpalettised RGB data files.

    KIPS : IBM KIPS : .KPS
      Reads 8 bit palettised files.
      Will look for palette in .PAL file unless .KPL file specified.
        Input options: pal,kpl (default: pal)
      Writes 8 bit palettised files.
      Will write palette in .PAL file unless .KPL file specified.
        Output options: pal,kpl (default: pal)

    IAX : IBM Image Access eXecutive : .IAX
      Reads array as 8 bit greyscale.
      File format does not hold image dimensions.
      Hence code assumes width is 512 pixels unless overridden.
        Input options: width=# (default: 512)
      File format does not include palette.
      Writes red, green, blue plane or greyscale equivelent of 8 bit image.
        Output options: r,g,b,k (default: k)

    XBitmap : X Windows bitmap : .XBM
      Reads 1bpp X bitmaps, presenting 1's as black, 0's as white.
      Writes 1bpp X bitmaps, darkest colours as 1's, brightest colour as 0's.
      Tested upon some sample .XBM files.

    Sprite : Archimedes Sprite format from RiscOS : .SPR .SPRITE
      Technically sprite files have no extension.
      But GBM recognises .SPR and .SPRITE for convenience.
      Reads 1,4 and 8 bit sprites.
      'First bit' value in header must be a multiple of 8 (v.likely).
      Will only read image plane, will ignore any mask plane.
      Will handle case when no palette present in file.
      Will default to the default Wimp palette in this case.
      If input contains more than one sprite then which can be specified.
        Input options: index=# (default: 0)
      Will output 1,4 and 8 bit files.
      Will write a palette in the file.
      Will only write an image plane, ie: no mask plane.
      Will write a 16 entry palette for 8 bit data (not 64 entry).
      Will map to wierd archmedes palette when writing 8 bit data.
      Tested reading 4bpp sprites with no palette.
      Tested reading 8bpp sprites with no palette and with 64 entry palette.
      Sprites generated by GBM have been loaded on RiscOS.
      Remember: Use SetType to change type of file from PC-file to Sprite,
      by SetType option of filer menu or "*SetType <filename> Sprite".

    PSEG : IBM Printer Page Segment : .PSE .PSEG .PSEG38PP .PSEG3820
      This is a file format used by IBM document/printing systems.
      It is used to represent a bi-level image to be used in a document.
      Reads data and presents a 1bpp bitmap.
      Image is presented 1's as black on 0's as white background.
      PSEG files should be downloaded from a VM host in binary mode.
      Some PSEG files have a corrupt record structure.
      This doesn't cause a problem on VM but can confuse a non-VM reader.
      GBM can be made to attempt to handle these files.
        Input option: fixrec
      Will output 1bpp file.
      Will output file with scale factor of 1000
      Can specify new scale for both x and y
        Output options: scalex=#, scaley=#
      Can double the scale factors (option exists for backwards compatibility).
        Output option: double
      WIll output file with pel values of 2400 (dots per 10 inches, ie: 240 dpi).
      Can specify new pel values for both x and y
        Output options: pelx=#, pely=#
      Palette in 1bpp data is lost when written to file.
      The resulting non-VM file has no record structure.
      So when it is uploaded it must be fixed using FIXL3820 EXEC or similar.
      Image width is rounded up to next multiple of 8 when written.

    GemRas : GEM Raster : .IMG
      There is a basic level of support, and assorted XIMG extensions.
      One extension is the inclusion of palette info.
      Another allows 24 bpp data to be placed into an .IMG file.
      Reads 1 bpp files (which are B/W) and returns 1 bpp data.
      Reads 2,3 and 4 bpp files (col, grey, XIMG with pal) and returns 4 bpp.
      Reads 5,6,7 and 8 bpp files (grey, XIMG with pal) and returns 8 bpp.
      Reads 24 bpp (which are by definition XIMG) files and returns 24 bpp.
      Writes 1 bpp data as B/W 1 bpp file.
      Writes 4 bpp data mapped to 'standard' 16 colour palette.
      Or writes 4 bpp data greyscale 4 bpp file.
        Output option: grey
      Or writes 4 bpp data to XIMG file with palette.
        Output option: pal
      There is no 'standard' palette for 256 colour files.
      Writes 8 bpp data as greyscale 8 bpp file.
      Or writes 8 bpp to XIMG file with palette.
        Output option: pal
      Writes 24 bpp data as an XIMG file (normal file can't do 24 bpp).
      The pixel dimensions in microns can be specified.
        Output options: pixw=#,pixh=# (defaults: 85,85)

    Portrait : Portrait : .CVP
      In Germany, photographers sometimes supply a floppy with a .CVP on it.
      File holds a single 512x512 24bpp RGB image.
      File is uncompressed, and will therefore always be 3/4Mb.
      You can only write 512x512 images using this format.
      Pixels in the file are not square, the width is approx. 3/4 the height.
      This aspect ratio problem is not adjusted for when reading or writing.

    JPEG : JPEG File Interchange Format : .JPG .JPEG .JPE
      Can read 8 bpp (greyscale) and 24 bpp files.
      Can write 24 bpp data to a file.
      Can write with varying degrees of quality.
        Output option: quality=# (range 0 to 100, default 75)
      Can write progressive JPEGs.
        Output option: prog

## Command line programs

All the command line programs are written in portable C, and therefore can be compiled up on a wide variety of platforms.

### GBMHDR - Display header information from bitmap files

      usage: gbmhdr [-g] [-s] [--] {fn.ext{,opt}}
      flags: -g            don't guess bitmap format, try each type
             -s            be silent about errors
             fn.ext{,opt}  input filenames (with any format specific options)
                           Bitmap when ext in [BMP VGA BGA RLE DIB RL4 RL8]
                           GIF when ext in [GIF]
                           PCX when ext in [PCX]
                           TIFF when ext in [TIF]
                           Targa when ext in [TGA VST AFI]
                           ILBM when ext in [IFF LBM]
                           YUV12C when ext in [VID]
                           Greymap when ext in [PGM]
                           Pixmap when ext in [PPM]
                           KIPS when ext in [KPS]
                           IAX when ext in [IAX]
                           XBitmap when ext in [XBM]
                           Sprite when ext in [SPR]
                           GemRas when ext in [IMG]
                           Portrait when ext in [CVP]
                           JPEG when ext in [JPG JPEG JPE]
             opt           bitmap format specific option to pass to bitmap reader

Note that the GBM module only ever surfaces the size and bits per pixel of images (regardless of the other information present in the header). All GBM programs have access to the bitmap file formats documented above, although this list is omitted in subsequent documentation.

GBMHDR displays output in the following style :-

       384x768   8bpp    51Kb  17% GIF        aab.gif
       227x254   8bpp    58Kb 102% Bitmap     andy.bmp
       256x256  24bpp    84Kb  43% TIFF       bardot.tif

Listed is the size, bits per pixel, Kb size of the file, a percentage value, the file format, and the file name. The percentage is calculated as (filesize*100/datasize) and effectively gives the compression ratio. For example `aab.gif` is well compressed (to 17% of the theoretical size). `andy.bmp` gives a >100% value because of the file header.

### GBMREF - Reflect in horizontal and/or vertical directions

      usage: gbmref [-h] [-v] [-t] [--] fn1.ext{,opt} [fn2.ext{,opt}]
      flags: -h             reflect horizontally
             -v             reflect vertically
             -t             transpose x for y
             fn1.ext{,opt}  input filename (with any format specific options)
             fn2.ext{,opt}  optional output filename (or will use fn1 if not present)
                            bitmap formats and options as before

Certain non-obvious combinations of `-h`, `-v` and `-t` can be very handy :-

None of them
  can be used for just file format translation.
`-h -v`
  reflect both, equivelent to 180 degree turn.
`-h -t`
  equivelent to 90 degree turn clockwise.
`-v -t`
  equivelent to 90 degree turn anti-clockwise.

### GBMSUB - Extract a subrectangle of a bitmap

      usage: gbmsub [-x x] [-y y] [-w w] [-h h] [--] fn1.ext{,opt} [fn2.ext{,opt}]
      flags: -x x           left edge of rectangle (default 0)
             -y y           bottom edge of rectangle (default 0)
             -w w           width of rectangle (default width of image - x)
             -h h           height of rectangle (default height of image - y)
             fn1.ext{,opt}  input filename (with any format specific options)
             fn2.ext{,opt}  optional output filename (or will use fn1 if not present)
                            bitmap formats and options as before

If none of the `-x`, `-y`, `-w` and `-h` options are supplied the defaults cover the whole of the input file. Hence this program will just read one file and write the data as another. Great for format conversion.

### GBMSIZE - Change the size of a bitmap

      usage: gbmsize [-w w] [-h h] [-a] [--] fn1.ext{,opt} [fn2.ext{,opt}]
      flags: -w w           new width of bitmap (default width of bitmap)
             -h h           new height of bitmap (default height of bitmap)
             -a             preserve aspect ratio when only one of -w or -h given
             fn1.ext{,opt}  input filename (with any format specific options)
             fn2.ext{,opt}  optional output filename (or will use fn1 if not present)
                            bitmap formats and options as before

If none of the `-w` or `-h` options are supplied, the defaults will be the input image size. Hence this program will just read one file and write the data as another. Great for format conversion.

The scaling algorithm simply uses pixel skipping and/or replication.

### GBMBPP - Do various bits per pixel conversions

      usage: gbmbpp [-m map] [-e] [-hN] [-p fnp.ext{,opt}]
                    [--] fn1.ext{,opt} [fn2.ext{,opt}]
      flags: -m map            mapping to perform (default 7x8x4)
                               bw           black and white
                               vga          16 colour VGA
                               8            8 colour (in 4 bit file)
                               4g           4 bit greyscale
                               7x8x4        7 levels red, 8 green, 4 blue 8514/A
                               6x6x6        6 levels red, 6 green, 6 blue
                               8g           8 bit greyscale
                               tripel       64 reds, 64 greens, 64 blues tripel
                               pal1bpp      map to 1bpp, palette specified via -p
                               pal4bpp      map to 4bpp, palette specified via -p
                               pal8bpp      map to 8bpp, palette specified via -p
                               freqR:G:B:N  keep R red, G green, b blue bits, and map
                                            to N most used colours in 8 bit palette
                               mcutN        median cut to N colours
                               R:G:B        keep R red, G green, B blue bits
             -e                enable error-diffusion (default is to truncate)
                               -e only with -m bw, vga, 4g, 7x8x4, 6x6x6, no -h
             -h                enable halftoning (default is to truncate)
                               -h only with -m 7x8x4, 6x6x6, 8, vga or R:G:B, no -e
                               N is a halftoning algorithm number (default 0)
             -p fnp.ext{,opt}  palette is taken from this bitmap
             fn1.ext{,opt}     input filename (with any format specific options)
             fn2.ext{,opt}     optional output filename (or use fn1 if not present)
                               bitmap formats and options as before

This program reads the input bitmap. If it is not 24 bit, then it is expanded to 24 bit per pixel. The data is then processed using the supplied mapping giving a 24,8,4 or 1 bit per pixel image, which is then written to the output bitmap file.

The `bw` mapping produces a 1 bpp output file, `vga` and `4g` gives 4 bit output files, `7x8x4`, `6x6x6`, `8g`, `freq` and `tripel` give 8 bit output files. `R:G:B` (where R,G and B are numbers in the range 0 to 8), gives a 24 bit output file where only the top R bits of red are non-zero, the top G of green and B of blue.

The normal way to map is simply to map each colour in the source bitmap to the closest one in the destination bitmap. However if `-e` is supplied, error diffusion is used to get a smoother result. Also, if `-h` is supplied halftoning may be used instead. `-e` and `-h` are not valid together, and are only valid with certain mappings.

### GBMGAMMA - Convert between various colour spaces

      usage: gbmgamma [-m map] [-g gamma] [-s shelf] [--] fn1.ext{,opt} [fn2.ext{,opt}]
      flags: -m map         mapping in the form ?_to_? (default: i_to_l), where ? is
                            i  physical intensitys (eg: raytracer output)
                            p  gamma corrected for a specific monitor
                            l  L* cyclometric linear perceived intensitys (as in PM)
             -g gamma       set monitor gamma (default 2.1)
             -s shelf       set monitor shelf (default 0.0)
                            gamma and shelf only used for mapping to or from p
                            for 8514 monitor gamma=2.3,shelf=0.136
                            for 8515 monitor gamma=2.1,shelf=0.0
             fn1.ext{,opt}  input filename (with any format specific options)
             fn2.ext{,opt}  optional output filename (or will use fn1 if not present)
                            bitmap formats and options as before

This program reads a bitmap and assumes the pixel values in it are in the input colour space.

If the bitmap has a palette it maps each palette entry according to the supplied mapping, otherwise it maps each individual 24 bit pixel.

For example, if you get a 24 bit per pixel image from a Windows video capture program, the odds are in may be in a gamma corrected colour space with a gamma of 2.2. You can convert this to the L* cyclometric colour space used by PM by typing :-

      gbmgamma -m p_to_l -g 2.2 captured.bmp nicepm.bmp

The shelf option is primarily for when converting to a gamma corrected colour space for a specific monitor (when you aren't going to use PM to display the bitmap, and the display program doesn't do any correction). Some monitors don't actually start to light up pixels until the pixel values are a certain value. Normally `-s shelf` will not be used.

### GBMCPAL - Map to Common Palette

      usage: gbmcpal [-m map] [-v] n1 n2 n3 ifspec{,opt} ofspec{,opt}
      flags: -m map         mapping to perform (default freq6:6:6:256)
                            freqR:G:B:N       map all bitmaps to same palette, worked
                                              out using frequency of use histogram
                            mcutN             map all bitmaps to same palette, worked
                                              out using median cut algorithm
                            rofreqR:G:B:N:N2  map each bitmap to frequency palette,
                                              reordered to minimise differences
                                              between successive bitmaps
                            romcutN:N2        map each bitmap to median cut palette,
                                              reordered to minimise differences
                                              between successive bitmaps
                                              R,G,B are bits of red, green and blue
                                              to keep, N is number of unique colours,
                                              N2 is extra palette entries
             -v             verbose mode
             n1 n2 n3       for ( f=n1; f<n2; f+=n3 )
             ifspec           printf(ifspec, f);
             ofspec           printf(ofspec, f);
                            filespecs are of the form fn.ext
                            ext's are used to deduce desired bitmap file formats
                            bitmap formats and options as before

Given a set of bitmaps, it is possible to examine them all and compute a common palette for holding them, and then generate new bitmaps mapped to that palette.

The mappings available are frequency based and median-cut based.

Alternatively, it is possible to generate the most suitable palette for each frame, and then reorder the palettes of each bitmap so as to be as close as possible to its predecessor.

By reordering palettes (using `rofreq`/`romcut`) it is possible to remove almost all flicker on playback. From frame to frame, almost all palette entries in a given frame, have close entries in the previous frame.

However for a few, this is not true, and flicker may be seen. The `N2` parameter is designed to alleviate this. The process will handle the `N2` worst palette changes using `N2` extra palette entries. Thus the `N2` worst causes of flicker can be eliminated. A typical use might be :-

      gbmcpal -m romcut240:16 0 100 1 in%02d.bmp out%02d.bmp

This means map each frame to a palette with 240 unique colours in. Any given frame only uses 240 colours at most. But the palette is actually 240+16 colours in length, and the additional 16 are used to eliminate flicker caused by the 16 worst matches.

## Colour spaces

If a light is physically twice as bright, the eye does not necessarily see it as twice as bright. Also, if a pixel is written onto a monitor screen with twice the value, the physical intensity of the pixel is not necessarily double.

How exactly should numbers inside a bitmap file relate to physical or perceived intensitys when displayed on the screen?

In OS/2 PM perceived intensitys are proportional to the values in the bitmap file. Pixels in such a bitmap are in the 'L* cyclometric' colour space.

Ray Tracers often write pixel values in the bitmap proportional to the physical intensity computed for that ray. Such data is in the 'intensity' colour space.

Finally, if a bitmap holds values computed in such a way as to compensate for the gamma of the monitor (ie: intensitys transformed to cancel out the gamma of the monitor), then the data is in a 'gamma corrected' colour space.

So, if you have some Ray Tracer output, and you wish to display on an 8514 monitor WITHOUT using OS/2 PM, then to get a decent colour rendition, you must map the bitmap from the 'intensity' to a 'gamma corrected' colour space. To do this you must know the gamma of the 8514 monitor (which is about 2.1).

Also, if you have some Ray Tracer output, and you wish to display on OS/2 PM, then to get a decent rendition you must map the bitmap from the 'intensity' to the 'L* cyclometric' colour space.

GBMGAMMA is a colour mapping program capable of performing mappings between any 2 of the 3 colour spaces above.

Mapping of this sort should really be done on 24 bit data, before error-diffusion or halftoning takes place.

## Making bitmap animations

GBM was originally written as the bitmap handling portion of my homebrew Ray Tracer, RT. RT was originally written to allow me to trace snazzy animations. For example, here is what I did to make a spinning globe animation.

First I traced a largish number of individual bitmap frames using RT. I wrote these out under the names `globeNNN.tif` where `NNN` is `000`, `010`, `020`, ... `350` (ie: the angle of rotation in degrees). I used the `,lzw` option to get the files written LZW encoded to reduce the disk space requirements.

Then to map the data to a common palette, I used GBMCPAL :-

      gbmcpal -m freq6:6:6:256 0 360 10 globe%03d.tif globe%03d.bmp

Obviously there are file formats specifically for holding animations, and algorithms for having animations where palette entries vary from frame to frame, but the simple example above is ok for many purposes.

## Examples of use

      gbmhdr *.bmp *.tif
        Displays the headers of all the bitmaps and TIFF files

      gbmref file.bmp file.tga
        Perform no reflection (no -h, -v or -t).
        Hence simply converts file from Bitmap to Targa format!

      gbmref -h larrow.tga rarrow.tga
        Reflects larrow.tga to make rarrow.tga

      gbmref -h -t profit.gif loss.gif
        The combination of a horizontal flip with a transpose gives a 90
        degree rotation clockwise. Thus a graph going up from bottom left
        to top right, ends up going from top left to bottom right!

      gbmref -v uarrow.pcx "darrow.lbm,xaspect=5,yaspect=6,xscreen=320,yscreen=200"
        Reflects uarrow.pcx to make darrow.lbm
        Output options defined for ILBM files used to write to aspect ratio
        and screen size fields in output .lbm file.
        Note: some command processors (such as OS/2 CMD.EXE) will split command
        line arguments at spaces and commas, so we quote second argument.

      gbmsub -x 100 -y 50 page.bmp
        Trims 100 pixels off the left, and 50 off of the bottom
        Note: no second filename given, so output overwrites page.bmp

      gbmsize -w 1024 -h 768 strangesize.bmp screensized.bmp
        Takes any bitmap and scales it to a typical SVGA screen size.

      gbmbpp -m 7x8x4 24bit.tga 8bit.bpp
        Maps a 24 RGB image to the 8514/A PM palette
        Note: Source image format (Targa) not same as output format (Bitmap)

      gbmbpp -m 7x8x4 -h 24bit.bmp nice8bit.bmp
        As above but with halftoning

      gbmbpp -m 7x8x4 -e 24bit.bmp nice8bit.bmp
        As above, but with error diffusion

      gbmbpp -m vga -e 24bit.bmp nice4bit.bmp
        As above, but suitable for VGA display

      gbmbpp -m 5:5:5 -e 8r8g8b.tga "5r5g5b.tga,16"
        Error diffuse from 24 bit RGB to 15 bit RGB
        (bottom 3 bits of each of R,G and B become zero)
        Output option ",16" ensures data written in Targa-16 form
        This reduces wasted disk space.

      gbmbpp -m freq8:8:8:240 24bit.bmp 8bit.bmp
        Finds 240 most frequently used colours.
        For other colours finds closest match in most common 240 colours.
        Maps colours in 24bit.bmp to give 8 bit output file.
        If excessively large number of colours in original, may truncate bits.

      gbmgamma -m i_to_l raytrace.bmp pmsuited.bmp
        raytrace.bmp has pixels values proportional to physical intensity.
        pmsuited.bmp is made with pixels proportional to perceived intensity.

      gbmcpal -m freq6:6:6:256 0 360 10 globe%03d.bmp cpal%03d.bmp
        Read globe000.bmp, globe010.bmp, ... globe350.bmp.
        Compute a common shared palette.
        Map each globeXXX.bmp file to a cpalXXX.bmp file.

## Related code

GBM was originally written as the file handling part of my homebrew ray tracer, RT. This may be found via my home page too.

My follow-on Modular Renderer package, currently in development, uses GBM. It does wire-frame, polygon rendering and raytracing. Not currently publically available.

Martin Lisowski informs me he is working on something he calls GBMV3, which is like the OS/2 PM GBMV2 viewer, only with extra features. It is currently "far from being ready, and still has bugs".

From time to time I notice people (other than myself) using GBM either in its precompiled DLL form, or by recompiling bits of the source. Sometimes people email me to let me know.

Of course, simply using the code unmodified makes it easier for you to pick up improvements in the code, as and when they happen.

IBM WebExplorer uses the Bitmap, GIF and XBM handling parts of GBM to some degree - in `webexwin.dll`, around byte offset 86924 (in my copy) are a whole load of GBM error strings.

IBM VisualAge C++ 3.0 for OS/2 uses large wedges of GBM source code. I think they're using it in their supplied `class IGBitmap`. This is apparent from the object filenames listed in `\ibmcpp\iocdll\cppoou3.rsp` and the exported function names in `\ibmcpp\iocdll\cppoou3.def`.

The IBM Person to Person personal conferencing system for OS/2 used the PCX and TIFF parts of GBM, and I think the AIX variant used whole loads more.

BITMAP32, a bitmap viewer for OS/2 PM, uses GBM.DLL unmodified. Because the IBM Developer Connection shipped BITMAP32, they ship GBM too.

BluePaint, an OS/2 PM painting program, being developed for Shareware (I think) uses GBM.DLL unmodified.

## Legal stuff

### Public domain declaration

I wrote all this code in my own time on my own equiptment.

I used public non-confidential information to do so.

I hereby place all this code into the public domain.

Feel free to do whatever you like with it.

No copyright / no royalties / no guarantees / no problem.

Caveat Emptor!

Anyone offering ideas/code must be happy with the above.

The above does not apply to the JPEG support.

### JPEG support

This section is applicable if you are using GBM with JPEG support.

The Independent JPEG Group JPEGLIB version 6a may be used provided they are credited, (which I do so here).

This software is based in part on the work of the Independent JPEG Group.

Martin Lisowski has donated `gbmjpg.c` to GBM and it is just as public domain as the rest of GBM.

### Compu$erve GIF Tax

Both Unisys and IBM (and others) have various patents pertaining to the LZW algorithm used in GIF and LZW compressed TIFF files.

For many years Unisys have only licensed their LZW technology in hardware implementations (typically Modems). Now Unisys (through Compu$erve) are looking to license the use of LZW in software applications, such as GIF and TIFF. This is the infamous 'Compu$erve GIF Tax'.

Unisys have stated (in news postings) that non-commercial software need not be licensed.

Assuming this to be true, GBM will continue to support GIF and LZW compressed TIFF.

It is anticipated that this move will mean the death of LZW in image files, and that the Net will develop a replacement based on LZSS, LZ77, LZHUF, Yabba or other (hopefully) non-patented technology. The emerging PNG format could be exactly that.

If and when this occurs, there is a good chance GBM will support it.

## Change Log

    11/5/92		Initial general release.

    29/11/93	Supplied to IBM OS/2 Developer Connection.

    1/8/94		Submitted to Internet hobbes.nmsu.edu.

    10/1/95		Added gbm_version(), better error checking, const's.
    		Added clarification on LZW 'software patent'.
    		Submitted to hobbes.nmsu.edu.

    16/1/95		Added support for Portrait files (.CVP files).

    21/3/95		Fixed palettes in XIMG GemRas files (thanks Eero).
    		Fixed GIF writing transcol=edge, & reading local colour tables.
    		Added GBMLOGO.EXE to ease use of MAKELOGO.EXE on DevCon CD 6.

    16/5/95		Distribution now uses InfoZIP ZIP.EXE, not PKZIP.EXE 2.04g.
    		Added Product Information dialog box to GBMV2.EXE.
    		Fixed GBMLOGO.EXE error message trap for non 640x400 bitmaps.

    25/3/96		Improved Bitmap reader to tolerate bad #colours in header.
    		Fixed reading XBitmaps with digits in their identifiers.
    		Added support for ilace flag on GIF output.

    1/4/96		Fixed reading XBitmaps with other chars in their identifiers.
    		Fixed interlaced GIF support.
    		Added Win32 makefile and compilability.
    		Added ability to cause GBM.DLL to use user defined I/O funcs.
    		Added accessibility of I/O funcs used by GBM.

    16/4/96		Applied fixes found by Wonkoo in 1/4/96 release.
    		Increase warning levels for OS/2 compile and cleaned up source.
    		Added /Os- to work around C-Set++ bug.

    29/4/96		Applied fix to GIF/TIFF readers found by David Wendt.

    19/6/96		Applied fixes found by Ralf and Andreas.
    		Fixed RLE4 Bitmap decoder (thanks for Marc for bug report).

    28/10/96	Changed over from IBM C-Set++ to IBM VisualAge C++ with CTC305.
    		Fixed 16bpp display bug in GBMV2.EXE.

    18/11/96	Added darkfg option on 1bpp BMP writing.
    		Fixed printout of 1bpp bitmaps problem.

    1/2/97  	Changed colour->greyscale coefficients, as Wonkoo suggested.
    		Added JPEG support.
    		Changed documentation to HTML.
    		Submitted to Internet hobbes.nmsu.edu.

    1/5/98		Added initial Linux port.
    		Support GIF files without EOI code in compressed data.
    		Included source for OS/2 PM Scroller control.

    12/7/98 	Fixed writing 1bpp PCXs with reverse palettes (ta Wonkoo).
    		Fixed OS/2 c0000005 Trap by increasing stack size (ta Gunter).

    1/1/99		Added OS/2 _System Gbm_ entrypoints.
    		Added support for filenames starting with -, via -- convention.
    		Initial port to 32 bit DOS, via Watcom C/C++ and CauseWay.

    20/1/99		Fixed reading of .pgm palettes (ta Wonkoo Kim).
    		Fixed 2 low probability bugs in LZW encoders in GIF and TIFF.

    ?/?/99		Change to gbmpgm.c and gbmppm.c to use \n in header.
    		Splitting out of OS/2 specific stuff to seperate package.
    		Fixed 32 bit DOS port to work properly with JPEG support.

    21/11/99	Fixed reading OS/2 bitmaps with < 2**N colours.

    04/01/2000	Fixed reading of 24 bit GemRas image files.

    12/05/2000	Improved TIFF and GIF LZW readers corrupt data detection.
    		Improved TIFF LZW decompressor to work if EOI missing (ta Doug).

    31/12/2000	A few minor tweaks to make source more friendly to Mac compiler.
    		Basically factored in Karl Timmermann suggestions, fixed a few
    		minor signed/unsigned char problems, and removed some #includes.

    05/02/2001	gbmsize -a option, Jeroen Mosterts idea.

    12/02/2001	gbmbpp -c palNbpp options to map to user defined palette.

    Future?		Palette Manager capability in GBMV.EXE and GBMV2.EXE?
    		Non-scaled and fixed scale print for GBMV2.EXE?
    		Special logic for print to 1bpp and 3bpp printers for GBMV2.EXE?
    		Photo-CD, RLE-Bitmap, G3-TIFF, G3-Bitmap for GBM.DLL?
    		My free time is scarce - don't hold your breath!

This documentation is written and maintained by the GBM author, Andy Key