/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * $XConsortium: GifUtils.c /main/5 1996/05/07 13:21:42 drk $ * Copyright (c) 1993 HAL Computer Systems International, Ltd. * All rights reserved. Unpublished -- rights reserved under * the Copyright Laws of the United States. USE OF A COPYRIGHT * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION * OR DISCLOSURE. * * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. USE, * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS * INTERNATIONAL, LTD. * * RESTRICTED RIGHTS LEGEND * Use, duplication, or disclosure by the Government is subject * to the restrictions as set forth in subparagraph (c)(l)(ii) * of the Rights in Technical Data and Computer Software clause * at DFARS 252.227-7013. * * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. * 1315 Dell Avenue * Campbell, CA 95008 * */ /* +-------------------------------------------------------------------+ */ /* | Portions lifted from giftoppm.c (pbmplus version 10dec91) | */ /* | | */ /* | Copyright 1990, David Koblas. | */ /* | 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. | */ /* +-------------------------------------------------------------------+ */ #define C_Gif #define L_Graphics #define C_MessageMgr #define L_Managers /* include files */ #include #include #include #include #include #include #include #include "GifUtilsI.h" #ifndef __STDC__ #define debug1(s, x) s << "x" << " = " << (x) << "\n" #else #define debug1(s, x) s << #x << " = " << (x) << "\n" #endif #define MAX_GHANDS 16 /* maximum # of GRAF handles */ #define PPM_ASSIGN(p,red,grn,blu) (p) = ((pixel) (red) << 20) | ((pixel) (grn) << 10) | (pixel) (blu) #define PPM_GETR(p) (((p) & 0x3ff00000) >> 20) #define PPM_GETG(p) (((p) & 0xffc00) >> 10) #define PPM_GETB(p) ((p) & 0x3ff) #define MAXCOLORMAPSIZE 256 #define TRUE 1 #define FALSE 0 #define CM_RED 0 #define CM_GREEN 1 #define CM_BLUE 2 #define MAX_LWZ_BITS 12 #define INTERLACE 0x40 #define LOCALCOLORMAP 0x80 #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define LM_to_uint(a,b) (((b)<<8)|(a)) typedef struct { unsigned int Width; unsigned int Height; unsigned char ColorMap[3][MAXCOLORMAPSIZE]; unsigned int BitPixel; unsigned int ColorResolution; unsigned int Background; unsigned int AspectRatio; } GifScreenType; typedef struct { int transparent; int delayTime; int inputFlag; int disposal; } Gif89Type; /* * This structure holds variables that were formerly global or static * within a function in the original giftoppm code. They have been * moved into this object to ensure thread re-entrancy of the routines * that use them. A unique instance of this object is created for each * thread and passed to the appropriate routines. */ typedef struct { /* Formerly global variables */ GifScreenType GifScreen; Gif89Type Gif89; int ZeroDataBlock; /* Formerly static variables declared in DoExtension */ char ext_buf[256]; /* Formerly static variables declared in GetCode */ unsigned char buf[280]; int curbit, lastbit, done, last_byte; /* Formerly static variables declared in LWZReadByte*/ int fresh; int code_size, set_code_size; int max_code, max_code_size; int firstcode, oldcode; int clear_code, end_code; int table[2][(1<< MAX_LWZ_BITS)]; int stack[(1<<(MAX_LWZ_BITS))*2], *sp; } GifState; /*********************/ static void _gif_error( char *format, ... ) { va_list args; va_start( args, format ); fprintf( stderr, "GifObject: " ); (void) vfprintf( stderr, format, args ); fputc( '\n', stderr ); va_end( args ); /* throw (Exception()); */ #if 0 abort(); #endif } /*********************/ static void _gif_message( char *format, ... ) { va_list args; va_start( args, format ); fprintf( stderr, "GifObject: " ); (void) vfprintf( stderr, format, args ); fputc( '\n', stderr ); va_end( args ); } /*********************/ static pixel ** _gif_allocarray( int cols, int rows, int size ) { char** its; int i; its = (char**) malloc( rows * sizeof(char*) ); if ( its == (char**) 0 ) _gif_error( "out of memory allocating an array", 0 ); its[0] = (char*) malloc( rows * cols * size ); if ( its[0] == (char*) 0 ) _gif_error( "out of memory allocating an array", 0 ); for ( i = 1; i < rows; ++i ) its[i] = &(its[0][i * cols * size]); return (pixel **)its; } /*********************/ static int GetDataBlock(byte **inbuf, unsigned char *buf, GifState *g) { unsigned char count; count = (*inbuf)[0]; (*inbuf)++; g->ZeroDataBlock = count == 0; if (count) { memcpy (buf, *inbuf, count); *inbuf += count; } return count; } /*********************/ static int ReadColorMap(byte **inbuf, int number, unsigned char buffer[3][MAXCOLORMAPSIZE]) { int i; unsigned char *rgb; for (i = 0; i < number; ++i) { rgb = (unsigned char *)*inbuf; *inbuf += 3; buffer[CM_RED][i] = rgb[0] ; buffer[CM_GREEN][i] = rgb[1] ; buffer[CM_BLUE][i] = rgb[2] ; } return FALSE; } /*********************/ static int DoExtension(byte **inbuf, int label, GifState *g) { char *str; char *buf = g->ext_buf; switch (label) { case 0x01: /* Plain Text Extension */ str = "Plain Text Extension"; break; case 0xff: /* Application Extension */ str = "Application Extension"; break; case 0xfe: /* Comment Extension */ str = "Comment Extension"; while (GetDataBlock(inbuf, (unsigned char*) buf, g) != 0) { #ifdef DEBUG _gif_message("gif comment: %s", buf ); #endif } return FALSE; case 0xf9: /* Graphic Control Extension */ str = "Graphic Control Extension"; (void) GetDataBlock(inbuf, (unsigned char*) buf, g); g->Gif89.disposal = (buf[0] >> 2) & 0x7; g->Gif89.inputFlag = (buf[0] >> 1) & 0x1; g->Gif89.delayTime = LM_to_uint(buf[1], buf[2]); if ((buf[0] & 0x1) != 0) g->Gif89.transparent = buf[3]; while (GetDataBlock(inbuf, (unsigned char*) buf, g) != 0) ; return FALSE; default: str = buf; sprintf(buf, "UNKNOWN (0x%02x)", label); break; } #ifdef DEBUG _gif_message("got a '%s' extension", str ); #endif while (GetDataBlock(inbuf, (unsigned char*) buf, g) != 0) ; return FALSE; } /*********************/ static int GetCode(byte **inbuf, int code_size, int flag, GifState *g) { int i, j, ret; unsigned char count; unsigned char *buf = g->buf; if (flag) { for (i = 0; i < 280; i++) buf[i] = 0; g->last_byte = 0; g->curbit = 0; g->lastbit = 0; g->done = FALSE; return 0; } if ( (g->curbit+code_size) >= g->lastbit) { if (g->done) { if (g->curbit >= g->lastbit) _gif_error("ran off the end of my bits", 0 ); return -1; } if (g->last_byte) { buf[0] = buf[g->last_byte-2]; buf[1] = buf[g->last_byte-1]; } if ((count = GetDataBlock(inbuf, &buf[2], g)) == 0) g->done = TRUE; g->last_byte = 2 + count; g->curbit = (g->curbit - g->lastbit) + 16; g->lastbit = (2+count)*8 ; } ret = 0; for (i = g->curbit, j = 0; j < code_size; ++i, ++j) ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; g->curbit += code_size; return ret; } /*********************/ static int LWZReadByte(byte **inbuf, int flag, int input_code_size, GifState *g) { int code, incode; int i; if (flag) { g->set_code_size = input_code_size; g->code_size = g->set_code_size+1; g->clear_code = 1 << g->set_code_size ; g->end_code = g->clear_code + 1; g->max_code_size = 2*g->clear_code; g->max_code = g->clear_code+2; GetCode(inbuf, 0, TRUE, g); g->fresh = TRUE; for (i = 0; i < g->clear_code; ++i) { g->table[0][i] = 0; g->table[1][i] = i; } for (; i < (1<table[0][i] = g->table[1][0] = 0; g->sp = g->stack; return 0; } else if (g->fresh) { g->fresh = FALSE; do { g->firstcode = g->oldcode = GetCode(inbuf, g->code_size, FALSE, g); } while (g->firstcode == g->clear_code); return g->firstcode; } if (g->sp > g->stack) return *--(g->sp); while ((code = GetCode(inbuf, g->code_size, FALSE, g)) >= 0) { if (code == g->clear_code) { for (i = 0; i < g->clear_code; ++i) { g->table[0][i] = 0; g->table[1][i] = i; } for (; i < (1<table[0][i] = g->table[1][i] = 0; g->code_size = g->set_code_size+1; g->max_code_size = 2*g->clear_code; g->max_code = g->clear_code+2; g->sp = g->stack; g->firstcode = g->oldcode = GetCode(inbuf, g->code_size, FALSE, g); return g->firstcode; } else if (code == g->end_code) { int count; unsigned char buf[260]; if (g->ZeroDataBlock) return -2; while ((count = GetDataBlock(inbuf, buf, g)) > 0) ; #ifdef DEBUG if (count != 0) _gif_message("missing EOD in data stream (common occurence)"); #endif return -2; } incode = code; if (code >= g->max_code) { *(g->sp)++ = g->firstcode; code = g->oldcode; } while (code >= g->clear_code) { *(g->sp++) = g->table[1][code]; if (code == g->table[0][code]) _gif_error("circular table entry BIG ERROR", 0); code = g->table[0][code]; } *(g->sp)++ = g->firstcode = g->table[1][code]; if ((code = g->max_code) <(1<table[0][code] = g->oldcode; g->table[1][code] = g->firstcode; ++(g->max_code); if ((g->max_code >= g->max_code_size) && (g->max_code_size < (1<max_code_size *= 2; ++(g->code_size); } } g->oldcode = incode; if (g->sp > g->stack) return *--(g->sp); } return code; } /*********************/ pixel ** ReadImage(byte **inbuf, int len, int height, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore, GifState *g) { unsigned char c; int v; int xpos = 0, ypos = 0, pass = 0; pixel **image; /* ** Initialize the Compression routines */ c = (*inbuf)[0]; (*inbuf)++; if (LWZReadByte(inbuf, TRUE, c, g) < 0) _gif_error("error reading image", 0 ); /* ** If this is an "uninteresting picture" ignore it. */ if (ignore) { #ifdef DEBUG _gif_message("skipping image..." ); #endif while (LWZReadByte(inbuf, FALSE, c, g) >= 0) ; return NULL; } if ((image = _gif_allocarray(len, height, sizeof(pixel))) == NULL) _gif_error("couldn't alloc space for image", 0 ); #ifdef DEBUG _gif_message("reading %d by %d%s GIF image", len, height, interlace ? " interlaced" : "" ); #endif while ((v = LWZReadByte(inbuf,FALSE,c, g)) >= 0 ) { PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v], cmap[CM_GREEN][v], cmap[CM_BLUE][v]); ++xpos; if (xpos == len) { xpos = 0; if (interlace) { switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { ++pass; switch (pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } else { ++ypos; } } if (ypos >= height) break; } fini: #ifdef DEBUG if (LWZReadByte(inbuf,FALSE,c, g)>=0) _gif_message("too much input data, ignoring extra..."); #endif return image; } /* //////////////////////////////////////////////////////////// // class constructor // ////////////////////////////////////////////////////////// */ enum _DtGrLoadStatus InitGifObject ( GifObj *go, Display *dpy, Drawable drawable, Screen *screen, int depth, Colormap colormap, Visual *visual, GC gc, enum _DtGrColorModel colorModel, Boolean allowReducedColors) { int r, g, b, i, visualsMatched; XVisualInfo vTemplate, *visualList; /* ** Initialize structure values */ go->bits_per_pixel = 2; go->colors_per_pixel = (int) pow (2, go->bits_per_pixel); go->total_colors = (int) pow (go->colors_per_pixel, 3); go->f_color_map_constructed = 0; go->f_total_greys = 2; go->f_ximage = NULL; go->f_dpy = dpy; go->f_drawable = drawable; go->f_screen = XScreenNumberOfScreen(screen); go->f_dft_depth = depth; go->f_cmap = colormap; go->f_gc = gc; go->f_visual = visual; go->f_ncells = DisplayCells(go->f_dpy, go->f_screen); go->f_nplanes = DisplayPlanes(go->f_dpy,go->f_screen); go->f_white = WhitePixel(go->f_dpy, go->f_screen); go->f_black = BlackPixel(go->f_dpy, go->f_screen); go->f_allow_reduced_colors = allowReducedColors; go->f_color_reduction_used = FALSE; /* ** Initialize color allocation fields according to the color model ** specified by the caller. */ switch (colorModel) { case _DtGrCOLOR: go->f_do_visual = DO_COLOR; go->f_init_total_greys = 32; break; case _DtGrGRAY_SCALE: go->f_do_visual = DO_GREY; go->f_init_total_greys = 32; break; case _DtGrBITONAL: go->f_do_visual = DO_GREY; go->f_init_total_greys = 2; break; default: /* Should never get here */ go->f_do_visual = DO_COLOR; go->f_init_total_greys = 32; } /* Return if the colormap is already allocated */ if ( go->f_color_map_constructed ) return (_DtGrSUCCESS); /* find the visual class code */ vTemplate.screen = go->f_screen; vTemplate.depth = go->f_dft_depth; visualList = XGetVisualInfo( go->f_dpy, VisualScreenMask | VisualDepthMask, &vTemplate, &visualsMatched ); /* Return failure if we can't find a matching visual */ if ( visualsMatched == 0 ) return (_DtGrCONVERT_FAILURE); go->f_visual_class = StaticGray; for ( i=0; if_visual ) { go->f_visual_class = visualList[i].class; break; } } XFree(visualList); /* Construct a 4x4x4 color cube */ i = 0; for (r = 0; r < go->colors_per_pixel; r++) for (g = 0; g < go->colors_per_pixel; g++) for (b = 0; b < go->colors_per_pixel; b++) { go->GifCMap[i].red = ((r * 65535)/(go->colors_per_pixel - 1)); go->GifCMap[i].green = ((g * 65535)/(go->colors_per_pixel - 1)); go->GifCMap[i].blue = ((b * 65535)/(go->colors_per_pixel - 1)); i++; } /* ** Allocate X pixels, either color or greyscale values depending upon ** visual class and color model. */ switch ( go->f_visual_class ) { case StaticGray: case GrayScale: case StaticColor: { /* ** Return failure if caller is insisting on color and this ** visual can't provide it. */ if ((colorModel == _DtGrCOLOR) && !allowReducedColors) return (_DtGrCOLOR_FAILED); if ( allocate_greys(go) != 0 ) return (_DtGrCOLOR_FAILED); break; } case PseudoColor: case DirectColor: case TrueColor: { if (colorModel == _DtGrCOLOR) { if ( allocate_colors(go) != 0 ) return (_DtGrCOLOR_FAILED); } else { if ( allocate_greys(go) != 0 ) return (_DtGrCOLOR_FAILED); } break; } default: return (_DtGrCONVERT_FAILURE); } /* ** Colors successfully allocated, return status code indicating ** whether we had to fallback to a degraded color model. */ if (go->f_color_reduction_used) return (_DtGrCOLOR_REDUCE); else return (_DtGrSUCCESS); } /* ///////////////////////////////////////////////////////////////// // class destructor // /////////////////////////////////////////////////////////////// */ void DeleteGifObjectResources(GifObj *g) { } int allocate_colors(GifObj *g) { int i, j; /*return allocate_greys(); // use this to test grey-scale */ XColor color; unsigned long* colors; color.flags = DoRed | DoGreen | DoBlue; for (i = 0; i < g->total_colors; i++) { color.red = g->GifCMap[i].red; color.green = g->GifCMap[i].green; color.blue = g->GifCMap[i].blue; /*printf ("Allocating %3d: ", i); */ if ( !XAllocColor (g->f_dpy, g->f_cmap, &color) ) { /*puts ("FAILED!!!"); */ colors = (unsigned long *) malloc (sizeof(unsigned long) * i); for (j = 0; j < i; j++) colors[j] = g->GifCMap[j].pixel; /*cerr << "Xfree in allocate_colors(): " << i << "\n"; */ XFreeColors (g->f_dpy, g->f_cmap, colors, i, 0); free(colors); /* fallback to greys */ if (g->f_allow_reduced_colors) { g->f_color_reduction_used = TRUE; return allocate_greys(g); } else return (_DtGrCOLOR_FAILED); } /*fprintf(stderr, "i=%d pixel=%d\n", i, color.pixel);*/ /*printf ("@ %d\n", color.pixel); */ g->GifCMap[i].pixel = color.pixel; } g->f_do_visual = DO_COLOR; g->f_color_map_constructed = 1; return 0; } int allocate_greys(GifObj *g) { XColor color; int i, j; unsigned long* colors; color.flags = DoRed | DoGreen | DoBlue; for ( i=0; itotal_colors; i++ ) { /* debug1(cerr, i); debug1(cerr, GifCMap[i].red); debug1(cerr, GifCMap[i].green); debug1(cerr, GifCMap[i].blue); debug1(cerr, 0.299 * GifCMap[i].red + 0.587 * GifCMap[i].green + 0.114 * GifCMap[i].blue); debug1(cerr, GifCMap[i].grey); */ g->GifCMap[i].grey = (unsigned short)(0.299 * g->GifCMap[i].red + 0.587 * g->GifCMap[i].green + 0.114 * g->GifCMap[i].blue); } /* if ( StaticColor == g->f_visual_class || TrueColor == g->f_visual_class ) */ if ( StaticColor == g->f_visual_class) { g->f_do_visual = DO_GREY; g->f_total_greys = 2; return 0; } for ( g->f_total_greys=g->f_init_total_greys; g->f_total_greys>=2; g->f_total_greys/=2 ) { /*fprintf(stderr, "f_total_greys = %d\n", g->f_total_greys); */ /* ** Return failure if we're about to downgrade from greyscale ** to dithered monochrome and we don't allow reduced colors. */ if ((g->f_total_greys == 2) && (g->f_init_total_greys > 2) && (!g->f_allow_reduced_colors)) return -1; for (i = 0; if_total_greys; i++) { color.red = color.green = color.blue = (i*65535)/(g->f_total_greys - 1); /*fprintf (stderr, "Allocating %3d: ", i);*/ if ( !XAllocColor (g->f_dpy, g->f_cmap, &color) ) { /*fprintf(stderr, "alloc Grey FAILED!!!");*/ colors = (unsigned long *) malloc (sizeof(unsigned long) * i); for (j = 0; j < i; j++) colors[j] = g->GifGMap[j]; /*cerr << "Xfree in allocate_greys()\n"; */ XFreeColors (g->f_dpy, g->f_cmap, colors, i, 0); free(colors); break; } /*printf ("@ %d\n", color.pixel); */ g->GifGMap[i] = color.pixel; } if ( i == g->f_total_greys ) { /* for ( int l=0; lf_color_map_constructed = 1; g->f_do_visual = DO_GREY; /* If greyscape was downgraded to bitonal, record the fact */ if ((g->f_total_greys == 2) && (g->f_init_total_greys > 2)) g->f_color_reduction_used = TRUE; return 0; } } return -1; } /* //////////////////////////////////////////////////////////// // Free allocated raw image data // ////////////////////////////////////////////////////////// */ void free_raw_image( pixel **image ) { free( (char *)image[0] ); free( (char *)image ); } /* //////////////////////////////////////////////////////////// // Decompress GIF data into raw bytes // ////////////////////////////////////////////////////////// */ pixel ** create_raw_image( byte *inbuf, unsigned int buflen, int *width, int *height, int imageNumber ) { unsigned char *buf; unsigned char *start_of_buf = inbuf; unsigned char c; unsigned char localColorMap[3][MAXCOLORMAPSIZE]; int useGlobalColormap; int bitPixel; int imageCount = 0; char version[4]; pixel **image; GifState g; /* Initialize the GIF state object */ g.Gif89.transparent = g.Gif89.delayTime = g.Gif89.inputFlag = -1; g.Gif89.disposal = 0; g.ZeroDataBlock = FALSE; g.fresh = FALSE; /* XXXSWM -- hack */ if (buflen < 13) { fprintf (stderr, "Not GIF Data, buffer too small\n"); return NULL; } buf = (unsigned char *)inbuf; inbuf += 6; if (strncmp((const char *)buf,"GIF",3) != 0) { fprintf( stderr, "GifObject: not GIF data\n" ); return NULL; } strncpy(version, (const char *)(buf + 3), 3); version[3] = '\0'; if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { fprintf (stderr, "bad version number, not '87a' or '89a'\n" ); return NULL; } buf = (unsigned char *)inbuf; inbuf += 7; g.GifScreen.Width = LM_to_uint(buf[0],buf[1]); g.GifScreen.Height = LM_to_uint(buf[2],buf[3]); g.GifScreen.BitPixel = 2<<(buf[4]&0x07); g.GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1); g.GifScreen.Background = buf[5]; g.GifScreen.AspectRatio = buf[6]; if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ if (ReadColorMap(&inbuf,g.GifScreen.BitPixel,g.GifScreen.ColorMap)) { fprintf (stderr, "error reading global colormap\n" ); return NULL; } } if (g.GifScreen.AspectRatio != 0 && g.GifScreen.AspectRatio != 49) { float r; r = ( (float) g.GifScreen.AspectRatio + 15.0 ) / 64.0; #ifdef DEBUG _gif_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'", r < 1.0 ? 'x' : 'y', r < 1.0 ? 1.0 / r : r ); #endif } image = NULL; for (;;) { if (inbuf - start_of_buf >= buflen) { fprintf (stderr, "Premature EOF in GIF data\n"); return NULL; } c = inbuf[0]; inbuf++; if (c == ';') { /* GIF terminator */ if (imageCount < imageNumber) _gif_error("only %d image%s found in file", imageCount, imageCount>1?"s":"" ); return image; } if (c == '!') { /* Extension */ if (inbuf - start_of_buf >= buflen) { fprintf (stderr, "Premature EOF in GIF data\n"); return NULL; } c = inbuf[0]; inbuf++; DoExtension(&inbuf, c, &g); continue; } if (c != ',') { /* Not a valid start character */ #ifdef DEBUG _gif_message("bogus character 0x%02x, ignoring", (int) c ); #endif continue; } ++imageCount; buf = (unsigned char *)inbuf; inbuf += 9; useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP); bitPixel = 1<<((buf[8]&0x07)+1); *width = LM_to_uint(buf[4],buf[5]); *height = LM_to_uint(buf[6],buf[7]); if (! useGlobalColormap) { if (ReadColorMap(&inbuf, bitPixel, localColorMap)) _gif_error("error reading local colormap", 0 ); image = ReadImage(&inbuf, *width, *height, localColorMap, BitSet(buf[8], INTERLACE), imageCount != imageNumber, &g); } else { image = ReadImage(&inbuf, *width, *height, g.GifScreen.ColorMap, BitSet(buf[8], INTERLACE), imageCount != imageNumber, &g); } } } /* //////////////////////////////////////////////////////////// // Create X pixmap from raw image data // ////////////////////////////////////////////////////////// */ /* from "Computer Graphics" by Foley, VanDam, Feiner, Hughes */ /* 2nd edition */ static int dither_8X8[8][8] = { { 0, 32, 8, 40, 2, 34, 10, 42 }, { 48, 16, 56, 24, 50, 18, 58, 26 }, { 42, 44, 4, 36, 14, 46, 6, 38 }, { 60, 28, 52, 20, 62, 30, 54, 22 }, { 3, 35, 11, 43, 1, 33, 9, 41 }, { 51, 19, 59, 27, 49, 17, 57, 25 }, { 15, 47, 7, 39, 13, 45, 5, 37 }, { 63, 31, 55, 23, 61, 29, 53, 21 } }; /*static int dither_6X6[6][6] = //{ // { 24, 32, 16, 26, 34, 18}, // { 4, 0, 12, 6, 2, 14}, // { 20, 8, 28, 22, 10, 30}, // { 27, 35, 19, 25, 33, 17}, // { 7, 3, 15, 5, 1, 13}, // { 23, 11, 31, 21, 9, 29} //}; */ /* static int dither_4X4[4][4] = { { 0, 8, 2, 10 }, { 12, 4, 14, 6}, { 3, 11, 1, 9}, { 15, 7, 13, 5} }; static int dither_3X3[3][3] = { { 6, 8, 4 }, { 1, 0, 3}, { 5, 2, 7} }; static int dither_2X2[2][2] = { { 0, 2 }, { 3, 1} }; */ /*static int dither_matrix_sz = 2; */ /*static int dither_matrix_sz = 4; */ /*static int dither_matrix_sz = 3; */ static int dither_matrix_sz = 8; /* call XListPixFormat() to get bits/pix and pads ? */ Pixmap create_pixmap( GifObj *g, pixel **image, int width, int height, Pixel fg, Pixel bg, float ratio) { int nullCount = (4 - (width % 4)) & 0x03; int ximWidth = width + nullCount; byte *ximData = 0; pixel *ipp = *image; int spacing; long pixval; int x, y; int index; Pixmap pm; int scaledWidth, scaledHeight; if ( g->f_nplanes > 8 ) ximData = (byte *) malloc(ximWidth * height * 4 ); else ximData = (byte *) malloc(ximWidth * height ); if (!ximData) { fprintf(stderr, "Could not allocate ximage data\n"); return None; } /* Monochrome */ if (g->f_nplanes == 1) g->f_ximage = XCreateImage(g->f_dpy, g->f_visual, g->f_nplanes, XYPixmap, 0, (char *)ximData, width, height, 32, 0); /* 8 bit color */ /*else if (g->f_nplanes == 8) */ /* non-mono display */ else g->f_ximage = XCreateImage(g->f_dpy, g->f_visual, g->f_nplanes, ZPixmap, 0, (char *)ximData, width, height, 32, 0); if (!g->f_ximage) { fprintf(stderr, "XCreateImage failed\n"); return None; } /* RGB to Pixel Conversion */ if ( g->f_total_greys == 2 ) spacing = 65536 / (dither_matrix_sz * dither_matrix_sz); else spacing = 65536 / g->f_total_greys; /*cerr << "spacing" << spacing << "\n"; */ for (y=0; y < height; y++) { for (x=0; x < width; x++) { pixval = (long)*ipp; /* XColor cellDef; */ /* cellDef.red = (short)PPM_GETR(pixval); */ /* cellDef.green = (short)PPM_GETG(pixval); */ /* cellDef.blue = (short)PPM_GETB(pixval); */ index = (((short)PPM_GETR(pixval))/64)*16 + (((short)PPM_GETG(pixval))/64)*4 + ((short)PPM_GETB(pixval))/64; /*fprintf(stderr, "grey= %d, grey/space=%d\n", g->GifCMap[index].grey, g->GifCMap[index].grey / spacing);*/ switch (g->f_do_visual) { case DO_GREY: switch ( g->f_total_greys ) { case 2: /*cerr << "index=" << index << "\n"; */ /*cerr << "GifCMap[index].grey" << GifCMap[index].grey << "\n"; */ /*cerr << "GifCMap[index].grey/spacing" << GifCMap[index].grey / spacing << "\n"; */ if ( dither_8X8[x%dither_matrix_sz][y%dither_matrix_sz] < g->GifCMap[index].grey / spacing ) { XPutPixel(g->f_ximage,x,y,g->f_white); } else { XPutPixel(g->f_ximage,x,y,g->f_black); } break; default: /*cerr << GifCMap[index].grey / spacing << " "; */ XPutPixel(g->f_ximage,x,y, g->GifGMap[g->GifCMap[index].grey / spacing]); } break; case DO_COLOR: #ifdef FLOOD fprintf(stderr, "%03d %03d %03d -- %03d %03d %03d ", (short)PPM_GETR(pixval),(short)PPM_GETG(pixval),(short)PPM_GETB(pixval), g->GifCMap[index].red>>8, g->GifCMap[index].green>>8, g->GifCMap[index].blue>>8 ); if ((short)PPM_GETR(pixval) != (GifCMap[index].red>>8) || (short)PPM_GETG(pixval) != (GifCMap[index].green>>8) || (short)PPM_GETB(pixval) != (GifCMap[index].blue>>8)) puts (" *"); else puts (" -"); #endif XPutPixel(g->f_ximage,x,y, g->GifCMap[index].pixel); /* switch ( g->f_visual_class ) { case StaticColor: case PseudoColor: XPutPixel(g->f_ximage,x,y, g->GifCMap[index].pixel); break; case TrueColor: case DirectColor: break; } */ } ipp++; } for (x=width;xf_ximage,x,y,bg); /* padding */ } scaledWidth = width * ratio + 0.5; scaledHeight = height * ratio + 0.5; if (scaledWidth == 0) scaledWidth = 1; if (scaledHeight == 0) scaledHeight = 1; pm = XCreatePixmap(g->f_dpy,g->f_drawable, scaledWidth,scaledHeight, g->f_nplanes); if (!pm) { fprintf(stderr, "could not create pixmap\n"); return None; } _XmPutScaledImage (g->f_dpy,pm,g->f_gc,g->f_ximage, 0,0,0,0,width,height, scaledWidth,scaledHeight); XDestroyImage(g->f_ximage); g->f_ximage = NULL; return(pm); } /* ///////////////////////////////////////////////////////////////// // Load pixmap from GIF data // /////////////////////////////////////////////////////////////// */ Pixmap gif_to_pixmap(GifObj *g, byte *inbuf, unsigned int buflen, Dimension *w, Dimension *h, Pixel fg, Pixel bg, float ratio) { Pixmap pixmap; pixel **raw_image; int width, height; /* Create raw image from compress GIF data */ raw_image = create_raw_image (inbuf, buflen, &width, &height, 1); if (!raw_image) return None; /* Create X pixmap from raw image data */ pixmap = create_pixmap(g, raw_image, width, height, fg, bg, ratio); /* Free raw image data */ free_raw_image(raw_image); /* Set X pixmap dimensions */ *w = (Dimension) width * ratio + 0.5; *h = (Dimension) height * ratio + 0.5; if (*w == 0) *w = 1; if (*h == 0) *h = 1; /* Return X pixmap */ return pixmap; }