From Frida Schlaug, "Imageio for ios had a poorly implemented function for reading from streams (always returning null). In this patch I copied some code from the non-ios imageio file and adjusted it to work on ios. "

This commit is contained in:
Robert Osfield 2011-06-06 11:48:32 +00:00
parent 323ccafb0a
commit 3a5ef17ca7

View File

@ -13,7 +13,123 @@
#import <UIKit/UIImage.h>
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
//#include "CoreGraphicsLoader.h"
#import <ImageIO/CGImageSource.h>
/**************************************************************
***** 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<int>(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);