View Raw SPL
/*****************************************************************************
*                                                                            *
*   WRITEBMP.SPL Copyright (C) 1997 DSP Development Corporation              *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Writes a Microsoft .BMP bitmap file                         *
*                                                                            *
*   Revisions:    5 Dec 1997  RRR  Creation                                  *
*                                                                            *
*****************************************************************************/

#include 

#if @HELP_WRITEBMP

    WRITEBMP

    Purpose: Reads a Microsoft .BMP bitmap file

    Syntax:  WRITEBMP(filename, image, colormap)

              filename - a string specifying the destination .BMP file
              image    - an optional image array, defaults to current window
              colormap - an optional 3xN colormap, defaults to current colormap

    Returns: 1 if successful

    Example:
             (x, y) = fxyvals(-1, 1, 0.05, -1, 1, 0.05);

             W1: Density(cos(x*y))

             WRITEBMP("cos2d.bmp", w1)

             writes the image displayed in W1 as a bitmap file


    Remarks:

          WRITEBMP currently supports only uncompressed .BMP files
          with at most 256 colors. The image is automatically scaled to
          8 bits per pixel.

          WRITEBMP.SPL is based on SAVEBMP.M (Copyright 1993) written by:

               Ralph Sucher
               Dept. of Communications Engineering
               Technical University of Vienna
               Gusshausstrasse 25/389
               A-1040 Vienna
               AUSTRIA

    See Also
             Readbmp

#endif


writebmp(bmpfile, X, map)
{
        local fid, nCol, rgb, biBitCnt, xx, i, xmin, xmax;
        local biHeight, biWidth, ndata, Width, Xsize, bfSize, bfOffs;

        if (argc < 1)
        {
                error('Writebmp: filename required');
        }

        if (argc < 2)
        {
                X = current;
        }
        if (argc < 3)
        {
                map = getcolormap();
        }

        if (strlen(strfind(".", bmpfile)) == 0)
        {
                bmpfile = strcat(bmpfile, ".bmp");
        }

        (nCol, rgb) = size(map);

        if (nCol > 256)
        {
                error('Writebmp supports only images with at most 256 colors.');
        }
        if (rgb != 3)
        {
                error('Writebmp: The colormap must have 3 columns: {R,G,B}.');
        }

        if (minval(map[..]) < 0 || maxval(map[..]) > 1)
        {
                error('Writebmp: The colormap must have values between 0.0 and 1.0.');
        }

        // determine number of bits per pixel
        if (nCol <= 2)
        {
                biBitCnt = 1;
        }
        else if (nCol <= 16)
        {
                biBitCnt = 4;
        }
        else
        {
                biBitCnt = 8;
        }

        /* scales between 0.0 and 1.0 */
        X = (X - min(minval(X))) / (max(maxval(X)) - min(minval(X)));

        /* scale betweem 0.0 and 255 */
        X = X * 255;

        // truncate image data
        X = round(X);

        // determine image size
        (biWidth, biHeight) = size(X);
        Width = ceil(biWidth * biBitCnt / 32) * 32 / biBitCnt;
        ndata = Width * biHeight * biBitCnt / 8;

        if (Width - biWidth > 0)
        {
                X = {X, zeros(Width - biWidth, biHeight)};
        }
        
        X = X[..];

        Xsize = Width * biHeight;

        fopen(bmpfile, 'wb');
        fid = bmpfile;

        // ------------------------------- BMP HEADER -------------------------------

        // write file identifier
        fwriteb(fid, UBYTE, {"BM"});

        // write file length (bytes)
        bfSize = 54 + 4 * nCol + ndata;
        fwriteb(fid, LONG, {bfSize});

        // set bytes reserved for later extensions to zero
        fwriteb(fid, LONG, {0});

        // write offset from beginning of file to first data byte
        bfOffs = 54 + 4 * nCol;
        fwriteb(fid, LONG, {bfOffs});

        // ----------------------------- BMP INFO-BLOCK -----------------------------

        // *** bitmap information header ***

        // write length of bitmap information header
        fwriteb(fid, LONG, {40});

        // write width of bitmap
        fwriteb(fid, LONG, {biWidth});

        // write height of bitmap
        fwriteb(fid, LONG, {biHeight});

        // write number of color planes
        fwriteb(fid, UINT, {1});

        // write number of bits per pixel
        fwriteb(fid, UINT, {biBitCnt});

        // write type of data compression
        fwriteb(fid, LONG, {0});

        // write size of compressed image
        fwriteb(fid, LONG, {0});

        // write horizontal resolution
        fwriteb(fid, LONG, {0});

        // write vertical resolution
        fwriteb(fid, LONG, {0});

        // write number of used colors
        fwriteb(fid, LONG, {0});

        // write number of important colors
        fwriteb(fid, LONG, {0});

        // *** colormap ***

        map = ravel(fix(255 * map[.., 3..-1..1]), zeros(nCol, 1))';
        map = map[..];
        fwriteb(fid, UBYTE, map);

        // ------------------------------ BITMAP DATA -------------------------------

        if (biBitCnt == 1)
        {
                xx = zeros(1, ndata);
                
                for (i = 1; i <= 8; i++)
                {
                        xx = xx + 2 ^ (8 - i) * X[i..8..Xsize];
                }
                
                fwriteb(fid, UBYTE, xx);
        }
        else if (biBitCnt == 4)
        {
                xx = 16 * X[1..2..Xsize] + X[2..2..Xsize];
                fwriteb(fid, UBYTE, xx);
        }
        else
        {
                fwriteb(fid, UBYTE, X);
        }

        fclose(fid);
        
        return(1);
}