jimf@saber.com (09/28/90)
Submitted-by: saber.com!jimf@saber.com Posting-number: Volume 9, Issue 51 Archive-name: xloadimage/part04 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 4 (of 9)." # Contents: gif.c halftone.c hash.c mac.c merge.c new.c # Wrapped by jimf@armory on Tue Sep 25 19:37:40 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'gif.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'gif.c'\" else echo shar: Extracting \"'gif.c'\" \(14417 characters\) sed "s/^X//" >'gif.c' <<'END_OF_FILE' X/* gif.c: X * X * adapted from code by kirk johnson (tuna@athena.mit.edu). most of this X * code is unchanged. -- jim frost 12.31.89 X * X * gifin.c X * kirk johnson X * november 1989 X * X * routines for reading GIF files X * X * Copyright 1989 Kirk L. Johnson (see the included file X * "kljcpyrght.h" for complete copyright information) X */ X X#include "image.h" X#include "gif.h" X#include "kljcpyrght.h" X X/**** X ** X ** local #defines X ** X ****/ X X#define PUSH_PIXEL(p) \ X{ \ X if (pstk_idx == PSTK_SIZE) \ X gifin_fatal("pixel stack overflow in PUSH_PIXEL()"); \ X else \ X pstk[pstk_idx++] = (p); \ X} X X X/**** X ** X ** local variables X ** X ****/ X Xstatic int interlace_start[4]= { /* start line for interlacing */ X 0, 4, 2, 1 X}; X Xstatic int interlace_rate[4]= { /* rate at which we accelerate vertically */ X 8, 8, 4, 2 X}; X Xstatic BYTE file_open = 0; /* status flags */ Xstatic BYTE image_open = 0; X Xstatic ZFILE *ins; /* input stream */ X Xstatic int root_size; /* root code size */ Xstatic int clr_code; /* clear code */ Xstatic int eoi_code; /* end of information code */ Xstatic int code_size; /* current code size */ Xstatic int code_mask; /* current code mask */ Xstatic int prev_code; /* previous code */ X X/* X * NOTE: a long is assumed to be at least 32 bits wide X */ Xstatic long work_data; /* working bit buffer */ Xstatic int work_bits; /* working bit count */ X Xstatic BYTE buf[256]; /* byte buffer */ Xstatic int buf_cnt; /* byte count */ Xstatic int buf_idx; /* buffer index */ X Xstatic int table_size; /* string table size */ Xstatic int prefix[STAB_SIZE]; /* string table : prefixes */ Xstatic int extnsn[STAB_SIZE]; /* string table : extensions */ X Xstatic BYTE pstk[PSTK_SIZE]; /* pixel stack */ Xstatic int pstk_idx; /* pixel stack pointer */ X X X/**** X ** X ** global variables X ** X ****/ X Xstatic int gifin_rast_width; /* raster width */ Xstatic int gifin_rast_height; /* raster height */ Xstatic BYTE gifin_g_cmap_flag; /* global colormap flag */ Xstatic int gifin_g_pixel_bits; /* bits per pixel, global colormap */ Xstatic int gifin_g_ncolors; /* number of colors, global colormap */ Xstatic BYTE gifin_g_cmap[3][256]; /* global colormap */ Xstatic int gifin_bg_color; /* background color index */ Xstatic int gifin_color_bits; /* bits of color resolution */ X Xstatic int gifin_img_left; /* image position on raster */ Xstatic int gifin_img_top; /* image position on raster */ Xstatic int gifin_img_width; /* image width */ Xstatic int gifin_img_height; /* image height */ Xstatic BYTE gifin_l_cmap_flag; /* local colormap flag */ Xstatic int gifin_l_pixel_bits; /* bits per pixel, local colormap */ Xstatic int gifin_l_ncolors; /* number of colors, local colormap */ Xstatic BYTE gifin_l_cmap[3][256]; /* local colormap */ Xstatic BYTE gifin_interlace_flag; /* interlace image format flag */ X X/* X * open a GIF file, using s as the input stream X */ X Xstatic int gifin_open_file(s) X ZFILE *s; X{ X /* make sure there isn't already a file open */ X if (file_open) X return GIFIN_ERR_FAO; X X /* remember that we've got this file open */ X file_open = 1; X ins = s; X X /* check GIF signature */ X if (zread(ins, buf, GIF_SIG_LEN) != GIF_SIG_LEN) X return GIFIN_ERR_EOF; X X buf[GIF_SIG_LEN] = '\0'; X if (strcmp((char *) buf, GIF_SIG) != 0) X return GIFIN_ERR_BAD_SIG; X X /* read screen descriptor */ X if (zread(ins, buf, GIF_SD_SIZE) != GIF_SD_SIZE) X return GIFIN_ERR_EOF; X X /* decode screen descriptor */ X gifin_rast_width = (buf[1] << 8) + buf[0]; X gifin_rast_height = (buf[3] << 8) + buf[2]; X gifin_g_cmap_flag = (buf[4] & 0x80) ? 1 : 0; X gifin_color_bits = ((buf[4] & 0x70) >> 4) + 1; X gifin_g_pixel_bits = (buf[4] & 0x07) + 1; X gifin_bg_color = buf[5]; X X if (buf[6] != 0) X return GIFIN_ERR_BAD_SD; X X /* load global colormap */ X if (gifin_g_cmap_flag) X { X gifin_g_ncolors = (1 << gifin_g_pixel_bits); X X if (gifin_load_cmap(gifin_g_cmap, gifin_g_ncolors) != GIFIN_SUCCESS) X return GIFIN_ERR_EOF; X } X else X { X gifin_g_ncolors = 0; X } X X /* done! */ X return GIFIN_SUCCESS; X} X X X/* X * open next GIF image in the input stream; returns GIFIN_SUCCESS if X * successful. if there are no more images, returns GIFIN_DONE. (might X * also return various GIFIN_ERR codes.) X */ X Xstatic int gifin_open_image() X{ X int i; X int separator; X X /* make sure there's a file open */ X if (!file_open) X return GIFIN_ERR_NFO; X X /* make sure there isn't already an image open */ X if (image_open) X return GIFIN_ERR_IAO; X X /* remember that we've got this image open */ X image_open = 1; X X /* skip over any extension blocks */ X do X { X separator = zgetc(ins); X if (separator == GIF_EXTENSION) X { X if (gifin_skip_extension() != GIFIN_SUCCESS) X return GIFIN_ERR_EOF; X } X } X while (separator == GIF_EXTENSION); X X /* check for end of file marker */ X if (separator == GIF_TERMINATOR) X return GIFIN_DONE; X X /* make sure we've got an image separator */ X if (separator != GIF_SEPARATOR) X return GIFIN_ERR_BAD_SEP; X X /* read image descriptor */ X if (zread(ins, buf, GIF_ID_SIZE) != GIF_ID_SIZE) X return GIFIN_ERR_EOF; X X /* decode image descriptor */ X gifin_img_left = (buf[1] << 8) + buf[0]; X gifin_img_top = (buf[3] << 8) + buf[2]; X gifin_img_width = (buf[5] << 8) + buf[4]; X gifin_img_height = (buf[7] << 8) + buf[6]; X gifin_l_cmap_flag = (buf[8] & 0x80) ? 1 : 0; X gifin_interlace_flag = (buf[8] & 0x40) ? 1 : 0; X gifin_l_pixel_bits = (buf[8] & 0x07) + 1; X X /* load local colormap */ X if (gifin_l_cmap_flag) X { X gifin_l_ncolors = (1 << gifin_l_pixel_bits); X X if (gifin_load_cmap(gifin_l_cmap, gifin_l_ncolors) != GIFIN_SUCCESS) X return GIFIN_ERR_EOF; X } X else X { X gifin_l_ncolors = 0; X } X X /* initialize raster data stream decoder */ X root_size = zgetc(ins); X clr_code = 1 << root_size; X eoi_code = clr_code + 1; X code_size = root_size + 1; X code_mask = (1 << code_size) - 1; X work_bits = 0; X work_data = 0; X buf_cnt = 0; X buf_idx = 0; X X /* initialize string table */ X for (i=0; i<STAB_SIZE; i++) X { X prefix[i] = NULL_CODE; X extnsn[i] = i; X } X X /* initialize pixel stack */ X pstk_idx = 0; X X /* done! */ X return GIFIN_SUCCESS; X} X X/* X * try to read next pixel from the raster, return result in *pel X */ X Xstatic int gifin_get_pixel(pel) X int *pel; X{ X int code; X int first; X int place; X X /* decode until there are some pixels on the pixel stack */ X while (pstk_idx == 0) X { X /* load bytes until we have enough bits for another code */ X while (work_bits < code_size) X { X if (buf_idx == buf_cnt) X { X /* read a new data block */ X if (gifin_read_data_block() != GIFIN_SUCCESS) X return GIFIN_ERR_EOF; X X if (buf_cnt == 0) X return GIFIN_ERR_EOD; X } X X work_data |= ((long) buf[buf_idx++]) << work_bits; X work_bits += 8; X } X X /* get the next code */ X code = work_data & code_mask; X work_data >>= code_size; X work_bits -= code_size; X X /* interpret the code */ X if (code == clr_code) X { X /* reset decoder stream */ X code_size = root_size + 1; X code_mask = (1 << code_size) - 1; X prev_code = NULL_CODE; X table_size = eoi_code + 1; X } X else if (code == eoi_code) X { X /* Ooops! no more pixels */ X return GIFIN_ERR_EOF; X } X else if (prev_code == NULL_CODE) X { X gifin_push_string(code); X prev_code = code; X } X else X { X if (code < table_size) X { X first = gifin_push_string(code); X } X else X { X place = pstk_idx; X PUSH_PIXEL(NULL_CODE); X first = gifin_push_string(prev_code); X pstk[place] = first; X } X X gifin_add_string(prev_code, first); X prev_code = code; X } X } X X /* pop a pixel off the pixel stack */ X *pel = (int) pstk[--pstk_idx]; X X /* done! */ X return GIFIN_SUCCESS; X} X X X/* X * close an open GIF image X */ X Xstatic int gifin_close_image() X{ X /* make sure there's an image open */ X if (!image_open) X return GIFIN_ERR_NIO; X X /* skip any remaining raster data */ X do X { X if (gifin_read_data_block() != GIFIN_SUCCESS) X return GIFIN_ERR_EOF; X } X while (buf_cnt > 0); X X /* mark image as closed */ X image_open = 0; X X /* done! */ X return GIFIN_SUCCESS; X} X X X/* X * close an open GIF file X */ X Xstatic int gifin_close_file() X{ X /* make sure there's a file open */ X if (!file_open) X return GIFIN_ERR_NFO; X X /* mark file (and image) as closed */ X file_open = 0; X image_open = 0; X X /* done! */ X return GIFIN_SUCCESS; X} X X/* X * load a colormap from the input stream X */ X Xstatic int gifin_load_cmap(cmap, ncolors) X BYTE cmap[3][256]; X int ncolors; X{ X int i; X X for (i=0; i<ncolors; i++) X { X if (zread(ins, buf, 3) != 3) X return GIFIN_ERR_EOF; X X cmap[GIF_RED][i] = buf[GIF_RED]; X cmap[GIF_GRN][i] = buf[GIF_GRN]; X cmap[GIF_BLU][i] = buf[GIF_BLU]; X } X X /* done! */ X return GIFIN_SUCCESS; X} X X/* X * skip an extension block in the input stream X */ X Xstatic int gifin_skip_extension() X{ X int function; X X /* get the extension function byte */ X function = zgetc(ins); X X /* skip any remaining raster data */ X do X { X if (gifin_read_data_block() != GIFIN_SUCCESS) X return GIFIN_ERR_EOF; X } X while (buf_cnt > 0); X X /* done! */ X return GIFIN_SUCCESS; X} X X/* X * read a new data block from the input stream X */ X Xstatic int gifin_read_data_block() X{ X /* read the data block header */ X buf_cnt = zgetc(ins); X X /* read the data block body */ X if (zread(ins, buf, buf_cnt) != buf_cnt) X return GIFIN_ERR_EOF; X X buf_idx = 0; X X /* done! */ X return GIFIN_SUCCESS; X} X X/* X * push a string (denoted by a code) onto the pixel stack X * (returns the code of the first pixel in the string) X */ X Xstatic int gifin_push_string(code) X int code; X{ X int rslt; X X while (prefix[code] != NULL_CODE) X { X PUSH_PIXEL(extnsn[code]); X code = prefix[code]; X } X X PUSH_PIXEL(extnsn[code]); X rslt = extnsn[code]; X X return rslt; X} X X/* X * add a new string to the string table X */ X Xstatic gifin_add_string(p, e) X int p; X int e; X{ X prefix[table_size] = p; X extnsn[table_size] = e; X X if ((table_size == code_mask) && (code_size < 12)) X { X code_size += 1; X code_mask = (1 << code_size) - 1; X } X X table_size += 1; X} X X/* X * semi-graceful fatal error mechanism X */ X Xstatic gifin_fatal(msg) X char *msg; X{ X printf("Error reading GIF file: %s\n", msg); X exit(0); X} X X/* these are the routines added for interfacing to xloadimage X */ X X/* tell someone what the image we're loading is. this could be a little more X * descriptive but I don't care X */ X Xstatic void tellAboutImage(name) X char *name; X{ X printf("%s is a %dx%d %sGIF image with %d colors\n", name, X gifin_img_width, gifin_img_height, X (gifin_interlace_flag ? "interlaced " : ""), X (gifin_l_cmap_flag ? gifin_l_ncolors : gifin_g_ncolors)); X} X XImage *gifLoad(fullname, name, verbose) X char *fullname, *name; X unsigned int verbose; X{ ZFILE *zf; X Image *image; X int x, y, pixel, pass, yrate, scanlen; X byte *pixptr, *pixline; X X if (! (zf= zopen(fullname))) X return(NULL); X if ((gifin_open_file(zf) != GIFIN_SUCCESS) || /* read GIF header */ X (gifin_open_image() != GIFIN_SUCCESS)) { /* read image header */ X gifin_close_file(); X zclose(zf); X return(NULL); X } X if (verbose) X tellAboutImage(name); X X image= newRGBImage(gifin_img_width, gifin_img_height, (gifin_l_cmap_flag ? X gifin_l_pixel_bits : X gifin_g_pixel_bits)); X for (x= 0; x < gifin_g_ncolors; x++) { X image->rgb.red[x]= gifin_g_cmap[GIF_RED][x] << 8; X image->rgb.green[x]= gifin_g_cmap[GIF_GRN][x] << 8; X image->rgb.blue[x]= gifin_g_cmap[GIF_BLU][x] << 8; X } X image->rgb.used= gifin_g_ncolors; X X /* if image has a local colormap, override global colormap X */ X X if (gifin_l_cmap_flag) { X for (x= 0; x < image->rgb.size; x++) { X image->rgb.red[x]= gifin_g_cmap[GIF_RED][x] << 8; X image->rgb.green[x]= gifin_g_cmap[GIF_GRN][x] << 8; X image->rgb.blue[x]= gifin_g_cmap[GIF_BLU][x] << 8; X } X image->rgb.used= gifin_l_ncolors; X } X X /* interlaced image -- futz with the vertical trace. i wish i knew what X * kind of drugs the GIF people were on when they decided that they X * needed to support interlacing. X */ X X if (gifin_interlace_flag) { X scanlen= image->height * image->pixlen; X X /* interlacing takes four passes to read, each starting at a different X * vertical point. X */ X X for (pass= 0; pass < 4; pass++) { X y= interlace_start[pass]; X scanlen= image->width * image->pixlen * interlace_rate[pass]; X pixline= image->data + (y * image->width * image->pixlen); X while (y < gifin_img_height) { X pixptr= pixline; X for (x= 0; x < gifin_img_width; x++) { X if (gifin_get_pixel(&pixel) != GIFIN_SUCCESS) { X printf("%s: Short read within image data\n", fullname); X exit(0); X } X valToMem(pixel, pixptr, image->pixlen); X pixptr += image->pixlen; X } X y += interlace_rate[pass]; X pixline += scanlen; X } X } X } X X /* not an interlaced image, just read in sequentially X */ X X else { X pixptr= image->data; X for (y= 0; y < gifin_img_height; y++) X for (x= 0; x < gifin_img_width; x++) { X if (gifin_get_pixel(&pixel) != GIFIN_SUCCESS) { X printf("%s: Short read within image data\n", fullname); X exit(0); X } X valToMem(pixel, pixptr, image->pixlen); X pixptr += image->pixlen; X } X } X gifin_close_file(); X zclose(zf); X image->title= dupString(name); X return(image); X} X Xunsigned int gifIdent(fullname, name) X char *fullname, *name; X{ ZFILE *zf; X unsigned int ret; X X if (! (zf= zopen(fullname))) X return(0); X if ((gifin_open_file(zf) == GIFIN_SUCCESS) && X (gifin_open_image() == GIFIN_SUCCESS)) { X tellAboutImage(name); X ret= 1; X } X else X ret= 0; X gifin_close_file(); X zclose(zf); X return(ret); X} END_OF_FILE if test 14417 -ne `wc -c <'gif.c'`; then echo shar: \"'gif.c'\" unpacked with wrong size! fi # end of 'gif.c' fi if test -f 'halftone.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'halftone.c'\" else echo shar: Extracting \"'halftone.c'\" \(4115 characters\) sed "s/^X//" >'halftone.c' <<'END_OF_FILE' X/* dither.c: X * X * routine for dithering a color image to monochrome based on color X * intensity. this is loosely based on an algorithm which barry shein X * (bzs@std.com) used in his "xf" program. X * X * jim frost 07.10.89 X * X * Copyright 1989, 1990 Jim Frost. See included file "copyright.h" for X * complete copyright information. X */ X X#include "copyright.h" X#include "image.h" X X/* 4x4 arrays used for dithering, arranged by nybble X */ X X#define GRAYS 17 /* ((4 * 4) + 1) patterns for a good dither */ X#define GRAYSTEP ((unsigned long)(65536 * 3) / GRAYS) X Xstatic byte DitherBits[GRAYS][4] = { X 0xf, 0xf, 0xf, 0xf, X 0xe, 0xf, 0xf, 0xf, X 0xe, 0xf, 0xb, 0xf, X 0xa, 0xf, 0xb, 0xf, X 0xa, 0xf, 0xa, 0xf, X 0xa, 0xd, 0xa, 0xf, X 0xa, 0xd, 0xa, 0x7, X 0xa, 0x5, 0xa, 0x7, X 0xa, 0x5, 0xa, 0x5, X 0x8, 0x5, 0xa, 0x5, X 0x8, 0x5, 0x2, 0x5, X 0x0, 0x5, 0x2, 0x5, X 0x0, 0x5, 0x0, 0x5, X 0x0, 0x4, 0x0, 0x5, X 0x0, 0x4, 0x0, 0x1, X 0x0, 0x0, 0x0, 0x1, X 0x0, 0x0, 0x0, 0x0 X}; X X/* simple dithering algorithm, really optimized for the 4x4 array X */ X XImage *halftone(cimage, verbose) X Image *cimage; X unsigned int verbose; X{ Image *image; X unsigned char *sp, *dp, *dp2; /* data pointers */ X unsigned int dindex; /* index into dither array */ X unsigned int spl; /* source pixel length in bytes */ X unsigned int dll; /* destination line length in bytes */ X Pixel color; /* pixel color */ X unsigned int *index; /* index into dither array for a given pixel */ X unsigned int a, x, y; /* random counters */ X X goodImage(cimage, "dither"); X if (! RGBP(cimage)) X return(NULL); X X /* set up X */ X X if (verbose) { X printf(" Halftoning image..."); X fflush(stdout); X } X image= newBitImage(cimage->width * 4, cimage->height * 4); X if (cimage->title) { X image->title= (char *)lmalloc(strlen(cimage->title) + 13); X sprintf(image->title, "%s (halftoned)", cimage->title); X } X spl= cimage->pixlen; X dll= (image->width / 8) + (image->width % 8 ? 1 : 0); X X /* if the number of possible pixels isn't very large, build an array X * which we index by the pixel value to find the dither array index X * by color brightness. we do this in advance so we don't have to do X * it for each pixel. things will break if a pixel value is greater X * than (1 << depth), which is bogus anyway. this calculation is done X * on a per-pixel basis if the colormap is too big. X */ X X if (cimage->depth <= 16) { X index= (unsigned int *)lmalloc(sizeof(unsigned int) * cimage->rgb.used); X for (x= 0; x < cimage->rgb.used; x++) { X *(index + x)= X ((unsigned long)(*(cimage->rgb.red + x)) + X *(cimage->rgb.green + x) + X *(cimage->rgb.blue + x)) / GRAYSTEP; X if (*(index + x) >= GRAYS) /* rounding errors can do this */ X *(index + x)= GRAYS - 1; X } X } X else X index= NULL; X X /* dither each pixel X */ X X sp= cimage->data; X dp= image->data; X for (y= 0; y < cimage->height; y++) { X for (x= 0; x < cimage->width; x++) { X dp2= dp + (x >> 1); X color= memToVal(sp, spl); X if (index) X dindex= *(index + color); X else { X dindex= ((unsigned long)(*(cimage->rgb.red + color)) + X *(cimage->rgb.green + color) + X *(cimage->rgb.blue + color)) / GRAYSTEP; X if (dindex >= GRAYS) /* rounding errors can do this */ X dindex= GRAYS - 1; X } X X /* loop for the four Y bits in the dither pattern, putting all X * four X bits in at once. if you think this would be hard to X * change to be an NxN dithering array, you're right, since we're X * banking on the fact that we need only shift the mask based on X * whether x is odd or not. an 8x8 array wouldn't even need that, X * but blowing an image up by 64x is probably not a feature. X */ X X if (x & 1) X for (a= 0; a < 4; a++, dp2 += dll) X *dp2 |= DitherBits[dindex][a]; X else X for (a= 0; a < 4; a++, dp2 += dll) X *dp2 |= (DitherBits[dindex][a] << 4); X sp += spl; X } X dp += (dll << 2); /* (dll * 4) but I like shifts */ X } X if (verbose) X printf("done\n"); X return(image); X} END_OF_FILE if test 4115 -ne `wc -c <'halftone.c'`; then echo shar: \"'halftone.c'\" unpacked with wrong size! fi # end of 'halftone.c' fi if test -f 'hash.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hash.c'\" else echo shar: Extracting \"'hash.c'\" \(3707 characters\) sed "s/^X//" >'hash.c' <<'END_OF_FILE' X/* X * Determine colormap of rgb tuple and remap for xloadimage X * X * Portions of this were borrowed from the PBMPLUS software package X * written by Jef Poskanzer (see Copyright below) X * X * The rest of it was munged up by Ian MacPhedran (macphed@dvinci.usask.ca) X * X */ X/* X** Copyright (C) 1989 by Jef Poskanzer. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X#include "hash.h" X X/* Swiped from image.h, but it's the only thing we need */ Xtypedef unsigned short Intensity; Xtypedef struct rgbmap { X unsigned int size; /* size of RGB map */ X unsigned int used; /* number of colors used in RGB map */ X Intensity *red; /* color values in X style */ X Intensity *green; X Intensity *blue; X} RGBMap; X X/* Get memory set up for hashing */ Xhash_list init_hash() X{ X hash_list h; int i; X h = (hash_list) lmalloc(HASHLEN*sizeof(hash_ent)); X if (h == (hash_list) 0) X { X printf("Can't allocate room for mapping function.\n"); X exit(1); X } X X for (i=0; i<HASHLEN; i++) h[i] = (hash_ent)0; X return( h ); X} X X/* Add a colour to the hashing list */ Xvoid add_hash(hl,r,g,b) Xhash_list hl; unsigned int r,g,b; X{ X int hval; X hash_ent loc,*prev; X hval = HashRGB(r,g,b); X prev = &(hl[hval]); X loc = hl[hval]; X while (loc != (hash_ent)0) X { /* Descend through entries */ X if ((loc->pix.r == r) && (loc->pix.g == g) && (loc->pix.b == b)) X return; X prev = &(loc->next); X loc = loc->next; X } /* Fell through - must be new colour */ X X loc = (hash_ent)lmalloc(sizeof(struct hash_elem)); X if (loc == (hash_ent)0) X { X printf("Out of memory in color hashing.\n"); X exit(1); X } X loc->pix.r = r; X loc->pix.g = g; X loc->pix.b = b; X loc->mapnum = 0; loc->next = (hash_ent)0; X *prev = loc; X return; X} X X/* Generate a listing for the colour table from the hash list */ Xint count_hash(hl) Xhash_list hl; X{ X int i,j; X hash_ent loc; X j = 0; X for (i=0; i<HASHLEN; i++) X { X if ((hash_ent)hl[i] != (hash_ent)0) X { X loc = (hash_ent)hl[i]; X while (loc != (hash_ent)0) X { X loc->mapnum = j++; X loc = loc->next; X } X } X } X return(j); X} X X/* Generate a color map from the hash list */ Xint fill_map(hl,rgbm,maxval) Xhash_list hl; RGBMap *rgbm; unsigned int maxval; X{ X int i,j; X hash_ent loc; X j = 0; X if (rgbm == (RGBMap *)0) X { X printf("Memory map not allocated.\n"); X exit(1); X } X for (i=0; i<HASHLEN; i++) X { X if ((hash_ent)hl[i] != (hash_ent)0) X { X loc = (hash_ent)hl[i]; X while (loc != (hash_ent)0) X { X j = loc->mapnum; X rgbm->red[j] = PM_SCALE(loc->pix.r,maxval,0xffff); X rgbm->green[j] = PM_SCALE(loc->pix.g,maxval,0xffff); X rgbm->blue[j] = PM_SCALE(loc->pix.b,maxval,0xffff); X loc = loc->next; X } X } X } X return(j); X} X X/* Find map value from rgb triplet */ Xunsigned int find_hash(hl,r,g,b) Xhash_list hl; unsigned int r,g,b; X{ X int hval; X hash_ent loc; X hval = HashRGB(r,g,b); X loc = hl[hval]; X while (loc != (hash_ent)0) X { /* Descend through entries */ X if ((loc->pix.r == r) && (loc->pix.g == g) && (loc->pix.b == b)) X return(loc->mapnum); X loc = loc->next; X } /* Fell through - must be new colour - shouldn't happen here */ X X printf("Colour not found in hash table.\n"); X exit(1); X} X X/* Free hash list */ Xvoid free_hash(hl) Xhash_list hl; X{ X int i; X X for (i=0; i<HASHLEN; i++) X { X if (hl[i] != 0) free_helem(hl[i]); X } X X lfree(hl); X} X Xvoid free_helem(he) Xhash_ent he; X{ X if (he->next != (hash_ent)0) free_helem(he->next); X lfree(he); X} END_OF_FILE if test 3707 -ne `wc -c <'hash.c'`; then echo shar: \"'hash.c'\" unpacked with wrong size! fi # end of 'hash.c' fi if test -f 'mac.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mac.c'\" else echo shar: Extracting \"'mac.c'\" \(4817 characters\) sed "s/^X//" >'mac.c' <<'END_OF_FILE' X/* X * mac.c: X * X * adapted from code by Patrick Naughton (naughton@sun.soe.clarkson.edu) X * X * macin.c X * Mark Majhor X * August 1990 X * X * routines for reading MAC files X * X * Copyright 1990 Mark Majhor (see the included file X * "mrmcpyrght.h" for complete copyright information) X */ X# include <stdio.h> X# include <math.h> X# include <ctype.h> X# include "image.h" X# include "mac.h" X X/**** X ** X ** local variables X ** X ****/ X Xstatic BYTE file_open = 0; /* status flags */ Xstatic BYTE image_open = 0; X Xstatic ZFILE *ins; /* input stream */ X X/**** X ** X ** global variables X ** X ****/ X Xstatic int macin_img_width; /* image width */ Xstatic int macin_img_height; /* image height */ Xstatic int macin_img_depth; /* image depth */ Xstatic int macin_img_planes; /* image planes */ Xstatic int macin_img_BPL; /* image bytes per line */ X X/* X * open MAC image in the input stream; returns MACIN_SUCCESS if X * successful. (might also return various MACIN_ERR codes.) X */ Xstatic int macin_open_image(s) XZFILE *s; X{ X BYTE mhdr[MAC_HDR_LEN]; X char *hp; /* header pointer */ X int c, i, mhsum = 0; X X /* make sure there isn't already a file open */ X if (file_open) X return(MACIN_ERR_FAO); X X /* remember that we've got this file open */ X file_open = 1; X ins = s; X X /* X * the mac paint files that came with xmac had an extra X * 128 byte header on the front, with a image name in it. X * true mac paint images don't seem to have this extra X * header. The following code tries to figure out what X * type the image is and read the right amount of file X * header (512 or 640 bytes). X */ X /* read in the mac file header */ X hp = (char *) mhdr; X if (zread(ins, hp, ADD_HDR_LEN) != ADD_HDR_LEN) X return MACIN_ERR_EOF; X X /* X * if mhsum = 0 this is probably a X * a g3 fax file. X */ X for (i = 0; i < 10; i++) mhsum += mhdr[1]; X X if (mhdr[0] != MAC_MAGIC && mhsum != 0) X return MACIN_ERR_BAD_SD; X X /* Get image name (if available) */ X if (mhdr[1] != 0) { /* if name header */ X if (zread(ins, hp, MAC_HDR_LEN) != MAC_HDR_LEN) X return MACIN_ERR_EOF; X } else X /* else read rest of header */ X if (zread(ins, hp, MAC_HDR_LEN - ADD_HDR_LEN) != MAC_HDR_LEN - ADD_HDR_LEN) X return MACIN_ERR_EOF; X X /* Now set relevant values */ X macin_img_width = BYTES_LINE * 8; X macin_img_height = MAX_LINES; X macin_img_depth = 1; /* always monochrome */ X macin_img_planes = 1; /* always 1 */ X macin_img_BPL = BYTES_LINE; X X return MACIN_SUCCESS; X} X X/* X * close an open MAC file X */ X Xstatic int macin_close_file() X{ X /* make sure there's a file open */ X if (!file_open) X return MACIN_ERR_NFO; X X /* mark file (and image) as closed */ X file_open = 0; X image_open = 0; X X /* done! */ X return MACIN_SUCCESS; X} X X/* X * semi-graceful fatal error mechanism X */ X Xstatic macin_fatal(msg) X char *msg; X{ X printf("Error reading MacPaint file: %s\n", msg); X exit(0); X} X X/* X * these are the routines added for interfacing to xloadimage X */ X X/* X * tell someone what the image we're loading is. this could be a little more X * descriptive but I don't care X */ X Xstatic void tellAboutImage(name) Xchar *name; X{ X printf("%s is a %dx%d MacPaint image\n", X name, macin_img_width, macin_img_height); X} X XImage *macLoad(fullname, name, verbose) X char *fullname, *name; X unsigned int verbose; X{ X ZFILE *zf; X Image *image; X BYTE *pixptr, ch; X register int x, y, c, scanLine; X register unsigned int i, j, k; X X if (! (zf = zopen(fullname))) X return(NULL); X if (macin_open_image(zf) != MACIN_SUCCESS) { /* read image header */ X macin_close_file(); X zclose(zf); X return(NULL); X } X X if (verbose) X tellAboutImage(name); X X image = newBitImage(macin_img_width, macin_img_height); X X pixptr = &(image->data[0]); X scanLine = 0; k = 0; X X while (scanLine < macin_img_height) { X X ch = (BYTE) zgetc(zf); /* Count byte */ X i = (unsigned int) ch; X if (ch < 0x80) { /* Unpack next (I+1) chars as is */ X for (j = 0; j <= i; j++) X if (scanLine < macin_img_height) { X *pixptr++ = (BYTE) zgetc(zf); k++; X if (!(k %= BYTES_LINE)) { X scanLine++; X } X } X } else { /* Repeat next char (2's comp I) times */ X ch = zgetc(zf); X for (j = 0; j <= 256 - i; j++) X if (scanLine < macin_img_height) { X *pixptr++ = (BYTE) ch; k++; X if (!(k %= BYTES_LINE)) { X scanLine++; X } X } X } X } X macin_close_file(); X zclose(zf); X image->title = dupString(name); X return(image); X} X Xunsigned int macIdent(fullname, name) Xchar *fullname, *name; X{ X ZFILE *zf; X unsigned int ret; X X if (! (zf = zopen(fullname))) X return(0); X if (macin_open_image(zf) == MACIN_SUCCESS) { X tellAboutImage(name); X ret = 1; X } else X ret = 0; X macin_close_file(); X zclose(zf); X return(ret); X} END_OF_FILE if test 4817 -ne `wc -c <'mac.c'`; then echo shar: \"'mac.c'\" unpacked with wrong size! fi # end of 'mac.c' fi if test -f 'merge.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'merge.c'\" else echo shar: Extracting \"'merge.c'\" \(9163 characters\) sed "s/^X//" >'merge.c' <<'END_OF_FILE' X/* merge.c: X * X * this merges two images, folding and reducing colormaps as necessary. X * X * jim frost 09.27.89 X * X * Copyright 1989, 1990 Jim Frost. See included file "copyright.h" for X * complete copyright information. X */ X X#include "copyright.h" X#include "image.h" X Xstatic void mergeColors(dest, src, verbose) X Image *dest, *src; X unsigned int verbose; X{ RGBMap newcolors; X unsigned int a, b; X X if (dest->rgb.used + src->rgb.used > dest->rgb.size) { X newRGBMapData(&newcolors, dest->rgb.used + src->rgb.used); X newcolors.used= newcolors.size; X for (a= 0; a < dest->rgb.used; a++) { X *(newcolors.red + a)= *(dest->rgb.red + a); X *(newcolors.green + a)= *(dest->rgb.green + a); X *(newcolors.blue + a)= *(dest->rgb.blue + a); X } X for (b= 0; b < src->rgb.used; a++, b++) { X *(newcolors.red + a)= *(src->rgb.red + b); X *(newcolors.green + a)= *(src->rgb.green + b); X *(newcolors.blue + a)= *(src->rgb.blue + b); X } X X reduceRGBMap(&newcolors, dest->rgb.size, verbose); X X for (a= 0; a < dest->rgb.used; a++) { /* put new colors into */ X *(dest->rgb.red + a)= *(newcolors.red + a); /* old colormaps */ X *(dest->rgb.green + a)= *(newcolors.green + a); X *(dest->rgb.blue + a)= *(newcolors.blue + a); X } X for (a= 0; a < src->rgb.used; a++) { X *(src->rgb.red + a)= *(newcolors.red + a + dest->rgb.used); X *(src->rgb.green + a)= *(newcolors.green + a + dest->rgb.used); X *(src->rgb.blue + a)= *(newcolors.blue + a + dest->rgb.used); X } X } X else X for (a= 0; a < src->rgb.used; a++, (dest->rgb.used)++) { X *(dest->rgb.red + dest->rgb.used)= *(src->rgb.red + a); X *(dest->rgb.green + dest->rgb.used)= *(src->rgb.green + a); X *(dest->rgb.blue + dest->rgb.used)= *(src->rgb.blue + a); X } X} X Xstatic void bitmapToBitmap(src, dest, atx, aty, clipw, cliph, verbose) X Image *src, *dest; X unsigned int atx, aty, clipw, cliph; X unsigned int verbose; X{ unsigned int dithered; X unsigned int destlinelen, srclinelen; X unsigned int deststart; X unsigned int flip; X unsigned int x, y; X byte *destline, *srcline; X byte deststartmask; X byte destmask, srcmask; X byte *destpixel, *srcpixel; X X if (verbose) { X printf(" Merging bitmap image onto bitmap image..."); X fflush(stdout); X } X X if (RGBP(src)) { /* dither the RGB image to mono */ X dithered= 1; X src= dither(src, verbose); X } X else X dithered= 0; X X destlinelen= (dest->width / 8) + (dest->width % 8 ? 1 : 0); X srclinelen= (src->width / 8) + (src->width % 8 ? 1 : 0); X destline= dest->data + (aty * destlinelen); X srcline= src->data; X deststart= atx / 8; X deststartmask= 0x80 >> (atx % 8); X flip= ((*dest->rgb.red == *(src->rgb.red + 1)) && X (*dest->rgb.green == *(src->rgb.green + 1)) && X (*dest->rgb.blue == *(src->rgb.blue + 1))); X for (y= 0; y < cliph; y++) { X destpixel= destline + deststart; X srcpixel= srcline; X destmask= deststartmask; X srcmask= 0x80; X for (x= 0; x < clipw; x++) { X if (flip) X if (*srcpixel & srcmask) X *destpixel &= ~destmask; X else X *destpixel |= destmask; X else X if (*srcpixel & srcmask) X *destpixel |= destmask; X else X *destpixel &= ~destmask; X destmask >>= 1; X srcmask >>= 1; X if (destmask == 0) { X destmask= 0x80; X destpixel++; X } X if (srcmask == 0) { X srcmask= 0x80; X srcpixel++; X } X } X destline += destlinelen; X srcline += srclinelen; X } X if (dithered) X freeImage(src); X X if (verbose) X printf("done\n"); X} X Xstatic void bitmapToRGB(src, dest, atx, aty, clipw, cliph, verbose) X Image *src, *dest; X unsigned int atx, aty, clipw, cliph; X unsigned int verbose; X{ unsigned int bg, fg; X unsigned int destlinelen, srclinelen; X unsigned int deststart; X unsigned int x, y; X byte *destline, *srcline; X byte *destpixel, *srcpixel; X byte srcmask; X X if (verbose) { X printf(" Merging bitmap image onto RGB image..."); X fflush(stdout); X } X X /* get fg and bg colors from dest image X */ X X fg= bg= 0; X for (x= 0; x < dest->rgb.used; x++) X if ((*(dest->rgb.red + x) == *src->rgb.red) && X (*(dest->rgb.green + x) == *src->rgb.green) && X (*(dest->rgb.blue + x) == *src->rgb.blue)) { X bg= x; X break; X } X if (x == dest->rgb.used) X printf("merge: warning: can't find background color in dest image\n"); X for (x= 0; x < dest->rgb.used; x++) X if ((*(dest->rgb.red + x) == *(src->rgb.red + 1)) && X (*(dest->rgb.green + x) == *(src->rgb.green + 1)) && X (*(dest->rgb.blue + x) == *(src->rgb.blue + 1))) { X fg= x; X break; X } X if (x == dest->rgb.used) X printf("merge: warning: can't find foreground color in dest image\n"); X X /* merge 'em X */ X X destlinelen= dest->width * dest->pixlen; X srclinelen= (src->width / 8) + (src->width % 8 ? 1 : 0); X destline= dest->data + (aty * destlinelen); X srcline= src->data; X deststart= atx * dest->pixlen; X X for (y= 0; y < cliph; y++) { X destpixel= destline + deststart; X srcpixel= srcline; X srcmask= 0x80; X for (x= 0; x < clipw; x++) { X valToMem((*srcpixel & srcmask ? fg : bg), destpixel, dest->pixlen); X destpixel += dest->pixlen; X srcmask >>= 1; X if (srcmask == 0) { X srcpixel++; X srcmask= 0x80; X } X } X destline += destlinelen; X srcline += srclinelen; X } X X if (verbose) X printf("done\n"); X} X Xstatic void RGBToRGB(src, dest, atx, aty, clipw, cliph, verbose) X Image *src, *dest; X unsigned int atx, aty, clipw, cliph; X unsigned int verbose; X{ unsigned int destlinelen, srclinelen; X unsigned int deststart; X unsigned int x, y; X Pixel *index; X byte *destline, *srcline; X byte *destpixel, *srcpixel; X X if (verbose) { X printf(" Merging RGB images..."); X fflush(stdout); X } X X /* build src->dest pixel mapping X */ X X index= (Pixel *)lmalloc(sizeof(Pixel) * src->rgb.used); X for (x= 0; x < src->rgb.used; x++) { X for (y= 0; y < dest->rgb.used; y++) X if ((*(dest->rgb.red + y) == *(src->rgb.red + x)) && X (*(dest->rgb.green + y) == *(src->rgb.green + x)) && X (*(dest->rgb.blue + y) == *(src->rgb.blue + x))) { X *(index + x)= y; X break; X } X if (y == dest->rgb.used) X if (y < dest->rgb.size) { X *(dest->rgb.red + y)= *(src->rgb.red + x); X *(dest->rgb.green + y)= *(src->rgb.green + x); X *(dest->rgb.blue + y)= *(src->rgb.blue + x); X *(index + x)= y; X dest->rgb.used++; X } X else { X printf("merge: warning: To few colors in destination colormap?!?\n"); X *(index + x)= 0; X } X } X X destlinelen= dest->width * dest->pixlen; X srclinelen= src->width * src->pixlen; X deststart= atx * dest->pixlen; X destline= dest->data + (aty * destlinelen); X srcline= src->data; X X for (y= 0; y < cliph; y++) { X destpixel= destline + deststart; X srcpixel= srcline; X for (x= 0; x < clipw; x++) { X valToMem(*(index + memToVal(srcpixel, src->pixlen)), X destpixel, dest->pixlen); X destpixel += dest->pixlen; X srcpixel += src->pixlen; X } X destline += destlinelen; X srcline += srclinelen; X } X lfree(index); X X if (verbose) X printf("done\n"); X} X X/* put src image on dest image (and clip while we're at it). the bitmap X * to bitmap merge could be sped up by a factor of four for the general X * case and eight to thirty-two for specific cases. i'm for simplicity, X * though. X */ X Xvoid merge(dest, src, atx, aty, verbose) X Image *dest; X Image *src; X int atx, aty; X unsigned int verbose; X{ unsigned int clipw, cliph; X int clipped = 0; X X goodImage(dest, "merge"); X goodImage(src, "merge"); X X /* adjust clipping of src to fit within dest X */ X X clipw= src->width; X cliph= src->height; X if ((atx + clipw < 0) || (aty + cliph < 0) || X (atx >= (int)dest->width) || X (aty >= (int)dest->height)) /* not on dest, ignore */ X return; X X if (atx + clipw > dest->width) X clipw = dest->width - atx; X if (aty + cliph > dest->height) X cliph = dest->height - aty; X X /* extra clipping required for negative offsets */ X if ( atx < 0 || aty < 0 ) { X int clipx, clipy; X X if ( atx < 0 ) { X clipx = -atx; X clipw += atx; X atx = 0; X } X else X clipx = 0; X X if ( aty < 0 ) { X clipy = -aty; X cliph += aty; X aty = 0; X } X else X clipy = 0; X X clipped = 1; X src = clip(src, clipx, clipy, clipw, cliph, verbose); X } X X if (BITMAPP(dest) && (BITMAPP(src) || RGBP(src))) X bitmapToBitmap(src, dest, (unsigned int)atx, (unsigned int)aty, X clipw, cliph, verbose); X else { X mergeColors(dest, src, verbose); X if (RGBP(dest) && BITMAPP(src)) X bitmapToRGB(src, dest, (unsigned int)atx, (unsigned int)aty, X clipw, cliph, verbose); X else if (RGBP(dest) && RGBP(src)) X RGBToRGB(src, dest, (unsigned int)atx, (unsigned int)aty, X clipw, cliph, verbose); X else { X printf("merge: Can't merge these two types of images (sorry)\n"); X exit(1); X } X } X if (clipped) X freeImage(src); X compress(dest, verbose); X} END_OF_FILE if test 9163 -ne `wc -c <'merge.c'`; then echo shar: \"'merge.c'\" unpacked with wrong size! fi # end of 'merge.c' fi if test -f 'new.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'new.c'\" else echo shar: Extracting \"'new.c'\" \(2646 characters\) sed "s/^X//" >'new.c' <<'END_OF_FILE' X/* new.c: X * X * functions to allocate and deallocate structures and structure data X * X * jim frost 09.29.89 X * X * Copyright 1989 Jim Frost. See included file "copyright.h" for complete X * copyright information. X */ X X#include "copyright.h" X#include "image.h" X Xchar *dupString(s) X char *s; X{ char *d; X X if (!s) X return(NULL); X d= (char *)lmalloc(strlen(s) + 1); X strcpy(d, s); X return(d); X} X Xvoid newRGBMapData(rgb, size) X RGBMap *rgb; X unsigned int size; X{ X rgb->used= 0; X rgb->size= size; X rgb->red= (Intensity *)lmalloc(sizeof(Intensity) * size); X rgb->green= (Intensity *)lmalloc(sizeof(Intensity) * size); X rgb->blue= (Intensity *)lmalloc(sizeof(Intensity) * size); X} X Xvoid freeRGBMapData(rgb) X RGBMap *rgb; X{ X lfree(rgb->red); X lfree(rgb->green); X lfree(rgb->blue); X} X XImage *newBitImage(width, height) X unsigned int width, height; X{ Image *image; X unsigned int linelen; X X image= (Image *)lmalloc(sizeof(Image)); X image->type= IBITMAP; X image->title= NULL; X newRGBMapData(&(image->rgb), (unsigned int)2); X *(image->rgb.red)= *(image->rgb.green)= *(image->rgb.blue)= 65535; X *(image->rgb.red + 1)= *(image->rgb.green + 1)= *(image->rgb.blue + 1)= 0; X image->rgb.used= 2; X image->width= width; X image->height= height; X image->depth= 1; X linelen= (width / 8) + (width % 8 ? 1 : 0); /* thanx johnh@amcc.com */ X image->data= (unsigned char *)lcalloc(linelen * height); X return(image); X} X XImage *newRGBImage(width, height, depth) X unsigned int width, height, depth; X{ Image *image; X unsigned int pixlen, numcolors, a; X X pixlen= (depth / 8) + (depth % 8 ? 1 : 0); X for (numcolors= 2, a= depth - 1; a; a--) X numcolors *= 2; X image= (Image *)lmalloc(sizeof(Image)); X image->type= IRGB; X image->title= NULL; X newRGBMapData(&(image->rgb), numcolors); X image->width= width; X image->height= height; X image->depth= depth; X image->pixlen= pixlen; X image->data= (unsigned char *)lmalloc(width * height * pixlen); X return(image); X} X Xvoid freeImageData(image) X Image *image; X{ X if (image->title) { X lfree(image->title); X image->title= NULL; X } X freeRGBMapData(&(image->rgb)); X lfree(image->data); X} X Xvoid freeImage(image) X Image *image; X{ X freeImageData(image); X lfree(image); X} X Xbyte *lmalloc(size) X unsigned int size; X{ byte *area; X X if (!(area= (byte *)malloc(size))) { X perror("malloc"); X exit(1); X } X return(area); X} X Xbyte *lcalloc(size) X unsigned int size; X{ byte *area; X X if (!(area= (byte *)calloc(1, size))) { X perror("calloc"); X exit(1); X } X return(area); X} X Xvoid lfree(area) X byte *area; X{ X free(area); X} END_OF_FILE if test 2646 -ne `wc -c <'new.c'`; then echo shar: \"'new.c'\" unpacked with wrong size! fi # end of 'new.c' fi echo shar: End of archive 4 \(of 9\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.