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
ShiftCount(mask)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
CountBits(mask)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
ComputeMasks(visualPtr)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
TrueColorPixel(visualPtr,pixelPtr)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
DirectColorPixel(colorTabPtr,pixelPtr)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
PseudoColorPixel(pixelPtr,lut)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
Blt_ColorImageToPixmap(interp,tkwin,image,colorTablePtr)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
XGetImageErrorProc(clientData,errEventPtr)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
Blt_DrawableToColorImage(tkwin,drawable,x,y,width,height,inputGamma)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
Blt_PhotoImageMask(tkwin,src)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
Blt_ColorImageMask(tkwin,image)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
Blt_RotateBitmap(tkwin,srcBitmap,srcWidth,srcHeight,theta,destWidthPtr,destHeightPtr)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
Blt_ScaleBitmap(tkwin,srcBitmap,srcWidth,srcHeight,destWidth,destHeight)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
Blt_ScaleRotateBitmapRegion(Tk_Window tkwin,Pixmap srcBitmap,unsigned int srcWidth,unsigned int srcHeight,int regionX,int regionY,unsigned int regionWidth,unsigned int regionHeight,unsigned int destWidth,unsigned int destHeight,double theta)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
ErrorProc(jpgPtr)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
MessageProc(jpgPtr)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
Blt_JPEGToColorImage(interp,fileName)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 */
1346