4 * send an Image to an X pixmap
9 /* extra colors to try allocating in private color maps to minimise flashing */
10 #define NOFLASH_COLORS 256
12 Image *monochrome(Image *cimage)
15 unsigned char *sp, *dp, *dp2; /* data pointers */
16 unsigned int spl; /* source pixel length in bytes */
17 unsigned int dll; /* destination line length in bytes */
18 Pixel color; /* pixel color */
19 unsigned int x, y; /* random counters */
26 printf(" Converting to monochrome...");
30 image= newBitImage(cimage->width, cimage->height);
33 image->title= (char *)lmalloc(strlen(cimage->title) + 13);
34 sprintf(image->title, "%s (monochrome)", cimage->title);
38 dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
43 for (y= 0; y < cimage->height; y++)
45 for (x= 0; x < cimage->width; x++)
47 dp2 = dp + (x / 8); /* dp + x/8 */
48 color= memToVal(sp, spl);
50 if (cimage->rgb.red[color] > 0x0000 ||
51 cimage->rgb.green[color] > 0x0000 ||
52 cimage->rgb.blue[color] > 0x0000)
57 *dp2 |= bitmap_pixel >> ( x % 8);
61 dp += dll; /* next row */
71 static unsigned int *buildIndex(unsigned int width,
86 fzoom= (float)zoom / 100.0;
87 *rwidth= (unsigned int)(fzoom * width + 0.5);
89 index= (unsigned int *)lmalloc(sizeof(unsigned int) * *rwidth);
90 for (a= 0; a < *rwidth; a++)
93 *(index + a)= (unsigned int)((float)a / fzoom + 0.5);
100 Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
103 unsigned int *xindex, *yindex;
104 unsigned int xwidth, ywidth;
105 unsigned int x, y, xsrc, ysrc;
107 unsigned int srclinelen;
108 unsigned int destlinelen;
109 byte *srcline, *srcptr;
110 byte *destline, *destptr;
111 byte srcmask, destmask, bit;
114 if ((!xzoom || xzoom==100) && (!yzoom || yzoom==100))
118 printf(" Zooming image Y axis by %d%%...", yzoom);
120 printf(" Zooming image X axis by %d%%...", xzoom);
121 else if (xzoom == yzoom)
122 printf(" Zooming image by %d%%...", xzoom);
124 printf(" Zooming image X axis by %d%% and Y axis by %d%%...",
128 xindex= buildIndex(oimage->width, xzoom, &xwidth);
129 yindex= buildIndex(oimage->height, yzoom, &ywidth);
131 switch (oimage->type)
134 image= newBitImage(xwidth, ywidth);
135 for (x= 0; x < oimage->rgb.used; x++)
137 *(image->rgb.red + x)= *(oimage->rgb.red + x);
138 *(image->rgb.green + x)= *(oimage->rgb.green + x);
139 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
141 image->rgb.used= oimage->rgb.used;
142 destline= image->data;
143 destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
144 srcline= oimage->data;
145 srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
146 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
148 while (ysrc != *(yindex + y))
151 srcline += srclinelen;
157 bit= srcmask & *srcptr;
158 for (x= 0, xsrc= *(xindex + x); x < xwidth; x++)
160 if (xsrc != *(xindex + x))
165 if (!(srcmask >>= 1))
171 while (xsrc != *(xindex + x));
173 bit= srcmask & *srcptr;
176 *destptr |= destmask;
177 if (!(destmask >>= 1))
183 destline += destlinelen;
188 image= newRGBImage(xwidth, ywidth, oimage->depth);
189 for (x= 0; x < oimage->rgb.used; x++)
191 *(image->rgb.red + x)= *(oimage->rgb.red + x);
192 *(image->rgb.green + x)= *(oimage->rgb.green + x);
193 *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
195 image->rgb.used= oimage->rgb.used;
197 pixlen= oimage->pixlen;
198 destptr= image->data;
199 srcline= oimage->data;
200 srclinelen= oimage->width * pixlen;
201 for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
203 while (ysrc != *(yindex + y))
206 srcline += srclinelen;
210 value = memToVal(srcptr, image->pixlen);
212 for (x=0, xsrc= *(xindex + x); x<xwidth; x++)
214 if (xsrc != *(xindex + x))
221 while (xsrc != *(xindex + x));
222 value = memToVal(srcptr, 1);
224 valToMem(value, destptr, 1);
236 image->title = dupString(oimage->title);
237 lfree((byte *)xindex);
238 lfree((byte *)yindex);
245 void compress(Image *image)
247 unsigned char *used, fast[32][32][32];
248 unsigned int dmask; /* Depth mask protection */
250 unsigned int next_index;
251 Intensity *red = image->rgb.red,
252 *green = image->rgb.green,
253 *blue = image->rgb.blue;
255 unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
256 unsigned char *pixptr, *pixend;
258 if (!RGBP(image) || image->rgb.compressed)
262 printf(" Compressing colormap...");
266 used = (unsigned char *)lcalloc(sizeof(unsigned char) * depthToColors(image->depth));
267 dmask = (1 << image->depth) -1; /* Mask any illegal bits for that depth */
268 map = (Pixel *)lcalloc(sizeof(Pixel) * depthToColors(image->depth));
270 /* init fast duplicate check table */
276 /* do pass 1 through the image to check index usage */
278 pixptr = image->data;
279 pixend = pixptr + (image->height * image->width);
280 for(;pixptr < pixend; pixptr++)
281 used[(*pixptr) & dmask] = 1;
283 /* count the bad pixels */
284 for (x = image->rgb.used; x < depthToColors(image->depth); x++)
288 /* figure out duplicates and unuseds, and create the new mapping */
290 for (x = 0; x < image->rgb.used; x++)
295 continue; /* delete this index */
298 /* check for duplicate */
302 if (fast[r>>11][g>>11][b>>11]) /* if matches fast check */
304 /* then do a linear search */
305 for (y = x+1; y < image->rgb.used; y++)
307 if (r == red[y] && g == green[y] && b == blue[y])
310 if (y < image->rgb.used) /* found match */
314 continue; /* delete this index */
316 fast[r>>11][g>>11][b>>11] = 1;
318 /* will map to this index */
323 /* change the image pixels */
324 pixptr = image->data;
325 pixend = pixptr + (image->height * image->width);
326 for(;pixptr < pixend; pixptr++)
327 *pixptr = map[(*pixptr) & dmask];
329 /* change the colormap */
330 for (x = 0; x < image->rgb.used; x++)
334 red[map[x]] = red[x];
335 green[map[x]] = green[x];
336 blue[map[x]] = blue[x];
338 image->rgb.used = next_index;
346 printf("%d out-of-range pixels, ", badcount);
348 if (!unusedcount && !dupcount)
349 printf("no improvment\n");
353 printf("%d duplicate%s and %d unused color%s removed...",
354 dupcount, (dupcount == 1 ? "" : "s"),
355 unusedcount, (unusedcount == 1 ? "" : "s"));
356 printf("%d unique color%s\n",
357 next_index, (next_index == 1 ? "" : "s"));
361 image->rgb.compressed= TRUE; /* don't do it again */
367 Pixmap ximageToPixmap(Display *disp, Window parent, XImageInfo *ximageinfo)
371 pixmap = XCreatePixmap(disp, parent,
372 ximageinfo->ximage->width, ximageinfo->ximage->height,
375 ximageinfo->drawable = pixmap;
377 sendXImage(ximageinfo, 0, 0, 0, 0,
378 ximageinfo->ximage->width, ximageinfo->ximage->height);
382 /* find the best pixmap depth supported by the server for a particular
383 * visual and return that depth.
385 * this is complicated by R3's lack of XListPixmapFormats so we fake it
386 * by looking at the structure ourselves.
389 static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
392 #if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 4)
393 /* the way things are */
394 XPixmapFormatValues *xf;
397 xf = XListPixmapFormats(disp, &nxf);
398 for (a = 0; a < nxf; a++)
400 if (xf[a].depth == depth)
403 bpp = xf[a].bits_per_pixel;
405 return (unsigned int) bpp;
409 #else /* the way things were (X11R3) */
412 for (a= 0; a < disp->nformats; a++)
413 if (disp->pixmap_format[a].depth == depth)
414 return(disp->pixmap_format[a].bits_per_pixel);
417 /* this should never happen; if it does, we're in trouble
420 fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
424 XImageInfo *imageToXImage(Display *disp, int scrn, Visual *visual,
425 unsigned int ddepth, Image *image)
427 static XColor xcolor_private[NOFLASH_COLORS];
428 static int colorcell_used[NOFLASH_COLORS];
429 static Colormap global_cmap = 0;
430 static Pixel *global_cmap_index;
431 static int num_cmap_entries, free_cmap_entries;
432 static private_cmap = FALSE;
433 Pixel *redvalue, *greenvalue, *bluevalue;
434 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
437 XImageInfo *ximageinfo;
441 if (visual == DefaultVisual(disp, scrn))
442 global_cmap = DefaultColormap(disp, scrn);
445 global_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
451 xcolor.flags = DoRed | DoGreen | DoBlue;
452 redvalue = greenvalue = bluevalue = NULL;
453 ximageinfo = (XImageInfo *)lmalloc(sizeof(XImageInfo));
454 ximageinfo->disp = disp;
455 ximageinfo->scrn = scrn;
456 ximageinfo->depth = 0;
457 ximageinfo->drawable = None;
458 ximageinfo->index = NULL;
459 ximageinfo->rootimage = FALSE;
460 ximageinfo->foreground = ximageinfo->background= 0;
461 ximageinfo->gc = NULL;
462 ximageinfo->ximage = NULL;
464 switch (visual->class)
470 unsigned int redcolors, greencolors, bluecolors;
471 unsigned int redstep, greenstep, bluestep;
472 unsigned int redbottom, greenbottom, bluebottom;
473 unsigned int redtop, greentop, bluetop;
475 redvalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
476 greenvalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
477 bluevalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
479 ximageinfo->cmap = global_cmap;
481 retry_direct: /* tag we hit if a DirectColor allocation fails on
482 * default colormap */
484 /* calculate number of distinct colors in each band
487 redcolors = greencolors = bluecolors = 1;
488 for (pixval=1; pixval; pixval <<= 1)
490 if (pixval & visual->red_mask)
492 if (pixval & visual->green_mask)
494 if (pixval & visual->blue_mask)
501 if ((redcolors > visual->map_entries) ||
502 (greencolors > visual->map_entries) ||
503 (bluecolors > visual->map_entries))
505 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
508 redstep = 256 / redcolors;
509 greenstep = 256 / greencolors;
510 bluestep = 256 / bluecolors;
511 redbottom = greenbottom = bluebottom = 0;
512 redtop = greentop = bluetop = 0;
513 for (a=0; a<visual->map_entries; a++)
516 redtop = redbottom + redstep;
517 if (greenbottom < 256)
518 greentop = greenbottom + greenstep;
519 if (bluebottom < 256)
520 bluetop = bluebottom + bluestep;
522 xcolor.red = (redtop - 1) << 8;
523 xcolor.green = (greentop - 1) << 8;
524 xcolor.blue = (bluetop - 1) << 8;
525 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
527 /* if an allocation fails for a DirectColor default visual then
528 * we should create a private colormap and try again.
531 if ((visual->class == DirectColor) &&
532 (visual == DefaultVisual(disp, scrn)))
534 global_cmap = XCopyColormapAndFree(disp, global_cmap);
535 ximageinfo->cmap = global_cmap;
541 /* something completely unexpected happened
544 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
545 lfree((byte *)redvalue);
546 lfree((byte *)greenvalue);
547 lfree((byte *)bluevalue);
548 lfree((byte *)ximageinfo);
552 /* fill in pixel values for each band at this intensity
555 while ((redbottom < 256) && (redbottom < redtop))
556 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
557 while ((greenbottom < 256) && (greenbottom < greentop))
558 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
559 while ((bluebottom < 256) && (bluebottom < bluetop))
560 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
567 ximageinfo->cmap = global_cmap;
568 ximageinfo->index = (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
570 for (a=0; a<image->rgb.used; a++)
577 xcolor.red = *(image->rgb.red + a);
578 xcolor.green = *(image->rgb.green + a);
579 xcolor.blue = *(image->rgb.blue + a);
581 /* look if this color already exists in our colormap */
582 if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
587 printf("switching to private colormap...\n");
590 /* we just filled up the default colormap -- get a private one
591 which contains all already allocated colors */
593 global_cmap = XCopyColormapAndFree(disp, global_cmap);
594 ximageinfo->cmap = global_cmap;
597 /* allocate the rest of the color cells read/write */
599 (Pixel *)lmalloc(sizeof(Pixel) * NOFLASH_COLORS);
600 for (i=0; i<NOFLASH_COLORS; i++)
601 if (!XAllocColorCells(disp, global_cmap, FALSE, NULL, 0,
602 global_cmap_index + i, 1))
604 num_cmap_entries = free_cmap_entries = i;
607 printf("We've got %d free colormap entries.\n", free_cmap_entries);
610 /* to minimize colormap flashing, copy default colors and try
611 to keep them as near as possible to the old values */
613 for(i=0; i<num_cmap_entries; i++)
615 xcolor2.pixel = *(global_cmap_index + i);
616 XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor2);
617 XStoreColor(disp, global_cmap, &xcolor2);
618 xcolor_private[xcolor2.pixel] = xcolor2;
619 colorcell_used[xcolor2.pixel] = FALSE;
622 /* now we have the default colormap private: all colors we
623 successfully allocated so far are read-only, which is okay,
624 because we don't want to change them anymore -- if we need
625 an existing color again, we get it by XAllocColor; all other
626 colors are read/write and we can set them by XStoreColor,
627 but we will try to overwrite those color cells with our new
628 color which are as close as possible to our new color */
631 /* look for an existing default color close the one we want */
638 for (i=num_cmap_entries-1; i>=0; i--)
640 xcolor2.pixel = *(global_cmap_index + i);
641 xcolor2 = xcolor_private[xcolor2.pixel];
643 if (colorcell_used[xcolor2.pixel])
646 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
647 (xcolor.green & mask) == (xcolor2.green & mask) &&
648 (xcolor.blue & mask) == (xcolor2.blue & mask))
651 printf("replacing color cell %ld with a close color\n",
662 mask = (mask << 1) & 0xffff;
665 if (!color_found) /* no more free color cells */
667 printf("Sorry, cannot allocate enough colors!\n");
671 xcolor.pixel = xcolor2.pixel;
672 xcolor_private[xcolor.pixel] = xcolor;
673 colorcell_used[xcolor.pixel] = TRUE;
674 XStoreColor(disp, ximageinfo->cmap, &xcolor);
678 *(ximageinfo->index + a) = xcolor.pixel;
682 printf("still %d free colormap entries\n", free_cmap_entries);
685 ximageinfo->no = a; /* number of pixels allocated for this image */
689 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
694 /* create an XImage and related colormap based on the image type
699 printf(" Building XImage...");
709 /* we copy the data to be more consistent
712 linelen = ((image->width + 7) / 8);
713 data= lmalloc(linelen * image->height);
715 memcpy((char *)data, (char *)image->data, linelen * image->height);
717 gcv.function= GXcopy;
718 ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
719 0, (char *)data, image->width, image->height,
722 /* use this if you want to use the bitmap as a mask */
723 ximageinfo->depth = image->depth;
725 if(visual->class == DirectColor || visual->class == TrueColor)
728 dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
729 dpixlen= (dbits + 7) / 8;
730 pixval= redvalue[image->rgb.red[0] >> 8] |
731 greenvalue[image->rgb.green[0] >> 8] |
732 bluevalue[image->rgb.blue[0] >> 8];
733 ximageinfo->background = pixval;
734 pixval= redvalue[image->rgb.red[1] >> 8] |
735 greenvalue[image->rgb.green[1] >> 8] |
736 bluevalue[image->rgb.blue[1] >> 8];
737 ximageinfo->foreground = pixval;
739 else /* Not Direct or True Color */
741 ximageinfo->foreground = BlackPixel(disp,scrn);
742 ximageinfo->background = WhitePixel(disp,scrn);
744 ximageinfo->ximage->bitmap_bit_order= MSBFirst;
745 ximageinfo->ximage->byte_order= MSBFirst;
752 /* modify image data to match visual and colormap
755 byte *data, *destptr, *srcptr;
757 dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); /* bits per pixel */
758 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
760 ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
761 NULL, image->width, image->height,
762 8, image->width * dpixlen);
764 data = (byte *)lmalloc(image->width * image->height * dpixlen);
765 ximageinfo->depth = ddepth;
766 ximageinfo->ximage->data = (char *)data;
767 ximageinfo->ximage->byte_order = MSBFirst;
768 srcptr = image->data;
771 switch (visual->class)
778 for (y=0; y<image->height; y++)
780 for (x=0; x<image->width; x++)
782 pixval = memToVal(srcptr, 1);
783 pixval = redvalue[image->rgb.red[pixval] >> 8] |
784 greenvalue[image->rgb.green[pixval] >> 8] |
785 bluevalue[image->rgb.blue[pixval] >> 8];
786 valToMem(pixval, destptr, dpixlen);
796 if (dpixlen == 1) /* most common */
798 for (y=0; y<image->height; y++)
800 for (x=0; x<image->width; x++)
802 *destptr = ximageinfo->index[c + *srcptr];
808 else /* less common */
810 for (y=0; y<image->height; y++)
812 for (x=0; x<image->width; x++)
814 register unsigned long temp;
815 temp = memToVal(srcptr, 1);
816 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
834 lfree((byte *)redvalue);
835 lfree((byte *)greenvalue);
836 lfree((byte *)bluevalue);
842 /* Given an XImage and a drawable, move a rectangle from the Ximage
846 void sendXImage(XImageInfo *ximageinfo,
847 int src_x, int src_y, int dst_x, int dst_y,
848 unsigned int w, unsigned int h)
852 /* build and cache the GC
857 gcv.function = GXcopy;
858 if (ximageinfo->ximage->depth == 1)
860 gcv.foreground = ximageinfo->foreground;
861 gcv.background = ximageinfo->background;
862 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
863 GCFunction | GCForeground | GCBackground,
867 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
871 XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
872 ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
875 /* free up anything cached in the local Ximage structure.
878 void freeXImage(Image *image, XImageInfo *ximageinfo)
880 if (ximageinfo->index != NULL) /* if we allocated colors */
882 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
883 XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index, ximageinfo->no, 0);
884 lfree(ximageinfo->index);
887 XFreeGC(ximageinfo->disp, ximageinfo->gc);
888 lfree((byte *)ximageinfo->ximage->data);
889 ximageinfo->ximage->data= NULL;
890 XDestroyImage(ximageinfo->ximage);
891 lfree((byte *)ximageinfo);
892 /* should we free private color map to ??? */