1/* 2 * XWD image handling 3 */ 4 5#include "ctwm.h" 6 7#include <stdio.h> 8#include <stdlib.h> 9 10#include <X11/XWDFile.h> 11 12#include "screen.h" 13#include "animate.h" 14 15#include "image.h" 16#include "image_xwd.h" 17 18 19static Image *LoadXwdImage(const char *filename, ColorPair cp); 20static void compress(XImage *image, XColor *colors, int *ncolors); 21static void swapshort(char *bp, unsigned n); 22static void swaplong(char *bp, unsigned n); 23 24 25 26/* 27 * External entry 28 */ 29Image * 30GetXwdImage(const char *name, ColorPair cp) 31{ 32 /* Non-animated */ 33 if(! strchr(name, '%')) { 34 return (LoadXwdImage(name, cp)); 35 } 36 37 /* Animated */ 38 return get_image_anim_cp(name, cp, LoadXwdImage); 39} 40 41 42/* 43 * Internal backend 44 */ 45static Image * 46LoadXwdImage(const char *filename, ColorPair cp) 47{ 48 FILE *file; 49 char *fullname; 50 XColor colors [256]; 51 XWDColor xwdcolors [256]; 52 unsigned buffer_size; 53 XImage *image; 54 unsigned char *imagedata; 55 Pixmap pixret; 56 Visual *visual; 57 char win_name [256]; 58 int win_name_size; 59 int ispipe; 60 int i, len; 61 int w, h, depth, ncolors; 62 int scrn; 63 Colormap cmap; 64 Colormap stdcmap = Scr->RootColormaps.cwins[0]->colormap->c; 65 GC gc; 66 XGCValues gcvalues; 67 XWDFileHeader header; 68 Image *ret; 69 unsigned long swaptest = 1; 70 71 ispipe = 0; 72 if(filename [0] == '|') { 73 file = (FILE *) popen(filename + 1, "r"); 74 if(file == NULL) { 75 return NULL; 76 } 77 ispipe = 1; 78 if(AnimationActive) { 79 StopAnimation(); 80 } 81 goto file_opened; 82 } 83 fullname = ExpandPixmapPath(filename); 84 if(! fullname) { 85 return NULL; 86 } 87 file = fopen(fullname, "r"); 88 free(fullname); 89 if(file == NULL) { 90 if(reportfilenotfound) { 91 fprintf(stderr, "unable to locate %s\n", filename); 92 } 93 return NULL; 94 } 95file_opened: 96 len = fread((char *) &header, sizeof(header), 1, file); 97 if(len != 1) { 98 fprintf(stderr, "ctwm: cannot read %s\n", filename); 99 return NULL; 100 } 101 if(*(char *) &swaptest) { 102 swaplong((char *) &header, sizeof(header)); 103 } 104 if(header.file_version != XWD_FILE_VERSION) { 105 fprintf(stderr, "ctwm: XWD file format version mismatch : %s\n", filename); 106 return NULL; 107 } 108 win_name_size = header.header_size - sizeof(header); 109 len = fread(win_name, win_name_size, 1, file); 110 if(len != 1) { 111 fprintf(stderr, "file %s has not the correct format\n", filename); 112 return NULL; 113 } 114 115 if(header.pixmap_format == XYPixmap) { 116 fprintf(stderr, "ctwm: XYPixmap XWD file not supported : %s\n", filename); 117 return NULL; 118 } 119 w = header.pixmap_width; 120 h = header.pixmap_height; 121 depth = header.pixmap_depth; 122 ncolors = header.ncolors; 123 len = fread((char *) xwdcolors, sizeof(XWDColor), ncolors, file); 124 if(len != ncolors) { 125 fprintf(stderr, "file %s has not the correct format\n", filename); 126 return NULL; 127 } 128 if(*(char *) &swaptest) { 129 for(i = 0; i < ncolors; i++) { 130 swaplong((char *) &xwdcolors [i].pixel, 4); 131 swapshort((char *) &xwdcolors [i].red, 3 * 2); 132 } 133 } 134 for(i = 0; i < ncolors; i++) { 135 colors [i].pixel = xwdcolors [i].pixel; 136 colors [i].red = xwdcolors [i].red; 137 colors [i].green = xwdcolors [i].green; 138 colors [i].blue = xwdcolors [i].blue; 139 colors [i].flags = xwdcolors [i].flags; 140 colors [i].pad = xwdcolors [i].pad; 141 } 142 143 scrn = Scr->screen; 144 cmap = AlternateCmap ? AlternateCmap : stdcmap; 145 visual = Scr->d_visual; 146 gc = DefaultGC(dpy, scrn); 147 148 buffer_size = header.bytes_per_line * h; 149 imagedata = malloc(buffer_size); 150 if(! imagedata) { 151 fprintf(stderr, "cannot allocate memory for image %s\n", filename); 152 return NULL; 153 } 154 len = fread(imagedata, (int) buffer_size, 1, file); 155 if(len != 1) { 156 free(imagedata); 157 fprintf(stderr, "file %s has not the correct format\n", filename); 158 return NULL; 159 } 160 if(ispipe) { 161 pclose(file); 162 } 163 else { 164 fclose(file); 165 } 166 167 image = XCreateImage(dpy, visual, depth, header.pixmap_format, 168 0, (char *) imagedata, w, h, 169 header.bitmap_pad, header.bytes_per_line); 170 if(image == NULL) { 171 free(imagedata); 172 fprintf(stderr, "cannot create image for %s\n", filename); 173 return NULL; 174 } 175 if(header.pixmap_format == ZPixmap) { 176 compress(image, colors, &ncolors); 177 } 178 if(header.pixmap_format != XYBitmap) { 179 for(i = 0; i < ncolors; i++) { 180 XAllocColor(dpy, cmap, &(colors [i])); 181 } 182 for(i = 0; i < buffer_size; i++) { 183 imagedata [i] = (unsigned char) colors [imagedata [i]].pixel; 184 } 185 } 186 if(w > Scr->rootw) { 187 w = Scr->rootw; 188 } 189 if(h > Scr->rooth) { 190 h = Scr->rooth; 191 } 192 193 ret = AllocImage(); 194 if(! ret) { 195 fprintf(stderr, "unable to allocate memory for image : %s\n", filename); 196 free(image); 197 free(imagedata); 198 for(i = 0; i < ncolors; i++) { 199 XFreeColors(dpy, cmap, &(colors [i].pixel), 1, 0L); 200 } 201 return NULL; 202 } 203 if(header.pixmap_format == XYBitmap) { 204 gcvalues.foreground = cp.fore; 205 gcvalues.background = cp.back; 206 XChangeGC(dpy, gc, GCForeground | GCBackground, &gcvalues); 207 } 208 if((w > (Scr->rootw / 2)) || (h > (Scr->rooth / 2))) { 209 int x, y; 210 211 pixret = XCreatePixmap(dpy, Scr->Root, Scr->rootw, 212 Scr->rooth, Scr->d_depth); 213 x = (Scr->rootw - w) / 2; 214 y = (Scr->rooth - h) / 2; 215 XFillRectangle(dpy, pixret, gc, 0, 0, Scr->rootw, Scr->rooth); 216 XPutImage(dpy, pixret, gc, image, 0, 0, x, y, w, h); 217 ret->width = Scr->rootw; 218 ret->height = Scr->rooth; 219 } 220 else { 221 pixret = XCreatePixmap(dpy, Scr->Root, w, h, depth); 222 XPutImage(dpy, pixret, gc, image, 0, 0, 0, 0, w, h); 223 ret->width = w; 224 ret->height = h; 225 } 226 XDestroyImage(image); 227 228 ret->pixmap = pixret; 229 ret->mask = None; 230 ret->next = NULL; 231 return ret; 232} 233 234 235/* 236 * Utils 237 */ 238static void 239compress(XImage *image, XColor *colors, int *ncolors) 240{ 241 unsigned char ind [256]; 242 unsigned int used [256]; 243 int i, j, size, nused; 244 unsigned char color; 245 XColor newcolors [256]; 246 unsigned char *imagedata; 247 248 for(i = 0; i < 256; i++) { 249 used [i] = 0; 250 ind [i] = 0; 251 } 252 nused = 0; 253 size = image->bytes_per_line * image->height; 254 imagedata = (unsigned char *) image->data; 255 for(i = 0; i < size; i++) { 256 if((i % image->bytes_per_line) > image->width) { 257 continue; 258 } 259 color = imagedata [i]; 260 if(used [color] == 0) { 261 for(j = 0; j < nused; j++) { 262 if((colors [color].red == newcolors [j].red) && 263 (colors [color].green == newcolors [j].green) && 264 (colors [color].blue == newcolors [j].blue)) { 265 break; 266 } 267 } 268 ind [color] = j; 269 used [color] = 1; 270 if(j == nused) { 271 newcolors [j].red = colors [color].red; 272 newcolors [j].green = colors [color].green; 273 newcolors [j].blue = colors [color].blue; 274 nused++; 275 } 276 } 277 } 278 for(i = 0; i < size; i++) { 279 imagedata [i] = ind [imagedata [i]]; 280 } 281 for(i = 0; i < nused; i++) { 282 colors [i] = newcolors [i]; 283 } 284 *ncolors = nused; 285} 286 287 288static void 289swapshort(char *bp, unsigned n) 290{ 291 char c; 292 char *ep = bp + n; 293 294 while(bp < ep) { 295 c = *bp; 296 *bp = *(bp + 1); 297 bp++; 298 *bp++ = c; 299 } 300} 301 302 303static void 304swaplong(char *bp, unsigned n) 305{ 306 char c; 307 char *ep = bp + n; 308 char *sp; 309 310 while(bp < ep) { 311 sp = bp + 3; 312 c = *sp; 313 *sp = *bp; 314 *bp++ = c; 315 sp = bp + 1; 316 c = *sp; 317 *sp = *bp; 318 *bp++ = c; 319 bp += 2; 320 } 321} 322