home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / fbm / src / fliff.c < prev    next >
C/C++ Source or Header  |  1990-06-24  |  24KB  |  805 lines

  1. /*****************************************************************
  2.  * fliff.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
  3.  *
  4.  * Copyright (C) 1989,1990 by Michael Mauldin.  Permission is granted
  5.  * to use this file in whole or in part for any purpose, educational,
  6.  * recreational or commercial, provided that this copyright notice
  7.  * is retained unchanged.  This software is available to all free of
  8.  * charge by anonymous FTP and in the UUNET archives.
  9.  *
  10.  * fliff.c: 
  11.  *
  12.  * CONTENTS
  13.  *    write_iff (image, stream)
  14.  *    read_iff (image, stream, mstr, mlen)
  15.  *
  16.  * EDITLOG
  17.  *    LastEditDate = Mon Jun 25 00:16:58 1990 - Michael Mauldin
  18.  *    LastFileName = /usr2/mlm/src/misc/fbm/fliff.c
  19.  *
  20.  * HISTORY
  21.  * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
  22.  *    Package for Release 1.0
  23.  *
  24.  * 06-Sep-89  Michael Mauldin (mlm) at Carnegie Mellon University
  25.  *    Beta release (version 0.96) mlm@cs.cmu.edu
  26.  *
  27.  * 04-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
  28.  *    Read and Write support for Amiga IFF (except HAM mode)
  29.  *****************************************************************/
  30.  
  31. # include <stdio.h>
  32. # include <math.h>
  33. # include <ctype.h>
  34. # include "fbm.h"
  35.  
  36. #ifndef lint
  37. static char *fbmid =
  38. "$FBM fliff.c <1.0> 25-Jun-90  (C) 1989,1990 by Michael Mauldin, source \
  39. code available free from MLM@CS.CMU.EDU and from UUNET archives$";
  40. #endif
  41.  
  42. /****************************************************************
  43.  * from iff.h
  44.  ****************************************************************/
  45.  
  46. # define BOOL    int        /*  1 bit value            */
  47. # define SBYTE    char        /*  8 bits signend        */
  48. # define UBYTE    unsigned char    /*  8 bits unsigned        */
  49. # define WORD    short        /* 16 bits signed        */
  50. # define UWORD    unsigned short    /* 16 bits unsigned        */
  51. # define LONG    long        /* 32 bits signed        */
  52. # define ID    long
  53. # define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
  54. # define FORM MakeID('F','O','R','M')
  55. # define PROP MakeID('P','R','O','P')
  56. # define LIST MakeID('L','I','S','T')
  57. # define CAT  MakeID('C','A','T',' ')
  58. # define FILLER MakeID(' ',' ',' ',' ')
  59. # define NULL_CHUNK 0L           /* No current chunk.*/
  60. # define TRUE    1
  61. # define FALSE    0
  62.  
  63.  
  64. /* ---------- Chunk ----------------------------------------------------*/
  65.  
  66. /* All chunks start with a type ID and a count of the data bytes that 
  67.    follow--the chunk's "logical size" or "data size". If that number is odd,
  68.    a 0 pad byte is written, too. */
  69.  
  70. typedef struct {
  71.     ID      ckID;
  72.     LONG  ckSize;
  73.     } ChunkHeader;
  74.  
  75. typedef struct {
  76.     ID      ckID;
  77.     LONG  ckSize;
  78.     UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
  79.     } Chunk;
  80.  
  81. /*----------------------------------------------------------------------*
  82.  * ILBM.H  Definitions for InterLeaved BitMap raster image.     1/23/86
  83.  *
  84.  * By Jerry Morrison and Steve Shaw, Electronic Arts.
  85.  * This software is in the public domain.
  86.  *
  87.  * This version for the Commodore-Amiga computer.
  88.  *----------------------------------------------------------------------*/
  89.  
  90. # define ID_ILBM MakeID('I','L','B','M')
  91. # define ID_BMHD MakeID('B','M','H','D')
  92. # define ID_CMAP MakeID('C','M','A','P')
  93. # define ID_GRAB MakeID('G','R','A','B')
  94. # define ID_DEST MakeID('D','E','S','T')
  95. # define ID_SPRT MakeID('S','P','R','T')
  96. # define ID_CAMG MakeID('C','A','M','G')
  97. # define ID_BODY MakeID('B','O','D','Y')
  98.  
  99. /* ---------- BitMapHeader ---------------------------------------------*/
  100.  
  101. typedef UBYTE Masking;        /* Choice of masking technique.*/
  102. # define mskNone                 0
  103. # define mskHasMask              1
  104. # define mskHasTransparentColor  2
  105. # define mskLasso                3
  106.  
  107. typedef UBYTE Compression;    /* Choice of compression algorithm applied to
  108.      * each row of the source and mask planes. "cmpByteRun1" is the byte run
  109.      * encoding generated by Mac's PackBits. See Packer.h . */
  110. # define cmpNone      0
  111. # define cmpByteRun1  1
  112.  
  113. /* Aspect ratios: The proper fraction xAspect/yAspect represents the pixel
  114.  * aspect ratio pixel_width/pixel_height.
  115.  *
  116.  * For the 4 Amiga display modes:
  117.  *   320 x 200: 10/11  (these pixels are taller than they are wide)
  118.  *   320 x 400: 20/11
  119.  *   640 x 200:  5/11
  120.  *   640 x 400: 10/11        */
  121. # define x320x200Aspect 10
  122. # define y320x200Aspect 11
  123. # define x320x400Aspect 20
  124. # define y320x400Aspect 11
  125. # define x640x200Aspect  5
  126. # define y640x200Aspect 11
  127. # define x640x400Aspect 10
  128. # define y640x400Aspect 11
  129.  
  130. /* A BitMapHeader is stored in a BMHD chunk. */
  131. typedef struct {
  132.     UWORD w, h;            /* raster width & height in pixels */
  133.     WORD  x, y;            /* position for this image */
  134.     UBYTE nPlanes;        /* # source bitplanes */
  135.     Masking masking;        /* masking technique */
  136.     Compression compression;    /* compression algorithm */
  137.     UBYTE pad1;            /* UNUSED.  For consistency, put 0 here.*/
  138.     UWORD transparentColor;    /* transparent "color number" */
  139.     UBYTE xAspect, yAspect;    /* aspect ratio, a rational number x/y */
  140.     WORD  pageWidth, pageHeight;  /* source "page" size in pixels */
  141.     } BitMapHeader;
  142.  
  143. /* RowBytes computes the number of bytes in a row, from the width in pixels.*/
  144. # define RowBytes(w)   (2 * (((w) + 15) / 16))
  145.  
  146.  
  147. /* ---------- ColorRegister --------------------------------------------*/
  148. /* A CMAP chunk is a packed array of ColorRegisters (3 bytes each). */
  149. typedef struct {
  150.     UBYTE red, green, blue;   /* MUST be UBYTEs so ">> 4" won't sign extend.*/
  151.     } ColorRegister;
  152.  
  153. /* Use this constant instead of sizeof(ColorRegister). */
  154. # define sizeofColorRegister  3
  155.  
  156. typedef WORD Color4;    /* Amiga RAM version of a color-register,
  157.              * with 4 bits each RGB in low 12 bits.*/
  158.  
  159. # define swapword(X)    ((((X) & 0xff) << 8) | (((X) & 0xff00) >> 8))
  160. # define swaplong(X)    (((unsigned) ((X) & 0xff000000) >> 24) |    \
  161.              ((unsigned) ((X) & 0x00ff0000) >> 8) |    \
  162.              ((unsigned) ((X) & 0x0000ff00) << 8) |    \
  163.              ((unsigned) ((X) & 0x000000ff) << 24))
  164.  
  165. # define swapsize(X) ((machine_byte_order () == LITTLE) ? swaplong(X) : (X))
  166.  
  167. /* Maximum number of bitplanes in RAM. Current Amiga max w/dual playfield. */
  168. # define MaxAmDepth 6
  169.  
  170. /* Chunks must be padded to align to even boundaries */
  171. # define EVENALIGN(X) (((X) + 1) & ~1)
  172.  
  173. /* ---------- Point2D --------------------------------------------------*/
  174. /* A Point2D is stored in a GRAB chunk. */
  175. typedef struct {
  176.     WORD x, y;        /* coordinates (pixels) */
  177.     } Point2D;
  178.  
  179. /* ---------- DestMerge ------------------------------------------------*/
  180. /* A DestMerge is stored in a DEST chunk. */
  181. typedef struct {
  182.     UBYTE depth;    /* # bitplanes in the original source */
  183.     UBYTE pad1;        /* UNUSED; for consistency store 0 here */
  184.     UWORD planePick;    /* how to scatter source bitplanes into destination */
  185.     UWORD planeOnOff;    /* default bitplane data for planePick */
  186.     UWORD planeMask;    /* selects which bitplanes to store into */
  187.     } DestMerge;
  188.  
  189. /* ---------- SpritePrecedence -----------------------------------------*/
  190. /* A SpritePrecedence is stored in a SPRT chunk. */
  191. typedef UWORD SpritePrecedence;
  192.  
  193. /* ---------- Viewport Mode --------------------------------------------*/
  194. /* A Commodore Amiga ViewPort->Modes is stored in a CAMG chunk. */
  195. /* The chunk's content is declared as a LONG. */
  196.  
  197. /* ---------- CRange ---------------------------------------------------*/
  198. /* A CRange is store in a CRNG chunk. */
  199. typedef struct {
  200.     WORD  pad1;        /* reserved for future use; store 0 here */
  201.     WORD  rate;        /* color cycling rate, 16384 = 60 steps/second */
  202.     WORD  active;    /* nonzero means color cycling is turned on */
  203.     UBYTE low, high;    /* lower and upper color registers selected */
  204.     } CRange;
  205.  
  206. /*----------------------------------------------------------------------*
  207.  * PACKER.H  typedefs for Data-Compresser.                  1/22/86
  208.  *
  209.  * This module implements the run compression algorithm "cmpByteRun1"; the
  210.  * same encoding generated by Mac's PackBits.
  211.  *
  212.  * By Jerry Morrison and Steve Shaw, Electronic Arts.
  213.  * This software is in the public domain.
  214.  *
  215.  * This version for the Commodore-Amiga computer.
  216.  *----------------------------------------------------------------------*/
  217.  
  218. /* This macro computes the worst case packed size of a "row" of bytes. */
  219. # define MaxPackedSize(rowSize)  ( (rowSize) + ( ((rowSize)+127) >> 7 ) )
  220.  
  221. /*----------------------------------------------------------------------*
  222.  * unpacker.c Convert data from "cmpByteRun1" run compression. 11/15/85
  223.  *
  224.  * By Jerry Morrison and Steve Shaw, Electronic Arts.
  225.  * This software is in the public domain.
  226.  *
  227.  *    control bytes:
  228.  *     [0..127]   : followed by n+1 bytes of data.
  229.  *     [-1..-127] : followed by byte to be repeated (-n)+1 times.
  230.  *     -128       : NOOP.
  231.  *
  232.  * This version for the Commodore-Amiga computer.
  233.  *----------------------------------------------------------------------*/
  234.  
  235. /*----------- UnPackRow ------------------------------------------------*/
  236.  
  237. # define UGetByte()    (*source++)
  238. # define UPutByte(c)    (*dest++ = (c))
  239.  
  240. /* Given POINTERS to POINTER variables, unpacks one row, updating the source
  241.  * and destination pointers until it produces dstBytes bytes. */
  242. static UnPackRow(pSource, pDest, srcBytes0, dstBytes0)
  243.     char **pSource, **pDest;  int srcBytes0, dstBytes0; {
  244.     register char *source = *pSource;
  245.     register char *dest   = *pDest;
  246.     register int n;
  247.     register char c;
  248.     register int srcBytes = srcBytes0, dstBytes = dstBytes0;
  249.     BOOL error = TRUE;    /* assume error until we make it through the loop */
  250.  
  251.  
  252. # ifdef DEBUG
  253.     fprintf (stderr, "Unpack called, src %d, dst %d\n",
  254.              srcBytes0, dstBytes0);
  255. # endif
  256.  
  257.     while( dstBytes > 0 )  {
  258.     if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
  259.         n = UGetByte() & 0x0ff;
  260.  
  261.         if (n < 128) {
  262. # ifdef DEBUG
  263.             fprintf (stderr, "Got %02x, copying %d bytes...\n", n, n+1);
  264. # endif
  265.  
  266.         n += 1;
  267.         
  268.         if ( (srcBytes -= n) < 0 )  goto ErrorExit;
  269.         if ( (dstBytes -= n) < 0 )  goto ErrorExit;
  270.         do {  UPutByte(UGetByte());  } while (--n > 0);
  271.         }
  272.  
  273.         else if (n != 128) {
  274. # ifdef DEBUG
  275.             fprintf (stderr, "Got %02x, repeating byte %d times...\n",
  276.             n, 257-n);
  277. # endif
  278.  
  279.         n = 257 - n;
  280.         
  281.         if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
  282.         if ( (dstBytes -= n) < 0 )  goto ErrorExit;
  283.         c = UGetByte();
  284.         do {  UPutByte(c);  } while (--n > 0);
  285.         }
  286.     }
  287.     error = FALSE;    /* success! */
  288.  
  289.   ErrorExit:
  290.     *pSource = source;  *pDest = dest;
  291.     
  292.     if (error)
  293.     { fprintf (stderr, "error in unpack, src %d, dst %d\n", 
  294.            srcBytes, dstBytes);
  295.     }
  296.     
  297.     return(error);
  298.     }
  299.  
  300. /****************************************************************
  301.  * read_iff: Read an Amiga format IFF Interleaved Bitmap
  302.  ****************************************************************/
  303.  
  304. read_iff (image, rfile, mstr, mlen)
  305. FBM *image;
  306. FILE *rfile;
  307. char *mstr;
  308. int mlen;
  309. { char magic[8];
  310.   long formsize, buflen;
  311.   Chunk *form;
  312.   int result;
  313.  
  314.   /* First word is magic number */
  315.   magic[0] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  316.   magic[1] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  317.   magic[2] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  318.   magic[3] = NEXTMCH(rfile,mstr,mlen) & 0xff;
  319.   magic[4] = '\0';
  320.  
  321.   /* If magic number is not FORM, lose */
  322.   if (strcmp (magic, "FORM") != 0)
  323.   { if (strncmp (magic, "FOR", 3) == 0 ||
  324.     strncmp (magic, "LIS", 3) == 0 ||
  325.     strncmp (magic, "CAT", 3) == 0)
  326.     { fprintf (stderr, "Sorry, I only handle FORM type IFF files\n");
  327.       return (0);
  328.     }
  329.     
  330.     fprintf (stderr,
  331.          "read_iff: error, file not a FORM type IFF file, magic '%s'\n",
  332.           magic);
  333.     return (0);
  334.   }
  335.  
  336.   /* Second longword is length of data chunk */
  337.   formsize = get_long (rfile, BIG);  
  338.   
  339.   form = (Chunk *) malloc (formsize + 8);
  340.   form->ckID = FORM;
  341.   form->ckSize = formsize;
  342.  
  343.   /* Now read the rest of the chunk */
  344.   if ((buflen = fread (form->ckData, 1, formsize, stdin)) < formsize)
  345.   { if (buflen < 0)
  346.     { perror ("stdin"); }
  347.     else
  348.     { fprintf (stderr, "error: premature EOF in FORM after %d of %d bytes\n",
  349.            buflen, formsize);
  350.     }
  351.  
  352.     exit (1);
  353.   }
  354.  
  355.   /* Recursively parse the FORM */  
  356.   result = parse_form (image, form);
  357.  
  358.   /* Now we've read the image (or not) */  
  359.   free (form);
  360.  
  361.   return (result);
  362. }
  363.  
  364. /****************************************************************
  365.  * parse_form: Parse an IFF form chunk
  366.  *
  367.  *    FORM       ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* }
  368.  *    FormType   ::= ID
  369.  *    LocalChunk ::= Property | Chunk
  370.  ****************************************************************/
  371.  
  372. parse_form (image, chunk)
  373. FBM *image;
  374. Chunk *chunk;
  375. { register UBYTE *data, *tail;
  376.   register int clrlen, colors;
  377.   register BitMapHeader *bmh;
  378.   register int i, bits;
  379.   long formtype;
  380.   int found_bmhd=0, found_cmap=0, found_body=0;
  381.   Chunk *part;
  382.  
  383.   data = chunk->ckData;
  384.   tail = data + chunk->ckSize;  
  385.   
  386.   formtype = MakeID(data[0], data[1], data[2], data[3]);
  387.   data += 4;
  388.   
  389.   if (formtype != ID_ILBM)
  390.   { fprintf (stderr, "this FORM doesn't start with ILBM, but %4.4s, sorry.\n",
  391.          &formtype);
  392.     return (0);
  393.   }
  394.   
  395.   while (data < tail)
  396.   { part = (Chunk *) data;
  397.     part->ckID   = swapsize (part->ckID);
  398.     part->ckSize = swapsize (part->ckSize);
  399.     data += ( EVENALIGN (part->ckSize) + 8 );
  400.     
  401. # ifdef DEBUG
  402.     fprintf (stderr, "Found %c%c%c%c, size %ld\n",
  403.         (part->ckID & 0xff000000) >> 24,
  404.         (part->ckID & 0x00ff0000) >> 16,
  405.         (part->ckID & 0x0000ff00) >>  8,
  406.         (part->ckID & 0x000000ff),
  407.         part->ckSize);
  408. # endif
  409.  
  410.     if (part->ckID == ID_BMHD)
  411.     { found_bmhd++;
  412.       bmh = (BitMapHeader *) part->ckData;
  413.       
  414.       /* IFF uses BIG byte order, swap if necessary */
  415.       if (machine_byte_order () == LITTLE)
  416.       { bmh->w = swapword (bmh->w);
  417.         bmh->h = swapword (bmh->h);
  418.     bmh->x = swapword (bmh->x);
  419.     bmh->y = swapword (bmh->y);
  420.     bmh->transparentColor = swapword (bmh->transparentColor);
  421.     bmh->pageWidth = swapword (bmh->pageWidth);
  422.     bmh->pageHeight = swapword (bmh->pageHeight);
  423.       }
  424.       
  425.       image->hdr.rows = bmh->h;
  426.       image->hdr.cols = bmh->w;
  427.       image->hdr.planes = 1;
  428.       image->hdr.bits = bmh->nPlanes;
  429.       image->hdr.physbits = 8;
  430.       image->hdr.rowlen = 2 * ((image->hdr.cols + 1) / 2);
  431.       image->hdr.plnlen = image->hdr.rowlen * image->hdr.rows;
  432.       image->hdr.clrlen = 0;
  433.       image->hdr.aspect = (double) bmh->yAspect / bmh->xAspect;
  434.       image->hdr.title[0] = '\0';
  435.       image->hdr.credits[0] = '\0';
  436.     }
  437.     else if (part->ckID == ID_CMAP)
  438.     { image->hdr.clrlen = part->ckSize;
  439.  
  440.       alloc_fbm (image);
  441.  
  442.       clrlen = image->hdr.clrlen;
  443.       colors = clrlen / 3;
  444.  
  445.       for (i=0; i<image->hdr.clrlen; i++)
  446.       { image->cm[(colors * (i%3)) + i/3] = part->ckData[i]; }
  447.  
  448.       /* Compute number of bits in colormap */
  449.       for (i=colors, bits=1; i > 2; i /= 2, bits++) ;
  450.       
  451.       if (bits < image->hdr.bits) image->hdr.bits = bits;
  452.  
  453.       found_cmap++;
  454.     }
  455.     else if (part->ckID == ID_BODY)
  456.     { if (!found_bmhd)
  457.       { fprintf (stderr, "Error, BODY found with no BMHD header\n");
  458.         return (0);
  459.       }
  460.       
  461.       if (found_cmap == 0)
  462.       { alloc_fbm (image); }
  463.       
  464.       found_body++;
  465.       
  466.       /* Decode body */
  467.       fprintf (stderr, "Reading IFF [%dx%dx%d], %d physbits, %1.3lf aspect",
  468.         image->hdr.cols, image->hdr.rows,
  469.         image->hdr.bits, image->hdr.physbits,
  470.         image->hdr.aspect);
  471.       if (image->hdr.planes > 1)
  472.       { fprintf (stderr, ", %d planes", image->hdr.planes); }
  473.       if (image->hdr.clrlen > 1)
  474.       { fprintf (stderr, ", %d colors", image->hdr.clrlen / 3); }
  475.       if (bmh->compression)
  476.       { fprintf (stderr, ", compressed"); }
  477.       if (bmh->masking == mskHasMask)
  478.       { fprintf (stderr, ", with mask"); }
  479.       fprintf (stderr, "\n");
  480.  
  481. # ifdef DEBUG
  482.       fprintf (stderr,
  483.            "masking %d, compression %d, transparent %d, page [%dx%d]\n",
  484.            bmh->masking, bmh->compression, bmh->transparentColor,
  485.            bmh->pageWidth, bmh->pageHeight);
  486.  
  487.     for (i=0; i<colors; i++)
  488.     { fprintf (stderr, "    color %3d:  <%3d, %3d, %3d>\n", i,
  489.            image->cm[i], image->cm[i+colors], image->cm[i+colors*2]);
  490.     }
  491. # endif
  492.       
  493.       return (read_iff_body (image, bmh, part));
  494.     }
  495.   }
  496.   
  497.   return (0);
  498. }
  499.  
  500. /****************************************************************
  501.  * read_iff_body: Read the bits in the ILBM body into the FBM image
  502.  ****************************************************************/
  503.  
  504. read_iff_body (image, bmh, body)
  505. FBM *image;
  506. BitMapHeader *bmh;
  507. Chunk *body;
  508. { register int r, c, k, pmask, byte, bit;
  509.   unsigned char *row, *bp, *buf, *obm, *tail;
  510.   int bytlen = image->hdr.cols / 8;
  511.   int planes =  bmh->nPlanes + ((bmh->masking == mskHasMask) ? 1 : 0);
  512.   
  513.   buf = (unsigned char *) malloc (bytlen);
  514.   
  515.   bp = body->ckData;
  516.   tail = bp + body->ckSize;
  517.  
  518. # ifdef DEBUG
  519.   fprintf (stderr, "Body length %d, planes %d: ", tail-bp, planes);
  520.   for (c=0; c<20; c++) fprintf (stderr, "%02x", bp[c]);
  521.   fprintf (stderr, "\n");
  522. # endif
  523.  
  524.   /* Each iteration reads one scan line */
  525.   for (r=0; r<image->hdr.rows; r++)
  526.   {
  527.     if (bp > tail)
  528.     { fprintf (stderr, "Ran out of data in body after %d of %d rows\n",
  529.         r, image->hdr.rows);
  530.       return (0);
  531.     }
  532.  
  533.     obm = &(image->bm[r * image->hdr.rowlen]);
  534.  
  535.     /* Clear the output row of pixels */
  536.     for (c=0; c<image->hdr.cols; c++)
  537.     { obm[c] = 0; }
  538.  
  539.     /* Each loop reads one plane of this scan line */    
  540.     for (k=0; k<planes; k++)
  541.     {
  542.       /* First get pointer to data packed 8 bits per byte */
  543.       if (bmh->compression == 0)
  544.       { row = bp; bp += RowBytes (bmh->w); }
  545.       else
  546.       { row = buf;
  547.         if (UnPackRow ((char **)&bp, (char **)&row, (int)(tail-bp),
  548.             RowBytes (bmh->w)) != 0)
  549.         { fprintf (stderr,
  550.            "%s, row %d of %d, plane %d of %d, bytes per row %d\n",
  551.            "Error in UnPackRow",
  552.            r, image->hdr.rows, k, planes, RowBytes (bmh->w));
  553.       return (0);
  554.     }
  555.     row = buf;
  556.       }
  557.  
  558.       /* Ignore extra planes (including the mask if any) */
  559.       if (k >= image->hdr.bits)
  560.         continue;
  561.  
  562.       /* Now OR in these bits into the output pixels */
  563.       pmask = 1 << k;
  564.  
  565.       for (c=0; c<image->hdr.cols; c++)
  566.       { byte = c >> 3;
  567.         bit = 7 - (c & 7);
  568.     bit = row[byte] & (1 << bit);
  569.  
  570.     obm[c] |= bit ? pmask : 0;
  571.       }
  572.     }
  573.   }
  574.  
  575.   if (tail-bp > 1)
  576.   { fprintf (stderr, "Warning, %d bytes of data unread\n", tail - bp); }
  577.   
  578.   return (1);
  579. }
  580.  
  581. /****************************************************************
  582.  * write_iff: Write AMIGA IFF format ILBM file
  583.  *
  584.  * Writes        FORM type ILBM
  585.  *                BMHD
  586.  *                CMAP (optional)
  587.  *                BODY (uncompressed)
  588.  *
  589.  ****************************************************************/
  590.  
  591. write_iff (image, wfile)
  592. FBM *image;
  593. FILE *wfile;
  594. { BitMapHeader bmhd;
  595.   unsigned char *cmap, *body;
  596.   int bodylen, cmaplen, bmhdlen, formlen, ilbmbits;
  597.  
  598.   if (image->hdr.planes > 1)
  599.   { fprintf (stderr, "Error, write_iff cannot handle multi-plane images\n");
  600.     return (0);
  601.   }
  602.  
  603.   /* Determine number of bits in output */
  604.   if (image->hdr.clrlen == 0)
  605.   { ilbmbits = image->hdr.bits; }
  606.   else
  607.   { int colors = image->hdr.clrlen/3;
  608.     for (ilbmbits=1; colors > 2; ilbmbits++, colors >>= 1) ;
  609.   }
  610.   
  611.   fprintf (stderr, "Writing \"%s\" [%dx%d] as a %d bit IFF ILBM file\n",
  612.        image->hdr.title[0] ? image->hdr.title : "",
  613.        image->hdr.cols, image->hdr.rows, ilbmbits);
  614.  
  615.   if (ilbmbits > 5)
  616.   { fprintf (stderr, "%s\n%s\n%s\n",
  617.     "Warning: most IFF ILBM displays cannot handle more than",
  618.     "     32 colors. You should probably run the image though",
  619.     "     'gray2clr -u | fbquant -c32' first.");
  620.   }
  621.  
  622.   /* Build BMHD, CMAP, and body chunks */
  623.   bmhdlen = build_bmhd (image, &bmhd, ilbmbits) ;
  624.   cmaplen = build_cmap (image, &cmap, ilbmbits);
  625.   bodylen = build_body (image, &body, ilbmbits);
  626.   
  627.   /* Length of FORM is length of subparts plus 8 for header + 4 for type */
  628.   formlen = bmhdlen + cmaplen + bodylen + 12;
  629.  
  630.   /*--------Write out FORM chunk header--------*/
  631.   fprintf (wfile, "FORM");
  632.   put_long (formlen-8, wfile, BIG);
  633.   fprintf (wfile, "ILBM");
  634.  
  635.   /*----Write out BMHD chunk----*/
  636.   fprintf (wfile, "BMHD");
  637.   put_long (bmhdlen-8, wfile, BIG);
  638.   fwrite (&bmhd, bmhdlen-8, 1, wfile);
  639.  
  640.   /* No need to pad BMHD chunk, it must be even */
  641.       
  642.   /*----Write out CMAP chunk----*/
  643.   if (cmaplen > 0)
  644.   { fprintf (wfile, "CMAP");
  645.     put_long (cmaplen-8, wfile, BIG);
  646.     fwrite (cmap, cmaplen-8, 1, wfile);
  647.   
  648.     /* Pad CMAP chunk if necessary */
  649.     if (cmaplen & 1) fputc (0, wfile);
  650.   }
  651.       
  652.   /*----Write out BODY chunk----*/
  653.   fprintf (wfile, "BODY");
  654.   put_long (bodylen-8, wfile, BIG);
  655.   fwrite (body, bodylen-8, 1, wfile);
  656.  
  657.   /* Pad BODY chunk if necessary */
  658.   if (bodylen & 1) fputc (0, wfile);
  659.       
  660.   /*--------Free memory and return--------*/
  661.   if (cmap)    free (cmap);
  662.   if (body)    free (body);
  663.  
  664.   return (1);
  665. }
  666.  
  667. /****************************************************************
  668.  * build_bmhd: Build a BitMapHeader, and byte swap it if necessary
  669.  ****************************************************************/
  670.  
  671. build_bmhd (image, bmh, bits)
  672. FBM *image;
  673. BitMapHeader *bmh;
  674. int bits;
  675. {
  676.   bmh->w = image->hdr.cols;
  677.   bmh->h = image->hdr.rows;
  678.   bmh->x = 0;
  679.   bmh->y = 0;
  680.   bmh->nPlanes = bits;
  681.   bmh->masking = 0;  
  682.   bmh->compression = 0;
  683.   bmh->pad1 = 0;
  684.   bmh->transparentColor = 0;
  685.   bmh->xAspect = 100;
  686.   bmh->yAspect = (image->hdr.aspect * 100.0) + 0.5;
  687.   bmh->pageWidth = bmh->w;
  688.   bmh->pageHeight = bmh->h;
  689.  
  690.   /* IFF uses BIG byte order, swap if necessary */
  691.   if (machine_byte_order () == LITTLE)
  692.   { bmh->w = swapword (bmh->w);
  693.     bmh->h = swapword (bmh->h);
  694.     bmh->x = swapword (bmh->x);
  695.     bmh->y = swapword (bmh->y);
  696.     bmh->transparentColor = swapword (bmh->transparentColor);
  697.     bmh->pageWidth = swapword (bmh->pageWidth);
  698.     bmh->pageHeight = swapword (bmh->pageHeight);
  699.   }
  700.  
  701.   return (sizeof (*bmh) + 8);
  702. }
  703.  
  704. /****************************************************************
  705.  * build_cmap: Convert an FBM format colormap to IFF format
  706.  ****************************************************************/
  707.  
  708. build_cmap (image, cmap, bits)
  709. FBM *image;
  710. unsigned char **cmap;
  711. int bits;
  712. { register int len, i;
  713.   register unsigned char *r, *g, *b, *c;
  714.   int colors;
  715.  
  716.   colors = image->hdr.clrlen / 3;
  717.   
  718.   r = image->cm;
  719.   g = r + colors;
  720.   b = g + colors;
  721.   
  722.   len = 3*colors;
  723.   *cmap = (unsigned char *) malloc (len);
  724.  
  725.   /* Now convert from three vectors to a vector of triples */
  726.   for (i=0, c= *cmap; i<colors; i++)
  727.   { *c++ = *r++;
  728.     *c++ = *g++;
  729.     *c++ = *b++;
  730.   }
  731.   
  732.   /* Return length of chunk, just length of map plus 8 bytes chunk header */
  733.   return (len + 8);
  734. }
  735.  
  736. /****************************************************************
  737.  * build_body: Interleave the bits for the byte plane
  738.  ****************************************************************/
  739.  
  740. build_body (image, body, bits)
  741. register FBM *image;
  742. unsigned char **body;
  743. int bits;
  744. { int bpr, size;
  745.   register unsigned char *obm, *bmp;
  746.   register int r, c, k, mask, byte, bit;
  747.  
  748.   bpr = RowBytes (image->hdr.cols);
  749.   
  750.   size = bpr * image->hdr.rows * bits;
  751.   
  752.   *body = (unsigned char *) malloc (size);
  753.  
  754.   obm = *body;  
  755.  
  756.   for (r=0; r < image->hdr.rows; r++)
  757.   { for (k=0; k<bits; k++)
  758.     { mask = 1 << k;
  759.       bmp = &(image->bm[r * image->hdr.rowlen]);
  760.  
  761. # ifdef DEBUG      
  762.       if (r==23)
  763.       { fprintf (stderr, "Row %d, plane %d, bytes: ", r, k);
  764.         for (c=0; c<32; c++) fprintf (stderr, "%02x", bmp[c]);
  765.     fprintf (stderr, "\n");
  766.       }
  767. # endif
  768.       
  769.       for (c=0, byte=0; c<image->hdr.cols; c++)
  770.       { bit = (*bmp++ & mask) ? 1 : 0;
  771.  
  772.  
  773. # ifdef DEBUG
  774.         if (r == 23 && c < 32)
  775.     { fprintf (stderr, "%d", bit); }
  776. # endif
  777.  
  778.     byte = (byte << 1) | bit;
  779.         if ((c&7) == 7)
  780.     { *obm++ = byte;
  781.  
  782. # ifdef DEBUG
  783.       if (r == 23 && c <32) fprintf (stderr, " %d ", byte);
  784. # endif
  785.  
  786.       byte=0;
  787.         }
  788.       }
  789.       
  790. # ifdef DEBUG
  791.       if (r == 23) fprintf (stderr, "\n");
  792. # endif
  793.       
  794.       if ((c & 7) != 0)
  795.       { while ((c&7) != 0)
  796.         { c++; byte <<= 1; }
  797.     *obm++ = byte;
  798.       }
  799.     }
  800.   }
  801.   
  802.   return (size + 8);
  803.   
  804. }
  805.