5 * This module implements image processing procedures for the BLT
8 * Copyright 1997-1998 Lucent Technologies, Inc.
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.
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
32 #include <X11/Xutil.h>
33 #include <X11/Xproto.h>
35 #define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c)))
37 int redAdjust, greenAdjust, blueAdjust;
38 int redMaskShift, greenMaskShift, blueMaskShift;
42 *----------------------------------------------------------------------
46 * Returns the position of the least significant (low) bit in
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.
58 * The number of the least significant bit.
60 *----------------------------------------------------------------------
64 register unsigned int mask;
68 for (count = 0; count < 32; count++) {
78 *----------------------------------------------------------------------
82 * Returns the number of bits set in the given mask.
84 * Reference: Graphics Gems Volume 2.
87 * The number of bits to set in the mask.
90 *----------------------------------------------------------------------
94 register unsigned long mask; /* 32 1-bit tallies */
96 /* 16 2-bit tallies */
97 mask = (mask & 0x55555555) + ((mask >> 1) & (0x55555555));
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));
105 mask = (mask & 0x0000001F) + ((mask >> 16) & (0x0000001F));
110 ComputeMasks(visualPtr)
115 redMaskShift = ShiftCount((unsigned int)visualPtr->red_mask);
116 greenMaskShift = ShiftCount((unsigned int)visualPtr->green_mask);
117 blueMaskShift = ShiftCount((unsigned int)visualPtr->blue_mask);
119 redAdjust = greenAdjust = blueAdjust = 0;
120 count = CountBits((unsigned long)visualPtr->red_mask);
122 redAdjust = 8 - count;
124 count = CountBits((unsigned long)visualPtr->green_mask);
126 greenAdjust = 8 - count;
128 count = CountBits((unsigned long)visualPtr->blue_mask);
130 blueAdjust = 8 - count;
135 *----------------------------------------------------------------------
139 * Computes a pixel index from the 3 component RGB values.
142 * The pixel index is returned.
144 *----------------------------------------------------------------------
146 static INLINE unsigned int
147 TrueColorPixel(visualPtr, pixelPtr)
151 unsigned int red, green, blue;
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.
159 red = ((unsigned int)pixelPtr->Red >> redAdjust);
160 green = ((unsigned int)pixelPtr->Green >> greenAdjust);
161 blue = ((unsigned int)pixelPtr->Blue >> blueAdjust);
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);
171 *----------------------------------------------------------------------
173 * DirectColorPixel --
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.
180 * The pixel index is returned.
182 *----------------------------------------------------------------------
184 static INLINE unsigned int
185 DirectColorPixel(colorTabPtr, pixelPtr)
186 struct ColorTableStruct *colorTabPtr;
189 unsigned int red, green, blue;
191 red = colorTabPtr->red[pixelPtr->Red];
192 green = colorTabPtr->green[pixelPtr->Green];
193 blue = colorTabPtr->blue[pixelPtr->Blue];
194 return (red | green | blue);
198 *----------------------------------------------------------------------
200 * PseudoColorPixel --
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.
207 * The pixel index is returned.
209 *----------------------------------------------------------------------
211 static INLINE unsigned int
212 PseudoColorPixel(pixelPtr, lut)
216 int red, green, blue;
219 red = (pixelPtr->Red >> 3) + 1;
220 green = (pixelPtr->Green >> 3) + 1;
221 blue = (pixelPtr->Blue >> 3) + 1;
222 pixel = RGBIndex(red, green, blue);
227 *----------------------------------------------------------------------
229 * Blt_ColorImageToPixmap --
231 * Converts a color image into a pixmap.
233 * Right now this only handles TrueColor visuals.
236 * The new pixmap is returned.
238 *----------------------------------------------------------------------
241 Blt_ColorImageToPixmap(interp, tkwin, image, colorTablePtr)
244 Blt_ColorImage image;
245 ColorTable *colorTablePtr; /* Points to array of colormap indices */
255 visualPtr = Tk_Visual(tkwin);
256 width = Blt_ColorImageWidth(image);
257 height = Blt_ColorImageHeight(image);
258 display = Tk_Display(tkwin);
260 ComputeMasks(visualPtr);
262 *colorTablePtr = NULL;
263 imagePtr = XCreateImage(Tk_Display(tkwin), visualPtr, Tk_Depth(tkwin),
264 ZPixmap, 0, (char *)NULL, width, height, 32, 0);
267 nPixels = width * height;
268 imagePtr->data = Blt_Malloc(sizeof(Pix32) * nPixels);
269 assert(imagePtr->data);
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);
275 switch (visualPtr->class) {
279 register Pix32 *srcPtr;
280 register char *destPtr;
285 * Compute the colormap locations directly from pixel RGB values.
287 srcPtr = Blt_ColorImageBits(image);
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) {
295 *destPtr++ = (pixel >> 24) & 0xFF;
298 *destPtr++ = (pixel >> 16) & 0xFF;
301 *destPtr++ = (pixel >> 8) & 0xFF;
304 *destPtr++ = pixel & 0xFF;
308 rowOffset += imagePtr->bytes_per_line;
316 register Pix32 *srcPtr;
317 register char *destPtr;
320 struct ColorTableStruct *colorTabPtr;
322 /* Build a color table first */
323 colorTabPtr = Blt_DirectColorTable(interp, tkwin, image);
326 * Compute the colormap locations directly from pixel RGB values.
328 srcPtr = Blt_ColorImageBits(image);
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) {
336 *destPtr++ = (pixel >> 24) & 0xFF;
339 *destPtr++ = (pixel >> 16) & 0xFF;
342 *destPtr++ = (pixel >> 8) & 0xFF;
345 *destPtr++ = pixel & 0xFF;
349 rowOffset += imagePtr->bytes_per_line;
351 *colorTablePtr = colorTabPtr;
361 register Pix32 *srcPtr;
362 register char *destPtr;
365 struct ColorTableStruct *colorTabPtr;
367 colorTabPtr = Blt_PseudoColorTable(interp, tkwin, image);
369 srcPtr = Blt_ColorImageBits(image);
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) {
377 *destPtr++ = (pixel >> 24) & 0xFF;
380 *destPtr++ = (pixel >> 16) & 0xFF;
383 *destPtr++ = (pixel >> 8) & 0xFF;
386 *destPtr++ = pixel & 0xFF;
390 rowOffset += imagePtr->bytes_per_line;
392 Blt_Free(colorTabPtr->lut);
393 *colorTablePtr = colorTabPtr;
397 return None; /* Bad or unknown visual class. */
399 pixmapGC = Tk_GetGC(tkwin, 0L, (XGCValues *)NULL);
400 pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height,
402 XPutImage(display, pixmap, pixmapGC, imagePtr, 0, 0, 0, 0, width, height);
403 XDestroyImage(imagePtr);
404 Tk_FreeGC(display, pixmapGC);
410 XGetImageErrorProc(clientData, errEventPtr)
411 ClientData clientData;
412 XErrorEvent *errEventPtr;
414 int *errorPtr = clientData;
416 *errorPtr = TCL_ERROR;
421 *----------------------------------------------------------------------
423 * Blt_DrawableToColorImage --
425 * Takes a snapshot of an X drawable (pixmap or window) and
426 * converts it to a color image.
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.
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.]
441 * Returns a color image of the drawable. If an error occurred,
444 *----------------------------------------------------------------------
447 Blt_DrawableToColorImage(tkwin, drawable, x, y, width, height, inputGamma)
450 register int x, y; /* Offset of image from the drawable's
452 int width, height; /* Dimension of the image. Image must
453 * be completely contained by the
458 Blt_ColorImage image;
459 register Pix32 *destPtr;
462 Tk_ErrorHandler errHandler;
464 unsigned char lut[256];
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,
470 Tk_DeleteErrorHandler(errHandler);
471 XSync(Tk_Display(tkwin), False);
472 if (result != TCL_OK) {
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);
486 * First allocate a color image to hold the screen snapshot.
488 image = Blt_CreateColorImage(width, height);
489 visualPtr = Tk_Visual(tkwin);
490 if (visualPtr->class == TrueColor) {
491 unsigned int red, green, blue;
493 * Directly compute the RGB color values from the pixel index
494 * rather than of going through XQueryColors.
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);
502 red = ((pixel & visualPtr->red_mask) >> redMaskShift) << redAdjust;
503 green = ((pixel & visualPtr->green_mask) >> greenMaskShift) << greenAdjust;
504 blue = ((pixel & visualPtr->blue_mask) >> blueMaskShift) << blueAdjust;
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
514 destPtr->Red = lut[red];
515 destPtr->Green = lut[green];
516 destPtr->Blue = lut[blue];
517 destPtr->Alpha = (unsigned char)-1;
521 XDestroyImage(imagePtr);
524 Blt_HashSearch cursor;
525 Blt_HashTable pixelTable;
526 XColor *colorPtr, *colorArr;
533 * Fill the array with each pixel of the image. At the same time, build
534 * up a hashtable of the pixels used.
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);
544 Blt_SetHashValue(hPtr, (char *)pixel);
546 destPtr->value = pixel;
550 XDestroyImage(imagePtr);
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.
557 nColors = pixelTable.numEntries;
558 colorArr = Blt_Malloc(sizeof(XColor) * nColors);
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);
568 XQueryColors(Tk_Display(tkwin), Tk_Colormap(tkwin), colorArr, nColors);
571 * Go again through the array of pixels, replacing each pixel
572 * of the image with its RGB value.
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;
585 Blt_DeleteHashTable(&pixelTable);
592 Blt_PhotoImageMask(tkwin, src)
594 Tk_PhotoImageBlock src;
597 int arraySize, bytes_per_line;
602 unsigned char *srcPtr;
603 unsigned char *destPtr;
606 bytes_per_line = (src.width + 7) / 8;
607 arraySize = src.height * bytes_per_line;
608 bits = Blt_Malloc(sizeof(unsigned char) * arraySize);
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);
620 count++; /* Count the number of transparent pixels. */
625 *destPtr++ = (unsigned char)value;
626 value = 0, bitMask = 1;
628 srcPtr += src.pixelSize;
631 *destPtr++ = (unsigned char)value;
636 Tk_MakeWindowExist(tkwin);
637 bitmap = XCreateBitmapFromData(Tk_Display(tkwin), Tk_WindowId(tkwin),
638 (char *)bits, (unsigned int)src.width, (unsigned int)src.height);
640 bitmap = None; /* Image is opaque. */
647 Blt_ColorImageMask(tkwin, image)
649 Blt_ColorImage image;
652 int arraySize, bytes_per_line;
658 unsigned char *destPtr;
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);
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);
678 count++; /* Count the number of transparent pixels. */
683 *destPtr++ = (unsigned char)value;
684 value = 0, bitMask = 1;
689 *destPtr++ = (unsigned char)value;
693 Tk_MakeWindowExist(tkwin);
694 bitmap = XCreateBitmapFromData(Tk_Display(tkwin), Tk_WindowId(tkwin),
695 (char *)bits, (unsigned int)width, (unsigned int)height);
697 bitmap = None; /* Image is opaque. */
704 * -----------------------------------------------------------------
706 * Blt_RotateBitmap --
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.
713 * Returns a new bitmap containing the rotated image.
715 * -----------------------------------------------------------------
718 Blt_RotateBitmap(tkwin, srcBitmap, srcWidth, srcHeight, theta,
719 destWidthPtr, destHeightPtr)
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;
726 Display *display; /* X display */
727 Window root; /* Root window drawable */
729 int destWidth, destHeight;
731 register int x, y; /* Destination bitmap coordinates */
732 register int sx, sy; /* Source bitmap coordinates */
735 double rotWidth, rotHeight;
737 display = Tk_Display(tkwin);
738 root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
740 /* Create a bitmap and image big enough to contain the rotated text */
741 Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight,
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);
750 src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
751 dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1,
753 theta = FMOD(theta, 360.0);
754 if (FMOD(theta, (double)90.0) == 0.0) {
757 /* Handle right-angle rotations specifically */
759 quadrant = (int)(theta / 90.0);
761 case ROTATE_270: /* 270 degrees */
762 for (y = 0; y < destHeight; y++) {
764 for (x = 0; x < destWidth; x++) {
765 sy = destWidth - x - 1;
766 pixel = XGetPixel(src, sx, sy);
768 XPutPixel(dest, x, y, pixel);
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);
781 XPutPixel(dest, x, y, pixel);
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++) {
792 pixel = XGetPixel(src, sx, sy);
794 XPutPixel(dest, x, y, pixel);
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);
805 XPutPixel(dest, x, y, pixel);
812 /* The calling routine should never let this happen. */
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
821 double tx, ty; /* Translated coordinates from center */
822 double rx, ry; /* Angle of rotation for x and y coordinates */
824 radians = (theta / 180.0) * M_PI;
825 sinTheta = sin(radians), cosTheta = cos(radians);
828 * Coordinates of the centers of the source and destination rectangles
830 sox = srcWidth * 0.5;
831 soy = srcHeight * 0.5;
832 destCX = destWidth * 0.5;
833 destCY = destHeight * 0.5;
835 /* For each pixel of the destination image, transform back to the
836 * associated pixel in the source image. */
838 for (y = 0; y < destHeight; y++) {
840 for (x = 0; x < destWidth; x++) {
842 /* Translate origin to center of destination image. */
845 /* Rotate the coordinates about the origin. */
846 rx = (tx * cosTheta) - (ty * sinTheta);
847 ry = (tx * sinTheta) + (ty * cosTheta);
849 /* Translate back to the center of the source image. */
857 * Verify the coordinates, since the destination image can be
858 * bigger than the source.
861 if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) ||
865 pixel = XGetPixel(src, sx, sy);
867 XPutPixel(dest, x, y, pixel);
872 /* Write the rotated image into the destination bitmap. */
873 XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, destWidth,
876 /* Clean up the temporary resources used. */
877 XDestroyImage(src), XDestroyImage(dest);
878 *destWidthPtr = destWidth;
879 *destHeightPtr = destHeight;
884 * -----------------------------------------------------------------------
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.
892 * By bounding scaling to a region we can generate a new bitmap
893 * which is no bigger than the specified viewport.
896 * The new scaled bitmap is returned.
899 * A new pixmap is allocated. The caller must release this.
901 * -----------------------------------------------------------------------
904 Blt_ScaleBitmap(tkwin, srcBitmap, srcWidth, srcHeight, destWidth, destHeight)
907 int srcWidth, srcHeight, destWidth, destHeight;
914 double xScale, yScale;
915 register int sx, sy; /* Source bitmap coordinates */
916 register int x, y; /* Destination bitmap coordinates */
919 /* Create a new bitmap the size of the region and clear it */
921 display = Tk_Display(tkwin);
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);
929 src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
930 dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1,
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
938 xScale = (double)srcWidth / (double)destWidth;
939 yScale = (double)srcHeight / (double)destHeight;
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);
948 XPutPixel(dest, x, y, pixel);
952 /* Write the scaled image into the destination bitmap */
954 XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0,
955 destWidth, destHeight);
956 XDestroyImage(src), XDestroyImage(dest);
962 * -----------------------------------------------------------------------
964 * Blt_RotateScaleBitmapRegion --
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.
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.
980 * The new rotated and scaled bitmap is returned.
983 * A new pixmap is allocated. The caller must release this.
985 * -----------------------------------------------------------------------
988 Blt_ScaleRotateBitmapRegion(
990 Pixmap srcBitmap, /* Source bitmap. */
991 unsigned int srcWidth,
992 unsigned int srcHeight, /* Size of source bitmap */
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. */
1002 Display *display; /* X display */
1003 Window root; /* Root window drawable */
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;
1013 display = Tk_Display(tkwin);
1014 root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
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,
1023 src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
1024 dest = XGetImage(display, destBitmap, 0, 0, regionWidth, regionHeight, 1,
1026 theta = FMOD(theta, 360.0);
1028 Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight,
1030 xScale = rotWidth / (double)destWidth;
1031 yScale = rotHeight / (double)destHeight;
1033 if (FMOD(theta, (double)90.0) == 0.0) {
1036 /* Handle right-angle rotations specifically */
1038 quadrant = (int)(theta / 90.0);
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);
1047 XPutPixel(dest, x, y, pixel);
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);
1060 XPutPixel(dest, x, y, pixel);
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);
1073 XPutPixel(dest, x, y, pixel);
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);
1086 XPutPixel(dest, x, y, pixel);
1093 /* The calling routine should never let this happen. */
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 */
1105 radians = (theta / 180.0) * M_PI;
1106 sinTheta = sin(radians), cosTheta = cos(radians);
1109 * Coordinates of the centers of the source and destination rectangles
1111 sox = srcWidth * 0.5;
1112 soy = srcHeight * 0.5;
1113 rox = rotWidth * 0.5;
1114 roy = rotHeight * 0.5;
1116 /* For each pixel of the destination image, transform back to the
1117 * associated pixel in the source image. */
1119 for (y = 0; y < regionHeight; y++) {
1120 ty = (yScale * (double)(y + regionY)) - roy;
1121 for (x = 0; x < regionWidth; x++) {
1123 /* Translate origin to center of destination image. */
1124 tx = (xScale * (double)(x + regionX)) - rox;
1126 /* Rotate the coordinates about the origin. */
1127 rx = (tx * cosTheta) - (ty * sinTheta);
1128 ry = (tx * sinTheta) + (ty * cosTheta);
1130 /* Translate back to the center of the source image. */
1138 * Verify the coordinates, since the destination image can be
1139 * bigger than the source.
1142 if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) ||
1146 pixel = XGetPixel(src, sx, sy);
1148 XPutPixel(dest, x, y, pixel);
1153 /* Write the rotated image into the destination bitmap. */
1154 XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, regionWidth,
1157 /* Clean up the temporary resources used. */
1158 XDestroyImage(src), XDestroyImage(dest);
1165 #undef HAVE_STDLIB_H
1170 #include "jpeglib.h"
1174 struct jpeg_error_mgr pub; /* "public" fields */
1176 Tcl_DString dString;
1179 static void ErrorProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1180 static void MessageProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1183 * Here's the routine that will replace the standard error_exit method:
1188 j_common_ptr jpgPtr;
1190 ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err;
1192 (*handlerPtr->pub.output_message) (jpgPtr);
1193 longjmp(handlerPtr->jmpBuf, 1);
1198 j_common_ptr jpgPtr;
1200 ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err;
1201 char buffer[JMSG_LENGTH_MAX];
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);
1210 *----------------------------------------------------------------------
1212 * Blt_JPEGToColorImage --
1214 * Reads a JPEG file and converts it into a color image.
1217 * The color image is returned. If an error occured, such
1218 * as the designated file could not be opened, NULL is returned.
1220 *----------------------------------------------------------------------
1223 Blt_JPEGToColorImage(interp, fileName)
1227 struct jpeg_decompress_struct jpg;
1228 Blt_ColorImage image;
1229 unsigned int imageWidth, imageHeight;
1230 register Pix32 *destPtr;
1231 ReaderHandler handler;
1233 JSAMPLE **readBuffer;
1236 register JSAMPLE *bufPtr;
1238 f = fopen(fileName, "rb");
1240 Tcl_AppendResult(interp, "can't open \"", fileName, "\":",
1241 Tcl_PosixError(interp), (char *)NULL);
1246 /* Step 1: allocate and initialize JPEG decompression object */
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;
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);
1259 if (setjmp(handler.jmpBuf)) {
1260 jpeg_destroy_decompress(&jpg);
1262 Tcl_DStringResult(interp, &(handler.dString));
1265 jpeg_create_decompress(&jpg);
1266 jpeg_stdio_src(&jpg, f);
1268 jpeg_read_header(&jpg, TRUE); /* Step 3: read file parameters */
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);
1278 /* JSAMPLEs per row in output buffer */
1279 row_stride = imageWidth * jpg.output_components;
1281 /* Make a one-row-high sample array that will go away when done
1283 readBuffer = (*jpg.mem->alloc_sarray) ((j_common_ptr)&jpg, JPOOL_IMAGE,
1285 image = Blt_CreateColorImage(imageWidth, imageHeight);
1286 destPtr = Blt_ColorImageBits(image);
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;
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;
1311 jpeg_finish_decompress(&jpg); /* We can ignore the return value
1312 * since suspension is not
1313 * possible with the stdio data
1315 jpeg_destroy_decompress(&jpg);
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
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).
1331 if (handler.pub.num_warnings > 0) {
1332 Tcl_SetErrorCode(interp, "IMAGE", "JPEG",
1333 Tcl_DStringValue(&(handler.dString)), (char *)NULL);
1335 Tcl_SetErrorCode(interp, "NONE", (char *)NULL);
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.
1341 Tcl_DStringFree(&(handler.dString));
1345 #endif /* HAVE_JPEGLIB_H */