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 
GrFmtImageIO()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 
~GrFmtImageIO()27 GrFmtImageIO::~GrFmtImageIO()
28 {
29 }
30 
31 
CheckFile(const char * filename)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 
NewReader(const char * filename)57 GrFmtReader* GrFmtImageIO::NewReader( const char* filename )
58 {
59     return new GrFmtImageIOReader( filename );
60 }
61 
62 
NewWriter(const char * filename)63 GrFmtWriter* GrFmtImageIO::NewWriter( const char* filename )
64 {
65     return new GrFmtImageIOWriter( filename );
66 }
67 
68 
69 /////////////////////// GrFmtImageIOReader ///////////////////
70 
GrFmtImageIOReader(const char * filename)71 GrFmtImageIOReader::GrFmtImageIOReader( const char* filename ) : GrFmtReader( filename )
72 {
73     // Nothing to do here
74 }
75 
76 
~GrFmtImageIOReader()77 GrFmtImageIOReader::~GrFmtImageIOReader()
78 {
79     Close();
80 }
81 
82 
Close()83 void  GrFmtImageIOReader::Close()
84 {
85     CGImageRelease( imageRef );
86 
87     GrFmtReader::Close();
88 }
89 
90 
ReadHeader()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 
ReadData(uchar * data,int step,int color)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 
GrFmtImageIOWriter(const char * filename)231 GrFmtImageIOWriter::GrFmtImageIOWriter( const char* filename ) : GrFmtWriter( filename )
232 {
233     // Nothing to do here
234 }
235 
236 
~GrFmtImageIOWriter()237 GrFmtImageIOWriter::~GrFmtImageIOWriter()
238 {
239     // Nothing to do here
240 }
241 
242 
243 static
FilenameToUTI(const char * filename)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 
WriteImage(const uchar * data,int step,int width,int height,int,int _channels)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