summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkCanvas.c41
-rw-r--r--macosx/tkMacOSXImage.c259
2 files changed, 101 insertions, 199 deletions
diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c
index 400f379..fd65796 100644
--- a/generic/tkCanvas.c
+++ b/generic/tkCanvas.c
@@ -2808,19 +2808,10 @@ DrawCanvas(
blockPtr.height = cHeight;
blockPtr.pixelSize = 4;
blockPtr.pitch = blockPtr.pixelSize * blockPtr.width;
-#ifndef MAC_OSX_TK
-/* XGetImage returns a pixmap whose 32-bit pixels have byte order RGBA */
blockPtr.offset[0] = 0;
blockPtr.offset[1] = 1;
blockPtr.offset[2] = 2;
blockPtr.offset[3] = 3;
-#else
-/* XGetImage returns a pixmap whose 32-bit pixels have byte order ARGB */
- blockPtr.offset[0] = 1;
- blockPtr.offset[1] = 2;
- blockPtr.offset[2] = 3;
- blockPtr.offset[3] = 0;
-#endif
blockPtr.pixelPtr = (unsigned char *)ckalloc(blockPtr.pixelSize * blockPtr.height * blockPtr.width);
/*
@@ -2857,7 +2848,7 @@ DrawCanvas(
for(x = 0; x < blockPtr.width; ++x) {
unsigned int pixel = 0;
- int pixel_offset = blockPtr.pitch * y + blockPtr.pixelSize * x;
+
switch (ximagePtr->bits_per_pixel) {
/*
@@ -2910,35 +2901,21 @@ DrawCanvas(
*/
#ifdef _WIN32
-#define R_OFFSET blockPtr.offset[2]
-#define G_OFFSET blockPtr.offset[1]
-#define B_OFFSET blockPtr.offset[0]
-#define A_OFFSET blockPtr.offset[3]
+#define R_OFFSET 2
+#define B_OFFSET 0
#else
-#define R_OFFSET blockPtr.offset[0]
-#define G_OFFSET blockPtr.offset[1]
-#define B_OFFSET blockPtr.offset[2]
-#define A_OFFSET blockPtr.offset[3]
+#define R_OFFSET 0
+#define B_OFFSET 2
#endif
- if (ximagePtr->bits_per_pixel < 32) {
- blockPtr.pixelPtr[pixel_offset + R_OFFSET] =
+ blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x + R_OFFSET] =
(unsigned char)((pixel & visualPtr->red_mask) >> rshift);
- blockPtr.pixelPtr[pixel_offset + G_OFFSET] =
+ blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x +1] =
(unsigned char)((pixel & visualPtr->green_mask) >> gshift);
- blockPtr.pixelPtr[pixel_offset + B_OFFSET] =
+ blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x + B_OFFSET] =
(unsigned char)((pixel & visualPtr->blue_mask) >> bshift);
- blockPtr.pixelPtr[pixel_offset + A_OFFSET] = 0xFF;
- } else {
- *((unsigned int *) (blockPtr.pixelPtr + pixel_offset)) = pixel;
- }
+ blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x +3] = 0xFF;
#ifdef DEBUG_DRAWCANVAS
- fprintf(stderr, "Set pixel %x to %hhx %hhx %hhx %hhx \n",
- pixel,
- blockPtr.pixelPtr[pixel_offset + 0],
- blockPtr.pixelPtr[pixel_offset + 1],
- blockPtr.pixelPtr[pixel_offset + 2],
- blockPtr.pixelPtr[pixel_offset + 3]);
{
int ix;
if (x > 0)
diff --git a/macosx/tkMacOSXImage.c b/macosx/tkMacOSXImage.c
index 3b45be6..6b0a8c6 100644
--- a/macosx/tkMacOSXImage.c
+++ b/macosx/tkMacOSXImage.c
@@ -3,10 +3,10 @@
*
* The code in this file provides an interface for XImages,
*
- * Copyright (c) 1995-1997 Sun Microsystems, Inc.
- * Copyright (c) 2001-2009, Apple Inc.
- * Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
- * Copyright (c) 2017-2021 Marc Culler.
+ * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright © 2001-2009, Apple Inc.
+ * Copyright © 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright © 2017-2020 Marc Culler.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -19,71 +19,6 @@ static CGImageRef CreateCGImageFromPixmap(Drawable pixmap);
static CGImageRef CreateCGImageFromDrawableRect( Drawable drawable,
int x, int y, unsigned int width, unsigned int height);
-/* Pixel formats
- *
- * Tk uses the XImage structure defined in Xlib.h for storing images. The
- * image data in an XImage is a 32-bit aligned array of bytes. Interpretation
- * of that data is not specified, but the structure includes parameters which
- * provide interpretation hints so that an application can use a family of
- * different data structures.
- *
- * The possible values for the XImage format field are XYBitmap, XYPixmap and
- * ZPixmap. The macOS port does not support the XYPixmap format. This means
- * that bitmap images are stored as a single bit plane (XYBitmap) and that
- * color images are stored as a sequence of pixel values (ZPixmap).
- *
- * For a ZPixmap, the number of bits allocated to each pixel is specified by
- * the bits_per_pixel field of the XImage structure. The functions in this
- * module which convert between XImage and native CGImage or NSImage structures
- * only support XImages with 32 bits per pixel. The ImageGetPixel and PutPixel
- * implementations in this file allow 1, 4, 8, 16 or 32 bits per pixel, however.
- *
- * In tkImgPhInstance.c the layout used for pixels is determined by the values
- * of the red_mask, blue_mask and green_mask fields in the XImage structure.
- * The Aqua port always sets red_mask = 0xFF0000, green_mask = 0xFF00, and
- * blue_mask = 0xFF. This means that a 32bpp ZPixmap XImage uses ARGB32 pixels,
- * with small-endian byte order BGRA. The data array for such an XImage can be
- * passed directly to construct a CGBitmapImageRep if one specifies the
- * bitmapInfo as kCGBitmapByteOrder32Big | kCGImageAlphaLast.
- *
- * The structures below describe the bitfields in two common 32 bpp pixel
- * layouts. Note that bit field layouts are compiler dependent. The layouts
- * shown in the comments are those produced by clang and gcc. Also note
- * that kCGBitmapByteOrder32Big is consistently set when creating CGImages or
- * CGImageBitmapReps.
- */
-
-/* RGBA32 0xRRGGBBAA (Byte order is RGBA on big-endian systems.)
- * This is used by NSBitmapImageRep when the bitmapFormat property is 0,
- * the default value.
- */
-
-typedef struct RGBA32pixel_t {
- unsigned red: 8;
- unsigned green: 8;
- unsigned blue: 8;
- unsigned alpha: 8;
-} RGBA32pixel;
-
-/*
- * ARGB32 0xAARRGGBB (Byte order is ARGB on big-endian systems.)
- * This is used by Aqua Tk for XImages and by NSBitmapImageReps whose
- * bitmapFormat property is NSBitmapFormatAlphaFirst.
- */
-
-typedef struct ARGB32pixel_t {
- unsigned blue: 8;
- unsigned green: 8;
- unsigned red: 8;
- unsigned alpha: 8;
-} ARGB32pixel;
-
-typedef union pixel32_t {
- unsigned int uint;
- RGBA32pixel rgba;
- ARGB32pixel argb;
-} pixel32;
-
#pragma mark XImage handling
int
@@ -181,7 +116,9 @@ TkMacOSXCreateCGImageWithXImage(
}
bitsPerComponent = 8;
bitsPerPixel = 32;
- bitmapInfo = kCGBitmapByteOrder32Big | alphaInfo;
+ bitmapInfo = (image->byte_order == MSBFirst ?
+ kCGBitmapByteOrder32Little : kCGBitmapByteOrder32Big);
+ bitmapInfo |= alphaInfo;
data = (char *)memcpy(ckalloc(len), image->data + image->xoffset, len);
if (data) {
provider = CGDataProviderCreateWithData(data, data, len,
@@ -271,12 +208,14 @@ ImageGetPixel(
switch (image->bits_per_pixel) {
case 32: /* 8 bits per channel */
- {
- ARGB32pixel *pixel = (ARGB32pixel *)srcPtr;
- r = pixel->red;
- g = pixel->green;
- b = pixel->blue;
- }
+ r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
+ g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
+ b = (*((unsigned int*) srcPtr) ) & 0xff;
+ /*if (image->byte_order == LSBFirst) {
+ r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0];
+ } else {
+ r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
+ }*/
break;
case 16: /* 5 bits per channel */
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
@@ -313,10 +252,7 @@ ImageGetPixel(
*
* ImagePutPixel --
*
- * Set a single pixel in an image. The pixel is provided as an unsigned
- * 32-bit integer. The value of that integer is interpreted by assuming
- * that its low-order N bits have the format specified by the XImage,
- * where N is equal to the bits_per_pixel field of the XImage.
+ * Set a single pixel in an image.
*
* Results:
* None.
@@ -342,20 +278,27 @@ ImagePutPixel(
if (image->bits_per_pixel == 32) {
*((unsigned int*) dstPtr) = pixel;
} else {
+ unsigned char r = ((pixel & image->red_mask) >> 16) & 0xff;
+ unsigned char g = ((pixel & image->green_mask) >> 8) & 0xff;
+ unsigned char b = ((pixel & image->blue_mask) ) & 0xff;
switch (image->bits_per_pixel) {
case 16:
- *((unsigned short*) dstPtr) = pixel & 0xffff;
+ *((unsigned short*) dstPtr) = ((r & 0xf8) << 7) |
+ ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
break;
case 8:
- *dstPtr = pixel & 0xff;
+ *dstPtr = ((r & 0xc0) >> 2) | ((g & 0xc0) >> 4) |
+ ((b & 0xc0) >> 6);
break;
case 4: {
- *dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (pixel & 0x0f)) :
- ((*dstPtr & 0x0f) | ((pixel << 4) & 0xf0));
+ unsigned char c = ((r & 0x80) >> 5) | ((g & 0x80) >> 6) |
+ ((b & 0x80) >> 7);
+ *dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (c & 0x0f)) :
+ ((*dstPtr & 0x0f) | ((c << 4) & 0xf0));
break;
}
case 1:
- *dstPtr = pixel ? (*dstPtr | (0x80 >> (x % 8))) :
+ *dstPtr = ((r|g|b) & 0x80) ? (*dstPtr | (0x80 >> (x % 8))) :
(*dstPtr & ~(0x80 >> (x % 8)));
break;
}
@@ -479,8 +422,10 @@ XCreateImage(
*----------------------------------------------------------------------
*/
-#define USE_ALPHA kCGImageAlphaLast
-#define IGNORE_ALPHA kCGImageAlphaNoneSkipLast
+#define PIXEL_RGBA kCGImageAlphaLast
+#define PIXEL_ARGB kCGImageAlphaFirst
+#define PIXEL_XRGB kCGImageAlphaNoneSkipFirst
+#define PIXEL_RGBX kCGImageAlphaNoneSkipLast
static int
TkMacOSXPutImage(
@@ -535,34 +480,19 @@ TkMacOSXPutImage(
return result;
}
-int XPutImage(
- Display* display,
- Drawable drawable,
- GC gc,
- XImage* image,
- int src_x,
- int src_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height) {
- return TkMacOSXPutImage(IGNORE_ALPHA, display, drawable, gc, image,
+int XPutImage(Display* display, Drawable drawable, GC gc, XImage* image,
+ int src_x, int src_y, int dest_x, int dest_y,
+ unsigned int width, unsigned int height) {
+ return TkMacOSXPutImage(PIXEL_RGBX, display, drawable, gc, image,
src_x, src_y, dest_x, dest_y, width, height);
}
-int TkpPutRGBAImage(
- Display* display,
- Drawable drawable,
- GC gc,
- XImage* image,
- int src_x,
- int src_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height) {
- return TkMacOSXPutImage(USE_ALPHA, display, drawable, gc, image,
- src_x, src_y, dest_x, dest_y, width, height);
+int TkpPutRGBAImage(Display* display,
+ Drawable drawable, GC gc, XImage* image,
+ int src_x, int src_y, int dest_x, int dest_y,
+ unsigned int width, unsigned int height) {
+ return TkMacOSXPutImage(PIXEL_RGBA, display, drawable, gc, image,
+ src_x, src_y, dest_x, dest_y, width, height);
}
@@ -571,40 +501,33 @@ int TkpPutRGBAImage(
*
* CreateCGImageFromDrawableRect
*
- * Extract image data from a MacOSX drawable as a CGImage. The drawable
- * may be either a pixmap or a window, but there issues in the case of
- * a window.
- *
- * CreateCGImageFromDrawableRect is called by XGetImage and XCopyArea.
- * The Tk core uses these two functions on some platforms in order to
- * implement explicit double-buffered drawing -- a pixmap is copied from a
- * window, modified using CPU-based graphics composition, and then copied
- * back to the window. Platforms, such as macOS, on which the system
- * provides double-buffered drawing and GPU-based composition operations
- * can avoid calls to XGetImage and XCopyArea from the core by defining
- * the compile-time variable TK_NO_DOUBLE_BUFFERING. Nonetheless, these
- * two functions are in the stubs table and therefore could be used by
- * extensions.
- *
- * The implementation here does not always work correctly when the source
- * is a window. The original version of this function relied on
+ * Extract image data from a MacOSX drawable as a CGImage.
+ *
+ * This is only called by XGetImage and XCopyArea. The Tk core uses
+ * these functions on some platforms, but on macOS the core does not
+ * call them with a source drawable which is a window. Such calls are
+ * used only for double-buffered drawing. Since macOS defines the
+ * macro TK_NO_DOUBLE_BUFFERING, the generic code never calls XGetImage
+ * or XCopyArea on macOS. Nonetheless, these function are in the stubs
+ * table and therefore could be used by extensions.
+ *
+ * This implementation does not work correctly. Originally it relied on
* [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was
* deprecated by Apple in OSX 10.14 and also required the use of other
* deprecated functions such as [NSView lockFocus]. Apple's suggested
* replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that
- * is being used here. However, cacheDisplayInRect works by calling
- * [NSView drawRect] after setting the current graphics context to be one
- * which draws to a bitmap. There are situations in which this can be
- * used, e.g. when taking a screenshot of a window. But it cannot be used
- * as part of a normal display procedure, using the copy-modify-paste
- * paradigm that is the basis of the explicit double-buffering. Since the
- * copy operation will call the same display procedure that is calling
- * this function via XGetImage or XCopyArea, this would create an infinite
- * recursion.
- *
- * An alternative to the copy-modify-paste paradigm is to use GPU-based
- * graphics composition, clipping to the specified rectangle. That is
- * the approach that must be followed by display procedures on macOS.
+ * is what is being used here. However, that method only works when the
+ * view has a valid CGContext, and a view is only guaranteed to have a
+ * valid context during a call to [NSView drawRect]. To further complicate
+ * matters, cacheDisplayInRect calls [NSView drawRect]. Essentially it is
+ * asking the view to draw a subrectangle of itself using a special
+ * graphics context which is linked to the BitmapImageRep. But our
+ * implementation of [NSView drawRect] does not allow recursive calls. If
+ * called recursively it returns immediately without doing any drawing.
+ * So the bottom line is that this function either returns a NULL pointer
+ * or a black image. To make it useful would require a significant amount
+ * of rewriting of the drawRect method. Perhaps the next release of OSX
+ * will include some more helpful ways of doing this.
*
* Results:
* Returns an NSBitmapRep representing the image of the given rectangle of
@@ -654,8 +577,7 @@ CreateCGImageFromDrawableRect(
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
cg_context = CGBitmapContextCreate(imageData, view_width, view_height,
bitsPerComponent, bytesPerRow, colorSpace,
- kCGImageAlphaPremultipliedLast |
- kCGBitmapByteOrder32Big);
+ kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CFRelease(colorSpace);
[view.layer renderInContext:cg_context];
}
@@ -722,6 +644,9 @@ CreateCGImageFromPixmap(
*
*----------------------------------------------------------------------
*/
+struct pixel_fmt {int r; int g; int b; int a;};
+static const struct pixel_fmt bgra = {2, 1, 0, 3};
+static const struct pixel_fmt abgr = {3, 2, 1, 0};
XImage *
XGetImage(
@@ -738,6 +663,7 @@ XGetImage(
NSUInteger bitmap_fmt = 0;
XImage* imagePtr = NULL;
char *bitmap = NULL;
+ char R, G, B, A;
int depth = 32, offset = 0, bitmap_pad = 0;
unsigned int bytes_per_row, size, row, n, m;
@@ -760,11 +686,12 @@ XGetImage(
size = [bitmapRep bytesPerPlane];
bytes_per_row = [bitmapRep bytesPerRow];
bitmap = (char *)ckalloc(size);
- if ((bitmap_fmt != 0 && bitmap_fmt != NSBitmapFormatAlphaFirst)
- || [bitmapRep samplesPerPixel] != 4
- || [bitmapRep isPlanar] != 0
- || bytes_per_row < 4 * width
- || size != bytes_per_row * height) {
+ if (!bitmap
+ || (bitmap_fmt != 0 && bitmap_fmt != 1)
+ || [bitmapRep samplesPerPixel] != 4
+ || [bitmapRep isPlanar] != 0
+ || bytes_per_row < 4 * width
+ || size != bytes_per_row * height) {
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
[bitmapRep release];
return NULL;
@@ -772,37 +699,35 @@ XGetImage(
memcpy(bitmap, (char *)[bitmapRep bitmapData], size);
[bitmapRep release];
- for (row = 0, n = 0; row < height; row++, n += bytes_per_row) {
- for (m = n; m < n + 4*width; m += 4) {
- pixel32 pixel = *((pixel32 *)(bitmap + m));
- if (bitmap_fmt == 0) { // default format
+ /*
+ * When Apple extracts a bitmap from an NSView, it may be in either
+ * BGRA or ABGR format. For an XImage we need RGBA.
+ */
- /*
- * This pixel is in ARGB32 format. We need RGBA32.
- */
+ struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
- pixel32 flipped;
- flipped.rgba.red = pixel.argb.red;
- flipped.rgba.green = pixel.argb.green;
- flipped.rgba.blue = pixel.argb.blue;
- flipped.rgba.alpha = pixel.argb.alpha;
- *((pixel32 *)(bitmap + m)) = flipped;
- } else { // bitmap_fmt = NSBitmapFormatAlphaFirst
- *((pixel32 *)(bitmap + m)) = pixel;
- }
+ for (row = 0, n = 0; row < height; row++, n += bytes_per_row) {
+ for (m = n; m < n + 4*width; m += 4) {
+ R = *(bitmap + m + pixel.r);
+ G = *(bitmap + m + pixel.g);
+ B = *(bitmap + m + pixel.b);
+ A = *(bitmap + m + pixel.a);
+
+ *(bitmap + m) = R;
+ *(bitmap + m + 1) = G;
+ *(bitmap + m + 2) = B;
+ *(bitmap + m + 3) = A;
}
}
imagePtr = XCreateImage(display, NULL, depth, format, offset,
(char*) bitmap, width, height,
bitmap_pad, bytes_per_row);
} else {
-
/*
* There are some calls to XGetImage in the generic Tk code which pass
* an XYPixmap rather than a ZPixmap. XYPixmaps should be handled
* here.
*/
-
TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
}
return imagePtr;