home *** CD-ROM | disk | FTP | other *** search
- /*
- * igif.c -- display GIF images on the personal iris and other SGI machines.
- *
- * usage: igif [ -d -e -f -l -t -2 ] { file.gif }
- *
- * If no images are specified, a GIF image is read from standard input.
- * flags:
- *
- * -d Dither the images before displaying it.
- * -e Erase the entire previous image before going to the next one.
- * -f Stay in the foreground; this is useful for 3 line browsers:
- * foreach f (*.gif)
- * igif -f $f
- * end
- * -l Force igif to not use lrectwrite. This may be faster and it
- * may be necessary for it to work ('though some autodection is done).
- * -t Display true colours on colour-mapped displays. On displays with
- * only 8 planes, igif will change the colours of images to fit the
- * standard NeWS colourmap. This option makes igif display the true
- * colours; even if that means that other programs will get their
- * colours (temporarily) stomped on. It tries hard to be as
- * inconspicuous as possible, but if you gotta have 256 colours...
- * -2 Display the images in double height and double width mode. A
- * cheap hack, but it saves some eyestrain on those itsy-bitsy
- * 320 x 200 GIFs.
- *
- * When in igif, the left and middle mouse buttons (or the n and p keys)
- * move to the next and previous images respectively. The right mouse
- * button brings up a menu of the images. The q key will quit igif.
- * Until all the images are loaded, you may not see the image even if you
- * move to it. When no numbers appear to the left of the title bar all
- * images should be loaded.
- *
- * Bugs:
- * If some program has munged the "standard" 8 plane colourmap, the images
- * won't look too good. Either run makemap (/usr/sbin/makemap, perhaps)
- * or use the -t flag. Igif may itself wipe out the colourmap if you
- * kill it.
- * Auto-dection of a missing lrectwrite() may not work on all systems.
- * I'll be happy to apply a fix if you have one.
- * Dithering should be done after doubling the image. It isn't and the
- * results are not too pretty.
- *
- * TODO list:
- * - we can't dither interlaced GIFs right away (but we do anyways!)
- * - support GIF89a fully
- * - work on displays without RGB but > 8 planes. Not too hard,
- * but _I_ can't test it.
- * - true colour mode should check if a local colourmap is in fact the same.
- * - set NeWS colourmap on startup?
- * - display meaninful information if an image is not yet loaded.
- * - transmogrification into a generalized image viewer which supports
- * lots of different formats, perhaps in concert with PBM+.
- * - generalize the magnification (esp. to correct aspect ratio)
- * - options to perform gamma correction of images
- * - clean up the code
- *
- * Copyright 1989,1990 by George Phillips
- *
- * 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.
- *
- * The GIF LZW decoder was written by someone else who's copyright notice
- * is contained in decode.c.
- *
- * The Floyd-Steinburg dithering code was based on ppmquant from Jef
- * Poskanzer's PBM+ package.
- *
- * George Phillips <phillips@cs.ubc.ca>
- * Department of Computer Science
- * University of British Columbia
- */
-
- #include <stdio.h>
- #include <malloc.h>
- #include <gl.h>
- #include <device.h>
-
- #include "errs.h"
- #include "mem_image.h"
- #include "imgfile.h"
- #include "newsmap.h"
-
- int bad_code_count;
-
- struct imgfile* imf_list = NULL;
- struct imgfile** imf_ins = &imf_list;
- struct mem_image* cur_img = NULL;
-
- int stay_in_foreground = 0;
- int mag = 1;
- int use_lrectwrite = 1;
- int true_colours = 0;
- int dither = 0;
- int erase_all = 0;
- int timing = 0;
-
- enum disp_mode_type { RGB_LRECT, RGB_WRITE, CMAP_NEWS, CMAP_TRUE };
- static enum disp_mode_type disp_mode;
- static int win_width;
- static int win_height;
- int redrawing = 0;
- int redraw_line = 0;
- struct imgfile* cur_imf = NULL;
- long imgmenu;
-
- int loading;
-
- char* image_title();
-
- main(argc, argv)
- int argc;
- char* argv[];
- {
- FILE* fp;
- int argn;
- int i;
- int maxwidth;
- int maxheight;
- struct imgfile* imf;
-
- argn = 1;
- for (argn = 1; argn < argc && argv[argn][0] == '-'; argn++) {
- if (!strcmp(argv[argn], "-f"))
- stay_in_foreground = 1;
- else if (!strcmp(argv[argn], "-l"))
- use_lrectwrite = 0;
- else if (!strcmp(argv[argn], "-t"))
- true_colours = 1;
- else if (!strcmp(argv[argn], "-d"))
- dither = 1;
- else if (!strcmp(argv[argn], "-e"))
- erase_all = 1;
- else if (!strcmp(argv[argn], "-2")) {
- mag = 2;
- }
- else if (!strcmp(argv[argn], "-T"))
- timing = 1;
- else {
- fprintf(stderr, "igif: unknown option '%s'\n", argv[argn]);
- exit(1);
- }
- }
-
- if (true_colours && dither) {
- fprintf(stderr, "igif: only one of -t and -d may be specified; -t assumed\n");
- dither = 0;
- }
-
- if (argn == argc)
- setup_file("standard input", stdin);
- else
- for (i = argn; i < argc; i++)
- setup_file(argv[i], (FILE*)NULL);
-
- loading = 0;
- maxwidth = 10;
- maxheight = 10;
- for (imf = imf_list; imf != NULL; imf = imf->next) {
- loading++;
- if (imf->width > maxwidth)
- maxwidth = imf->width;
- if (imf->height > maxheight)
- maxheight = imf->height;
- }
-
- if (loading == 0) {
- fprintf(stderr, "igif: no images to display\n");
- exit(1);
- }
-
- screen_init(maxwidth, maxheight);
- if (dither && (disp_mode == RGB_LRECT || disp_mode == RGB_WRITE))
- dither = 0;
-
- for (imf = imf_list; imf != NULL; imf = imf->next) {
- if (imf->stream != NULL || (fp = fopen(imf->filename, "r")) != NULL) {
- if (cur_imf == NULL) {
- cur_imf = imf;
- wintitle(image_title(imf));
- }
- if (imf->stream != NULL)
- load_gif(imf, imf->stream, imf->width, imf->height);
- else {
- load_gif(imf, fp, -1, -1);
- fclose(fp);
- }
- loading--;
- update_loadinfo();
- }
- }
-
- update_loadinfo();
- screen_handle(1);
- exit(0);
- }
-
- sizeof_gif(name, fp, width, height)
- char* name;
- FILE* fp;
- int* width;
- int* height;
- {
- unsigned char buf[10];
-
- if (fread(buf, 10, 1, fp) != 1) {
- fprintf(stderr, "igif: %s is too short\n", name);
- return(0);
- }
- if (strncmp(buf, "GIF", 3)) {
- fprintf(stderr, "igif: %s is not a GIF file\n", name);
- return(0);
- }
- if (strncmp(buf + 3, "87a", 3) && strncmp(buf + 3, "89a", 3)) {
- buf[6] = '\0';
- fprintf(stderr, "igif: %s is an unsupported GIF file version\n", name);
- return(0);
- }
- *width = buf[6] + (buf[7] << 8);
- *height = buf[8] + (buf[9] << 8);
- return(1);
- }
-
- static int err = 0;
- static int i_y;
- static int pass;
-
- #define error(x) printf("%s at byte %d\n", x, ftell(fp)); return(0)
- #define reterr(x) if (err != 0) { error(x); }
- #define reteof() reterr("Unexpected EOF")
- #define skipbyte(x) getbyte(x); reteof()
-
- int* gif2rgb();
- struct mem_image* add_image();
- void adjust_colourmap();
-
- setup_file(filename, stream)
- char* filename;
- FILE* stream;
- {
- FILE* fp;
- int width, height;
- struct imgfile* imf;
- char* p;
- char* lastslash;
-
- if (stream != NULL)
- fp = stream;
- else if ((fp = fopen(filename, "r")) == NULL) {
- fprintf(stderr, "can't open '%s'\n", filename);
- return;
- }
-
- if (sizeof_gif(filename, fp, &width, &height)) {
- imf = (struct imgfile*)malloc(sizeof(struct imgfile));
- if (imf == NULL)
- no_mem();
- imf->filename = filename;
- imf->stream = stream;
- imf->width = width;
- imf->height = height;
-
- for (p = filename, lastslash = filename - 1; *p; p++)
- if (*p == '/')
- lastslash = p;
-
- imf->name = lastslash + 1;
- imf->imglist = NULL;
- imf->next = NULL;
- *imf_ins = imf;
- imf_ins = &(imf->next);
- }
- if (stream == NULL)
- fclose(fp);
- }
-
- load_gif(imf, fp, s_width, s_height)
- struct imgfile* imf;
- FILE* fp;
- int s_width;
- int s_height;
- {
- static unsigned char buf[4096];
- int s_control, back;
- int i_top, i_left, i_width, i_control, i_height;
- int ch;
- int i, j;
- int* global_colourmap;
- int* local_colourmap;
- struct mem_image* img;
- struct mem_image** img_ins;
-
- img_ins = &(imf->imglist);
-
- if (s_width == -1) {
- /* read signature */
- if (fread(buf, 3, 1, fp) != 1) {
- error("File too short");
- }
-
- if (strncmp(buf, "GIF", 3)) {
- error("Not a GIF file");
- }
-
- if (fread(buf, 3, 1, fp) != 1) {
- error("File too short");
- }
-
- if (strncmp(buf, "87a", 3) && strncmp(buf, "89a", 3)) {
- buf[3] = '\0';
- printf("unknown version '%s'\n", buf);
- return(0);
- }
-
- /* read screen descriptor */
- s_width = getword(fp); reteof();
- s_height = getword(fp); reteof();
- }
-
- s_control = getbyte(fp); reteof();
- back = getbyte(fp); reteof();
- skipbyte(fp);
-
- if (s_control & 128) { /* global colour map */
- global_colourmap = gif2rgb(fp, 2 << (s_control & 7));
- }
-
- for (;;) {
- ch = getbyte(fp);
- reterr("no terminator");
- switch (ch) {
- case ',': /* image follows */
- i_left = getword(fp); reteof();
- i_top = getword(fp); reteof();
- i_width = getword(fp); reteof();
- i_height = getword(fp); reteof();
- i_control = getbyte(fp); reteof();
-
- if (i_control & 128) { /* local colour map */
- local_colourmap = gif2rgb(fp, 2 << (i_control & 7));
- img = add_image(i_width, i_height, 2 << (i_control & 7),
- s_width, s_height);
- img->colourmap = local_colourmap;
- img->maplen = 2 << (i_control & 7);
- }
- else {
- img = add_image(i_width, i_height, 2 << (s_control & 7),
- s_width, s_height);
- img->colourmap = global_colourmap;
- img->maplen = 2 << (s_control & 7);
- }
- img->x_off += i_left * mag;
- img->y_off += i_top * mag;
- img->gif_interlaced = i_control & 64;
- img->background = back;
- img->imf = imf;
- *img_ins = img;
- img_ins = &(img->next);
- adjust_colourmap(img);
- if (img->imf == cur_imf && img->imf->imglist == img)
- paint_background(img);
- bad_code_count = 0;
- i_y = 0;
- pass = 0;
- decoder(fp, img);
- /* ignore rest of blocks used by decoder */
- skipblocks(fp); reterr("Bad block in image");
- break;
- case ';': /* terminator ... */
- return(0);
- case '!': /* extension block */
- skipbyte(fp); /* function code */
- skipblocks(fp); reterr("Bad block in extension block");
- break;
- default:
- /* Supposed to ignore any unknown characters up to the image
- * separator, but I prefer to be tight about these things because
- * there are many corrupt images out there.
- */
- printf("Unknown block type '%c' (%d) at byte %d\n",
- ch, ch, ftell(fp));
- return(0);
- }
- }
- }
-
- /*
- * Read the GIF colourmap from the given file and convert it into
- * the format used by lrectwrite.
- *
- * GIF colourmap is a byte stream: rgbrgbrgb
- * lrect format is in 4 byte words: abgr abgr abgr
- * (the a is alpha, which should be zero)
- */
- int* gif2rgb(fp, len)
- FILE* fp;
- int len;
- {
- register int i;
- int* rgb;
-
- if ((rgb = (int*)malloc(len * sizeof(int))) == NULL)
- no_mem();
-
- /* very loose about EOF, oh well */
- for (i = 0; i < len; i++) {
- rgb[i] = fgetc(fp);
- rgb[i] |= fgetc(fp) << 8;
- rgb[i] |= fgetc(fp) << 16;
- }
- return(rgb);
- }
-
- static int pass_width[] = { 8, 8, 4, 2 };
- static int pass_start[] = { 0, 4, 2, 1 };
-
- char* out_line(img)
- struct mem_image* img;
- {
- if (dither)
- floydstein(img, i_y);
-
- if (disp_mode == CMAP_TRUE)
- true_cmap(img, i_y);
-
- if (cur_imf == img->imf) {
- switch (disp_mode) {
- case CMAP_TRUE:
- case CMAP_NEWS:
- cmap_incr_redraw(img, i_y);
- break;
- case RGB_LRECT:
- incr_redraw(img, i_y);
- break;
- case RGB_WRITE:
- nonrect_incr_redraw(img, i_y);
- break;
- }
- }
- screen_handle(0);
-
- if (!img->gif_interlaced)
- return(img->data + ++i_y * img->width);
-
- i_y += pass_width[pass];
- if (i_y >= img->height) {
- pass++;
- i_y = pass_start[pass];
- }
- return(img->data + i_y * img->width);
- }
-
- int getbyte(fp)
- FILE* fp;
- {
- int ch;
-
- err = 0;
- if ((ch = fgetc(fp)) == EOF) {
- err = 1;
- return(READ_ERROR);
- }
- return(ch & 255);
- }
-
- int getword(fp)
- FILE* fp;
- {
- int c1, c2;
-
- err = 0;
- if ((c1 = fgetc(fp)) == EOF) {
- err = 1;
- return(0);
- }
- if ((c2 = fgetc(fp)) == EOF) {
- err = 1;
- return(0);
- }
- return(((c2 & 255) << 8) | (c1 & 255));
- }
-
- skipblocks(fp)
- FILE* fp;
- {
- int len;
- static char buf[256];
-
- err = 0;
-
- for (;;) {
- len = getbyte(fp);
- reterr("EOF in blocks");
-
- if (len == 0)
- return(0);
-
- if (fread(buf, len, 1, fp) != 1) {
- puts("EOF in blocks");
- err = 1;
- return(0);
- }
- }
- }
-
- void set_display_mode();
- void save_colourmap();
- void set_colourmap();
- void toggle_colourmap();
- void restore_colourmap();
-
- screen_init(maxwidth, maxheight)
- int maxwidth;
- int maxheight;
- {
- struct imgfile* imf;
-
- init_newsmap();
-
- if (stay_in_foreground)
- foreground();
-
- prefsize(win_width = maxwidth * mag, win_height = maxheight * mag);
- if (winopen("igif") < 0) {
- fprintf(stderr, "igif: couldn't open a window.\n");
- exit(1);
- }
- set_display_mode();
-
- if (disp_mode == RGB_LRECT || disp_mode == RGB_WRITE)
- RGBmode();
-
- gconfig();
-
- if (disp_mode == RGB_LRECT)
- rectzoom((float)mag, (float)mag);
-
- if (disp_mode == CMAP_TRUE)
- save_colourmap();
-
- rectf(0, 0, win_width - 1, win_height - 1);
-
- qdevice(REDRAW);
- qdevice(PIECECHANGE);
- qdevice(WINQUIT);
- qdevice(LEFTMOUSE);
- qdevice(MIDDLEMOUSE);
- qdevice(INPUTCHANGE);
-
- qdevice(NKEY);
- qdevice(PKEY);
- qdevice(QKEY);
-
- qdevice(MENUBUTTON);
- imgmenu = newpup();
- addtopup(imgmenu, "images %t");
- for (imf = imf_list; imf != NULL; imf = imf->next)
- addtopup(imgmenu, imf->name);
- }
-
- screen_handle(block)
- int block;
- {
- short data;
- int i;
- struct imgfile* imf;
-
- if (block)
- update_loadinfo();
-
- do {
- while (qtest()) {
- switch (qread(&data)) {
- case MENUBUTTON:
- if ((i = dopup(imgmenu)) <= 0)
- break;
- for (cur_imf = imf_list; i > 1; i--)
- cur_imf = cur_imf->next;
- new_imf();
- break;
- case PKEY:
- case MIDDLEMOUSE:
- if (data == 0)
- break;
- for (imf = imf_list; imf != NULL; imf = imf->next)
- if (imf->next == cur_imf ||
- (imf->next == NULL && cur_imf == imf_list))
- break;
-
- cur_imf = imf;
- new_imf();
- break;
- case NKEY:
- case LEFTMOUSE:
- /* no need to redraw if we have only one image */
- if (imf_list->next == NULL || data == 0)
- break;
- if ((cur_imf = cur_imf->next) == NULL)
- cur_imf = imf_list;
- new_imf();
- break;
- case REDRAW:
- case PIECECHANGE:
- if (cur_imf != NULL) {
- cur_img = cur_imf->imglist;
- if (cur_img != NULL) {
- redrawing = 1;
- redraw_line = 0;
- paint_background(cur_img);
- }
- else
- redrawing = 0;
- }
- break;
- case QKEY:
- case WINQUIT:
- if (disp_mode == CMAP_TRUE)
- restore_colourmap();
- exit(0);
- case INPUTCHANGE:
- if (disp_mode == CMAP_TRUE && cur_imf->imglist != NULL)
- toggle_colourmap(cur_imf->imglist);
- break;
- default:
- break;
- }
- }
- if (redrawing) {
- switch (disp_mode) {
- case CMAP_TRUE:
- case CMAP_NEWS:
- redraw_line = cmap_incr_redraw(cur_img, redraw_line);
- break;
- case RGB_LRECT:
- redraw_line = incr_redraw(cur_img, redraw_line);
- break;
- case RGB_WRITE:
- redraw_line = nonrect_incr_redraw(cur_img, redraw_line);
- break;
- }
-
- if (redraw_line >= cur_img->height) {
- cur_img = cur_img->next;
- if (cur_img == NULL)
- redrawing = 0;
- else
- redraw_line = 0;
- }
- }
- } while (block);
- }
-
- new_imf()
- {
- wintitle(image_title(cur_imf));
- cur_img = cur_imf->imglist;
- if (cur_img != NULL) {
- if (disp_mode == CMAP_TRUE)
- set_colourmap(cur_img);
- paint_background(cur_img);
- redrawing = 1;
- redraw_line = 0;
- }
- else
- redrawing = 0;
- }
-
- update_loadinfo()
- {
- if (cur_imf != NULL)
- wintitle(image_title(cur_imf));
- }
-
- no_mem()
- {
- fprintf(stderr, "out of memory\n");
- exit(1);
- }
-
-
- struct mem_image* add_image(width, height, depth, scr_width, scr_height)
- int width;
- int height;
- int depth;
- int scr_width;
- int scr_height;
- {
- struct mem_image* img;
-
- if ((img = (struct mem_image*)malloc(sizeof(struct mem_image))) == NULL)
- no_mem();
-
- img->width = width;
- img->height = height;
- img->depth = depth;
- img->colourmap = NULL;
- img->mapmap = NULL;
- img->gif_interlaced = 0;
- img->seq = -1;
-
- img->x_off = (win_width - scr_width * mag) / 2;
- img->y_off = (win_height - scr_height * mag) / 2;
- /*img->state = LOADING;*/
-
- if ((img->data = malloc(width * height)) == NULL)
- no_mem();
-
- bzero(img->data, width * height);
-
- img->next = NULL;
-
- return(img);
- }
-
- char* image_title(imf)
- struct imgfile* imf;
- {
- static char title[256];
- char lbuf[32];
-
- sprintf(lbuf, "%d ", loading);
-
- sprintf(title, "%s%s",
- loading > 0 ? lbuf : "",
- imf->name);
-
- return(title);
- }
-
-
- paint_background(img)
- struct mem_image* img;
- {
- int xleft, xright, ytop, ybottom;
-
- switch (disp_mode) {
- case RGB_LRECT:
- RGBcolor(img->colourmap[img->background] & 255,
- (img->colourmap[img->background] >> 8) & 255,
- (img->colourmap[img->background] >> 16) & 255);
- break;
- case RGB_WRITE:
- RGBcolor(*((char*)img->colourmap + img->background),
- *((char*)img->colourmap + img->maplen + img->background),
- *((char*)img->colourmap + img->maplen * 2 + img->background));
- break;
- case CMAP_NEWS:
- color(rgb2newsmap(img->colourmap[img->background] & 255,
- (img->colourmap[img->background] >> 8) & 255,
- (img->colourmap[img->background] >> 16) & 255));
- break;
- case CMAP_TRUE:
- if (img->mapmap[img->background] >= 0)
- color(img->mapmap[img->background]);
- else {
- int m;
-
- /* we haven't mapped any colours yet so collision isn't possible */
- m = rgb2newsmap(img->colourmap[img->background] & 255,
- (img->colourmap[img->background] >> 8) & 255,
- (img->colourmap[img->background] >> 16) & 255);
- img->mapmap[img->background] = m;
- color(m);
- }
- }
-
- if (erase_all) {
- rectf(0, 0, win_width, win_height);
- return;
- }
-
- if (img->imf->width >= win_width && img->imf->height >= win_height)
- return;
-
- xleft = (win_width - img->imf->width * mag) / 2;
- xright = win_width - img->imf->width * mag - xleft;
- ybottom = (win_height - img->imf->height * mag) / 2;
- ytop = win_height - img->imf->height * mag - ybottom;
-
- rectf(0, 0, win_width - 1, ybottom);
- rectf(0, 0, xleft, win_height - 1);
- rectf(0, win_height - ytop, win_width - 1, win_height - 1);
- rectf(win_width - xright, 0, win_width - 1, win_height - 1);
- }
-
- int incr_redraw(img, line)
- register struct mem_image* img;
- register int line;
- {
- static int argb_buf[XMAXSCREEN];
- register char* p;
- register int* argb;
-
- p = img->data + line * img->width + img->width - 1;
- argb = argb_buf + img->width - 1;
-
- while (argb >= argb_buf)
- *argb-- = img->colourmap[*p--];
-
- lrectwrite(img->x_off,
- (win_height - (line + 1) * mag) - img->y_off,
- img->width /* * mag */ - 1 + img->x_off,
- (win_height - (line + 1) * mag) - img->y_off,
- argb_buf);
-
- return(line + 1);
- }
-
-
- /* This is based on code From: moss@BRL.MIL ("Gary S. Moss", VLD/VMB) */
-
- int nonrect_incr_redraw(img, line)
- register struct mem_image* img;
- register int line;
- {
- static unsigned char Red_pixels[XMAXSCREEN];
- static unsigned char Green_pixels[XMAXSCREEN];
- static unsigned char Blue_pixels[XMAXSCREEN];
- register short i;
- register char* p;
- register char* red_map;
- register char* green_map;
- register char* blue_map;
-
- p = img->data + line * img->width;
-
- red_map = (char*)img->colourmap;
- green_map = (char*)img->colourmap + img->maplen;
- blue_map = (char*)img->colourmap + img->maplen * 2;
-
- for (i = 0; i < img->width * mag; i++, p++) {
- Red_pixels[i] = red_map[*p];
- Green_pixels[i] = green_map[*p];
- Blue_pixels[i] = blue_map[*p];
- if (mag == 2) {
- Red_pixels[++i] = red_map[*p];
- Green_pixels[i] = green_map[*p];
- Blue_pixels[i] = blue_map[*p];
- }
- }
-
- cmov2i(img->x_off, (win_height - (line + 1) * mag) - img->y_off);
- writeRGB(img->width * mag, Red_pixels, Green_pixels, Blue_pixels);
- if (mag == 2) {
- cmov2i(img->x_off, (win_height - (line + 1) * mag) - img->y_off + 1);
- writeRGB(img->width * mag, Red_pixels, Green_pixels, Blue_pixels);
- }
-
- return(line + 1);
- }
-
- int cmap_incr_redraw(img, line)
- register struct mem_image* img;
- register int line;
- {
- static unsigned short cmap[XMAXSCREEN];
- register short i;
- register char* p;
-
- p = img->data + line * img->width;
-
- for (i = 0; i < img->width * mag; i++, p++) {
- cmap[i] = img->mapmap[*p];
- if (mag == 2)
- cmap[++i] = img->mapmap[*p];
- }
-
- cmov2i(img->x_off, (win_height - (line + 1) * mag) - img->y_off);
- writepixels(img->width * mag, cmap);
- if (mag == 2) {
- cmov2i(img->x_off, (win_height - (line + 1) * mag) - img->y_off + 1);
- writepixels(img->width * mag, cmap);
- }
-
- return(line + 1);
- }
-
- /* auto-dectection code From: <cditi!caw@uunet.uucp> */
-
- void set_display_mode()
- {
- char buf[32];
-
- gversion(buf);
-
- if (getplanes() <= 8)
- disp_mode = true_colours ? CMAP_TRUE : CMAP_NEWS;
- else if (strncmp(buf, "GL4D-", 5) || !use_lrectwrite)
- disp_mode = RGB_WRITE;
- else
- disp_mode = RGB_LRECT;
- }
-
- struct map_entry {
- int orig_index;
- int abgr;
- int screen_index;
- int used;
- };
-
- static int colour_used[256];
-
- int map_ent_cmp(a, b)
- struct map_entry* a;
- struct map_entry* b;
- {
- if (!a->used)
- return(1);
- if (!b->used)
- return(-1);
- return(a->abgr - b->abgr);
- }
-
- static int abs(x)
- {
- if (x < 0) return(-x);
- return(x);
- }
-
- /*
- * Depending on how the images will be displayed, we may wish to
- * change the colour maps in our images into a more convenient form.
- * Lrectwrite() is the default, but writeRGB would rather have 3
- * tables. For screens with colour maps, we can either map the
- * images colour map into the screen colour map or load the screen
- * colour map with the image colour map. In the latter case we'll
- * want to compress the colourmap as much as possible to minimize
- * on-screen weirdness. It would also be nice to put the image
- * colours into screen map entries that won't change a lot when
- * they are re-loaded. We could also change the image data to
- * avoid a colourmap to colourmap conversion, but it probably isn't
- * worth it.
- *
- * This should really be 3 or 4 separate functions :-(
- */
- void adjust_colourmap(img)
- struct mem_image* img;
- {
- int i, r, g, b;
- int mindiff, best;
- unsigned char* red;
- unsigned char* green;
- unsigned char* blue;
- int new;
- char* p;
- int workspace[256];
- struct map_entry map[256];
-
- if (disp_mode == RGB_LRECT)
- return;
-
- if (disp_mode == RGB_WRITE) {
- /* do it for writeRGB */
- for (i = 0; i < img->maplen; i++)
- workspace[i] = img->colourmap[i];
- red = (unsigned char*)img->colourmap;
- green = (unsigned char*)img->colourmap + img->maplen;
- blue = (unsigned char*)img->colourmap + img->maplen * 2;
- for (i = 0; i < img->maplen; i++) {
- *red++ = workspace[i] & 255;
- *green++ = (workspace[i] >> 8) & 255;
- *blue++ = (workspace[i] >> 16) & 255;
- }
- return;
- }
-
- /*img->mapmap = (int*)malloc(img->maplen * sizeof(int));*/
- /* Don't necessarily need 256, but ... */
- img->mapmap = (int*)malloc(256 * sizeof(int));
- if (img->mapmap == NULL)
- no_mem();
-
- /* colourmapped display */
- if (disp_mode == CMAP_NEWS) {
- if (!dither) {
- for (i = 0; i < img->maplen; i++) {
- img->mapmap[i] = rgb2newsmap(
- r = img->colourmap[i] & 255,
- g = (img->colourmap[i] >> 8) & 255,
- b = (img->colourmap[i] >> 16) & 255
- );
- }
- }
- else {
- /* we're going to change all the indicies anyways... */
- for (i = 0; i < 256; i++)
- img->mapmap[i] = i;
- init_floydstein(img);
- }
- return;
- }
-
- /* disp_mode == CMAP_TRUE */
-
- /* A little kludge here. The basic idea is that all the images
- * which use a global colourmap should have the same mapmap. What
- * is not so pretty is that maybe the first image didn't use the
- * global map.
- */
- if (img->imf->imglist != img &&
- img->imf->imglist->colourmap == img->colourmap) {
- int qq;
-
- img->mapmap = img->imf->imglist->mapmap;
- for (i = 0; i < 256; i++)
- colour_used[i] = 0;
-
- for (i = 0; i < 256; i++)
- if (img->mapmap[i] >= 0)
- colour_used[img->mapmap[i]] = 1;
- return;
- }
-
- for (i = 0; i < 256; i++) {
- img->mapmap[i] = -1;
- colour_used[i] = 0;
- }
-
- #ifdef OLD
- /* disp_mode == CMAP_TRUE */
- /* ok, let's crank */
- for (i = 0; i < img->maplen; i++) {
- map[i].orig_index = i;
- map[i].abgr = img->colourmap[i];
- map[i].screen_index = -1;
- map[i].used = 0;
- }
-
- for (p = img->data, i = img->width * img->height; i > 0; i--)
- map[*p++].used = 1;
-
- qsort(map, img->maplen, sizeof(struct map_entry), map_ent_cmp);
-
- for (i = 1; i < img->maplen; i++) {
- if (!map[i].used)
- break; /* 'cause all the unused ones are at the end */
- if (map[i].abgr == map[i - 1].abgr)
- map[i].used = -1;
- }
-
- for (i = 0; i < 256; i++)
- workspace[i] = 0; /* i.e., we haven't used this screen colour */
-
- for (i = 0; i < img->maplen; i++) {
- if (!map[i].used)
- break;
- if (map[i].used == -1)
- continue;
- new = rgb2newsmap(map[i].abgr & 255,
- (map[i].abgr >> 8) & 255,
- (map[i].abgr >> 16) & 255
- );
- if (workspace[new] == 0) {
- workspace[new] = 1;
- map[i].screen_index = new;
- }
- }
-
- new = 0;
- for (i = 0; i < img->maplen; i++)
- if (map[i].used && map[i].screen_index == -1)
- new++;
- printf("%d hard colours to map\n", new);
-
- #ifdef SIMPFIT
- /*
- * allocate entries for the guys who collided; I should do some sort of
- * best fitting, but for now just start from the top. The only best
- * fit algorithm I can think of is rather expensive.
- */
- new = 255;
- for (i = 0; i < img->maplen; i++) {
- if (!map[i].used)
- break;
- if (map[i].screen_index != -1)
- continue;
- while (workspace[new])
- new--;
- workspace[new] = 1;
- map[i].screen_index = new;
- }
- #endif
-
- for (i = 0; i < img->maplen; i++) {
- int d;
- short r,g,b;
- if (!map[i].used)
- break;
- if (map[i].screen_index != -1)
- continue;
- best = 0;
- mindiff = 10000;
- for (new = 0; new < 256; new++) {
- if (workspace[new])
- continue;
- getmcolor(new, &r, &g, &b);
- d = abs(r - ((map[i].abgr & 255))) +
- abs(g - ((map[i].abgr >> 8) & 255)) +
- abs(b - ((map[i].abgr >> 16) & 255));
- if (d < mindiff) {
- best = new;
- mindiff = d;
- }
- }
- workspace[best] = 1;
- map[i].screen_index = best;
- }
-
- /* finally, re-define the image's colourmap. Don't forget about those
- * duplicate entries.
- */
- for (i = 0; i < img->maplen; i++)
- img->mapmap[i] = -1;
-
- for (i = 0; i < img->maplen; i++) {
- if (!map[i].used)
- break;
- if (map[i].used == -1)
- img->mapmap[map[i].orig_index] =
- img->mapmap[map[i - 1].orig_index];
- else
- img->mapmap[map[i].orig_index] = map[i].screen_index;
- }
- #endif
- }
-
- static short orig_colourmap[256 * 3];
- static int orig_cmap_inst = 1;
-
- true_cmap(img, line)
- struct mem_image* img;
- int line;
- {
- register unsigned char* p;
- register int i;
- register int try;
- short r,g,b;
-
- for (p = img->data + img->width * line, i = img->width; i >= 0; p++, i--) {
- if (img->mapmap[*p] >= 0)
- continue;
- try = rgb2newsmap(r = img->colourmap[*p] & 255,
- g = (img->colourmap[*p] >> 8) & 255,
- b = (img->colourmap[*p] >> 16) & 255
- );
- if (colour_used[try]) {
- int mindiff, d, j;
-
- try = 255;
- mindiff = 10000;
- for (j = 255; j >= 0; j--) {
- if (colour_used[j])
- continue;
- if ((d = abs(r - orig_colourmap[j * 3]) +
- abs(g - orig_colourmap[j * 3 + 1]) +
- abs(b - orig_colourmap[j * 3 + 2])) < mindiff) {
- try = j;
- mindiff = d;
- }
- }
- }
- img->mapmap[*p] = try;
- colour_used[try] = 1;
- if (!orig_cmap_inst && img->imf == cur_imf)
- mapcolor(try, r, g, b);
- }
- }
-
- void save_colourmap()
- {
- short* p;
- int i;
-
- for (i = 0, p = orig_colourmap; i < 256; i++, p += 3)
- getmcolor(i, p, p + 1, p + 2);
- }
-
- void set_colourmap(img)
- struct mem_image* img;
- {
- int i;
-
- for (i = 0; i < img->maplen; i++)
- if (img->mapmap[i] >= 0)
- mapcolor(img->mapmap[i],
- img->colourmap[i] & 255,
- (img->colourmap[i] >> 8) & 255,
- (img->colourmap[i] >> 16) & 255
- );
- orig_cmap_inst = 0;
- }
-
- void toggle_colourmap(img)
- struct mem_image* img;
- {
- if (orig_cmap_inst)
- set_colourmap(img);
- else
- restore_colourmap();
- }
-
- void restore_colourmap()
- {
- short* p;
- int i;
-
- for (i = 0, p = orig_colourmap; i < 256; i++, p += 3)
- mapcolor(i, p[0], p[1], p[2]);
- orig_cmap_inst = 1;
- }
-