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 */
22 printf("-->ERROR(monochrome)\n");
27 image = newBitImage(cimage->width, cimage->height);
30 dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
35 for (y= 0; y < cimage->height; y++)
37 for (x= 0; x < cimage->width; x++)
39 dp2 = dp + (x / 8); /* dp + x/8 */
40 color= memToVal(sp, spl);
42 if (cimage->rgb.red[color] > 0x0000 ||
43 cimage->rgb.green[color] > 0x0000 ||
44 cimage->rgb.blue[color] > 0x0000)
49 *dp2 |= bitmap_pixel >> ( x % 8);
53 dp += dll; /* next row */
59 static unsigned int *buildIndex(unsigned int width,
74 fzoom= (float)zoom / 100.0;
75 *rwidth= (unsigned int)(fzoom * width + 0.5);
77 index= (unsigned int *)checked_malloc(sizeof(unsigned int) * *rwidth);
78 for (a= 0; a < *rwidth; a++)
81 *(index + a)= (unsigned int)((float)a / fzoom + 0.5);
88 Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
91 unsigned int *xindex, *yindex;
92 unsigned int xwidth, ywidth;
93 unsigned int x, y, xsrc, ysrc;
95 unsigned int srclinelen;
96 unsigned int destlinelen;
97 byte *srcline, *srcptr;
98 byte *destline, *destptr;
99 byte srcmask, destmask, bit;
102 if ((!xzoom || xzoom==100) && (!yzoom || yzoom==100))
106 printf(" Zooming image Y axis by %d%%...", yzoom);
108 printf(" Zooming image X axis by %d%%...", xzoom);
109 else if (xzoom == yzoom)
110 printf(" Zooming image by %d%%...", xzoom);
112 printf(" Zooming image X axis by %d%% and Y axis by %d%%...",
116 xindex= buildIndex(oimage->width, xzoom, &xwidth);
117 yindex= buildIndex(oimage->height, yzoom, &ywidth);
119 switch (oimage->type)
122 image= newBitImage(xwidth, ywidth);
123 for (x= 0; x < oimage->rgb.used; x++)
125 *(image->rgb.red + x)= *(oimage->rgb.red + x);
126 *(image->rgb.green + x)= *(oimage->rgb.green + x);
127 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
129 image->rgb.used= oimage->rgb.used;
130 destline= image->data;
131 destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
132 srcline= oimage->data;
133 srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
134 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
136 while (ysrc != *(yindex + y))
139 srcline += srclinelen;
145 bit= srcmask & *srcptr;
146 for (x= 0, xsrc= *(xindex + x); x < xwidth; x++)
148 if (xsrc != *(xindex + x))
153 if (!(srcmask >>= 1))
159 while (xsrc != *(xindex + x));
161 bit= srcmask & *srcptr;
164 *destptr |= destmask;
165 if (!(destmask >>= 1))
171 destline += destlinelen;
176 image= newRGBImage(xwidth, ywidth, oimage->depth);
177 for (x= 0; x < oimage->rgb.used; x++)
179 *(image->rgb.red + x)= *(oimage->rgb.red + x);
180 *(image->rgb.green + x)= *(oimage->rgb.green + x);
181 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
183 image->rgb.used= oimage->rgb.used;
185 pixlen= oimage->pixlen;
186 destptr= image->data;
187 srcline= oimage->data;
188 srclinelen= oimage->width * pixlen;
189 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
191 while (ysrc != *(yindex + y))
194 srcline += srclinelen;
198 value = memToVal(srcptr, image->pixlen);
200 for (x=0, xsrc= *(xindex + x); x<xwidth; x++)
202 if (xsrc != *(xindex + x))
209 while (xsrc != *(xindex + x));
210 value = memToVal(srcptr, 1);
212 valToMem(value, destptr, 1);
224 free((byte *)xindex);
225 free((byte *)yindex);
232 void compress(Image *image)
234 unsigned char *used, fast[32][32][32];
235 unsigned int dmask; /* Depth mask protection */
237 unsigned int next_index;
238 Intensity *red = image->rgb.red,
239 *green = image->rgb.green,
240 *blue = image->rgb.blue;
242 unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
243 unsigned char *pixptr, *pixend;
245 if (!RGBP(image) || image->rgb.compressed)
248 used = (unsigned char *)checked_calloc(sizeof(unsigned char) * depthToColors(image->depth));
249 dmask = (1 << image->depth) -1; /* Mask any illegal bits for that depth */
250 map = (Pixel *)checked_calloc(sizeof(Pixel) * depthToColors(image->depth));
252 /* init fast duplicate check table */
258 /* do pass 1 through the image to check index usage */
260 pixptr = image->data;
261 pixend = pixptr + (image->height * image->width);
262 for(;pixptr < pixend; pixptr++)
263 used[(*pixptr) & dmask] = 1;
265 /* count the bad pixels */
266 for (x = image->rgb.used; x < depthToColors(image->depth); x++)
270 /* figure out duplicates and unuseds, and create the new mapping */
272 for (x = 0; x < image->rgb.used; x++)
277 continue; /* delete this index */
280 /* check for duplicate */
284 if (fast[r>>11][g>>11][b>>11]) /* if matches fast check */
286 /* then do a linear search */
287 for (y = x+1; y < image->rgb.used; y++)
289 if (r == red[y] && g == green[y] && b == blue[y])
292 if (y < image->rgb.used) /* found match */
296 continue; /* delete this index */
298 fast[r>>11][g>>11][b>>11] = 1;
300 /* will map to this index */
305 /* change the image pixels */
306 pixptr = image->data;
307 pixend = pixptr + (image->height * image->width);
308 for(;pixptr < pixend; pixptr++)
309 *pixptr = map[(*pixptr) & dmask];
311 /* change the colormap */
312 for (x = 0; x < image->rgb.used; x++)
316 red[map[x]] = red[x];
317 green[map[x]] = green[x];
318 blue[map[x]] = blue[x];
320 image->rgb.used = next_index;
330 printf("%d out-of-range pixels, ", badcount);
332 if (!unusedcount && !dupcount)
333 printf("no improvment\n");
337 printf("%d duplicate%s and %d unused color%s removed...",
338 dupcount, (dupcount == 1 ? "" : "s"),
339 unusedcount, (unusedcount == 1 ? "" : "s"));
340 printf("%d unique color%s\n",
341 next_index, (next_index == 1 ? "" : "s"));
347 image->rgb.compressed= TRUE; /* don't do it again */
353 Pixmap XImage_to_Pixmap(Display *disp, Window parent, XImageInfo *ximageinfo)
357 pixmap = XCreatePixmap(disp, parent,
358 ximageinfo->ximage->width, ximageinfo->ximage->height,
361 ximageinfo->drawable = pixmap;
363 XImage_to_Drawable(ximageinfo, 0, 0, 0, 0,
364 ximageinfo->ximage->width, ximageinfo->ximage->height);
368 /* find the best pixmap depth supported by the server for a particular
369 * visual and return that depth.
371 * this is complicated by R3's lack of XListPixmapFormats so we fake it
372 * by looking at the structure ourselves.
375 static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
378 XPixmapFormatValues *xf;
381 xf = XListPixmapFormats(disp, &nxf);
382 for (a = 0; a < nxf; a++)
384 if (xf[a].depth == depth)
387 bpp = xf[a].bits_per_pixel;
389 return (unsigned int) bpp;
394 /* this should never happen; if it does, we're in trouble
397 fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
401 XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
402 unsigned int ddepth, Image *image)
404 static XColor xcolor_private[NOFLASH_COLORS];
405 static int colorcell_used[NOFLASH_COLORS];
406 static Colormap global_cmap = 0;
407 static Pixel *global_cmap_index;
408 static int num_cmap_entries, free_cmap_entries;
409 static private_cmap = FALSE;
410 Pixel *redvalue, *greenvalue, *bluevalue;
411 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
414 XImageInfo *ximageinfo;
418 if (visual == DefaultVisual(disp, scrn))
419 global_cmap = DefaultColormap(disp, scrn);
422 global_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
428 xcolor.flags = DoRed | DoGreen | DoBlue;
429 redvalue = greenvalue = bluevalue = NULL;
430 ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
431 ximageinfo->disp = disp;
432 ximageinfo->scrn = scrn;
433 ximageinfo->depth = 0;
434 ximageinfo->drawable = None;
435 ximageinfo->index = NULL;
436 ximageinfo->rootimage = FALSE;
437 ximageinfo->foreground = ximageinfo->background= 0;
438 ximageinfo->gc = NULL;
439 ximageinfo->ximage = NULL;
441 switch (visual->class)
447 unsigned int redcolors, greencolors, bluecolors;
448 unsigned int redstep, greenstep, bluestep;
449 unsigned int redbottom, greenbottom, bluebottom;
450 unsigned int redtop, greentop, bluetop;
452 redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
453 greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
454 bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
456 ximageinfo->cmap = global_cmap;
458 retry_direct: /* tag we hit if a DirectColor allocation fails on
459 * default colormap */
461 /* calculate number of distinct colors in each band
464 redcolors = greencolors = bluecolors = 1;
465 for (pixval=1; pixval; pixval <<= 1)
467 if (pixval & visual->red_mask)
469 if (pixval & visual->green_mask)
471 if (pixval & visual->blue_mask)
478 if ((redcolors > visual->map_entries) ||
479 (greencolors > visual->map_entries) ||
480 (bluecolors > visual->map_entries))
482 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
485 redstep = 256 / redcolors;
486 greenstep = 256 / greencolors;
487 bluestep = 256 / bluecolors;
488 redbottom = greenbottom = bluebottom = 0;
489 redtop = greentop = bluetop = 0;
490 for (a=0; a<visual->map_entries; a++)
493 redtop = redbottom + redstep;
494 if (greenbottom < 256)
495 greentop = greenbottom + greenstep;
496 if (bluebottom < 256)
497 bluetop = bluebottom + bluestep;
499 xcolor.red = (redtop - 1) << 8;
500 xcolor.green = (greentop - 1) << 8;
501 xcolor.blue = (bluetop - 1) << 8;
502 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
504 /* if an allocation fails for a DirectColor default visual then
505 * we should create a private colormap and try again.
508 if ((visual->class == DirectColor) &&
509 (visual == DefaultVisual(disp, scrn)))
511 global_cmap = XCopyColormapAndFree(disp, global_cmap);
512 ximageinfo->cmap = global_cmap;
518 /* something completely unexpected happened
521 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
522 free((byte *)redvalue);
523 free((byte *)greenvalue);
524 free((byte *)bluevalue);
525 free((byte *)ximageinfo);
529 /* fill in pixel values for each band at this intensity
532 while ((redbottom < 256) && (redbottom < redtop))
533 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
534 while ((greenbottom < 256) && (greenbottom < greentop))
535 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
536 while ((bluebottom < 256) && (bluebottom < bluetop))
537 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
544 ximageinfo->cmap = global_cmap;
546 (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
548 for (a=0; a<image->rgb.used; a++)
555 xcolor.red = *(image->rgb.red + a);
556 xcolor.green = *(image->rgb.green + a);
557 xcolor.blue = *(image->rgb.blue + a);
559 /* look if this color already exists in our colormap */
560 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
565 printf("switching to private colormap...\n");
568 /* we just filled up the default colormap -- get a private one
569 which contains all already allocated colors */
571 global_cmap = XCopyColormapAndFree(disp, global_cmap);
572 ximageinfo->cmap = global_cmap;
575 /* allocate the rest of the color cells read/write */
577 (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
578 for (i=0; i<NOFLASH_COLORS; i++)
579 if (!XAllocColorCells(disp, global_cmap, FALSE, NULL, 0,
580 global_cmap_index + i, 1))
582 num_cmap_entries = free_cmap_entries = i;
585 printf("We've got %d free colormap entries.\n", free_cmap_entries);
588 /* to minimize colormap flashing, copy default colors and try
589 to keep them as near as possible to the old values */
591 for(i=0; i<num_cmap_entries; i++)
593 xcolor2.pixel = *(global_cmap_index + i);
594 XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor2);
595 XStoreColor(disp, global_cmap, &xcolor2);
596 xcolor_private[xcolor2.pixel] = xcolor2;
597 colorcell_used[xcolor2.pixel] = FALSE;
600 /* now we have the default colormap private: all colors we
601 successfully allocated so far are read-only, which is okay,
602 because we don't want to change them anymore -- if we need
603 an existing color again, we get it by XAllocColor; all other
604 colors are read/write and we can set them by XStoreColor,
605 but we will try to overwrite those color cells with our new
606 color which are as close as possible to our new color */
609 /* look for an existing default color close the one we want */
616 for (i=num_cmap_entries-1; i>=0; i--)
618 xcolor2.pixel = *(global_cmap_index + i);
619 xcolor2 = xcolor_private[xcolor2.pixel];
621 if (colorcell_used[xcolor2.pixel])
624 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
625 (xcolor.green & mask) == (xcolor2.green & mask) &&
626 (xcolor.blue & mask) == (xcolor2.blue & mask))
629 printf("replacing color cell %ld with a close color\n",
640 mask = (mask << 1) & 0xffff;
643 if (!color_found) /* no more free color cells */
645 printf("Sorry, cannot allocate enough colors!\n");
649 xcolor.pixel = xcolor2.pixel;
650 xcolor_private[xcolor.pixel] = xcolor;
651 colorcell_used[xcolor.pixel] = TRUE;
652 XStoreColor(disp, ximageinfo->cmap, &xcolor);
656 *(ximageinfo->index + a) = xcolor.pixel;
660 printf("still %d free colormap entries\n", free_cmap_entries);
663 ximageinfo->no = a; /* number of pixels allocated for this image */
667 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
672 /* create an XImage and related colormap based on the image type
677 printf(" Building XImage...");
687 /* we copy the data to be more consistent
690 linelen = ((image->width + 7) / 8);
691 data= checked_malloc(linelen * image->height);
693 memcpy((char *)data, (char *)image->data, linelen * image->height);
695 gcv.function= GXcopy;
696 ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
697 0, (char *)data, image->width, image->height,
700 /* use this if you want to use the bitmap as a mask */
701 ximageinfo->depth = image->depth;
703 if(visual->class == DirectColor || visual->class == TrueColor)
706 dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
707 dpixlen= (dbits + 7) / 8;
708 pixval= redvalue[image->rgb.red[0] >> 8] |
709 greenvalue[image->rgb.green[0] >> 8] |
710 bluevalue[image->rgb.blue[0] >> 8];
711 ximageinfo->background = pixval;
712 pixval= redvalue[image->rgb.red[1] >> 8] |
713 greenvalue[image->rgb.green[1] >> 8] |
714 bluevalue[image->rgb.blue[1] >> 8];
715 ximageinfo->foreground = pixval;
717 else /* Not Direct or True Color */
719 ximageinfo->foreground = BlackPixel(disp,scrn);
720 ximageinfo->background = WhitePixel(disp,scrn);
722 ximageinfo->ximage->bitmap_bit_order= MSBFirst;
723 ximageinfo->ximage->byte_order= MSBFirst;
730 /* modify image data to match visual and colormap
733 byte *data, *destptr, *srcptr;
735 dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); /* bits per pixel */
736 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
738 ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
739 NULL, image->width, image->height,
740 8, image->width * dpixlen);
742 data = (byte *)checked_malloc(image->width * image->height * dpixlen);
743 ximageinfo->depth = ddepth;
744 ximageinfo->ximage->data = (char *)data;
745 ximageinfo->ximage->byte_order = MSBFirst;
746 srcptr = image->data;
749 switch (visual->class)
756 for (y=0; y<image->height; y++)
758 for (x=0; x<image->width; x++)
760 pixval = memToVal(srcptr, 1);
761 pixval = redvalue[image->rgb.red[pixval] >> 8] |
762 greenvalue[image->rgb.green[pixval] >> 8] |
763 bluevalue[image->rgb.blue[pixval] >> 8];
764 valToMem(pixval, destptr, dpixlen);
774 if (dpixlen == 1) /* most common */
776 for (y=0; y<image->height; y++)
778 for (x=0; x<image->width; x++)
780 *destptr = ximageinfo->index[c + *srcptr];
786 else /* less common */
788 for (y=0; y<image->height; y++)
790 for (x=0; x<image->width; x++)
792 register unsigned long temp;
793 temp = memToVal(srcptr, 1);
794 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
812 free((byte *)redvalue);
813 free((byte *)greenvalue);
814 free((byte *)bluevalue);
820 /* Given an XImage and a drawable, move a rectangle from the Ximage
824 void XImage_to_Drawable(XImageInfo *ximageinfo,
825 int src_x, int src_y, int dst_x, int dst_y,
826 unsigned int w, unsigned int h)
830 /* build and cache the GC
835 gcv.function = GXcopy;
836 if (ximageinfo->ximage->depth == 1)
838 gcv.foreground = ximageinfo->foreground;
839 gcv.background = ximageinfo->background;
840 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
841 GCFunction | GCForeground | GCBackground,
845 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
849 XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
850 ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
853 /* free up anything cached in the local Ximage structure.
856 void freeXImage(Image *image, XImageInfo *ximageinfo)
858 if (ximageinfo->index != NULL) /* if we allocated colors */
860 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
861 XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index,
863 free(ximageinfo->index);
866 XFreeGC(ximageinfo->disp, ximageinfo->gc);
867 free((byte *)ximageinfo->ximage->data);
868 ximageinfo->ximage->data= NULL;
869 XDestroyImage(ximageinfo->ximage);
870 free((byte *)ximageinfo);
871 /* should we free private color map to ??? */
876 /* this table is useful for quick conversions between depth and ncolors
879 unsigned long DepthToColorsTable[] =
908 void newRGBMapData(RGBMap *rgb, unsigned int size)
912 rgb->compressed = FALSE;
913 rgb->red = (Intensity *)checked_malloc(sizeof(Intensity) * size);
914 rgb->green = (Intensity *)checked_malloc(sizeof(Intensity) * size);
915 rgb->blue = (Intensity *)checked_malloc(sizeof(Intensity) * size);
918 void freeRGBMapData(RGBMap *rgb)
920 free((byte *)rgb->red);
921 free((byte *)rgb->green);
922 free((byte *)rgb->blue);
925 Image *newBitImage(unsigned int width, unsigned int height)
928 unsigned int linelen;
930 image = (Image *)checked_malloc(sizeof(Image));
931 image->type = IBITMAP;
932 newRGBMapData(&(image->rgb), (unsigned int)2);
933 *(image->rgb.red)= *(image->rgb.green) = *(image->rgb.blue)= 65535;
934 *(image->rgb.red + 1)= *(image->rgb.green + 1) = *(image->rgb.blue + 1)= 0;
936 image->width = width;
937 image->height = height;
939 linelen = ((width + 7) / 8);
940 image->data = (unsigned char *)checked_calloc(linelen * height);
944 Image *newRGBImage(unsigned int width, unsigned int height, unsigned int depth)
947 unsigned int pixlen, numcolors;
949 if (depth == 0) /* special case for `zero' depth image, which is */
950 depth = 1; /* sometimes interpreted as `one color' */
951 pixlen = ((depth+7) / 8);
952 numcolors = depthToColors(depth);
953 image = (Image *)checked_malloc(sizeof(Image));
955 newRGBMapData(&(image->rgb), numcolors);
956 image->width = width;
957 image->height = height;
958 image->depth = depth;
959 image->pixlen = pixlen;
960 image->data = (unsigned char *)checked_malloc(width * height * pixlen);
964 void freeImageData(Image *image)
966 freeRGBMapData(&(image->rgb));
970 void freeImage(Image *image)
972 freeImageData(image);