OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tk8.6.12 / win / tkWinImage.c
1 /*
2  * tkWinImage.c --
3  *
4  *      This file contains routines for manipulation full-color images.
5  *
6  * Copyright (c) 1995 Sun Microsystems, Inc.
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  */
11
12 #include "tkWinInt.h"
13
14 static int              DestroyImage(XImage* data);
15 static unsigned long    ImageGetPixel(XImage *image, int x, int y);
16 static int              PutPixel(XImage *image, int x, int y,
17                             unsigned long pixel);
18 \f
19 /*
20  *----------------------------------------------------------------------
21  *
22  * DestroyImage --
23  *
24  *      This is a trivial wrapper around ckfree to make it possible to pass
25  *      ckfree as a pointer.
26  *
27  * Results:
28  *      None.
29  *
30  * Side effects:
31  *      Deallocates the image.
32  *
33  *----------------------------------------------------------------------
34  */
35
36 static int
37 DestroyImage(
38     XImage *imagePtr)           /* Image to free. */
39 {
40     if (imagePtr) {
41         if (imagePtr->data) {
42             ckfree(imagePtr->data);
43         }
44         ckfree(imagePtr);
45     }
46     return 0;
47 }
48 \f
49 /*
50  *----------------------------------------------------------------------
51  *
52  * ImageGetPixel --
53  *
54  *      Get a single pixel from an image.
55  *
56  * Results:
57  *      Returns the 32 bit pixel value.
58  *
59  * Side effects:
60  *      None.
61  *
62  *----------------------------------------------------------------------
63  */
64
65 static unsigned long
66 ImageGetPixel(
67     XImage *image,
68     int x, int y)
69 {
70     unsigned long pixel = 0;
71     unsigned char *srcPtr = (unsigned char *) &(image->data[(y * image->bytes_per_line)
72             + ((x * image->bits_per_pixel) / NBBY)]);
73
74     switch (image->bits_per_pixel) {
75     case 32:
76     case 24:
77         pixel = RGB(srcPtr[2], srcPtr[1], srcPtr[0]);
78         break;
79     case 16:
80         pixel = RGB(((((WORD*)srcPtr)[0]) >> 7) & 0xf8,
81                 ((((WORD*)srcPtr)[0]) >> 2) & 0xf8,
82                 ((((WORD*)srcPtr)[0]) << 3) & 0xf8);
83         break;
84     case 8:
85         pixel = srcPtr[0];
86         break;
87     case 4:
88         pixel = ((x%2) ? (*srcPtr) : ((*srcPtr) >> 4)) & 0x0f;
89         break;
90     case 1:
91         pixel = ((*srcPtr) & (0x80 >> (x%8))) ? 1 : 0;
92         break;
93     }
94     return pixel;
95 }
96 \f
97 /*
98  *----------------------------------------------------------------------
99  *
100  * PutPixel --
101  *
102  *      Set a single pixel in an image.
103  *
104  * Results:
105  *      None.
106  *
107  * Side effects:
108  *      None.
109  *
110  *----------------------------------------------------------------------
111  */
112
113 static int
114 PutPixel(
115     XImage *image,
116     int x, int y,
117     unsigned long pixel)
118 {
119     unsigned char *destPtr = (unsigned char *) &(image->data[(y * image->bytes_per_line)
120             + ((x * image->bits_per_pixel) / NBBY)]);
121
122     switch  (image->bits_per_pixel) {
123     case 32:
124         /*
125          * Pixel is DWORD: 0x00BBGGRR
126          */
127
128         destPtr[3] = 0;
129         /* FALLTHRU */
130     case 24:
131         /*
132          * Pixel is triplet: 0xBBGGRR.
133          */
134
135         destPtr[0] = (unsigned char) GetBValue(pixel);
136         destPtr[1] = (unsigned char) GetGValue(pixel);
137         destPtr[2] = (unsigned char) GetRValue(pixel);
138         break;
139     case 16:
140         /*
141          * Pixel is WORD: 5-5-5 (R-G-B)
142          */
143
144         (*(WORD*)destPtr) = ((GetRValue(pixel) & 0xf8) << 7)
145                 | ((GetGValue(pixel) & 0xf8) <<2)
146                 | ((GetBValue(pixel) & 0xf8) >> 3);
147         break;
148     case 8:
149         /*
150          * Pixel is 8-bit index into color table.
151          */
152
153         (*destPtr) = (unsigned char) pixel;
154         break;
155     case 4:
156         /*
157          * Pixel is 4-bit index in MSBFirst order.
158          */
159
160         if (x%2) {
161             (*destPtr) = (unsigned char) (((*destPtr) & 0xf0)
162                     | (pixel & 0x0f));
163         } else {
164             (*destPtr) = (unsigned char) (((*destPtr) & 0x0f)
165                     | ((pixel << 4) & 0xf0));
166         }
167         break;
168     case 1: {
169         /*
170          * Pixel is bit in MSBFirst order.
171          */
172
173         int mask = (0x80 >> (x%8));
174
175         if (pixel) {
176             (*destPtr) |= mask;
177         } else {
178             (*destPtr) &= ~mask;
179         }
180         break;
181     }
182     }
183     return 0;
184 }
185 \f
186 /*
187  *----------------------------------------------------------------------
188  *
189  * XCreateImage --
190  *
191  *      Allocates storage for a new XImage.
192  *
193  * Results:
194  *      Returns a newly allocated XImage.
195  *
196  * Side effects:
197  *      None.
198  *
199  *----------------------------------------------------------------------
200  */
201
202 XImage *
203 XCreateImage(
204     Display *display,
205     Visual *visual,
206     unsigned int depth,
207     int format,
208     int offset,
209     char *data,
210     unsigned int width,
211     unsigned int height,
212     int bitmap_pad,
213     int bytes_per_line)
214 {
215     XImage* imagePtr = ckalloc(sizeof(XImage));
216     imagePtr->width = width;
217     imagePtr->height = height;
218     imagePtr->xoffset = offset;
219     imagePtr->format = format;
220     imagePtr->data = data;
221     imagePtr->byte_order = LSBFirst;
222     imagePtr->bitmap_unit = 8;
223     imagePtr->bitmap_bit_order = LSBFirst;
224     imagePtr->bitmap_pad = bitmap_pad;
225     imagePtr->bits_per_pixel = depth;
226     imagePtr->depth = depth;
227
228     /*
229      * Under Windows, bitmap_pad must be on an LONG data-type boundary.
230      */
231
232 #define LONGBITS    (sizeof(LONG) * 8)
233
234     bitmap_pad = (bitmap_pad + LONGBITS - 1) / LONGBITS * LONGBITS;
235
236     /*
237      * Round to the nearest bitmap_pad boundary.
238      */
239
240     if (bytes_per_line) {
241         imagePtr->bytes_per_line = bytes_per_line;
242     } else {
243         imagePtr->bytes_per_line = (((depth * width)
244                 + (bitmap_pad - 1)) >> 3) & ~((bitmap_pad >> 3) - 1);
245     }
246
247     imagePtr->red_mask = 0;
248     imagePtr->green_mask = 0;
249     imagePtr->blue_mask = 0;
250
251     imagePtr->f.put_pixel = PutPixel;
252     imagePtr->f.get_pixel = ImageGetPixel;
253     imagePtr->f.destroy_image = DestroyImage;
254     imagePtr->f.create_image = NULL;
255     imagePtr->f.sub_image = NULL;
256     imagePtr->f.add_pixel = NULL;
257
258     return imagePtr;
259 }
260 \f
261 /*
262  *----------------------------------------------------------------------
263  *
264  * XGetImageZPixmap --
265  *
266  *      This function copies data from a pixmap or window into an XImage. This
267  *      handles the ZPixmap case only.
268  *
269  * Results:
270  *      Returns a newly allocated image containing the data from the given
271  *      rectangle of the given drawable.
272  *
273  * Side effects:
274  *      None.
275  *
276  * This procedure is adapted from the XGetImage implementation in TkNT. That
277  * code is Copyright (c) 1994 Software Research Associates, Inc.
278  *
279  *----------------------------------------------------------------------
280  */
281
282 static XImage *
283 XGetImageZPixmap(
284     Display *display,
285     Drawable d,
286     int x, int y,
287     unsigned int width, unsigned int height,
288     unsigned long plane_mask,
289     int format)
290 {
291     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
292     XImage *ret_image;
293     HDC hdc, hdcMem;
294     HBITMAP hbmp, hbmpPrev;
295     BITMAPINFO *bmInfo = NULL;
296     HPALETTE hPal, hPalPrev1 = 0, hPalPrev2 = 0;
297     int size;
298     unsigned int n;
299     unsigned int depth;
300     unsigned char *data;
301     TkWinDCState state;
302     BOOL ret;
303
304     if (format != ZPixmap) {
305         TkpDisplayWarning("Only ZPixmap types are implemented",
306                 "XGetImageZPixmap Failure");
307         return NULL;
308     }
309
310     hdc = TkWinGetDrawableDC(display, d, &state);
311
312     /*
313      * Need to do a Blt operation to copy into a new bitmap.
314      */
315
316     hbmp = CreateCompatibleBitmap(hdc, (int) width, (int) height);
317     hdcMem = CreateCompatibleDC(hdc);
318     hbmpPrev = SelectObject(hdcMem, hbmp);
319     hPal = state.palette;
320     if (hPal) {
321         hPalPrev1 = SelectPalette(hdcMem, hPal, FALSE);
322         n = RealizePalette(hdcMem);
323         if (n > 0) {
324             UpdateColors(hdcMem);
325         }
326         hPalPrev2 = SelectPalette(hdc, hPal, FALSE);
327         n = RealizePalette(hdc);
328         if (n > 0) {
329             UpdateColors(hdc);
330         }
331     }
332
333     ret = BitBlt(hdcMem, 0, 0, (int) width, (int) height, hdc, x, y, SRCCOPY);
334     if (hPal) {
335         SelectPalette(hdc, hPalPrev2, FALSE);
336     }
337     SelectObject(hdcMem, hbmpPrev);
338     TkWinReleaseDrawableDC(d, hdc, &state);
339     if (ret == FALSE) {
340         ret_image = NULL;
341         goto cleanup;
342     }
343     if (twdPtr->type == TWD_WINDOW) {
344         depth = Tk_Depth((Tk_Window) twdPtr->window.winPtr);
345     } else {
346         depth = twdPtr->bitmap.depth;
347     }
348
349     size = sizeof(BITMAPINFO);
350     if (depth <= 8) {
351         size += sizeof(unsigned short) << depth;
352     }
353     bmInfo = ckalloc(size);
354
355     bmInfo->bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
356     bmInfo->bmiHeader.biWidth           = width;
357     bmInfo->bmiHeader.biHeight          = -(int) height;
358     bmInfo->bmiHeader.biPlanes          = 1;
359     bmInfo->bmiHeader.biBitCount        = depth;
360     bmInfo->bmiHeader.biCompression     = BI_RGB;
361     bmInfo->bmiHeader.biSizeImage       = 0;
362     bmInfo->bmiHeader.biXPelsPerMeter   = 0;
363     bmInfo->bmiHeader.biYPelsPerMeter   = 0;
364     bmInfo->bmiHeader.biClrUsed         = 0;
365     bmInfo->bmiHeader.biClrImportant    = 0;
366
367     if (depth == 1) {
368         unsigned char *p, *pend;
369
370         GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_PAL_COLORS);
371         data = ckalloc(bmInfo->bmiHeader.biSizeImage);
372         if (!data) {
373             /* printf("Failed to allocate data area for XImage.\n"); */
374             ret_image = NULL;
375             goto cleanup;
376         }
377         ret_image = XCreateImage(display, NULL, depth, ZPixmap, 0, (char *) data,
378                 width, height, 32, (int) ((width + 31) >> 3) & ~1);
379         if (ret_image == NULL) {
380             ckfree(data);
381             goto cleanup;
382         }
383
384         /*
385          * Get the BITMAP info into the Image.
386          */
387
388         if (GetDIBits(hdcMem, hbmp, 0, height, data, bmInfo,
389                 DIB_PAL_COLORS) == 0) {
390             ckfree(ret_image->data);
391             ckfree(ret_image);
392             ret_image = NULL;
393             goto cleanup;
394         }
395         p = data;
396         pend = data + bmInfo->bmiHeader.biSizeImage;
397         while (p < pend) {
398             *p = ~*p;
399             p++;
400         }
401     } else if (depth == 8) {
402         unsigned short *palette;
403         unsigned int i;
404         unsigned char *p;
405
406         GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_PAL_COLORS);
407         data = ckalloc(bmInfo->bmiHeader.biSizeImage);
408         if (!data) {
409             /* printf("Failed to allocate data area for XImage.\n"); */
410             ret_image = NULL;
411             goto cleanup;
412         }
413         ret_image = XCreateImage(display, NULL, 8, ZPixmap, 0, (char *) data,
414                 width, height, 8, (int) width);
415         if (ret_image == NULL) {
416             ckfree(data);
417             goto cleanup;
418         }
419
420         /*
421          * Get the BITMAP info into the Image.
422          */
423
424         if (GetDIBits(hdcMem, hbmp, 0, height, data, bmInfo,
425                 DIB_PAL_COLORS) == 0) {
426             ckfree(ret_image->data);
427             ckfree(ret_image);
428             ret_image = NULL;
429             goto cleanup;
430         }
431         p = data;
432         palette = (unsigned short *) bmInfo->bmiColors;
433         for (i = 0; i < bmInfo->bmiHeader.biSizeImage; i++, p++) {
434             *p = (unsigned char) palette[*p];
435         }
436     } else if (depth == 16) {
437         GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_RGB_COLORS);
438         data = ckalloc(bmInfo->bmiHeader.biSizeImage);
439         if (!data) {
440             /* printf("Failed to allocate data area for XImage.\n"); */
441             ret_image = NULL;
442             goto cleanup;
443         }
444         ret_image = XCreateImage(display, NULL, 16, ZPixmap, 0, (char *) data,
445                 width, height, 16, 0 /* will be calc'ed from bitmap_pad */);
446         if (ret_image == NULL) {
447             ckfree(data);
448             goto cleanup;
449         }
450
451         /*
452          * Get the BITMAP info directly into the Image.
453          */
454
455         if (GetDIBits(hdcMem, hbmp, 0, height, ret_image->data, bmInfo,
456                 DIB_RGB_COLORS) == 0) {
457             ckfree(ret_image->data);
458             ckfree(ret_image);
459             ret_image = NULL;
460             goto cleanup;
461         }
462     } else {
463         GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_RGB_COLORS);
464         data = ckalloc(width * height * 4);
465         if (!data) {
466             /* printf("Failed to allocate data area for XImage.\n"); */
467             ret_image = NULL;
468             goto cleanup;
469         }
470         ret_image = XCreateImage(display, NULL, 32, ZPixmap, 0, (char *) data,
471                 width, height, 0, (int) width * 4);
472         if (ret_image == NULL) {
473             ckfree(data);
474             goto cleanup;
475         }
476
477         if (depth <= 24) {
478             /*
479              * This used to handle 16 and 24 bpp, but now just handles 24. It
480              * can likely be optimized for that. -- hobbs
481              */
482
483             unsigned char *smallBitData, *smallBitBase, *bigBitData;
484             unsigned int byte_width, h, w;
485
486             byte_width = ((width * 3 + 3) & ~(unsigned)3);
487             smallBitBase = ckalloc(byte_width * height);
488             if (!smallBitBase) {
489                 ckfree(ret_image->data);
490                 ckfree(ret_image);
491                 ret_image = NULL;
492                 goto cleanup;
493             }
494             smallBitData = smallBitBase;
495
496             /*
497              * Get the BITMAP info into the Image.
498              */
499
500             if (GetDIBits(hdcMem, hbmp, 0, height, smallBitData, bmInfo,
501                     DIB_RGB_COLORS) == 0) {
502                 ckfree(ret_image->data);
503                 ckfree(ret_image);
504                 ckfree(smallBitBase);
505                 ret_image = NULL;
506                 goto cleanup;
507             }
508
509             /*
510              * Copy the 24 Bit Pixmap to a 32-Bit one.
511              */
512
513             for (h = 0; h < height; h++) {
514                 bigBitData   = (unsigned char *) ret_image->data + h * ret_image->bytes_per_line;
515                 smallBitData = smallBitBase + h * byte_width;
516
517                 for (w = 0; w < width; w++) {
518                     *bigBitData++ = ((*smallBitData++));
519                     *bigBitData++ = ((*smallBitData++));
520                     *bigBitData++ = ((*smallBitData++));
521                     *bigBitData++ = 0;
522                 }
523             }
524
525             /*
526              * Free the Device contexts, and the Bitmap.
527              */
528
529             ckfree(smallBitBase);
530         } else {
531             /*
532              * Get the BITMAP info directly into the Image.
533              */
534
535             if (GetDIBits(hdcMem, hbmp, 0, height, ret_image->data, bmInfo,
536                     DIB_RGB_COLORS) == 0) {
537                 ckfree(ret_image->data);
538                 ckfree(ret_image);
539                 ret_image = NULL;
540                 goto cleanup;
541             }
542         }
543     }
544
545   cleanup:
546     if (bmInfo) {
547         ckfree(bmInfo);
548     }
549     if (hPal) {
550         SelectPalette(hdcMem, hPalPrev1, FALSE);
551     }
552     DeleteDC(hdcMem);
553     DeleteObject(hbmp);
554
555     return ret_image;
556 }
557 \f
558 /*
559  *----------------------------------------------------------------------
560  *
561  * XGetImage --
562  *
563  *      This function copies data from a pixmap or window into an XImage.
564  *
565  * Results:
566  *      Returns a newly allocated image containing the data from the given
567  *      rectangle of the given drawable.
568  *
569  * Side effects:
570  *      None.
571  *
572  *----------------------------------------------------------------------
573  */
574
575 XImage *
576 XGetImage(
577     Display* display,
578     Drawable d,
579     int x, int y,
580     unsigned int width, unsigned int height,
581     unsigned long plane_mask,
582     int format)
583 {
584     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
585     XImage *imagePtr;
586     HDC dc;
587
588     display->request++;
589
590     if (twdPtr == NULL) {
591         /*
592          * Avoid unmapped windows or bad drawables
593          */
594
595         return NULL;
596     }
597
598     if (twdPtr->type != TWD_BITMAP) {
599         /*
600          * This handles TWD_WINDOW or TWD_WINDC, always creating a 32bit
601          * image. If the window being copied isn't visible (unmapped or
602          * obscured), we quietly stop copying (no user error). The user will
603          * see black where the widget should be. This branch is likely
604          * followed in favor of XGetImageZPixmap as postscript printed widgets
605          * require RGB data.
606          */
607
608         TkWinDCState state;
609         unsigned int xx, yy, size;
610         COLORREF pixel;
611
612         dc = TkWinGetDrawableDC(display, d, &state);
613
614         imagePtr = XCreateImage(display, NULL, 32, format, 0, NULL,
615                 width, height, 32, 0);
616         size = imagePtr->bytes_per_line * imagePtr->height;
617         imagePtr->data = ckalloc(size);
618         ZeroMemory(imagePtr->data, size);
619
620         for (yy = 0; yy < height; yy++) {
621             for (xx = 0; xx < width; xx++) {
622                 pixel = GetPixel(dc, x+(int)xx, y+(int)yy);
623                 if (pixel == CLR_INVALID) {
624                     break;
625                 }
626                 PutPixel(imagePtr, (int) xx, (int) yy, pixel);
627             }
628         }
629
630         TkWinReleaseDrawableDC(d, dc, &state);
631     } else if (format == ZPixmap) {
632         /*
633          * This actually handles most TWD_WINDOW requests, but it varies from
634          * the above in that it really does a screen capture of an area, which
635          * is consistent with the Unix behavior, but does not appear to handle
636          * all bit depths correctly. -- hobbs
637          */
638
639         imagePtr = XGetImageZPixmap(display, d, x, y,
640                 width, height, plane_mask, format);
641     } else {
642         const char *errMsg = NULL;
643         char infoBuf[sizeof(BITMAPINFO) + sizeof(RGBQUAD)];
644         BITMAPINFO *infoPtr = (BITMAPINFO*)infoBuf;
645
646         if (twdPtr->bitmap.handle == NULL) {
647             errMsg = "XGetImage: not implemented for empty bitmap handles";
648         } else if (format != XYPixmap) {
649             errMsg = "XGetImage: not implemented for format != XYPixmap";
650         } else if (plane_mask != 1) {
651             errMsg = "XGetImage: not implemented for plane_mask != 1";
652         }
653         if (errMsg != NULL) {
654             /*
655              * Do a soft warning for the unsupported XGetImage types.
656              */
657
658             TkpDisplayWarning(errMsg, "XGetImage Failure");
659             return NULL;
660         }
661
662         imagePtr = XCreateImage(display, NULL, 1, XYBitmap, 0, NULL,
663                 width, height, 32, 0);
664         imagePtr->data = ckalloc(imagePtr->bytes_per_line * imagePtr->height);
665
666         dc = GetDC(NULL);
667
668         GetDIBits(dc, twdPtr->bitmap.handle, 0, height, NULL,
669                 infoPtr, DIB_RGB_COLORS);
670
671         infoPtr->bmiHeader.biSize               = sizeof(BITMAPINFOHEADER);
672         infoPtr->bmiHeader.biWidth              = width;
673         infoPtr->bmiHeader.biHeight             = -(LONG)height;
674         infoPtr->bmiHeader.biPlanes             = 1;
675         infoPtr->bmiHeader.biBitCount           = 1;
676         infoPtr->bmiHeader.biCompression        = BI_RGB;
677         infoPtr->bmiHeader.biSizeImage          = 0;
678         infoPtr->bmiHeader.biXPelsPerMeter      = 0;
679         infoPtr->bmiHeader.biYPelsPerMeter      = 0;
680         infoPtr->bmiHeader.biClrUsed            = 0;
681         infoPtr->bmiHeader.biClrImportant       = 0;
682
683         GetDIBits(dc, twdPtr->bitmap.handle, 0, height, imagePtr->data,
684                 infoPtr, DIB_RGB_COLORS);
685         ReleaseDC(NULL, dc);
686     }
687
688     return imagePtr;
689 }
690 \f
691 /*
692  * Local Variables:
693  * mode: c
694  * c-basic-offset: 4
695  * fill-column: 78
696  * End:
697  */