diff options
author | Kevin Walzer <kw@codebykevin.com> | 2014-06-22 01:35:34 (GMT) |
---|---|---|
committer | Kevin Walzer <kw@codebykevin.com> | 2014-06-22 01:35:34 (GMT) |
commit | fe3c1f4986ee4cf0442fa51f2e036b0bfb83df43 (patch) | |
tree | 984b970e6b79425a23d0aaf01643d78163e7cfe8 | |
parent | 3b641c87437e0c46c5d0044fb7d8776cb0a7057e (diff) | |
download | tk-fe3c1f4986ee4cf0442fa51f2e036b0bfb83df43.zip tk-fe3c1f4986ee4cf0442fa51f2e036b0bfb83df43.tar.gz tk-fe3c1f4986ee4cf0442fa51f2e036b0bfb83df43.tar.bz2 |
Fix for images with alpha channel data on Mavericks; thanks to Mark Culler for the patch.
-rw-r--r-- | macosx/GNUmakefile | 2 | ||||
-rw-r--r-- | macosx/tkMacOSXDraw.c | 153 | ||||
-rw-r--r-- | macosx/tkMacOSXPrivate.h | 2 | ||||
-rw-r--r-- | macosx/tkMacOSXSubwindows.c | 4 | ||||
-rw-r--r-- | macosx/tkMacOSXXStubs.c | 90 |
5 files changed, 137 insertions, 114 deletions
diff --git a/macosx/GNUmakefile b/macosx/GNUmakefile index 333961c..9d57df8 100644 --- a/macosx/GNUmakefile +++ b/macosx/GNUmakefile @@ -134,7 +134,7 @@ endif INSTALL_TARGETS = install-binaries install-libraries ifeq (${EMBEDDED_BUILD},) -INSTALL_TARGETS += install-private-headers install-demos +INSTALL_TARGETS += install-private-headers install-demos install-headers endif ifeq (${INSTALL_BUILD}_${EMBEDDED_BUILD}_${BUILD_STYLE},1__Deployment) INSTALL_TARGETS += html-tk diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 5be04a4..3ce38fd 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -113,6 +113,70 @@ TkMacOSXInitCGDrawing( /* *---------------------------------------------------------------------- * + * BitmapRepFromDrawableRect + * + * Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep. + * + * Results: + * Returns an NSBitmapRep representing the image of the given rectangle of + * the given drawable. + * + * NOTE: The x,y coordinates should be relative to a coordinate system with + * origin at the top left, as used by XImage and CGImage, not bottom + * left as used by NSView. + * + * Side effects: + * Allocates an NSBitmapImageRep, which must be released. + * + *---------------------------------------------------------------------- + */ +NSBitmapImageRep* +BitmapRepFromDrawableRect( + MacDrawable *drawable, + int x, + int y, + unsigned int width, + unsigned int height) +{ + CGImageRef cg_image=NULL, sub_cg_image=NULL; + NSBitmapImageRep *bitmap_rep=NULL; + NSView *view=NULL; + + if ( drawable->flags & TK_IS_PIXMAP && drawable->context) { + /* This means that the MacDrawable is functioning as a Tk Pixmap, so its view + field is NULL and its context field points to a CGBitmapContext. + */ + CGRect image_rect = CGRectMake(x, y, width, height); + cg_image = CGBitmapContextCreateImage( (CGContextRef) drawable->context); + sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect); + if ( sub_cg_image ) { + bitmap_rep = [NSBitmapImageRep alloc]; + [bitmap_rep initWithCGImage:sub_cg_image]; + CGImageRelease(sub_cg_image); + } + if ( cg_image ) { + CGImageRelease(cg_image); + } + } else if ( (view = TkMacOSXDrawableView(drawable)) ) { + /* convert top-left coordinates to NSView coordinates */ + int view_height = [view bounds].size.height; + NSRect view_rect = NSMakeRect(x + drawable->xOff, + view_height - height - y - drawable->yOff, + width,height); + bitmap_rep = [NSBitmapImageRep alloc]; + [view lockFocus]; + [bitmap_rep initWithFocusedViewRect:view_rect]; + [view unlockFocus]; + } else { + TkMacOSXDbgMsg("Invalid source drawable"); + } + + return bitmap_rep; +} + +/* + *---------------------------------------------------------------------- + * * XCopyArea -- * * Copies data from one drawable to another using block transfer @@ -133,86 +197,45 @@ XCopyArea( Display *display, /* Display. */ Drawable src, /* Source drawable. */ Drawable dst, /* Destination drawable. */ - GC gc, /* GC to use. */ + GC gc, /* GC to use. */ int src_x, /* X & Y, width & height */ int src_y, /* define the source rectangle */ - unsigned int width, /* that will be copied. */ + unsigned int width, /* that will be copied. */ unsigned int height, int dest_x, /* Dest X & Y on dest rect. */ int dest_y) { TkMacOSXDrawingContext dc; MacDrawable *srcDraw = (MacDrawable *) src; + NSBitmapImageRep *bitmap_rep = NULL; display->request++; if (!width || !height) { - /* TkMacOSXDbgMsg("Drawing of emtpy area requested"); */ + /* TkMacOSXDbgMsg("Drawing of empty area requested"); */ return; } - if (srcDraw->flags & TK_IS_PIXMAP) { - if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - return; - } - if (dc.context) { - CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src); - - if (img) { - DrawCGImage(dst, gc, dc.context, img, gc->foreground, - gc->background, CGRectMake(0, 0, - srcDraw->size.width, srcDraw->size.height), - CGRectMake(src_x, src_y, width, height), - CGRectMake(dest_x, dest_y, width, height)); - CFRelease(img); - } else { - TkMacOSXDbgMsg("Invalid source drawable"); - } - } else { - TkMacOSXDbgMsg("Invalid destination drawable"); - } - TkMacOSXRestoreDrawingContext(&dc); - } else if (TkMacOSXDrawableWindow(src)) { - NSView *view = TkMacOSXDrawableView(srcDraw); - NSWindow *w = [view window]; - NSInteger gs = [w windowNumber] > 0 ? [w gState] : 0; - /* // alternative using per-view gState: - NSInteger gs = [view gState]; - if (!gs) { - [view allocateGState]; - if ([view lockFocusIfCanDraw]) { - [view unlockFocus]; - } - gs = [view gState]; - } - */ - if (!gs || !TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - return; - } - if (dc.context) { - NSGraphicsContext *gc = nil; - CGFloat boundsH = [view bounds].size.height; - NSRect srcRect = NSMakeRect(srcDraw->xOff + src_x, boundsH - - height - (srcDraw->yOff + src_y), width, height); - - if (((MacDrawable *) dst)->flags & TK_IS_PIXMAP) { - gc = [NSGraphicsContext graphicsContextWithGraphicsPort: - dc.context flipped:NO]; - if (gc) { - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:gc]; + if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { + TkMacOSXDbgMsg("Invalid destination drawable"); + } + if (dc.context) { + bitmap_rep = BitmapRepFromDrawableRect(srcDraw, src_x, src_y, width, height); + if ( bitmap_rep ) { + CGImageRef img = [bitmap_rep CGImage]; + CGRect image_rect = CGRectMake(0, 0, + srcDraw->size.width, srcDraw->size.height); + if (img) { + DrawCGImage(dst, gc, dc.context, img, gc->foreground, + gc->background, image_rect, + CGRectMake(src_x, src_y, width, height), + CGRectMake(dest_x, dest_y, width, height)); + CFRelease(img); } - } - NSCopyBits(gs, srcRect, NSMakePoint(dest_x, - dc.portBounds.size.height - dest_y)); - if (gc) { - [NSGraphicsContext restoreGraphicsState]; - } - } else { - TkMacOSXDbgMsg("Invalid destination drawable"); + [bitmap_rep release]; + } else { + TkMacOSXDbgMsg("Invalid source drawable"); } - TkMacOSXRestoreDrawingContext(&dc); - } else { - TkMacOSXDbgMsg("Invalid source drawable"); } + TkMacOSXRestoreDrawingContext(&dc); } /* @@ -253,7 +276,7 @@ XCopyPlane( display->request++; if (!width || !height) { - /* TkMacOSXDbgMsg("Drawing of emtpy area requested"); */ + /* TkMacOSXDbgMsg("Drawing of empty area requested"); */ return; } if (plane != 1) { diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 3ad0689..1c174fe 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -228,6 +228,8 @@ MODULE_SCOPE WindowClass TkMacOSXWindowClass(TkWindow *winPtr); MODULE_SCOPE int TkMacOSXIsWindowZoomed(TkWindow *winPtr); MODULE_SCOPE int TkGenerateButtonEventForXPointer(Window window); MODULE_SCOPE EventModifiers TkMacOSXModifierState(void); +MODULE_SCOPE NSBitmapImageRep* BitmapRepFromDrawableRect(MacDrawable *drawable, + int x, int y, unsigned int width, unsigned int height); MODULE_SCOPE int TkMacOSXSetupDrawingContext(Drawable d, GC gc, int useCG, TkMacOSXDrawingContext *dcPtr); MODULE_SCOPE void TkMacOSXRestoreDrawingContext( diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index c235cbf..915dea1 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -1277,7 +1277,7 @@ UpdateOffsets( * Returns a handle to a new pixmap. * * Side effects: - * Allocates a new Macintosh GWorld. + * Allocates a new CGBitmapContext. * *---------------------------------------------------------------------- */ @@ -1323,7 +1323,7 @@ Tk_GetPixmap( * None. * * Side effects: - * Deletes the Macintosh GWorld created by Tk_GetPixmap. + * Deletes the CGBitmapContext created by Tk_GetPixmap. * *---------------------------------------------------------------------- */ diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index 9594cd3..29233d9 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -869,7 +869,7 @@ XCreateImage( * This function copies data from a pixmap or window into an XImage. * * Results: - * Returns a newly allocated image containing the data from the given + * Returns a newly allocated XImage containing the data from the given * rectangle of the given drawable. * * Side effects: @@ -890,59 +890,57 @@ XGetImage( int format) { MacDrawable *macDraw = (MacDrawable *) d; - XImage * imagePtr = NULL; - Pixmap pixmap = (Pixmap) NULL; - Tk_Window win = (Tk_Window) macDraw->winPtr; - GC gc; - char * data = NULL; - int depth = 32; - int offset = 0; - int bitmap_pad = 0; - int bytes_per_line = 0; - + NSBitmapImageRep *bitmap_rep; + XImage * imagePtr = NULL; + char * bitmap = NULL; + char * image_data=NULL; + int depth = 32; + int offset = 0; + int bitmap_pad = 0; + int bytes_per_row = 4*width; + int size; if (format == ZPixmap) { - if (width > 0 && height > 0) { - /* - * Tk_GetPixmap fails for zero width or height. - */ - - pixmap = Tk_GetPixmap(display, d, width, height, depth); + if (width == 0 || height == 0) { + return NULL; } - if (win) { - XGCValues values; - gc = Tk_GetGC(win, 0, &values); - } else { - gc = XCreateGC(display, pixmap, 0, NULL); - } - if (pixmap) { - CGContextRef context; - - XCopyArea(display, d, pixmap, gc, x, y, width, height, 0, 0); - context = ((MacDrawable *) pixmap)->context; - if (context) { - data = CGBitmapContextGetData(context); - bytes_per_line = CGBitmapContextGetBytesPerRow(context); + bitmap_rep = BitmapRepFromDrawableRect(macDraw, x, y,width, height); + NSSize image_size = NSMakeSize(width, height); + NSImage* ns_image = [[NSImage alloc]initWithSize:image_size]; + [ns_image addRepresentation:bitmap_rep]; + + /* Assume premultiplied nonplanar data with 4 bytes per pixel and alpha last.*/ + if ( [bitmap_rep bitmapFormat] == 0 && + [bitmap_rep isPlanar ] == 0 && + [bitmap_rep samplesPerPixel] == 4 ) { + bytes_per_row = [bitmap_rep bytesPerRow]; + size = bytes_per_row*height; + image_data = (char*)[bitmap_rep bitmapData]; + if ( image_data ) { + int row, n, m; + bitmap = ckalloc(size); + /* + Oddly enough, the bitmap has the top row at the beginning, + and the pixels are in BGRA format. + */ + for (row=0, n=0; row<height; row++, n+=bytes_per_row) { + for (m=n; m<n+bytes_per_row; m+=4) { + *(bitmap+m) = *(image_data+m+2); + *(bitmap+m+1) = *(image_data+m+1); + *(bitmap+m+2) = *(image_data+m); + *(bitmap+m+3) = *(image_data+m+3); + } + } } } - if (data) { + if (bitmap) { imagePtr = XCreateImage(display, NULL, depth, format, offset, - data, width, height, bitmap_pad, bytes_per_line); - - /* - * Track Pixmap underlying the XImage in the unused obdata field - * so that we can treat XImages coming from XGetImage specially. - */ - - imagePtr->obdata = (XPointer) pixmap; - } else if (pixmap) { - Tk_FreePixmap(display, pixmap); - } - if (!win) { - XFreeGC(display, gc); + (char*)bitmap, width, height, bitmap_pad, bytes_per_row); + [ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/ + [ns_image release]; } } else { - TkMacOSXDbgMsg("Invalid image format"); + TkMacOSXDbgMsg("Could not extract image from drawable."); } return imagePtr; } |