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:
parent
323ccafb0a
commit
3a5ef17ca7
@ -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;
|
||||
}
|
||||
|
||||
@ -129,6 +245,81 @@ osg::Image* ReadCoreGraphicsImageFromFile(std::string file)
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -258,14 +449,14 @@ public:
|
||||
|
||||
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);
|
||||
// Create an osg::Image from the CGImageRef.
|
||||
osg::Image* osg_image = CreateOSGImageFromCGImage(cg_image_ref);
|
||||
|
||||
CFRelease(cg_image_ref);
|
||||
return osg_image;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user