16acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/*
26acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn *  grfmt_imageio.cpp
36acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn *
46acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn *
56acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn *  Created by Morgan Conbere on 5/17/07.
66acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn *
76acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn */
86acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
96acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "_highgui.h"
106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#ifdef HAVE_IMAGEIO
126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include "grfmt_imageio.h"
146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <iostream>
156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennusing namespace std;
166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn// ImageIO filter factory
186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtImageIO::GrFmtImageIO()
206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_sign_len = 0;
226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_signature = NULL;
236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_description = "Apple ImageIO (*.bmp;*.dib;*.exr;*.jpeg;*.jpg;*.jpe;*.jp2;*.pdf;*.png;*.tiff;*.tif)";
246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtImageIO::~GrFmtImageIO()
286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennbool  GrFmtImageIO::CheckFile( const char* filename )
336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !filename ) return false;
356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // If a CFImageRef can be retrieved from an image file, it is
376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // readable by ImageIO.  Effectively this is using ImageIO
386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // to check the signatures and determine the file format for us.
396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                    (const UInt8*)filename,
416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                    strlen( filename ),
426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                    false );
436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !imageURLRef ) return false;
446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageSourceRef sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL );
466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFRelease( imageURLRef );
476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !sourceRef ) return false;
486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageRef imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL );
506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFRelease( sourceRef );
516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !imageRef ) return false;
526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return true;
546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtReader* GrFmtImageIO::NewReader( const char* filename )
586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return new GrFmtImageIOReader( filename );
606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtWriter* GrFmtImageIO::NewWriter( const char* filename )
646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return new GrFmtImageIOWriter( filename );
666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/////////////////////// GrFmtImageIOReader ///////////////////
706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtImageIOReader::GrFmtImageIOReader( const char* filename ) : GrFmtReader( filename )
726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Nothing to do here
746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtImageIOReader::~GrFmtImageIOReader()
786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    Close();
806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennvoid  GrFmtImageIOReader::Close()
846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageRelease( imageRef );
866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    GrFmtReader::Close();
886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennbool  GrFmtImageIOReader::ReadHeader()
926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFURLRef         imageURLRef;
946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageSourceRef sourceRef;
956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    imageRef = NULL;
966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                           (const UInt8*)m_filename,
996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                           strlen(m_filename),
1006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                           false );
1016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    sourceRef = CGImageSourceCreateWithURL( imageURLRef, NULL );
1036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFRelease( imageURLRef );
1046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if ( !sourceRef )
1056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    imageRef = CGImageSourceCreateImageAtIndex( sourceRef, 0, NULL );
1086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFRelease( sourceRef );
1096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !imageRef )
1106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_width = CGImageGetWidth( imageRef );
1136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_height = CGImageGetHeight( imageRef );
1146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGColorSpaceRef colorSpace = CGImageGetColorSpace( imageRef );
1166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !colorSpace )
1176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    m_iscolor = ( CGColorSpaceGetNumberOfComponents( colorSpace ) > 1 );
1206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return true;
1226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennbool  GrFmtImageIOReader::ReadData( uchar* data, int step, int color )
1266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int bpp; // Bytes per pixel
1286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Set color to either CV_IMAGE_LOAD_COLOR or CV_IMAGE_LOAD_GRAYSCALE if unchanged
1306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    color = color > 0 || ( m_iscolor && color < 0 );
1316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Get Height, Width, and color information
1336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !ReadHeader() )
1346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGContextRef     context = NULL; // The bitmap context
1376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGColorSpaceRef  colorSpace = NULL;
1386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    uchar*           bitmap = NULL;
1396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageAlphaInfo alphaInfo;
1406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // CoreGraphics will take care of converting to grayscale and back as long as the
1426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // appropriate colorspace is set
1436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( color == CV_LOAD_IMAGE_GRAYSCALE )
1446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        colorSpace = CGColorSpaceCreateDeviceGray();
1466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        bpp = 1;
1476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        alphaInfo = kCGImageAlphaNone;
1486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( color == CV_LOAD_IMAGE_COLOR )
1506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        colorSpace = CGColorSpaceCreateDeviceRGB();
1526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        bpp = 4; /* CG only has 8 and 32 bit color spaces, so we waste a byte */
1536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        alphaInfo = kCGImageAlphaNoneSkipLast;
1546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !colorSpace )
1566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bitmap = (uchar*)malloc( bpp * m_height * m_width );
1596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !bitmap )
1606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CGColorSpaceRelease( colorSpace );
1626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    context = CGBitmapContextCreate( (void *)bitmap,
1666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     m_width,        /* width */
1676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     m_height,       /* height */
1686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     m_bit_depth,    /* bit depth */
1696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     bpp * m_width,  /* bytes per row */
1706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     colorSpace,     /* color space */
1716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     alphaInfo);
1726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGColorSpaceRelease( colorSpace );
1746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !context )
1756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        free( bitmap );
1776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Copy the image data into the bitmap region
1816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGRect rect = {{0,0},{m_width,m_height}};
1826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGContextDrawImage( context, rect, imageRef );
1836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    uchar* bitdata = (uchar*)CGBitmapContextGetData( context );
1856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !bitdata )
1866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        free( bitmap);
1886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CGContextRelease( context );
1896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
1906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Move the bitmap (in RGB) into data (in BGR)
1936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int bitmapIndex = 0;
1946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( color == CV_LOAD_IMAGE_COLOR )
1966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn	{
1976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		uchar * base = data;
1986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		for (int y = 0; y < m_height; y++)
2006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		{
2016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			uchar * line = base + y * step;
2026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		    for (int x = 0; x < m_width; x++)
2046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		    {
2056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				// Blue channel
2066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				line[0] = bitdata[bitmapIndex + 2];
2076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				// Green channel
2086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				line[1] = bitdata[bitmapIndex + 1];
2096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				// Red channel
2106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				line[2] = bitdata[bitmapIndex + 0];
2116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				line        += 3;
2136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				bitmapIndex += bpp;
2146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			}
2156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		}
2166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( color == CV_LOAD_IMAGE_GRAYSCALE )
2186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
2196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		for (int y = 0; y < m_height; y++)
2206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			memcpy (data + y * step, bitmap + y * m_width, m_width);
2216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    free( bitmap );
2246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGContextRelease( context );
2256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return true;
2266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/////////////////////// GrFmtImageIOWriter ///////////////////
2306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtImageIOWriter::GrFmtImageIOWriter( const char* filename ) : GrFmtWriter( filename )
2326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Nothing to do here
2346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennGrFmtImageIOWriter::~GrFmtImageIOWriter()
2386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Nothing to do here
2406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic
2446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius RennCFStringRef  FilenameToUTI( const char* filename )
2456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    const char* ext = filename;
2476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    for(;;)
2486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
2496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        const char* temp = strchr( ext + 1, '.' );
2506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        if( !temp ) break;
2516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        ext = temp;
2526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
2536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFStringRef imageUTI = NULL;
2556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !strcmp(ext, ".bmp") || !strcmp(ext, ".dib") )
2576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "com.microsoft.bmp" );
2586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( !strcmp(ext, ".exr") )
2596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "com.ilm.openexr-image" );
2606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( !strcmp(ext, ".jpeg") || !strcmp(ext, ".jpg") || !strcmp(ext, ".jpe") )
2616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "public.jpeg" );
2626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( !strcmp(ext, ".jp2") )
2636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "public.jpeg-2000" );
2646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( !strcmp(ext, ".pdf") )
2656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "com.adobe.pdf" );
2666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( !strcmp(ext, ".png") )
2676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "public.png" );
2686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( !strcmp(ext, ".tiff") || !strcmp(ext, ".tif") )
2696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        imageUTI = CFSTR( "public.tiff" );
2706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return imageUTI;
2726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
2736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennbool  GrFmtImageIOWriter::WriteImage( const uchar* data, int step,
2766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                      int width, int height, int /*depth*/, int _channels )
2776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
2786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Determine the appropriate UTI based on the filename extension
2796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFStringRef imageUTI = FilenameToUTI( m_filename );
2806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Determine the Bytes Per Pixel
2826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    int bpp = (_channels == 1) ? 1 : 4;
2836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Write the data into a bitmap context
2856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGContextRef context;
2866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGColorSpaceRef colorSpace;
2876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    uchar* bitmapData = NULL;
2886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( bpp == 1 )
2906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericGray );
2916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if( bpp == 4 )
2926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );
2936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !colorSpace )
2946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
2956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
2966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    bitmapData = (uchar*)malloc( bpp * height * width );
2976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !bitmapData )
2986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
2996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CGColorSpaceRelease( colorSpace );
3006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
3016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    context = CGBitmapContextCreate( bitmapData,
3046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     width,
3056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     height,
3066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     8,
3076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     bpp * width,
3086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     colorSpace,
3096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     (bpp == 1) ? kCGImageAlphaNone :
3106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                     kCGImageAlphaNoneSkipLast );
3116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGColorSpaceRelease( colorSpace );
3126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !context )
3136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        free( bitmapData );
3156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
3166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Copy pixel information from data into bitmapData
3196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if (bpp == 4)
3206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        int           bitmapIndex = 0;
3226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		const uchar * base        = data;
3236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		for (int y = 0; y < height; y++)
3256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		{
3266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			const uchar * line = base + y * step;
3276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		    for (int x = 0; x < width; x++)
3296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		    {
3306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				// Blue channel
3316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                bitmapData[bitmapIndex + 2] = line[0];
3326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				// Green channel
3336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				bitmapData[bitmapIndex + 1] = line[1];
3346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				// Red channel
3356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				bitmapData[bitmapIndex + 0] = line[2];
3366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				line        += 3;
3386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn				bitmapIndex += bpp;
3396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			}
3406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		}
3416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    else if (bpp == 1)
3436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn		for (int y = 0; y < height; y++)
3456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn			memcpy (bitmapData + y * width, data + y * step, width);
3466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Turn the bitmap context into an imageRef
3496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageRef imageRef = CGBitmapContextCreateImage( context );
3506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGContextRelease( context );
3516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !imageRef )
3526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        free( bitmapData );
3546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
3556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    // Write the imageRef to a file based on the UTI
3586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFURLRef imageURLRef = CFURLCreateFromFileSystemRepresentation( NULL,
3596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                    (const UInt8*)m_filename,
3606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                    strlen(m_filename),
3616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                    false );
3626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !imageURLRef )
3636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CGImageRelease( imageRef );
3656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        free( bitmapData );
3666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
3676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageDestinationRef destRef = CGImageDestinationCreateWithURL( imageURLRef,
3706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                     imageUTI,
3716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                     1,
3726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn                                                                     NULL);
3736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFRelease( imageURLRef );
3746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !destRef )
3756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        CGImageRelease( imageRef );
3776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        free( bitmapData );
3786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        std::cerr << "!destRef" << std::endl << std::flush;
3796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
3806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageDestinationAddImage(destRef, imageRef, NULL);
3836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    if( !CGImageDestinationFinalize(destRef) )
3846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
3856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        std::cerr << "Finalize failed" << std::endl << std::flush;
3866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        return false;
3876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
3886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CFRelease( destRef );
3906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    CGImageRelease( imageRef );
3916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    free( bitmapData );
3926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return true;
3946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
3956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
3966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#endif /* HAVE_IMAGEIO */
397