OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltUnixImage.c
1
2 /*
3  * bltUnixImage.c --
4  *
5  *      This module implements image processing procedures for the BLT
6  *      toolkit.
7  *
8  * Copyright 1997-1998 Lucent Technologies, Inc.
9  *
10  * Permission to use, copy, modify, and distribute this software and
11  * its documentation for any purpose and without fee is hereby
12  * granted, provided that the above copyright notice appear in all
13  * copies and that both that the copyright notice and warranty
14  * disclaimer appear in supporting documentation, and that the names
15  * of Lucent Technologies any of their entities not be used in
16  * advertising or publicity pertaining to distribution of the software
17  * without specific, written prior permission.
18  *
19  * Lucent Technologies disclaims all warranties with regard to this
20  * software, including all implied warranties of merchantability and
21  * fitness.  In no event shall Lucent Technologies be liable for any
22  * special, indirect or consequential damages or any damages
23  * whatsoever resulting from loss of use, data or profits, whether in
24  * an action of contract, negligence or other tortuous action, arising
25  * out of or in connection with the use or performance of this
26  * software.
27  */
28
29 #include "bltInt.h"
30 #include "bltImage.h"
31 #include "bltHash.h"
32 #include <X11/Xutil.h>
33 #include <X11/Xproto.h>
34
35 #define CLAMP(c)        ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c)))
36
37 int redAdjust, greenAdjust, blueAdjust;
38 int redMaskShift, greenMaskShift, blueMaskShift;
39
40
41 /*
42  *----------------------------------------------------------------------
43  *
44  * ShiftCount --
45  *
46  *      Returns the position of the least significant (low) bit in
47  *      the given mask.
48  *
49  *      For TrueColor and DirectColor visuals, a pixel value is
50  *      formed by OR-ing the red, green, and blue colormap indices
51  *      into a single 32-bit word.  The visual's color masks tell
52  *      you where in the word the indices are supposed to be.  The
53  *      masks contain bits only where the index is found.  By counting
54  *      the leading zeros in the mask, we know how many bits to shift
55  *      to the individual red, green, and blue values to form a pixel.
56  *
57  * Results:
58  *      The number of the least significant bit.
59  *
60  *----------------------------------------------------------------------
61  */
62 static int
63 ShiftCount(mask)
64     register unsigned int mask;
65 {
66     register int count;
67
68     for (count = 0; count < 32; count++) {
69         if (mask & 0x01) {
70             break;
71         }
72         mask >>= 1;
73     }
74     return count;
75 }
76
77 /*
78  *----------------------------------------------------------------------
79  *
80  * CountBits --
81  *
82  *      Returns the number of bits set in the given mask.
83  *
84  *      Reference: Graphics Gems Volume 2.
85  *      
86  * Results:
87  *      The number of bits to set in the mask.
88  *
89  *
90  *----------------------------------------------------------------------
91  */
92 static int
93 CountBits(mask)
94     register unsigned long mask; /* 32  1-bit tallies */
95 {
96     /* 16  2-bit tallies */
97     mask = (mask & 0x55555555) + ((mask >> 1) & (0x55555555));  
98     /* 8  4-bit tallies */
99     mask = (mask & 0x33333333) + ((mask >> 2) & (0x33333333)); 
100     /* 4  8-bit tallies */
101     mask = (mask & 0x07070707) + ((mask >> 4) & (0x07070707));  
102     /* 2 16-bit tallies */
103     mask = (mask & 0x000F000F) + ((mask >> 8) & (0x000F000F));  
104     /* 1 32-bit tally */
105     mask = (mask & 0x0000001F) + ((mask >> 16) & (0x0000001F));  
106     return mask;
107 }
108
109 static void
110 ComputeMasks(visualPtr)
111     Visual *visualPtr;
112 {
113     int count;
114
115     redMaskShift = ShiftCount((unsigned int)visualPtr->red_mask);
116     greenMaskShift = ShiftCount((unsigned int)visualPtr->green_mask);
117     blueMaskShift = ShiftCount((unsigned int)visualPtr->blue_mask);
118
119     redAdjust = greenAdjust = blueAdjust = 0;
120     count = CountBits((unsigned long)visualPtr->red_mask);
121     if (count < 8) {
122         redAdjust = 8 - count;
123     }
124     count = CountBits((unsigned long)visualPtr->green_mask);
125     if (count < 8) {
126         greenAdjust = 8 - count;
127     }
128     count = CountBits((unsigned long)visualPtr->blue_mask);
129     if (count < 8) {
130         blueAdjust = 8 - count;
131     }
132 }
133
134 /*
135  *----------------------------------------------------------------------
136  *
137  * TrueColorPixel --
138  *
139  *      Computes a pixel index from the 3 component RGB values.
140  *
141  * Results:
142  *      The pixel index is returned.
143  *
144  *----------------------------------------------------------------------
145  */
146 static INLINE unsigned int
147 TrueColorPixel(visualPtr, pixelPtr)
148     Visual *visualPtr;
149     Pix32 *pixelPtr;
150 {
151     unsigned int red, green, blue;
152
153     /*
154      * The number of bits per color may be less than eight. For example,
155      * 15/16 bit displays (hi-color) use only 5 bits, 8-bit displays
156      * use 2 or 3 bits (don't ask me why you'd have an 8-bit TrueColor
157      * display). So shift off the least significant bits.
158      */
159     red = ((unsigned int)pixelPtr->Red >> redAdjust);
160     green = ((unsigned int)pixelPtr->Green >> greenAdjust);
161     blue = ((unsigned int)pixelPtr->Blue >> blueAdjust);
162
163     /* Shift each color into the proper location of the pixel index. */
164     red = (red << redMaskShift) & visualPtr->red_mask;
165     green = (green << greenMaskShift) & visualPtr->green_mask;
166     blue = (blue << blueMaskShift) & visualPtr->blue_mask;
167     return (red | green | blue);
168 }
169
170 /*
171  *----------------------------------------------------------------------
172  *
173  * DirectColorPixel --
174  *
175  *      Translates the 3 component RGB values into a pixel index.
176  *      This differs from TrueColor only in that it first translates
177  *      the RGB values through a color table.
178  *
179  * Results:
180  *      The pixel index is returned.
181  *
182  *----------------------------------------------------------------------
183  */
184 static INLINE unsigned int
185 DirectColorPixel(colorTabPtr, pixelPtr)
186     struct ColorTableStruct *colorTabPtr;
187     Pix32 *pixelPtr;
188 {
189     unsigned int red, green, blue;
190
191     red = colorTabPtr->red[pixelPtr->Red];
192     green = colorTabPtr->green[pixelPtr->Green];
193     blue = colorTabPtr->blue[pixelPtr->Blue];
194     return (red | green | blue);
195 }
196
197 /*
198  *----------------------------------------------------------------------
199  *
200  * PseudoColorPixel --
201  *
202  *      Translates the 3 component RGB values into a pixel index.
203  *      This differs from TrueColor only in that it first translates
204  *      the RGB values through a color table.
205  *
206  * Results:
207  *      The pixel index is returned.
208  *
209  *----------------------------------------------------------------------
210  */
211 static INLINE unsigned int
212 PseudoColorPixel(pixelPtr, lut)
213     Pix32 *pixelPtr;
214     unsigned int *lut;
215 {
216     int red, green, blue;
217     int pixel;
218
219     red = (pixelPtr->Red >> 3) + 1;
220     green = (pixelPtr->Green >> 3) + 1;
221     blue = (pixelPtr->Blue >> 3) + 1;
222     pixel = RGBIndex(red, green, blue);
223     return lut[pixel];
224 }
225
226 /*
227  *----------------------------------------------------------------------
228  *
229  * Blt_ColorImageToPixmap --
230  *
231  *      Converts a color image into a pixmap.
232  *
233  *      Right now this only handles TrueColor visuals.
234  *
235  * Results:
236  *      The new pixmap is returned.
237  *
238  *----------------------------------------------------------------------
239  */
240 Pixmap
241 Blt_ColorImageToPixmap(interp, tkwin, image, colorTablePtr)
242     Tcl_Interp *interp;
243     Tk_Window tkwin;
244     Blt_ColorImage image;
245     ColorTable *colorTablePtr;  /* Points to array of colormap indices */
246 {
247     Display *display;
248     int width, height;
249     Pixmap pixmap;
250     GC pixmapGC;
251     Visual *visualPtr;
252     XImage *imagePtr;
253     int nPixels;
254
255     visualPtr = Tk_Visual(tkwin);
256     width = Blt_ColorImageWidth(image);
257     height = Blt_ColorImageHeight(image);
258     display = Tk_Display(tkwin);
259
260     ComputeMasks(visualPtr);
261
262     *colorTablePtr = NULL;
263     imagePtr = XCreateImage(Tk_Display(tkwin), visualPtr, Tk_Depth(tkwin),
264         ZPixmap, 0, (char *)NULL, width, height, 32, 0);
265     assert(imagePtr);
266
267     nPixels = width * height;
268     imagePtr->data = Blt_Malloc(sizeof(Pix32) * nPixels);
269     assert(imagePtr->data);
270
271     imagePtr->byte_order = MSBFirst;    /* Force the byte order */
272     imagePtr->bitmap_bit_order = imagePtr->byte_order;
273     imagePtr->bytes_per_line = width * sizeof(Pix32);
274
275     switch (visualPtr->class) {
276     case TrueColor:
277         {
278             register int x, y;
279             register Pix32 *srcPtr;
280             register char *destPtr;
281             unsigned int pixel;
282             int rowOffset;
283
284             /*
285              * Compute the colormap locations directly from pixel RGB values.
286              */
287             srcPtr = Blt_ColorImageBits(image);
288             rowOffset = 0;
289             for (y = 0; y < height; y++) {
290                 destPtr = imagePtr->data + rowOffset;
291                 for (x = 0; x < width; x++, srcPtr++) {
292                     pixel = TrueColorPixel(visualPtr, srcPtr);
293                     switch (imagePtr->bits_per_pixel) {
294                     case 32:
295                         *destPtr++ = (pixel >> 24) & 0xFF;
296                         /*FALLTHRU*/
297                     case 24:
298                         *destPtr++ = (pixel >> 16) & 0xFF;
299                         /*FALLTHRU*/
300                     case 16:
301                         *destPtr++ = (pixel >> 8) & 0xFF;
302                         /*FALLTHRU*/
303                     case 8:
304                         *destPtr++ = pixel & 0xFF;
305                         /*FALLTHRU*/
306                     }
307                 }
308                 rowOffset += imagePtr->bytes_per_line;
309             }
310         }
311         break;
312
313     case DirectColor:
314         {
315             register int x, y;
316             register Pix32 *srcPtr;
317             register char *destPtr;
318             unsigned int pixel;
319             int rowOffset;
320             struct ColorTableStruct *colorTabPtr;
321
322             /* Build a color table first */
323             colorTabPtr = Blt_DirectColorTable(interp, tkwin, image);
324
325             /*
326              * Compute the colormap locations directly from pixel RGB values.
327              */
328             srcPtr = Blt_ColorImageBits(image);
329             rowOffset = 0;
330             for (y = 0; y < height; y++) {
331                 destPtr = imagePtr->data + rowOffset;
332                 for (x = 0; x < width; x++, srcPtr++) {
333                     pixel = DirectColorPixel(colorTabPtr, srcPtr);
334                     switch (imagePtr->bits_per_pixel) {
335                     case 32:
336                         *destPtr++ = (pixel >> 24) & 0xFF;
337                         /*FALLTHRU*/
338                     case 24:
339                         *destPtr++ = (pixel >> 16) & 0xFF;
340                         /*FALLTHRU*/
341                     case 16:
342                         *destPtr++ = (pixel >> 8) & 0xFF;
343                         /*FALLTHRU*/
344                     case 8:
345                         *destPtr++ = pixel & 0xFF;
346                         /*FALLTHRU*/
347                     }
348                 }
349                 rowOffset += imagePtr->bytes_per_line;
350             }
351             *colorTablePtr = colorTabPtr;
352         }
353         break;
354
355     case GrayScale:
356     case StaticGray:
357     case PseudoColor:
358     case StaticColor:
359         {
360             register int x, y;
361             register Pix32 *srcPtr;
362             register char *destPtr;
363             unsigned int pixel;
364             int rowOffset;
365             struct ColorTableStruct *colorTabPtr;
366
367             colorTabPtr = Blt_PseudoColorTable(interp, tkwin, image);
368
369             srcPtr = Blt_ColorImageBits(image);
370             rowOffset = 0;
371             for (y = 0; y < height; y++) {
372                 destPtr = imagePtr->data + rowOffset;
373                 for (x = 0; x < width; x++, srcPtr++) {
374                     pixel = PseudoColorPixel(srcPtr, colorTabPtr->lut);
375                     switch (imagePtr->bits_per_pixel) {
376                     case 32:
377                         *destPtr++ = (pixel >> 24) & 0xFF;
378                         /*FALLTHRU*/
379                     case 24:
380                         *destPtr++ = (pixel >> 16) & 0xFF;
381                         /*FALLTHRU*/
382                     case 16:
383                         *destPtr++ = (pixel >> 8) & 0xFF;
384                         /*FALLTHRU*/
385                     case 8:
386                         *destPtr++ = pixel & 0xFF;
387                         /*FALLTHRU*/
388                     }
389                 }
390                 rowOffset += imagePtr->bytes_per_line;
391             }
392             Blt_Free(colorTabPtr->lut);
393             *colorTablePtr = colorTabPtr;
394         }
395         break;
396     default:
397         return None;            /* Bad or unknown visual class. */
398     }
399     pixmapGC = Tk_GetGC(tkwin, 0L, (XGCValues *)NULL);
400     pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height,
401         Tk_Depth(tkwin));
402     XPutImage(display, pixmap, pixmapGC, imagePtr, 0, 0, 0, 0, width, height);
403     XDestroyImage(imagePtr);
404     Tk_FreeGC(display, pixmapGC);
405     return pixmap;
406 }
407
408 /* ARGSUSED */
409 static int
410 XGetImageErrorProc(clientData, errEventPtr)
411     ClientData clientData;
412     XErrorEvent *errEventPtr;
413 {
414     int *errorPtr = clientData;
415
416     *errorPtr = TCL_ERROR;
417     return 0;
418 }
419
420 /*
421  *----------------------------------------------------------------------
422  *
423  * Blt_DrawableToColorImage --
424  *
425  *      Takes a snapshot of an X drawable (pixmap or window) and
426  *      converts it to a color image.
427  *
428  *      The trick here is to efficiently convert the pixel values
429  *      (indices into the color table) into RGB color values.  In the
430  *      days of 8-bit displays, it was simpler to get RGB values for
431  *      all 256 indices into the colormap.  Instead we'll build a
432  *      hashtable of unique pixels and from that an array of pixels to
433  *      pass to XQueryColors.  For TrueColor visuals, we'll simple
434  *      compute the colors from the pixel.
435  *
436  *      [I don't know how much faster it would be to take advantage
437  *      of all the different visual types.  This pretty much depends
438  *      on the size of the image and the number of colors it uses.]
439  *
440  * Results:
441  *      Returns a color image of the drawable.  If an error occurred,
442  *      NULL is returned.
443  *
444  *----------------------------------------------------------------------
445  */
446 Blt_ColorImage
447 Blt_DrawableToColorImage(tkwin, drawable, x, y, width, height, inputGamma)
448     Tk_Window tkwin;
449     Drawable drawable;
450     register int x, y;          /* Offset of image from the drawable's
451                                  * origin. */
452     int width, height;          /* Dimension of the image.  Image must
453                                  * be completely contained by the
454                                  * drawable. */
455     double inputGamma;
456 {
457     XImage *imagePtr;
458     Blt_ColorImage image;
459     register Pix32 *destPtr;
460     unsigned long pixel;
461     int result = TCL_OK;
462     Tk_ErrorHandler errHandler;
463     Visual *visualPtr;
464     unsigned char lut[256];
465
466     errHandler = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch,
467         X_GetImage, -1, XGetImageErrorProc, &result);
468     imagePtr = XGetImage(Tk_Display(tkwin), drawable, x, y, width, height, 
469         AllPlanes, ZPixmap);
470     Tk_DeleteErrorHandler(errHandler);
471     XSync(Tk_Display(tkwin), False);
472     if (result != TCL_OK) {
473         return NULL;
474     }
475
476     {
477         register int i;
478         double value;
479         
480         for (i = 0; i < 256; i++) {
481             value = pow(i / 255.0, inputGamma) * 255.0 + 0.5;
482             lut[i] = (unsigned char)CLAMP(value);
483         }
484     }
485     /*
486      * First allocate a color image to hold the screen snapshot.
487      */
488     image = Blt_CreateColorImage(width, height);
489     visualPtr = Tk_Visual(tkwin);
490     if (visualPtr->class == TrueColor) {
491         unsigned int red, green, blue;
492         /*
493          * Directly compute the RGB color values from the pixel index
494          * rather than of going through XQueryColors.
495          */
496         ComputeMasks(visualPtr);
497         destPtr = Blt_ColorImageBits(image);
498         for (y = 0; y < height; y++) {
499             for (x = 0; x < width; x++) {
500                 pixel = XGetPixel(imagePtr, x, y);
501
502                 red = ((pixel & visualPtr->red_mask) >> redMaskShift) << redAdjust;
503                 green = ((pixel & visualPtr->green_mask) >> greenMaskShift) << greenAdjust;
504                 blue = ((pixel & visualPtr->blue_mask) >> blueMaskShift) << blueAdjust;
505
506                 /*
507                  * The number of bits per color in the pixel may be
508                  * less than eight. For example, 15/16 bit displays
509                  * (hi-color) use only 5 bits, 8-bit displays use 2 or
510                  * 3 bits (don't ask me why you'd have an 8-bit
511                  * TrueColor display). So shift back the least
512                  * significant bits.
513                  */
514                 destPtr->Red = lut[red];
515                 destPtr->Green = lut[green];
516                 destPtr->Blue = lut[blue];
517                 destPtr->Alpha = (unsigned char)-1;
518                 destPtr++;
519             }
520         }
521         XDestroyImage(imagePtr);
522     } else {
523         Blt_HashEntry *hPtr;
524         Blt_HashSearch cursor;
525         Blt_HashTable pixelTable;
526         XColor *colorPtr, *colorArr;
527         Pix32 *endPtr;
528         int nPixels;
529         int nColors;
530         int isNew;
531
532         /*
533          * Fill the array with each pixel of the image. At the same time, build
534          * up a hashtable of the pixels used.
535          */
536         nPixels = width * height;
537         Blt_InitHashTableWithPool(&pixelTable, BLT_ONE_WORD_KEYS);
538         destPtr = Blt_ColorImageBits(image);
539         for (y = 0; y < height; y++) {
540             for (x = 0; x < width; x++) {
541                 pixel = XGetPixel(imagePtr, x, y);
542                 hPtr = Blt_CreateHashEntry(&pixelTable, (char *)pixel, &isNew);
543                 if (isNew) {
544                     Blt_SetHashValue(hPtr, (char *)pixel);
545                 }
546                 destPtr->value = pixel;
547                 destPtr++;
548             }
549         }
550         XDestroyImage(imagePtr);
551
552         /* 
553          * Convert the hashtable of pixels into an array of XColors so
554          * that we can call XQueryColors with it. XQueryColors will
555          * convert the pixels into their RGB values.  
556          */
557         nColors = pixelTable.numEntries;
558         colorArr = Blt_Malloc(sizeof(XColor) * nColors);
559         assert(colorArr);
560
561         colorPtr = colorArr;
562         for (hPtr = Blt_FirstHashEntry(&pixelTable, &cursor); hPtr != NULL;
563             hPtr = Blt_NextHashEntry(&cursor)) {
564             colorPtr->pixel = (unsigned long)Blt_GetHashValue(hPtr);
565             Blt_SetHashValue(hPtr, (char *)colorPtr);
566             colorPtr++;
567         }
568         XQueryColors(Tk_Display(tkwin), Tk_Colormap(tkwin), colorArr, nColors);
569
570         /* 
571          * Go again through the array of pixels, replacing each pixel
572          * of the image with its RGB value.  
573          */
574         destPtr = Blt_ColorImageBits(image);
575         endPtr = destPtr + nPixels;
576         for (/* empty */; destPtr < endPtr; destPtr++) {
577             hPtr = Blt_FindHashEntry(&pixelTable, (char *)destPtr->value);
578             colorPtr = (XColor *)Blt_GetHashValue(hPtr);
579             destPtr->Red = lut[colorPtr->red >> 8];
580             destPtr->Green = lut[colorPtr->green >> 8];
581             destPtr->Blue = lut[colorPtr->blue >> 8];
582             destPtr->Alpha = (unsigned char)-1;
583         }
584         Blt_Free(colorArr);
585         Blt_DeleteHashTable(&pixelTable);
586     }
587     return image;
588 }
589
590
591 Pixmap
592 Blt_PhotoImageMask(tkwin, src)
593     Tk_Window tkwin;
594     Tk_PhotoImageBlock src;
595 {
596     Pixmap bitmap;
597     int arraySize, bytes_per_line;
598     int offset, count;
599     int value, bitMask;
600     register int x, y;
601     unsigned char *bits;
602     unsigned char *srcPtr;
603     unsigned char *destPtr;
604     unsigned long pixel;
605
606     bytes_per_line = (src.width + 7) / 8;
607     arraySize = src.height * bytes_per_line;
608     bits = Blt_Malloc(sizeof(unsigned char) * arraySize);
609     assert(bits);
610     destPtr = bits;
611     offset = count = 0;
612     for (y = 0; y < src.height; y++) {
613         value = 0, bitMask = 1;
614         srcPtr = src.pixelPtr + offset;
615         for (x = 0; x < src.width; /*empty*/ ) {
616             pixel = (srcPtr[src.offset[3]] != 0x00);
617             if (pixel) {
618                 value |= bitMask;
619             } else {
620                 count++;        /* Count the number of transparent pixels. */
621             }
622             bitMask <<= 1;
623             x++;
624             if (!(x & 7)) {
625                 *destPtr++ = (unsigned char)value;
626                 value = 0, bitMask = 1;
627             }
628             srcPtr += src.pixelSize;
629         }
630         if (x & 7) {
631             *destPtr++ = (unsigned char)value;
632         }
633         offset += src.pitch;
634     }
635     if (count > 0) {
636         Tk_MakeWindowExist(tkwin);
637         bitmap = XCreateBitmapFromData(Tk_Display(tkwin), Tk_WindowId(tkwin),
638             (char *)bits, (unsigned int)src.width, (unsigned int)src.height);
639     } else {
640         bitmap = None;          /* Image is opaque. */
641     }
642     Blt_Free(bits);
643     return bitmap;
644 }
645
646 Pixmap
647 Blt_ColorImageMask(tkwin, image)
648     Tk_Window tkwin;
649     Blt_ColorImage image;
650 {
651     Pixmap bitmap;
652     int arraySize, bytes_per_line;
653     int count;
654     int value, bitMask;
655     register int x, y;
656     unsigned char *bits;
657     Pix32 *srcPtr;
658     unsigned char *destPtr;
659     unsigned long pixel;
660     int width, height;
661
662     width = Blt_ColorImageWidth(image);
663     height = Blt_ColorImageHeight(image);
664     bytes_per_line = (width + 7) / 8;
665     arraySize = height * bytes_per_line;
666     bits = Blt_Malloc(sizeof(unsigned char) * arraySize);
667     assert(bits);
668     destPtr = bits;
669     count = 0;
670     srcPtr = Blt_ColorImageBits(image);
671     for (y = 0; y < height; y++) {
672         value = 0, bitMask = 1;
673         for (x = 0; x < width; /*empty*/ ) {
674             pixel = (srcPtr->Alpha != 0x00);
675             if (pixel) {
676                 value |= bitMask;
677             } else {
678                 count++;        /* Count the number of transparent pixels. */
679             }
680             bitMask <<= 1;
681             x++;
682             if (!(x & 7)) {
683                 *destPtr++ = (unsigned char)value;
684                 value = 0, bitMask = 1;
685             }
686             srcPtr++;
687         }
688         if (x & 7) {
689             *destPtr++ = (unsigned char)value;
690         }
691     }
692     if (count > 0) {
693         Tk_MakeWindowExist(tkwin);
694         bitmap = XCreateBitmapFromData(Tk_Display(tkwin), Tk_WindowId(tkwin),
695             (char *)bits, (unsigned int)width, (unsigned int)height);
696     } else {
697         bitmap = None;          /* Image is opaque. */
698     }
699     Blt_Free(bits);
700     return bitmap;
701 }
702
703 /*
704  * -----------------------------------------------------------------
705  *
706  * Blt_RotateBitmap --
707  *
708  *      Creates a new bitmap containing the rotated image of the given
709  *      bitmap.  We also need a special GC of depth 1, so that we do
710  *      not need to rotate more than one plane of the bitmap.
711  *
712  * Results:
713  *      Returns a new bitmap containing the rotated image.
714  *
715  * -----------------------------------------------------------------
716  */
717 Pixmap
718 Blt_RotateBitmap(tkwin, srcBitmap, srcWidth, srcHeight, theta,
719     destWidthPtr, destHeightPtr)
720     Tk_Window tkwin;
721     Pixmap srcBitmap;           /* Source bitmap to be rotated */
722     int srcWidth, srcHeight;    /* Width and height of the source bitmap */
723     double theta;               /* Right angle rotation to perform */
724     int *destWidthPtr, *destHeightPtr;
725 {
726     Display *display;           /* X display */
727     Window root;                /* Root window drawable */
728     Pixmap destBitmap;
729     int destWidth, destHeight;
730     XImage *src, *dest;
731     register int x, y;          /* Destination bitmap coordinates */
732     register int sx, sy;        /* Source bitmap coordinates */
733     unsigned long pixel;
734     GC bitmapGC;
735     double rotWidth, rotHeight;
736
737     display = Tk_Display(tkwin);
738     root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
739
740     /* Create a bitmap and image big enough to contain the rotated text */
741     Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight,
742         (Point2D *)NULL);
743     destWidth = ROUND(rotWidth);
744     destHeight = ROUND(rotHeight);
745     destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1);
746     bitmapGC = Blt_GetBitmapGC(tkwin);
747     XSetForeground(display, bitmapGC, 0x0);
748     XFillRectangle(display, destBitmap, bitmapGC, 0, 0, destWidth, destHeight);
749
750     src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
751     dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1,
752         ZPixmap);
753     theta = FMOD(theta, 360.0);
754     if (FMOD(theta, (double)90.0) == 0.0) {
755         int quadrant;
756
757         /* Handle right-angle rotations specifically */
758
759         quadrant = (int)(theta / 90.0);
760         switch (quadrant) {
761         case ROTATE_270:        /* 270 degrees */
762             for (y = 0; y < destHeight; y++) {
763                 sx = y;
764                 for (x = 0; x < destWidth; x++) {
765                     sy = destWidth - x - 1;
766                     pixel = XGetPixel(src, sx, sy);
767                     if (pixel) {
768                         XPutPixel(dest, x, y, pixel);
769                     }
770                 }
771             }
772             break;
773
774         case ROTATE_180:        /* 180 degrees */
775             for (y = 0; y < destHeight; y++) {
776                 sy = destHeight - y - 1;
777                 for (x = 0; x < destWidth; x++) {
778                     sx = destWidth - x - 1, 
779                     pixel = XGetPixel(src, sx, sy);
780                     if (pixel) {
781                         XPutPixel(dest, x, y, pixel);
782                     }
783                 }
784             }
785             break;
786
787         case ROTATE_90:         /* 90 degrees */
788             for (y = 0; y < destHeight; y++) {
789                 sx = destHeight - y - 1;
790                 for (x = 0; x < destWidth; x++) {
791                     sy = x;
792                     pixel = XGetPixel(src, sx, sy);
793                     if (pixel) {
794                         XPutPixel(dest, x, y, pixel);
795                     }
796                 }
797             }
798             break;
799
800         case ROTATE_0:          /* 0 degrees */
801             for (y = 0; y < destHeight; y++) {
802                 for (x = 0; x < destWidth; x++) {
803                     pixel = XGetPixel(src, x, y);
804                     if (pixel) {
805                         XPutPixel(dest, x, y, pixel);
806                     }
807                 }
808             }
809             break;
810
811         default:
812             /* The calling routine should never let this happen. */
813             break;
814         }
815     } else {
816         double radians, sinTheta, cosTheta;
817         double sox, soy;        /* Offset from the center of
818                                  * the source rectangle. */
819         double destCX, destCY;  /* Offset to the center of the destination
820                                  * rectangle. */
821         double tx, ty;          /* Translated coordinates from center */
822         double rx, ry;          /* Angle of rotation for x and y coordinates */
823
824         radians = (theta / 180.0) * M_PI;
825         sinTheta = sin(radians), cosTheta = cos(radians);
826
827         /*
828          * Coordinates of the centers of the source and destination rectangles
829          */
830         sox = srcWidth * 0.5;
831         soy = srcHeight * 0.5;
832         destCX = destWidth * 0.5;
833         destCY = destHeight * 0.5;
834
835         /* For each pixel of the destination image, transform back to the
836          * associated pixel in the source image. */
837
838         for (y = 0; y < destHeight; y++) {
839             ty = y - destCY;
840             for (x = 0; x < destWidth; x++) {
841
842                 /* Translate origin to center of destination image. */
843                 tx = x - destCX;
844
845                 /* Rotate the coordinates about the origin. */
846                 rx = (tx * cosTheta) - (ty * sinTheta);
847                 ry = (tx * sinTheta) + (ty * cosTheta);
848
849                 /* Translate back to the center of the source image. */
850                 rx += sox;
851                 ry += soy;
852
853                 sx = ROUND(rx);
854                 sy = ROUND(ry);
855
856                 /*
857                  * Verify the coordinates, since the destination image can be
858                  * bigger than the source.
859                  */
860
861                 if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) ||
862                     (sy < 0)) {
863                     continue;
864                 }
865                 pixel = XGetPixel(src, sx, sy);
866                 if (pixel) {
867                     XPutPixel(dest, x, y, pixel);
868                 }
869             }
870         }
871     }
872     /* Write the rotated image into the destination bitmap. */
873     XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, destWidth,
874         destHeight);
875
876     /* Clean up the temporary resources used. */
877     XDestroyImage(src), XDestroyImage(dest);
878     *destWidthPtr = destWidth;
879     *destHeightPtr = destHeight;
880     return destBitmap;
881 }
882
883 /*
884  * -----------------------------------------------------------------------
885  *
886  * Blt_ScaleBitmap --
887  *
888  *      Creates a new scaled bitmap from another bitmap. The new bitmap
889  *      is bounded by a specified region. Only this portion of the bitmap
890  *      is scaled from the original bitmap.
891  *
892  *      By bounding scaling to a region we can generate a new bitmap
893  *      which is no bigger than the specified viewport.
894  *
895  * Results:
896  *      The new scaled bitmap is returned.
897  *
898  * Side Effects:
899  *      A new pixmap is allocated. The caller must release this.
900  *
901  * -----------------------------------------------------------------------
902  */
903 Pixmap
904 Blt_ScaleBitmap(tkwin, srcBitmap, srcWidth, srcHeight, destWidth, destHeight)
905     Tk_Window tkwin;
906     Pixmap srcBitmap;
907     int srcWidth, srcHeight, destWidth, destHeight;
908 {
909     Display *display;
910     GC bitmapGC;
911     Pixmap destBitmap;
912     Window root;
913     XImage *src, *dest;
914     double xScale, yScale;
915     register int sx, sy;        /* Source bitmap coordinates */
916     register int x, y;          /* Destination bitmap coordinates */
917     unsigned long pixel;
918
919     /* Create a new bitmap the size of the region and clear it */
920
921     display = Tk_Display(tkwin);
922
923     root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
924     destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1);
925     bitmapGC = Blt_GetBitmapGC(tkwin);
926     XSetForeground(display, bitmapGC, 0x0);
927     XFillRectangle(display, destBitmap, bitmapGC, 0, 0, destWidth, destHeight);
928
929     src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
930     dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1, 
931                      ZPixmap);
932
933     /*
934      * Scale each pixel of destination image from results of source
935      * image. Verify the coordinates, since the destination image can
936      * be bigger than the source
937      */
938     xScale = (double)srcWidth / (double)destWidth;
939     yScale = (double)srcHeight / (double)destHeight;
940
941     /* Map each pixel in the destination image back to the source. */
942     for (y = 0; y < destHeight; y++) {
943         sy = (int)(yScale * (double)y);
944         for (x = 0; x < destWidth; x++) {
945             sx = (int)(xScale * (double)x);
946             pixel = XGetPixel(src, sx, sy);
947             if (pixel) {
948                 XPutPixel(dest, x, y, pixel);
949             }
950         }
951     }
952     /* Write the scaled image into the destination bitmap */
953
954     XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, 
955         destWidth, destHeight);
956     XDestroyImage(src), XDestroyImage(dest);
957     return destBitmap;
958 }
959
960
961 /*
962  * -----------------------------------------------------------------------
963  *
964  * Blt_RotateScaleBitmapRegion --
965  *
966  *      Creates a scaled and rotated bitmap from a given bitmap.  The
967  *      caller also provides (offsets and dimensions) the region of
968  *      interest in the destination bitmap.  This saves having to
969  *      process the entire destination bitmap is only part of it is
970  *      showing in the viewport.
971  *
972  *      This uses a simple rotation/scaling of each pixel in the 
973  *      destination image.  For each pixel, the corresponding 
974  *      pixel in the source bitmap is used.  This means that 
975  *      destination coordinates are first scaled to the size of 
976  *      the rotated source bitmap.  These coordinates are then
977  *      rotated back to their original orientation in the source.
978  *
979  * Results:
980  *      The new rotated and scaled bitmap is returned.
981  *
982  * Side Effects:
983  *      A new pixmap is allocated. The caller must release this.
984  *
985  * -----------------------------------------------------------------------
986  */
987 Pixmap
988 Blt_ScaleRotateBitmapRegion(
989     Tk_Window tkwin,
990     Pixmap srcBitmap,           /* Source bitmap. */
991     unsigned int srcWidth, 
992     unsigned int srcHeight,     /* Size of source bitmap */
993     int regionX, 
994     int regionY,                /* Offset of region in virtual
995                                  * destination bitmap. */
996     unsigned int regionWidth, 
997     unsigned int regionHeight,  /* Desire size of bitmap region. */
998     unsigned int destWidth,             
999     unsigned int destHeight,    /* Virtual size of destination bitmap. */
1000     double theta)               /* Angle to rotate bitmap.  */
1001 {
1002     Display *display;           /* X display */
1003     Window root;                /* Root window drawable */
1004     Pixmap destBitmap;
1005     XImage *src, *dest;
1006     register int x, y;          /* Destination bitmap coordinates */
1007     register int sx, sy;        /* Source bitmap coordinates */
1008     unsigned long pixel;
1009     double xScale, yScale;
1010     double rotWidth, rotHeight;
1011     GC bitmapGC;
1012
1013     display = Tk_Display(tkwin);
1014     root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
1015
1016     /* Create a bitmap and image big enough to contain the rotated text */
1017     bitmapGC = Blt_GetBitmapGC(tkwin);
1018     destBitmap = Tk_GetPixmap(display, root, regionWidth, regionHeight, 1);
1019     XSetForeground(display, bitmapGC, 0x0);
1020     XFillRectangle(display, destBitmap, bitmapGC, 0, 0, regionWidth, 
1021         regionHeight);
1022
1023     src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
1024     dest = XGetImage(display, destBitmap, 0, 0, regionWidth, regionHeight, 1,
1025         ZPixmap);
1026     theta = FMOD(theta, 360.0);
1027
1028     Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight,
1029                        (Point2D *)NULL);
1030     xScale = rotWidth / (double)destWidth;
1031     yScale = rotHeight / (double)destHeight;
1032
1033     if (FMOD(theta, (double)90.0) == 0.0) {
1034         int quadrant;
1035
1036         /* Handle right-angle rotations specifically */
1037
1038         quadrant = (int)(theta / 90.0);
1039         switch (quadrant) {
1040         case ROTATE_270:        /* 270 degrees */
1041             for (y = 0; y < regionHeight; y++) {
1042                 sx = (int)(yScale * (double)(y + regionY));
1043                 for (x = 0; x < regionWidth; x++) {
1044                     sy = (int)(xScale *(double)(destWidth - (x + regionX) - 1));
1045                     pixel = XGetPixel(src, sx, sy);
1046                     if (pixel) {
1047                         XPutPixel(dest, x, y, pixel);
1048                     }
1049                 }
1050             }
1051             break;
1052
1053         case ROTATE_180:        /* 180 degrees */
1054             for (y = 0; y < regionHeight; y++) {
1055                 sy = (int)(yScale * (double)(destHeight - (y + regionY) - 1));
1056                 for (x = 0; x < regionWidth; x++) {
1057                     sx = (int)(xScale *(double)(destWidth - (x + regionX) - 1));
1058                     pixel = XGetPixel(src, sx, sy);
1059                     if (pixel) {
1060                         XPutPixel(dest, x, y, pixel);
1061                     }
1062                 }
1063             }
1064             break;
1065
1066         case ROTATE_90:         /* 90 degrees */
1067             for (y = 0; y < regionHeight; y++) {
1068                 sx = (int)(yScale * (double)(destHeight - (y + regionY) - 1));
1069                 for (x = 0; x < regionWidth; x++) {
1070                     sy = (int)(xScale * (double)(x + regionX));
1071                     pixel = XGetPixel(src, sx, sy);
1072                     if (pixel) {
1073                         XPutPixel(dest, x, y, pixel);
1074                     }
1075                 }
1076             }
1077             break;
1078
1079         case ROTATE_0:          /* 0 degrees */
1080             for (y = 0; y < regionHeight; y++) {
1081                 sy = (int)(yScale * (double)(y + regionY));
1082                 for (x = 0; x < regionWidth; x++) {
1083                     sx = (int)(xScale * (double)(x + regionX));
1084                     pixel = XGetPixel(src, sx, sy);
1085                     if (pixel) {
1086                         XPutPixel(dest, x, y, pixel);
1087                     }
1088                 }
1089             }
1090             break;
1091
1092         default:
1093             /* The calling routine should never let this happen. */
1094             break;
1095         }
1096     } else {
1097         double radians, sinTheta, cosTheta;
1098         double sox, soy;        /* Offset from the center of the
1099                                  * source rectangle. */
1100         double rox, roy;        /* Offset to the center of the
1101                                  * rotated rectangle. */
1102         double tx, ty;          /* Translated coordinates from center */
1103         double rx, ry;          /* Angle of rotation for x and y coordinates */
1104
1105         radians = (theta / 180.0) * M_PI;
1106         sinTheta = sin(radians), cosTheta = cos(radians);
1107
1108         /*
1109          * Coordinates of the centers of the source and destination rectangles
1110          */
1111         sox = srcWidth * 0.5;
1112         soy = srcHeight * 0.5;
1113         rox = rotWidth * 0.5;
1114         roy = rotHeight * 0.5;
1115
1116         /* For each pixel of the destination image, transform back to the
1117          * associated pixel in the source image. */
1118
1119         for (y = 0; y < regionHeight; y++) {
1120             ty = (yScale * (double)(y + regionY)) - roy;
1121             for (x = 0; x < regionWidth; x++) {
1122
1123                 /* Translate origin to center of destination image. */
1124                 tx = (xScale * (double)(x + regionX)) - rox;
1125
1126                 /* Rotate the coordinates about the origin. */
1127                 rx = (tx * cosTheta) - (ty * sinTheta);
1128                 ry = (tx * sinTheta) + (ty * cosTheta);
1129
1130                 /* Translate back to the center of the source image. */
1131                 rx += sox;
1132                 ry += soy;
1133
1134                 sx = ROUND(rx);
1135                 sy = ROUND(ry);
1136
1137                 /*
1138                  * Verify the coordinates, since the destination image can be
1139                  * bigger than the source.
1140                  */
1141
1142                 if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) ||
1143                     (sy < 0)) {
1144                     continue;
1145                 }
1146                 pixel = XGetPixel(src, sx, sy);
1147                 if (pixel) {
1148                     XPutPixel(dest, x, y, pixel);
1149                 }
1150             }
1151         }
1152     }
1153     /* Write the rotated image into the destination bitmap. */
1154     XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, regionWidth,
1155       regionHeight);
1156
1157     /* Clean up the temporary resources used. */
1158     XDestroyImage(src), XDestroyImage(dest);
1159     return destBitmap;
1160
1161 }
1162
1163 #if HAVE_JPEGLIB_H
1164
1165 #undef HAVE_STDLIB_H
1166 #undef EXTERN
1167 #ifdef WIN32
1168 #define XMD_H   1
1169 #endif
1170 #include "jpeglib.h"
1171 #include <setjmp.h>
1172
1173 typedef struct {
1174     struct jpeg_error_mgr pub;  /* "public" fields */
1175     jmp_buf jmpBuf;
1176     Tcl_DString dString;
1177 } ReaderHandler;
1178
1179 static void ErrorProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1180 static void MessageProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1181
1182 /*
1183  * Here's the routine that will replace the standard error_exit method:
1184  */
1185
1186 static void
1187 ErrorProc(jpgPtr)
1188     j_common_ptr jpgPtr;
1189 {
1190     ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err;
1191
1192     (*handlerPtr->pub.output_message) (jpgPtr);
1193     longjmp(handlerPtr->jmpBuf, 1);
1194 }
1195
1196 static void
1197 MessageProc(jpgPtr)
1198     j_common_ptr jpgPtr;
1199 {
1200     ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err;
1201     char buffer[JMSG_LENGTH_MAX];
1202
1203     /* Create the message and append it into the dynamic string. */
1204     (*handlerPtr->pub.format_message) (jpgPtr, buffer);
1205     Tcl_DStringAppend(&(handlerPtr->dString), " ", -1);
1206     Tcl_DStringAppend(&(handlerPtr->dString), buffer, -1);
1207 }
1208
1209 /*
1210  *----------------------------------------------------------------------
1211  *
1212  * Blt_JPEGToColorImage --
1213  *
1214  *      Reads a JPEG file and converts it into a color image.
1215  *
1216  * Results:
1217  *      The color image is returned.  If an error occured, such
1218  *      as the designated file could not be opened, NULL is returned.
1219  *
1220  *----------------------------------------------------------------------
1221  */
1222 Blt_ColorImage
1223 Blt_JPEGToColorImage(interp, fileName)
1224     Tcl_Interp *interp;
1225     char *fileName;
1226 {
1227     struct jpeg_decompress_struct jpg;
1228     Blt_ColorImage image;
1229     unsigned int imageWidth, imageHeight;
1230     register Pix32 *destPtr;
1231     ReaderHandler handler;
1232     FILE *f;
1233     JSAMPLE **readBuffer;
1234     int row_stride;
1235     register int i;
1236     register JSAMPLE *bufPtr;
1237
1238     f = fopen(fileName, "rb");
1239     if (f == NULL) {
1240         Tcl_AppendResult(interp, "can't open \"", fileName, "\":",
1241             Tcl_PosixError(interp), (char *)NULL);
1242         return NULL;
1243     }
1244     image = NULL;
1245
1246     /* Step 1: allocate and initialize JPEG decompression object */
1247
1248     /* We set up the normal JPEG error routines, then override error_exit. */
1249     jpg.dct_method = JDCT_IFAST;
1250     jpg.err = jpeg_std_error(&handler.pub);
1251     handler.pub.error_exit = ErrorProc;
1252     handler.pub.output_message = MessageProc;
1253
1254     Tcl_DStringInit(&handler.dString);
1255     Tcl_DStringAppend(&handler.dString, "error reading \"", -1);
1256     Tcl_DStringAppend(&handler.dString, fileName, -1);
1257     Tcl_DStringAppend(&handler.dString, "\": ", -1);
1258
1259     if (setjmp(handler.jmpBuf)) {
1260         jpeg_destroy_decompress(&jpg);
1261         fclose(f);
1262         Tcl_DStringResult(interp, &(handler.dString));
1263         return NULL;
1264     }
1265     jpeg_create_decompress(&jpg);
1266     jpeg_stdio_src(&jpg, f);
1267
1268     jpeg_read_header(&jpg, TRUE);       /* Step 3: read file parameters */
1269
1270     jpeg_start_decompress(&jpg);        /* Step 5: Start decompressor */
1271     imageWidth = jpg.output_width;
1272     imageHeight = jpg.output_height;
1273     if ((imageWidth < 1) || (imageHeight < 1)) {
1274         Tcl_AppendResult(interp, "bad JPEG image size", (char *)NULL);
1275         fclose(f);
1276         return NULL;
1277     }
1278     /* JSAMPLEs per row in output buffer */
1279     row_stride = imageWidth * jpg.output_components;
1280
1281     /* Make a one-row-high sample array that will go away when done
1282      * with image */
1283     readBuffer = (*jpg.mem->alloc_sarray) ((j_common_ptr)&jpg, JPOOL_IMAGE, 
1284         row_stride, 1);
1285     image = Blt_CreateColorImage(imageWidth, imageHeight);
1286     destPtr = Blt_ColorImageBits(image);
1287
1288     if (jpg.output_components == 1) {
1289         while (jpg.output_scanline < imageHeight) {
1290             jpeg_read_scanlines(&jpg, readBuffer, 1);
1291             bufPtr = readBuffer[0];
1292             for (i = 0; i < (int)imageWidth; i++) {
1293                 destPtr->Red = destPtr->Green = destPtr->Blue = *bufPtr++;
1294                 destPtr->Alpha = (unsigned char)-1;
1295                 destPtr++;
1296             }
1297         }
1298     } else {
1299         while (jpg.output_scanline < imageHeight) {
1300             jpeg_read_scanlines(&jpg, readBuffer, 1);
1301             bufPtr = readBuffer[0];
1302             for (i = 0; i < (int)imageWidth; i++) {
1303                 destPtr->Red = *bufPtr++;
1304                 destPtr->Green = *bufPtr++;
1305                 destPtr->Blue = *bufPtr++;
1306                 destPtr->Alpha = (unsigned char)-1;
1307                 destPtr++;
1308             }
1309         }
1310     }
1311     jpeg_finish_decompress(&jpg);       /* We can ignore the return value
1312                                          * since suspension is not
1313                                          * possible with the stdio data
1314                                          * source.  */
1315     jpeg_destroy_decompress(&jpg);
1316
1317
1318     /*  
1319      * After finish_decompress, we can close the input file.  Here we
1320      * postpone it until after no more JPEG errors are possible, so as
1321      * to simplify the setjmp error logic above.  (Actually, I don't
1322      * think that jpeg_destroy can do an error exit, but why assume
1323      * anything...)  
1324      */
1325     fclose(f);
1326
1327     /* 
1328      * At this point you may want to check to see whether any corrupt-data
1329      * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
1330      */
1331     if (handler.pub.num_warnings > 0) {
1332         Tcl_SetErrorCode(interp, "IMAGE", "JPEG", 
1333                  Tcl_DStringValue(&(handler.dString)), (char *)NULL);
1334     } else {
1335         Tcl_SetErrorCode(interp, "NONE", (char *)NULL);
1336     }
1337     /*
1338      * We're ready to call the Tk_Photo routines. They'll take the RGB
1339      * array we've processed to build the Tk image of the JPEG.
1340      */
1341     Tcl_DStringFree(&(handler.dString));
1342     return image;
1343 }
1344
1345 #endif /* HAVE_JPEGLIB_H */