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