From 565d2e1389b0a72e6eca7068988a9312991abfb1 Mon Sep 17 00:00:00 2001 From: elektrahesse Date: Sat, 9 Oct 2010 19:05:40 +0200 Subject: Mac Only: Implemented initial CoreGraphics image decoding to support uploads, both single and bulk, bypassing viewer's internal decoding classes and using osx native frameworks. Also pushing non-fully-working-yet (and thus disabled) code for native j2c decoding. --- linden/indra/llcommon/stdtypes.h | 9 +- linden/indra/llimagej2coj/CMakeLists.txt | 19 ++- linden/indra/llimagej2coj/llimagej2cquartz.h | 9 ++ linden/indra/llimagej2coj/llimagej2cquartz.mm | 147 +++++++++++++++++++++++ linden/indra/llwindow/llwindowmacosx-objc.h | 10 ++ linden/indra/llwindow/llwindowmacosx-objc.mm | 60 +++++++++ linden/indra/newview/floaterlocalassetbrowse.cpp | 11 ++ linden/indra/newview/llfloaterimagepreview.cpp | 12 +- linden/indra/newview/llviewerimagelist.cpp | 11 +- 9 files changed, 282 insertions(+), 6 deletions(-) create mode 100644 linden/indra/llimagej2coj/llimagej2cquartz.h create mode 100644 linden/indra/llimagej2coj/llimagej2cquartz.mm (limited to 'linden') diff --git a/linden/indra/llcommon/stdtypes.h b/linden/indra/llcommon/stdtypes.h index af0b4dd..aed1e46 100644 --- a/linden/indra/llcommon/stdtypes.h +++ b/linden/indra/llcommon/stdtypes.h @@ -64,10 +64,17 @@ typedef long long unsigned int U64; #endif #endif +#ifdef LL_DARWIN + #ifndef BOOL + #define BOOL S32 + #endif +#else + typedef S32 BOOL; +#endif + typedef float F32; typedef double F64; -typedef S32 BOOL; typedef U8 KEY; typedef U32 MASK; typedef U32 TPACKETID; diff --git a/linden/indra/llimagej2coj/CMakeLists.txt b/linden/indra/llimagej2coj/CMakeLists.txt index 97d22cf..30f73ab 100644 --- a/linden/indra/llimagej2coj/CMakeLists.txt +++ b/linden/indra/llimagej2coj/CMakeLists.txt @@ -19,10 +19,26 @@ set(llimagej2coj_SOURCE_FILES set(llimagej2coj_HEADER_FILES CMakeLists.txt - llimagej2coj.h ) +set(COREIMAGE_LIBRARIES) + +if (DARWIN) + list(APPEND llimagej2coj_SOURCE_FILES + llimagej2cquartz.mm + ) + list(APPEND llimagej2coj_HEADER_FILES + llimagej2cquartz.h + ) + + find_library(QUARTZCORE_LIBRARY QuartzCore) + find_library(ACCELERATE_LIBRARY Accelerate) + + list(APPEND COREIMAGE_LIBRARIES ${QUARTZCORE_LIBRARY}) + list(APPEND COREIMAGE_LIBRARIES ${ACCELERATE_LIBRARY}) +endif (DARWIN) + set_source_files_properties(${llimagej2coj_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) @@ -32,4 +48,5 @@ add_library (llimagej2coj ${llimagej2coj_SOURCE_FILES}) target_link_libraries( llimagej2coj ${OPENJPEG_LIBRARIES} + ${COREIMAGE_LIBRARIES} ) diff --git a/linden/indra/llimagej2coj/llimagej2cquartz.h b/linden/indra/llimagej2coj/llimagej2cquartz.h new file mode 100644 index 0000000..ba11bfd --- /dev/null +++ b/linden/indra/llimagej2coj/llimagej2cquartz.h @@ -0,0 +1,9 @@ +#include "llimagej2c.h" + +#ifdef __OBJC__ + #ifdef BOOL + #undef BOOL + #endif +#endif // __OBJC__ + +BOOL decodeJ2CQuartz(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count); \ No newline at end of file diff --git a/linden/indra/llimagej2coj/llimagej2cquartz.mm b/linden/indra/llimagej2coj/llimagej2cquartz.mm new file mode 100644 index 0000000..d5eefd1 --- /dev/null +++ b/linden/indra/llimagej2coj/llimagej2cquartz.mm @@ -0,0 +1,147 @@ +#import <Accelerate/Accelerate.h> +#import <QuartzCore/QuartzCore.h> +#import <Quartz/Quartz.h> + +#include "llimagej2cquartz.h" + +#if defined(__BIG_ENDIAN__) + CGImageAlphaInfo const kDefaultAlphaLocation = kCGImageAlphaPremultipliedLast; +#else + CGImageAlphaInfo const kDefaultAlphaLocation = kCGImageAlphaPremultipliedFirst; +#endif + +BOOL decodeJ2CQuartz(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) +{ + U8 *srcData = (U8*)base.getData(); + int srcLen = base.getDataSize(); + + llinfos << "[1] compressed image size: '" << srcLen << "'" << llendl; + + int width = base.getWidth(); + int height = base.getHeight(); + int components = base.getComponents(); + + S32 channels = components - first_channel; + if( channels > max_channel_count ) + channels = max_channel_count; + + llinfos << "[2] components: '" << components << "' - channels: '" << channels << "' - first_channel: '" << first_channel << "' - max_channel_count: '" << max_channel_count << "'" << llendl; + + if(components <= first_channel || components > 4) + return FALSE; + + llinfos << "[3] attempting to decode a texture: '" << width << "'X'" << height << "'@'" << components * 8 << "'" << llendl; + + U8 *tgt = (U8*)raw_image.getData(); + if (!tgt) + return FALSE; + + raw_image.resize(width, height, channels); + + size_t rowBytes = width * components; + int realLen = width * height * components; + + llinfos << "[4] allocating buffer of size: '" << realLen << "' to hold temp texture data" << llendl; + unsigned char* dataplane; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSBitmapImageRep *rep = [NSBitmapImageRep alloc]; + + switch (components) + { + case 1: + { + rep = [[rep + initWithBitmapDataPlanes:nil + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:1 + hasAlpha:NO + isPlanar:NO + colorSpaceName:NSDeviceWhiteColorSpace + bytesPerRow:rowBytes + bitsPerPixel:8 + ] autorelease]; + + memcpy([rep bitmapData], srcData, srcLen); + + dataplane = (unsigned char*)malloc(realLen); + memcpy(dataplane, [rep bitmapData], realLen); + + [rep release]; + } + break; + + case 3: + { + NSData *data = [NSData dataWithBytes:srcData length:srcLen]; + rep = [rep initWithData:data]; + + dataplane = (unsigned char*)malloc(realLen); + memcpy(dataplane, [rep bitmapData], realLen); + + [data release]; + [rep release]; + } + break; + + case 4: + { + NSData *data = [NSData dataWithBytes:srcData length:srcLen]; + rep = [rep initWithData:data]; + + int imgLen = [rep pixelsHigh] * [rep bytesPerRow]; + if (imgLen != realLen) + { + llwarns << "decoded image buffer size (" << imgLen << ") != expected buffer size (" << realLen << ") !" << llendl; + [rep release]; + [data release]; + return FALSE; + } + + dataplane = (unsigned char*)malloc(realLen); + memcpy(dataplane, [rep bitmapData], realLen); + + vImage_Buffer vb; + vb.data = dataplane; + vb.height = [rep pixelsHigh]; + vb.width = [rep pixelsWide]; + vb.rowBytes = [rep bytesPerRow]; + + llinfos << "Attempting Alpha Unpremultiplication" << llendl; + vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0); + llinfos << "Unpremultiplied Alpha" << llendl; + + llwarns << "after decoding: " << [rep pixelsWide] << "'X'" << [rep pixelsHigh] << "'@'" << [rep bitsPerPixel] << "'" << llendl; + + [rep release]; + [data release]; + } + break; + } + + if (dataplane) + { + for (int h=height-1; h>=0; h--) + { + for (int w=0; w<rowBytes; w+=(first_channel + channels)) + { + for (int c=first_channel; c<(first_channel + channels); c++) + memcpy(tgt++, &dataplane[h*rowBytes + w + c], sizeof(unsigned char)); + } + } + + free(dataplane); + + llinfos << "[5] size of decoded image is: '" << width*height*channels << "'" << llendl; + + return TRUE; + } + else + { + llwarns << "[5] cannot decode image !" << llendl; + } + + return FALSE; +} diff --git a/linden/indra/llwindow/llwindowmacosx-objc.h b/linden/indra/llwindow/llwindowmacosx-objc.h index 14cddaa..14c9c92 100644 --- a/linden/indra/llwindow/llwindowmacosx-objc.h +++ b/linden/indra/llwindow/llwindowmacosx-objc.h @@ -31,6 +31,14 @@ * $/LicenseInfo$ */ +#include "llimagej2c.h" +#include <Carbon/Carbon.h> + +#ifdef __OBJC__ +#ifdef BOOL +#undef BOOL +#endif +#endif // __OBJC__ // This will actually hold an NSCursor*, but that type is only available in objective C. typedef void *CursorRef; @@ -40,3 +48,5 @@ void setupCocoa(); CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY); OSErr releaseImageCursor(CursorRef ref); OSErr setImageCursor(CursorRef ref); +BOOL decodeImageQuartz(std::string filename, LLImageRaw *raw_image); +BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image); diff --git a/linden/indra/llwindow/llwindowmacosx-objc.mm b/linden/indra/llwindow/llwindowmacosx-objc.mm index bc47164..5f33764 100644 --- a/linden/indra/llwindow/llwindowmacosx-objc.mm +++ b/linden/indra/llwindow/llwindowmacosx-objc.mm @@ -32,6 +32,8 @@ */ #include <AppKit/AppKit.h> +#include <Accelerate/Accelerate.h> +#include <Quartz/Quartz.h> /* * These functions are broken out into a separate file because the @@ -42,6 +44,64 @@ #include "llwindowmacosx-objc.h" +BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image) +{ + CFDataRef theData = CFDataCreate(kCFAllocatorDefault, data, len); + CGImageSourceRef srcRef = CGImageSourceCreateWithData(theData, NULL); + CGImageRef image_ref = CGImageSourceCreateImageAtIndex(srcRef, 0, NULL); + + size_t width = CGImageGetWidth(image_ref); + size_t height = CGImageGetHeight(image_ref); + size_t comps = CGImageGetBitsPerPixel(image_ref) / 8; + size_t bytes_per_row = CGImageGetBytesPerRow(image_ref); + CFDataRef result = CGDataProviderCopyData(CGImageGetDataProvider(image_ref)); + UInt8* bitmap = (UInt8*)CFDataGetBytePtr(result); + + CGImageAlphaInfo format = CGImageGetAlphaInfo(image_ref); + if (format & kCGImageAlphaPremultipliedFirst) + { + vImage_Buffer vb; + vb.data = bitmap; + vb.height = height; + vb.width = width; + vb.rowBytes = bytes_per_row; + llinfos << "Unpremultiplying ARGB888" << llendl; + vImageUnpremultiplyData_ARGB8888(&vb, &vb, 0); + } + else if (format & kCGImageAlphaPremultipliedLast) + { + vImage_Buffer vb; + vb.data = bitmap; + vb.height = height; + vb.width = width; + vb.rowBytes = bytes_per_row; + llinfos << "Unpremultiplying RGBA888" << llendl; + vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0); + } + + raw_image->resize(width, height, comps); + llinfos << "Decoding an image of width: " << width << " and height: " << height << " and components: " << comps << llendl; + memcpy(raw_image->getData(), bitmap, height * bytes_per_row); + raw_image->verticalFlip(); + + CFRelease(theData); + CFRelease(srcRef); + CGImageRelease(image_ref); + CFRelease(result); + + return TRUE; +} + +BOOL decodeImageQuartz(std::string filename, LLImageRaw *raw_image) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSURL *url = [[NSURL alloc] initFileURLWithPath:[NSString stringWithCString:filename.c_str()]]; + NSData *data = [NSData dataWithContentsOfURL:url]; + BOOL result = decodeImageQuartz((UInt8*)[data bytes], [data length], raw_image); + [pool release]; + return result; +} + void setupCocoa() { static bool inited = false; diff --git a/linden/indra/newview/floaterlocalassetbrowse.cpp b/linden/indra/newview/floaterlocalassetbrowse.cpp index 6564528..443b5bf 100644 --- a/linden/indra/newview/floaterlocalassetbrowse.cpp +++ b/linden/indra/newview/floaterlocalassetbrowse.cpp @@ -74,6 +74,9 @@ this feature is still a work in progress. #include "llvovolume.h" #include "llface.h" +#ifdef LL_DARWIN +#include "llwindowmacosx-objc.h" +#endif /*=======================================*/ /* Instantiating manager class */ @@ -227,6 +230,13 @@ void LocalBitmap::updateSelf() bool LocalBitmap::decodeSelf(LLImageRaw* rawimg) { +#ifdef LL_DARWIN + if (decodeImageQuartz(filename, rawimg)) + { + rawimg->biasedScaleToPowerOfTwo( LLViewerImage::MAX_IMAGE_SIZE_DEFAULT ); + return true; + } +#else switch (this->extension) { case IMG_EXTEN_BMP: @@ -275,6 +285,7 @@ bool LocalBitmap::decodeSelf(LLImageRaw* rawimg) default: break; } +#endif return false; } diff --git a/linden/indra/newview/llfloaterimagepreview.cpp b/linden/indra/newview/llfloaterimagepreview.cpp index 9827a31..c81081f 100644 --- a/linden/indra/newview/llfloaterimagepreview.cpp +++ b/linden/indra/newview/llfloaterimagepreview.cpp @@ -62,6 +62,10 @@ #include "hippoGridManager.h" +#ifdef LL_DARWIN +#include "llwindowmacosx-objc.h" +#endif + //static S32 LLFloaterImagePreview::sUploadAmount = 10; @@ -353,7 +357,10 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) } LLPointer<LLImageRaw> raw_image = new LLImageRaw; - +#ifdef LL_DARWIN + if (! decodeImageQuartz(src_filename, raw_image)) + return false; +#else switch (codec) { case IMG_CODEC_BMP: @@ -428,8 +435,9 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) } raw_image->biasedScaleToPowerOfTwo(1024); +#endif + mRawImagep = raw_image; - return true; } diff --git a/linden/indra/newview/llviewerimagelist.cpp b/linden/indra/newview/llviewerimagelist.cpp index cb02b09..869c9d7 100644 --- a/linden/indra/newview/llviewerimagelist.cpp +++ b/linden/indra/newview/llviewerimagelist.cpp @@ -65,6 +65,10 @@ #include <sys/stat.h> +#ifdef LL_DARWIN +#include "llwindowmacosx-objc.h" +#endif + //////////////////////////////////////////////////////////////////////////// void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL; @@ -920,7 +924,10 @@ BOOL LLViewerImageList::createUploadFile(const std::string& filename, { // First, load the image. LLPointer<LLImageRaw> raw_image = new LLImageRaw; - +#ifdef LL_DARWIN + if (!decodeImageQuartz(filename, raw_image)) + return FALSE; +#else switch (codec) { case IMG_CODEC_BMP: @@ -993,7 +1000,7 @@ BOOL LLViewerImageList::createUploadFile(const std::string& filename, default: return FALSE; } - +#endif LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image); if( !compressedImage->save(out_filename) ) -- cgit v1.1