diff --git a/src/osgPlugins/imageio/ReaderWriterImageIO_IOS.cpp b/src/osgPlugins/imageio/ReaderWriterImageIO_IOS.cpp index 13657c290..1a175f8fd 100755 --- a/src/osgPlugins/imageio/ReaderWriterImageIO_IOS.cpp +++ b/src/osgPlugins/imageio/ReaderWriterImageIO_IOS.cpp @@ -13,7 +13,123 @@ #import #import #import -//#include "CoreGraphicsLoader.h" +#import + +/************************************************************** + ***** Begin Callback functions for istream block reading ***** + **************************************************************/ + +// This callback reads some bytes from an istream and copies it +// to a Quartz buffer (supplied by Apple framework). +size_t MyProviderGetBytesCallback(void* istream_userdata, void* quartz_buffer, size_t the_count) +{ + std::istream* the_istream = (std::istream*)istream_userdata; + the_istream->read((char*)quartz_buffer, the_count); + return the_istream->gcount(); // return the actual number of bytes read +} + +// This callback is triggered when the data provider is released +// so you can clean up any resources. +void MyProviderReleaseInfoCallback(void* istream_userdata) +{ + // What should I put here? Do I need to close the istream? + // The png and tga don't seem to. + // std::istream* the_istream = (std::istream*)istream_userdata; +} + +void MyProviderRewindCallback(void* istream_userdata) +{ + std::istream* the_istream = (std::istream*)istream_userdata; + the_istream->seekg(0, std::ios::beg); +} + +off_t MyProviderSkipForwardBytesCallback(void* istream_userdata, off_t the_count) +{ + std::istream* the_istream = (std::istream*)istream_userdata; + off_t start_position = the_istream->tellg(); + the_istream->seekg(the_count, std::ios::cur); + off_t end_position = the_istream->tellg(); + return (end_position - start_position); +} + +/************************************************************** + ***** End Callback functions for istream block reading ******** + **************************************************************/ + + +/************************************************************** + ***** Begin Callback functions for ostream block writing ****** + **************************************************************/ +size_t MyConsumerPutBytesCallback(void* ostream_userdata, const void* quartz_buffer, size_t the_count) +{ + std::ostream* the_ostream = (std::ostream*)ostream_userdata; + the_ostream->write((char*)quartz_buffer, the_count); + // Don't know how to get number of bytes actually written, so + // just returning the_count. + return the_count; +} + +void MyConsumerReleaseInfoCallback(void* ostream_userdata) +{ + std::ostream* the_ostream = (std::ostream*)ostream_userdata; + the_ostream->flush(); +} +/************************************************************** + ***** End Callback functions for ostream block writing ******** + **************************************************************/ + + +/************************************************************** + ***** Begin Support functions for reading (stream and file) *** + **************************************************************/ + +/* Create a CGImageSourceRef from raw data */ +CGImageRef CreateCGImageFromDataStream(std::istream& fin) +{ + CGImageRef image_ref = NULL; + CGImageSourceRef source_ref; + /* The easy way would be to use CGImageSourceCreateWithData, + * but this presumes you have a known fixed-length buffer of data. + * The istream makes this harder to know, so we use the ProviderCallbacks APIs + CFDataRef the_cf_data = CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, + (const UInt8*)the_data, + CFIndex length, + kCFAllocatorNull // do not free data buffer, must do it yourself + ); + source_ref = CGImageSourceCreateWithData(the_cf_data, NULL); + */ + + CGDataProviderSequentialCallbacks provider_callbacks = + { + 0, + MyProviderGetBytesCallback, + MyProviderSkipForwardBytesCallback, + MyProviderRewindCallback, + MyProviderReleaseInfoCallback + }; + + CGDataProviderRef data_provider = CGDataProviderCreateSequential(&fin, &provider_callbacks); + + // If we had a way of hinting at what the data type is, we could + // pass this hint in the second parameter. + source_ref = CGImageSourceCreateWithDataProvider(data_provider, NULL); + + CGDataProviderRelease(data_provider); + + + if(!source_ref) + { + return NULL; + } + + image_ref = CGImageSourceCreateImageAtIndex(source_ref, 0, NULL); + + /* Don't need the SourceRef any more (error or not) */ + CFRelease(source_ref); + + return image_ref; +} static NSString* toNSString(const std::string& text, NSStringEncoding nsse) { @@ -40,7 +156,6 @@ static NSString* toNSString(const std::string& text) return toNSString(text, NSUTF8StringEncoding); } - // //really basic image io for IOS // @@ -62,6 +177,7 @@ osg::Image* ReadCoreGraphicsImageFromFile(std::string file) if (textureImage == nil) { NSLog(@"imageio: failed to load CGImageRef image '%@'", path ); + [pool release]; return NULL; } @@ -122,13 +238,88 @@ osg::Image* ReadCoreGraphicsImageFromFile(std::string file) pixels += 4; } - + [pool release]; return image; } +osg::Image* CreateOSGImageFromCGImage(CGImageRef textureImage) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + if (textureImage == nil) { + [pool release]; + NSLog(@"imageio: failed to load CGImageRef image"); + return NULL; + } + + + + NSInteger texWidth = CGImageGetWidth(textureImage); + NSInteger texHeight = CGImageGetHeight(textureImage); + + GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4); + + CGContextRef textureContext = CGBitmapContextCreate(textureData, + texWidth, texHeight, + 8, texWidth * 4, + CGColorSpaceCreateDeviceRGB(), + kCGImageAlphaPremultipliedLast); + + + //copy into texturedata + CGContextDrawImage(textureContext, + CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), + textureImage); + CGContextFlush(textureContext); + CGContextRelease(textureContext); + + + //create the osg image + unsigned int dataType = GL_UNSIGNED_BYTE; + int s = texWidth; + int t = texHeight; + + + osg::Image* image = new osg::Image(); + image->setImage(s, t, 1, + GL_RGBA, + GL_RGBA, + GL_UNSIGNED_BYTE, + textureData, + osg::Image::USE_MALLOC_FREE); + + //flip vertical + image->flipVertical(); + + // + // Reverse the premultiplied alpha for avoiding unexpected darker edges + // by Tatsuhiro Nishioka (based on SDL's workaround on the similar issue) + // http://bugzilla.libsdl.org/show_bug.cgi?id=868 + // + + + int i, j; + GLubyte *pixels = (GLubyte *)image->data(); + for (i = image->t() * image->s(); i--; ) { + + GLubyte alpha = pixels[3]; + if (alpha && (alpha < 255)) { + for (j = 0; j < 3; ++j) { + pixels[j] = (static_cast(pixels[j]) * 255) / alpha; + } + } + pixels += 4; + } + + + [pool release]; + return image; + + + +} class ReaderWriterImageIO : public osgDB::ReaderWriter @@ -136,73 +327,73 @@ class ReaderWriterImageIO : public osgDB::ReaderWriter public: ReaderWriterImageIO() { - - supportsExtension("jpg", "jpg image file"); - supportsExtension("jpeg", "jpeg image file"); - supportsExtension("jpe", "jpe image file"); - supportsExtension("jp2", "jp2 image file"); - supportsExtension("tiff", "tiff image file"); - supportsExtension("tif", "tif image file"); - supportsExtension("gif", "gif image file"); - supportsExtension("png", "png image file"); - supportsExtension("pict", "pict image file"); - supportsExtension("pct", "pct image file"); - supportsExtension("pic", "pic image file"); - supportsExtension("bmp", "bmp image file"); - supportsExtension("BMPf", "BMPf image file"); - supportsExtension("ico", "ico image file"); - supportsExtension("icns", "icns image file"); - supportsExtension("tga", "tga image file"); - supportsExtension("targa", "targa image file"); - supportsExtension("psd", "psd image file"); - - supportsExtension("pdf", "pdf image file"); - supportsExtension("eps", "eps image file"); - supportsExtension("epi", "epi image file"); - supportsExtension("epsf", "epsf image file"); - supportsExtension("epsi", "epsi image file"); - supportsExtension("ps", "postscript image file"); - - supportsExtension("dng", "dng image file"); - supportsExtension("cr2", "cr2 image file"); - supportsExtension("crw", "crw image file"); - supportsExtension("fpx", "fpx image file"); - supportsExtension("fpxi", "fpxi image file"); - supportsExtension("raf", "raf image file"); - supportsExtension("dcr", "dcr image file"); - supportsExtension("ptng", "ptng image file"); - supportsExtension("pnt", "pnt image file"); - supportsExtension("mac", "mac image file"); - supportsExtension("mrw", "mrw image file"); - supportsExtension("nef", "nef image file"); - supportsExtension("orf", "orf image file"); - supportsExtension("exr", "exr image file"); - supportsExtension("qti", "qti image file"); - supportsExtension("qtif", "qtif image file"); - supportsExtension("hdr", "hdr image file"); - supportsExtension("sgi", "sgi image file"); - supportsExtension("srf", "srf image file"); - supportsExtension("cur", "cur image file"); - supportsExtension("xbm", "xbm image file"); - - supportsExtension("raw", "raw image file"); + + supportsExtension("jpg", "jpg image file"); + supportsExtension("jpeg", "jpeg image file"); + supportsExtension("jpe", "jpe image file"); + supportsExtension("jp2", "jp2 image file"); + supportsExtension("tiff", "tiff image file"); + supportsExtension("tif", "tif image file"); + supportsExtension("gif", "gif image file"); + supportsExtension("png", "png image file"); + supportsExtension("pict", "pict image file"); + supportsExtension("pct", "pct image file"); + supportsExtension("pic", "pic image file"); + supportsExtension("bmp", "bmp image file"); + supportsExtension("BMPf", "BMPf image file"); + supportsExtension("ico", "ico image file"); + supportsExtension("icns", "icns image file"); + supportsExtension("tga", "tga image file"); + supportsExtension("targa", "targa image file"); + supportsExtension("psd", "psd image file"); + + supportsExtension("pdf", "pdf image file"); + supportsExtension("eps", "eps image file"); + supportsExtension("epi", "epi image file"); + supportsExtension("epsf", "epsf image file"); + supportsExtension("epsi", "epsi image file"); + supportsExtension("ps", "postscript image file"); + + supportsExtension("dng", "dng image file"); + supportsExtension("cr2", "cr2 image file"); + supportsExtension("crw", "crw image file"); + supportsExtension("fpx", "fpx image file"); + supportsExtension("fpxi", "fpxi image file"); + supportsExtension("raf", "raf image file"); + supportsExtension("dcr", "dcr image file"); + supportsExtension("ptng", "ptng image file"); + supportsExtension("pnt", "pnt image file"); + supportsExtension("mac", "mac image file"); + supportsExtension("mrw", "mrw image file"); + supportsExtension("nef", "nef image file"); + supportsExtension("orf", "orf image file"); + supportsExtension("exr", "exr image file"); + supportsExtension("qti", "qti image file"); + supportsExtension("qtif", "qtif image file"); + supportsExtension("hdr", "hdr image file"); + supportsExtension("sgi", "sgi image file"); + supportsExtension("srf", "srf image file"); + supportsExtension("cur", "cur image file"); + supportsExtension("xbm", "xbm image file"); + + supportsExtension("raw", "raw image file"); } - + virtual const char* className() const { return "Mac OS X ImageIO based Image Reader/Writer"; } - - - virtual bool acceptsExtension(const std::string& extension) const - { - // ImageIO speaks in UTIs. - // http://developer.apple.com/graphicsimaging/workingwithimageio.html - // The Cocoa drawing guide lists these and says to use the - // imageFileTypes class method of NSImage to get a complete - // list of extensions. But remember ImageIO may support more formats - // than Cocoa. - // http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Images/chapter_7_section_3.html - // Apple's UTI guide: - // http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/utilist/chapter_4_section_1.html - return + + + virtual bool acceptsExtension(const std::string& extension) const + { + // ImageIO speaks in UTIs. + // http://developer.apple.com/graphicsimaging/workingwithimageio.html + // The Cocoa drawing guide lists these and says to use the + // imageFileTypes class method of NSImage to get a complete + // list of extensions. But remember ImageIO may support more formats + // than Cocoa. + // http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Images/chapter_7_section_3.html + // Apple's UTI guide: + // http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/utilist/chapter_4_section_1.html + return osgDB::equalCaseInsensitive(extension,"jpg") || osgDB::equalCaseInsensitive(extension,"jpeg") || osgDB::equalCaseInsensitive(extension,"jpe") || @@ -221,14 +412,14 @@ public: osgDB::equalCaseInsensitive(extension,"tga") || osgDB::equalCaseInsensitive(extension,"targa") || osgDB::equalCaseInsensitive(extension,"psd") || - + osgDB::equalCaseInsensitive(extension,"pdf") || osgDB::equalCaseInsensitive(extension,"eps") || osgDB::equalCaseInsensitive(extension,"epi") || osgDB::equalCaseInsensitive(extension,"epsf") || osgDB::equalCaseInsensitive(extension,"epsi") || osgDB::equalCaseInsensitive(extension,"ps") || - + osgDB::equalCaseInsensitive(extension,"dng") || osgDB::equalCaseInsensitive(extension,"cr2") || osgDB::equalCaseInsensitive(extension,"crw") || @@ -250,25 +441,25 @@ public: osgDB::equalCaseInsensitive(extension,"srf") || osgDB::equalCaseInsensitive(extension,"cur") || osgDB::equalCaseInsensitive(extension,"xbm") || - + osgDB::equalCaseInsensitive(extension,"raw"); - } - - + } + + ReadResult readImageStream(std::istream& fin) const { - /*// Call ImageIO to load the image. + // Call ImageIO to load the image. CGImageRef cg_image_ref = CreateCGImageFromDataStream(fin); if (NULL == cg_image_ref) return ReadResult::FILE_NOT_FOUND; - */ + // Create an osg::Image from the CGImageRef. - osg::Image* osg_image = NULL; //CreateOSGImageFromCGImage(cg_image_ref); - - //CFRelease(cg_image_ref); + osg::Image* osg_image = CreateOSGImageFromCGImage(cg_image_ref); + + CFRelease(cg_image_ref); return osg_image; } - + virtual ReadResult readImage(std::istream& fin, const osgDB::ReaderWriter::Options* the_options = NULL) const { ReadResult read_result = readImageStream(fin); @@ -317,7 +508,7 @@ public: return WriteResult::FILE_SAVED; } - + virtual WriteResult writeImage(const osg::Image& osg_image, std::ostream& fout, const osgDB::ReaderWriter::Options* the_options) const { WriteResult write_result = writeImageStream(osg_image, fout, the_options);