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