diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | generic/tkCanvPs.c | 50 | ||||
-rw-r--r-- | generic/tkCanvWind.c | 9 | ||||
-rw-r--r-- | generic/tkCanvas.h | 16 | ||||
-rw-r--r-- | tests/canvPs.test | 32 | ||||
-rw-r--r-- | win/tkWinImage.c | 350 |
6 files changed, 404 insertions, 64 deletions
@@ -1,3 +1,14 @@ +2002-10-10 Jeff Hobbs <jeffh@ActiveState.com> + + * tests/canvPs.test: tests for canvas embedded window ps generation + * generic/tkCanvWind.c (CanvasPsWindow): removed dead code loop. + * generic/tkCanvas.h: moved TkColormapData struct to tkCanvPs.c + * generic/tkCanvPs.c (TkImageGetColor): corrected bogus use of + TkColormapData on Windows. Non-separated data may need correction + as well. + * win/tkWinImage.c (XGetImage, XGetImageZPixmap): added support + for generating ps for embedded windows on canvases. + 2002-10-09 Jeff Hobbs <jeffh@ActiveState.com> * unix/README: doc'ed --enable-symbols options. diff --git a/generic/tkCanvPs.c b/generic/tkCanvPs.c index 643f2a9..b72ded9 100644 --- a/generic/tkCanvPs.c +++ b/generic/tkCanvPs.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvPs.c,v 1.10 2002/08/05 04:30:38 dgp Exp $ + * RCS: @(#) $Id: tkCanvPs.c,v 1.11 2002/10/10 07:25:24 hobbs Exp $ */ #include "tkInt.h" @@ -23,6 +23,20 @@ */ /* + * The following definition is used in generating postscript for images + * and windows. + */ + +typedef struct TkColormapData { /* Hold color information for a window */ + int separated; /* Whether to use separate color bands */ + int color; /* Whether window is color or black/white */ + int ncolors; /* Number of color values stored */ + XColor *colors; /* Pixel value -> RGB mappings */ + int red_mask, green_mask, blue_mask; /* Masks and shifts for each */ + int red_shift, green_shift, blue_shift; /* color band */ +} TkColormapData; + +/* * One of the following structures is created to keep track of Postscript * output being generated. It consists mostly of information provided on * the widget command line. @@ -458,12 +472,13 @@ TkCanvPostscriptCmd(canvasPtr, interp, argc, argv) /* * Insert the prolog */ - Tcl_AppendResult(interp, Tcl_GetVar(interp,"::tk::ps_preamable",TCL_GLOBAL_ONLY), (char *) NULL); + Tcl_AppendResult(interp, Tcl_GetVar(interp,"::tk::ps_preamable", + TCL_GLOBAL_ONLY), (char *) NULL); + if (psInfo.chan != NULL) { Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); Tcl_ResetResult(canvasPtr->interp); } - /* *----------------------------------------------------------- @@ -1118,13 +1133,24 @@ TkImageGetColor(cdata, pixel, red, green, blue) int r = (pixel & cdata->red_mask) >> cdata->red_shift; int g = (pixel & cdata->green_mask) >> cdata->green_shift; int b = (pixel & cdata->blue_mask) >> cdata->blue_shift; - *red = cdata->colors[r].red / 65535.0; +#ifdef WIN32 + /* + * Because XQueryColors is an empty stub on Windows, we need + * to just make this simple calculation. The TkColormapData + * XColor data is otherwise bogus on Windows. -- hobbs + */ + *red = (double)r / 255.0; + *green = (double)g / 255.0; + *blue = (double)b / 255.0; +#else + *red = cdata->colors[r].red / 65535.0; *green = cdata->colors[g].green / 65535.0; - *blue = cdata->colors[b].blue / 65535.0; + *blue = cdata->colors[b].blue / 65535.0; +#endif } else { - *red = cdata->colors[pixel].red / 65535.0; + *red = cdata->colors[pixel].red / 65535.0; *green = cdata->colors[pixel].green / 65535.0; - *blue = cdata->colors[pixel].blue / 65535.0; + *blue = cdata->colors[pixel].blue / 65535.0; } } @@ -1218,7 +1244,6 @@ TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) else cdata.color = 1; - XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors); /* @@ -1241,8 +1266,7 @@ TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) * Postscript interpreter). */ - switch (level) - { + switch (level) { case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; case 1: bytesPerLine = width; maxWidth = 60000; break; case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; @@ -1323,9 +1347,7 @@ TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), &red, &green, &blue); sprintf(buffer, "%02X", (int) floor(0.5 + 255.0 * - (0.30 * red + - 0.59 * green + - 0.11 * blue))); + (0.30 * red + 0.59 * green + 0.11 * blue))); Tcl_AppendResult(interp, buffer, (char *) NULL); lineLen += 2; if (lineLen > 60) { @@ -1340,7 +1362,7 @@ TkPostscriptImage(interp, tkwin, psInfo, ximage, x, y, width, height) * Finally, color mode. Here, just output the red, green, * and blue values directly. */ - for (xx = x; xx < x+width; xx++) { + for (xx = x; xx < x+width; xx++) { TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), &red, &green, &blue); sprintf(buffer, "%02X%02X%02X", diff --git a/generic/tkCanvWind.c b/generic/tkCanvWind.c index c197584..b82efa1 100644 --- a/generic/tkCanvWind.c +++ b/generic/tkCanvWind.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvWind.c,v 1.7 2002/08/05 04:30:38 dgp Exp $ + * RCS: @(#) $Id: tkCanvWind.c,v 1.8 2002/10/10 07:25:24 hobbs Exp $ */ #include <stdio.h> @@ -845,7 +845,6 @@ CanvasPsWindow(interp, tkwin, canvas, x, y, width, height) int width, height; /* width/height of window. */ { char buffer[256]; - TkWindow *winPtr; XImage *ximage; int result; Tcl_DString buffer1, buffer2; @@ -885,12 +884,6 @@ CanvasPsWindow(interp, tkwin, canvas, x, y, width, height) (char *) NULL); Tcl_DStringFree(&buffer1); - for (winPtr = ((TkWindow *) tkwin)->childList; winPtr != NULL; - winPtr = winPtr->nextPtr) { - if (Tk_IsMapped(winPtr)) { -/* printf("child window: %s\n", winPtr->pathName);*/ - } - } return result; } Tcl_DStringFree(&buffer1); diff --git a/generic/tkCanvas.h b/generic/tkCanvas.h index 70cb03d..cb601a9 100644 --- a/generic/tkCanvas.h +++ b/generic/tkCanvas.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvas.h,v 1.5 2002/08/05 04:30:38 dgp Exp $ + * RCS: @(#) $Id: tkCanvas.h,v 1.6 2002/10/10 07:25:24 hobbs Exp $ */ #ifndef _TKCANVAS @@ -295,18 +295,4 @@ typedef struct TkCanvas { extern int TkCanvPostscriptCmd _ANSI_ARGS_((TkCanvas *canvasPtr, Tcl_Interp *interp, int argc, CONST char **argv)); -/* - * The following definition is shared between tkCanvPs.c and tkCanvImg.c, - * and is used in generating postscript for images and windows. - */ - -typedef struct TkColormapData { /* Hold color information for a window */ - int separated; /* Whether to use separate color bands */ - int color; /* Whether window is color or black/white */ - int ncolors; /* Number of color values stored */ - XColor *colors; /* Pixel value -> RGB mappings */ - int red_mask, green_mask, blue_mask; /* Masks and shifts for each */ - int red_shift, green_shift, blue_shift; /* color band */ -} TkColormapData; - #endif /* _TKCANVAS */ diff --git a/tests/canvPs.test b/tests/canvPs.test index 8faad75..8ab93a0 100644 --- a/tests/canvPs.test +++ b/tests/canvPs.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: canvPs.test,v 1.4 2002/07/14 05:48:46 dgp Exp $ +# RCS: @(#) $Id: canvPs.test,v 1.5 2002/10/10 07:25:24 hobbs Exp $ package require tcltest 2.1 namespace import -force tcltest::configure @@ -94,6 +94,36 @@ test canvPs-2.4 {test writing to channel and file, same output} {pcOnly} { set status } ok +test canvPs-3.1 {test ps generation with an embedded window} {} { + removeFile bar.ps + destroy .c + pack [canvas .c -width 200 -height 200 -background white] + .c create rect 20 20 150 150 -tags rect0 -dash . -width 2 + .c create arc 0 50 200 200 -tags arc0 \ + -dash {4 4} -stipple question -outline red -fill green + + image create photo logo \ + -file [file join $tk_library images pwrdLogo150.gif] + .c create image 200 50 -image logo -anchor nw + + entry .c.e -background pink -foreground blue -width 14 + .c.e insert 0 "we gonna be postscripted" + .c create window 50 180 -anchor nw -window .c.e + update + .c postscript -file bar.ps + file exists bar.ps +} 1 +test canvPs-3.2 {test ps generation with an embedded window not mapped} {} { + removeFile bar.ps + destroy .c + pack [canvas .c -width 200 -height 200 -background white] + entry .c.e -background pink -foreground blue -width 14 + .c.e insert 0 "we gonna be postscripted" + .c create window 50 180 -anchor nw -window .c.e + .c postscript -file bar.ps + file exists bar.ps +} 1 + # cleanup removeFile foo.ps removeFile bar.ps diff --git a/win/tkWinImage.c b/win/tkWinImage.c index e4a153b..32b2ecb 100644 --- a/win/tkWinImage.c +++ b/win/tkWinImage.c @@ -8,7 +8,7 @@ * 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.4 2002/03/26 20:13:39 chengyemao Exp $ + * RCS: @(#) $Id: tkWinImage.c,v 1.5 2002/10/10 07:25:24 hobbs Exp $ */ #include "tkWinInt.h" @@ -261,6 +261,242 @@ XCreateImage(display, visual, depth, format, offset, data, width, height, /* *---------------------------------------------------------------------- + * 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; + unsigned char *smallBitData, *smallBitBase, *bigBitData; + HDC hdc, hdcMem; + HBITMAP hbmp, hbmpPrev; + BITMAPINFO *bmInfo = NULL; + HPALETTE hPal, hPalPrev1, hPalPrev2; + unsigned int byte_width; + unsigned int h, w, n; + unsigned char plmr, plmg, plmb; + unsigned char *data; + int size; + unsigned int depth; + 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 { + 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; + } + + 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); + ret_image = NULL; + goto cleanup; + } + + plmr = (unsigned char) (plane_mask & 0xff0000) >> 16; + plmg = (unsigned char) (plane_mask & 0x00ff00) >> 8; + plmb = (unsigned char) (plane_mask & 0x0000ff); + + /* 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++)) /* & plmr */; + *bigBitData++ = ((*smallBitData++)) /* & plmg */; + *bigBitData++ = ((*smallBitData++)) /* & plmb */; + *bigBitData++ = 0; + } + } + /* Free the Device contexts, and the Bitmap */ + ckfree((char *) smallBitBase); + } + + cleanup: + if (bmInfo) { + ckfree((char *) bmInfo); + } + if (hPal) { + SelectPalette(hdcMem, hPalPrev1, FALSE); + } + DeleteDC(hdcMem); + DeleteObject(hbmp); + + return ret_image; +} + +/* + *---------------------------------------------------------------------- * * XGetImage -- * @@ -291,39 +527,101 @@ XGetImage(display, d, x, y, width, height, plane_mask, format) TkWinDrawable *twdPtr = (TkWinDrawable *)d; XImage *imagePtr; HDC dc; - char infoBuf[sizeof(BITMAPINFO) + sizeof(RGBQUAD)]; - BITMAPINFO *infoPtr = (BITMAPINFO*)infoBuf; - if ((twdPtr->type != TWD_BITMAP) || (twdPtr->bitmap.handle == NULL) - || (format != XYPixmap) || (plane_mask != 1)) { - panic("XGetImage: not implemented"); + display->request++; + + if (twdPtr == NULL) { + /* + * Avoid unmapped windows or bad drawables + */ + return NULL; } + if (format == ZPixmap) { + /* + * This actually handles most TWD_WINDOW requests, but it varies + * from the one below in that it really does a screen capture of + * an area, but that is consistent with the Unix behavior -- hobbs + */ + imagePtr = XGetImageZPixmap(display, d, x, y, + width, height, plane_mask, format); + } else if (twdPtr->type != TWD_BITMAP) { + /* + * This handles TWD_WINDOW or TWD_WINDC. + * 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 not followed in favor of XGetImageZPixmap. + */ + Tk_Window tkwin = (Tk_Window) TkWinGetWinPtr(d); + TkWinDCState state; + unsigned int xx, yy, size; + COLORREF pixel; - imagePtr = XCreateImage(display, NULL, 1, XYBitmap, 0, NULL, - width, height, 32, 0); - imagePtr->data = ckalloc(imagePtr->bytes_per_line * imagePtr->height); + dc = TkWinGetDrawableDC(display, d, &state); - dc = GetDC(NULL); + imagePtr = XCreateImage(display, NULL, Tk_Depth(tkwin), + format, 0, NULL, width, height, 32, 0); + size = imagePtr->bytes_per_line * imagePtr->height; + imagePtr->data = ckalloc(size); + ZeroMemory(imagePtr->data, size); - GetDIBits(dc, twdPtr->bitmap.handle, 0, height, NULL, - infoPtr, DIB_RGB_COLORS); + 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); + } + } - 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.biCompression = 0; - infoPtr->bmiHeader.biXPelsPerMeter = 0; - infoPtr->bmiHeader.biYPelsPerMeter = 0; - infoPtr->bmiHeader.biClrUsed = 0; - infoPtr->bmiHeader.biClrImportant = 0; + TkWinReleaseDrawableDC(d, dc, &state); + } else { + char *errMsg = NULL; + char infoBuf[sizeof(BITMAPINFO) + sizeof(RGBQUAD)]; + BITMAPINFO *infoPtr = (BITMAPINFO*)infoBuf; - GetDIBits(dc, twdPtr->bitmap.handle, 0, height, imagePtr->data, - infoPtr, DIB_RGB_COLORS); - ReleaseDC(NULL, dc); + 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.biCompression = 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; } |