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.