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,
430 Pixel *redvalue, *greenvalue, *bluevalue;
431 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
434 static XColor xcolor_used[NOFLASH_COLORS];
437 XImageInfo *ximageinfo;
440 static Colormap our_default_cmap = 0;
441 static Pixel *our_default_index;
442 static int free_cmap_entries, max_cmap_entries;
446 static unsigned long pixel_used[NOFLASH_COLORS];
449 if (!our_default_cmap)
452 our_default_cmap = DefaultColormap(disp, scrn);
455 our_default_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
457 our_default_index = (Pixel *)lmalloc(sizeof(Pixel) * NOFLASH_COLORS);
459 for (a=0; a<NOFLASH_COLORS; a++) /* count entries we got */
460 if (!XAllocColorCells(disp, our_default_cmap, FALSE, NULL, 0,
461 our_default_index + a, 1))
464 free_cmap_entries = max_cmap_entries = a;
466 printf("We've got %d colormap entries.\n", free_cmap_entries);
468 for(a=0; a<max_cmap_entries; a++) /* copy default colors */
470 xcolor.pixel = *(our_default_index + a);
471 XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor);
472 XStoreColor(disp, our_default_cmap, &xcolor);
474 pixel_used[xcolor.pixel] = 0;
475 xcolor_used[xcolor.pixel] = xcolor;
479 xcolor.flags= DoRed | DoGreen | DoBlue;
480 redvalue= greenvalue= bluevalue= NULL;
482 ximageinfo= (XImageInfo *)lmalloc(sizeof(XImageInfo));
483 ximageinfo->disp= disp;
484 ximageinfo->scrn= scrn;
485 ximageinfo->depth= 0;
486 ximageinfo->drawable= None;
487 ximageinfo->index= NULL;
488 ximageinfo->rootimage= FALSE; /* assume not */
489 ximageinfo->foreground= ximageinfo->background= 0;
490 ximageinfo->gc= NULL;
491 ximageinfo->ximage= NULL;
493 /* do color allocation
496 switch (visual->class)
502 unsigned int redcolors, greencolors, bluecolors;
503 unsigned int redstep, greenstep, bluestep;
504 unsigned int redbottom, greenbottom, bluebottom;
505 unsigned int redtop, greentop, bluetop;
507 redvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
508 greenvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
509 bluevalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
512 if (visual == DefaultVisual(disp, scrn))
513 ximageinfo->cmap= DefaultColormap(disp, scrn);
515 ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
518 ximageinfo->cmap = our_default_cmap;
521 retry_direct: /* tag we hit if a DirectColor allocation fails on
522 * default colormap */
524 /* calculate number of distinct colors in each band
527 redcolors= greencolors= bluecolors= 1;
528 for (pixval= 1; pixval; pixval <<= 1)
530 if (pixval & visual->red_mask)
532 if (pixval & visual->green_mask)
534 if (pixval & visual->blue_mask)
541 if ((redcolors > visual->map_entries) ||
542 (greencolors > visual->map_entries) ||
543 (bluecolors > visual->map_entries))
545 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
548 redstep = 256 / redcolors;
549 greenstep = 256 / greencolors;
550 bluestep = 256 / bluecolors;
551 redbottom = greenbottom = bluebottom = 0;
552 redtop = greentop = bluetop = 0;
553 for (a= 0; a < visual->map_entries; a++)
556 redtop= redbottom + redstep;
557 if (greenbottom < 256)
558 greentop= greenbottom + greenstep;
559 if (bluebottom < 256)
560 bluetop= bluebottom + bluestep;
562 xcolor.red= (redtop - 1) << 8;
563 xcolor.green= (greentop - 1) << 8;
564 xcolor.blue= (bluetop - 1) << 8;
565 if (! XAllocColor(disp, ximageinfo->cmap, &xcolor))
567 /* if an allocation fails for a DirectColor default visual then
568 * we should create a private colormap and try again.
571 if ((visual->class == DirectColor) &&
572 (visual == DefaultVisual(disp, scrn)))
575 ximageinfo->cmap = XCreateColormap(disp, RootWindow(disp, scrn),
578 our_default_cmap = XCopyColormapAndFree(disp, our_default_cmap);
579 ximageinfo->cmap = our_default_cmap;
584 /* something completely unexpected happened
587 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
588 lfree((byte *)redvalue);
589 lfree((byte *)greenvalue);
590 lfree((byte *)bluevalue);
591 lfree((byte *)ximageinfo);
595 /* fill in pixel values for each band at this intensity
598 while ((redbottom < 256) && (redbottom < redtop))
599 redvalue[redbottom++]= xcolor.pixel & visual->red_mask;
600 while ((greenbottom < 256) && (greenbottom < greentop))
601 greenvalue[greenbottom++]= xcolor.pixel & visual->green_mask;
602 while ((bluebottom < 256) && (bluebottom < bluetop))
603 bluevalue[bluebottom++]= xcolor.pixel & visual->blue_mask;
610 ximageinfo->index= (Pixel *)lmalloc(sizeof(Pixel) * (image->rgb.used+NOFLASH_COLORS));
613 /* get the colormap to use.
616 ximageinfo->cmap = our_default_cmap;
618 /* allocate colors shareable (if we can)
621 for (a = 0; a < image->rgb.used; a++)
626 xcolor2.flags = DoRed | DoGreen | DoBlue;
628 xcolor.red= *(image->rgb.red + a);
629 xcolor.green= *(image->rgb.green + a);
630 xcolor.blue= *(image->rgb.blue + a);
632 /* look if this color already exists in our colormap */
635 for (i=max_cmap_entries-1; i>=free_cmap_entries; i--)
638 for (i=max_cmap_entries-1; i>=0; i--)
646 xcolor2.pixel = *(our_default_index + i);
649 XQueryColor(disp, ximageinfo->cmap, &xcolor2);
651 xcolor2 = xcolor_used[xcolor2.pixel];
654 if ((xcolor.red >> 8) == (xcolor2.red >> 8) &&
655 (xcolor.green >> 8) == (xcolor2.green >> 8) &&
656 (xcolor.blue >> 8) == (xcolor2.blue >> 8))
662 if (0 && use_cmap_entry < free_cmap_entries) /* not found in colormap */
666 else if (0 && use_cmap_entry < free_cmap_entries) /* not found in colormap */
669 else if (use_cmap_entry < 0) /* not found in colormap */
671 /* look for an existing 'unused' color near the one we want */
673 for (i=free_cmap_entries-1; i>=0; i--)
680 xcolor2.pixel = *(our_default_index + i);
683 XQueryColor(disp, ximageinfo->cmap, &xcolor2);
685 xcolor2 = xcolor_used[xcolor2.pixel];
689 if ((xcolor.red >> closeness) == (xcolor2.red >> closeness) &&
690 (xcolor.green >> closeness) == (xcolor2.green >> closeness) &&
691 (xcolor.blue >> closeness) == (xcolor2.blue >> closeness))
697 if (use_cmap_entry < 0) /* no 'near' color found */
699 /* look for the next free color */
701 while (pixel_used[--free_cmap_entries])
703 use_cmap_entry = free_cmap_entries;
707 if (free_cmap_entries < 0)
709 printf("imageToXImage: too many global colors!\n");
715 printf("--> eating color %d\n", use_cmap_entry);
720 xcolor.pixel = use_cmap_entry;
722 xcolor_used[xcolor.pixel] = xcolor;
724 *(ximageinfo->index + a) = xcolor.pixel;
726 XStoreColor(disp, ximageinfo->cmap, &xcolor);
728 pixel_used[use_cmap_entry] = 1;
731 ximageinfo->no = a; /* number of pixels allocated in default visual */
734 printf("still %d free colormap entries\n", free_cmap_entries);
740 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
747 /* create an XImage and related colormap based on the image type
752 printf(" Building XImage...");
762 /* we copy the data to be more consistent
765 linelen = ((image->width + 7) / 8);
766 data= lmalloc(linelen * image->height);
768 memcpy((char *)data, (char *)image->data, linelen * image->height);
770 gcv.function= GXcopy;
771 ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
772 0, (char *)data, image->width, image->height,
775 /* use this if you want to use the bitmap as a mask */
776 ximageinfo->depth = image->depth;
778 if(visual->class == DirectColor || visual->class == TrueColor)
781 dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
782 dpixlen= (dbits + 7) / 8;
783 pixval= redvalue[image->rgb.red[0] >> 8] |
784 greenvalue[image->rgb.green[0] >> 8] |
785 bluevalue[image->rgb.blue[0] >> 8];
786 ximageinfo->background = pixval;
787 pixval= redvalue[image->rgb.red[1] >> 8] |
788 greenvalue[image->rgb.green[1] >> 8] |
789 bluevalue[image->rgb.blue[1] >> 8];
790 ximageinfo->foreground = pixval;
792 else /* Not Direct or True Color */
794 ximageinfo->foreground = BlackPixel(disp,scrn);
795 ximageinfo->background = WhitePixel(disp,scrn);
797 ximageinfo->ximage->bitmap_bit_order= MSBFirst;
798 ximageinfo->ximage->byte_order= MSBFirst;
805 /* modify image data to match visual and colormap
808 byte *data, *destptr, *srcptr;
810 dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); /* bits per pixel */
811 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
813 ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
814 NULL, image->width, image->height,
815 8, image->width * dpixlen);
817 data = (byte *)lmalloc(image->width * image->height * dpixlen);
818 ximageinfo->depth = ddepth;
819 ximageinfo->ximage->data = (char *)data;
820 ximageinfo->ximage->byte_order = MSBFirst;
821 srcptr = image->data;
824 switch (visual->class)
831 for (y=0; y<image->height; y++)
833 for (x=0; x<image->width; x++)
835 pixval = memToVal(srcptr, 1);
836 pixval = redvalue[image->rgb.red[pixval] >> 8] |
837 greenvalue[image->rgb.green[pixval] >> 8] |
838 bluevalue[image->rgb.blue[pixval] >> 8];
839 valToMem(pixval, destptr, dpixlen);
849 if (dpixlen == 1) /* most common */
851 for (y=0; y<image->height; y++)
853 for (x=0; x<image->width; x++)
855 *destptr = ximageinfo->index[c + *srcptr];
861 else /* less common */
863 for (y=0; y<image->height; y++)
865 for (x=0; x<image->width; x++)
867 register unsigned long temp;
868 temp = memToVal(srcptr, 1);
869 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
887 lfree((byte *)redvalue);
888 lfree((byte *)greenvalue);
889 lfree((byte *)bluevalue);
892 if (image != orig_image)
897 /* Given an XImage and a drawable, move a rectangle from the Ximage
901 void sendXImage(XImageInfo *ximageinfo,
902 int src_x, int src_y, int dst_x, int dst_y,
903 unsigned int w, unsigned int h)
907 /* build and cache the GC
912 gcv.function = GXcopy;
913 if (ximageinfo->ximage->depth == 1)
915 gcv.foreground = ximageinfo->foreground;
916 gcv.background = ximageinfo->background;
917 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
918 GCFunction | GCForeground | GCBackground,
922 ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
926 XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
927 ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
930 /* free up anything cached in the local Ximage structure.
933 void freeXImage(Image *image, XImageInfo *ximageinfo)
935 if (ximageinfo->index != NULL) /* if we allocated colors */
937 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
938 XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index, ximageinfo->no, 0);
939 lfree(ximageinfo->index);
942 XFreeGC(ximageinfo->disp, ximageinfo->gc);
943 lfree((byte *)ximageinfo->ximage->data);
944 ximageinfo->ximage->data= NULL;
945 XDestroyImage(ximageinfo->ximage);
946 lfree((byte *)ximageinfo);
947 /* should we free private color map to ??? */