Home | History | Annotate | Download | only in highgui
      1 /*
      2  *  grfmt_imageio.cpp
      3  *
      4  *
      5  *  Created by Morgan Conbere on 5/17/07.
      6  *
      7  */
      8 
      9 #include "_highgui.h"
     10 
     11 #ifdef HAVE_IMAGEIO
     12 
     13 #include "grfmt_imageio.h"
     14 #include <iostream>
     15 using namespace std;
     16 
     17 // ImageIO filter factory
     18 
     19 GrFmtImageIO::GrFmtImageIO()
     20 {
     21     m_sign_len = 0;
     22     m_signature = NULL;
     23     m_description = "Apple ImageIO (*.bmp;*.dib;*.exr;*.jpeg;*.jpg;*.jpe;*.jp2;*.pdf;*.png;*.tiff;*.tif)";
     24 }
     25 
     26 
     27 GrFmtImageIO::~GrFmtImageIO()
     28 {
     29 }
     30 
     31 
     32 bool  GrFmtImageIO::CheckFile( const char* filename )
     33 {
     34     if( !filename ) return false;
     35 
     36     // If a CFImageRef can be retrieved from an image file, it is
     37     // readable by ImageIO.  Effectively this is using ImageIO
     38     // to check the signatures and determine the file format for us.
     39     CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
     40                                                                     (const UInt8*)filename,
     41                                                                     strlen( filename ),
     42                                                                     false );
     43     if( !imageURLRef ) return false;
     44 
     45     CGImageSourceRef sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL );
     46     CFRelease( imageURLRef );
     47     if( !sourceRef ) return false;
     48 
     49     CGImageRef imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL );
     50     CFRelease( sourceRef );
     51     if( !imageRef ) return false;
     52 
     53     return true;
     54 }
     55 
     56 
     57 GrFmtReader* GrFmtImageIO::NewReader( const char* filename )
     58 {
     59     return new GrFmtImageIOReader( filename );
     60 }
     61 
     62 
     63 GrFmtWriter* GrFmtImageIO::NewWriter( const char* filename )
     64 {
     65     return new GrFmtImageIOWriter( filename );
     66 }
     67 
     68 
     69 /////////////////////// GrFmtImageIOReader ///////////////////
     70 
     71 GrFmtImageIOReader::GrFmtImageIOReader( const char* filename ) : GrFmtReader( filename )
     72 {
     73     // Nothing to do here
     74 }
     75 
     76 
     77 GrFmtImageIOReader::~GrFmtImageIOReader()
     78 {
     79     Close();
     80 }
     81 
     82 
     83 void  GrFmtImageIOReader::Close()
     84 {
     85     CGImageRelease( imageRef );
     86 
     87     GrFmtReader::Close();
     88 }
     89 
     90 
     91 bool  GrFmtImageIOReader::ReadHeader()
     92 {
     93     CFURLRef         imageURLRef;
     94     CGImageSourceRef sourceRef;
     95     imageRef = NULL;
     96 
     97     imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
     98                                                            (const UInt8*)m_filename,
     99                                                            strlen(m_filename),
    100                                                            false );
    101 
    102     sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL );
    103     CFRelease( imageURLRef );
    104     if ( !sourceRef )
    105         return false;
    106 
    107     imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL );
    108     CFRelease( sourceRef );
    109     if( !imageRef )
    110         return false;
    111 
    112     m_width = CGImageGetWidth( imageRef );
    113     m_height = CGImageGetHeight( imageRef );
    114 
    115     CGColorSpaceRef colorSpace = CGImageGetColorSpace( imageRef );
    116     if( !colorSpace )
    117         return false;
    118 
    119     m_iscolor = ( CGColorSpaceGetNumberOfComponents( colorSpace ) > 1 );
    120 
    121     return true;
    122 }
    123 
    124 
    125 bool  GrFmtImageIOReader::ReadData( uchar* data, int step, int color )
    126 {
    127     int bpp; // Bytes per pixel
    128 
    129     // Set color to either CV_IMAGE_LOAD_COLOR or CV_IMAGE_LOAD_GRAYSCALE if unchanged
    130     color = color > 0 || ( m_iscolor && color < 0 );
    131 
    132     // Get Height, Width, and color information
    133     if( !ReadHeader() )
    134         return false;
    135 
    136     CGContextRef     context = NULL; // The bitmap context
    137     CGColorSpaceRef  colorSpace = NULL;
    138     uchar*           bitmap = NULL;
    139     CGImageAlphaInfo alphaInfo;
    140 
    141     // CoreGraphics will take care of converting to grayscale and back as long as the
    142     // appropriate colorspace is set
    143     if( color == CV_LOAD_IMAGE_GRAYSCALE )
    144     {
    145         colorSpace = CGColorSpaceCreateDeviceGray();
    146         bpp = 1;
    147         alphaInfo = kCGImageAlphaNone;
    148     }
    149     else if( color == CV_LOAD_IMAGE_COLOR )
    150     {
    151         colorSpace = CGColorSpaceCreateDeviceRGB();
    152         bpp = 4; /* CG only has 8 and 32 bit color spaces, so we waste a byte */
    153         alphaInfo = kCGImageAlphaNoneSkipLast;
    154     }
    155     if( !colorSpace )
    156         return false;
    157 
    158     bitmap = (uchar*)malloc( bpp * m_height * m_width );
    159     if( !bitmap )
    160     {
    161         CGColorSpaceRelease( colorSpace );
    162         return false;
    163     }
    164 
    165     context = CGBitmapContextCreate( (void *)bitmap,
    166                                      m_width,        /* width */
    167                                      m_height,       /* height */
    168                                      m_bit_depth,    /* bit depth */
    169                                      bpp * m_width,  /* bytes per row */
    170                                      colorSpace,     /* color space */
    171                                      alphaInfo);
    172 
    173     CGColorSpaceRelease( colorSpace );
    174     if( !context )
    175     {
    176         free( bitmap );
    177         return false;
    178     }
    179 
    180     // Copy the image data into the bitmap region
    181     CGRect rect = {{0,0},{m_width,m_height}};
    182     CGContextDrawImage( context, rect, imageRef );
    183 
    184     uchar* bitdata = (uchar*)CGBitmapContextGetData( context );
    185     if( !bitdata )
    186     {
    187         free( bitmap);
    188         CGContextRelease( context );
    189         return false;
    190     }
    191 
    192     // Move the bitmap (in RGB) into data (in BGR)
    193     int bitmapIndex = 0;
    194 
    195     if( color == CV_LOAD_IMAGE_COLOR )
    196 	{
    197 		uchar * base = data;
    198 
    199 		for (int y = 0; y < m_height; y++)
    200 		{
    201 			uchar * line = base + y * step;
    202 
    203 		    for (int x = 0; x < m_width; x++)
    204 		    {
    205 				// Blue channel
    206 				line[0] = bitdata[bitmapIndex + 2];
    207 				// Green channel
    208 				line[1] = bitdata[bitmapIndex + 1];
    209 				// Red channel
    210 				line[2] = bitdata[bitmapIndex + 0];
    211 
    212 				line        += 3;
    213 				bitmapIndex += bpp;
    214 			}
    215 		}
    216     }
    217     else if( color == CV_LOAD_IMAGE_GRAYSCALE )
    218     {
    219 		for (int y = 0; y < m_height; y++)
    220 			memcpy (data + y * step, bitmap + y * m_width, m_width);
    221     }
    222 
    223     free( bitmap );
    224     CGContextRelease( context );
    225     return true;
    226 }
    227 
    228 
    229 /////////////////////// GrFmtImageIOWriter ///////////////////
    230 
    231 GrFmtImageIOWriter::GrFmtImageIOWriter( const char* filename ) : GrFmtWriter( filename )
    232 {
    233     // Nothing to do here
    234 }
    235 
    236 
    237 GrFmtImageIOWriter::~GrFmtImageIOWriter()
    238 {
    239     // Nothing to do here
    240 }
    241 
    242 
    243 static
    244 CFStringRef  FilenameToUTI( const char* filename )
    245 {
    246     const char* ext = filename;
    247     for(;;)
    248     {
    249         const char* temp = strchr( ext + 1, '.' );
    250         if( !temp ) break;
    251         ext = temp;
    252     }
    253 
    254     CFStringRef imageUTI = NULL;
    255 
    256     if( !strcmp(ext, ".bmp") || !strcmp(ext, ".dib") )
    257         imageUTI = CFSTR( "com.microsoft.bmp" );
    258     else if( !strcmp(ext, ".exr") )
    259         imageUTI = CFSTR( "com.ilm.openexr-image" );
    260     else if( !strcmp(ext, ".jpeg") || !strcmp(ext, ".jpg") || !strcmp(ext, ".jpe") )
    261         imageUTI = CFSTR( "public.jpeg" );
    262     else if( !strcmp(ext, ".jp2") )
    263         imageUTI = CFSTR( "public.jpeg-2000" );
    264     else if( !strcmp(ext, ".pdf") )
    265         imageUTI = CFSTR( "com.adobe.pdf" );
    266     else if( !strcmp(ext, ".png") )
    267         imageUTI = CFSTR( "public.png" );
    268     else if( !strcmp(ext, ".tiff") || !strcmp(ext, ".tif") )
    269         imageUTI = CFSTR( "public.tiff" );
    270 
    271     return imageUTI;
    272 }
    273 
    274 
    275 bool  GrFmtImageIOWriter::WriteImage( const uchar* data, int step,
    276                                       int width, int height, int /*depth*/, int _channels )
    277 {
    278     // Determine the appropriate UTI based on the filename extension
    279     CFStringRef imageUTI = FilenameToUTI( m_filename );
    280 
    281     // Determine the Bytes Per Pixel
    282     int bpp = (_channels == 1) ? 1 : 4;
    283 
    284     // Write the data into a bitmap context
    285     CGContextRef context;
    286     CGColorSpaceRef colorSpace;
    287     uchar* bitmapData = NULL;
    288 
    289     if( bpp == 1 )
    290         colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray );
    291     else if( bpp == 4 )
    292         colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );
    293     if( !colorSpace )
    294         return false;
    295 
    296     bitmapData = (uchar*)malloc( bpp * height * width );
    297     if( !bitmapData )
    298     {
    299         CGColorSpaceRelease( colorSpace );
    300         return false;
    301     }
    302 
    303     context = CGBitmapContextCreate( bitmapData,
    304                                      width,
    305                                      height,
    306                                      8,
    307                                      bpp * width,
    308                                      colorSpace,
    309                                      (bpp == 1) ? kCGImageAlphaNone :
    310                                      kCGImageAlphaNoneSkipLast );
    311     CGColorSpaceRelease( colorSpace );
    312     if( !context )
    313     {
    314         free( bitmapData );
    315         return false;
    316     }
    317 
    318     // Copy pixel information from data into bitmapData
    319     if (bpp == 4)
    320     {
    321         int           bitmapIndex = 0;
    322 		const uchar * base        = data;
    323 
    324 		for (int y = 0; y < height; y++)
    325 		{
    326 			const uchar * line = base + y * step;
    327 
    328 		    for (int x = 0; x < width; x++)
    329 		    {
    330 				// Blue channel
    331                 bitmapData[bitmapIndex + 2] = line[0];
    332 				// Green channel
    333 				bitmapData[bitmapIndex + 1] = line[1];
    334 				// Red channel
    335 				bitmapData[bitmapIndex + 0] = line[2];
    336 
    337 				line        += 3;
    338 				bitmapIndex += bpp;
    339 			}
    340 		}
    341     }
    342     else if (bpp == 1)
    343     {
    344 		for (int y = 0; y < height; y++)
    345 			memcpy (bitmapData + y * width, data + y * step, width);
    346     }
    347 
    348     // Turn the bitmap context into an imageRef
    349     CGImageRef imageRef = CGBitmapContextCreateImage( context );
    350     CGContextRelease( context );
    351     if( !imageRef )
    352     {
    353         free( bitmapData );
    354         return false;
    355     }
    356 
    357     // Write the imageRef to a file based on the UTI
    358     CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
    359                                                                     (const UInt8*)m_filename,
    360                                                                     strlen(m_filename),
    361                                                                     false );
    362     if( !imageURLRef )
    363     {
    364         CGImageRelease( imageRef );
    365         free( bitmapData );
    366         return false;
    367     }
    368 
    369     CGImageDestinationRef destRef = CGImageDestinationCreateWithURL( imageURLRef,
    370                                                                      imageUTI,
    371                                                                      1,
    372                                                                      NULL);
    373     CFRelease( imageURLRef );
    374     if( !destRef )
    375     {
    376         CGImageRelease( imageRef );
    377         free( bitmapData );
    378         std::cerr << "!destRef" << std::endl << std::flush;
    379         return false;
    380     }
    381 
    382     CGImageDestinationAddImage(destRef, imageRef, NULL);
    383     if( !CGImageDestinationFinalize(destRef) )
    384     {
    385         std::cerr << "Finalize failed" << std::endl << std::flush;
    386         return false;
    387     }
    388 
    389     CFRelease( destRef );
    390     CGImageRelease( imageRef );
    391     free( bitmapData );
    392 
    393     return true;
    394 }
    395 
    396 #endif /* HAVE_IMAGEIO */
    397