source: trunk/kitgen/8.x/blt/unix/bltUnixImage.c

Last change on this file was 175, checked in by demin, 12 years ago

initial commit

File size: 37.6 KB
Line 
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
37int redAdjust, greenAdjust, blueAdjust;
38int 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 */
62static int
63ShiftCount(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 */
92static int
93CountBits(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
109static void
110ComputeMasks(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 */
146static INLINE unsigned int
147TrueColorPixel(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 */
184static INLINE unsigned int
185DirectColorPixel(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 */
211static INLINE unsigned int
212PseudoColorPixel(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 */
240Pixmap
241Blt_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 */
409static int
410XGetImageErrorProc(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 */
446Blt_ColorImage
447Blt_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
591Pixmap
592Blt_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
646Pixmap
647Blt_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 */
717Pixmap
718Blt_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 */
903Pixmap
904Blt_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 */
987Pixmap
988Blt_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
1173typedef struct {
1174 struct jpeg_error_mgr pub; /* "public" fields */
1175 jmp_buf jmpBuf;
1176 Tcl_DString dString;
1177} ReaderHandler;
1178
1179static void ErrorProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1180static 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
1186static void
1187ErrorProc(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
1196static void
1197MessageProc(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 */
1222Blt_ColorImage
1223Blt_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 */
Note: See TracBrowser for help on using the repository browser.