[comp.sources.unix] v19i053: FBM, image manipulation library, Part07/08

rsalz@uunet.uu.net (Rich Salz) (06/09/89)

Submitted-by: Michael.Mauldin@NL.CS.CMU.EDU
Posting-number: Volume 19, Issue 53
Archive-name: fbm/part07

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 8)."
# Contents:  fbham.c flgifr.c fliff.c
# Wrapped by rsalz@fig.bbn.com on Fri Jun  9 08:38:29 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'fbham.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fbham.c'\"
else
echo shar: Extracting \"'fbham.c'\" \(14765 characters\)
sed "s/^X//" >'fbham.c' <<'END_OF_FILE'
X/*****************************************************************
X * fbham.c: FBM Library 0.94 (Beta test) 20-May-89  Michael Mauldin
X *
X * fbham.c: Write a 24bit RGB file as an Amiga HAM IFF file
X *
X * USAGE
X *     % fbham < image1 > image2
X *
X * EDITLOG
X *	LastEditDate = Sat May 20 19:15:08 1989 - Michael Mauldin
X *	LastFileName = /usr2/mlm/src/misc/fbm/fbham.c
X *
X * HISTORY
X * 20-May-89  Michael Mauldin (mlm) at Carnegie Mellon University
X *	Beta release (version 0.94) mlm@cs.cmu.edu
X *
X * 20-Apr-89  C. Harald Koch (chk) at DCIEM Toronto.
X *     Created.  chk@ben.dciem.dnd.ca
X *
X *================================================================
X * based on ray2.c from DBW_Render, Copyright 1987 David B. Wecker
X *
X * From: chk@dretor.dciem.dnd.ca (C. Harald Koch)
X * Subject: fbham.c - convert a 24bit FBM file to an IFF file using HAM mode
X * To: Michael.Mauldin@nl.cs.cmu.edu (Michael Maudlin)
X * Date: Mon, 1 May 89 17:21:16 EDT
X * X-Mailer: ELM [version 2.2 PL0]
X * 
X * This is the source to my program to convert from a 24bit FBM file to Amiga
X * HAM mode. It is based on Dave Wecker's RAY2 program, which converts the
X * output of his raytracer to HAM mode. His code uses the Amiga graphics
X * library to plot the pixels in a framebuffer for encoding; this version will
X * run standalone.
X * 
X * There may be bugs, although it works well for me here. It is probably not in
X * the format you want for FBM source; Please go ahead and modify it. There is
X * probably room for some command line options for various things (such as the
X * verbose output, run length encoding, etc) which I haven't needed and so
X * haven't added.
X * 
X * I will send you the IRIS programs when I get them. Enjoy!
X *	-chk
X *****************************************************************/
X
X#include <stdio.h>
X#include <math.h>
X#include "fbm.h"
X
X# define USAGE "Usage: fbham < image > image"
X
X#ifndef lint
Xstatic char    *fbmid = 
X"$FBM fbham.c <0.93> 03-May-89  (C) 1989 by C. Harald Koch$";
X#endif
X
X#define DEPTH	    6		/* max depth of Amiga HAM image */
X
X#define BMHDsize    20L		/* chunk sizes */
X#define CMAPsize    96L
X#define CAMGsize    4L
X#define BODYsize    ((long)(16000L))
X#define FORMsize    (BODYsize+CAMGsize+CMAPsize+BMHDsize+36L)
X
Xunsigned char *planes[DEPTH];	/* bitplane pointers */
X
Xstatic int      comp = 1;	/* compress image? */
Xstatic int      depth = DEPTH;	/* depth of image being created */
Xstatic int      colors = 16;	/* number of colors in color lookup table */
Xstatic int      colorstats[4096][2];	/* color usage statistics */
Xstatic int	row_size;	/* number of bytes in IFF row of data */
X
X/* temp variables for writing IFF file */
Xchar            str[40];
Xlong            lng, pos1, pos2;
Xshort           wrd;
Xunsigned char   byt;
Xunsigned char  *dest, destbuf[BUFSIZ];
X
X
Xmain(argc, argv)
Xchar           *argv[];
X{
X    FBM             input;
X
X    /* Clear the memory pointers so alloc_fbm won't be confused */
X    input.cm = input.bm = (unsigned char *) NULL;
X
X    /* Read the image and rotate it */
X    if (!read_bitmap(&input, argc > 0 ? argv[1] : (char *) NULL))
X    {
X	exit(1);
X    }
X
X    /* slight sanity checks. could be better. */
X    if (input.hdr.physbits != 8 || input.hdr.planes != 3) {
X	fprintf(stderr, "input file must be 24 bit RGB data\n");
X	exit(1);
X    }
X
X    /* convert to HAM */
X    if (!fbm2ham(&input, stdout)) {
X	exit(1);
X    }
X
X    exit(0);
X}
X
X
X/************************ run length encoding from Amiga RKM *****************/
X#define DUMP		0   /* list of different bytes */
X#define RUN		1   /* single run of bytes */
X#define MinRun		3   /* shortest allowed run */
X#define MaxRun		128 /* longest run (length is signed char) */
X#define	MaxDat		128 /* longest block of unencoded data */
X#define GetByte()	(*source++)
X#define PutByte(c)	{ *dest++ = (c); ++PutSize; }
X#define OutDump(nn)	dest = PutDump(dest,nn);
X#define OutRun(nn,cc)	dest = PutRun(dest,nn,cc);
X
Xint             PutSize;
Xchar            buf[256];
X
Xunsigned char  *
XPutDump(dest, nn)
Xunsigned char  *dest;
Xint             nn;
X{
X    int             i;
X
X    PutByte(nn - 1);
X    for (i = 0; i < nn; i++)
X	PutByte(buf[i]);
X    return (dest);
X}
X
Xunsigned char  *
XPutRun(dest, nn, cc)
Xunsigned char  *dest;
Xint             nn, cc;
X{
X    PutByte(-(nn - 1));
X    PutByte(cc);
X    return (dest);
X}
X
X/* PackRow - pack a row of data using Amiga IFF RLE */
Xint 
XPackRow(pSource, pDest, RowSize)
Xunsigned char **pSource, **pDest;
Xint             RowSize;
X{
X    unsigned char  *source, *dest;
X    char            c, lastc = '\000';
X    int             mode = DUMP, nbuf = 0,	/* number of chars in buf */
X                    rstart = 0;	/* buf index current run starts */
X
X    source = *pSource;
X    dest = *pDest;
X
X    PutSize = 0;
X    buf[0] = lastc = c = GetByte();
X    nbuf = 1;
X    RowSize--;
X
X    for (; RowSize; --RowSize) {
X	buf[nbuf++] = c = GetByte();
X
X	switch (mode) {
X	case DUMP:
X	    if (nbuf > MaxDat) {
X		OutDump(nbuf - 1);
X		buf[0] = c;
X		nbuf = 1;
X		rstart = 0;
X		break;
X	    }
X	    if (c == lastc) {
X		if (nbuf - rstart >= MinRun) {
X		    if (rstart > 0)
X			OutDump(rstart);
X		    mode = RUN;
X		}
X		else if (rstart == 0)
X		    mode = RUN;
X	    }
X	    else
X		rstart = nbuf - 1;
X	    break;
X
X	case RUN:
X	    if ((c != lastc) || (nbuf - rstart > MaxRun)) {
X		OutRun((nbuf - 1) - rstart, lastc);
X		buf[0] = c;
X		nbuf = 1;
X		rstart = 0;
X		mode = DUMP;
X	    }
X	    break;
X	}
X	lastc = c;
X    }
X    switch (mode) {
X    case DUMP:
X	OutDump(nbuf);
X	break;
X    case RUN:
X	OutRun(nbuf - rstart, lastc);
X	break;
X    }
X
X    *pSource = source;
X    *pDest = dest;
X
X    return (PutSize);
X}
X/******************* end of RKM RL encoding routines **********************/
X
X
X/* build_histogram - count frequency of 12bit colors in an FBM image */
Xbuild_histogram(image)
XFBM *image;
X{
X    int i, j, t0, t1, gap, val, used;
X    unsigned char *rp, *gp, *bp;
X    int diff;
X
X    /* initialize color statistics. */
X    for (i = 0; i < 4096; i++) {
X	colorstats[i][0] = i;
X	colorstats[i][1] = 0;
X    }
X
X    /* obtain pointers to the beginning of each plane (Red, Green, Blue) */
X    rp = image->bm;
X    gp = rp + image->hdr.plnlen;
X    bp = gp + image->hdr.plnlen;
X
X    /* count the number of occurences of each color in the image */
X    for (i = 0 ; i < image->hdr.plnlen ; i++) {
X	val = ((*rp++ & 0xf0) << 4) + (*gp++ & 0xf0) + ((*bp++ & 0xf0) >> 4);
X	val %= 4096;
X	if (colorstats[val][1] < 32767) {
X	    colorstats[val][1]++;
X	}
X    }
X
X    /* sort the color stats in order of decreasing usage */
X    for (gap = 2048; gap > 0; gap /= 2) {
X	for (i = gap; i < 4096; i++) {
X	    for (j = i - gap; j >= 0 &&
X		    colorstats[j][1] < colorstats[j + gap][1]; j -= gap) {
X		t0 = colorstats[j][0];
X		t1 = colorstats[j][1];
X		colorstats[j][0] = colorstats[j + gap][0];
X		colorstats[j][1] = colorstats[j + gap][1];
X		colorstats[j + gap][0] = t0;
X		colorstats[j + gap][1] = t1;
X	    }
X	}
X    }
X
X    /* count the number of colors actually used in the image */
X    for (used = 0; used < 4096 && colorstats[used][1] > 0; used++);
X    fprintf(stderr, "Used %d colors out of a possible 4096\n", used);
X}
X
X/*-
X * plot_pixel - plot a color in an Amiga style bitmap (one plane per bit)
X *
X * Description:
X *	A somewhat optimized routine to set/reset one bit in each plane
X *	at the specified (x,y) coordinates. plane i gets the bit in
X *	position i of color. a replacement for the Amiga WritePixel call.
X-*/
Xplot_pixel(planes, x, y, color)
Xunsigned char *planes[];
Xint x, y;
Xregister int color;
X{
X    register int bit;
X    register unsigned char shifted_bit = 1 << (7-(x%8));
X    register int array_offset = y * row_size + x/8;
X    register int i;
X
X    for (i = 0; color && i < depth; i++) {
X	bit = color & 1;
X	color >>= 1;
X
X	if (bit)    *(planes[i] + array_offset) |= shifted_bit;
X    }
X}
X
X
X/*-
X * fbm2ham - write an FBM image in HAM IFF format on the given file pointer.
X *
X-*/
Xfbm2ham(image, ofil)
XFBM *image;
XFILE *ofil;
X{
X    int             i, j, k, gap, t0, t1, prgb, crgb, cpix, ppix, maxdis, used;
X    int		    c1, c2, diff;
X    unsigned char *rp, *gp, *bp;
X
X    fprintf(stderr, "Building a color histogram:\n");
X    build_histogram(image);
X
X    /* convert the image to an Amiga HAM bitplane based image */
X    cpix = 0;
X    crgb = colorstats[0][1];
X
X    rp = image->bm;
X    gp = rp + image->hdr.plnlen;
X    bp = gp + image->hdr.plnlen;
X
X    row_size = ((image->hdr.cols + 15) / 16) * 2;
X    diff = image->hdr.rowlen - image->hdr.cols;
X
X    for (i = 0; i < depth ; i++) {
X	planes[i] = (unsigned char *)malloc(row_size * image->hdr.rows);
X    }
X
X    for (i = 0; i < image->hdr.rows; i ++) {
X	/* verbose output because this program is slow even on a Sun */
X	if (i%50 == 0) { fprintf(stderr, "...%d", i); fflush(stderr); }
X
X	/* step through current row, converting FBM pixel to nearest equivalent
X	 * HAM pixel */
X	for (j = 0; j < image->hdr.cols; j++) {
X	    prgb = crgb;
X	    crgb = ((*rp++ & 0xf0) << 4) + (*gp++ & 0xf0) + ((*bp++ & 0xf0) >> 4);
X	    crgb %= 4096;
X	    ppix = cpix;
X
X	    /* start of scan line is ALWAYS an absolute color */
X	    if (j == 0)
X		cpix = getcolor(ppix, &crgb, -1);
X	    else
X		cpix = getcolor(ppix, &crgb, prgb);
X
X	    /* plot the computed pixel */
X	    plot_pixel(planes, j, i, cpix);
X	}
X	rp += diff;
X	gp += diff;
X	bp += diff;
X    }
X    fprintf(stderr, "\n");
X
X    /* Now we write the planes[] array we just created in ILBM format */
X    sprintf(str, "FORM");
X    fwrite(str, 1, 4, ofil);
X    pos1 = ftell(ofil);
X    lng = FORMsize;
X    fwrite(&lng, 4, 1, ofil);
X    sprintf(str, "ILBM");
X    fwrite(str, 1, 4, ofil);
X
X    sprintf(str, "BMHD");
X    fwrite(str, 1, 4, ofil);
X    lng = BMHDsize;
X    fwrite(&lng, 4, 1, ofil);
X    wrd = image->hdr.cols;
X    fwrite(&wrd, 2, 1, ofil);	/* width */
X    wrd = image->hdr.rows;
X    fwrite(&wrd, 2, 1, ofil);	/* height */
X    wrd = 0;
X    fwrite(&wrd, 2, 1, ofil);	/* top */
X    wrd = 0;
X    fwrite(&wrd, 2, 1, ofil);	/* left */
X    byt = depth;
X    fwrite(&byt, 1, 1, ofil);	/* Depth */
X    byt = 0;
X    fwrite(&byt, 1, 1, ofil);	/* mask */
X    byt = comp;
X    fwrite(&byt, 1, 1, ofil);	/* compress */
X    byt = 0;
X    fwrite(&byt, 1, 1, ofil);	/* pad */
X    wrd = 0;
X    fwrite(&wrd, 2, 1, ofil);	/* transparency */
X    byt = 10;
X    fwrite(&byt, 1, 1, ofil);	/* aspect x */
X    byt = 11;
X    fwrite(&byt, 1, 1, ofil);	/* aspect y */
X    wrd = image->hdr.cols;
X    fwrite(&wrd, 2, 1, ofil);	/* page width */
X    wrd = image->hdr.rows;
X    fwrite(&wrd, 2, 1, ofil);	/* page height */
X
X    /* CAMG chunk for displaying files on the Amiga. should include at least
X     * the HAM flag; I also add lace if the picture is large enough. Perhaps
X     * this should be an option. -CHK */
X    sprintf(str, "CAMG");
X    fwrite(str, 1, 4, ofil);
X    lng = CAMGsize;
X    fwrite(&lng, 4, 1, ofil);
X    if (image->hdr.rows > 200)
X	lng = 0x804L;		/* HAM | LACE */
X    else
X	lng = 0x800L;		/* HAM */
X    fwrite(&lng, 4, 1, ofil);
X
X    /* write out the color lookup table */
X    sprintf(str, "CMAP");
X    fwrite(str, 1, 4, ofil);
X    lng = CMAPsize;
X    fwrite(&lng, 4, 1, ofil);
X    for (i = 0; i < 32; i++) {
X	str[0] = (colorstats[i][0] >> 4) & 0xF0;
X	str[1] = (colorstats[i][0]) & 0xF0;
X	str[2] = (colorstats[i][0] << 4) & 0xF0;
X	fwrite(str, 1, 3, ofil);
X    }
X
X    sprintf(str, "BODY");
X    fwrite(str, 1, 4, ofil);
X    pos2 = ftell(ofil);
X    lng = BODYsize;
X    fwrite(&lng, 4, 1, ofil);
X
X    lng = 0L;
X
X    for (i = 0; i < image->hdr.rows; i ++) {
X	for (j = 0; j < depth; j++) {
X	    if (comp) {
X		dest = destbuf;
X		wrd = PackRow(&planes[j], &dest, row_size);
X		lng += (long) wrd;
X		fwrite(destbuf, 1, wrd, ofil);
X	    }
X	    else {
X		fwrite(planes[j], 1, row_size, ofil);
X		planes[j] += row_size;
X	    }
X	}
X    }
X    if (comp) {
X	fseek(ofil, (long) pos2, 0);
X	fwrite(&lng, 4, 1, ofil);
X	lng -= BODYsize;
X	lng += FORMsize;
X	fseek(ofil, (long) pos1, 0);
X	fwrite(&lng, 4, 1, ofil);
X    }
X
X    return 1;
X}
X
X/* get the next encoding for a pixel, based on the previous pixel and the
X * current 12 bit RGB value */
X
X#define BPP	    4		/* Bits per pixel */
X#define MAXGRAY	    (1 << BPP)
X#define	ABS(x)	    ((x) < 0 ? -(x) : (x))
X
X/*-
X *	first, check to see if pixel is the same color. if so, return
X *	check if only one of R, G, B have changed. if so, return new pixel.
X *	find closest entry in colormap. if exact match, return it.
X *	modify one of R, G, B (whichever difference is largest)
X *	compare previous calculation to best match in color table. return
X *	    whichever is a better match.
X-*/
Xgetcolor(ppix, crgb, prgb)
Xint             ppix, *crgb, prgb;
X{
X    int             i, j, val, cr, cg, cb, pr, pg, pb, nr, ng, nb, best, dist, nrgb;
X
X    /* if same color, then do a NOOP (same as previous pixel) */
X    if (*crgb == prgb)
X	return (ppix);
X
X    /* set up for comparisons */
X    cb = *crgb & (MAXGRAY - 1);
X    cg = (*crgb >> BPP) & (MAXGRAY - 1);
X    cr = (*crgb >> (BPP * 2)) & (MAXGRAY - 1);
X
X    pb = prgb & (MAXGRAY - 1);
X    pg = (prgb >> BPP) & (MAXGRAY - 1);
X    pr = (prgb >> (BPP * 2)) & (MAXGRAY - 1);
X
X    /* see if only one plane changed, if so, use HAM encoding */
X    if (prgb != -1) {
X	if (pr == cr && pg == cg)
X	    return (cb + 0x10);
X	if (pr == cr && pb == cb)
X	    return (cg + 0x30);
X	if (pg == cg && pb == cb)
X	    return (cr + 0x20);
X    }
X
X    /* else look for an exact match in the color table (or minimal distance) */
X    for (i = 0; i < colors; i++) {
X	if (colorstats[i][0] == *crgb)
X	    return (i);
X	if (i == 0) {
X	    best = 0;
X	    dist = distance(colorstats[i][0], *crgb);
X	}
X	else if ((j = distance(colorstats[i][0], *crgb)) < dist) {
X	    best = i;
X	    dist = j;
X	}
X    }
X
X    /* do a forced absolute */
X    if (prgb == -1) {
X	*crgb = colorstats[best][0];
X	return (best);
X    }
X
X    /* find which color is off the most from previous */
X    i = 0;
X    val = ABS(cr - pr);
X    if (ABS(cg - pg) > val) {
X	i = 1;
X	val = ABS(cg - pg);
X    }
X    if (ABS(cb - pb) > val) {
X	i = 2;
X	val = ABS(cb - pb);
X    }
X
X    nr = pr;
X    ng = pg;
X    nb = pb;
X    switch (i) {
X    case 0:
X	nr = cr;
X	val = nr + 0x20;
X	break;
X    case 1:
X	ng = cg;
X	val = ng + 0x30;
X	break;
X    case 2:
X	nb = cb;
X	val = nb + 0x10;
X	break;
X    }
X    nrgb = (nr << (2 * BPP)) + (ng << BPP) + nb;
X
X    /* now pick the best */
X    if (distance(nrgb, *crgb) < dist) {
X
X	/* do a best relative */
X	*crgb = nrgb;
X	return (val);
X    }
X
X    /* do a best absolute */
X    *crgb = colorstats[best][0];
X    return (best);
X}
X
X/* calculate distance between two colors in 3D space */
Xdistance(argb, brgb)
X{
X    int             b, g, r;
X
X    /* set up for comparisons */
X    b = argb & (MAXGRAY - 1);
X    g = (argb >> BPP) & (MAXGRAY - 1);
X    r = (argb >> (BPP * 2)) & (MAXGRAY - 1);
X
X    b -= brgb & (MAXGRAY - 1);
X    g -= (brgb >> BPP) & (MAXGRAY - 1);
X    r -= (brgb >> (BPP * 2)) & (MAXGRAY - 1);
X
X    return (r * r + g * g + b * b);
X}
END_OF_FILE
if test 14765 -ne `wc -c <'fbham.c'`; then
    echo shar: \"'fbham.c'\" unpacked with wrong size!
fi
# end of 'fbham.c'
fi
if test -f 'flgifr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'flgifr.c'\"
else
echo shar: Extracting \"'flgifr.c'\" \(13672 characters\)
sed "s/^X//" >'flgifr.c' <<'END_OF_FILE'
X/*****************************************************************
X * flgifr.c: FBM Library 0.91 (Beta test) 26-Apr-89  Michael Mauldin
X *
X * Copyright (C) 1989 by Michael Mauldin.  Permission is granted to
X * use this file in whole or in part provided that you do not sell it
X * for profit and that this copyright notice is retained unchanged.
X *
X * Derived from 'giftorle', written by David Koblas
X *
X * +------------------------------------------------------------------+ 
X * | Copyright 1989, David Koblas.                                    | 
X * |   You may copy this file in whole or in part as long as you      | 
X * |   don't try to make money off it, or pretend that you wrote it.  | 
X * +------------------------------------------------------------------+ 
X *
X * flgifr.c:
X *
X * CONTENTS
X *	read_gif (image, stream, mstr, mlen)
X *
X * HISTORY
X * 26-Apr-89  Michael Mauldin (mlm) at Carnegie Mellon University
X *	Beta release (version 0.91) mlm@cs.cmu.edu
X *
X * 19-Feb-89  Michael Mauldin (mlm) at Carnegie Mellon University
X *	Changed name to flgifr from flgif (since there is now an flgifw)
X *
X * 13-Feb-89  Michael Mauldin (mlm) at Carnegie Mellon University
X *	Modified from gif2rle program Copyright 1989 by David Koblas.
X *	Converted to produce FBM image format in memory.
X *
X *
X *****************************************************************/
X
X# include <stdio.h>
X# include "fbm.h"
X
X#define MAXCOLORMAPSIZE         256
X
X#define TRUE    1
X#define FALSE   0
X#define BAD     0
X#define OK      1
X
X#define MAX_LWZ_BITS            12
X
X#define ReadOK(file,buffer,len) (fread(buffer,len,1,file)!=0)
X#define EasyFail(str,status)    while(1){fprintf(stderr,str);return(status);}
X#define HardFail(str,status)    while(1){fprintf(stderr,str);exit  (status);}
X
X#define LM_to_uint(a,b)                 (((b)<<8)|(a))
X
X#ifndef lint
Xstatic char *fbmid =
X	"$FBM flgifr.c <0.91> 26-Apr-89  (C) 1989 by Michael Mauldin$";
X#endif
X
Xread_gif (image, fd, mstr, mlen)
XFBM *image;
XFILE *fd;
Xchar *mstr;
Xint mlen;
X{
X  unsigned char   buf[16];
X  unsigned char   c;
X  int             use_global_colormap;
X  int             bit_pixel;
X  int             count = 0;
X  int             rows, cols, rowlen, depth, colors;
X
X  /* Read magic number 'GIF87a' */
X  buf[0] = NEXTMCH (fd, mstr, mlen) & 0xff;
X  buf[1] = NEXTMCH (fd, mstr, mlen) & 0xff;
X  buf[2] = NEXTMCH (fd, mstr, mlen) & 0xff;
X  buf[3] = NEXTMCH (fd, mstr, mlen) & 0xff;
X  buf[4] = NEXTMCH (fd, mstr, mlen) & 0xff;
X  buf[5] = NEXTMCH (fd, mstr, mlen) & 0xff;
X  buf[6] = 0;
X
X  if (strcmp (buf, GIF_MAGIC) != 0)
X    EasyFail("bad magic number (version mismatch?)\n", BAD);
X
X  if (!ReadOK (fd, buf, 7))
X    EasyFail("error reading screen descriptor\n", BAD);
X
X  /* Read image data */
X  image->hdr.cols = cols = LM_to_uint(buf[0], buf[1]);
X  image->hdr.rows = rows = LM_to_uint(buf[2], buf[3]);
X  image->hdr.planes = 1;
X  image->hdr.bits = depth = (buf[4] & 0x07) + 1;
X  image->hdr.physbits = 8;
X
X  /* Pad to even byte */
X  if (depth == 1)
X  { image->hdr.rowlen = rowlen = 16 * ((cols + 15) / 16); }
X  else
X  { image->hdr.rowlen = rowlen = 2 * ((cols + 1) / 2); }
X
X  image->hdr.plnlen = rowlen * rows;
X  colors = 1 << depth;
X  image->hdr.clrlen = 3 * colors;
X  image->hdr.title[0] = '\0';
X  image->hdr.credits[0] = '\0';
X  
X  /* Try to guess aspect ratio */
X  if (cols == 320 && rows == 200)	{ image->hdr.aspect = 1.2; }
X  else if (cols == 320 && rows == 175)	{ image->hdr.aspect = 1.2; }
X  else if (cols == 320 && rows == 400)	{ image->hdr.aspect = 0.6; }
X  else if (cols == 320 && rows == 350)	{ image->hdr.aspect = 0.6; }
X  else if (cols == 640 && rows == 200)	{ image->hdr.aspect = 2.4; }
X  else if (cols == 640 && rows == 175)	{ image->hdr.aspect = 2.4; }
X  else if (cols == 640 && rows == 400)	{ image->hdr.aspect = 1.2; }
X  else if (cols == 640 && rows == 350)	{ image->hdr.aspect = 1.2; }
X  else					{ image->hdr.aspect = 1.0; }
X  
X# ifdef DEBUG
X  fprintf (stderr, "\nImage file header:\n\n");
X  fprintf (stderr, "cols       %d\n", image->hdr.cols);
X  fprintf (stderr, "rows       %d\n", image->hdr.rows);
X  fprintf (stderr, "planes     %d\n", image->hdr.planes);
X  fprintf (stderr, "bits       %d\n", image->hdr.bits);
X  fprintf (stderr, "physbits   %d\n", image->hdr.physbits);
X  fprintf (stderr, "rowlen     %d\n", image->hdr.rowlen);
X  fprintf (stderr, "plnlen     %d\n", image->hdr.plnlen);
X  fprintf (stderr, "clrlen     %d\n", image->hdr.clrlen);
X  fprintf (stderr, "aspect     %1.3lf\n", image->hdr.aspect);
X  fprintf (stderr, "title      '%s'\n", image->hdr.title);
X  fprintf (stderr, "credits    '%s'\n", image->hdr.credits);
X# endif
X  
X  /* Allocate image */
X  alloc_fbm (image);
X
X  /* Read colormap if given */
X  if ((buf[4] & 0x80) == 0x80)
X  { if (ReadColorMap (fd, colors, image->cm) == BAD)
X      return (BAD);
X  }
X
X  while (1)
X  { if (!ReadOK (fd, &c, 1))
X      EasyFail("No image data -- EOF\n", BAD);
X
X    if (c == ';')
X      return OK;
X
X    if (c == '!')
X    { if (!ReadOK (fd, &c, 1))
X        EasyFail("No extention function code -- EOF\n", BAD);
X      if (IgnoreExtention(fd) == BAD)
X        return (BAD);
X    }
X
X    if (c != ',')
X    { fprintf(stderr, "Bogus character ignoring '%c'\n", c);
X      continue;
X    }
X
X    if (count == 1)
X      HardFail("This file contains more than one image! FAILING\n", 1);
X    count++;
X
X    if (!ReadOK (fd, buf, 9))
X      EasyFail("Couldn't read left/top/width/height\n", TRUE);
X
X# ifdef DEBUG
X    fprintf (stderr, "Image description: ");
X    for (i=0; i<9; i++) fprintf (stderr, "%02x", buf[i]);
X    fprintf (stderr, "\n");
X# endif
X
X    if ((buf[8] & 0x80) == 0x80)
X      use_global_colormap = FALSE;
X    else
X      use_global_colormap = TRUE;
X
X    bit_pixel = 2 << (buf[8] & 0x07);
X    
X    if (!use_global_colormap && bit_pixel > colors)
X    { HardFail ("Local colormap has more colors than global!\n", BAD); }
X
X    if (!use_global_colormap)
X    { fprintf (stderr,
X               "Overriding global colormap (%d) with local (%d)\n",
X               colors, bit_pixel);
X
X      colors = bit_pixel;
X      image->hdr.clrlen = 3 * colors;
X      
X      if (ReadColorMap(fd, colors, image->cm) == BAD)
X        return BAD;
X    }
X
X    fprintf (stderr, "Reading GIF image [%dx%d], %d bits",
X	     image->hdr.cols, image->hdr.rows, image->hdr.bits);
X    if (image->hdr.clrlen > 0)
X    { fprintf (stderr, ", %d colors", image->hdr.clrlen / 3); }
X    else if (image->hdr.bits > 1)
X    { fprintf (stderr, ", grayscale"); }
X
X    if ((buf[8] & 0x40) == 0x40)
X    { fprintf (stderr, ", interlaced"); }
X    fprintf (stderr, "\n");
X
X
X    if ((buf[8] & 0x40) == 0x40)
X    { 
X      if (ReadInterlaced(fd,
X			 LM_to_uint(buf[4],buf[5]),
X			 LM_to_uint(buf[6],buf[7]),
X			 image->bm,
X			 rowlen) == BAD)
X	return BAD;
X    }
X    else
X    { if (ReadRaster(fd,
X                     LM_to_uint(buf[4], buf[5]),
X                     LM_to_uint(buf[6], buf[7]),
X                     image->bm,
X                     rowlen) == BAD)
X        return BAD;
X      else
X        return OK;
X    }
X  }
X}
X
XReadColorMap (fd, number, buffer)
X  FILE           *fd;
X  int             number;
X  unsigned char   *buffer;
X{
X  int             i;
X  unsigned char   rgb[3], *red, *grn, *blu;
X
X  red = buffer;
X  grn = buffer + number;
X  blu = grn + number;
X
X  for (i = 0; i < number; i++)
X  { if (!ReadOK (fd, rgb, sizeof(rgb)))
X      EasyFail("Bogus colormap\n", BAD);
X
X    red[i] = rgb[0];
X    grn[i] = rgb[1];
X    blu[i] = rgb[2];
X  }
X
X  return OK;
X}
X
XIgnoreExtention(fd)
X  FILE           *fd;
X{
X  static char     buf[256];
X  unsigned char   c;
X
X  while (1)
X  {
X    if (!ReadOK (fd, &c, 1))
X      EasyFail("EOF in extention\n", BAD);
X
X    if (c == 0)
X      return OK;
X
X    if (read(fd, buf, (int) c) != (int) c)
X      EasyFail("EOF in extention\n", BAD);
X  }
X}
X
XGetCode(fd, code_size, flag)
X  FILE           *fd;
X  int             code_size;
X  int             flag;
X{
X  static unsigned char buf[280];
X  static int      curbit, lastbit, done, last_byte;
X  int             i, j, ret;
X  unsigned char   count;
X
X  if (flag)
X  {
X    curbit = 0;
X    lastbit = 0;
X    done = FALSE;
X    return 0;
X  }
X
X  if ((curbit + code_size) >= lastbit)
X  { if (done)
X    { if (curbit >= lastbit)
X        EasyFail("Ran off the end of my bits\n", -1);
X    }
X    buf[0] = buf[last_byte - 2];
X    buf[1] = buf[last_byte - 1];
X
X    if (!ReadOK (fd, &count, 1))
X    { EasyFail("Error in getting buffer size\n", -1); }
X
X    if (count == 0)
X    { done = TRUE; } 
X
X    else if (!ReadOK (fd, &buf[2], count))
X      EasyFail("Error in getting buffer\n", -1);
X
X    last_byte = 2 + count;
X    curbit = (curbit - lastbit) + 16;
X    lastbit = (2 + count) * 8;
X  }
X
X  ret = 0;
X
X  for (i = curbit, j = 0; j < code_size; i++, j++)
X    ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
X
X  curbit += code_size;
X
X  return ret;
X}
X
XLWZReadByte(fd, flag, input_code_size)
X  FILE           *fd;
X  int             flag;
X  int             input_code_size;
X{
X  static int      fresh = FALSE;
X  int             code, incode;
X  static int      code_size, set_code_size;
X  static int      max_code, max_code_size;
X  static int      firstcode, oldcode;
X  static int      clear_code, end_code;
X  static int      table[2][(1 << MAX_LWZ_BITS)];
X  static int      stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
X  register int    i;
X
X  if (flag)
X  {
X    set_code_size = input_code_size;
X    code_size = set_code_size + 1;
X    clear_code = 1 << set_code_size;
X    end_code = clear_code + 1;
X    max_code_size = 2 * clear_code;
X    max_code = clear_code + 2;
X
X    GetCode(fd, NULL, NULL);
X
X    fresh = TRUE;
X
X    for (i = 0; i < clear_code; i++)
X    {
X      table[0][i] = 0;
X      table[1][i] = i;
X    }
X
X    for (; i < (1 << MAX_LWZ_BITS); i++)
X      table[0][i] = table[1][0] = 0;
X
X    sp = stack;
X    return 0;
X  }
X  else if (fresh)
X  { fresh = FALSE;
X    do
X    { firstcode = oldcode =
X        GetCode(fd, code_size, FALSE);
X    } while (firstcode == clear_code);
X
X    return firstcode;
X  }
X
X  if (sp > stack)
X    return *--sp;
X
X  while ((code = GetCode(fd, code_size, FALSE)) >= 0)
X  { if (code == clear_code)
X    { for (i = 0; i < clear_code; i++)
X      {table[0][i] = 0;
X        table[1][i] = i;
X      }
X
X      for (; i < (1 << MAX_LWZ_BITS); i++)
X        table[0][i] = table[1][i] = 0;
X
X      code_size = set_code_size + 1;
X      max_code_size = 2 * clear_code;
X      max_code = clear_code + 2;
X      sp = stack;
X      firstcode = oldcode =
X        GetCode(fd, code_size, FALSE);
X      return firstcode;
X    }
X    else if (code == end_code)
X    { unsigned char   count;
X      unsigned char   junk;
X
X      while (ReadOK (fd, &count, 1) && (count != 0))
X        while (count-- != 0 && ReadOK (fd, &junk, 1));
X
X      if (count != 0)
X        EasyFail("missing EOD in data stream (common occurance)\n", -3);
X
X      return -2;
X    }
X
X    incode = code;
X
X    if (code >= max_code)
X    { *sp++ = firstcode;
X      code = oldcode;
X    }
X
X    while (code >= clear_code)
X    {
X      *sp++ = table[1][code];
X      if (code == table[0][code])
X        EasyFail("Circular table entry BIG ERROR\n", -1);
X      code = table[0][code];
X    }
X
X    *sp++ = firstcode = table[1][code];
X
X    if ((code = max_code) < (1 << MAX_LWZ_BITS))
X    {
X      table[0][code] = oldcode;
X      table[1][code] = firstcode;
X      max_code++;
X
X      if ((max_code >= max_code_size) &&
X          (max_code_size < (1 << MAX_LWZ_BITS)))
X      {
X        max_code_size *= 2;
X        code_size++;
X      }
X    }
X    oldcode = incode;
X
X    if (sp > stack)
X      return *--sp;
X  }
X
X  return code;
X}
X
XReadInterlaced(fd, len, height, buffer, rowlen)
X  FILE           *fd;
X  int             len, height;
X  unsigned char	 *buffer;
X  int		  rowlen;
X{
X  unsigned char   c;
X  register unsigned char *bmp;
X  register int    v;
X  register int    xpos = 0;
X  register int    ypos = 0, pass = 0;
X  register int    maxypos = 0;
X
X
X  if (!ReadOK(fd, &c, 1))
X    EasyFail("Bogus image data -- EOF\n", BAD);
X  if (LWZReadByte(fd, TRUE, c) < 0)
X    return BAD;
X
X  while ((v = LWZReadByte(fd, FALSE, c)) >= 0)
X  {
X    if (xpos == 0)
X    { bmp = &(buffer[ypos * rowlen]);
X      if (ypos > height)
X      { fprintf (stderr, "Wanring Too much data, started to read line %d\n",
X		 ypos);
X        return (OK);
X      }
X    }
X    
X    *bmp++ = v;
X
X    if (++xpos == len)
X    {
X      xpos = 0;
X      switch (pass)
X      {
X       case 0: case 1:		ypos += 8; break;
X       case 2:			ypos += 4; break;
X       case 3:			ypos += 2; break;
X      }
X      
X      if (ypos > maxypos)	maxypos = ypos;
X
X      if (ypos >= height)
X      {
X	switch (++pass)
X	{
X	 case 1:		ypos = 4; break;
X	 case 2:		ypos = 2; break;
X	 case 3:		ypos = 1; break;
X	}
X      }
X    }
X  }
X
X  if (maxypos >= height) return OK;
X
X  if (v == (-2))
X    return OK;
X  return BAD;
X}
X
XReadRaster (fd, len, height, buffer, rowlen)
X  FILE           *fd;
X  int             len, height;
X  unsigned char  *buffer;
X  int             rowlen;
X{
X  unsigned char   c;
X  register unsigned char  *bmp;
X  register int    v;
X  register int    xpos = 0;
X  register int    ypos = 0;
X
X  if (!ReadOK (fd, &c, 1))
X    EasyFail("Bogus image data -- EOF\n", TRUE);
X
X  if (LWZReadByte(fd, TRUE, c) < 0)
X    return BAD;
X
X  /* Read the raster data and dump it into the FBM bitmap */
X  while ((v = LWZReadByte(fd, FALSE, c)) >= 0)
X  {
X    if (xpos == 0)
X    { bmp = &(buffer[ypos++ * rowlen]);
X      if (ypos > height)
X      { fprintf (stderr, "Warning: too much data, started to read line %d\n",
X		 ypos);
X        return (OK);
X      }
X    }
X    
X    *bmp++ = v;
X    
X    if (++xpos == len)
X
X    if (xpos == len) xpos = 0;
X  }
X
X  fprintf (stderr, "Done storing bitmap, xpos %d, ypos %d [%dx%d]\n",
X           xpos, ypos, len, height);
X
X  if (ypos >= height) return OK;
X
X  if (v == (-2))
X    return OK;
X  return BAD;
X}
END_OF_FILE
if test 13672 -ne `wc -c <'flgifr.c'`; then
    echo shar: \"'flgifr.c'\" unpacked with wrong size!
fi
# end of 'flgifr.c'
fi
if test -f 'fliff.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fliff.c'\"
else
echo shar: Extracting \"'fliff.c'\" \(23454 characters\)
sed "s/^X//" >'fliff.c' <<'END_OF_FILE'
X/*****************************************************************
X * fliff.c: FBM Library 0.9 (Beta test) 07-Mar-89  Michael Mauldin
X *
X * Copyright (C) 1989 by Michael Mauldin.  Permission is granted to
X * use this file in whole or in part provided that you do not sell it
X * for profit and that this copyright notice is retained unchanged.
X *
X * fliff.c: 
X *
X * CONTENTS
X *	write_iff (image, stream)
X *	read_iff (image, stream, mstr, mlen)
X *
X * EDITLOG
X *	LastEditDate = Mon Mar 20 18:54:08 1989 - Michael Mauldin
X *	LastFileName = /usr2/mlm/src/misc/fbm/fliff.c
X *
X * HISTORY
X * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
X *	Beta release (version 0.9) mlm@cs.cmu.edu
X *
X * 04-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
X *	Read and Write support for Amiga IFF (except HAM mode)
X *****************************************************************/
X
X# include <stdio.h>
X# include <math.h>
X# include <ctype.h>
X# include "fbm.h"
X
X#ifndef lint
Xstatic char *fbmid =
X	"$FBM fliff.c <0.9> 07-Mar-89  (C) 1989 by Michael Mauldin$";
X#endif
X
X/****************************************************************
X * from iff.h
X ****************************************************************/
X
X# define BOOL	int		/*  1 bit value			*/
X# define SBYTE	char		/*  8 bits signend		*/
X# define UBYTE	unsigned char	/*  8 bits unsigned		*/
X# define WORD	short		/* 16 bits signed		*/
X# define UWORD	unsigned short	/* 16 bits unsigned		*/
X# define LONG	long		/* 32 bits signed		*/
X# define ID	long
X# define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
X# define FORM MakeID('F','O','R','M')
X# define PROP MakeID('P','R','O','P')
X# define LIST MakeID('L','I','S','T')
X# define CAT  MakeID('C','A','T',' ')
X# define FILLER MakeID(' ',' ',' ',' ')
X# define NULL_CHUNK 0L	       /* No current chunk.*/
X# define TRUE	1
X# define FALSE	0
X
X
X/* ---------- Chunk ----------------------------------------------------*/
X
X/* All chunks start with a type ID and a count of the data bytes that 
X   follow--the chunk's "logical size" or "data size". If that number is odd,
X   a 0 pad byte is written, too. */
X
Xtypedef struct {
X    ID	  ckID;
X    LONG  ckSize;
X    } ChunkHeader;
X
Xtypedef struct {
X    ID	  ckID;
X    LONG  ckSize;
X    UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
X    } Chunk;
X
X/*----------------------------------------------------------------------*
X * ILBM.H  Definitions for InterLeaved BitMap raster image.     1/23/86
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X
X# define ID_ILBM MakeID('I','L','B','M')
X# define ID_BMHD MakeID('B','M','H','D')
X# define ID_CMAP MakeID('C','M','A','P')
X# define ID_GRAB MakeID('G','R','A','B')
X# define ID_DEST MakeID('D','E','S','T')
X# define ID_SPRT MakeID('S','P','R','T')
X# define ID_CAMG MakeID('C','A','M','G')
X# define ID_BODY MakeID('B','O','D','Y')
X
X/* ---------- BitMapHeader ---------------------------------------------*/
X
Xtypedef UBYTE Masking;		/* Choice of masking technique.*/
X# define mskNone                 0
X# define mskHasMask              1
X# define mskHasTransparentColor  2
X# define mskLasso                3
X
Xtypedef UBYTE Compression;	/* Choice of compression algorithm applied to
X     * each row of the source and mask planes. "cmpByteRun1" is the byte run
X     * encoding generated by Mac's PackBits. See Packer.h . */
X# define cmpNone      0
X# define cmpByteRun1  1
X
X/* Aspect ratios: The proper fraction xAspect/yAspect represents the pixel
X * aspect ratio pixel_width/pixel_height.
X *
X * For the 4 Amiga display modes:
X *   320 x 200: 10/11  (these pixels are taller than they are wide)
X *   320 x 400: 20/11
X *   640 x 200:  5/11
X *   640 x 400: 10/11		*/
X# define x320x200Aspect 10
X# define y320x200Aspect 11
X# define x320x400Aspect 20
X# define y320x400Aspect 11
X# define x640x200Aspect  5
X# define y640x200Aspect 11
X# define x640x400Aspect 10
X# define y640x400Aspect 11
X
X/* A BitMapHeader is stored in a BMHD chunk. */
Xtypedef struct {
X    UWORD w, h;			/* raster width & height in pixels */
X    WORD  x, y;			/* position for this image */
X    UBYTE nPlanes;		/* # source bitplanes */
X    Masking masking;		/* masking technique */
X    Compression compression;	/* compression algorithm */
X    UBYTE pad1;			/* UNUSED.  For consistency, put 0 here.*/
X    UWORD transparentColor;	/* transparent "color number" */
X    UBYTE xAspect, yAspect;	/* aspect ratio, a rational number x/y */
X    WORD  pageWidth, pageHeight;  /* source "page" size in pixels */
X    } BitMapHeader;
X
X/* RowBytes computes the number of bytes in a row, from the width in pixels.*/
X# define RowBytes(w)   (2 * (((w) + 15) / 16))
X
X
X/* ---------- ColorRegister --------------------------------------------*/
X/* A CMAP chunk is a packed array of ColorRegisters (3 bytes each). */
Xtypedef struct {
X    UBYTE red, green, blue;   /* MUST be UBYTEs so ">> 4" won't sign extend.*/
X    } ColorRegister;
X
X/* Use this constant instead of sizeof(ColorRegister). */
X# define sizeofColorRegister  3
X
Xtypedef WORD Color4;	/* Amiga RAM version of a color-register,
X			 * with 4 bits each RGB in low 12 bits.*/
X
X# define swapword(X)	((((X) & 0xff) << 8) | (((X) & 0xff00) >> 8))
X# define swaplong(X)	(((unsigned) ((X) & 0xff000000) >> 24) |	\
X			 ((unsigned) ((X) & 0x00ff0000) >> 8) |	\
X			 ((unsigned) ((X) & 0x0000ff00) << 8) |	\
X			 ((unsigned) ((X) & 0x000000ff) << 24))
X
X# define swapsize(X) ((machine_byte_order () == LITTLE) ? swaplong(X) : (X))
X
X/* Maximum number of bitplanes in RAM. Current Amiga max w/dual playfield. */
X# define MaxAmDepth 6
X
X/* Chunks must be padded to align to even boundaries */
X# define EVENALIGN(X) (((X) + 1) & ~1)
X
X/* ---------- Point2D --------------------------------------------------*/
X/* A Point2D is stored in a GRAB chunk. */
Xtypedef struct {
X    WORD x, y;		/* coordinates (pixels) */
X    } Point2D;
X
X/* ---------- DestMerge ------------------------------------------------*/
X/* A DestMerge is stored in a DEST chunk. */
Xtypedef struct {
X    UBYTE depth;	/* # bitplanes in the original source */
X    UBYTE pad1;		/* UNUSED; for consistency store 0 here */
X    UWORD planePick;	/* how to scatter source bitplanes into destination */
X    UWORD planeOnOff;	/* default bitplane data for planePick */
X    UWORD planeMask;	/* selects which bitplanes to store into */
X    } DestMerge;
X
X/* ---------- SpritePrecedence -----------------------------------------*/
X/* A SpritePrecedence is stored in a SPRT chunk. */
Xtypedef UWORD SpritePrecedence;
X
X/* ---------- Viewport Mode --------------------------------------------*/
X/* A Commodore Amiga ViewPort->Modes is stored in a CAMG chunk. */
X/* The chunk's content is declared as a LONG. */
X
X/* ---------- CRange ---------------------------------------------------*/
X/* A CRange is store in a CRNG chunk. */
Xtypedef struct {
X    WORD  pad1;		/* reserved for future use; store 0 here */
X    WORD  rate;		/* color cycling rate, 16384 = 60 steps/second */
X    WORD  active;	/* nonzero means color cycling is turned on */
X    UBYTE low, high;	/* lower and upper color registers selected */
X    } CRange;
X
X/*----------------------------------------------------------------------*
X * PACKER.H  typedefs for Data-Compresser.  		        1/22/86
X *
X * This module implements the run compression algorithm "cmpByteRun1"; the
X * same encoding generated by Mac's PackBits.
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X
X/* This macro computes the worst case packed size of a "row" of bytes. */
X# define MaxPackedSize(rowSize)  ( (rowSize) + ( ((rowSize)+127) >> 7 ) )
X
X/*----------------------------------------------------------------------*
X * unpacker.c Convert data from "cmpByteRun1" run compression. 11/15/85
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X *	control bytes:
X *	 [0..127]   : followed by n+1 bytes of data.
X *	 [-1..-127] : followed by byte to be repeated (-n)+1 times.
X *	 -128       : NOOP.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X
X/*----------- UnPackRow ------------------------------------------------*/
X
X# define UGetByte()	(*source++)
X# define UPutByte(c)	(*dest++ = (c))
X
X/* Given POINTERS to POINTER variables, unpacks one row, updating the source
X * and destination pointers until it produces dstBytes bytes. */
Xstatic UnPackRow(pSource, pDest, srcBytes0, dstBytes0)
X	char **pSource, **pDest;  int srcBytes0, dstBytes0; {
X    register char *source = *pSource;
X    register char *dest   = *pDest;
X    register int n;
X    register char c;
X    register int srcBytes = srcBytes0, dstBytes = dstBytes0;
X    BOOL error = TRUE;	/* assume error until we make it through the loop */
X
X
X# ifdef DEBUG
X    fprintf (stderr, "Unpack called, src %d, dst %d\n",
X             srcBytes0, dstBytes0);
X# endif
X
X    while( dstBytes > 0 )  {
X	if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
X    	n = UGetByte() & 0x0ff;
X
X    	if (n < 128) {
X# ifdef DEBUG
X            fprintf (stderr, "Got %02x, copying %d bytes...\n", n, n+1);
X# endif
X
X	    n += 1;
X	    
X	    if ( (srcBytes -= n) < 0 )  goto ErrorExit;
X	    if ( (dstBytes -= n) < 0 )  goto ErrorExit;
X	    do {  UPutByte(UGetByte());  } while (--n > 0);
X	    }
X
X    	else if (n != 128) {
X# ifdef DEBUG
X            fprintf (stderr, "Got %02x, repeating byte %d times...\n",
X			n, 257-n);
X# endif
X
X	    n = 257 - n;
X	    
X	    if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
X	    if ( (dstBytes -= n) < 0 )  goto ErrorExit;
X	    c = UGetByte();
X	    do {  UPutByte(c);  } while (--n > 0);
X	    }
X	}
X    error = FALSE;	/* success! */
X
X  ErrorExit:
X    *pSource = source;  *pDest = dest;
X    
X    if (error)
X    { fprintf (stderr, "error in unpack, src %d, dst %d\n", 
X	       srcBytes, dstBytes);
X    }
X    
X    return(error);
X    }
X
X/****************************************************************
X * read_iff: Read an Amiga format IFF Interleaved Bitmap
X ****************************************************************/
X
Xread_iff (image, rfile, mstr, mlen)
XFBM *image;
XFILE *rfile;
Xchar *mstr;
Xint mlen;
X{ char magic[8];
X  long formsize, buflen;
X  Chunk *form;
X  int result;
X
X  /* First word is magic number */
X  magic[0] = NEXTMCH(rfile,mstr,mlen) & 0xff;
X  magic[1] = NEXTMCH(rfile,mstr,mlen) & 0xff;
X  magic[2] = NEXTMCH(rfile,mstr,mlen) & 0xff;
X  magic[3] = NEXTMCH(rfile,mstr,mlen) & 0xff;
X  magic[4] = '\0';
X
X  /* If magic number is not FORM, lose */
X  if (strcmp (magic, "FORM") != 0)
X  { if (strncmp (magic, "FOR", 3) == 0 ||
X	strncmp (magic, "LIS", 3) == 0 ||
X	strncmp (magic, "CAT", 3) == 0)
X    { fprintf (stderr, "Sorry, I only handle FORM type IFF files\n");
X      return (0);
X    }
X    
X    fprintf (stderr,
X	     "read_iff: error, file not a FORM type IFF file, magic '%s'\n",
X	      magic);
X    return (0);
X  }
X
X  /* Second longword is length of data chunk */
X  formsize = get_long (rfile, BIG);  
X  
X  form = (Chunk *) malloc (formsize + 8);
X  form->ckID = FORM;
X  form->ckSize = formsize;
X
X  /* Now read the rest of the chunk */
X  if ((buflen = fread (form->ckData, 1, formsize, stdin)) < formsize)
X  { if (buflen < 0)
X    { perror ("stdin"); }
X    else
X    { fprintf (stderr, "error: premature EOF in FORM after %d of %d bytes\n",
X	       buflen, formsize);
X    }
X
X    exit (1);
X  }
X
X  /* Recursively parse the FORM */  
X  result = parse_form (image, form);
X
X  /* Now we've read the image (or not) */  
X  free (form);
X
X  return (result);
X}
X
X/****************************************************************
X * parse_form: Parse an IFF form chunk
X *
X *	FORM       ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* }
X *	FormType   ::= ID
X *	LocalChunk ::= Property | Chunk
X ****************************************************************/
X
Xparse_form (image, chunk)
XFBM *image;
XChunk *chunk;
X{ register UBYTE *data, *tail;
X  register int clrlen, colors;
X  register BitMapHeader *bmh;
X  register int i, bits;
X  long formtype;
X  int found_bmhd=0, found_cmap=0, found_body=0;
X  Chunk *part;
X
X  data = chunk->ckData;
X  tail = data + chunk->ckSize;  
X  
X  formtype = MakeID(data[0], data[1], data[2], data[3]);
X  data += 4;
X  
X  if (formtype != ID_ILBM)
X  { fprintf (stderr, "this FORM doesn't start with ILBM, but %4.4s, sorry.\n",
X	     &formtype);
X    return (0);
X  }
X  
X  while (data < tail)
X  { part = (Chunk *) data;
X    part->ckID   = swapsize (part->ckID);
X    part->ckSize = swapsize (part->ckSize);
X    data += ( EVENALIGN (part->ckSize) + 8 );
X    
X# ifdef DEBUG
X    fprintf (stderr, "Found %c%c%c%c, size %ld\n",
X		(part->ckID & 0xff000000) >> 24,
X		(part->ckID & 0x00ff0000) >> 16,
X		(part->ckID & 0x0000ff00) >>  8,
X		(part->ckID & 0x000000ff),
X		part->ckSize);
X# endif
X
X    if (part->ckID == ID_BMHD)
X    { found_bmhd++;
X      bmh = (BitMapHeader *) part->ckData;
X      
X      /* IFF uses BIG byte order, swap if necessary */
X      if (machine_byte_order () == LITTLE)
X      { bmh->w = swapword (bmh->w);
X        bmh->h = swapword (bmh->h);
X	bmh->x = swapword (bmh->x);
X	bmh->y = swapword (bmh->y);
X	bmh->transparentColor = swapword (bmh->transparentColor);
X	bmh->pageWidth = swapword (bmh->pageWidth);
X	bmh->pageHeight = swapword (bmh->pageHeight);
X      }
X      
X      image->hdr.rows = bmh->h;
X      image->hdr.cols = bmh->w;
X      image->hdr.planes = 1;
X      image->hdr.bits = bmh->nPlanes;
X      image->hdr.physbits = 8;
X      image->hdr.rowlen = 16 * ((image->hdr.cols + 15) / 16);
X      image->hdr.plnlen = image->hdr.rowlen * image->hdr.rows;
X      image->hdr.clrlen = 0;
X      image->hdr.aspect = (double) bmh->yAspect / bmh->xAspect;
X      image->hdr.title[0] = '\0';
X      image->hdr.credits[0] = '\0';
X    }
X    else if (part->ckID == ID_CMAP)
X    { image->hdr.clrlen = part->ckSize;
X
X      alloc_fbm (image);
X
X      clrlen = image->hdr.clrlen;
X      colors = clrlen / 3;
X
X      for (i=0; i<image->hdr.clrlen; i++)
X      { image->cm[(colors * (i%3)) + i/3] = part->ckData[i]; }
X
X      /* Compute number of bits in colormap */
X      for (i=colors, bits=1; i > 2; i /= 2, bits++) ;
X      
X      if (bits < image->hdr.bits) image->hdr.bits = bits;
X
X      found_cmap++;
X    }
X    else if (part->ckID == ID_BODY)
X    { if (!found_bmhd)
X      { fprintf (stderr, "Error, BODY found with no BMHD header\n");
X        return (0);
X      }
X      
X      if (found_cmap == 0)
X      { alloc_fbm (image); }
X      
X      found_body++;
X      
X      /* Decode body */
X      fprintf (stderr, "Reading IFF [%dx%dx%d], %d physbits, %1.3lf aspect",
X		image->hdr.cols, image->hdr.rows,
X		image->hdr.bits, image->hdr.physbits,
X		image->hdr.aspect);
X      if (image->hdr.planes > 1)
X      { fprintf (stderr, ", %d planes", image->hdr.planes); }
X      if (image->hdr.clrlen > 1)
X      { fprintf (stderr, ", %d colors", image->hdr.clrlen / 3); }
X      if (bmh->compression)
X      { fprintf (stderr, ", compressed"); }
X      if (bmh->masking == mskHasMask)
X      { fprintf (stderr, ", with mask"); }
X      fprintf (stderr, "\n");
X
X# ifdef DEBUG
X      fprintf (stderr,
X	       "masking %d, compression %d, transparent %d, page [%dx%d]\n",
X	       bmh->masking, bmh->compression, bmh->transparentColor,
X	       bmh->pageWidth, bmh->pageHeight);
X
X	for (i=0; i<colors; i++)
X	{ fprintf (stderr, "    color %3d:  <%3d, %3d, %3d>\n", i,
X		   image->cm[i], image->cm[i+colors], image->cm[i+colors*2]);
X	}
X# endif
X      
X      return (read_iff_body (image, bmh, part));
X    }
X  }
X  
X  return (0);
X}
X
X/****************************************************************
X * read_iff_body: Read the bits in the ILBM body into the FBM image
X ****************************************************************/
X
Xread_iff_body (image, bmh, body)
XFBM *image;
XBitMapHeader *bmh;
XChunk *body;
X{ register int r, c, k, pmask, byte, bit;
X  unsigned char *row, *bp, *buf, *obm, *tail;
X  int bytlen = image->hdr.cols / 8;
X  int planes =  bmh->nPlanes + ((bmh->masking == mskHasMask) ? 1 : 0);
X  
X  buf = (unsigned char *) malloc (bytlen);
X  
X  bp = body->ckData;
X  tail = bp + body->ckSize;
X
X# ifdef DEBUG
X  fprintf (stderr, "Body length %d, planes %d: ", tail-bp, planes);
X  for (c=0; c<20; c++) fprintf (stderr, "%02x", bp[c]);
X  fprintf (stderr, "\n");
X# endif
X
X  /* Each iteration reads one scan line */
X  for (r=0; r<image->hdr.rows; r++)
X  {
X    if (bp > tail)
X    { fprintf (stderr, "Ran out of data in body after %d of %d rows\n",
X		r, image->hdr.rows);
X      return (0);
X    }
X
X    obm = &(image->bm[r * image->hdr.rowlen]);
X
X    /* Clear the output row of pixels */
X    for (c=0; c<image->hdr.cols; c++)
X    { obm[c] = 0; }
X
X    /* Each loop reads one plane of this scan line */    
X    for (k=0; k<planes; k++)
X    {
X      /* First get pointer to data packed 8 bits per byte */
X      if (bmh->compression == 0)
X      { row = bp; bp += RowBytes (bmh->w); }
X      else
X      { row = buf;
X        if (UnPackRow (&bp, &row, (int) (tail-bp), RowBytes (bmh->w)) != 0)
X        { fprintf (stderr,
X		   "%s, row %d of %d, plane %d of %d, bytes per row %d\n",
X		   "Error in UnPackRow",
X		   r, image->hdr.rows, k, planes, RowBytes (bmh->w));
X	  return (0);
X	}
X	row = buf;
X      }
X
X      /* Ignore extra planes (including the mask if any) */
X      if (k >= image->hdr.bits)
X        continue;
X
X      /* Now OR in these bits into the output pixels */
X      pmask = 1 << k;
X
X      for (c=0; c<image->hdr.cols; c++)
X      { byte = c >> 3;
X        bit = 7 - (c & 7);
X	bit = row[byte] & (1 << bit);
X
X	obm[c] |= bit ? pmask : 0;
X      }
X    }
X  }
X
X  if (tail-bp > 1)
X  { fprintf (stderr, "Warning, %d bytes of data unread\n", tail - bp); }
X  
X  return (1);
X}
X
X/****************************************************************
X * write_iff: Write AMIGA IFF format ILBM file
X *
X * Writes		FORM type ILBM
X *			    BMHD
X *			    CMAP (optional)
X *			    BODY (uncompressed)
X *
X ****************************************************************/
X
Xwrite_iff (image, wfile)
XFBM *image;
XFILE *wfile;
X{ BitMapHeader bmhd;
X  unsigned char *cmap, *body;
X  int bodylen, cmaplen, bmhdlen, formlen, ilbmbits;
X
X  if (image->hdr.planes > 1)
X  { fprintf (stderr, "Error, write_iff cannot handle multi-plane images\n");
X    return (0);
X  }
X
X  /* Determine number of bits in output */
X  if (image->hdr.clrlen == 0)
X  { ilbmbits = image->hdr.bits; }
X  else
X  { int colors = image->hdr.clrlen/3;
X    for (ilbmbits=1; colors > 2; ilbmbits++, colors >>= 1) ;
X  }
X  
X  fprintf (stderr, "Writing \"%s\" [%dx%d] as a %d bit IFF ILBM file\n",
X	   image->hdr.title[0] ? image->hdr.title : "",
X	   image->hdr.cols, image->hdr.rows, ilbmbits);
X
X  if (ilbmbits > 5)
X  { fprintf (stderr, "%s\n%s\n%s\n",
X	"Warning: most IFF ILBM displays cannot handle more than",
X	"	 32 colors. You should probably run the image though",
X	"	 'gray2clr -u | fbquant -c32' first.");
X  }
X
X  /* Build BMHD, CMAP, and body chunks */
X  bmhdlen = build_bmhd (image, &bmhd, ilbmbits) ;
X  cmaplen = build_cmap (image, &cmap, ilbmbits);
X  bodylen = build_body (image, &body, ilbmbits);
X  
X  /* Length of FORM is length of subparts plus 8 for header + 4 for type */
X  formlen = bmhdlen + cmaplen + bodylen + 12;
X
X  /*--------Write out FORM chunk header--------*/
X  fprintf (wfile, "FORM");
X  put_long (formlen-8, wfile, BIG);
X  fprintf (wfile, "ILBM");
X
X  /*----Write out BMHD chunk----*/
X  fprintf (wfile, "BMHD");
X  put_long (bmhdlen-8, wfile, BIG);
X  fwrite (&bmhd, bmhdlen-8, 1, wfile);
X
X  /* No need to pad BMHD chunk, it must be even */
X      
X  /*----Write out CMAP chunk----*/
X  if (cmaplen > 0)
X  { fprintf (wfile, "CMAP");
X    put_long (cmaplen-8, wfile, BIG);
X    fwrite (cmap, cmaplen-8, 1, wfile);
X  
X    /* Pad CMAP chunk if necessary */
X    if (cmaplen & 1) fputc (0, wfile);
X  }
X      
X  /*----Write out BODY chunk----*/
X  fprintf (wfile, "BODY");
X  put_long (bodylen-8, wfile, BIG);
X  fwrite (body, bodylen-8, 1, wfile);
X
X  /* Pad BODY chunk if necessary */
X  if (bodylen & 1) fputc (0, wfile);
X      
X  /*--------Free memory and return--------*/
X  if (cmap)	free (cmap);
X  if (body)	free (body);
X
X  return (1);
X}
X
X/****************************************************************
X * build_bmhd: Build a BitMapHeader, and byte swap it if necessary
X ****************************************************************/
X
Xbuild_bmhd (image, bmh, bits)
XFBM *image;
XBitMapHeader *bmh;
Xint bits;
X{
X  bmh->w = image->hdr.cols;
X  bmh->h = image->hdr.rows;
X  bmh->x = 0;
X  bmh->y = 0;
X  bmh->nPlanes = bits;
X  bmh->masking = 0;  
X  bmh->compression = 0;
X  bmh->pad1 = 0;
X  bmh->transparentColor = 0;
X  bmh->xAspect = 100;
X  bmh->yAspect = (image->hdr.aspect * 100.0) + 0.5;
X  bmh->pageWidth = bmh->w;
X  bmh->pageHeight = bmh->h;
X
X  /* IFF uses BIG byte order, swap if necessary */
X  if (machine_byte_order () == LITTLE)
X  { bmh->w = swapword (bmh->w);
X    bmh->h = swapword (bmh->h);
X    bmh->x = swapword (bmh->x);
X    bmh->y = swapword (bmh->y);
X    bmh->transparentColor = swapword (bmh->transparentColor);
X    bmh->pageWidth = swapword (bmh->pageWidth);
X    bmh->pageHeight = swapword (bmh->pageHeight);
X  }
X
X  return (sizeof (*bmh) + 8);
X}
X
X/****************************************************************
X * build_cmap: Convert an FBM format colormap to IFF format
X ****************************************************************/
X
Xbuild_cmap (image, cmap, bits)
XFBM *image;
Xunsigned char **cmap;
Xint bits;
X{ register int len, i;
X  register unsigned char *r, *g, *b, *c;
X  int colors;
X
X  colors = image->hdr.clrlen / 3;
X  
X  r = image->cm;
X  g = r + colors;
X  b = g + colors;
X  
X  len = 3*colors;
X  *cmap = (unsigned char *) malloc (len);
X
X  /* Now convert from three vectors to a vector of triples */
X  for (i=0, c= *cmap; i<colors; i++)
X  { *c++ = *r++;
X    *c++ = *g++;
X    *c++ = *b++;
X  }
X  
X  /* Return length of chunk, just length of map plus 8 bytes chunk header */
X  return (len + 8);
X}
X
X/****************************************************************
X * build_body: Interleave the bits for the byte plane
X ****************************************************************/
X
Xbuild_body (image, body, bits)
Xregister FBM *image;
Xunsigned char **body;
Xint bits;
X{ int bpr, size;
X  register unsigned char *obm, *bmp;
X  register int r, c, k, mask, byte, bit;
X
X  bpr = RowBytes (image->hdr.cols);
X  
X  size = bpr * image->hdr.rows * bits;
X  
X  *body = (unsigned char *) malloc (size);
X
X  obm = *body;  
X
X  for (r=0; r < image->hdr.rows; r++)
X  { for (k=0; k<bits; k++)
X    { mask = 1 << k;
X      bmp = &(image->bm[r * image->hdr.rowlen]);
X
X# ifdef DEBUG      
X      if (r==23)
X      { fprintf (stderr, "Row %d, plane %d, bytes: ", r, k);
X        for (c=0; c<32; c++) fprintf (stderr, "%02x", bmp[c]);
X	fprintf (stderr, "\n");
X      }
X# endif
X      
X      for (c=0, byte=0; c<image->hdr.cols; c++)
X      { bit = (*bmp++ & mask) ? 1 : 0;
X
X
X# ifdef DEBUG
X        if (r == 23 && c < 32)
X	{ fprintf (stderr, "%d", bit); }
X# endif
X
X	byte = (byte << 1) | bit;
X        if ((c&7) == 7)
X	{ *obm++ = byte;
X
X# ifdef DEBUG
X	  if (r == 23 && c <32) fprintf (stderr, " %d ", byte);
X# endif
X
X	  byte=0;
X        }
X      }
X      
X# ifdef DEBUG
X      if (r == 23) fprintf (stderr, "\n");
X# endif
X      
X      if ((c & 7) != 0)
X      { while ((c&7) != 0)
X        { c++; byte <<= 1; }
X	*obm++ = byte;
X      }
X    }
X  }
X  
X  return (size + 8);
X  
X}
END_OF_FILE
if test 23454 -ne `wc -c <'fliff.c'`; then
    echo shar: \"'fliff.c'\" unpacked with wrong size!
fi
# end of 'fliff.c'
fi
echo shar: End of archive 7 \(of 8\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.