You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
11 KiB
396 lines
11 KiB
/* |
|
* grfmt_imageio.cpp |
|
* |
|
* |
|
* Created by Morgan Conbere on 5/17/07. |
|
* |
|
*/ |
|
|
|
#include "_highgui.h" |
|
|
|
#ifdef HAVE_IMAGEIO |
|
|
|
#include "grfmt_imageio.h" |
|
#include <iostream> |
|
using namespace std; |
|
|
|
// ImageIO filter factory |
|
|
|
GrFmtImageIO::GrFmtImageIO() |
|
{ |
|
m_sign_len = 0; |
|
m_signature = NULL; |
|
m_description = "Apple ImageIO (*.bmp;*.dib;*.exr;*.jpeg;*.jpg;*.jpe;*.jp2;*.pdf;*.png;*.tiff;*.tif)"; |
|
} |
|
|
|
|
|
GrFmtImageIO::~GrFmtImageIO() |
|
{ |
|
} |
|
|
|
|
|
bool GrFmtImageIO::CheckFile( const char* filename ) |
|
{ |
|
if( !filename ) return false; |
|
|
|
// If a CFImageRef can be retrieved from an image file, it is |
|
// readable by ImageIO. Effectively this is using ImageIO |
|
// to check the signatures and determine the file format for us. |
|
CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL, |
|
(const UInt8*)filename, |
|
strlen( filename ), |
|
false ); |
|
if( !imageURLRef ) return false; |
|
|
|
CGImageSourceRef sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL ); |
|
CFRelease( imageURLRef ); |
|
if( !sourceRef ) return false; |
|
|
|
CGImageRef imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL ); |
|
CFRelease( sourceRef ); |
|
if( !imageRef ) return false; |
|
|
|
return true; |
|
} |
|
|
|
|
|
GrFmtReader* GrFmtImageIO::NewReader( const char* filename ) |
|
{ |
|
return new GrFmtImageIOReader( filename ); |
|
} |
|
|
|
|
|
GrFmtWriter* GrFmtImageIO::NewWriter( const char* filename ) |
|
{ |
|
return new GrFmtImageIOWriter( filename ); |
|
} |
|
|
|
|
|
/////////////////////// GrFmtImageIOReader /////////////////// |
|
|
|
GrFmtImageIOReader::GrFmtImageIOReader( const char* filename ) : GrFmtReader( filename ) |
|
{ |
|
// Nothing to do here |
|
} |
|
|
|
|
|
GrFmtImageIOReader::~GrFmtImageIOReader() |
|
{ |
|
Close(); |
|
} |
|
|
|
|
|
void GrFmtImageIOReader::Close() |
|
{ |
|
CGImageRelease( imageRef ); |
|
|
|
GrFmtReader::Close(); |
|
} |
|
|
|
|
|
bool GrFmtImageIOReader::ReadHeader() |
|
{ |
|
CFURLRef imageURLRef; |
|
CGImageSourceRef sourceRef; |
|
imageRef = NULL; |
|
|
|
imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL, |
|
(const UInt8*)m_filename, |
|
strlen(m_filename), |
|
false ); |
|
|
|
sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL ); |
|
CFRelease( imageURLRef ); |
|
if ( !sourceRef ) |
|
return false; |
|
|
|
imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL ); |
|
CFRelease( sourceRef ); |
|
if( !imageRef ) |
|
return false; |
|
|
|
m_width = CGImageGetWidth( imageRef ); |
|
m_height = CGImageGetHeight( imageRef ); |
|
|
|
CGColorSpaceRef colorSpace = CGImageGetColorSpace( imageRef ); |
|
if( !colorSpace ) |
|
return false; |
|
|
|
m_iscolor = ( CGColorSpaceGetNumberOfComponents( colorSpace ) > 1 ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
bool GrFmtImageIOReader::ReadData( uchar* data, int step, int color ) |
|
{ |
|
int bpp; // Bytes per pixel |
|
|
|
// Set color to either CV_IMAGE_LOAD_COLOR or CV_IMAGE_LOAD_GRAYSCALE if unchanged |
|
color = color > 0 || ( m_iscolor && color < 0 ); |
|
|
|
// Get Height, Width, and color information |
|
if( !ReadHeader() ) |
|
return false; |
|
|
|
CGContextRef context = NULL; // The bitmap context |
|
CGColorSpaceRef colorSpace = NULL; |
|
uchar* bitmap = NULL; |
|
CGImageAlphaInfo alphaInfo; |
|
|
|
// CoreGraphics will take care of converting to grayscale and back as long as the |
|
// appropriate colorspace is set |
|
if( color == CV_LOAD_IMAGE_GRAYSCALE ) |
|
{ |
|
colorSpace = CGColorSpaceCreateDeviceGray(); |
|
bpp = 1; |
|
alphaInfo = kCGImageAlphaNone; |
|
} |
|
else if( color == CV_LOAD_IMAGE_COLOR ) |
|
{ |
|
colorSpace = CGColorSpaceCreateDeviceRGB(); |
|
bpp = 4; /* CG only has 8 and 32 bit color spaces, so we waste a byte */ |
|
alphaInfo = kCGImageAlphaNoneSkipLast; |
|
} |
|
if( !colorSpace ) |
|
return false; |
|
|
|
bitmap = (uchar*)malloc( bpp * m_height * m_width ); |
|
if( !bitmap ) |
|
{ |
|
CGColorSpaceRelease( colorSpace ); |
|
return false; |
|
} |
|
|
|
context = CGBitmapContextCreate( (void *)bitmap, |
|
m_width, /* width */ |
|
m_height, /* height */ |
|
m_bit_depth, /* bit depth */ |
|
bpp * m_width, /* bytes per row */ |
|
colorSpace, /* color space */ |
|
alphaInfo); |
|
|
|
CGColorSpaceRelease( colorSpace ); |
|
if( !context ) |
|
{ |
|
free( bitmap ); |
|
return false; |
|
} |
|
|
|
// Copy the image data into the bitmap region |
|
CGRect rect = {{0,0},{m_width,m_height}}; |
|
CGContextDrawImage( context, rect, imageRef ); |
|
|
|
uchar* bitdata = (uchar*)CGBitmapContextGetData( context ); |
|
if( !bitdata ) |
|
{ |
|
free( bitmap); |
|
CGContextRelease( context ); |
|
return false; |
|
} |
|
|
|
// Move the bitmap (in RGB) into data (in BGR) |
|
int bitmapIndex = 0; |
|
|
|
if( color == CV_LOAD_IMAGE_COLOR ) |
|
{ |
|
uchar * base = data; |
|
|
|
for (int y = 0; y < m_height; y++) |
|
{ |
|
uchar * line = base + y * step; |
|
|
|
for (int x = 0; x < m_width; x++) |
|
{ |
|
// Blue channel |
|
line[0] = bitdata[bitmapIndex + 2]; |
|
// Green channel |
|
line[1] = bitdata[bitmapIndex + 1]; |
|
// Red channel |
|
line[2] = bitdata[bitmapIndex + 0]; |
|
|
|
line += 3; |
|
bitmapIndex += bpp; |
|
} |
|
} |
|
} |
|
else if( color == CV_LOAD_IMAGE_GRAYSCALE ) |
|
{ |
|
for (int y = 0; y < m_height; y++) |
|
memcpy (data + y * step, bitmap + y * m_width, m_width); |
|
} |
|
|
|
free( bitmap ); |
|
CGContextRelease( context ); |
|
return true; |
|
} |
|
|
|
|
|
/////////////////////// GrFmtImageIOWriter /////////////////// |
|
|
|
GrFmtImageIOWriter::GrFmtImageIOWriter( const char* filename ) : GrFmtWriter( filename ) |
|
{ |
|
// Nothing to do here |
|
} |
|
|
|
|
|
GrFmtImageIOWriter::~GrFmtImageIOWriter() |
|
{ |
|
// Nothing to do here |
|
} |
|
|
|
|
|
static |
|
CFStringRef FilenameToUTI( const char* filename ) |
|
{ |
|
const char* ext = filename; |
|
for(;;) |
|
{ |
|
const char* temp = strchr( ext + 1, '.' ); |
|
if( !temp ) break; |
|
ext = temp; |
|
} |
|
|
|
CFStringRef imageUTI = NULL; |
|
|
|
if( !strcmp(ext, ".bmp") || !strcmp(ext, ".dib") ) |
|
imageUTI = CFSTR( "com.microsoft.bmp" ); |
|
else if( !strcmp(ext, ".exr") ) |
|
imageUTI = CFSTR( "com.ilm.openexr-image" ); |
|
else if( !strcmp(ext, ".jpeg") || !strcmp(ext, ".jpg") || !strcmp(ext, ".jpe") ) |
|
imageUTI = CFSTR( "public.jpeg" ); |
|
else if( !strcmp(ext, ".jp2") ) |
|
imageUTI = CFSTR( "public.jpeg-2000" ); |
|
else if( !strcmp(ext, ".pdf") ) |
|
imageUTI = CFSTR( "com.adobe.pdf" ); |
|
else if( !strcmp(ext, ".png") ) |
|
imageUTI = CFSTR( "public.png" ); |
|
else if( !strcmp(ext, ".tiff") || !strcmp(ext, ".tif") ) |
|
imageUTI = CFSTR( "public.tiff" ); |
|
|
|
return imageUTI; |
|
} |
|
|
|
|
|
bool GrFmtImageIOWriter::WriteImage( const uchar* data, int step, |
|
int width, int height, int /*depth*/, int _channels ) |
|
{ |
|
// Determine the appropriate UTI based on the filename extension |
|
CFStringRef imageUTI = FilenameToUTI( m_filename ); |
|
|
|
// Determine the Bytes Per Pixel |
|
int bpp = (_channels == 1) ? 1 : 4; |
|
|
|
// Write the data into a bitmap context |
|
CGContextRef context; |
|
CGColorSpaceRef colorSpace; |
|
uchar* bitmapData = NULL; |
|
|
|
if( bpp == 1 ) |
|
colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray ); |
|
else if( bpp == 4 ) |
|
colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB ); |
|
if( !colorSpace ) |
|
return false; |
|
|
|
bitmapData = (uchar*)malloc( bpp * height * width ); |
|
if( !bitmapData ) |
|
{ |
|
CGColorSpaceRelease( colorSpace ); |
|
return false; |
|
} |
|
|
|
context = CGBitmapContextCreate( bitmapData, |
|
width, |
|
height, |
|
8, |
|
bpp * width, |
|
colorSpace, |
|
(bpp == 1) ? kCGImageAlphaNone : |
|
kCGImageAlphaNoneSkipLast ); |
|
CGColorSpaceRelease( colorSpace ); |
|
if( !context ) |
|
{ |
|
free( bitmapData ); |
|
return false; |
|
} |
|
|
|
// Copy pixel information from data into bitmapData |
|
if (bpp == 4) |
|
{ |
|
int bitmapIndex = 0; |
|
const uchar * base = data; |
|
|
|
for (int y = 0; y < height; y++) |
|
{ |
|
const uchar * line = base + y * step; |
|
|
|
for (int x = 0; x < width; x++) |
|
{ |
|
// Blue channel |
|
bitmapData[bitmapIndex + 2] = line[0]; |
|
// Green channel |
|
bitmapData[bitmapIndex + 1] = line[1]; |
|
// Red channel |
|
bitmapData[bitmapIndex + 0] = line[2]; |
|
|
|
line += 3; |
|
bitmapIndex += bpp; |
|
} |
|
} |
|
} |
|
else if (bpp == 1) |
|
{ |
|
for (int y = 0; y < height; y++) |
|
memcpy (bitmapData + y * width, data + y * step, width); |
|
} |
|
|
|
// Turn the bitmap context into an imageRef |
|
CGImageRef imageRef = CGBitmapContextCreateImage( context ); |
|
CGContextRelease( context ); |
|
if( !imageRef ) |
|
{ |
|
free( bitmapData ); |
|
return false; |
|
} |
|
|
|
// Write the imageRef to a file based on the UTI |
|
CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL, |
|
(const UInt8*)m_filename, |
|
strlen(m_filename), |
|
false ); |
|
if( !imageURLRef ) |
|
{ |
|
CGImageRelease( imageRef ); |
|
free( bitmapData ); |
|
return false; |
|
} |
|
|
|
CGImageDestinationRef destRef = CGImageDestinationCreateWithURL( imageURLRef, |
|
imageUTI, |
|
1, |
|
NULL); |
|
CFRelease( imageURLRef ); |
|
if( !destRef ) |
|
{ |
|
CGImageRelease( imageRef ); |
|
free( bitmapData ); |
|
std::cerr << "!destRef" << std::endl << std::flush; |
|
return false; |
|
} |
|
|
|
CGImageDestinationAddImage(destRef, imageRef, NULL); |
|
if( !CGImageDestinationFinalize(destRef) ) |
|
{ |
|
std::cerr << "Finalize failed" << std::endl << std::flush; |
|
return false; |
|
} |
|
|
|
CFRelease( destRef ); |
|
CGImageRelease( imageRef ); |
|
free( bitmapData ); |
|
|
|
return true; |
|
} |
|
|
|
#endif /* HAVE_IMAGEIO */
|
|
|