/* JIFF.H */ /************ I usually put these in a file called format.h ****/ #define XMAX 640 #define LOXMAX 320 #define YMAX 200 #define XASPECT 5 #define YASPECT 11 /* EA handy make a long from 4 chars macros redone to work with Aztec*/ #define MAKE_ID(a, b, c, d)\ ( ((long)(a)<<24) | ((long)(b)<<16) | ((long)(c)<<8) | (long)(d) ) /* These are the IFF types I deal with */ #define FORM MAKE_ID('F', 'O', 'R', 'M') #define ILBM MAKE_ID('I', 'L', 'B', 'M') #define BMHD MAKE_ID('B', 'M', 'H', 'D') #define CMAP MAKE_ID('C', 'M', 'A', 'P') #define BODY MAKE_ID('B', 'O', 'D', 'Y') /* And these are the IFF types I ignore but don't squawk about */ #define GRAB MAKE_ID('G', 'R', 'A', 'B') #define DEST MAKE_ID('D', 'E', 'S', 'T') #define SPRT MAKE_ID('S', 'P', 'R', 'T') #define CAMG MAKE_ID('C', 'A', 'M', 'G') #define CRNG MAKE_ID('C', 'R', 'N', 'G') #define CCRT MAKE_ID('C', 'C', 'R', 'T') #define EVEN(x) (((x) + 1) & ~1) #define MANDEL /* Some macros for raster memory allocation ... redefine if you're sensible and manage memory locally */ #ifndef MANDEL /* ralloc - raster alloc */ # define ralloc(amount) (PLANEPTR)AllocMem((long)(amount), MEMF_CHIP) /* rfree - raster free */ # define rfree(pt, amount) FreeMem( (pt), (long)(amount) ) #else /* MANDEL */ # include /* * We don't want to allocate a complete raster for the picture, since we * already have a screen with a window where we want to have it. * Therefore, we allocate some small buffers, which get blitted into * our window as soon as they fill up. */ # define MAXPLANESIZE 1040L /* ralloc - raster alloc */ # define ralloc(amount) (PLANEPTR)AllocMem(MAXPLANESIZE, MEMF_CHIP) /* rfree - raster free */ # define rfree(pt, amount) FreeMem( (pt), MAXPLANESIZE ) #endif /* !MANDEL */ /* line_bytes = the number of words * 2 (for bytes) a raster line takes up */ #define line_bytes(width) (((width + 15) >> 3) & ~0x0001) /* psize - plane size in bytes (an even number) of a raster given width and height */ #define psize(width, height) ( line_bytes(width)*height) /* The place to throw excess bits */ #define bit_bucket(file, length) fseek(file, (long)EVEN(length), 1) union bytes4 { char b4_name[4]; long b4_type; }; struct iff_chunk { union bytes4 iff_type; long iff_length; }; struct form_chunk { union bytes4 fc_type; /* == FORM */ long fc_length; union bytes4 fc_subtype; }; #ifndef MANDEL /* We have this already in Mandel.H */ struct BitMapHeader { UWORD w, h; UWORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE pad1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; }; /* ILBM_info is the structure read_iff returns, and is hopefully all you need to deal with out of the iff reader routines below */ struct ILBM_info { struct BitMapHeader header; UBYTE cmap[MAXCOL*3]; struct BitMap bitmap; }; #endif /* !MANDEL */ /* I sure wish C function "prototypes" were real and not just ANSI * extern struct ILBM_info *read_iff(); * read_iff( char *filename, short just_colors, int ExtraSize, * APTR ExtraInfo ); * extern void free_planes(); free_planes( struct BitMap *bitmap); * extern int write_iff(); * write_iff(char *name, unsigned char *colors, struct BitMap *bits, * short xoff, short yoff, short width, short compressed); */ /* extern char *AllocMem(); */ /* Anyone know where some useful minterms are defined? */ #define COPY_MINTERM 0x0C0L /*** A meditation for the guru from the Diamond Sutra - So shall you think of all this fleeting world: A star at dawn, a bubble in a stream; A flash of lightning in a summer cloud, A flickering lamp, a phantom, and a dream. ***/ /********************************************************************** * * jiff.c Jim Kent's iff - ilbm reader * * This is the (sortof) short (sortof) simple no-frills IFF reader * to get something out of DPaint, Images, or the Animator. It * works well with the Aztec C compiler. It should work with Lattice * but you never know until you try it. I haven't. * * I've included a simple main program. This is just to make it * stand alone. Since amiga screen initializations are massive, all * it does as is is read it into a BitMap, and then free up the BitMap. * Should crash it if it's gonna crash though. * * The main interface to this is through the routine read_iff(filename). * This returns a ILBM_info structure-pointer on success, and NULL on * failure. It cleans up after itself on failure. * * I hope you will find this useful and easy to use. Please forgive * my funky indentation style? Well at least I'm consistent! * (* Run through the C-Beautifier by Olaf Seibert !! *) * * To demonstrate what a nice guy I am even though I'm far from wild * about the IFF standard I'm placing this in the public domain. When * you remove the DEBUG and PARANOID definitions the code is only * 1536 bytes long. * * -Jim Kent April 22, 1986 ************************************************************************/ #include #include #include #include #include /* #include "jiff.h" */ /* This is an all too common state of software development. Get rid of this define as soon as it runs. */ #undef DEBUG /* This is the normal state of software development. Seriously undefine this to make it shut up about errors and reduce code size half way through beta testing... */ #undef PARANOID /* This is nice if you want to use a debugger on the STATIC data and routines in this file. Redefine only if you don't need a debugger. */ /* #undef STATIC */ /* #define STATIC */ STATIC struct ILBM_info *read_ilbm(), *read_body(); /* OK this code is almost re-entrant. Pass this guy from above to make it really re-entrant. (Why do you need a reentrant ILBM reader though?? Maybe for Dale ... ) Well, look in the IFF specs for instance... [Olaf Seibert, KosmoSoft] */ STATIC struct ILBM_info root_info; /* static so get initialized to zero */ #ifdef PARANOID /* a little paranoid routine that say's where we got before EOF */ STATIC void iff_truncated(where) int where; { printf("ILBM truncated %d\n", where); free_planes(&root_info.bitmap); } #endif PARANOID struct ILBM_info *read_iff(name, just_colors, ExtraSize, ExtraPointer) char *name; short just_colors; int ExtraSize; APTR ExtraPointer; { struct ILBM_info *info = &root_info; FILE *file; struct form_chunk chunk; if ((file = fopen(name, "r") ) == 0) { #ifdef PARANOID printf("couldn't Open %s to read\n", name); #endif PARANOID return NULL; } if ( fread(&chunk, sizeof(struct form_chunk), 1, file) != 1) { #ifdef PARANOID iff_truncated(0); #endif PARANOID fclose(file); return NULL; } if (chunk.fc_type.b4_type != FORM) { #ifdef PARANOID printf("not a FORM - %s\n", name); #endif PARANOID fclose(file); return NULL; } if (chunk.fc_subtype.b4_type != ILBM) { #ifdef PARANOID printf("FORM not an ILBM - %s\n", name); #endif PARANOID fclose(file); return NULL; } #ifdef DEBUG printf("FORM %ld ILBM\n", chunk.fc_length); #endif DEBUG info = read_ilbm(file, info, chunk.fc_length - sizeof(chunk), just_colors); #ifdef DEBUG printf("info = %lx\n", info); #endif DEBUG #ifdef MANDEL if (info && ExtraSize) { /* We may want to read the extra MAND */ fread(ExtraPointer, 1, ExtraSize, file); } #endif MANDEL fclose(file); return info; } STATIC struct ILBM_info *read_ilbm(file, info, length, just_colors) FILE *file; struct ILBM_info *info; long length; short just_colors; { struct iff_chunk chunk; int i; long read_in = 0; int got_header = FALSE; /* To make sure gots the header first */ int got_cmap = FALSE; /* Make sure get cmap before "BODY" */ /* Make sure the Planes are all NULL so can free up memory easily on error abort */ for (i=0; i<8; i++) info->bitmap.Planes[i] = NULL; while (read_in < length) { if (fread(&chunk, sizeof(chunk), 1, file) != 1) { #ifdef PARANOID iff_truncated(1); #endif PARANOID return NULL; } switch (chunk.iff_type.b4_type) { case BMHD: #ifdef DEBUG printf("\tBMHD %ld\n", chunk.iff_length); #endif DEBUG if (fread(&info->header, sizeof(info->header), 1, file) != 1) { #ifdef PARANOID iff_truncated(2); #endif PARANOID return NULL; } got_header = TRUE; break; case CMAP: #ifdef DEBUG printf("\tCMAP %ld\n", chunk.iff_length); #endif DEBUG if (!got_header) { #ifdef PARANOID printf("CMAP befor BMHD\n"); #endif PARANOID return NULL; } if (chunk.iff_length <= 3*MAXCOL ) { if (fread(info->cmap, (int)chunk.iff_length, 1, file) != 1) { #ifdef PARANOID iff_truncated(3); #endif PARANOID return NULL; } } else { #ifdef PARANOID printf("warning, more than %d colors in ILBM CMAP\n", MAXCOL); #endif PARANOID if (fread(info->cmap, (int) 3*MAXCOL, 1, file) != 1) { #ifdef PARANOID iff_truncated(4); #endif PARANOID return NULL; } bit_bucket(file, chunk.iff_length - 3*MAXCOL); } got_cmap = TRUE; if (just_colors) return info; break; case BODY: if (!got_cmap) { #ifdef PARANOID printf("BODY before CMAP\n"); #endif PARANOID return NULL; } #ifdef DEBUG printf("\tBODY %ld\n", chunk.iff_length); #endif DEBUG return read_body(file, info, chunk.iff_length); default: /* Squawk about unknown types if PARANOID */ #ifdef PARANOID printf("\t unknown type %lx of b4_type\n", chunk.iff_type.b4_type); case GRAB: /* Ignore documented but unwanted types */ case DEST: case SPRT: case CAMG: case CRNG: case CCRT: #endif PARANOID bit_bucket(file, chunk.iff_length); break; } read_in += EVEN(chunk.iff_length) + sizeof(chunk); } #ifdef PARANOID printf("no BODY in ILBM\n"); #endif PARANOID return NULL; } STATIC struct ILBM_info *read_body(file, info, length) FILE *file; register struct ILBM_info *info; long length; { struct ILBM_header *header; struct BitMap *bm; int i, j; int rlength; int plane_offset; #ifdef MANDEL int YSize, DestY = 0; #endif #ifdef DEBUG printf("read_body( %lx %lx %ld)\n", file, info, length); #endif DEBUG #ifdef PARANOID /* When paranoid do a little error checking first ... fail fast! */ if (info->header.nPlanes > 8) { printf("Whoa, woe Dale only speaks 8 planes boy, not %d\n", info->header.nPlanes); return NULL; } #endif PARANOID /* Ok a little more error checking */ if (info->header.compression != 0 && info->header.compression != 1) { #ifdef PARANOID printf("unrecognized compression type %d\n", info->header.compression); #endif PARANOID return NULL; } /* Set up the bitmap part that doesn't involve memory allocation first - hey this part does get done, and let's be optimistic...*/ info->bitmap.BytesPerRow = line_bytes(info->header.w); info->bitmap.Rows = info->header.h; info->bitmap.Depth = info->header.nPlanes; info->bitmap.Flags = info->bitmap.pad = 0; rlength = info->bitmap.Rows * info->bitmap.BytesPerRow; for (i=0; iheader.nPlanes; i++) { if ((info->bitmap.Planes[i] = ralloc(rlength)) == NULL) { #ifdef PARANOID printf("couldn't alloc plane %d in read_body\n",i); #endif PARANOID free_planes( &info->bitmap ); return NULL; } } plane_offset = 0; #ifdef MANDEL YSize = (MAXPLANESIZE / info->bitmap.BytesPerRow); #endif MANDEL for (i=0; ibitmap.Rows; i++) { /* This test should be in the inner loop for shortest code, */ /* in the outer loop for greatest speed, so sue me I compromised */ if (info->header.compression == 0) { for (j = 0; j < info->bitmap.Depth; j++) { if ( fread(info->bitmap.Planes[j] + plane_offset, info->bitmap.BytesPerRow, 1, file) != 1) { #ifdef PARANOID iff_truncated(6); #endif PARANOID free_planes( &info->bitmap); return NULL; } } } else { register char *dest, value; register int so_far, count; /* How much have unpacked so far */ for (j = 0; j < info->bitmap.Depth; j++) { so_far = info->bitmap.BytesPerRow; dest = (char *)info->bitmap.Planes[j] + plane_offset; while (so_far > 0) { if ( (value = getc(file)) == 128) { #ifdef DEBUG printf("NOP\n"); #endif DEBUG } else if (value > 0) { count = (int)value + 1; so_far -= count; if ( fread(dest, count, 1, file) != 1) { #ifdef PARANOID iff_truncated(7); #endif PARANOID free_planes( &info->bitmap); return NULL; } dest += count; } else { count = (int)-value + 1; so_far -= count; value = getc(file); while (--count >= 0) /* This is fastest loop on the 68000 */ *dest++ = value; } } if (so_far != 0) { #ifdef PARANOID printf("compression quite screwed up, aborting %d\n", so_far); #endif PARANOID free_planes( &info->bitmap); return NULL; } } } plane_offset += info->bitmap.BytesPerRow; #ifdef MANDEL if (plane_offset > MAXPLANESIZE - info->bitmap.BytesPerRow) { BltBitMapRastPort(&info->bitmap, 0L, 0L, MainWindow->RPort, 0L, (long) DestY, info->bitmap.BytesPerRow * 8L, (long) YSize, COPY_MINTERM); plane_offset = 0; DestY += YSize; } #endif MANDEL } #ifdef MANDEL if (plane_offset) { BltBitMapRastPort(&info->bitmap, 0L, 0L, MainWindow->RPort, 0L, (long) DestY, info->bitmap.BytesPerRow * 8L, (long) plane_offset / info->bitmap.BytesPerRow, COPY_MINTERM); } #endif MANDEL if (length & 1) { /* Skip padding byte */ getc(file); } return info; } void free_planes(bmap) register struct BitMap *bmap; { PLANEPTR plane; long length; short i; length = bmap->BytesPerRow * bmap->Rows; for (i=0; i<8; i++) if ( (plane = bmap->Planes[i]) != NULL) rfree(plane, length); } #undef DEBUG #undef PARANOID /*----------------------------------------------------------------------* * jpacker.c Convert data to "cmpByteRun1" run compression. * * pack_row() is an adaptation of PackRow() * by Jerry Morrison and Steve Shaw, Electronic Arts, * modified and tweaked by Jim Kent, Dancing Flame 05/02/86 * * control bytes: * [0..127] : followed by n+1 bytes of data. * [-1..-127] : followed by byte to be repeated(-n)+1 times. * -128 : NOOP. * * * write_iff() is the only function you can access in this module. *----------------------------------------------------------------------*/ /* #include #include #include #include "jiff.h" */ #define DUMP 0 #define RUN 1 #define MINRUN 3 #define MAXRUN 128 #define MAXDAT 128 /* pack_row - pass source line pointer, length of line, and file. Returns # of bytes after compression. Returns 0 on write error. Pass file = NULL to just find out length, otherwise will write compressed row to file. */ STATIC unsigned int pack_row(file, source, size) FILE *file; char *source; int size; { char c, lastc = '\0'; short mode = DUMP; short nbuf = 0; /* Number of chars in buffer */ short rstart = 0; /* Buffer index current run starts */ unsigned short putsize; char buf[MAXDAT*3/2]; /* I think MAXDAT+1 would suffice */ putsize = 0; buf[0] = lastc = *source++;/* So have valid lastc */ nbuf = 1; size--; /* Since one byte eaten. */ for (; size; --size) { buf[nbuf++] = c = *source++; switch (mode) { case DUMP: /* If the buffer is full, write the length byte, then the data */ if (nbuf > MAXDAT) { if (file != NULL) { if (putc(nbuf-2, file) == EOF) return 0; if (fwrite(buf, nbuf-1, 1, file) != 1) return 0; } putsize += nbuf; buf[0] = c; nbuf = 1; rstart = 0; break; } if (c == lastc) { if (nbuf - rstart >= MINRUN) { if (rstart > 0) { if (file != NULL) { if (putc(rstart-1, file) == EOF) return 0; if (fwrite(buf, rstart, 1, file) != 1) return 0; } putsize += rstart+1; } 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 */ if (file != NULL) { if (putc( -(nbuf - rstart - 2), file) == EOF) return 0; if (putc( lastc, file) == EOF) return 0; } putsize += 2; buf[0] = c; nbuf = 1; rstart = 0; mode = DUMP; } break; } lastc = c; } switch (mode) { case DUMP: if (file != NULL) { if (putc(nbuf-1, file) == EOF) return 0; if (fwrite(buf, nbuf, 1, file) != 1) return 0; } putsize += nbuf+1; break; case RUN: if (file != NULL) { if (putc( -(nbuf - rstart - 1), file) == EOF) return 0; if (putc( lastc, file) == EOF) return 0; } putsize += 2; break; } return putsize; } STATIC unsigned long pack_bitmap(file, bm) FILE *file; struct BitMap *bm; { unsigned short i, j; unsigned row_length; unsigned long compressed_length; unsigned plane_offset; #ifdef DEBUG printf("pack_bitmap( %lx %lx)\n", file, bm); #endif DEBUG #ifdef PARANOID /* When paranoid do a little error checking first ... Fail fast! */ if (bm->BytesPerRow <= 0 || bm->Rows <= 0 || bm->BytesPerRow > MAXDAT) { printf("bitmap %d bytes by %d rows?????\n", bm->BytesPerRow, bm->Rows); return 0; } if (bm->Depth <= 0 || bm->Depth > 8) { printf("bitmap with %d planes ??????\n", bm->Depth); return 0; } #endif PARANOID compressed_length = 0; plane_offset = 0; for (i=0; iRows; i++) { for (j = 0; j < bm->Depth; j++) { if ( (row_length = pack_row(file, bm->Planes[j] + plane_offset, bm->BytesPerRow)) == 0) { #ifdef PARANOID printf("error packing row %d plane %d\n", i, j); #endif PARANOID return 0; } compressed_length += row_length; } plane_offset += bm->BytesPerRow; } if ( compressed_length & 1) { /* Check to see odd length */ if (file != NULL) { if ( putc( 0, file) == EOF) { return 0; } } /* compressed_length++; Deleted!!! Padding should NOT be included */ /* in the chunk size !!! */ } return compressed_length; } int write_iff(name, colors, bits, xoff, yoff, width, compressed, ExtraSize, ExtraInfo) char *name; unsigned char *colors; register struct BitMap *bits; short xoff, yoff; short compressed; int ExtraSize; APTR ExtraInfo; { FILE *file; struct form_chunk chunk; struct iff_chunk ichunk; struct BitMapHeader header; long bits_size; short i; register short j; register short row_offset; if ((file = fopen(name, "w") ) == 0) { #ifdef PARANOID printf("couldn't Open %s to write\n", name); #endif PARANOID goto abort; } /* Say its a FORM ILBM */ chunk.fc_type.b4_type = FORM; chunk.fc_subtype.b4_type = ILBM; #ifdef MANDEL chunk.fc_length = 4 + 3*sizeof(struct iff_chunk) + MAXCOL*3 + sizeof(struct BitMapHeader) + ExtraSize; #else chunk.fc_length = 4 + 3*sizeof(struct iff_chunk) + MAXCOL*3 + sizeof(struct BitMapHeader); #endif MANDEL if (bits) { if (compressed) { if ( (bits_size = pack_bitmap(NULL, bits)) == 0) goto abort; } else { bits_size = bits->BytesPerRow*bits->Rows*bits->Depth; } chunk.fc_length += bits_size; if (bits_size & 1) chunk.fc_length++; } if (fwrite(&chunk, sizeof(chunk), 1, file) != 1) goto abort; /* Here comes a BitMapHeader */ ichunk.iff_type.b4_type = BMHD; ichunk.iff_length = sizeof(header); if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1) goto abort; /* Initialize the BitMapHeader to normal values */ header.masking = 0; header.pad1 = 0; header.transparentColor = 0; if (compressed) header.compression = 1; else header.compression = 0; header.pageWidth = width; header.pageHeight = bits? bits->Rows: YMAX; header.xAspect = width > LOXMAX? XASPECT: XASPECT*2; header.yAspect = YASPECT; /* If it's not just a color map give the dimensions of rasters */ if (bits) { header.w = width; header.h = bits->Rows; header.nPlanes = bits->Depth; header.x = xoff; header.y = yoff; } if (fwrite(&header, sizeof(header), 1, file) != 1) goto abort; /* Squirt out the color map */ ichunk.iff_type.b4_type = CMAP; ichunk.iff_length = MAXCOL*3; if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1) goto abort; if (fwrite(colors, (int) 3*MAXCOL, 1, file) != 1) goto abort; /* If they be bits then squirt out the bits */ if (bits) { ichunk.iff_type.b4_type = BODY; ichunk.iff_length = bits_size; if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1) goto abort; if (compressed) { if (pack_bitmap(file, bits) == 0) goto abort; } else { i = bits->Rows; row_offset = 0; while (--i >= 0) { for (j=0; jDepth; j++) { if (fwrite( bits->Planes[j]+row_offset, bits->BytesPerRow, 1, file) != 1) goto abort; } row_offset += bits->BytesPerRow; } } } #ifdef MANDEL if (ExtraSize) { /* We want to tack on an extra MAND */ if (fwrite(ExtraInfo, ExtraSize, 1, file) != 1) goto abort; } #endif MANDEL fclose(file); return 1; abort: fclose(file); return 0; } /*********************************************************************** * put_ea_cmap given an ea-type color map: * an array of unsigned chars of form ea_cmap[] = {r, g, b, r, g, b...} * turn it into an amiga-type color map: * an array of unsigned short of form amiga_cmap = {0xrgb, 0xrgb, ...} * and then tell Dale this is the colors we want for our viewport */ void put_ea_cmap(ea_cmap, colors, Screen) unsigned char *ea_cmap; int colors; struct Screen *Screen; { unsigned short amy_cmap[MAXCOL]; register int i; register short color; if (colors > MAXCOL) /* Color clipping */ colors = MAXCOL; for (i=0; i> 4; amy_cmap[i] = color; } LoadRGB4( &Screen->ViewPort, amy_cmap, (long)colors); } void get_ea_cmap(ea_cmap, colors, Screen) unsigned char *ea_cmap; int colors; struct Screen *Screen; { register long i; register unsigned short rgb; if (colors > MAXCOL) /* Color clipping */ colors = MAXCOL; for (i=0; iViewPort.ColorMap, i); *ea_cmap++ = (rgb & 0xF00) >> 4; *ea_cmap++ = (rgb & 0x0F0); *ea_cmap++ = (rgb & 0x00F) << 4; } }