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