/* IFF images * * dieter fiebelkorn 13.05.91 * */ #include #include #include #include #include #include #include #include "image.h" #include "imageopt.h" #include "module.h" #include "iff.h" extern char *DupString(LOAD_Structure *loadS, char *s); COLOR_ENTRY color_map[256]; static int loadIffMonoCompressed(ZFILE *zf, LOAD_Structure *loadS, char *data, unsigned int width, unsigned int height) { unsigned char wert, run; signed char command; long read, toRead; toRead = (width >> 3) + ((width & 0x0007) ? 1 : 0); toRead *= height; read = 0UL; do { command = (signed char) (*loadS->input.getchr)(zf); if (command == -128) { (*loadS->input.close)(zf); (*loadS->print.printout)("DegasLoad: Bad read on image data\n"); return(-1); } if (command < 0) { wert = (unsigned char) (*loadS->input.getchr)(zf); for (run = 0; run < -command+1; run++, read++) *data++ = wert; } else { for (run = 0; run < command+1; run++, read++) { wert = (unsigned char) (*loadS->input.getchr)(zf); *data++ = wert; } } } while (read < toRead); return(0); } static int loadIffColorCompressed(ZFILE *zf, LOAD_Structure *loadS, char *data, unsigned int width, unsigned int height, unsigned int planes, unsigned int ismask) { unsigned char wert, run, buffer[BUFSIZ]; signed char command, warning; long read; unsigned long x, y, plane, offs; unsigned long set_bit, mask; warning = '\0'; for (y= 0; y < height; y++) { for (plane= 0; plane < planes+(ismask!=0); plane++) { read = 0UL; do { command = (signed char) (*loadS->input.getchr)(zf); if (command == -128) continue; if (command < 0) { wert = (unsigned char) (*loadS->input.getchr)(zf); for (run = 0; run < -command+1; run++, read++) buffer[read] = wert; } else { for (run = 0; run < command+1; run++, read++) { wert = (unsigned char) (*loadS->input.getchr)(zf); buffer[read] = wert; } } } while (read < width/8); if (read > width/8 && warning == '\0') { (*loadS->print.printout)(" \034\001Warning:\034\100 Incorrect length of decoded scanline\n"); warning = '\x01'; } if (plane < planes) { set_bit = 1U << plane; for (x= 0; x < width/8; x++) { mask = 0x80; offs = 0; do { if (buffer[x] & mask) data[8UL * x + offs] |= set_bit; mask >>= 1; offs++; } while(mask); } } } data += width; } return(0); } static void loadIffMonoUnCompressed(ZFILE *zf, LOAD_Structure *loadS, char *data, unsigned int width, unsigned int height) { unsigned long toRead; toRead = (width >> 3) + ((width & 0x0007) ? 1 : 0); toRead *= height; (*loadS->input.read)(zf, data, toRead); } static int loadIffColorUnCompressed(ZFILE *zf, LOAD_Structure *loadS, char *data, unsigned int width, unsigned int height, unsigned int planes, unsigned int ismask) { long x, y; unsigned int buffer, plane; unsigned int mask, offs; for (y= 0; y < height; y++) { for (plane= 0; plane < planes+(ismask!=0); plane++) { for (x= 0; x < width/16; x++) { if ((*loadS->input.read)(zf, &buffer, 2UL) < 2UL) { (*loadS->error.printerr)(" Error reading IFF!"); (*loadS->input.close)(zf); return(-1); } if (plane < planes) { mask = 0x8000; offs = 0; while (mask) { if (buffer & mask) data[16*x + offs] |= 1U << plane; mask >>= 1; offs++; } } } } data += width; } return(0); } static loadIffHam(ZFILE *zf, LOAD_Structure *loadS, char *data, unsigned int width, unsigned int height, unsigned int alignwidth, unsigned int planes, unsigned int compressed) { COLOR_ENTRY color; unsigned char *new_data; unsigned int skip, x, y; unsigned int op_shift, col_shift; unsigned char op, col, col_mask; new_data = data + 2L * width * height; if (compressed) loadIffColorCompressed(zf, loadS, new_data, width, height, planes, 0); else loadIffColorUnCompressed(zf, loadS, new_data, width, height, planes, 0); if (planes != 6 && planes != 8) return(0); color.red = 0; color.green = 0; color.blue = 0; if (planes == 6) { op_shift = 4; col_mask = 0x0F; col_shift = 4; } if (planes == 8) { op_shift = 6; col_mask = 0x3F; col_shift = 2; } skip = alignwidth - width; for (y= 0; y < height; y++) { for (x= 0; x < width; x++) { op = *new_data >> op_shift; col = *new_data & col_mask; if (op == 0) { color.red = color_map[(int)col].red; color.green = color_map[(int)col].green; color.blue = color_map[(int)col].blue; } if (op == 2) { color.red = col << col_shift; } if (op == 3) { color.green = col << col_shift; } if (op == 1) { color.blue = col << col_shift; } *data++ = color.red; *data++ = color.green; *data++ = color.blue; new_data++; } data += 3L * skip; } return(0); } int iffIdent(LOAD_Structure *loadS, unsigned int verbose) { ZFILE *zf; IFF_HEADER iffheader; CHUNK_HEADER chunkheader; BITMAP_HEADER bitmapheader; int found_camgchunk, found_bitmapheader; long i; char *fullname = loadS->in_filename; if ((zf= (*loadS->input.open)(fullname, 0x00)) != NULL) { (*loadS->input.read)(zf, &iffheader, sizeof(iffheader)); while ((*(long*)&iffheader.form_id == 'FORM') && (*(long*)&iffheader.file_id != 'ILBM')) { (*loadS->input.skip)(zf, iffheader.lenght); if ((*loadS->input.read)(zf, &iffheader, sizeof(iffheader)) != sizeof(iffheader)) { (*loadS->input.close)(zf); return(0); } } if ((*(long*)&iffheader.form_id != 'FORM') || (*(long*)&iffheader.file_id != 'ILBM')) { (*loadS->input.close)(zf); return(0); } found_camgchunk = 0; found_bitmapheader = 0; while(1) { (*loadS->input.read)(zf, &chunkheader, sizeof(chunkheader)); if ((!isupper(chunkheader.chunk_id[0]) && chunkheader.chunk_id[0] != ' ') || (!isupper(chunkheader.chunk_id[1]) && chunkheader.chunk_id[1] != ' ') || (!isupper(chunkheader.chunk_id[2]) && chunkheader.chunk_id[2] != ' ') ) { (*loadS->error.printerr)(" Error reading IFF!"); break; } if (*(long*)&chunkheader.chunk_id == 'CAMG') { (*loadS->input.read)(zf, &i, sizeof(long)); if (i & 0x00000800L) found_camgchunk = 1; continue; } if (*(long*)&chunkheader.chunk_id == 'BMHD') { (*loadS->input.read)(zf, &bitmapheader, sizeof(bitmapheader)); found_bitmapheader = 1; continue; } if (*(long*)&chunkheader.chunk_id == 'BODY') { if (bitmapheader.planes == 1) (*loadS->print.printout)("%s\n is a %dx%d monochrome/duochrome IFF-image\n", fullname, bitmapheader.width, bitmapheader.height); else if (found_camgchunk == 1 && (bitmapheader.planes == 6 || bitmapheader.planes == 8)) (*loadS->print.printout)("%s\n is a %dx%d HAM-IFF-image\n", fullname, bitmapheader.width, bitmapheader.height); else (*loadS->print.printout)("%s\n is a %dx%d IFF-image with %d colors\n", fullname, bitmapheader.width, bitmapheader.height, 1U << bitmapheader.planes); (*loadS->input.close)(zf); return(found_bitmapheader); } (*loadS->input.skip)(zf, chunkheader.lenght); } } (*loadS->input.close)(zf); return(0); } Image *iffLoad(LOAD_Structure *loadS, unsigned int verbose) { ZFILE *zf; Image *image = NULL; IFF_HEADER iffheader; CHUNK_HEADER chunkheader; BITMAP_HEADER bitmapheader; int found_bitmapheader; int found_camgchunk; int found_cmapchunk; int bw_pict; long map_colors, colors, max_colors, i; unsigned long factor; char *fullname = loadS->in_filename; int id_only = loadS->identify_only; found_bitmapheader = 0; map_colors = 0; max_colors = 8; if (id_only) return((Image*)iffIdent(loadS, verbose)); if (iffIdent(loadS, verbose) == 0) return(NULL); if ((zf= (*loadS->input.open)(fullname, 0x00)) == 0) { (*loadS->error.printerr)(" Error reading IFF!"); return(NULL); } (*loadS->input.read)(zf, &iffheader, sizeof(iffheader)); while ((*(long*)&iffheader.form_id == 'FORM') && (*(long*)&iffheader.file_id != 'ILBM')) { (*loadS->input.skip)(zf, iffheader.lenght); if ((*loadS->input.read)(zf, &iffheader, sizeof(iffheader)) != sizeof(iffheader)) { (*loadS->input.close)(zf); return(0); } } found_bitmapheader = 0; found_camgchunk = 0; found_cmapchunk = 0; while (1) { (*loadS->input.read)(zf, &chunkheader, sizeof(chunkheader)); if ((!isupper(chunkheader.chunk_id[0]) && chunkheader.chunk_id[0] != ' ') || (!isupper(chunkheader.chunk_id[1]) && chunkheader.chunk_id[1] != ' ') || (!isupper(chunkheader.chunk_id[2]) && chunkheader.chunk_id[2] != ' ') ) { (*loadS->error.printerr)(" Error reading IFF!"); if (image) (*loadS->images.freeGVImage)(image); image = NULL; (*loadS->input.close)(zf); return(image); } if (*(long*)&chunkheader.chunk_id == 'BMHD') { found_bitmapheader = 1; (*loadS->input.read)(zf, &bitmapheader, sizeof(bitmapheader)); if (bitmapheader.planes > 8) { (*loadS->print.printout)(" Don't support more then 8 planes"); (*loadS->input.close)(zf); return(NULL); } if (bitmapheader.compressed > 1) { (*loadS->print.printout)(" Don't supported compression algorithm"); (*loadS->input.close)(zf); return(NULL); } if ((bitmapheader.planes == 1) && (bitmapheader.mask & 0x01)) { (*loadS->print.printout)(" Don't support monochrome Images with _mask_"); (*loadS->input.close)(zf); return(NULL); } continue; } if (*(long*)&chunkheader.chunk_id == 'CMAP') { map_colors = chunkheader.lenght / 3; if (map_colors > 256) { (*loadS->print.printout)(" Don't support more then 256 colors"); (*loadS->input.close)(zf); return(NULL); } found_cmapchunk = 1; if (map_colors <= 2) bw_pict = 1; for (i = 0; i < map_colors; i++) { (*loadS->input.read)(zf, &(color_map[i]), 3UL /*sizeof(COLOR_ENTRY)*/); if (max_colors < 256) { if (max_colors < 16) { if ((color_map[i].red > 7) || (color_map[i].green > 7) || (color_map[i].blue > 7)) max_colors = 16; } if ((color_map[i].red > 15) || (color_map[i].green > 15) || (color_map[i].blue > 15)) max_colors = 256; } if (bw_pict == 1) { switch((int)max_colors) { case 8: bw_pict &= (color_map[i].red >= 7 && color_map[i].green >= 7 && color_map[i].blue >= 7) || (color_map[i].red <= 0 && color_map[i].green <= 0 && color_map[i].blue <= 0); break; case 16: bw_pict &= (color_map[i].red >= 15 && color_map[i].green >= 15 && color_map[i].blue >= 15) || (color_map[i].red <= 0 && color_map[i].green <= 0 && color_map[i].blue <= 0); break; case 256: bw_pict &= (color_map[i].red >= 254 && color_map[i].green >= 254 && color_map[i].blue >= 254) || (color_map[i].red <= 0 && color_map[i].green <= 0 && color_map[i].blue <= 0); break; } } } continue; } if (*(long*)&chunkheader.chunk_id == 'CAMG') { (*loadS->input.read)(zf, &i, sizeof(long)); if (i & 0x00000800L) found_camgchunk = 1; continue; } if (*(long*)&chunkheader.chunk_id == 'BODY') { if (found_bitmapheader) { if (bitmapheader.planes == 1 && (found_cmapchunk == 0 || bw_pict != 0)) { if ((bitmapheader.width == 0) || (bitmapheader.height == 0)) { (*loadS->input.close)(zf); return (NULL); } image = (*loadS->images.newBitImage)(NULL, (unsigned int) bitmapheader.width, (unsigned int) bitmapheader.height); if (!image) { (*loadS->input.close)(zf); return (image); } if (bitmapheader.width % 16) { image->unalignwidth = bitmapheader.width; image->width = (bitmapheader.width += 16 - (bitmapheader.width % 16)); } if (bitmapheader.compressed) loadIffMonoCompressed(zf, loadS, image->data, bitmapheader.width, bitmapheader.height); else loadIffMonoUnCompressed(zf, loadS, image->data, bitmapheader.width, bitmapheader.height); } else { if ((bitmapheader.width == 0) || (bitmapheader.height == 0) || (bitmapheader.planes == 0)) { (*loadS->input.close)(zf); return (NULL); } if (found_camgchunk == 0 || (bitmapheader.planes != 6 && bitmapheader.planes != 8)) image = (*loadS->images.newRGBImage)(NULL, (unsigned int) bitmapheader.width, (unsigned int) bitmapheader.height, bitmapheader.planes); else image = (*loadS->images.newTCImage)(NULL, (unsigned int) bitmapheader.width, (unsigned int) bitmapheader.height); if (!image) { (*loadS->input.close)(zf); return (image); } if (bitmapheader.width % 16) { image->unalignwidth = bitmapheader.width; image->width = (bitmapheader.width += 16 - (bitmapheader.width % 16)); } if (found_camgchunk == 1 && (bitmapheader.planes == 6 || bitmapheader.planes == 8)) { if (loadIffHam(zf, loadS, image->data, bitmapheader.width, bitmapheader.height, image->width, bitmapheader.planes, bitmapheader.compressed)) { (*loadS->images.freeGVImage)(image); image = NULL; } if (image) image->title= DupString(loadS, fullname); (*loadS->input.close)(zf); return(image); } image->rgb.red [ 0]= 0xFF00; image->rgb.green[ 0]= 0xFF00; image->rgb.blue [ 0]= 0xFF00; colors = 1U << bitmapheader.planes; switch((int)max_colors) { case 8: factor = 364; break; case 16: factor = 170; break; case 256: factor = 10; break; } if (map_colors > colors) map_colors = colors; /* colors -= map_colors; */ for (i = 0; i < map_colors; i++) { image->rgb.red[i] = ((int) (factor * color_map[i].red / 10)) << 8; image->rgb.green[i] = ((int) (factor * color_map[i].green / 10)) << 8; image->rgb.blue[i] = ((int) (factor * color_map[i].blue / 10)) << 8; } image->rgb.used = (int)map_colors; for (/* i = 0 */; i < colors; i++) { image->rgb.red[i] = 0x0000; image->rgb.green[i] = 0x0000; image->rgb.blue[i] = 0x0000; } if (bitmapheader.compressed) loadIffColorCompressed(zf, loadS, image->data, bitmapheader.width, bitmapheader.height, bitmapheader.planes, bitmapheader.mask & 0x01); else if (loadIffColorUnCompressed(zf, loadS, image->data, bitmapheader.width, bitmapheader.height, bitmapheader.planes, bitmapheader.mask & 0x01) == -1) { (*loadS->images.freeGVImage)(image); image = NULL; (*loadS->input.close)(zf); return(image); } } } break; } (*loadS->input.skip)(zf, chunkheader.lenght); } if (image) image->title= DupString(loadS, fullname); (*loadS->input.close)(zf); return(image); }