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