Update to 2.0.0 tree from current Fremantle build
[opencv] / src / highgui / grfmt_imageio.cpp
diff --git a/src/highgui/grfmt_imageio.cpp b/src/highgui/grfmt_imageio.cpp
new file mode 100644 (file)
index 0000000..bb2492f
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ *  grfmt_imageio.cpp
+ *
+ *
+ *  Created by Morgan Conbere on 5/17/07.
+ *
+ */
+
+#include "_highgui.h"
+
+#ifdef HAVE_IMAGEIO
+
+#include "grfmt_imageio.h"
+
+namespace cv
+{
+
+/////////////////////// ImageIODecoder ///////////////////
+
+ImageIODecoder::ImageIODecoder()
+{
+    imageRef = NULL;
+}
+
+ImageIODecoder::~ImageIODecoder()
+{
+    close();
+}
+
+
+void  ImageIODecoder::close()
+{
+    CGImageRelease( imageRef );
+    imageRef = NULL;
+}
+
+
+size_t ImageIODecoder::signatureLength() const
+{
+    return 12;
+}
+
+bool ImageIODecoder::checkSignature( const string& signature ) const
+{
+    // TODO: implement real signature check
+    return true;
+}
+    
+ImageDecoder ImageIODecoder::newDecoder() const
+{
+    return new ImageIODecoder;
+}
+
+bool ImageIODecoder::readHeader()
+{
+    CFURLRef         imageURLRef;
+    CGImageSourceRef sourceRef;
+    // diciu, if ReadHeader is called twice in a row make sure to release the previously allocated imageRef
+    if (imageRef != NULL)
+        CGImageRelease(imageRef);
+    imageRef = NULL;
+
+    imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
+        (const UInt8*)m_filename.c_str(), m_filename.size(), 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_type = CGColorSpaceGetNumberOfComponents( colorSpace ) > 1 ? CV_8UC3 : CV_8UC1;
+
+    return true;
+}
+
+
+bool  ImageIODecoder::readData( Mat& img )
+{
+    uchar* data = img.data;
+    int step = img.step;
+    bool color = img.channels() > 1;
+    int bpp; // Bytes per pixel
+    int bit_depth = 8;
+
+    // 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 = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGBLinear );
+        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 */
+                                     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;
+}
+
+
+/////////////////////// ImageIOEncoder ///////////////////
+
+ImageIOEncoder::ImageIOEncoder()
+{
+    m_description = "Apple ImageIO (*.bmp;*.dib;*.exr;*.jpeg;*.jpg;*.jpe;*.jp2;*.pdf;*.png;*.tiff;*.tif)";
+}
+
+
+ImageIOEncoder::~ImageIOEncoder()
+{
+}
+
+
+ImageEncoder ImageIOEncoder::newEncoder() const
+{
+    return new ImageIOEncoder;
+}
+    
+static
+CFStringRef  FilenameToUTI( const char* filename )
+{
+    const char* ext = filename;
+    char* ext_buf;
+    int i;
+    CFStringRef imageUTI = NULL;
+
+    for(;;)
+    {
+        const char* temp = strchr( ext + 1, '.' );
+        if( !temp ) break;
+        ext = temp;
+    }
+
+    if(!ext)
+        return NULL;
+
+    ext_buf = (char*)malloc(strlen(ext)+1);
+    for(i = 0; ext[i] != '\0'; i++)
+        ext_buf[i] = (char)tolower(ext[i]);
+    ext_buf[i] = '\0';
+    ext = ext_buf;
+
+    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" );
+
+    free(ext_buf);
+
+    return imageUTI;
+}
+
+
+bool  ImageIOEncoder::write( const Mat& img, const vector<int>& params )
+{
+    int width = img.cols, height = img.rows;
+    int _channels = img.channels();
+    const uchar* data = img.data;
+    int step = img.step;
+    
+    // Determine the appropriate UTI based on the filename extension
+    CFStringRef imageUTI = FilenameToUTI( m_filename.c_str() );
+
+    // 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( kCGColorSpaceGenericRGBLinear );
+    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.c_str(), m_filename.size(), false );
+    if( !imageURLRef )
+    {
+        CGImageRelease( imageRef );
+        free( bitmapData );
+        return false;
+    }
+
+    CGImageDestinationRef destRef = CGImageDestinationCreateWithURL( imageURLRef,
+                                                                     imageUTI,
+                                                                     1,
+                                                                     NULL);
+    CFRelease( imageURLRef );
+    if( !destRef )
+    {
+        CGImageRelease( imageRef );
+        free( bitmapData );
+        fprintf(stderr, "!destRef\n");
+        return false;
+    }
+
+    CGImageDestinationAddImage(destRef, imageRef, NULL);
+    if( !CGImageDestinationFinalize(destRef) )
+    {
+        fprintf(stderr, "Finalize failed\n");
+        return false;
+    }
+
+    CFRelease( destRef );
+    CGImageRelease( imageRef );
+    free( bitmapData );
+
+    return true;
+}
+
+}
+
+#endif /* HAVE_IMAGEIO */