v19i053: FBM, image manipulation library, Part07/08
Rich Salz
rsalz at uunet.uu.net
Fri Jun 9 22:50:12 AEST 1989
Submitted-by: Michael.Mauldin at 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 at 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 at cs.cmu.edu
X *
X * 20-Apr-89 C. Harald Koch (chk) at DCIEM Toronto.
X * Created. chk at ben.dciem.dnd.ca
X *
X *================================================================
X * based on ray2.c from DBW_Render, Copyright 1987 David B. Wecker
X *
X * From: chk at 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 at 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 at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.unix
mailing list