/* image.c - creates textured background and other pixmap stuff */ #include #include #include #include #include #include #include #include #include "HTList.h" #include "HTAccess.h" #include "www.h" extern Display *display; extern int screen; extern Window win; extern unsigned long labelColor, textColor, statusColor, strikeColor, transparent, windowColor, windowBottomShadow, windowShadow; extern int depth; extern int IsIndex; extern Doc *CurrentDoc; extern Context *context; extern int tileWidth, tileHeight; extern unsigned char *tileData; extern Pixmap default_pixmap; extern int default_pixmap_width, default_pixmap_height; extern Colormap colormap; extern int Magic256[256]; extern int Magic16[256]; extern int Magic32[256]; extern int Magic64[256]; extern GC disp_gc; extern unsigned int win_width, win_height; extern int debug; extern double Gamma; Pixmap smile, frown, note_pixmap, caution_pixmap, warning_pixmap; int imaging; /* set to COLOR888, COLOR232, GREY4 or MONO */ Image *images; /* linked list of images */ Image *note_image, *caution_image, *warning_image; /* standard icons */ unsigned long stdcmap[128]; /* 2/3/2 color maps for gifs etc */ unsigned long greymap[16]; /* for mixing with unsaturated colors */ #define smile_xbm_width 15 #define smile_xbm_height 15 static unsigned char smile_xbm_bits[] = { 0x1f, 0x7c, 0xe7, 0x73, 0xfb, 0x6f, 0xfd, 0x5f, 0xfd, 0x5f, 0xce, 0x39, 0xce, 0x39, 0xfe, 0x3f, 0xfe, 0x3f, 0xee, 0x3b, 0xdd, 0x5d, 0x3d, 0x5e, 0xfb, 0x6f, 0xe7, 0x73, 0x1f, 0x7c}; #define frown_xbm_width 15 #define frown_xbm_height 15 static unsigned char frown_xbm_bits[] = { 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f}; #define note_width 26 #define note_height 39 static unsigned char note_bits[] = { 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x38, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x7c, 0xfc, 0x30, 0xc6, 0x7c, 0xfc, 0x78, 0xef, 0x7d, 0xfc, 0x78, 0xef, 0x7f, 0xfc, 0x78, 0xef, 0x7f, 0xfc, 0x7c, 0x2f, 0x00, 0xfc, 0x7c, 0xcf, 0xff, 0xfc, 0x7c, 0xcf, 0xff, 0xfc, 0x7c, 0xcf, 0xff, 0xfc, 0x7c, 0x2f, 0xff, 0xfc, 0x7c, 0xef, 0xf8, 0xfc, 0x7c, 0xef, 0xfd, 0xfc, 0x38, 0xef, 0xfd, 0xfc, 0xc0, 0xf9, 0xff, 0xfc, 0xe0, 0xff, 0xff, 0xfc, 0xe0, 0xff, 0xff, 0xfc, 0xe0, 0xff, 0xff, 0xfc, 0xe0, 0xff, 0xff, 0xfc, 0xc0, 0xff, 0xff, 0xfc, 0x80, 0xff, 0x3f, 0xfc, 0x00, 0xff, 0x1f, 0xfc, 0x00, 0xff, 0x0f, 0xfc, 0x00, 0xff, 0x0f, 0xfc, 0x00, 0xff, 0x0f, 0xfc, 0x00, 0xff, 0x0f, 0xfc, 0x00, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc}; #define caution_width 26 #define caution_height 38 static unsigned char caution_bits[] = { 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xc0, 0x00, 0xfc, 0x00, 0xe0, 0x01, 0xfc, 0x00, 0xee, 0x19, 0xfc, 0x00, 0xef, 0x3d, 0xfc, 0x00, 0xef, 0x3d, 0xfc, 0x00, 0xef, 0x3d, 0xfc, 0x00, 0xef, 0x3d, 0xfc, 0x70, 0xef, 0x3d, 0xfc, 0x78, 0xef, 0x3d, 0xfc, 0x78, 0xef, 0x3d, 0xfc, 0x78, 0xef, 0x3d, 0xfc, 0x78, 0xef, 0x3d, 0xfc, 0x78, 0xef, 0xdd, 0xfc, 0x78, 0xef, 0xed, 0xfc, 0x78, 0xff, 0xef, 0xfc, 0xf8, 0xff, 0xf7, 0xfc, 0xf8, 0xff, 0xf7, 0xfc, 0xf8, 0xff, 0xf7, 0xfc, 0xf8, 0xff, 0xf7, 0xfc, 0xf8, 0xff, 0xf9, 0xfc, 0xf8, 0x7f, 0xfe, 0xfc, 0xf8, 0xbf, 0xff, 0xfc, 0xf8, 0xbf, 0xff, 0xfc, 0xf8, 0xdf, 0xff, 0xfc, 0xf8, 0xdf, 0xff, 0xfc, 0xf8, 0xdf, 0xff, 0xfc, 0xf0, 0xff, 0x7f, 0xfc, 0xe0, 0xff, 0x3f, 0xfc, 0x80, 0xff, 0x0f, 0xfc, 0x80, 0xff, 0x07, 0xfc, 0x80, 0xff, 0x07, 0xfc, 0x80, 0xff, 0x07, 0xfc, 0x80, 0xff, 0x07, 0xfc, 0x80, 0xff, 0x07, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc}; #define warning_width 26 #define warning_height 38 static unsigned char warning_bits[] = { 0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0xfc,0x00,0xc0,0x00,0xfc,0x00,0xe0,0x01, 0xfc,0x00,0xee,0x19,0xfc,0x00,0xef,0x3d,0xfc,0x00,0xef,0x3d,0xfc,0x00,0xef, 0x3d,0xfc,0x00,0xef,0x3d,0xfc,0x70,0xef,0x3d,0xfc,0x78,0xef,0x3d,0xfc,0x78, 0x2f,0x30,0xfc,0x78,0x0f,0x38,0xfc,0x78,0x0f,0x3c,0xfc,0x78,0x07,0xde,0xfc, 0x78,0x07,0xef,0xfc,0xf8,0x03,0xef,0xfc,0xf8,0x01,0xf6,0xfc,0xf8,0x0f,0xf7, 0xfc,0xf8,0x8f,0xf7,0xfc,0xf8,0xe7,0xf7,0xfc,0xf8,0xf3,0xf9,0xfc,0xf8,0x79, 0xfe,0xfc,0xf8,0xbe,0xff,0xfc,0xf8,0xbf,0xff,0xfc,0xf8,0xdf,0xff,0xfc,0xf8, 0xdf,0xff,0xfc,0xf8,0xdf,0xff,0xfc,0xf0,0xff,0x7f,0xfc,0xe0,0xff,0x3f,0xfc, 0x80,0xff,0x0f,0xfc,0x80,0xff,0x07,0xfc,0x80,0xff,0x07,0xfc,0x80,0xff,0x07, 0xfc,0x80,0xff,0x07,0xfc,0x80,0xff,0x07,0xfc,0x00,0x00,0x00,0xfc,0x00,0x00, 0x00,0xfc}; Image *DefaultImage(Image *image) { if (image->npixels > 0) { XFreeColors(display, colormap, image->pixels, image->npixels, 0); Free(image->pixels); image->pixels = NULL; image->npixels = 0; } image->pixmap = default_pixmap; image->width = default_pixmap_width; image->height = default_pixmap_height; image->next = images; images = image; return image; } /* don't add this to images list to avoid trouble when freeing document images */ Image *MakeIcon(unsigned int depth, char *name, int width, int height, char *bits) { GC drawGC; Pixmap pixmap; XImage *ximage; Image *image; unsigned char *data, *p, *s; int size, i, j, k, c; unsigned int byte; size = width * height; if (size == 0) return NULL; image = (Image *)malloc(sizeof(Image)); image->url = name; image->npixels = 0; image->pixels = 0; image->next = NULL; image->width = width; image->height = height; s = (unsigned char*)bits; if (depth == 8) { p = data = (unsigned char *)malloc(size); for (i = 0; i < height; ++i) for (j = 0, k= 8; j < width; ++j) { if (++k > 8) /* need to read next 8 pixel values */ { byte = *s++; k = 1; } if (byte & 0x01) *p++ = textColor; else p = Transparent(p, j, i); byte = byte >> 1; } } else if (depth == 24) { p = data = (unsigned char *)malloc(size * 4); for (i = 0; i < height; ++i) for (j = 0, k= 8; j < width; ++j) { if (++k > 8) /* need to read next 8 pixel values */ { byte = *s++; k = 1; } if (byte & 1) { *p++ = '\0'; *p++ = (textColor >> 16) & 0xFF; *p++ = (textColor >> 8) & 0xFF; *p++ = textColor & 0xFF; } else p = Transparent(p, j, i); byte = byte >> 1; } } else if (depth == 4 || depth == 2 || depth == 1) { int ppb, bpl, shift; ppb = 8/depth; /* pixels per byte */ bpl = width/ppb + (width%ppb ? 1 : 0); /* bytes per line */ p = data = (unsigned char *)malloc(bpl * height); *p = 0; for (i = 0; i < height; ++i) { for (j = 0, k= 8; j < width; ++j) { if (++k > 8) /* need to read next 8 pixel values */ { byte = *s++; k = 1; } if (byte & 0x01) { shift = (((7 - (j % 8)) % ppb) * depth); *p |= textColor << shift; if (shift == 0) { p++; *p = 0; } } else { shift = (((7 - (j % 8)) % ppb) * depth); *p |= transparent << shift; if (shift == 0) { p++; *p = 0; } } byte = byte >> 1; } if (shift) { p++; /* make sure we start on a new byte for the next line */ *p = 0; } } } else { fprintf(stderr,"Icons for display depth %d unsupported\n", depth); return NULL; } if ((ximage = XCreateImage(display, DefaultVisual(display, screen), depth, ZPixmap, 0, (char *)data, width, height, (depth == 24 ? 32 : 8), 0)) == 0) { Warn("Failed to create XImage: %s", image->url); Free(data); return DefaultImage(image); } /* howcome 22/2/95: do we need to set these?? */ ximage->byte_order = MSBFirst; ximage->bitmap_bit_order = MSBFirst; if ((pixmap = XCreatePixmap(display, win, width, height, depth)) == 0) { Warn("Failed to create Pixmap: %s", image->url); XDestroyImage(ximage); /* also free's image data */ return DefaultImage(image); } drawGC = XCreateGC(display, pixmap, 0, 0); XSetFunction(display, drawGC, GXcopy); XPutImage(display, pixmap, drawGC, ximage, 0, 0, 0, 0, width, height); XFreeGC(display, drawGC); XDestroyImage(ximage); /* also free's image data */ image = (Image *)malloc(sizeof(Image)); image->url = name; image->npixels = 0; image->pixels = 0; image->next = NULL; image->width = width; image->height = height; image->pixmap = pixmap; return image; } void MakeIcons(unsigned int depth) { note_image = MakeIcon(depth, "note", note_width, note_height, note_bits); caution_image = MakeIcon(depth, "caution", caution_width, caution_height, caution_bits); warning_image = MakeIcon(depth, "warning", warning_width, warning_height, warning_bits); } #if 0 void MakeFaces(unsigned int depth) { smile = XCreateBitmapFromData(display, win, smile_xbm_bits, smile_xbm_width, smile_xbm_height); frown = XCreateBitmapFromData(display, win, frown_xbm_bits, frown_xbm_width, frown_xbm_height); } void PaintFace(int sad) { int x1, y1, w, h; Pixmap face; XRectangle displayRect; face = (sad ? frown : smile); x1 = win_width - smile_xbm_width - 4; y1 = win_height - smile_xbm_height - 6; w = smile_xbm_width; h = smile_xbm_height; displayRect.x = 0; displayRect.y = 0; displayRect.width = win_width; displayRect.height = win_height; XSetClipRectangles(display, disp_gc, 0, 0, &displayRect, 1, Unsorted); XSetForeground(display, disp_gc, strikeColor); XSetBackground(display, disp_gc, windowColor); XCopyPlane(display, face, win, disp_gc, 0, 0, w, h, x1, y1, 0x01); XSetForeground(display, disp_gc, textColor); } #endif /* range is 0 to 65535 for use in getting colors from X11 */ int Brightness2Voltage(int brightness) { double voltage; static double log_a = 0; /* howcome added double */ if (brightness == 0) return 0; if (log_a == 0) log_a = (Gamma - 1.0) * log((double)65535); /* cast added by howcome 21/9/94 */ voltage = (log_a + log((double)brightness))/Gamma; /* cast added by howcome 21/9/94 */ return (int)(0.5 + exp(voltage)); } /* range is 0 to 255 for GIF colormap */ int Voltage2Brightness(int voltage) { double brightness; static double log_a; if (voltage == 0) return 0; if (log_a == 0) log_a = (Gamma - 1.0) * log((double)255); /* cast added by howcome 21/9/94 */ brightness = Gamma * log((double)voltage) - log_a; /* cast added by howcome 21/9/94 */ return (int)(0.5 + exp(brightness)); } int AllocStandardColors(void) { unsigned long r, g, b, i; XColor colors[127]; /* howcome 5/10/94 */ int status[127]; /* howcome 5/10/94 */ XColor color; stdcmap[0] = BlackPixel(display, screen); stdcmap[127] = WhitePixel(display, screen); for (i = 1; i < 127; ++i) { color.red = (i & 0x3) * 65535/3; color.green = ((i >> 2) & 0x7) * 65535/7; color.blue = ((i >> 5) & 0x3) * 65535/3; /* howcome 5/10/94: added support for XAllocColors which will speed things up. */ /* map brightness values into voltages for Gamma correction */ colors[i].red = Brightness2Voltage(color.red); colors[i].green = Brightness2Voltage(color.green); colors[i].blue = Brightness2Voltage(color.blue); } /* howcome 5/10/94: here comes the one and only call to XAllocColors */ if (XAllocColors(display, colormap, colors, i, status)) { for (i = 1; i < 127; i++ ) stdcmap[i] = colors[i].pixel; } else { for (i = 1; i < 127; i++ ) if (status[i]) { XFreeColors( display, colormap, &colors[i].pixel, 1, 0L ); } fprintf(stderr,"Can't alloc colors!\n"); return 0; } return 1; } int AllocGreyScale(void) { unsigned long g; XColor color; greymap[0] = BlackPixel(display, screen); greymap[15] = WhitePixel(display, screen); for (g = 1; g < 15; ++g) { color.red = color.green = color.blue = (65535/15) * g; /* map brightness values into voltages for Gamma correction */ color.red = Brightness2Voltage(color.red); color.green = Brightness2Voltage(color.green); color.blue = Brightness2Voltage(color.blue); if (XAllocColor(display, colormap, &color) == 0) { fprintf(stderr, "Can't allocate standard grey palette\n"); while (g > 1) XFreeColors(display, colormap, &(greymap[--g]), 1, 0); return 0; } greymap[g] = color.pixel; } return 1; } int SupportTrueColor(void) { long visual_info_mask; int number_visuals, i, flag; XVisualInfo *visual_array, visual_info_template; visual_info_template.screen = DefaultScreen(display); visual_info_mask = VisualClassMask | VisualScreenMask; visual_info_template.class = TrueColor; visual_array = XGetVisualInfo(display, visual_info_mask, &visual_info_template, &number_visuals); for (i = flag = 0; i < number_visuals; ++i) { if (visual_array[i].depth == 24) { flag = 1; break; } } XFree((void *)visual_array); return flag; } int InitImaging(int ColorStyle) { imaging = MONO; greymap[0] = BlackPixel(display, screen); greymap[15] = WhitePixel(display, screen); if (ColorStyle == MONO) { imaging = ColorStyle; return imaging; } if (ColorStyle == COLOR888 && SupportTrueColor()) { imaging = ColorStyle; return imaging; } if (AllocGreyScale()) { imaging = GREY4; if (ColorStyle == GREY4) return imaging; if (AllocStandardColors()) imaging = COLOR232; } return imaging; } void ReportVisuals(void) { long visual_info_mask; int number_visuals, i; XVisualInfo *visual_array, visual_info_template; visual_info_template.screen = DefaultScreen(display); visual_info_mask = VisualClassMask | VisualScreenMask; printf("TrueColor:\n"); visual_info_template.class = TrueColor; visual_array = XGetVisualInfo(display, visual_info_mask, &visual_info_template, &number_visuals); for (i = 0; i < number_visuals; ++i) { printf(" visual Id 0x%x\n", visual_array[i].visualid); printf(" depth = %d, bits per rgb = %d, size = %d\n", visual_array[i].depth, visual_array[i].bits_per_rgb, visual_array[i].colormap_size); printf(" rgb masks %lx, %lx, %lx\n", visual_array[i].red_mask, visual_array[i].green_mask, visual_array[i].blue_mask); } XFree((void *)visual_array); printf("DirectColor:\n"); visual_info_template.class = DirectColor; visual_array = XGetVisualInfo(display, visual_info_mask, &visual_info_template, &number_visuals); for (i = 0; i < number_visuals; ++i) { printf(" visual Id 0x%x\n", visual_array[i].visualid); printf(" depth = %d, bits per rgb = %d, size = %d\n", visual_array[i].depth, visual_array[i].bits_per_rgb, visual_array[i].colormap_size); printf(" rgb masks %lx, %lx, %lx\n", visual_array[i].red_mask, visual_array[i].green_mask, visual_array[i].blue_mask); } XFree((void *)visual_array); printf("PseudoColor:\n"); visual_info_template.class = PseudoColor; visual_array = XGetVisualInfo(display, visual_info_mask, &visual_info_template, &number_visuals); for (i = 0; i < number_visuals; ++i) { printf(" visual Id 0x%x\n", visual_array[i].visualid); printf(" depth = %d, bits per rgb = %d, size = %d\n", visual_array[i].depth, visual_array[i].bits_per_rgb, visual_array[i].colormap_size); printf(" rgb masks %lx, %lx, %lx\n", visual_array[i].red_mask, visual_array[i].green_mask, visual_array[i].blue_mask); } XFree((void *)visual_array); } void ReportStandardColorMaps(Atom which_map) { XStandardColormap *std_colormaps; int i, number_colormaps; char *atom_name; if (XGetRGBColormaps(display, RootWindow(display, screen), &std_colormaps, &number_colormaps, which_map) != 0) { atom_name = XGetAtomName(display, which_map); printf("\nPrinting %d standard colormaps for %s\n", number_colormaps, atom_name); XFree(atom_name); for (i = 0; i < number_colormaps; ++i) { printf("\tColormap: 0x%x\n", std_colormaps[i].colormap); printf("\tMax cells (rgb): %d, %d, %d\n", std_colormaps[i].red_max, std_colormaps[i].green_max, std_colormaps[i].blue_max); printf("\tMultipliers: %d, %d, %d\n", std_colormaps[i].red_mult, std_colormaps[i].green_mult, std_colormaps[i].blue_mult); printf("\tBase pixel: %d\n", std_colormaps[i].base_pixel); printf("\tVisual Id 0x%x, Kill Id 0x%x\n", std_colormaps[i].visualid, std_colormaps[i].killid); } XFree((void *)std_colormaps); } } /* create a textured background as paper */ unsigned char *CreateBackground(unsigned int width, unsigned int height, unsigned int depth) { unsigned char *data, *p; int size, i, j, n, max, m1, m2, m3; unsigned long c, cs[3]; /* howcome 21/9/94 */ unsigned long int ulp; if (depth == 8) { /* howcome 4/10/94: changed last arg to GetColor */ if (!GetColor(230, 218, 194, &cs[0])) return NULL; if (!GetColor(220, 209, 186, &cs[1])) return NULL; if (!GetColor(210, 199, 177, &cs[2])) return NULL; size = width * height; } else if (depth == 24) size = width * height * 4; else return NULL; p = data = (unsigned char *)malloc(size); if (data == NULL) return NULL; srand(0x6000); if (depth == 8) { for (i = 0; i < height; ++i) for (j = 0; j < width; ++j) { /* howcome 21/9/94: rand returns different ranges on different platforms, therefore: */ c = cs[rand() % 3]; /* n = rand(); if (n > 0x5000) c = c1; else if (n > 0x3000) c = c2; else c = c3; */ *p++ = (c & 0xFF); } } else { for (i = 0; i < height; ++i) for (j = 0; j < width; ++j) { *p++ = '\0'; /* howcome 21/9/94: the rand return value should be treated as above */ /* From Scott Nelson 24bit color 1/12/94 Dec 1 1994 */ switch (rand() % 3) { case 0: GetColor(230, 218, 194, &ulp); *p++ = ((char*)&ulp)[1]; *p++ = ((char*)&ulp)[2]; *p++ = ((char*)&ulp)[3]; break; case 1: GetColor(220, 209, 186, &ulp); *p++ = ((char*)&ulp)[1]; *p++ = ((char*)&ulp)[2]; *p++ = ((char*)&ulp)[3]; break; case 2: GetColor(210, 199, 177, &ulp); *p++ = ((char*)&ulp)[1]; *p++ = ((char*)&ulp)[2]; *p++ = ((char*)&ulp)[3]; break; } /* Scott's patch replaced this: switch (rand() % 3) { case 0: *p++ = 230; *p++ = 218; *p++ = 194; break; case 1: *p++ = 220; *p++ = 209; *p++ = 186; break; case 2: *p++ = 210; *p++ = 199; *p++ = 177; break; } */ /* n = rand(); if (n > 0x5000) { *p++ = 230; *p++ = 218; *p++ = 194; } else if (n > 0x3000) { *p++ = 220; *p++ = 209; *p++ = 186; } else { *p++ = 210; *p++ = 199; *p++ = 177; } */ } } return data; } #if 0 /* used to allow for nested comments */ /* XPM */ /********************************************************/ /** (c) Copyright Hewlett-Packard Company, 1992. **/ /********************************************************/ static char ** arizona.l.px = { /* width height ncolors cpp [x_hot y_hot] */ "28 38 13 1", /* colors */ " s iconColor2 m white c white", ". s iconGray2 m white c #c8c8c8c8c8c8", "X s iconColor1 m black c black", "o s iconGray6 m black c #646464646464", "O s iconGray3 m white c #afafafafafaf", "+ s iconColor3 m black c red", "@ s iconColor8 m white c magenta", "# s iconGray4 m white c #969696969696", "$ s iconGray5 m black c #7d7d7d7d7d7d", "% s iconColor6 m white c yellow", "& s iconGray1 m white c #e1e1e1e1e1e1", "* s iconColor4 m black c green", "= s bottomShadowColor m black c #646464646464", /* pixels */ " ", " ..........................X", " ..............oo..........X", " .........OOOoo+@@oooOOOOOOX", " .....OOOoooo@####@+ooooo..X", " ..ooo#oo+@###$$$$#####OOO.X", " ..OOOOOO###$$....$$#@+ooo.X", " .......+@#$.%%%%%%.$###OOOX", " ..o.ooo..$.%%%%%%%%%$#@+ooX", and so on, ending with: " XXXXXXXXXXXXXXXXXXXXXXXXXXX"}; #endif #define NEXTCHAR(s) (*s ? *s++ : '\0') static char *FindCh(char *s, char ch) { char c; for (;;) { c = NEXTCHAR(s); if (c == ch || c == '\0') return s; } } /* *c to first char and return last word */ static char *ReadColor(char *s, char **name, int *ch) { char *p; int c; static char line[256]; s = FindCh(s, '"'); *ch = NEXTCHAR(s); p = line; while ((c = NEXTCHAR(s)) != '"' && c != '\0' && p < line+255) *p++ = c; *p = '\0'; p = strrchr(line, ' '); if (p) ++p; *name = p; return s; } unsigned char *Transparent(unsigned char *p, int x, int y) { unsigned int i; unsigned char *s; if (tileData) { x = x % tileWidth; y = y % tileHeight; i = y * tileWidth + x; if (depth == 24) { s = tileData + 4 * i; *p++ = *s++; *p++ = *s++; *p++ = *s++; *p++ = *s++; return p; } *p++ = tileData[i]; return p; } if (depth == 24) { *p++ = '\0'; *p++ = (transparent >> 16) & 0xFF; *p++ = (transparent >> 8) & 0xFF; *p++ = transparent & 0xFF; return p; } *p++ = transparent; return p; } /* load data from an XPM file and allocate colors */ char *LoadXpmImage(Image *image, Block *bp, unsigned int depth) { int c, i, j, cr, cg, cb, r, g, b, ncolors, size, map[256]; unsigned int width, height; unsigned long pixel, *pixdata; unsigned char *data, *p; char *name, *s; Color *colors, color; XColor xcolor; s = bp->buffer + bp->next; s = FindCh(s, '"'); sscanf(s, "%d %d %d", &width, &height, &ncolors); s = FindCh(s, '\n'); size = width * height; image->width = width; image->height = height; if (size == 0 || ncolors == 0) return NULL; if (depth != 8 && depth != 24 && depth != 4 && depth != 2 && depth != 1) { printf("Display depth %d unsupported\n", depth); return NULL; } image->npixels = 0; image->pixels = 0; /*(unsigned long *)malloc(ncolors * sizeof(unsigned long)); */ colors = (Color *)malloc(ncolors * sizeof(Color)); for (i = 0; i < 256; ++i) map[i] = -1; for (i = 0; i < ncolors; ++i) { s = ReadColor(s, &name, &c); if (XParseColor(display, colormap, name, &xcolor) == 0) { map[c] = -1; continue; } map[c] = i; r = xcolor.red >> 8; g = xcolor.green >> 8; b = xcolor.blue >> 8; /* apply Gamma correction to map voltages to brightness values */ if (imaging != COLOR888) { r = Voltage2Brightness(r); g = Voltage2Brightness(g); b = Voltage2Brightness(b); } colors[i].red = r; colors[i].green = g; colors[i].blue = b; colors[i].grey = (3*r + 6*g + b)/10; } if (depth == 8) { p = data = malloc(size); for (i = 0; i < height; ++i) { s = FindCh(s, '"'); for (j = 0; j < width; ++j) { c = *s++; c = map[c]; if (c < 0) { p = Transparent(p, j, i); continue; } color = colors[c]; c = ((i % 16) << 4) + (j % 16); if (imaging == COLOR232) { cr = color.red; cg = color.green; cb = color.blue; if (cr == cg && cg == cb) { cg = color.grey; g = cg & 0xF0; if (cg - g > Magic16[c]) g += 16; g = min(g, 0xF0); *p++ = greymap[g >> 4]; } else { r = cr & 0xC0; g = cg & 0xE0; b = cb & 0xC0; if (cr - r > Magic64[c]) r += 64; if (cg - g > Magic32[c]) g += 32; if (cb - b > Magic64[c]) b += 64; r = min(r, 255) & 0xC0; g = min(g, 255) & 0xE0; b = min(b, 255) & 0xC0; *p++ = stdcmap[(r >> 6) | (g >> 3) | (b >> 1)]; } } else if (imaging == GREY4) { cg = color.grey; g = cg & 0xF0; if (cg - g > Magic16[c]) g += 16; g = min(g, 0xF0); *p++ = greymap[g >> 4]; } else /* MONO */ { if (color.grey < Magic256[c]) *p++ = greymap[0]; else *p++ = greymap[15]; } } s = FindCh(s, '\n'); } } else if (depth == 24) { p = data = malloc(size * 4); for (i = 0; i < height; ++i) { s = FindCh(s, '"'); for (j = 0; j < width; ++j) { if ((c = map[*s++]) < 0) { p = Transparent(p, j, i); continue; }; color = colors[c]; *p++ = '\0'; *p++ = color.red; *p++ = color.green; *p++ = color.blue; } s = FindCh(s, '\n'); } } else if (depth == 1 || depth == 2 || depth == 4) /* howcome added support for these */ { int ppb, bpl, shift; ppb = 8/depth; /* pixels per byte */ bpl = width/ppb + (width%ppb ? 1 : 0); /* bytes per line */ p = data = (unsigned char *)malloc(bpl * height); *p = 0; for (i = 0; i < height; ++i) { s = FindCh(s, '"'); for (j = 0; j < width; ++j) { c = *s++; c = map[c]; if (c < 0) { shift = (((7 - (j % 8)) % ppb) * depth); *p |= transparent << shift; if (shift == 0) { p++; *p = 0; } continue; } color = colors[c]; c = ((i % 16) << 4) + (j % 16); if (imaging == COLOR232) { cr = color.red; cg = color.green; cb = color.blue; if (cr == cg && cg == cb) { cg = color.grey; g = cg & 0xF0; if (cg - g > Magic16[c]) g += 16; g = min(g, 0xF0); shift = (((7 - (j % 8)) % ppb) * depth); *p |= greymap[g >> 4] << shift; if (shift == 0) { p++; *p = 0; } } else { r = cr & 0xC0; g = cg & 0xE0; b = cb & 0xC0; if (cr - r > Magic64[c]) r += 64; if (cg - g > Magic32[c]) g += 32; if (cb - b > Magic64[c]) b += 64; r = min(r, 255) & 0xC0; g = min(g, 255) & 0xE0; b = min(b, 255) & 0xC0; shift = (((7 - (j % 8)) % ppb) * depth); *p |= stdcmap[(r >> 6) | (g >> 3) | (b >> 1)] << shift; if (shift == 0) { p++; *p = 0; } } } else if (imaging == GREY4) { cg = color.grey; g = cg & 0xF0; if (cg - g > Magic16[c]) g += 16; g = min(g, 0xF0); shift = (((7 - (j % 8)) % ppb) * depth); *p |= greymap[g >> 4] << shift; if (shift == 0) { p++; *p = 0; } } else /* MONO */ { if (color.grey < Magic256[c]) { shift = (((7 - (j % 8)) % ppb) * depth); *p |= greymap[0] << shift; if (shift == 0) { p++; *p = 0; } } else { shift = (((7 - (j % 8)) % ppb) * depth); *p |= greymap[15] << shift; if (shift == 0) { p++; *p = 0; } } } } s = FindCh(s, '\n'); if (shift) { p++; /* make sure we start on a new byte for the next line */ *p = 0; } } } Free(colors); return (char *)data; } /* Load data from an XBM file #define back_width 20 #define back_height 23 static char back_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x0f, 0x60, 0x80, 0x0f, 0x70, 0x80, 0x0f, 0x78, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0xfe, 0xff, 0x07, 0xff, 0xff, 0x03, 0xfe, 0xff, 0x01, 0xfc, 0xff, 0x00, 0x78, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; So find line start with #define and read last number as width. Repeat to get height. Should really look at names to avoid problems if order is swapped, but probably won't be necessary. Number of bytes of data is: ((height * width) + 7)/8 Then skip to '{' char and then start reading data: whitespace or ',' followed by hex number */ char *LoadXbmImage(Image *image, Block *bp, unsigned int depth) { char *s; int c, i, j, k, size; unsigned int width, height, byte; unsigned char *data, *p; s = (char *)bp->buffer + bp->next; s = FindCh(s, '#'); /* find #define */ s = FindCh(s, ' '); /* find 1st space char */ s = FindCh(s, ' '); /* find 2nd space char */ sscanf(s, "%d", &width); /* and read width */ s = FindCh(s, '#'); /* find next #define */ s = FindCh(s, ' '); /* find 1st space char */ s = FindCh(s, ' '); /* find 2nd space char */ sscanf(s, "%d", &height); /* and read width */ s = FindCh(s, '{'); /* find opening brace for data */ size = width * height; image->width = width; image->height = height; if (size == 0) return NULL; image->npixels = 0; image->pixels = 0; if (depth == 8) { p = data = (unsigned char *)malloc(size); for (i = 0; i < height; ++i) for (j = 0, k= 8; j < width; ++j) { if (++k > 8) /* need to read next 8 pixel values */ { s = FindCh(s, '0'); sscanf(s+1, "%x", &byte); /* howcome 5/11/94: '-1' changed to '+1' since some don't like 0x */ while ((c = NEXTCHAR(s)) != ',' && c != '}'); k = 1; } if (byte & 0x01) *p++ = textColor; else p = Transparent(p, j, i); byte = byte >> 1; } } else if (depth == 24) { p = data = (unsigned char *)malloc(size * 4); for (i = 0; i < height; ++i) for (j = 0, k= 8; j < width; ++j) { if (++k > 8) /* need to read next 8 pixel values */ { s = FindCh(s, '0'); sscanf(s-1, "%x", &byte); while ((c = NEXTCHAR(s)) != ',' && c != '}'); k = 1; } if (byte & 1) { *p++ = '\0'; *p++ = (textColor >> 16) & 0xFF; *p++ = (textColor >> 8) & 0xFF; *p++ = textColor & 0xFF; } else p = Transparent(p, j, i); byte = byte >> 1; } } else if (depth == 1 || depth == 2 || depth == 4) /* howcome added support for these */ { int ppb, bpl, shift; ppb = 8/depth; /* pixels per byte */ bpl = width/ppb + (width%ppb ? 1 : 0); /* bytes per line */ p = data = (unsigned char *)malloc(bpl * height); *p = 0; for (i = 0; i < height; ++i) { for (j = 0, k= 8; j < width; ++j) { if (++k > 8) /* need to read next 8 pixel values */ { s = FindCh(s, '0'); sscanf(s+1, "%x", &byte); /* howcome 5/11/94: '-1' changed to '+1' since some don't like 0x */ while ((c = NEXTCHAR(s)) != ',' && c != '}'); k = 1; } if (byte & 0x01) { shift = (((7 - (j % 8)) % ppb) * depth); *p |= textColor << shift; } else { shift = (((7 - (j % 8)) % ppb) * depth); *p |= transparent << shift; } if (shift == 0) { p++; *p = 0; } byte = byte >> 1; } if (shift) { p++; *p = 0; } } } else { Warn("image/x-xbitmap unsupported for depth %d", depth); return NULL; } return (char *)data; } Image *GetImage(char *href, int hreflen) { XGCValues values; Image *image; int tag; HTList *l; HTAnchor *a; Doc *doc = NULL; /* check for null name */ if (href == NULL || hreflen == 0) { Warn("Missing or bad image name"); image = (Image *)malloc(sizeof(Image)); image->npixels = 0; return DefaultImage(image); } /* check if designated image is already loaded */ if (IMAGE_TRACE) { char *s = strndup(href, hreflen); fprintf(stderr,"GetImage %s\n",s); Free(s); } /* first, lets expand the href into an anchor */ a = libExpandHref(href, hreflen); /* check if document is already in place */ if (a->parent->document) { doc = (Doc *)a->parent->document; } else { /* no, the document does not seem to be in place, lets register it.. */ if (IMAGE_TRACE) { char *s = strndup(href, hreflen); fprintf(stderr,"GetImage registering %s returning default for now\n",s); Free(s); } libLoadAnchor(a, CurrentDoc, FALSE, FALSE, TRUE, FALSE); /* if image is still not there.. */ if (!a->parent->document) { image = (Image *)malloc(sizeof(Image)); image->npixels = 0; return DefaultImage(image); } else doc = (Doc *) a->parent->document; } #if 0 /* lets try to see if the image has been registered / loaded before */ /* first, look in list of previously registered docs in the current document */ l = CurrentDoc->inline_anchors; while (a = (HTParentAnchor *) HTList_nextObject(l) ) { if ((doc = (Doc *) a->document) && (strncmp(doc->href, href, hreflen) == 0)){ break; } doc = NULL; } /* now, it may be that the document has been registered, but that the anchor and the document structure has not been attached yet, those docs are found in the pending docs list */ if (!doc) { HTList *l = context->pending_docs; while (doc = (Doc *)HTList_nextObject(l)) { if (strncmp(doc->href, href, hreflen)==0) { break; } doc = NULL; } } /* if not found, look in the full list of registered anchors */ /**/ #endif if (doc) { /* the inline doc has been registered, it can be loading, loaded, processed*/ switch (doc->state) { case DOC_PENDING: if (IMAGE_TRACE) { char *s = strndup(href, hreflen); fprintf(stderr,"doc has been registered, but not loaded -> returning default%s\n",s); Free(s); } image = (Image *)malloc(sizeof(Image)); image->npixels = 0; return DefaultImage(image); break; case DOC_PROCESSED: if (IMAGE_TRACE) fprintf(stderr,"GetImage: doc processed returning image %s\n",doc->url); return(doc->image); break; case DOC_LOADED: return(ProcessLoadedImage(doc)); } } } Image *ProcessLoadedImage(Doc *doc) { char *data; Image *image; Block block; unsigned int width, height; XImage *ximage; Pixmap pixmap; GC drawGC; image = (Image *)malloc(sizeof(Image)); image->npixels = 0; block.next = 0; /*NewDoc.hdrlen; */ block.size = doc->loaded_length; /* NewDoc.length; */ block.buffer = doc->content_buffer; if (!doc->content_buffer) { /* probably externally viewed image */ return DefaultImage(image); } Announce("Processing image %s...", doc->url); if (DocType(doc->content_type, GIF_DOCUMENT)) { if ((data = (char *)LoadGifImage(image, &block, depth)) == NULL) { Warn("Failed to load GIF image: %s", doc->url); Free(block.buffer); return DefaultImage(image); } } else if (DocType(doc->content_type, XPM_DOCUMENT)) { if ((data = LoadXpmImage(image, &block, depth)) == NULL) { Warn("Failed to load XPM image: %s", doc->url); Free(block.buffer); return DefaultImage(image); } } else if (DocType(doc->content_type, XBM_DOCUMENT)) { if ((data = LoadXbmImage(image, &block, depth)) == NULL) { Warn("Failed to load XBM image: %s", doc->url); Free(block.buffer); return DefaultImage(image); } } #ifdef JPEG else if (DocType(doc->content_type, JPEG_DOCUMENT)) { if ((data = LoadJPEGImage(image, &block, depth)) == NULL) { Warn("Failed to load JPEG image: %s", doc->url); Free(block.buffer); return DefaultImage(image); } } #endif /* JPEG */ else { Warn("Failed to load unknown image format: %s", doc->url); Free(block.buffer); return DefaultImage(image); } Free(block.buffer); doc->state = DOC_PROCESSED; doc->content_buffer = NULL; /* howcome 4/12/94: no need to keep the gif source around */ width = image->width; height = image->height; if ((ximage = XCreateImage(display, DefaultVisual(display, screen), depth, ZPixmap, 0, data, width, height, (depth == 24 ? 32 : 8), 0)) == 0) { Warn("Failed to create XImage: %s", doc->url); Free(data); return DefaultImage(image); } /* howcome 22/2/95: do we need to set these?? */ ximage->byte_order = MSBFirst; ximage->bitmap_bit_order = MSBFirst; if ((pixmap = XCreatePixmap(display, win, width, height, depth)) == 0) { Warn("Failed to create Pixmap: %s", doc->url); XDestroyImage(ximage); /* also free's image data */ return DefaultImage(image); } drawGC = XCreateGC(display, pixmap, 0, 0); XSetFunction(display, drawGC, GXcopy); XPutImage(display, pixmap, drawGC, ximage, 0, 0, 0, 0, width, height); XFreeGC(display, drawGC); XDestroyImage(ximage); /* also free's image data */ image->pixmap = pixmap; image->width = width; image->height = height; doc->image = image; return doc->image; } void FreeImages(int cloned) { Image *im; while (images) { /* deallocate colors */ if (!cloned && images->npixels > 0) XFreeColors(display, colormap, images->pixels, images->npixels, 0); /* free pixmap and image structure */ if (!cloned && images->pixmap != default_pixmap) XFreePixmap(display, images->pixmap); im = images; images = im->next; Free(im->url); if (im->npixels > 0) Free(im->pixels); Free(im); } }