diff options
author | culler <culler> | 2017-11-08 17:43:14 (GMT) |
---|---|---|
committer | culler <culler> | 2017-11-08 17:43:14 (GMT) |
commit | ad660115aaeb3951cc4a1db16d6c6edcb5efa132 (patch) | |
tree | ba629df9ebb727b789b67ea49e19d29dbce481d1 /macosx/tkMacOSXImage.c | |
parent | 4e4fcc895c376f3a97ddd743e6c95182429cf758 (diff) | |
download | tk-ad660115aaeb3951cc4a1db16d6c6edcb5efa132.zip tk-ad660115aaeb3951cc4a1db16d6c6edcb5efa132.tar.gz tk-ad660115aaeb3951cc4a1db16d6c6edcb5efa132.tar.bz2 |
Reorganization to put all code related to Ximages in the new
file tkMacOSXImage.c
Diffstat (limited to 'macosx/tkMacOSXImage.c')
-rw-r--r-- | macosx/tkMacOSXImage.c | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/macosx/tkMacOSXImage.c b/macosx/tkMacOSXImage.c new file mode 100644 index 0000000..ac842f9 --- /dev/null +++ b/macosx/tkMacOSXImage.c @@ -0,0 +1,559 @@ +/* + * tkMacOSXImage.c -- + * + * The code in this file provides an interface for XImages, + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright 2017 Marc Culler. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tkMacOSXPrivate.h" +#include "xbytes.h" + +#pragma mark XImage handling + +int +_XInitImageFuncPtrs( + XImage *image) +{ + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXCreateCGImageWithXImage -- + * + * Create CGImage from XImage, copying the image data. + * + * Results: + * CGImage, release after use. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void ReleaseData(void *info, const void *data, size_t size) { + ckfree(info); +} + +CGImageRef +TkMacOSXCreateCGImageWithXImage( + XImage *image) +{ + CGImageRef img = NULL; + size_t bitsPerComponent, bitsPerPixel; + size_t len = image->bytes_per_line * image->height; + const CGFloat *decode = NULL; + CGBitmapInfo bitmapInfo; + CGDataProviderRef provider = NULL; + char *data = NULL; + CGDataProviderReleaseDataCallback releaseData = ReleaseData; + + if (image->bits_per_pixel == 1) { + /* + * BW image + */ + + /* Reverses the sense of the bits */ + static const CGFloat decodeWB[2] = {1, 0}; + decode = decodeWB; + + bitsPerComponent = 1; + bitsPerPixel = 1; + if (image->bitmap_bit_order != MSBFirst) { + char *srcPtr = image->data + image->xoffset; + char *endPtr = srcPtr + len; + char *destPtr = (data = ckalloc(len)); + + while (srcPtr < endPtr) { + *destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))]; + } + } else { + data = memcpy(ckalloc(len), image->data + image->xoffset, len); + } + if (data) { + provider = CGDataProviderCreateWithData(data, data, len, releaseData); + } + if (provider) { + img = CGImageMaskCreate(image->width, image->height, bitsPerComponent, + bitsPerPixel, image->bytes_per_line, provider, decode, 0); + } + } else if (image->format == ZPixmap && image->bits_per_pixel == 32) { + /* + * Color image + */ + + CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); + + bitsPerComponent = 8; + bitsPerPixel = 32; + bitmapInfo = (image->byte_order == MSBFirst ? + kCGBitmapByteOrder32Big : kCGBitmapByteOrder32Little) | + kCGImageAlphaNoneSkipFirst; + data = memcpy(ckalloc(len), image->data + image->xoffset, len); + if (data) { + provider = CGDataProviderCreateWithData(data, data, len, releaseData); + } + if (provider) { + img = CGImageCreate(image->width, image->height, bitsPerComponent, + bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo, + provider, decode, 0, kCGRenderingIntentDefault); + CFRelease(provider); + } + if (colorspace) { + CFRelease(colorspace); + } + } else { + TkMacOSXDbgMsg("Unsupported image type"); + } + return img; +} + + +/* + *---------------------------------------------------------------------- + * + * XGetImage -- + * + * This function copies data from a pixmap or window into an XImage. + * + * Results: + * Returns a newly allocated XImage containing the data from the given + * rectangle of the given drawable, or NULL if the XImage could not be + * constructed. NOTE: If we are copying from a window on a Retina + * display, the dimensions of the XImage will be 2*width x 2*height. + * + * 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) +{ + NSBitmapImageRep *bitmap_rep; + NSUInteger bitmap_fmt; + 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; + int scalefactor = 1; +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + NSWindow *win = TkMacOSXDrawableWindow(d); + /* This code assumes that backing scale factors are integers. Currently + * Retina displays use a scale factor of 2.0 and normal displays use 1.0. + * We do not support any other values here. + */ + if (win && [win respondsToSelector:@selector(backingScaleFactor)]) { + scalefactor = ([win backingScaleFactor] == 2.0) ? 2 : 1; + } +#endif + int scaled_height = height * scalefactor; + int scaled_width = width * scalefactor; + + if (format == ZPixmap) { + if (width == 0 || height == 0) { + /* This happens all the time. + TkMacOSXDbgMsg("XGetImage: empty image requested"); + */ + return NULL; + } + + bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(d, x, y, width, height); + bitmap_fmt = [bitmap_rep bitmapFormat]; + + if ( bitmap_rep == Nil || + (bitmap_fmt != 0 && bitmap_fmt != 1) || + [bitmap_rep samplesPerPixel] != 4 || + [bitmap_rep isPlanar] != 0 ) { + TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep"); + return NULL; + } + + 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.*/ + if ( [bitmap_rep isPlanar ] == 0 && + [bitmap_rep samplesPerPixel] == 4 ) { + bytes_per_row = [bitmap_rep bytesPerRow]; + assert(bytes_per_row == 4 * scaled_width); + assert([bitmap_rep bytesPerPlane] == bytes_per_row * scaled_height); + size = bytes_per_row*scaled_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 or ABGR format. + */ + if (bitmap_fmt == 0) { + /* BGRA */ + for (row=0, n=0; row<scaled_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); + } + } + } else { + /* ABGR */ + for (row=0, n=0; row<scaled_height; row++, n+=bytes_per_row) { + for (m=n; m<n+bytes_per_row; m+=4) { + *(bitmap+m) = *(image_data+m+3); + *(bitmap+m+1) = *(image_data+m+2); + *(bitmap+m+2) = *(image_data+m+1); + *(bitmap+m+3) = *(image_data+m); + } + } + } + } + } + if (bitmap) { + imagePtr = XCreateImage(display, NULL, depth, format, offset, + (char*)bitmap, scaled_width, scaled_height, + bitmap_pad, bytes_per_row); + if (scalefactor == 2) { + imagePtr->pixelpower = 1; + } + [ns_image removeRepresentation:bitmap_rep]; /*releases the rep*/ + [ns_image release]; + } + } else { + TkMacOSXDbgMsg("Could not extract image from drawable."); + } + return imagePtr; +} + +/* + *---------------------------------------------------------------------- + * + * DestroyImage -- + * + * Destroys storage associated with an image. + * + * Results: + * None. + * + * Side effects: + * Deallocates the image. + * + *---------------------------------------------------------------------- + */ + +static int +DestroyImage( + XImage *image) +{ + if (image) { + if (image->data) { + ckfree(image->data); + } + ckfree(image); + } + 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 char r = 0, g = 0, b = 0; + + if (image && image->data) { + unsigned char *srcPtr = ((unsigned char*) image->data) + + (y * image->bytes_per_line) + + (((image->xoffset + x) * image->bits_per_pixel) / NBBY); + + switch (image->bits_per_pixel) { + case 32: { + 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: + r = (*((unsigned short*) srcPtr) >> 7) & 0xf8; + g = (*((unsigned short*) srcPtr) >> 2) & 0xf8; + b = (*((unsigned short*) srcPtr) << 3) & 0xf8; + break; + case 8: + r = (*srcPtr << 2) & 0xc0; + g = (*srcPtr << 4) & 0xc0; + b = (*srcPtr << 6) & 0xc0; + r |= r >> 2 | r >> 4 | r >> 6; + g |= g >> 2 | g >> 4 | g >> 6; + b |= b >> 2 | b >> 4 | b >> 6; + break; + case 4: { + unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4); + r = (c & 0x04) ? 0xff : 0; + g = (c & 0x02) ? 0xff : 0; + b = (c & 0x01) ? 0xff : 0; + break; + } + case 1: + r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0; + break; + } + } + return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b; +} + +/* + *---------------------------------------------------------------------- + * + * ImagePutPixel -- + * + * Set a single pixel in an image. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ImagePutPixel( + XImage *image, + int x, + int y, + unsigned long pixel) +{ + if (image && image->data) { + 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; + unsigned char *dstPtr = ((unsigned char*) image->data) + + (y * image->bytes_per_line) + + (((image->xoffset + x) * image->bits_per_pixel) / NBBY); + + switch (image->bits_per_pixel) { + case 32: + *((unsigned int*) dstPtr) = (0xff << 24) | (r << 16) | + (g << 8) | b; + /*if (image->byte_order == LSBFirst) { + dstPtr[3] = 0xff; dstPtr[2] = r; dstPtr[1] = g; dstPtr[0] = b; + } else { + dstPtr[0] = 0xff; dstPtr[1] = r; dstPtr[2] = g; dstPtr[3] = b; + }*/ + break; + case 16: + *((unsigned short*) dstPtr) = ((r & 0xf8) << 7) | + ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); + break; + case 8: + *dstPtr = ((r & 0xc0) >> 2) | ((g & 0xc0) >> 4) | + ((b & 0xc0) >> 6); + break; + case 4: { + 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 = ((r|g|b) & 0x80) ? (*dstPtr | (0x80 >> (x % 8))) : + (*dstPtr & ~(0x80 >> (x % 8))); + 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 *ximage; + display->request++; + ximage = ckalloc(sizeof(XImage)); + + ximage->height = height; + ximage->width = width; + ximage->depth = depth; + ximage->xoffset = offset; + ximage->format = format; + ximage->data = data; + ximage->obdata = NULL; + /* The default pixelpower is 0. This must be explicitly set to 1 in the + * case of an XImage extracted from a Retina display. + */ + ximage->pixelpower = 0; + + if (format == ZPixmap) { + ximage->bits_per_pixel = 32; + ximage->bitmap_unit = 32; + } else { + ximage->bits_per_pixel = 1; + ximage->bitmap_unit = 8; + } + if (bitmap_pad) { + ximage->bitmap_pad = bitmap_pad; + } else { + /* Use 16 byte alignment for best Quartz perfomance */ + ximage->bitmap_pad = 128; + } + if (bytes_per_line) { + ximage->bytes_per_line = bytes_per_line; + } else { + ximage->bytes_per_line = ((width * ximage->bits_per_pixel + + (ximage->bitmap_pad - 1)) >> 3) & + ~((ximage->bitmap_pad >> 3) - 1); + } +#ifdef WORDS_BIGENDIAN + ximage->byte_order = MSBFirst; + ximage->bitmap_bit_order = MSBFirst; +#else + ximage->byte_order = LSBFirst; + ximage->bitmap_bit_order = LSBFirst; +#endif + ximage->red_mask = 0x00FF0000; + ximage->green_mask = 0x0000FF00; + ximage->blue_mask = 0x000000FF; + ximage->f.create_image = NULL; + ximage->f.destroy_image = DestroyImage; + ximage->f.get_pixel = ImageGetPixel; + ximage->f.put_pixel = ImagePutPixel; + ximage->f.sub_image = NULL; + ximage->f.add_pixel = NULL; + + return ximage; +} + +/* + *---------------------------------------------------------------------- + * + * TkPutImage -- + * + * Copies a subimage from an in-memory image to a rectangle of + * of the specified drawable. + * + * Results: + * None. + * + * Side effects: + * Draws the image on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +int +TkPutImage( + unsigned long *colors, /* Unused on Macintosh. */ + int ncolors, /* Unused on Macintosh. */ + Display* display, /* Display. */ + Drawable d, /* Drawable to place image on. */ + GC gc, /* GC to use. */ + XImage* image, /* Image to place. */ + int src_x, /* Source X & Y. */ + int src_y, + int dest_x, /* Destination X & Y. */ + int dest_y, + unsigned int width, /* Same width & height for both */ + unsigned int height) /* distination and source. */ +{ + TkMacOSXDrawingContext dc; + + display->request++; + if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + return BadDrawable; + } + if (dc.context) { + CGImageRef img = TkMacOSXCreateCGImageWithXImage(image); + + if (img) { + /* If the XImage has big pixels, rescale the source dimensions.*/ + int pp = image->pixelpower; + TkMacOSXDrawCGImage(d, gc, dc.context, + img, gc->foreground, gc->background, + CGRectMake(0, 0, image->width<<pp, image->height<<pp), + CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp), + CGRectMake(dest_x, dest_y, width, height)); + CFRelease(img); + } else { + TkMacOSXDbgMsg("Invalid source drawable"); + } + } else { + TkMacOSXDbgMsg("Invalid destination drawable"); + } + TkMacOSXRestoreDrawingContext(&dc); + return Success; +} + |