home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-02 | 36.4 KB | 1,309 lines |
- /* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
- **
- ** Copyright (C) 1989 by Jef Poskanzer.
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- **
- ** Modified by Mark Thompson on 10/4/90 to accomodate 24 bit IFF files
- ** as used by ASDG, NewTek, etc.
- **
- ** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
- ** 20/Jun/93:
- ** - row-by-row operation
- ** - better de-interleave algorithm
- ** - colormap files
- ** - direct color
- ** 04/Oct/93:
- ** - multipalette support (PCHG chunk)
- ** - options -ignore, -isham, -isehb and -adjustcolors
- */
-
- #include "ppm.h"
- #include "ilbm.h"
-
- /*#define DEBUG*/
-
- /* prototypes */
- static void getfourchars ARGS(( FILE* f, char fourchars[4] ));
- static unsigned char get_byte ARGS(( FILE* f ));
- static long get_big_long ARGS((FILE *f));
- static short get_big_short ARGS((FILE *f));
- static void readerr ARGS((FILE *f));
-
- static void skip_chunk ARGS((FILE *f, long chunksize));
- static void display_chunk ARGS((FILE *ifp, char *iffid, long chunksize));
- static pixel * read_colormap ARGS((FILE *f, long colors));
- static BitMapHeader * read_bmhd ARGS((FILE *f));
- static PCHGInfo *read_pchg ARGS((FILE *ifp, unsigned long chunksize));
-
- static void ham_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd, pixel *colormap, int colors, PCHGInfo *pchginfo));
- static void deep_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd));
- static void cmap_to_ppm ARGS((pixel *colormap, int colors));
- static void std_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd, pixel *colormap, int colors, PCHGInfo *pchginfo, long viewportmodes));
- static void direct_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd, DirectColor *dcol));
-
- static void init_pchg ARGS((PCHGInfo *pchginfo, pixel *colormap, int colors, pixval newmaxval));
- static void adjust_colormap ARGS((PCHGInfo *pchginfo, int row));
- static void scale_colormap ARGS((pixel *colormap, int colors, pixval oldmaxval, pixval newmaxval));
- static pixel * ehb_to_cmap ARGS((pixel *colormap, int *colors));
- static void read_ilbm_plane ARGS((FILE *ifp, int cols, int compression));
- static void decode_row ARGS((FILE *ifp, rawtype *chunkyrow, int planes, BitMapHeader *bmhd));
-
- static rawtype * alloc_rawrow ARGS((int cols));
- static void * xmalloc ARGS((int bytes));
- #define MALLOC(n, type) (type *)xmalloc((n) * sizeof(type))
-
-
- static short verbose = 0;
- static short adjustcolors = 0;
- static unsigned char *ilbmrow;
- static pixel *pixelrow;
-
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- FILE *ifp;
- pixel *colormap = 0;
- int argn, colors;
- char iffid[5];
- short body = 0;
- long formsize, bytesread, chunksize, viewportmodes = 0, fakeviewport = 0;
- char *usage = "[-verbose] [-ignore <chunkID>] [-isham|-isehb] [-adjustcolors] [ilbmfile]";
- BitMapHeader *bmhd = NULL;
- DirectColor *dcol = NULL;
- PCHGInfo *pchginfo = NULL;
- #define MAX_IGNORE 16
- char *ignorelist[MAX_IGNORE];
- int ignorecount = 0;
-
-
- ppm_init(&argc, argv);
-
- argn = 1;
- while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
- if( pm_keymatch(argv[argn], "-verbose", 2) )
- verbose = 1;
- else
- if( pm_keymatch(argv[argn], "-noverbose", 4) )
- verbose = 0;
- else
- if( pm_keymatch(argv[argn], "-isham", 4) )
- fakeviewport |= vmHAM;
- else
- if( pm_keymatch(argv[argn], "-isehb", 4) )
- fakeviewport |= vmEXTRA_HALFBRITE;
- else
- if( pm_keymatch(argv[argn], "-adjustcolors", 2) )
- adjustcolors = 1;
- else
- if( pm_keymatch(argv[argn], "-noadjustcolors", 4) )
- adjustcolors = 0;
- else
- if( pm_keymatch(argv[argn], "-ignore", 2) ) {
- if( ++argn >= argc )
- pm_usage(usage);
- if( strlen(argv[argn]) != 4 )
- pm_error("\"-ignore\" option needs a 4 byte chunk ID string as argument");
- if( ignorecount >= MAX_IGNORE )
- pm_error("max %d chunk IDs to ignore", MAX_IGNORE);
- ignorelist[ignorecount++] = argv[argn];
- }
- else
- pm_usage(usage);
- ++argn;
- }
-
- if( argn < argc ) {
- ifp = pm_openr( argv[argn] );
- argn++;
- }
- else
- ifp = stdin;
-
- if( argn != argc )
- pm_usage(usage);
-
- /* Read in the ILBM file. */
- iffid[4] = '\0';
- getfourchars(ifp, iffid);
- if( strcmp(iffid, "FORM") != 0 )
- pm_error("input is not a FORM type IFF file");
- formsize = get_big_long(ifp);
- getfourchars(ifp, iffid);
- if( strcmp(iffid, "ILBM") != 0 )
- pm_error( "input is not an ILBM type FORM IFF file" );
- bytesread = 4; /* FORM and formsize do not count */
-
- /* Main loop, parsing the IFF FORM. */
- while( bytesread < formsize ) {
- short i, ignore = 0;
-
- getfourchars(ifp, iffid);
- chunksize = get_big_long(ifp);
- bytesread += 8;
-
- for( i = 0; i < ignorecount && !ignore; i++ ) {
- if( strcmp(ignorelist[i], iffid) == 0 )
- ignore = 1;
- }
-
- if( ignore ) {
- ignore = 0;
- pm_message("ignoring \"%s\" chunk", iffid);
- skip_chunk(ifp, chunksize);
- }
- else
- if( body != 0 ) {
- pm_message("\"%s\" chunk found after BODY chunk - skipping", iffid);
- skip_chunk(ifp, chunksize);
- }
- else
- if( strcmp(iffid, "BMHD") == 0 ) {
- if( chunksize != BitMapHeaderSize )
- pm_error("BMHD chunk size mismatch");
- bmhd = read_bmhd(ifp);
- }
- else
- if( strcmp(iffid, "CMAP") == 0 ) {
- colors = chunksize / 3;
- if( colors == 0 ) {
- pm_error("warning - empty colormap");
- skip_chunk(ifp, chunksize);
- }
- else {
- long r = 3 * colors;
- colormap = read_colormap(ifp, colors);
- while( r++ < chunksize )
- (void)get_byte(ifp);
- }
- }
- else
- if( strcmp(iffid, "CAMG") == 0 ) {
- if( chunksize != CAMGChunkSize )
- pm_error("CAMG chunk size mismatch");
- viewportmodes = get_big_long(ifp);
- }
- else
- if( strcmp(iffid, "DCOL") == 0 ) {
- if( chunksize != DirectColorSize )
- pm_error("DCOL chunk size mismatch");
- dcol = MALLOC(1, DirectColor);
- dcol->r = get_byte(ifp);
- dcol->g = get_byte(ifp);
- dcol->b = get_byte(ifp);
- (void) get_byte(ifp);
- }
- else
- if( strcmp(iffid, "PCHG") == 0 ) {
- pchginfo = read_pchg(ifp, chunksize);
- }
- else
- if( strcmp(iffid, "BODY") == 0 ) {
- if( bmhd == NULL )
- pm_error("\"BODY\" chunk without \"BMHD\" chunk");
-
- ilbmrow = MALLOC(RowBytes(bmhd->w), unsigned char);
- pixelrow = ppm_allocrow(bmhd->w);
-
- viewportmodes |= fakeviewport;
-
- if( viewportmodes & vmHAM )
- ham_to_ppm(ifp, bmhd, colormap, colors, pchginfo);
- else
- if( dcol != NULL )
- direct_to_ppm(ifp, bmhd, dcol);
- else
- if( bmhd->nPlanes == 24 )
- deep_to_ppm(ifp, bmhd);
- else
- std_to_ppm(ifp, bmhd, colormap, colors, pchginfo, viewportmodes);
- body = 1;
- }
- else
- if( strcmp(iffid, "GRAB") == 0 || strcmp(iffid, "DEST") == 0 ||
- strcmp(iffid, "SPRT") == 0 || strcmp(iffid, "CRNG") == 0 ||
- strcmp(iffid, "CCRT") == 0 || strcmp(iffid, "CLUT") == 0 ||
- strcmp(iffid, "DPPV") == 0 || strcmp(iffid, "DRNG") == 0 ||
- strcmp(iffid, "EPSF") == 0 ) {
- skip_chunk(ifp, chunksize);
- }
- else
- if( strcmp(iffid, "(c) ") == 0 || strcmp(iffid, "AUTH") == 0 ||
- strcmp(iffid, "NAME") == 0 || strcmp(iffid, "ANNO") == 0 ||
- strcmp(iffid, "TEXT") == 0 ) {
- if( verbose )
- display_chunk(ifp, iffid, chunksize);
- else
- skip_chunk(ifp, chunksize);
- }
- else
- if( strcmp(iffid, "DPI ") == 0 ) {
- int x, y;
-
- x = get_big_short(ifp);
- y = get_big_short(ifp);
- if( verbose )
- pm_message("\"DPI \" chunk: dpi_x = %d dpi_y = %d", x, y);
- }
- else {
- pm_message("unknown chunk type \"%s\" - skipping", iffid);
- skip_chunk(ifp, chunksize);
- }
-
- bytesread += chunksize;
- if( odd(chunksize) ) {
- (void) get_byte(ifp);
- ++bytesread;
- }
- }
- pm_close(ifp);
-
- if( body == 0 ) {
- if( colormap )
- cmap_to_ppm(colormap, colors);
- else
- pm_error("no \"BODY\" or \"CMAP\" chunk found");
- }
-
- if( bytesread != formsize ) {
- pm_message("warning - file length (%ld bytes) does not match FORM size field (%ld bytes) +8",
- bytesread, formsize);
- }
-
- exit(0);
- }
-
-
- static void
- readerr(f)
- FILE *f;
- {
- if( ferror(f) )
- pm_error("read error");
- else
- pm_error("premature EOF");
- }
-
-
- static unsigned char
- get_byte(ifp)
- FILE* ifp;
- {
- int i;
-
- i = getc(ifp);
- if( i == EOF )
- readerr(ifp);
-
- return (unsigned char) i;
- }
-
- static void
- getfourchars(ifp, fourchars)
- FILE* ifp;
- char fourchars[4];
- {
- fourchars[0] = get_byte(ifp);
- fourchars[1] = get_byte(ifp);
- fourchars[2] = get_byte(ifp);
- fourchars[3] = get_byte(ifp);
- }
-
-
- static long
- get_big_long(ifp)
- FILE *ifp;
- {
- long l;
-
- if( pm_readbiglong(ifp, &l) == -1 )
- readerr(ifp);
-
- return l;
- }
-
- static short
- get_big_short(ifp)
- FILE *ifp;
- {
- short s;
-
- if( pm_readbigshort(ifp, &s) == -1 )
- readerr(ifp);
-
- return s;
- }
-
-
- static void
- skip_chunk(ifp, chunksize)
- FILE *ifp;
- long chunksize;
- {
- int i;
-
- for( i = 0; i < chunksize; i++ )
- (void) get_byte(ifp);
- }
-
-
- static pixel *
- read_colormap(ifp, colors)
- FILE *ifp;
- long colors;
- {
- pixel *colormap;
- int i, r, g, b;
- pixval colmaxval = 0;
-
- colormap = ppm_allocrow(colors);
- for( i = 0; i < colors; i++ ) {
- r = get_byte(ifp); if( r > colmaxval ) colmaxval = r;
- g = get_byte(ifp); if( g > colmaxval ) colmaxval = g;
- b = get_byte(ifp); if( b > colmaxval ) colmaxval = b;
- PPM_ASSIGN(colormap[i], r, g, b);
- }
- #ifdef DEBUG
- pm_message("colormap maxval is %d", colmaxval);
- #endif
- if( colmaxval == 0 )
- pm_message("warning - black colormap");
- else
- if( colmaxval <= 15 ) {
- if( !adjustcolors ) {
- pm_message("warning - probably 4 bit colormap");
- pm_message("use \"-adjustcolors\" to scale colormap to 8 bits");
- }
- else {
- pm_message("scaling colormap to 8 bits");
- scale_colormap(colormap, colors, 15, MAXCOLVAL);
- }
- }
- return colormap;
- }
-
-
- static BitMapHeader *
- read_bmhd(ifp)
- FILE *ifp;
- {
- BitMapHeader *bmhd;
-
- bmhd = MALLOC(1, BitMapHeader);
-
- bmhd->w = get_big_short(ifp); /* cols */
- bmhd->h = get_big_short(ifp); /* rows */
- bmhd->x = get_big_short(ifp);
- bmhd->y = get_big_short(ifp);
- bmhd->nPlanes = get_byte(ifp);
- bmhd->masking = get_byte(ifp);
- bmhd->compression = get_byte(ifp);
- bmhd->pad1 = get_byte(ifp); /* (ignored) */
- bmhd->transparentColor = get_big_short(ifp);
- bmhd->xAspect = get_byte(ifp);
- bmhd->yAspect = get_byte(ifp);
- bmhd->pageWidth = get_big_short(ifp);
- bmhd->pageHeight = get_big_short(ifp);
-
- if( verbose ) {
- pm_message("dimensions: %dx%d", bmhd->w, bmhd->h);
- pm_message("BODY compression: %s", bmhd->compression <= cmpMAXKNOWN ?
- cmpNAME[bmhd->compression] : "unknown");
- }
-
- /* fix aspect ratio */
- if( bmhd->xAspect == 0 ) {
- if( bmhd->yAspect == 0 ) {
- pm_message("warning - xAspect:yAspect = 0:0, using 1:1");
- bmhd->xAspect = bmhd->yAspect = 1;
- }
- else {
- pm_message("warning - xAspect = 0, setting to yAspect");
- bmhd->xAspect = bmhd->yAspect;
- }
- }
- else {
- if( bmhd->yAspect == 0 ) {
- pm_message("warning - yAspect = 0, setting to xAspect");
- bmhd->yAspect = bmhd->xAspect;
- }
- }
- if( bmhd->xAspect != bmhd->yAspect ) {
- pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
- bmhd->xAspect > bmhd->yAspect ? 'x' : 'y',
- bmhd->xAspect > bmhd->yAspect ? (float)(bmhd->xAspect)/bmhd->yAspect : (float)(bmhd->yAspect)/bmhd->xAspect);
- }
-
- return bmhd;
- }
-
-
- static void
- ham_to_ppm(ifp, bmhd, colormap, colors, pchginfo)
- FILE *ifp;
- BitMapHeader *bmhd;
- pixel *colormap;
- int colors;
- PCHGInfo *pchginfo;
- {
- int cols, rows, hambits, hammask, col, row;
- pixval maxval;
- rawtype *rawrow;
- int pchgflag = (pchginfo && colormap);
-
- cols = bmhd->w;
- rows = bmhd->h;
- hambits = bmhd->nPlanes - 2;
- hammask = (1 << hambits) - 1;
-
- pm_message("input is a %sHAM%d file", pchgflag ? "multipalette " : "", bmhd->nPlanes);
-
- if( hambits > MAXPLANES )
- pm_error("too many planes (max %d)", MAXPLANES);
- if( hambits < 0 ) {
- pm_message("HAM requires 2 or more planes");
- pm_error("try \"-ignore CAMG\" to treat this file as a normal ILBM");
- }
-
- maxval = pm_bitstomaxval(hambits);
- if( maxval > PPM_MAXMAXVAL )
- pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n or without PPM_PACKCOLORS" );
-
- /* scale colormap to new maxval */
- if( colormap && maxval != MAXCOLVAL )
- scale_colormap(colormap, colors, MAXCOLVAL, maxval);
-
- if( pchgflag )
- init_pchg(pchginfo, colormap, colors, maxval);
-
- rawrow = alloc_rawrow(cols);
-
- ppm_writeppminit(stdout, cols, rows, maxval, 0);
- for( row = 0; row < rows; row++ ) {
- pixval r, g, b;
-
- if( pchgflag )
- adjust_colormap(pchginfo, row);
-
- decode_row(ifp, rawrow, bmhd->nPlanes, bmhd);
-
- r = g = b = 0;
- for( col = 0; col < cols; col++ ) {
- switch((rawrow[col] >> hambits) & 0x03) {
- case HAMCODE_CMAP:
- if( colormap && colors >= maxval )
- pixelrow[col] = colormap[rawrow[col] & hammask];
- else
- PPM_ASSIGN(pixelrow[col], rawrow[col] & hammask,
- rawrow[col] & hammask, rawrow[col] & hammask);
- r = PPM_GETR(pixelrow[col]);
- g = PPM_GETG(pixelrow[col]);
- b = PPM_GETB(pixelrow[col]);
- break;
- case HAMCODE_BLUE:
- b = rawrow[col] & hammask;
- PPM_ASSIGN(pixelrow[col], r, g, b);
- break;
- case HAMCODE_RED:
- r = rawrow[col] & hammask;
- PPM_ASSIGN(pixelrow[col], r, g, b);
- break;
- case HAMCODE_GREEN:
- g = rawrow[col] & hammask;
- PPM_ASSIGN(pixelrow[col], r, g, b);
- break;
- default:
- pm_error("impossible HAM code");
- }
- }
- ppm_writeppmrow(stdout, pixelrow, cols, (pixval) maxval, 0);
- }
- }
-
-
- static void
- deep_to_ppm(ifp, bmhd)
- FILE *ifp;
- BitMapHeader *bmhd;
- {
- int cols, rows, col, row;
- rawtype *Rrow, *Grow, *Brow;
-
- cols = bmhd->w;
- rows = bmhd->h;
-
- pm_message("input is a deep (24bit) ILBM");
-
- Rrow = alloc_rawrow(cols);
- Grow = alloc_rawrow(cols);
- Brow = alloc_rawrow(cols);
-
- ppm_writeppminit(stdout, cols, rows, MAXCOLVAL, 0);
- for( row = 0; row < rows; row++ ) {
- decode_row(ifp, Rrow, 8, bmhd);
- decode_row(ifp, Grow, 8, bmhd);
- decode_row(ifp, Brow, 8, bmhd);
- for( col = 0; col < cols; col++ )
- PPM_ASSIGN(pixelrow[col], Rrow[col], Grow[col], Brow[col]);
- ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0);
- }
- pm_close(stdout);
- }
-
-
- static void
- direct_to_ppm(ifp, bmhd, dcol)
- FILE *ifp;
- BitMapHeader *bmhd;
- DirectColor *dcol;
- {
- int cols, rows, col, row, redplanes, greenplanes, blueplanes;
- rawtype *Rrow, *Grow, *Brow;
- pixval maxval, redmaxval, greenmaxval, bluemaxval;
- int scale;
-
- cols = bmhd->w;
- rows = bmhd->h;
-
- redplanes = dcol->r; greenplanes = dcol->g; blueplanes = dcol->b;
-
- pm_message("input is a %d:%d:%d direct color ILBM",
- redplanes, greenplanes, blueplanes);
-
- if( redplanes > MAXPLANES || blueplanes > MAXPLANES || greenplanes > MAXPLANES )
- pm_error("too many planes (max %d per color)", MAXPLANES);
-
- if( bmhd->nPlanes != (redplanes + greenplanes + blueplanes) )
- pm_error("BMHD/DCOL plane number mismatch");
-
- if( redplanes == blueplanes && redplanes == greenplanes ) {
- scale = 0;
- maxval = pm_bitstomaxval(redplanes);
- }
- else {
- scale = 1;
- redmaxval = pm_bitstomaxval(redplanes);
- greenmaxval = pm_bitstomaxval(greenplanes);
- bluemaxval = pm_bitstomaxval(blueplanes);
-
- maxval = max(redmaxval, max(greenmaxval, bluemaxval));
- pm_message("rescaling colors to %d bits", pm_maxvaltobits(maxval));
- }
-
- if( maxval > PPM_MAXMAXVAL )
- pm_error("too many planes - try reconfiguring with PGM_BIGGRAYS\n or without PPM_PACKCOLORS" );
-
- Rrow = alloc_rawrow(cols);
- Grow = alloc_rawrow(cols);
- Brow = alloc_rawrow(cols);
-
- ppm_writeppminit(stdout, cols, rows, maxval, 0);
- for( row = 0; row < rows; row++ ) {
- decode_row(ifp, Rrow, dcol->r, bmhd);
- decode_row(ifp, Grow, dcol->g, bmhd);
- decode_row(ifp, Brow, dcol->b, bmhd);
-
- if( scale ) {
- for( col = 0; col < cols; col++ ) {
- PPM_ASSIGN(pixelrow[col],
- Rrow[col] * maxval / redmaxval,
- Grow[col] * maxval / greenmaxval,
- Brow[col] * maxval / bluemaxval);
- }
- }
- else {
- for( col = 0; col < cols; col++ )
- PPM_ASSIGN(pixelrow[col], Rrow[col], Grow[col], Brow[col]);
- }
- ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
- }
- pm_close(stdout);
- }
-
-
- static void
- cmap_to_ppm(colormap, colors)
- pixel *colormap;
- int colors;
- {
- pm_message("input is a colormap file");
-
- ppm_writeppminit(stdout, colors, 1, MAXCOLVAL, 0);
- ppm_writeppmrow(stdout, colormap, colors, MAXCOLVAL, 0);
- pm_close(stdout);
- }
-
-
- static void
- std_to_ppm(ifp, bmhd, colormap, colors, pchginfo, viewportmodes)
- FILE *ifp;
- BitMapHeader *bmhd;
- pixel *colormap;
- int colors;
- PCHGInfo *pchginfo;
- long viewportmodes;
- {
- rawtype *rawrow;
- pixval maxval;
- int row, rows, col, cols;
- int pchgflag = (pchginfo && colormap);
-
- cols = bmhd->w;
- rows = bmhd->h;
-
- pm_message("input is a %d-plane %s%sILBM", bmhd->nPlanes,
- pchgflag ? "multipalette " : "",
- viewportmodes & vmEXTRA_HALFBRITE ? "EHB " : ""
- );
-
- if( bmhd->nPlanes > MAXPLANES )
- pm_error("too many planes (max %d)", MAXPLANES);
-
- if( colormap )
- maxval = MAXCOLVAL;
- else {
- maxval = pm_bitstomaxval(bmhd->nPlanes);
- pm_message("no colormap - interpreting values as grayscale");
- }
- if( maxval > PPM_MAXMAXVAL )
- pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n or without PPM_PACKCOLORS" );
-
- if( pchgflag )
- init_pchg(pchginfo, colormap, colors, maxval);
-
- rawrow = alloc_rawrow(cols);
-
- if( viewportmodes & vmEXTRA_HALFBRITE )
- colormap = ehb_to_cmap(colormap, &colors);
-
- ppm_writeppminit( stdout, cols, rows, (pixval) maxval, 0 );
- for( row = 0; row < rows; row++ ) {
-
- if( pchgflag )
- adjust_colormap(pchginfo, row);
-
- decode_row(ifp, rawrow, bmhd->nPlanes, bmhd);
- for( col = 0; col < cols; col++ ) {
- if( colormap )
- pixelrow[col] = colormap[rawrow[col]];
- else
- PPM_ASSIGN(pixelrow[col], rawrow[col], rawrow[col], rawrow[col]);
- }
- ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
- }
- }
-
-
- static pixel *
- ehb_to_cmap(colormap, colors)
- pixel *colormap;
- int *colors;
- {
- pixel *tempcolormap = NULL;
- int i, col;
-
- if( colormap ) {
- col = *colors;
- tempcolormap = ppm_allocrow(col * 2);
- for( i = 0; i < col; i++ ) {
- tempcolormap[i] = colormap[i];
- PPM_ASSIGN(tempcolormap[col + i], PPM_GETR(colormap[i]) / 2,
- PPM_GETG(colormap[i]) / 2, PPM_GETB(colormap[i]) / 2 );
- }
- ppm_freerow(colormap);
- *colors *= 2;
- }
- return tempcolormap;
- }
-
-
- static void
- read_ilbm_plane(ifp, cols, compression)
- FILE *ifp;
- int cols, compression;
- {
- unsigned char *ubp;
- int bytes, j, byte;
-
- bytes = RowBytes(cols);
-
- switch(compression) {
- case cmpNone:
- j = fread(ilbmrow, 1, bytes, ifp);
- if( j != bytes )
- readerr(ifp);
- break;
- case cmpByteRun1:
- ubp = ilbmrow;
- do {
- byte = (int)get_byte(ifp);
- if( byte <= 127 ) {
- j = byte;
- bytes -= (j+1);
- if( bytes < 0 )
- pm_error("error doing ByteRun1 decompression");
- for( ; j >= 0; j-- )
- *ubp++ = get_byte(ifp);
- }
- else
- if ( byte != 128 ) {
- j = 256 - byte;
- bytes -= (j+1);
- if( bytes < 0 )
- pm_error("error doing ByteRun1 decompression");
- byte = (int)get_byte(ifp);
- for( ; j >= 0; j-- )
- *ubp++ = (unsigned char)byte;
- }
- /* 128 is a NOP */
- }
- while( bytes > 0 );
- break;
- default:
- pm_error("unknown compression type");
- }
- }
-
-
- const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
-
- static void
- decode_row(ifp, chunkyrow, nPlanes, bmhd)
- FILE *ifp;
- rawtype *chunkyrow;
- int nPlanes;
- BitMapHeader *bmhd;
- {
- int plane, col, cols;
- unsigned char *ilp;
- rawtype *chp;
-
- cols = bmhd->w;
- for( plane = 0; plane < nPlanes; plane++ ) {
- int mask, cbit;
-
- mask = 1 << plane;
- read_ilbm_plane(ifp, cols, bmhd->compression);
-
- ilp = ilbmrow;
- chp = chunkyrow;
-
- cbit = 7;
- for( col = 0; col < cols; col++, cbit--, chp++ ) {
- if( cbit < 0 ) {
- cbit = 7;
- ilp++;
- }
- if( *ilp & bit_mask[cbit] )
- *chp |= mask;
- else
- *chp &= ~mask;
- }
- }
- /* skip mask plane */
- if( bmhd->masking == mskHasMask )
- read_ilbm_plane(ifp, cols, bmhd->compression);
- }
-
-
- static rawtype *
- alloc_rawrow(cols)
- int cols;
- {
- rawtype *r;
- int i;
-
- r = MALLOC(cols, rawtype);
-
- for( i = 0; i < cols; i++ )
- r[i] = 0;
-
- return r;
- }
-
-
- static void *
- xmalloc(bytes)
- int bytes;
- {
- void *mem;
-
- if( bytes == 0 )
- return NULL;
-
- mem = malloc(bytes);
- if( mem == NULL )
- pm_error("out of memory allocating %d bytes", bytes);
- return mem;
- }
-
-
- static void
- display_chunk(ifp, iffid, chunksize)
- FILE *ifp;
- char *iffid;
- long chunksize;
- {
- int byte;
-
- pm_message("contents of \"%s\" chunk:", iffid);
-
- while( chunksize-- ) {
- byte = get_byte(ifp);
- if( fputc(byte, stderr) == EOF )
- pm_error("write error");
- }
- if( fputc('\n', stderr) == EOF )
- pm_error("write error");
- }
-
- /*
- * PCHG stuff
- */
-
- static void PCHG_Decompress ARGS((PCHGHeader *PCHG, PCHGCompHeader *CompHdr, unsigned char *compdata, unsigned long compsize, unsigned char *comptree, unsigned char *data));
- static unsigned char * PCHG_MakeMask ARGS((PCHGHeader *PCHG, unsigned char *data, unsigned long datasize, unsigned char **newdata));
- static void PCHG_ConvertSmall ARGS((PCHGInfo *Info, unsigned char *data, unsigned long datasize));
- static void PCHG_ConvertBig ARGS((PCHGInfo *Info, unsigned char *data, unsigned long datasize));
- static void PCHG_DecompHuff ARGS((unsigned char *src, unsigned char *dest, short *tree, unsigned long origsize));
- static void pchgerr ARGS((char *when));
-
- /* Turn big-endian 4-byte long and 2-byte short stored at x (unsigned char *)
- * into the native format of the CPU
- */
- #define BIG_LONG(x) ( ((unsigned long)((x)[0]) << 24) + \
- ((unsigned long)((x)[1]) << 16) + \
- ((unsigned long)((x)[2]) << 8) + \
- ((unsigned long)((x)[3]) << 0) )
- #define BIG_WORD(x) ( ((unsigned short)((x)[0]) << 8) + \
- ((unsigned short)((x)[1]) << 0) )
-
-
- static PCHGInfo *
- read_pchg(ifp, bytesleft)
- FILE *ifp;
- unsigned long bytesleft;
- {
- static PCHGInfo Info;
- PCHGCompHeader CompHdr;
- PCHGHeader *PCHG;
- unsigned char *data, *chdata;
- unsigned long datasize;
-
- #ifdef DEBUG
- pm_message("PCHG chunk found");
- #endif
-
- if( bytesleft < PCHGHeaderSize )
- pchgerr("while reading PCHGHeader");
-
- Info.PCHG = PCHG = MALLOC(1, PCHGHeader);
- PCHG->Compression = get_big_short(ifp);
- PCHG->Flags = get_big_short(ifp);
- PCHG->StartLine = get_big_short(ifp);
- PCHG->LineCount = get_big_short(ifp);
- PCHG->ChangedLines= get_big_short(ifp);
- PCHG->MinReg = get_big_short(ifp);
- PCHG->MaxReg = get_big_short(ifp);
- PCHG->MaxChanges = get_big_short(ifp);
- PCHG->TotalChanges= get_big_long(ifp);
- bytesleft -= PCHGHeaderSize;
-
- #ifdef DEBUG
- pm_message("PCHG StartLine : %d", PCHG->StartLine);
- pm_message("PCHG LineCount : %d", PCHG->LineCount);
- pm_message("PCHG ChangedLines: %d", PCHG->ChangedLines);
- pm_message("PCHG TotalChanges: %d", PCHG->TotalChanges);
- #endif
-
- if( PCHG->Compression != PCHG_COMP_NONE ) {
- unsigned char *compdata, *comptree;
- unsigned long treesize;
-
- if( bytesleft < PCHGCompHeaderSize )
- pchgerr("while reading PCHGCompHeader");
-
- CompHdr.CompInfoSize = get_big_long(ifp);
- CompHdr.OriginalDataSize = get_big_long(ifp);
- bytesleft -= PCHGCompHeaderSize;
- treesize = CompHdr.CompInfoSize;
- datasize = CompHdr.OriginalDataSize;
-
- if( bytesleft < treesize )
- pchgerr("while reading compression info data");
-
- comptree = MALLOC(treesize, unsigned char);
- if( fread(comptree, 1, treesize, ifp) != treesize )
- readerr(ifp);
-
- bytesleft -= treesize;
- if( bytesleft == 0 )
- pchgerr("while reading compressed change structure data");
-
- compdata= MALLOC(bytesleft, unsigned char);
- data = MALLOC(datasize, unsigned char);
-
- if( fread(compdata, 1, bytesleft, ifp) != bytesleft )
- readerr(ifp);
-
- PCHG_Decompress(PCHG, &CompHdr, compdata, bytesleft, comptree, data);
- free(comptree);
- free(compdata);
- bytesleft = 0;
- }
- else {
- #ifdef DEBUG
- pm_message("uncompressed PCHG");
- #endif
- if( bytesleft == 0 )
- pchgerr("while reading uncompressed change structure data");
-
- datasize = bytesleft;
- data = MALLOC(datasize, unsigned char);
- if( fread(data, 1, datasize, ifp) != datasize )
- readerr(ifp);
- bytesleft = 0;
- }
-
- Info.LineMask = PCHG_MakeMask(PCHG, data, datasize, &chdata);
- datasize -= (chdata - data);
-
- Info.Palette = MALLOC(PCHG->TotalChanges, PaletteChange);
- Info.Change = MALLOC(PCHG->ChangedLines, LineChanges);
-
- if( PCHG->Flags & PCHGF_USE_ALPHA )
- pm_message("warning - PCHG alpha channel not supported");
-
- if( PCHG->Flags & PCHGF_12BIT ) {
- #ifdef DEBUG
- pm_message("SmallLineChanges");
- #endif
- PCHG_ConvertSmall(&Info, chdata, datasize);
- }
- else
- if( PCHG->Flags & PCHGF_32BIT ) {
- #ifdef DEBUG
- pm_message("BigLineChanges");
- #endif
- PCHG_ConvertBig(&Info, chdata, datasize);
- }
- else
- pm_error("unknown palette changes structure format in PCHG chunk");
-
- free(data);
- return &Info;
- }
-
-
- static void
- PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
- PCHGHeader *PCHG;
- PCHGCompHeader *CompHdr;
- unsigned char *compdata;
- unsigned long compsize;
- unsigned char *comptree;
- unsigned char *data;
- {
- short *hufftree;
- unsigned long huffsize, i;
- unsigned long treesize = CompHdr->CompInfoSize;
-
- switch( PCHG->Compression ) {
- case PCHG_COMP_HUFFMAN:
-
- #ifdef DEBUG
- pm_message("PCHG Huffman compression");
- #endif
- /* turn big-endian 2-byte shorts into native format */
- huffsize = treesize/2;
- hufftree = MALLOC(huffsize, short);
- for( i = 0; i < huffsize; i++ ) {
- hufftree[i] = (short)BIG_WORD(comptree);
- comptree += 2;
- }
-
- /* decompress the change structure data */
- PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], CompHdr->OriginalDataSize);
-
- free(hufftree);
- break;
- default:
- pm_error("unknown PCHG compression type");
- }
- }
-
-
- static unsigned char *
- PCHG_MakeMask(PCHG, data, datasize, newdata)
- PCHGHeader *PCHG;
- unsigned char *data;
- unsigned long datasize;
- unsigned char **newdata;
- {
- unsigned long bytes;
- unsigned char *mask;
-
- /* the mask at 'data' is in 4-byte big-endian longword format,
- * thus we can simply treat it at unsigned char and don't have
- * to convert it, just copy it to a new mem block so we can
- * free the original data
- */
- bytes = MaskLongWords(PCHG->LineCount) * 4;
- if( datasize < bytes )
- pchgerr("for line mask");
- mask = MALLOC(bytes, unsigned char);
-
- #ifdef DEBUG
- pm_message("%ld bytes for line mask", bytes);
- #endif
- bcopy(data, mask, bytes);
-
- *newdata = (data + bytes);
- return mask;
- }
-
-
- static void
- PCHG_ConvertSmall(Info, data, datasize)
- PCHGInfo *Info;
- unsigned char *data;
- unsigned long datasize;
- {
- PCHGHeader *PCHG = Info->PCHG;
- LineChanges *Change = Info->Change;
- PaletteChange *Palette = Info->Palette;
- unsigned long i, palettecount = 0;
- unsigned char ChangeCount16, ChangeCount32;
- unsigned short SmallChange;
-
- Info->maxval = 15; /* 4 bit values */
-
- for( i = 0; i < PCHG->ChangedLines; i++ ) {
- int n;
-
- if( datasize < 2 ) goto fail;
- ChangeCount16 = *data++;
- ChangeCount32 = *data++;
- datasize -= 2;
-
- Change[i].Count = ChangeCount16 + ChangeCount32;
- Change[i].Palette = &Palette[palettecount];
-
- for(n = 0; n < Change[i].Count; n++ ) {
- if( palettecount >= PCHG->TotalChanges ) goto fail;
- if( datasize < 2 ) goto fail;
- SmallChange = BIG_WORD(data);
- data += 2; datasize -= 2;
-
- Palette[palettecount].Register = (SmallChange >> 12) & 0x0f;
- if( n >= ChangeCount16 )
- Palette[palettecount].Register += 16;
- Palette[palettecount].Alpha = 0;
- Palette[palettecount].Red = (SmallChange >> 8) & 0x0f;
- Palette[palettecount].Green = (SmallChange >> 4) & 0x0f;
- Palette[palettecount].Blue = SmallChange & 0x0f;
- palettecount++;
- }
- }
- #ifdef DEBUG
- pm_message("%ld palette change structures", palettecount);
- #endif
- return;
- fail:
- pchgerr("while building SmallLineChanges array");
- }
-
-
- static void
- PCHG_ConvertBig(Info, data, datasize)
- PCHGInfo *Info;
- unsigned char *data;
- unsigned long datasize;
- {
- PCHGHeader *PCHG = Info->PCHG;
- LineChanges *Change = Info->Change;
- PaletteChange *Palette = Info->Palette;
- unsigned long i, palettecount = 0;
-
- Info->maxval = MAXCOLVAL;
-
- for( i = 0; i < PCHG->ChangedLines; i++ ) {
- int n;
-
- if( datasize < 2 ) goto fail;
- Change[i].Count = BIG_WORD(data);
- data += 2; datasize -= 2;
-
- Change[i].Palette = &Palette[palettecount];
-
- for( n = 0; n < Change[i].Count; n++ ) {
- if( palettecount >= PCHG->TotalChanges ) goto fail;
- if( datasize < 6 ) goto fail;
- Palette[palettecount].Register = BIG_WORD(data);
- data += 2;
- Palette[palettecount].Alpha = *data++;
- Palette[palettecount].Red = *data++;
- Palette[palettecount].Blue = *data++; /* yes, RBG */
- Palette[palettecount].Green = *data++;
- palettecount++;
- datasize -= 6;
- }
- }
- #ifdef DEBUG
- pm_message("%ld palette change structures", palettecount);
- #endif
- return;
- fail:
- pchgerr("while building BigLineChanges array");
- }
-
-
- static void
- pchgerr(when)
- char *when;
- {
- pm_message("insufficient data in PCHG chunk %s", when);
- pm_error("try the \"-ignore\" option to skip this chunk");
- }
-
-
- static void
- PCHG_DecompHuff(src, dest, tree, origsize)
- unsigned char *src, *dest;
- short *tree;
- unsigned long origsize;
- {
- unsigned long i = 0, bits = 0;
- unsigned char thisbyte;
- short *p;
-
- p = tree;
- while( i < origsize ) {
- if( bits == 0 ) {
- thisbyte = *src++;
- bits = 8;
- }
- if( thisbyte & (1 << 7) ) {
- if( *p >= 0 ) {
- *dest++ = (unsigned char)*p;
- i++;
- p = tree;
- }
- else
- p += (*p / 2);
- }
- else {
- p--;
- if( *p > 0 && (*p & 0x100) ) {
- *dest++ = (unsigned char )*p;
- i++;
- p = tree;
- }
- }
- thisbyte <<= 1;
- bits--;
- }
- }
-
-
- static void
- init_pchg(pchginfo, colormap, colors, newmaxval)
- PCHGInfo *pchginfo;
- pixel *colormap;
- int colors;
- pixval newmaxval;
- {
- PCHGHeader *PCHG = pchginfo->PCHG;
- pixval oldmaxval = pchginfo->maxval;
- int row;
-
- pchginfo->colormap = colormap;
- pchginfo->colors = colors;
-
- if( oldmaxval != newmaxval ) {
- PaletteChange *Palette = pchginfo->Palette;
- unsigned long i;
-
- #ifdef DEBUG
- pm_message("scaling PCHG palette from %d to %d", oldmaxval, newmaxval);
- #endif
-
- for( i = 0; i < PCHG->TotalChanges; i++ ) {
- Palette[i].Red = Palette[i].Red * newmaxval / oldmaxval;
- Palette[i].Green= Palette[i].Green * newmaxval / oldmaxval;
- Palette[i].Blue = Palette[i].Blue * newmaxval / oldmaxval;
- }
- pchginfo->maxval = newmaxval;
- }
-
- for( row = PCHG->StartLine; row < 0; row++ )
- adjust_colormap(pchginfo, row);
- }
-
-
- static void
- adjust_colormap(pchginfo, row)
- PCHGInfo *pchginfo;
- int row;
- {
- static unsigned long maskcount, changecount;
- static unsigned char thismask;
- static int bits;
-
- PCHGHeader *PCHG = pchginfo->PCHG;
-
- if( row < PCHG->StartLine || changecount >= PCHG->ChangedLines )
- return;
-
- if( bits == 0 ) {
- thismask = pchginfo->LineMask[maskcount++];
- bits = 8;
- }
-
- if( thismask & (1 << 7) ) {
- int i;
-
- for( i = 0; i < pchginfo->Change[changecount].Count; i++ ) {
- PaletteChange *pal = &(pchginfo->Change[changecount].Palette[i]);
- int reg = pal->Register;
-
- if( reg >= pchginfo->colors ) {
- pm_message("warning - PCHG palette change register value out of range");
- pm_message(" row %d change structure %ld palette %d", row, changecount, i);
- pm_message(" ignoring it... colors might get messed up from here");
- }
- else
- PPM_ASSIGN(pchginfo->colormap[reg], pal->Red, pal->Green, pal->Blue);
- }
- changecount++;
- }
- thismask <<= 1;
- bits--;
- }
-
-
- static void
- scale_colormap(colormap, colors, oldmaxval, newmaxval)
- pixel *colormap;
- int colors;
- pixval oldmaxval, newmaxval;
- {
- int i, r, g, b;
-
- for( i = 0; i < colors; i++ ) {
- r = PPM_GETR(colormap[i]) * newmaxval / oldmaxval;
- g = PPM_GETG(colormap[i]) * newmaxval / oldmaxval;
- b = PPM_GETB(colormap[i]) * newmaxval / oldmaxval;
- PPM_ASSIGN(colormap[i], r, g, b);
- }
- }
-
-