6 /* extra colors to try allocating in private color maps to minimise flashing */
7 #define NOFLASH_COLORS 256
9 Image *monochrome(Image *cimage)
12 unsigned char *sp, *dp, *dp2; /* data pointers */
13 unsigned int spl; /* source pixel length in bytes */
14 unsigned int dll; /* destination line length in bytes */
15 Pixel color; /* pixel color */
16 unsigned int x, y; /* random counters */
23 printf(" Converting to monochrome...");
27 image= newBitImage(cimage->width, cimage->height);
30 image->title= (char *)lmalloc(strlen(cimage->title) + 13);
31 sprintf(image->title, "%s (monochrome)", cimage->title);
35 dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
40 for (y= 0; y < cimage->height; y++)
42 for (x= 0; x < cimage->width; x++)
44 dp2 = dp + (x / 8); /* dp + x/8 */
45 color= memToVal(sp, spl);
47 if (cimage->rgb.red[color] > 0x0000 ||
48 cimage->rgb.green[color] > 0x0000 ||
49 cimage->rgb.blue[color] > 0x0000)
54 *dp2 |= bitmap_pixel >> ( x % 8);
58 dp += dll; /* next row */
68 static unsigned int *buildIndex(unsigned int width,
83 fzoom= (float)zoom / 100.0;
84 *rwidth= (unsigned int)(fzoom * width + 0.5);
86 index= (unsigned int *)lmalloc(sizeof(unsigned int) * *rwidth);
87 for (a= 0; a < *rwidth; a++)
90 *(index + a)= (unsigned int)((float)a / fzoom + 0.5);
97 Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
100 unsigned int *xindex, *yindex;
101 unsigned int xwidth, ywidth;
102 unsigned int x, y, xsrc, ysrc;
104 unsigned int srclinelen;
105 unsigned int destlinelen;
106 byte *srcline, *srcptr;
107 byte *destline, *destptr;
108 byte srcmask, destmask, bit;
111 if ((!xzoom || xzoom==100) && (!yzoom || yzoom==100))
115 printf(" Zooming image Y axis by %d%%...", yzoom);
117 printf(" Zooming image X axis by %d%%...", xzoom);
118 else if (xzoom == yzoom)
119 printf(" Zooming image by %d%%...", xzoom);
121 printf(" Zooming image X axis by %d%% and Y axis by %d%%...",
125 xindex= buildIndex(oimage->width, xzoom, &xwidth);
126 yindex= buildIndex(oimage->height, yzoom, &ywidth);
128 switch (oimage->type)
131 image= newBitImage(xwidth, ywidth);
132 for (x= 0; x < oimage->rgb.used; x++)
134 *(image->rgb.red + x)= *(oimage->rgb.red + x);
135 *(image->rgb.green + x)= *(oimage->rgb.green + x);
136 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
138 image->rgb.used= oimage->rgb.used;
139 destline= image->data;
140 destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
141 srcline= oimage->data;
142 srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
143 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
145 while (ysrc != *(yindex + y))
148 srcline += srclinelen;
154 bit= srcmask & *srcptr;
155 for (x= 0, xsrc= *(xindex + x); x < xwidth; x++)
157 if (xsrc != *(xindex + x))
162 if (!(srcmask >>= 1))
168 while (xsrc != *(xindex + x));
170 bit= srcmask & *srcptr;
173 *destptr |= destmask;
174 if (!(destmask >>= 1))
180 destline += destlinelen;
185 image= newRGBImage(xwidth, ywidth, oimage->depth);
186 for (x= 0; x < oimage->rgb.used; x++)
188 *(image->rgb.red + x)= *(oimage->rgb.red + x);
189 *(image->rgb.green + x)= *(oimage->rgb.green + x);
190 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
192 image->rgb.used= oimage->rgb.used;
194 pixlen= oimage->pixlen;
195 destptr= image->data;
196 srcline= oimage->data;
197 srclinelen= oimage->width * pixlen;
198 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
200 while (ysrc != *(yindex + y))
203 srcline += srclinelen;
207 value = memToVal(srcptr, image->pixlen);
209 for (x=0, xsrc= *(xindex + x); x<xwidth; x++)
211 if (xsrc != *(xindex + x))
218 while (xsrc != *(xindex + x));
219 value = memToVal(srcptr, 1);
221 valToMem(value, destptr, 1);
233 image->title = dupString(oimage->title);
234 lfree((byte *)xindex);
235 lfree((byte *)yindex);
242 void compress(Image *image)
244 unsigned char *used, fast[32][32][32];
245 unsigned int dmask; /* Depth mask protection */
247 unsigned int next_index;
248 Intensity *red = image->rgb.red,
249 *green = image->rgb.green,
250 *blue = image->rgb.blue;
252 unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
253 unsigned char *pixptr, *pixend;
255 if (!RGBP(image) || image->rgb.compressed)
259 printf(" Compressing colormap...");
263 used = (unsigned char *)lcalloc(sizeof(unsigned char) * depthToColors(image->depth));
264 dmask = (1 << image->depth) -1; /* Mask any illegal bits for that depth */
265 map = (Pixel *)lcalloc(sizeof(Pixel) * depthToColors(image->depth));
267 /* init fast duplicate check table */
273 /* do pass 1 through the image to check index usage */
275 pixptr = image->data;
276 pixend = pixptr + (image->height * image->width);
277 for(;pixptr < pixend; pixptr++)
278 used[(*pixptr) & dmask] = 1;
280 /* count the bad pixels */
281 for (x = image->rgb.used; x < depthToColors(image->depth); x++)
285 /* figure out duplicates and unuseds, and create the new mapping */
287 for (x = 0; x < image->rgb.used; x++)
292 continue; /* delete this index */
295 /* check for duplicate */
299 if (fast[r>>11][g>>11][b>>11]) /* if matches fast check */
301 /* then do a linear search */
302 for (y = x+1; y < image->rgb.used; y++)
304 if (r == red[y] && g == green[y] && b == blue[y])
307 if (y < image->rgb.used) /* found match */
311 continue; /* delete this index */
313 fast[r>>11][g>>11][b>>11] = 1;
315 /* will map to this index */
320 /* change the image pixels */
321 pixptr = image->data;
322 pixend = pixptr + (image->height * image->width);
323 for(;pixptr < pixend; pixptr++)
324 *pixptr = map[(*pixptr) & dmask];
326 /* change the colormap */
327 for (x = 0; x < image->rgb.used; x++)
331 red[map[x]] = red[x];
332 green[map[x]] = green[x];
333 blue[map[x]] = blue[x];
335 image->rgb.used = next_index;
343 printf("%d out-of-range pixels, ", badcount);
345 if (!unusedcount && !dupcount)
346 printf("no improvment\n");
350 printf("%d duplicate%s and %d unused color%s removed...",
351 dupcount, (dupcount == 1 ? "" : "s"),
352 unusedcount, (unusedcount == 1 ? "" : "s"));
353 printf("%d unique color%s\n",
354 next_index, (next_index == 1 ? "" : "s"));
358 image->rgb.compressed= TRUE; /* don't do it again */
364 Pixmap ximageToPixmap(Display *disp, Window parent, XImageInfo *ximageinfo)
368 pixmap = XCreatePixmap(disp, parent,
369 ximageinfo->ximage->width, ximageinfo->ximage->height,
372 ximageinfo->drawable = pixmap;
374 sendXImage(ximageinfo, 0, 0, 0, 0,
375 ximageinfo->ximage->width, ximageinfo->ximage->height);
379 /* find the best pixmap depth supported by the server for a particular
380 * visual and return that depth.
382 * this is complicated by R3's lack of XListPixmapFormats so we fake it
383 * by looking at the structure ourselves.
386 static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
389 #if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 4)
390 /* the way things are */
391 XPixmapFormatValues *xf;
394 xf = XListPixmapFormats(disp, &nxf);
395 for (a = 0; a < nxf; a++)
397 if (xf[a].depth == depth)
400 bpp = xf[a].bits_per_pixel;
402 return (unsigned int) bpp;
406 #else /* the way things were (X11R3) */
409 for (a= 0; a < disp->nformats; a++)
410 if (disp->pixmap_format[a].depth == depth)
411 return(disp->pixmap_format[a].bits_per_pixel);
414 /* this should never happen; if it does, we're in trouble
417 fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
421 XImageInfo *imageToXImage(Display *disp, int scrn, Visual *visual,
422 unsigned int ddepth, Image *image)
424 static XColor xcolor_private[NOFLASH_COLORS];
425 static int colorcell_used[NOFLASH_COLORS];
426 static Colormap global_cmap = 0;
427 static Pixel *global_cmap_index;
428 static int num_cmap_entries, free_cmap_entries;
429 static private_cmap = FALSE;
430 Pixel *redvalue, *greenvalue, *bluevalue;
431 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
434 XImageInfo *ximageinfo;
438 if (visual == DefaultVisual(disp, scrn))
439 global_cmap = DefaultColormap(disp, scrn);
442 global_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
448 xcolor.flags = DoRed | DoGreen | DoBlue;
449 redvalue = greenvalue = bluevalue = NULL;
450 ximageinfo = (XImageInfo *)lmalloc(sizeof(XImageInfo));
451 ximageinfo->disp = disp;
452 ximageinfo->scrn = scrn;
453 ximageinfo->depth = 0;
454 ximageinfo->drawable = None;
455 ximageinfo->index = NULL;
456 ximageinfo->rootimage = FALSE;
457 ximageinfo->foreground = ximageinfo->background= 0;
458 ximageinfo->gc = NULL;
459 ximageinfo->ximage = NULL;
461 switch (visual->class)
467 unsigned int redcolors, greencolors, bluecolors;
468 unsigned int redstep, greenstep, bluestep;
469 unsigned int redbottom, greenbottom, bluebottom;
470 unsigned int redtop, greentop, bluetop;
472 redvalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
473 greenvalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
474 bluevalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
476 ximageinfo->cmap = global_cmap;
478 retry_direct: /* tag we hit if a DirectColor allocation fails on
479 * default colormap */
481 /* calculate number of distinct colors in each band
484 redcolors = greencolors = bluecolors = 1;
485 for (pixval=1; pixval; pixval <<= 1)
487 if (pixval & visual->red_mask)
489 if (pixval & visual->green_mask)
491 if (pixval & visual->blue_mask)
498 if ((redcolors > visual->map_entries) ||
499 (greencolors > visual->map_entries) ||
500 (bluecolors > visual->map_entries))
502 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
505 redstep = 256 / redcolors;
506 greenstep = 256 / greencolors;
507 bluestep = 256 / bluecolors;
508 redbottom = greenbottom = bluebottom = 0;
509 redtop = greentop = bluetop = 0;
510 for (a=0; a<visual->map_entries; a++)
513 redtop = redbottom + redstep;
514 if (greenbottom < 256)
515 greentop = greenbottom + greenstep;
516 if (bluebottom < 256)
517 bluetop = bluebottom + bluestep;
519 xcolor.red = (redtop - 1) << 8;
520 xcolor.green = (greentop - 1) << 8;
521 xcolor.blue = (bluetop - 1) << 8;
522 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
524 /* if an allocation fails for a DirectColor default visual then
525 * we should create a private colormap and try again.
528 if ((visual->class == DirectColor) &&
529 (visual == DefaultVisual(disp, scrn)))
531 global_cmap = XCopyColormapAndFree(disp, global_cmap);
532 ximageinfo->cmap = global_cmap;
538 /* something completely unexpected happened
541 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
542 lfree((byte *)redvalue);
543 lfree((byte *)greenvalue);
544 lfree((byte *)bluevalue);
545 lfree((byte *)ximageinfo);
549 /* fill in pixel values for each band at this intensity
552 while ((redbottom < 256) && (redbottom < redtop))
553 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
554 while ((greenbottom < 256) && (greenbottom < greentop))
555 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
556 while ((bluebottom < 256) && (bluebottom < bluetop))
557 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
564 ximageinfo->cmap = global_cmap;
565 ximageinfo->index = (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
567 for (a=0; a<image->rgb.used; a++)
574 xcolor.red = *(image->rgb.red + a);
575 xcolor.green = *(image->rgb.green + a);
576 xcolor.blue = *(image->rgb.blue + a);
578 /* look if this color already exists in our colormap */
579 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
584 printf("switching to private colormap...\n");
587 /* we just filled up the default colormap -- get a private one
588 which contains all already allocated colors */
590 global_cmap = XCopyColormapAndFree(disp, global_cmap);
591 ximageinfo->cmap = global_cmap;
594 /* allocate the rest of the color cells read/write */
596 (Pixel *)lmalloc(sizeof(Pixel) * NOFLASH_COLORS);
597 for (i=0; i<NOFLASH_COLORS; i++)
598 if (!XAllocColorCells(disp, global_cmap, FALSE, NULL, 0,
599 global_cmap_index + i, 1))
601 num_cmap_entries = free_cmap_entries = i;
604 printf("We've got %d free colormap entries.\n", free_cmap_entries);
607 /* to minimize colormap flashing, copy default colors and try
608 to keep them as near as possible to the old values */
610 for(i=0; i<num_cmap_entries; i++)
612 xcolor2.pixel = *(global_cmap_index + i);
613 XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor2);
614 XStoreColor(disp, global_cmap, &xcolor2);
615 xcolor_private[xcolor2.pixel] = xcolor2;
616 colorcell_used[xcolor2.pixel] = FALSE;
619 /* now we have the default colormap private: all colors we
620 successfully allocated so far are read-only, which is okay,
621 because we don't want to change them anymore -- if we need
622 an existing color again, we get it by XAllocColor; all other
623 colors are read/write and we can set them by XStoreColor,
624 but we will try to overwrite those color cells with our new
625 color which are as close as possible to our new color */
628 /* look for an existing default color close the one we want */
635 for (i=num_cmap_entries-1; i>=0; i--)
637 xcolor2.pixel = *(global_cmap_index + i);
638 xcolor2 = xcolor_private[xcolor2.pixel];
640 if (colorcell_used[xcolor2.pixel])
643 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
644 (xcolor.green & mask) == (xcolor2.green & mask) &&
645 (xcolor.blue & mask) == (xcolor2.blue & mask))
648 printf("replacing color cell %ld with a close color\n",
659 mask = (mask << 1) & 0xffff;
662 if (!color_found) /* no more free color cells */
664 printf("Sorry, cannot allocate enough colors!\n");
668 xcolor.pixel = xcolor2.pixel;
669 xcolor_private[xcolor.pixel] = xcolor;
670 colorcell_used[xcolor.pixel] = TRUE;
671 XStoreColor(disp, ximageinfo->cmap, &xcolor);
675 *(ximageinfo->index + a) = xcolor.pixel;
679 printf("still %d free colormap entries\n", free_cmap_entries);
682 ximageinfo->no = a; /* number of pixels allocated for this image */
686 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
691 /* create an XImage and related colormap based on the image type
696 printf(" Building XImage...");
706 /* we copy the data to be more consistent
709 linelen = ((image->width + 7) / 8);
710 data= lmalloc(linelen * image->height);
712 memcpy((char *)data, (char *)image->data, linelen * image->height);
714 gcv.function= GXcopy;
715 ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
716 0, (char *)data, image->width, image->height,
719 /* use this if you want to use the bitmap as a mask */
720 ximageinfo->depth = image->depth;
722 if(visual->class == DirectColor || visual->class == TrueColor)
725 dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
726 dpixlen= (dbits + 7) / 8;
727 pixval= redvalue[image->rgb.red[0] >> 8] |
728 greenvalue[image->rgb.green[0] >> 8] |
729 bluevalue[image->rgb.blue[0] >> 8];
730 ximageinfo->background = pixval;
731 pixval= redvalue[image->rgb.red[1] >> 8] |
732 greenvalue[image->rgb.green[1] >> 8] |
733 bluevalue[image->rgb.blue[1] >> 8];
734 ximageinfo->foreground = pixval;
736 else /* Not Direct or True Color */
738 ximageinfo->foreground = BlackPixel(disp,scrn);
739 ximageinfo->background = WhitePixel(disp,scrn);
741 ximageinfo->ximage->bitmap_bit_order= MSBFirst;
742 ximageinfo->ximage->byte_order= MSBFirst;
749 /* modify image data to match visual and colormap
752 byte *data, *destptr, *srcptr;
754 dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); /* bits per pixel */
755 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
757 ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
758 NULL, image->width, image->height,
759 8, image->width * dpixlen);
761 data = (byte *)lmalloc(image->width * image->height * dpixlen);
762 ximageinfo->depth = ddepth;
763 ximageinfo->ximage->data = (char *)data;
764 ximageinfo->ximage->byte_order = MSBFirst;
765 srcptr = image->data;
768 switch (visual->class)
775 for (y=0; y<image->height; y++)
777 for (x=0; x<image->width; x++)
779 pixval = memToVal(srcptr, 1);
780 pixval = redvalue[image->rgb.red[pixval] >> 8] |
781 greenvalue[image->rgb.green[pixval] >> 8] |
782 bluevalue[image->rgb.blue[pixval] >> 8];
783 valToMem(pixval, destptr, dpixlen);
793 if (dpixlen == 1) /* most common */
795 for (y=0; y<image->height; y++)
797 for (x=0; x<image->width; x++)
799 *destptr = ximageinfo->index[c + *srcptr];
805 else /* less common */
807 for (y=0; y<image->height; y++)
809 for (x=0; x<image->width; x++)
811 register unsigned long temp;
812 temp = memToVal(srcptr, 1);
813 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
831 lfree((byte *)redvalue);
832 lfree((byte *)greenvalue);
833 lfree((byte *)bluevalue);
839 /* Given an XImage and a drawable, move a rectangle from the Ximage
843 void sendXImage(XImageInfo *ximageinfo,
844 int src_x, int src_y, int dst_x, int dst_y,
845 unsigned int w, unsigned int h)
849 /* build and cache the GC
854 gcv.function = GXcopy;
855 if (ximageinfo->ximage->depth == 1)
857 gcv.foreground = ximageinfo->foreground;
858 gcv.background = ximageinfo->background;
859 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
860 GCFunction | GCForeground | GCBackground,
864 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
868 XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
869 ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
872 /* free up anything cached in the local Ximage structure.
875 void freeXImage(Image *image, XImageInfo *ximageinfo)
877 if (ximageinfo->index != NULL) /* if we allocated colors */
879 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
880 XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index, ximageinfo->no, 0);
881 lfree(ximageinfo->index);
884 XFreeGC(ximageinfo->disp, ximageinfo->gc);
885 lfree((byte *)ximageinfo->ximage->data);
886 ximageinfo->ximage->data= NULL;
887 XDestroyImage(ximageinfo->ximage);
888 lfree((byte *)ximageinfo);
889 /* should we free private color map to ??? */