This is xviff.c in view mode; [Download] [Up]
/*
* xviff.c - IFF image file i/o routines
*/
/*
* ILBM's can be compressed or uncompressed, only uncompressed
* By Brett Van Sprewenburg (bpv9073@park.kodak.com or bpv9073@sjfc.edu)
*
* Credit to the ppm utilities, the developer(s) of xv, and Commodore-Amiga for
* code and ideas.
*
* Version Date
* 1.0 12/??/92 Initial attempts to read the 24 bit IFF
* ILBM format
* 1.1 2/4/93 Cleaned code, fixed bugs with read and
* writeilbm intergration
* 1.2 2/9/93 ANSI'fied code some more for compilation
* with acc
* 1.2.1 2/10/93 Checks to make sure it's a valid iff file,
* looks for FORM chuck id
* Fixed a couple of minor printf bugs.
* 1.2.2 2/11/93 Checks to make sure that there are 24 bit
* planes in the IFF.
* XVified the whole thing
*/
/* additional mods to hook it into XV 3.00 by John Bradley, 2/15/93 */
#include "xv.h"
#define RowBytes(cols) ( ( ( (int)(cols) + 15 ) / 16 ) * 2 )
/* definitions for BMHD */
struct BitMapHeader {
unsigned short w, h;
short x, y;
unsigned char nPlanes, masking, compression, pad1;
unsigned short transparentColor;
unsigned char xAspect, yAspect;
short pageWidth, pageHeight;
};
#define mskNone 0
#define mskHasMask 1
#define mskHasTransparentColor 2
#define mskLasso 3
#define cmpNone 0
#define cmpByteRun1 1
typedef struct { unsigned char r, g, b; } pixel;
#define ASSIGN(p,red,grn,blu) { (p).r = (red); (p).g = (grn); (p).b = (blu); }
#define ALLOCROW( cols ) ((pixel*) malloc( cols * sizeof(pixel) ))
pixel *pixelrow;
struct BitMapHeader ilbmheader;
#define ILBMHSIZE 40 /* Size of written ilbm header in bytes */
/*----------------------------------------------------------------------*
* PACKER.H typedefs for Data-Compresser. 1/22/86
*
* This module implements the run compression algorithm "cmpByteRun1"; the
* same encoding generated by Mac's PackBits.
*
* By Jerry Morrison and Steve Shaw, Electronic Arts.
* This software is in the public domain.
*
* This version for the Commodore-Amiga computer.
*
* This particular version has been slightly modified for this
* distribution by Brett Van Sprewenburg, Eastman Kodak
* <bpv9073@park.kodak.com or bpv9073@sjfc.edu>
*----------------------------------------------------------------------*/
/* This macro computes the worst case packed size of a "row" of bytes. */
#define MaxPackedSize(rowSize) ( (rowSize) + ( ((rowSize)+127) >> 7 ) )
static int iffError();
static void iffWarning();
static int getint32();
static int getint16();
static void putint32();
static void putint16();
char *bname;
long filesize;
/******************************************/
int LoadIFF(fname, pinfo)
char *fname;
PICINFO *pinfo;
/******************************************/
{
/* returns '1' if successful, '0' if not */
FILE *fp;
char form[5];
byte *ubp, *bp, *runbuf;
byte *Rrow, *Brow, *Grow;
byte *body = 0; /* To hold crazy IFF body data */
byte *image = 0;
unsigned int mybyte;
int totbytes,bytes,row,col,plane,j,w,h,d;
long bmsize,formsize;
unsigned long body_chunk_size;
pinfo->pic = (byte *) NULL;
pinfo->comment = (char *) NULL;
bname = BaseName(fname);
fp = fopen(fname,"r");
if (!fp) return ( iffError(pinfo, "can't open file"));
/* find the size of the file */
fseek(fp, 0L, 2);
filesize = ftell(fp);
fseek(fp, 0L, 0);
fread(form,4,1,fp); /* FORM */
if (strcmp(form,"FORM") != NULL) {
return ( iffError(pinfo, "not an IFF file.")); /* shouldn't happen. */
}
formsize = getint32(fp); /* size of whole form - 8 */
fread(form,4,1,fp); /* ILBM */
fread(form,4,1,fp); /* BMHD */
bmsize = getint32(fp); /* size of BMHD */
/* load up header info */
ilbmheader.w = getint16(fp);
ilbmheader.h = getint16(fp);
ilbmheader.x = getint16(fp);
ilbmheader.y = getint16(fp);
ilbmheader.nPlanes = getc(fp);
ilbmheader.masking = getc(fp);
ilbmheader.compression = getc(fp);
getc(fp); /* pad1 */
ilbmheader.transparentColor = getint16(fp);
ilbmheader.xAspect = getc(fp);
ilbmheader.yAspect = getc(fp);
ilbmheader.pageWidth = getint16(fp);
ilbmheader.pageHeight = getint16(fp);
if (ferror(fp)) {
fclose(fp);
return (iffError("error reading IFF header."));
}
w = ilbmheader.w;
h = ilbmheader.h;
d = ilbmheader.nPlanes;
if (d != 24) {
fclose(fp);
return (iffError("only 24-bit IFF files are supported."));
}
fread(form,4,1,fp); /* BODY (ANNO or CMAP sometimes) */
while ((strcmp(form,"BODY") != 0)) /* Find the damn thing */
fread(form,4,1,fp);
/* Read in the size of the body chunk */
body_chunk_size = getint32(fp);
pixelrow = ALLOCROW(w);
image = (byte *) malloc(w * h * 3);
body = (byte *) malloc(body_chunk_size);
runbuf = (byte *) malloc(RowBytes(w));
Rrow = (byte *) malloc(w);
Grow = (byte *) malloc(w);
Brow = (byte *) malloc(w);
if (!pixelrow || !image || !body || !runbuf || !Rrow || !Grow || !Brow)
FatalError("can't malloc() in LoadIFF()");
bp = body;
/* Read in the body of the ilbm */
fread(body, body_chunk_size, 1, fp);
if (ferror(fp)) iffWarning("IFF file appears to be truncated.");
fclose(fp);
for (row=0; row<h; row++) {
for (col=0; col<w; col++)
Rrow[col] = Grow[col] = Brow[col] = 0;
/* Image is compressed by plane, line by line */
for (plane=0; plane<d; plane++) {
switch (ilbmheader.compression) {
case 0: /* Uncompressed IFF */
ubp = bp;
bp += RowBytes(w);
break;
case 1: /* RLE Compressed IFF */
ubp = runbuf;
totbytes = RowBytes(w);
do {
mybyte = *bp++;
if ( mybyte <= 127 )
for ( j = mybyte, totbytes -= j + 1; j >= 0; j--) {
*ubp++ = *bp++;
}
else if ( mybyte != 128 )
for (j = 256 - mybyte, totbytes -= j + 1, mybyte = *bp++;
j >= 0; j--) {
*ubp++ = mybyte;
}
} while ( totbytes > 0 );
ubp = runbuf;
break;
}
/* Break raw row buffer up into separate rgb values */
/* In order to understand this a little better, it might help */
/* to know that the pixel values in an ILBM appear to be stored */
/* bit reversed. Hence all the logical bitwise juju. */
for (col=0; col<w; col++)
if (plane < 8) { /* red */
if (ubp[col / 8] & ( 128 >> ( col % 8 ) ) )
Rrow[col] |= 1 << plane;
}
else if ( plane > 15 ) { /* blue */
if ( ubp[col / 8] & ( 128 >> ( col % 8 ) ) )
Brow[col] |= 1 << (plane-16);
}
else { /* green */
if ( ubp[col / 8] & ( 128 >> ( col % 8 ) ) )
Grow[col] |= 1 << (plane-8);
}
}
/* Get the rgb values out of pixel structure, pointed at by pixelrow */
for ( col = 0; col < w ; col++)
ASSIGN(pixelrow[col],Rrow[col],Grow[col],Brow[col]);
/* Put the pixel data in a 24 bit image space */
memcpy(image + w * row * 3, pixelrow, w * 3);
}
pinfo->pic = image;
pinfo->w = w;
pinfo->h = h;
pinfo->type = PIC24;
pinfo->frmType = F_ILBM;
pinfo->colType = F_FULLCOLOR;
sprintf(pinfo->fullInfo,
"Amiga %s IFF24 ILBM. (%d planes) (%ld bytes)",
(ilbmheader.compression == cmpByteRun1) ?
"compressed" : "uncompressed",
d, filesize);
sprintf(pinfo->shrtInfo, "%dx%d Amiga ILBM.", w, h);
/* clean up */
free(pixelrow);
free(body);
free(runbuf);
free(Rrow); /* Fly! Be Free!! */
free(Grow);
free(Brow);
return 1;
}
/*
* Writeilbm.c
*
* Writes out a 24 bit IFF ILBM file, compressed or uncompressed.
* By Brett Van Sprewenburg
*
* This is a fairly complex format, or at least I thought so... :-)
*
* Version
* 1.0 2/1/93 First working version, with hardcoded form and
* body chunk sizes.
* Only uncompressed images work.
* 1.1 2/2/93 Added in the correct form and body sizes with
* compression by altering
* the file after it was written.
*
* 1.2 2/4/93 First working version with compression done correctly.
* I still wouldn't be able to tell you exactly what
* was wrong. Fixed multiple things with readilbm
* integration. The biggest problem with this version
* is that it's sloooow.
* A faster way may be to do 8 planes at once, instead of
* a plane at a time.
* 1.3 2/9/93 Fixed previous slowness by compiling with acc -fast.
* ANSI'fied code also for
* compilation with acc without warnings.
* 1.4 2/10/93 Added reading and conversion of 8 bit rasters
* into 24 bit ilbms.
*
*/
/******************************************************************/
int WriteILBM(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
compression)
FILE *fp;
byte *pic;
int ptype, w, h;
byte *rmap, *gmap, *bmap;
int numcols, colorstyle, compression;
/******************************************************************/
{
byte *tpic, *pp, *tp;
int formsize, bmhdsize, bodysize;
byte *coded_rowbuf,*cp,*raw_rowbuf;
int rel_count, rgbline, linesize, mask, yoffset, offset, push;
int row, col, plane;
unsigned int bit;
int pad,tot_bytes,packedbytes,ycoffset,coffset,ccol = 0;
linesize = RowBytes(w);
bmhdsize = 4 + 4 + 4 + 2 + 2 + 4; /* size of header info written */
if (!compression) {
bodysize = h * linesize * 24;
formsize = 4 + 4 + 4 + bmhdsize + 4 + 4 + bodysize;
}
else {
bodysize = 999999;
formsize = 999999; /* don't know how much compression we'll get */
}
/* write out header info */
fwrite("FORM", 4, 1, fp);
putint32(formsize, fp);
fwrite("ILBM", 4, 1, fp);
fwrite("BMHD", 4, 1, fp);
putint32(bmhdsize, fp);
putint16(w, fp);
putint16(h, fp);
putint16(0, fp); /* x */
putint16(0, fp); /* y */
putc(24, fp); /* nPlanes */
putc(mskNone, fp); /* masking */
putc(compression ? cmpByteRun1 : cmpNone, fp);
putc(0, fp); /* pad1 */
putint16(0, fp); /* transparent color */
putc(10, fp); /* xAspect */
putc(10, fp); /* yAspect */
putint16(w, fp); /* pageWidth */
putint16(h, fp); /* page height */
fwrite("BODY",4,1,fp);
putint32(bodysize,fp);
/* write the image data */
/* if pic is anything other than F_FULLCOLOR, PIC24, build a pic24 to hold
an appropriate version of the pic */
if (ptype == PIC24 && colorstyle == F_FULLCOLOR) tpic = pic;
else {
tpic = (byte *) malloc(w * h * 3);
if (!tpic) FatalError("can't alloc memory in WriteIFF()");
if (ptype == PIC8) {
for (i=0, pp=pic, tp=tpic; i<w*h; i++,pp++) {
if (colorstyle == F_GREYSCALE) {
j = MONO(rmap[*pp],gmap[*pp],bmap[*pp]);
*tpic++ = j; *tpic++ = j; *tpic++ = j;
}
else {
*tpic++ = rmap[*pp];
*tpic++ = gmap[*pp];
*tpic++ = bmap[*pp];
}
}
}
else { /* if PIC24 */
if (colorstyle == F_GREYSCALE) {
for (i=0, tp=tpic; i<w*h; i++) {
tp[0] = MONO(tp[0],tp[1],tp[2]);
tp[1] = tp[2] = tp[0];
}
}
else {
free(tpic);
tpic = pic;
}
}
}
/* at this point, tpic points to an appropriate 24-bit image to dump */
tot_bytes = packedbytes = 0;
rgbline = w * 3;
coded_rowbuf = (byte *) malloc(w);
raw_rowbuf = (byte *) malloc(rgbline);
if (!coded_rowbuf || !raw_rowbuf)
FatalError("out of memory in WriteIFF()");
/* This next whole thing took quite a while to figure out
This file format looks like this: ( all data is bit reversed )
Plane data scanline
-------------------------------------------
Plane 0: RowBytes of red 0
Plane 1: RowBytes of red 0
|
Plane 7: RowBytes of red 0
Plane 8: RowBytes of green 0
|
Plane 15: RowBytes of green 0
Plane 16: RowBytes of blue 0
|
Plane 23: RowBytes of blue 0
Plane 0: RowBytes of red 1
Plane 1: RowBytes of red 1
and the beat goes on...
*/
/* Figure this next bit out for yourself :-< */
for (row=0; row<h; row++) {
yoffset = row * rgbline;
for (plane=0; plane<24; plane++) {
if (plane < 8) push = plane;
else if (plane > 15) push = plane - 16;
else push = plane - 8;
mask = 1 << push; /* how many bits to push */
cp = coded_rowbuf;
*cp = 0;
for (col=(plane / 8), rel_count=0; col<rgbline; rel_count++, col+=3) {
offset = yoffset + col;
bit = (*(tpic + offset) & mask) ? 1 : 0;
*cp |= bit << ( 7 - (rel_count % 8) );
if ((rel_count % 8) == 7) { /* Every 8th byte, advance pixel */
cp++; *cp = 0;
}
}
if (compression) { /* This bit is pretty obvious. */
packedbytes = packrow(coded_rowbuf, raw_rowbuf, linesize);
tot_bytes += packedbytes;
fwrite(raw_rowbuf, packedbytes, 1, fp);
}
else /* Write uncompressed data */
fwrite(coded_rowbuf, linesize, 1, fp);
}
}
/* if we compressed, have to go fix bogus values we wrote earlier */
if (compression) {
formsize = tot_bytes + 4 + 4 + 4 + bmhdsize + 4 + 4;
fseek(fp,4L,0);
putint32(formsize, fp);
fseek(fp,44L,0);
putint32(tot_bytes, fp);
}
if ((tot_bytes % 2) != 0) { /* Pad the body chunk out to an even byte */
fseek(fp,0L,2);
pad = 0;
fwrite(&pad,1,1,fp);
}
free(coded_rowbuf);
free(raw_rowbuf);
if (tpic != pic) free(tpic);
return 0;
}
/*----------------------------------------------------------------------*
* packer.c Convert data to "cmpByteRun1" run compression. 11/15/85
*
* By Jerry Morrison and Steve Shaw, Electronic Arts.
* This software is in the public domain.
*
* control bytes:
* [0..127] : followed by n+1 bytes of data.
* [-1..-127] : followed by byte to be repeated (-n)+1 times.
* -128 : NOOP.
*
* This version for the Commodore-Amiga computer.
*
* Slightly modified by Brett Van Sprewenburg, Eastman Kodak.
* <bpv9073@park.kodak.com>
* It will now accept only a pointer to the image data, not pointers to pointers.
*
*----------------------------------------------------------------------*/
#include "xv.h"
#include "packer.h"
#define DUMP 0
#define RUN 1
#define MinRun 3
#define MaxRun 128
#define MaxDat 128
/* When used on global definitions, static means private.
* This keeps these names, which are only referenced in this
* module, from conficting with same-named objects in your program.
*/
static int putSize;
static byte buf[128]; /* [TBD] should be 128? on stack?*/
#define GetByte() (*source++)
#define PutByte(c) { *dest++ = (c); ++putSize; }
byte *PutDump(dest, nn)
byte *dest;
int nn;
{
int i;
PutByte(nn-1);
for(i = 0; i < nn; i++) PutByte(buf[i]);
return(dest);
}
byte *PutRun(dest, nn, cc)
byte *dest;
int nn, cc;
{
PutByte(-(nn-1));
PutByte(cc);
return(dest);
}
#define OutDump(nn) dest = PutDump(dest, nn)
#define OutRun(nn,cc) dest = PutRun(dest, nn, cc)
/*----------- packrow --------------------------------------------------*/
long packrow(pSource, pDest, rowSize)
byte *pSource;
byte *pDest;
long rowSize;
/*----------------------------------------------------------------------*/
{
byte *source, *dest;
byte c;
char lastc = '\0';
int mode = DUMP;
int nbuf = 0; /* number of chars in buffer */
int rstart = 0; /* buffer index current run starts */
source = pSource;
dest = pDest;
putSize = 0;
buf[0] = lastc = c = GetByte(); /* so have valid lastc */
nbuf = 1; rowSize--; /* since one byte eaten.*/
for (; rowSize; --rowSize) {
buf[nbuf++] = c = GetByte();
switch (mode) {
case DUMP:
/* If the buffer is full, write the length byte,
then the data */
if (nbuf>MaxDat) {
OutDump(nbuf-1);
buf[0] = c;
nbuf = 1; rstart = 0;
break;
}
if (c == lastc) {
if (nbuf-rstart >= MinRun) {
if (rstart > 0) OutDump(rstart);
mode = RUN;
}
else if (rstart == 0)
mode = RUN; /* no dump in progress,
so can't lose by making these 2 a run.*/
}
else rstart = nbuf-1; /* first of run */
break;
case RUN: if ( (c != lastc)|| ( nbuf-rstart > MaxRun)) {
/* output run */
OutRun(nbuf-1-rstart,lastc);
buf[0] = c;
nbuf = 1; rstart = 0;
mode = DUMP;
}
break;
}
lastc = c;
}
switch (mode) {
case DUMP: OutDump(nbuf); break;
case RUN: OutRun(nbuf-rstart,lastc); break;
}
pSource = source;
pDest = dest;
return(putSize);
}
/*****************************/
static int iffError(pinfo, st)
PICINFO *pinfo;
char *st;
{
iffWarning(st);
if (pinfo->pic) free(pinfo->pic);
if (pinfo->comment) free(pinfo->comment);
pinfo->pic = (byte *) NULL;
pinfo->comment = (char *) NULL;
return 0;
}
/*****************************/
static void iffWarning(st)
char *st;
{
SetISTR(ISTR_WARNING,"%s: %s", bname, st);
}
static int getint32(fp)
FILE *fp;
{
int i;
i = (getc(fp) & 0xff) << 24;
i |= (getc(fp) & 0xff) << 16;
i |= (getc(fp) & 0xff) << 8;
i |= (getc(fp) & 0xff);
return i;
}
static void putint32(i, fp)
int i;
FILE *fp;
{
putc( ((i>>24) & 0xff), fp);
putc( ((i>>16) & 0xff), fp);
putc( ((i>> 8) & 0xff), fp);
putc( ((i) & 0xff), fp);
}
static int getint16(fp)
FILE *fp;
{
int i;
i = (getc(fp) & 0xff) << 8;
i |= (getc(fp) & 0xff);
return i;
}
static void putint16(i, fp)
int i;
FILE *fp;
{
putc( ((i>> 8) & 0xff), fp);
putc( ((i) & 0xff), fp);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.