diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-18 17:31:55 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-18 17:31:55 (GMT) |
commit | 39e34335fb6eb6eaf2b7ee51ccf172006dd46fbb (patch) | |
tree | 8e5374666c7f0b3017176ec9d6e6b6eae0dcabac /tk8.6/win/tkWinImage.c | |
parent | 066971b1e6e77991d9161bb0216a63ba94ea04f9 (diff) | |
parent | 6b095f3c8521ca7215e6ff5dcbada52b197ef7d0 (diff) | |
download | blt-39e34335fb6eb6eaf2b7ee51ccf172006dd46fbb.zip blt-39e34335fb6eb6eaf2b7ee51ccf172006dd46fbb.tar.gz blt-39e34335fb6eb6eaf2b7ee51ccf172006dd46fbb.tar.bz2 |
Merge commit '6b095f3c8521ca7215e6ff5dcbada52b197ef7d0' as 'tk8.6'
Diffstat (limited to 'tk8.6/win/tkWinImage.c')
-rw-r--r-- | tk8.6/win/tkWinImage.c | 696 |
1 files changed, 696 insertions, 0 deletions
diff --git a/tk8.6/win/tkWinImage.c b/tk8.6/win/tkWinImage.c new file mode 100644 index 0000000..d61b84a --- /dev/null +++ b/tk8.6/win/tkWinImage.c @@ -0,0 +1,696 @@ +/* + * tkWinImage.c -- + * + * This file contains routines for manipulation full-color images. + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tkWinInt.h" + +static int DestroyImage(XImage* data); +static unsigned long ImageGetPixel(XImage *image, int x, int y); +static int PutPixel(XImage *image, int x, int y, + unsigned long pixel); + +/* + *---------------------------------------------------------------------- + * + * DestroyImage -- + * + * This is a trivial wrapper around ckfree to make it possible to pass + * ckfree as a pointer. + * + * Results: + * None. + * + * Side effects: + * Deallocates the image. + * + *---------------------------------------------------------------------- + */ + +static int +DestroyImage( + XImage *imagePtr) /* Image to free. */ +{ + if (imagePtr) { + if (imagePtr->data) { + ckfree(imagePtr->data); + } + ckfree(imagePtr); + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * ImageGetPixel -- + * + * Get a single pixel from an image. + * + * Results: + * Returns the 32 bit pixel value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned long +ImageGetPixel( + XImage *image, + int x, int y) +{ + unsigned long pixel = 0; + unsigned char *srcPtr = (unsigned char *) &(image->data[(y * image->bytes_per_line) + + ((x * image->bits_per_pixel) / NBBY)]); + + switch (image->bits_per_pixel) { + case 32: + case 24: + pixel = RGB(srcPtr[2], srcPtr[1], srcPtr[0]); + break; + case 16: + pixel = RGB(((((WORD*)srcPtr)[0]) >> 7) & 0xf8, + ((((WORD*)srcPtr)[0]) >> 2) & 0xf8, + ((((WORD*)srcPtr)[0]) << 3) & 0xf8); + break; + case 8: + pixel = srcPtr[0]; + break; + case 4: + pixel = ((x%2) ? (*srcPtr) : ((*srcPtr) >> 4)) & 0x0f; + break; + case 1: + pixel = ((*srcPtr) & (0x80 >> (x%8))) ? 1 : 0; + break; + } + return pixel; +} + +/* + *---------------------------------------------------------------------- + * + * PutPixel -- + * + * Set a single pixel in an image. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +PutPixel( + XImage *image, + int x, int y, + unsigned long pixel) +{ + unsigned char *destPtr = (unsigned char *) &(image->data[(y * image->bytes_per_line) + + ((x * image->bits_per_pixel) / NBBY)]); + + switch (image->bits_per_pixel) { + case 32: + /* + * Pixel is DWORD: 0x00BBGGRR + */ + + destPtr[3] = 0; + case 24: + /* + * Pixel is triplet: 0xBBGGRR. + */ + + destPtr[0] = (unsigned char) GetBValue(pixel); + destPtr[1] = (unsigned char) GetGValue(pixel); + destPtr[2] = (unsigned char) GetRValue(pixel); + break; + case 16: + /* + * Pixel is WORD: 5-5-5 (R-G-B) + */ + + (*(WORD*)destPtr) = ((GetRValue(pixel) & 0xf8) << 7) + | ((GetGValue(pixel) & 0xf8) <<2) + | ((GetBValue(pixel) & 0xf8) >> 3); + break; + case 8: + /* + * Pixel is 8-bit index into color table. + */ + + (*destPtr) = (unsigned char) pixel; + break; + case 4: + /* + * Pixel is 4-bit index in MSBFirst order. + */ + + if (x%2) { + (*destPtr) = (unsigned char) (((*destPtr) & 0xf0) + | (pixel & 0x0f)); + } else { + (*destPtr) = (unsigned char) (((*destPtr) & 0x0f) + | ((pixel << 4) & 0xf0)); + } + break; + case 1: { + /* + * Pixel is bit in MSBFirst order. + */ + + int mask = (0x80 >> (x%8)); + + if (pixel) { + (*destPtr) |= mask; + } else { + (*destPtr) &= ~mask; + } + break; + } + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * XCreateImage -- + * + * Allocates storage for a new XImage. + * + * Results: + * Returns a newly allocated XImage. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +XImage * +XCreateImage( + Display *display, + Visual *visual, + unsigned int depth, + int format, + int offset, + char *data, + unsigned int width, + unsigned int height, + int bitmap_pad, + int bytes_per_line) +{ + XImage* imagePtr = ckalloc(sizeof(XImage)); + imagePtr->width = width; + imagePtr->height = height; + imagePtr->xoffset = offset; + imagePtr->format = format; + imagePtr->data = data; + imagePtr->byte_order = LSBFirst; + imagePtr->bitmap_unit = 8; + imagePtr->bitmap_bit_order = LSBFirst; + imagePtr->bitmap_pad = bitmap_pad; + imagePtr->bits_per_pixel = depth; + imagePtr->depth = depth; + + /* + * Under Windows, bitmap_pad must be on an LONG data-type boundary. + */ + +#define LONGBITS (sizeof(LONG) * 8) + + bitmap_pad = (bitmap_pad + LONGBITS - 1) / LONGBITS * LONGBITS; + + /* + * Round to the nearest bitmap_pad boundary. + */ + + if (bytes_per_line) { + imagePtr->bytes_per_line = bytes_per_line; + } else { + imagePtr->bytes_per_line = (((depth * width) + + (bitmap_pad - 1)) >> 3) & ~((bitmap_pad >> 3) - 1); + } + + imagePtr->red_mask = 0; + imagePtr->green_mask = 0; + imagePtr->blue_mask = 0; + + imagePtr->f.put_pixel = PutPixel; + imagePtr->f.get_pixel = ImageGetPixel; + imagePtr->f.destroy_image = DestroyImage; + imagePtr->f.create_image = NULL; + imagePtr->f.sub_image = NULL; + imagePtr->f.add_pixel = NULL; + + return imagePtr; +} + +/* + *---------------------------------------------------------------------- + * + * XGetImageZPixmap -- + * + * This function copies data from a pixmap or window into an XImage. This + * handles the ZPixmap case only. + * + * Results: + * Returns a newly allocated image containing the data from the given + * rectangle of the given drawable. + * + * Side effects: + * None. + * + * This procedure is adapted from the XGetImage implementation in TkNT. That + * code is Copyright (c) 1994 Software Research Associates, Inc. + * + *---------------------------------------------------------------------- + */ + +static XImage * +XGetImageZPixmap( + Display *display, + Drawable d, + int x, int y, + unsigned int width, unsigned int height, + unsigned long plane_mask, + int format) +{ + TkWinDrawable *twdPtr = (TkWinDrawable *)d; + XImage *ret_image; + HDC hdc, hdcMem; + HBITMAP hbmp, hbmpPrev; + BITMAPINFO *bmInfo = NULL; + HPALETTE hPal, hPalPrev1 = 0, hPalPrev2 = 0; + int size; + unsigned int n; + unsigned int depth; + unsigned char *data; + TkWinDCState state; + BOOL ret; + + if (format != ZPixmap) { + TkpDisplayWarning("Only ZPixmap types are implemented", + "XGetImageZPixmap Failure"); + return NULL; + } + + hdc = TkWinGetDrawableDC(display, d, &state); + + /* + * Need to do a Blt operation to copy into a new bitmap. + */ + + hbmp = CreateCompatibleBitmap(hdc, (int) width, (int) height); + hdcMem = CreateCompatibleDC(hdc); + hbmpPrev = SelectObject(hdcMem, hbmp); + hPal = state.palette; + if (hPal) { + hPalPrev1 = SelectPalette(hdcMem, hPal, FALSE); + n = RealizePalette(hdcMem); + if (n > 0) { + UpdateColors(hdcMem); + } + hPalPrev2 = SelectPalette(hdc, hPal, FALSE); + n = RealizePalette(hdc); + if (n > 0) { + UpdateColors(hdc); + } + } + + ret = BitBlt(hdcMem, 0, 0, (int) width, (int) height, hdc, x, y, SRCCOPY); + if (hPal) { + SelectPalette(hdc, hPalPrev2, FALSE); + } + SelectObject(hdcMem, hbmpPrev); + TkWinReleaseDrawableDC(d, hdc, &state); + if (ret == FALSE) { + ret_image = NULL; + goto cleanup; + } + if (twdPtr->type == TWD_WINDOW) { + depth = Tk_Depth((Tk_Window) twdPtr->window.winPtr); + } else { + depth = twdPtr->bitmap.depth; + } + + size = sizeof(BITMAPINFO); + if (depth <= 8) { + size += sizeof(unsigned short) * (1 << depth); + } + bmInfo = ckalloc(size); + + bmInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmInfo->bmiHeader.biWidth = width; + bmInfo->bmiHeader.biHeight = -(int) height; + bmInfo->bmiHeader.biPlanes = 1; + bmInfo->bmiHeader.biBitCount = depth; + bmInfo->bmiHeader.biCompression = BI_RGB; + bmInfo->bmiHeader.biSizeImage = 0; + bmInfo->bmiHeader.biXPelsPerMeter = 0; + bmInfo->bmiHeader.biYPelsPerMeter = 0; + bmInfo->bmiHeader.biClrUsed = 0; + bmInfo->bmiHeader.biClrImportant = 0; + + if (depth == 1) { + unsigned char *p, *pend; + + GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_PAL_COLORS); + data = ckalloc(bmInfo->bmiHeader.biSizeImage); + if (!data) { + /* printf("Failed to allocate data area for XImage.\n"); */ + ret_image = NULL; + goto cleanup; + } + ret_image = XCreateImage(display, NULL, depth, ZPixmap, 0, (char *) data, + width, height, 32, (int) ((width + 31) >> 3) & ~1); + if (ret_image == NULL) { + ckfree(data); + goto cleanup; + } + + /* + * Get the BITMAP info into the Image. + */ + + if (GetDIBits(hdcMem, hbmp, 0, height, data, bmInfo, + DIB_PAL_COLORS) == 0) { + ckfree(ret_image->data); + ckfree(ret_image); + ret_image = NULL; + goto cleanup; + } + p = data; + pend = data + bmInfo->bmiHeader.biSizeImage; + while (p < pend) { + *p = ~*p; + p++; + } + } else if (depth == 8) { + unsigned short *palette; + unsigned int i; + unsigned char *p; + + GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_PAL_COLORS); + data = ckalloc(bmInfo->bmiHeader.biSizeImage); + if (!data) { + /* printf("Failed to allocate data area for XImage.\n"); */ + ret_image = NULL; + goto cleanup; + } + ret_image = XCreateImage(display, NULL, 8, ZPixmap, 0, (char *) data, + width, height, 8, (int) width); + if (ret_image == NULL) { + ckfree(data); + goto cleanup; + } + + /* + * Get the BITMAP info into the Image. + */ + + if (GetDIBits(hdcMem, hbmp, 0, height, data, bmInfo, + DIB_PAL_COLORS) == 0) { + ckfree(ret_image->data); + ckfree(ret_image); + ret_image = NULL; + goto cleanup; + } + p = data; + palette = (unsigned short *) bmInfo->bmiColors; + for (i = 0; i < bmInfo->bmiHeader.biSizeImage; i++, p++) { + *p = (unsigned char) palette[*p]; + } + } else if (depth == 16) { + GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_RGB_COLORS); + data = ckalloc(bmInfo->bmiHeader.biSizeImage); + if (!data) { + /* printf("Failed to allocate data area for XImage.\n"); */ + ret_image = NULL; + goto cleanup; + } + ret_image = XCreateImage(display, NULL, 16, ZPixmap, 0, (char *) data, + width, height, 16, 0 /* will be calc'ed from bitmap_pad */); + if (ret_image == NULL) { + ckfree(data); + goto cleanup; + } + + /* + * Get the BITMAP info directly into the Image. + */ + + if (GetDIBits(hdcMem, hbmp, 0, height, ret_image->data, bmInfo, + DIB_RGB_COLORS) == 0) { + ckfree(ret_image->data); + ckfree(ret_image); + ret_image = NULL; + goto cleanup; + } + } else { + GetDIBits(hdcMem, hbmp, 0, height, NULL, bmInfo, DIB_RGB_COLORS); + data = ckalloc(width * height * 4); + if (!data) { + /* printf("Failed to allocate data area for XImage.\n"); */ + ret_image = NULL; + goto cleanup; + } + ret_image = XCreateImage(display, NULL, 32, ZPixmap, 0, (char *) data, + width, height, 0, (int) width * 4); + if (ret_image == NULL) { + ckfree(data); + goto cleanup; + } + + if (depth <= 24) { + /* + * This used to handle 16 and 24 bpp, but now just handles 24. It + * can likely be optimized for that. -- hobbs + */ + + unsigned char *smallBitData, *smallBitBase, *bigBitData; + unsigned int byte_width, h, w; + + byte_width = ((width * 3 + 3) & ~(unsigned)3); + smallBitBase = ckalloc(byte_width * height); + if (!smallBitBase) { + ckfree(ret_image->data); + ckfree(ret_image); + ret_image = NULL; + goto cleanup; + } + smallBitData = smallBitBase; + + /* + * Get the BITMAP info into the Image. + */ + + if (GetDIBits(hdcMem, hbmp, 0, height, smallBitData, bmInfo, + DIB_RGB_COLORS) == 0) { + ckfree(ret_image->data); + ckfree(ret_image); + ckfree(smallBitBase); + ret_image = NULL; + goto cleanup; + } + + /* + * Copy the 24 Bit Pixmap to a 32-Bit one. + */ + + for (h = 0; h < height; h++) { + bigBitData = (unsigned char *) ret_image->data + h * ret_image->bytes_per_line; + smallBitData = smallBitBase + h * byte_width; + + for (w = 0; w < width; w++) { + *bigBitData++ = ((*smallBitData++)); + *bigBitData++ = ((*smallBitData++)); + *bigBitData++ = ((*smallBitData++)); + *bigBitData++ = 0; + } + } + + /* + * Free the Device contexts, and the Bitmap. + */ + + ckfree(smallBitBase); + } else { + /* + * Get the BITMAP info directly into the Image. + */ + + if (GetDIBits(hdcMem, hbmp, 0, height, ret_image->data, bmInfo, + DIB_RGB_COLORS) == 0) { + ckfree(ret_image->data); + ckfree(ret_image); + ret_image = NULL; + goto cleanup; + } + } + } + + cleanup: + if (bmInfo) { + ckfree(bmInfo); + } + if (hPal) { + SelectPalette(hdcMem, hPalPrev1, FALSE); + } + DeleteDC(hdcMem); + DeleteObject(hbmp); + + return ret_image; +} + +/* + *---------------------------------------------------------------------- + * + * XGetImage -- + * + * This function copies data from a pixmap or window into an XImage. + * + * Results: + * Returns a newly allocated image containing the data from the given + * rectangle of the given drawable. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +XImage * +XGetImage( + Display* display, + Drawable d, + int x, int y, + unsigned int width, unsigned int height, + unsigned long plane_mask, + int format) +{ + TkWinDrawable *twdPtr = (TkWinDrawable *)d; + XImage *imagePtr; + HDC dc; + + display->request++; + + if (twdPtr == NULL) { + /* + * Avoid unmapped windows or bad drawables + */ + + return NULL; + } + + if (twdPtr->type != TWD_BITMAP) { + /* + * This handles TWD_WINDOW or TWD_WINDC, always creating a 32bit + * image. If the window being copied isn't visible (unmapped or + * obscured), we quietly stop copying (no user error). The user will + * see black where the widget should be. This branch is likely + * followed in favor of XGetImageZPixmap as postscript printed widgets + * require RGB data. + */ + + TkWinDCState state; + unsigned int xx, yy, size; + COLORREF pixel; + + dc = TkWinGetDrawableDC(display, d, &state); + + imagePtr = XCreateImage(display, NULL, 32, format, 0, NULL, + width, height, 32, 0); + size = imagePtr->bytes_per_line * imagePtr->height; + imagePtr->data = ckalloc(size); + ZeroMemory(imagePtr->data, size); + + for (yy = 0; yy < height; yy++) { + for (xx = 0; xx < width; xx++) { + pixel = GetPixel(dc, x+(int)xx, y+(int)yy); + if (pixel == CLR_INVALID) { + break; + } + PutPixel(imagePtr, (int) xx, (int) yy, pixel); + } + } + + TkWinReleaseDrawableDC(d, dc, &state); + } else if (format == ZPixmap) { + /* + * This actually handles most TWD_WINDOW requests, but it varies from + * the above in that it really does a screen capture of an area, which + * is consistent with the Unix behavior, but does not appear to handle + * all bit depths correctly. -- hobbs + */ + + imagePtr = XGetImageZPixmap(display, d, x, y, + width, height, plane_mask, format); + } else { + const char *errMsg = NULL; + char infoBuf[sizeof(BITMAPINFO) + sizeof(RGBQUAD)]; + BITMAPINFO *infoPtr = (BITMAPINFO*)infoBuf; + + if (twdPtr->bitmap.handle == NULL) { + errMsg = "XGetImage: not implemented for empty bitmap handles"; + } else if (format != XYPixmap) { + errMsg = "XGetImage: not implemented for format != XYPixmap"; + } else if (plane_mask != 1) { + errMsg = "XGetImage: not implemented for plane_mask != 1"; + } + if (errMsg != NULL) { + /* + * Do a soft warning for the unsupported XGetImage types. + */ + + TkpDisplayWarning(errMsg, "XGetImage Failure"); + return NULL; + } + + imagePtr = XCreateImage(display, NULL, 1, XYBitmap, 0, NULL, + width, height, 32, 0); + imagePtr->data = ckalloc(imagePtr->bytes_per_line * imagePtr->height); + + dc = GetDC(NULL); + + GetDIBits(dc, twdPtr->bitmap.handle, 0, height, NULL, + infoPtr, DIB_RGB_COLORS); + + infoPtr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + infoPtr->bmiHeader.biWidth = width; + infoPtr->bmiHeader.biHeight = -(LONG)height; + infoPtr->bmiHeader.biPlanes = 1; + infoPtr->bmiHeader.biBitCount = 1; + infoPtr->bmiHeader.biCompression = BI_RGB; + infoPtr->bmiHeader.biSizeImage = 0; + infoPtr->bmiHeader.biXPelsPerMeter = 0; + infoPtr->bmiHeader.biYPelsPerMeter = 0; + infoPtr->bmiHeader.biClrUsed = 0; + infoPtr->bmiHeader.biClrImportant = 0; + + GetDIBits(dc, twdPtr->bitmap.handle, 0, height, imagePtr->data, + infoPtr, DIB_RGB_COLORS); + ReleaseDC(NULL, dc); + } + + return imagePtr; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |