7 /* extra colors to try allocating in private color maps to minimise flashing */
8 #define NOFLASH_COLORS 256
10 Image *monochrome(Image *cimage)
13 unsigned char *sp, *dp, *dp2; /* data pointers */
14 unsigned int spl; /* source pixel length in bytes */
15 unsigned int dll; /* destination line length in bytes */
16 Pixel color; /* pixel color */
17 unsigned int x, y; /* random counters */
23 image = newBitImage(cimage->width, cimage->height);
26 dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
31 for (y= 0; y < cimage->height; y++)
33 for (x= 0; x < cimage->width; x++)
35 dp2 = dp + (x / 8); /* dp + x/8 */
36 color= memToVal(sp, spl);
38 if (cimage->rgb.red[color] > 0x0000 ||
39 cimage->rgb.green[color] > 0x0000 ||
40 cimage->rgb.blue[color] > 0x0000)
45 *dp2 |= bitmap_pixel >> ( x % 8);
49 dp += dll; /* next row */
55 static unsigned int *buildIndex(unsigned int width,
70 fzoom= (float)zoom / 100.0;
71 *rwidth= (unsigned int)(fzoom * width + 0.5);
73 index= (unsigned int *)checked_malloc(sizeof(unsigned int) * *rwidth);
74 for (a= 0; a < *rwidth; a++)
77 *(index + a)= (unsigned int)((float)a / fzoom + 0.5);
84 Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
87 unsigned int *xindex, *yindex;
88 unsigned int xwidth, ywidth;
89 unsigned int x, y, xsrc, ysrc;
91 unsigned int srclinelen;
92 unsigned int destlinelen;
93 byte *srcline, *srcptr;
94 byte *destline, *destptr;
95 byte srcmask, destmask, bit;
98 if ((!xzoom || xzoom==100) && (!yzoom || yzoom==100))
102 printf(" Zooming image Y axis by %d%%...", yzoom);
104 printf(" Zooming image X axis by %d%%...", xzoom);
105 else if (xzoom == yzoom)
106 printf(" Zooming image by %d%%...", xzoom);
108 printf(" Zooming image X axis by %d%% and Y axis by %d%%...",
112 xindex= buildIndex(oimage->width, xzoom, &xwidth);
113 yindex= buildIndex(oimage->height, yzoom, &ywidth);
115 switch (oimage->type)
118 image= newBitImage(xwidth, ywidth);
119 for (x= 0; x < oimage->rgb.used; x++)
121 *(image->rgb.red + x)= *(oimage->rgb.red + x);
122 *(image->rgb.green + x)= *(oimage->rgb.green + x);
123 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
125 image->rgb.used= oimage->rgb.used;
126 destline= image->data;
127 destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
128 srcline= oimage->data;
129 srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
130 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
132 while (ysrc != *(yindex + y))
135 srcline += srclinelen;
141 bit= srcmask & *srcptr;
142 for (x= 0, xsrc= *(xindex + x); x < xwidth; x++)
144 if (xsrc != *(xindex + x))
149 if (!(srcmask >>= 1))
155 while (xsrc != *(xindex + x));
157 bit= srcmask & *srcptr;
160 *destptr |= destmask;
161 if (!(destmask >>= 1))
167 destline += destlinelen;
172 image= newRGBImage(xwidth, ywidth, oimage->depth);
173 for (x= 0; x < oimage->rgb.used; x++)
175 *(image->rgb.red + x)= *(oimage->rgb.red + x);
176 *(image->rgb.green + x)= *(oimage->rgb.green + x);
177 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
179 image->rgb.used= oimage->rgb.used;
181 pixlen= oimage->pixlen;
182 destptr= image->data;
183 srcline= oimage->data;
184 srclinelen= oimage->width * pixlen;
185 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
187 while (ysrc != *(yindex + y))
190 srcline += srclinelen;
194 value = memToVal(srcptr, image->pixlen);
196 for (x=0, xsrc= *(xindex + x); x<xwidth; x++)
198 if (xsrc != *(xindex + x))
205 while (xsrc != *(xindex + x));
206 value = memToVal(srcptr, 1);
208 valToMem(value, destptr, 1);
220 free((byte *)xindex);
221 free((byte *)yindex);
228 void compress(Image *image)
230 unsigned char *used, fast[32][32][32];
231 unsigned int dmask; /* Depth mask protection */
233 unsigned int next_index;
234 Intensity *red = image->rgb.red,
235 *green = image->rgb.green,
236 *blue = image->rgb.blue;
238 unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
239 unsigned char *pixptr, *pixend;
241 if (!RGBP(image) || image->rgb.compressed)
244 used = (unsigned char *)checked_calloc(sizeof(unsigned char) * depthToColors(image->depth));
245 dmask = (1 << image->depth) -1; /* Mask any illegal bits for that depth */
246 map = (Pixel *)checked_calloc(sizeof(Pixel) * depthToColors(image->depth));
248 /* init fast duplicate check table */
254 /* do pass 1 through the image to check index usage */
256 pixptr = image->data;
257 pixend = pixptr + (image->height * image->width);
258 for(;pixptr < pixend; pixptr++)
259 used[(*pixptr) & dmask] = 1;
261 /* count the bad pixels */
262 for (x = image->rgb.used; x < depthToColors(image->depth); x++)
266 /* figure out duplicates and unuseds, and create the new mapping */
268 for (x = 0; x < image->rgb.used; x++)
273 continue; /* delete this index */
276 /* check for duplicate */
280 if (fast[r>>11][g>>11][b>>11]) /* if matches fast check */
282 /* then do a linear search */
283 for (y = x+1; y < image->rgb.used; y++)
285 if (r == red[y] && g == green[y] && b == blue[y])
288 if (y < image->rgb.used) /* found match */
292 continue; /* delete this index */
294 fast[r>>11][g>>11][b>>11] = 1;
296 /* will map to this index */
301 /* change the image pixels */
302 pixptr = image->data;
303 pixend = pixptr + (image->height * image->width);
304 for(;pixptr < pixend; pixptr++)
305 *pixptr = map[(*pixptr) & dmask];
307 /* change the colormap */
308 for (x = 0; x < image->rgb.used; x++)
312 red[map[x]] = red[x];
313 green[map[x]] = green[x];
314 blue[map[x]] = blue[x];
316 image->rgb.used = next_index;
324 printf("%d out-of-range pixels, ", badcount);
326 if (!unusedcount && !dupcount)
327 printf("no improvment\n");
331 printf("%d duplicate%s and %d unused color%s removed...",
332 dupcount, (dupcount == 1 ? "" : "s"),
333 unusedcount, (unusedcount == 1 ? "" : "s"));
334 printf("%d unique color%s\n",
335 next_index, (next_index == 1 ? "" : "s"));
339 image->rgb.compressed= TRUE; /* don't do it again */
345 Pixmap XImage_to_Pixmap(Display *disp, Window parent, XImageInfo *ximageinfo)
349 pixmap = XCreatePixmap(disp, parent,
350 ximageinfo->ximage->width, ximageinfo->ximage->height,
353 ximageinfo->drawable = pixmap;
355 XImage_to_Drawable(ximageinfo, 0, 0, 0, 0,
356 ximageinfo->ximage->width, ximageinfo->ximage->height);
360 /* find the best pixmap depth supported by the server for a particular
361 * visual and return that depth.
363 * this is complicated by R3's lack of XListPixmapFormats so we fake it
364 * by looking at the structure ourselves.
367 static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
370 XPixmapFormatValues *xf;
373 xf = XListPixmapFormats(disp, &nxf);
374 for (a = 0; a < nxf; a++)
376 if (xf[a].depth == depth)
379 bpp = xf[a].bits_per_pixel;
381 return (unsigned int) bpp;
386 /* this should never happen; if it does, we're in trouble
389 fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
393 XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
394 unsigned int ddepth, Image *image)
396 static XColor xcolor_private[NOFLASH_COLORS];
397 static int colorcell_used[NOFLASH_COLORS];
398 static Colormap global_cmap = 0;
399 static Pixel *global_cmap_index;
400 static int num_cmap_entries, free_cmap_entries;
401 static private_cmap = FALSE;
402 Pixel *redvalue, *greenvalue, *bluevalue;
403 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
406 XImageInfo *ximageinfo;
410 if (visual == DefaultVisual(disp, scrn))
411 global_cmap = DefaultColormap(disp, scrn);
414 global_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
420 xcolor.flags = DoRed | DoGreen | DoBlue;
421 redvalue = greenvalue = bluevalue = NULL;
422 ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
423 ximageinfo->disp = disp;
424 ximageinfo->scrn = scrn;
425 ximageinfo->depth = 0;
426 ximageinfo->drawable = None;
427 ximageinfo->index = NULL;
428 ximageinfo->rootimage = FALSE;
429 ximageinfo->foreground = ximageinfo->background= 0;
430 ximageinfo->gc = NULL;
431 ximageinfo->ximage = NULL;
433 switch (visual->class)
439 unsigned int redcolors, greencolors, bluecolors;
440 unsigned int redstep, greenstep, bluestep;
441 unsigned int redbottom, greenbottom, bluebottom;
442 unsigned int redtop, greentop, bluetop;
444 redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
445 greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
446 bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
448 ximageinfo->cmap = global_cmap;
450 retry_direct: /* tag we hit if a DirectColor allocation fails on
451 * default colormap */
453 /* calculate number of distinct colors in each band
456 redcolors = greencolors = bluecolors = 1;
457 for (pixval=1; pixval; pixval <<= 1)
459 if (pixval & visual->red_mask)
461 if (pixval & visual->green_mask)
463 if (pixval & visual->blue_mask)
470 if ((redcolors > visual->map_entries) ||
471 (greencolors > visual->map_entries) ||
472 (bluecolors > visual->map_entries))
474 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
477 redstep = 256 / redcolors;
478 greenstep = 256 / greencolors;
479 bluestep = 256 / bluecolors;
480 redbottom = greenbottom = bluebottom = 0;
481 redtop = greentop = bluetop = 0;
482 for (a=0; a<visual->map_entries; a++)
485 redtop = redbottom + redstep;
486 if (greenbottom < 256)
487 greentop = greenbottom + greenstep;
488 if (bluebottom < 256)
489 bluetop = bluebottom + bluestep;
491 xcolor.red = (redtop - 1) << 8;
492 xcolor.green = (greentop - 1) << 8;
493 xcolor.blue = (bluetop - 1) << 8;
494 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
496 /* if an allocation fails for a DirectColor default visual then
497 * we should create a private colormap and try again.
500 if ((visual->class == DirectColor) &&
501 (visual == DefaultVisual(disp, scrn)))
503 global_cmap = XCopyColormapAndFree(disp, global_cmap);
504 ximageinfo->cmap = global_cmap;
510 /* something completely unexpected happened
513 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
514 free((byte *)redvalue);
515 free((byte *)greenvalue);
516 free((byte *)bluevalue);
517 free((byte *)ximageinfo);
521 /* fill in pixel values for each band at this intensity
524 while ((redbottom < 256) && (redbottom < redtop))
525 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
526 while ((greenbottom < 256) && (greenbottom < greentop))
527 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
528 while ((bluebottom < 256) && (bluebottom < bluetop))
529 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
536 ximageinfo->cmap = global_cmap;
538 (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
540 for (a=0; a<image->rgb.used; a++)
547 xcolor.red = *(image->rgb.red + a);
548 xcolor.green = *(image->rgb.green + a);
549 xcolor.blue = *(image->rgb.blue + a);
551 /* look if this color already exists in our colormap */
552 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
557 printf("switching to private colormap...\n");
560 /* we just filled up the default colormap -- get a private one
561 which contains all already allocated colors */
563 global_cmap = XCopyColormapAndFree(disp, global_cmap);
564 ximageinfo->cmap = global_cmap;
567 /* allocate the rest of the color cells read/write */
569 (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
570 for (i=0; i<NOFLASH_COLORS; i++)
571 if (!XAllocColorCells(disp, global_cmap, FALSE, NULL, 0,
572 global_cmap_index + i, 1))
574 num_cmap_entries = free_cmap_entries = i;
577 printf("We've got %d free colormap entries.\n", free_cmap_entries);
580 /* to minimize colormap flashing, copy default colors and try
581 to keep them as near as possible to the old values */
583 for(i=0; i<num_cmap_entries; i++)
585 xcolor2.pixel = *(global_cmap_index + i);
586 XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor2);
587 XStoreColor(disp, global_cmap, &xcolor2);
588 xcolor_private[xcolor2.pixel] = xcolor2;
589 colorcell_used[xcolor2.pixel] = FALSE;
592 /* now we have the default colormap private: all colors we
593 successfully allocated so far are read-only, which is okay,
594 because we don't want to change them anymore -- if we need
595 an existing color again, we get it by XAllocColor; all other
596 colors are read/write and we can set them by XStoreColor,
597 but we will try to overwrite those color cells with our new
598 color which are as close as possible to our new color */
601 /* look for an existing default color close the one we want */
608 for (i=num_cmap_entries-1; i>=0; i--)
610 xcolor2.pixel = *(global_cmap_index + i);
611 xcolor2 = xcolor_private[xcolor2.pixel];
613 if (colorcell_used[xcolor2.pixel])
616 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
617 (xcolor.green & mask) == (xcolor2.green & mask) &&
618 (xcolor.blue & mask) == (xcolor2.blue & mask))
621 printf("replacing color cell %ld with a close color\n",
632 mask = (mask << 1) & 0xffff;
635 if (!color_found) /* no more free color cells */
637 printf("Sorry, cannot allocate enough colors!\n");
641 xcolor.pixel = xcolor2.pixel;
642 xcolor_private[xcolor.pixel] = xcolor;
643 colorcell_used[xcolor.pixel] = TRUE;
644 XStoreColor(disp, ximageinfo->cmap, &xcolor);
648 *(ximageinfo->index + a) = xcolor.pixel;
652 printf("still %d free colormap entries\n", free_cmap_entries);
655 ximageinfo->no = a; /* number of pixels allocated for this image */
659 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
664 /* create an XImage and related colormap based on the image type
669 printf(" Building XImage...");
679 /* we copy the data to be more consistent
682 linelen = ((image->width + 7) / 8);
683 data= checked_malloc(linelen * image->height);
685 memcpy((char *)data, (char *)image->data, linelen * image->height);
687 gcv.function= GXcopy;
688 ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
689 0, (char *)data, image->width, image->height,
692 /* use this if you want to use the bitmap as a mask */
693 ximageinfo->depth = image->depth;
695 if(visual->class == DirectColor || visual->class == TrueColor)
698 dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
699 dpixlen= (dbits + 7) / 8;
700 pixval= redvalue[image->rgb.red[0] >> 8] |
701 greenvalue[image->rgb.green[0] >> 8] |
702 bluevalue[image->rgb.blue[0] >> 8];
703 ximageinfo->background = pixval;
704 pixval= redvalue[image->rgb.red[1] >> 8] |
705 greenvalue[image->rgb.green[1] >> 8] |
706 bluevalue[image->rgb.blue[1] >> 8];
707 ximageinfo->foreground = pixval;
709 else /* Not Direct or True Color */
711 ximageinfo->foreground = BlackPixel(disp,scrn);
712 ximageinfo->background = WhitePixel(disp,scrn);
714 ximageinfo->ximage->bitmap_bit_order= MSBFirst;
715 ximageinfo->ximage->byte_order= MSBFirst;
722 /* modify image data to match visual and colormap
725 byte *data, *destptr, *srcptr;
727 dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); /* bits per pixel */
728 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
730 ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
731 NULL, image->width, image->height,
732 8, image->width * dpixlen);
734 data = (byte *)checked_malloc(image->width * image->height * dpixlen);
735 ximageinfo->depth = ddepth;
736 ximageinfo->ximage->data = (char *)data;
737 ximageinfo->ximage->byte_order = MSBFirst;
738 srcptr = image->data;
741 switch (visual->class)
748 for (y=0; y<image->height; y++)
750 for (x=0; x<image->width; x++)
752 pixval = memToVal(srcptr, 1);
753 pixval = redvalue[image->rgb.red[pixval] >> 8] |
754 greenvalue[image->rgb.green[pixval] >> 8] |
755 bluevalue[image->rgb.blue[pixval] >> 8];
756 valToMem(pixval, destptr, dpixlen);
766 if (dpixlen == 1) /* most common */
768 for (y=0; y<image->height; y++)
770 for (x=0; x<image->width; x++)
772 *destptr = ximageinfo->index[c + *srcptr];
778 else /* less common */
780 for (y=0; y<image->height; y++)
782 for (x=0; x<image->width; x++)
784 register unsigned long temp;
785 temp = memToVal(srcptr, 1);
786 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
804 free((byte *)redvalue);
805 free((byte *)greenvalue);
806 free((byte *)bluevalue);
812 /* Given an XImage and a drawable, move a rectangle from the Ximage
816 void XImage_to_Drawable(XImageInfo *ximageinfo,
817 int src_x, int src_y, int dst_x, int dst_y,
818 unsigned int w, unsigned int h)
822 /* build and cache the GC
827 gcv.function = GXcopy;
828 if (ximageinfo->ximage->depth == 1)
830 gcv.foreground = ximageinfo->foreground;
831 gcv.background = ximageinfo->background;
832 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
833 GCFunction | GCForeground | GCBackground,
837 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
841 XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
842 ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
845 /* free up anything cached in the local Ximage structure.
848 void freeXImage(Image *image, XImageInfo *ximageinfo)
850 if (ximageinfo->index != NULL) /* if we allocated colors */
852 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
853 XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index,
855 free(ximageinfo->index);
858 XFreeGC(ximageinfo->disp, ximageinfo->gc);
859 free((byte *)ximageinfo->ximage->data);
860 ximageinfo->ximage->data= NULL;
861 XDestroyImage(ximageinfo->ximage);
862 free((byte *)ximageinfo);
863 /* should we free private color map to ??? */