tkWinImage.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
- /*
- * 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.
- *
- * RCS: @(#) $Id: tkWinImage.c,v 1.6.2.2 2003/10/29 01:08:02 hobbs Exp $
- */
- #include "tkWinInt.h"
- static int DestroyImage _ANSI_ARGS_((XImage* data));
- static unsigned long ImageGetPixel _ANSI_ARGS_((XImage *image, int x, int y));
- static int PutPixel _ANSI_ARGS_((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(imagePtr)
- XImage *imagePtr; /* image to free */
- {
- if (imagePtr) {
- if (imagePtr->data) {
- ckfree((char*)imagePtr->data);
- }
- ckfree((char*)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(image, x, y)
- XImage *image;
- int x, y;
- {
- unsigned long pixel = 0;
- unsigned char *srcPtr = &(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(image, x, y, pixel)
- XImage *image;
- int x, y;
- unsigned long pixel;
- {
- unsigned char *destPtr = &(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, visual, depth, format, offset, data, width, height,
- bitmap_pad, bytes_per_line)
- 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 = (XImage *) 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, d, x, y, width, height, plane_mask, format)
- 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, hPalPrev2;
- int size;
- unsigned int n;
- unsigned int depth;
- unsigned char *data;
- TkWinDCState state;
- BOOL ret;
- if (format != ZPixmap) {
- TkpDisplayWarning(
- "XGetImageZPixmap: 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, width, 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, width, height, hdc, x, y, SRCCOPY);
- if (hPal) {
- SelectPalette(hdc, hPalPrev2, FALSE);
- }
- SelectObject(hdcMem, hbmpPrev);
- TkWinReleaseDrawableDC(d, hdc, &state);
- if (ret == FALSE) {
- 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 = (BITMAPINFO *) 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, data,
- width, height, 32, ((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((char *) ret_image->data);
- ckfree((char *) 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, data,
- width, height, 8, width);
- if (ret_image == NULL) {
- ckfree((char *) data);
- goto cleanup;
- }
- /* Get the BITMAP info into the Image. */
- if (GetDIBits(hdcMem, hbmp, 0, height, data, bmInfo,
- DIB_PAL_COLORS) == 0) {
- ckfree((char *) ret_image->data);
- ckfree((char *) 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, data,
- width, height, 16, 0 /* will be calc'ed from bitmap_pad */);
- if (ret_image == NULL) {
- ckfree((char *) 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((char *) ret_image->data);
- ckfree((char *) 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, data,
- width, height, 0, width * 4);
- if (ret_image == NULL) {
- ckfree((char *) 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) & ~3);
- smallBitBase = ckalloc(byte_width * height);
- if (!smallBitBase) {
- ckfree((char *) ret_image->data);
- ckfree((char *) 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((char *) ret_image->data);
- ckfree((char *) ret_image);
- ckfree((char *) smallBitBase);
- ret_image = NULL;
- goto cleanup;
- }
- /* Copy the 24 Bit Pixmap to a 32-Bit one. */
- for (h = 0; h < height; h++) {
- bigBitData = 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((char *) 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((char *) ret_image->data);
- ckfree((char *) ret_image);
- ret_image = NULL;
- goto cleanup;
- }
- }
- }
- cleanup:
- if (bmInfo) {
- ckfree((char *) 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, d, x, y, width, height, plane_mask, format)
- 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, xx, 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 {
- 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;
- }