- Timestamp:
- 03/21/12 18:36:20 (14 months ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
OpenSceneGraph/trunk/src/osgPlugins/imageio/ReaderWriterImageIO.cpp
r12913 r13041 42 42 ***** Begin Callback functions for istream block reading ***** 43 43 **************************************************************/ 44 44 45 45 // This callback reads some bytes from an istream and copies it 46 46 // to a Quartz buffer (supplied by Apple framework). … … 141 141 MyProviderReleaseInfoCallback 142 142 }; 143 143 144 144 CGDataProviderRef data_provider = CGDataProviderCreateSequential(&fin, &provider_callbacks); 145 145 … … 154 154 MyProviderReleaseInfoCallback 155 155 }; 156 156 157 157 CGDataProviderRef data_provider = CGDataProviderCreate(&fin, &provider_callbacks); 158 158 #endif … … 170 170 171 171 image_ref = CGImageSourceCreateImageAtIndex(source_ref, 0, NULL); 172 172 173 173 /* Don't need the SourceRef any more (error or not) */ 174 174 CFRelease(source_ref); … … 198 198 return NULL; 199 199 } 200 200 201 201 /* Create a CFURL from a CFString */ 202 202 the_url = CFURLCreateWithFileSystemPath( 203 NULL, 203 NULL, 204 204 cf_string, 205 205 kCFURLPOSIXPathStyle, … … 209 209 /* Don't need the CFString any more (error or not) */ 210 210 CFRelease(cf_string); 211 211 212 212 if(!the_url) 213 213 { … … 216 216 } 217 217 218 218 219 219 source_ref = CGImageSourceCreateWithURL(the_url, NULL); 220 220 /* Don't need the URL any more (error or not) */ … … 233 233 OSG_WARN << "CreateCGImageFromFile :: could not get Image" << std::endl; 234 234 } 235 235 236 236 /* Don't need the SourceRef any more (error or not) */ 237 237 CFRelease(source_ref); … … 259 259 // size_t bits_per_component = CGImageGetBitsPerComponent(image_ref); 260 260 size_t bits_per_component = 8; 261 261 262 262 CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref); 263 263 264 264 GLint internal_format; 265 265 GLenum pixel_format; 266 266 GLenum data_type; 267 267 268 268 void* image_data = calloc(the_width * 4, the_height); 269 269 … … 289 289 pixel_format = GL_BGRA_EXT; 290 290 data_type = GL_UNSIGNED_INT_8_8_8_8_REV; 291 291 292 292 bytes_per_row = the_width*4; 293 293 // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); … … 298 298 #else 299 299 bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ 300 #endif 300 #endif 301 301 } 302 302 else … … 325 325 #else 326 326 bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ 327 #endif 327 #endif 328 328 break; 329 329 } … … 331 331 // Tatsuhiro Nishioka 332 332 // 16 bpp grayscale (8 bit white and 8 bit alpha) causes invalid argument combination 333 // in CGBitmapContextCreate. 333 // in CGBitmapContextCreate. 334 334 // I guess it is safer to handle 16 bit grayscale image as 32-bit RGBA image. 335 335 // It works at least on FlightGear … … 342 342 pixel_format = GL_BGRA_EXT; 343 343 data_type = GL_UNSIGNED_INT_8_8_8_8_REV; 344 344 345 345 bytes_per_row = the_width*4; 346 346 // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); … … 352 352 #else 353 353 bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ 354 #endif 354 #endif 355 355 break; 356 356 } … … 363 363 364 364 } 365 365 366 366 // Sets up a context to be drawn to with image_data as the area to be drawn to 367 367 CGContextRef bitmap_context = CGBitmapContextCreate( … … 374 374 bitmap_info 375 375 ); 376 376 377 377 // Draws the image into the context's image_data 378 378 CGContextDrawImage(bitmap_context, the_rect, image_ref); … … 380 380 CGContextRelease(bitmap_context); 381 381 382 // 382 // 383 383 // Reverse the premultiplied alpha for avoiding unexpected darker edges 384 384 // by Tatsuhiro Nishioka (based on SDL's workaround on the similar issue) 385 385 // http://bugzilla.libsdl.org/show_bug.cgi?id=868 386 // 386 // 387 387 if (bits_per_pixel > 8 && (bitmap_info & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst) { 388 388 int i, j; 389 389 GLubyte *pixels = (GLubyte *)image_data; 390 390 for (i = the_height * the_width; i--; ) { 391 391 392 392 #if __BIG_ENDIAN__ 393 393 // That value is a temporary one and only needed for endianess conversion 394 394 GLuint *value = (GLuint *)pixels; 395 // 395 // 396 396 // swap endian of each pixel for avoiding weird colors on ppc macs 397 397 // by Tatsuhiro Nishioka 398 // FIXME: I've tried many combinations of pixel_format, internal_format, and data_type 398 // FIXME: I've tried many combinations of pixel_format, internal_format, and data_type 399 399 // but none worked well. Therefore I tried endian swapping, which seems working with gif,png,tiff,tga,and psd. 400 // (for grayscaled tga and non-power-of-two tga, I can't guarantee since test images (made with Gimp) 400 // (for grayscaled tga and non-power-of-two tga, I can't guarantee since test images (made with Gimp) 401 401 // get corrupted on Preview.app ... 402 402 *value = ((*value) >> 24) | (((*value) << 8) & 0x00FF0000) | (((*value) >> 8) & 0x0000FF00) | ((*value) << 24); … … 420 420 data_type = GL_UNSIGNED_BYTE; 421 421 osg::Image* osg_image = new osg::Image; 422 422 423 423 osg_image->setImage( 424 424 the_width, … … 460 460 */ 461 461 size_t target_bytes_per_row; 462 462 463 463 CGColorSpaceRef color_space; 464 464 CGBitmapInfo bitmap_info; … … 477 477 * and invert the data. 478 478 */ 479 vImage_Buffer vimage_buffer_in = 479 vImage_Buffer vimage_buffer_in = 480 480 { 481 481 (void*)osg_image.data(), // need to override const, but we don't modify the data so it's safe … … 492 492 image_width, 493 493 0 // will fill-in in switch 494 }; 494 }; 495 495 vImage_Error vimage_error_flag; 496 496 … … 507 507 return NULL; 508 508 } 509 509 510 510 // out_image_data = calloc(target_bytes_per_row, image_height); 511 out_image_data = malloc(target_bytes_per_row * image_height); 511 out_image_data = malloc(target_bytes_per_row * image_height); 512 512 if(NULL == out_image_data) 513 513 { … … 532 532 CGColorSpaceRelease(color_space); 533 533 return NULL; 534 } 534 } 535 535 536 536 … … 545 545 // colorSpace=NULL is for alpha only 546 546 color_space = NULL; 547 547 548 548 // out_image_data = calloc(target_bytes_per_row, image_height); 549 out_image_data = malloc(target_bytes_per_row * image_height); 549 out_image_data = malloc(target_bytes_per_row * image_height); 550 550 if(NULL == out_image_data) 551 551 { … … 568 568 free(out_image_data); 569 569 return NULL; 570 } 570 } 571 571 572 572 … … 591 591 return NULL; 592 592 } 593 593 594 594 // out_image_data = calloc(target_bytes_per_row, image_height); 595 out_image_data = malloc(target_bytes_per_row * image_height); 595 out_image_data = malloc(target_bytes_per_row * image_height); 596 596 if(NULL == out_image_data) 597 597 { … … 631 631 CGColorSpaceRelease(color_space); 632 632 return NULL; 633 } 634 633 } 634 635 635 break; 636 636 } … … 646 646 } 647 647 // out_image_data = calloc(target_bytes_per_row, image_height); 648 out_image_data = malloc(target_bytes_per_row * image_height); 648 out_image_data = malloc(target_bytes_per_row * image_height); 649 649 if(NULL == out_image_data) 650 650 { … … 667 667 CGColorSpaceRelease(color_space); 668 668 return NULL; 669 } 669 } 670 670 break; 671 671 } … … 678 678 #else 679 679 bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ 680 #endif 680 #endif 681 681 } 682 682 else … … 694 694 } 695 695 // out_image_data = calloc(target_bytes_per_row, image_height); 696 out_image_data = malloc(target_bytes_per_row * image_height); 696 out_image_data = malloc(target_bytes_per_row * image_height); 697 697 if(NULL == out_image_data) 698 698 { … … 715 715 CGColorSpaceRelease(color_space); 716 716 return NULL; 717 } 717 } 718 718 break; 719 719 } … … 745 745 return NULL; 746 746 } 747 747 748 748 749 749 /* Make an image out of our bitmap; does a cheap vm_copy of the bitmap */ … … 782 782 return NULL; 783 783 } 784 784 785 785 /* Create a CFURL from a CFString */ 786 786 the_url = CFURLCreateWithFileSystemPath( 787 NULL, 787 NULL, 788 788 cf_string, 789 789 kCFURLPOSIXPathStyle, 790 790 false 791 791 ); 792 792 793 793 /* Don't need the CFString any more (error or not) */ 794 794 CFRelease(cf_string); 795 795 796 796 if(!the_url) 797 797 { 798 798 return NULL; 799 799 } 800 800 801 801 if(the_options) 802 802 { … … 806 806 { 807 807 // Not handled: The user could do something stupid and specify both PNG and JPEG options. 808 808 809 809 if(opt=="PNG_COMPRESSION") 810 810 { … … 813 813 int level; 814 814 iss >> level; 815 815 816 816 } 817 817 else if(opt=="JPEG_QUALITY") … … 827 827 } 828 828 } 829 829 830 830 831 831 CFStringRef path_extension = CFURLCopyPathExtension(the_url); … … 859 859 } 860 860 861 861 862 862 dest_ref = CGImageDestinationCreateWithURL( 863 the_url, 864 uti_type, 863 the_url, 864 uti_type, 865 865 1, // image file will contain only one image 866 866 NULL 867 867 ); 868 868 869 869 870 870 CFRelease(uti_type); 871 871 CFRelease(the_url); … … 879 879 CFNumberRef the_values[1]; 880 880 CFDictionaryRef the_dict; 881 881 882 882 the_keys[0] = kCGImageDestinationLossyCompressionQuality; 883 883 the_values[0] = CFNumberCreate( … … 886 886 &compression_quality 887 887 ); 888 888 889 889 the_dict = CFDictionaryCreate(NULL, (const void**)&the_keys, (const void**)&the_values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 890 890 CFRelease(the_values[0]); … … 892 892 // Now that we have the dict, actually set the property. 893 893 CGImageDestinationSetProperties(dest_ref, the_dict); 894 894 895 895 CFRelease(the_dict); 896 896 } … … 909 909 bool found_jpeg_option = false; 910 910 float compression_quality = 1.0f; 911 911 912 912 CGDataConsumerCallbacks consumer_callbacks = 913 913 { … … 915 915 MyConsumerReleaseInfoCallback 916 916 }; 917 917 918 918 CGDataConsumerRef data_consumer = CGDataConsumerCreate(&fout, &consumer_callbacks); 919 919 … … 925 925 { 926 926 // Not handled: The user could do something stupid and specify both PNG and JPEG options. 927 927 928 928 if(opt=="PNG_COMPRESSION") 929 929 { … … 932 932 int level; 933 933 iss >> level; 934 934 935 935 } 936 936 else if(opt=="JPEG_QUALITY") … … 946 946 } 947 947 } 948 948 949 949 950 950 if(found_jpeg_option) … … 964 964 ); 965 965 } 966 966 967 967 968 968 // If we had a way of hinting at what the data type is, we could … … 974 974 NULL 975 975 ); 976 976 977 977 CGDataConsumerRelease(data_consumer); 978 978 CFRelease(uti_type); 979 980 979 980 981 981 // Not handled: The user could do something stupid and specify both PNG and JPEG options. 982 982 if(found_jpeg_option) … … 986 986 CFNumberRef the_values[1]; 987 987 CFDictionaryRef the_dict; 988 988 989 989 the_keys[0] = kCGImageDestinationLossyCompressionQuality; 990 990 the_values[0] = CFNumberCreate( … … 993 993 &compression_quality 994 994 ); 995 995 996 996 the_dict = CFDictionaryCreate(NULL, (const void**)&the_keys, (const void**)&the_values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 997 997 CFRelease(the_values[0]); 998 998 999 999 // Now that we have the dict, actually set the property. 1000 1000 CGImageDestinationSetProperties(dest_ref, the_dict); 1001 1001 1002 1002 CFRelease(the_dict); 1003 1003 } 1004 1004 1005 1005 return dest_ref; 1006 1006 } … … 1018 1018 { 1019 1019 1020 supportsExtension("jpg", "jpg image file"); 1020 supportsExtension("jpg", "jpg image file"); 1021 1021 supportsExtension("jpeg", "jpeg image file"); 1022 1022 supportsExtension("jpe", "jpe image file"); 1023 1023 supportsExtension("jp2", "jp2 image file"); 1024 supportsExtension("tiff", "tiff image file"); 1025 supportsExtension("tif", "tif image file"); 1024 supportsExtension("tiff", "tiff image file"); 1025 supportsExtension("tif", "tif image file"); 1026 1026 supportsExtension("gif", "gif image file"); 1027 1027 supportsExtension("png", "png image file"); … … 1036 1036 supportsExtension("targa", "targa image file"); 1037 1037 supportsExtension("psd", "psd image file"); 1038 1038 1039 1039 supportsExtension("pdf", "pdf image file"); 1040 1040 supportsExtension("eps", "eps image file"); … … 1043 1043 supportsExtension("epsi", "epsi image file"); 1044 1044 supportsExtension("ps", "postscript image file"); 1045 1045 1046 1046 supportsExtension("dng", "dng image file"); 1047 1047 supportsExtension("cr2", "cr2 image file"); … … 1084 1084 // http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/utilist/chapter_4_section_1.html 1085 1085 return 1086 osgDB::equalCaseInsensitive(extension,"jpg") || 1086 osgDB::equalCaseInsensitive(extension,"jpg") || 1087 1087 osgDB::equalCaseInsensitive(extension,"jpeg") || 1088 1088 osgDB::equalCaseInsensitive(extension,"jpe") || 1089 1089 osgDB::equalCaseInsensitive(extension,"jp2") || 1090 osgDB::equalCaseInsensitive(extension,"tiff") || 1091 osgDB::equalCaseInsensitive(extension,"tif") || 1090 osgDB::equalCaseInsensitive(extension,"tiff") || 1091 osgDB::equalCaseInsensitive(extension,"tif") || 1092 1092 osgDB::equalCaseInsensitive(extension,"gif") || 1093 1093 osgDB::equalCaseInsensitive(extension,"png") || … … 1102 1102 osgDB::equalCaseInsensitive(extension,"targa") || 1103 1103 osgDB::equalCaseInsensitive(extension,"psd") || 1104 1104 1105 1105 osgDB::equalCaseInsensitive(extension,"pdf") || 1106 1106 osgDB::equalCaseInsensitive(extension,"eps") || … … 1109 1109 osgDB::equalCaseInsensitive(extension,"epsi") || 1110 1110 osgDB::equalCaseInsensitive(extension,"ps") || 1111 1111 1112 1112 osgDB::equalCaseInsensitive(extension,"dng") || 1113 1113 osgDB::equalCaseInsensitive(extension,"cr2") || … … 1136 1136 1137 1137 1138 1138 1139 1139 ReadResult readImageStream(std::istream& fin) const 1140 1140 { … … 1145 1145 // Create an osg::Image from the CGImageRef. 1146 1146 osg::Image* osg_image = CreateOSGImageFromCGImage(cg_image_ref); 1147 1147 1148 1148 CFRelease(cg_image_ref); 1149 1149 return osg_image; … … 1155 1155 return read_result; 1156 1156 } 1157 1157 1158 1158 ReadResult readImageFile(const std::string& file_name) const 1159 1159 { 1160 1160 OSG_INFO << "imageio readImageFile: " << file_name << std::endl; 1161 1161 1162 1162 // Call ImageIO to load the image. 1163 1163 CGImageRef cg_image_ref = CreateCGImageFromFile(file_name.c_str()); … … 1166 1166 // Create an osg::Image from the CGImageRef. 1167 1167 osg::Image* osg_image = CreateOSGImageFromCGImage(cg_image_ref); 1168 1168 1169 1169 CFRelease(cg_image_ref); 1170 1170 … … 1183 1183 ReadResult read_result = readImageFile(full_file_name); 1184 1184 #else 1185 // Only here to help test istream backend. The file version is better because 1185 // Only here to help test istream backend. The file version is better because 1186 1186 // the filenname.extension could potentially be used by ImageIO to hint what the format type is. 1187 1187 osgDB::ifstream istream(full_file_name.c_str(), std::ios::in | std::ios::binary); … … 1209 1209 CGImageDestinationRef cg_dest_ref = CreateCGImageDestinationFromDataStream(fout, the_options); 1210 1210 if (NULL == cg_dest_ref) return WriteResult::ERROR_IN_WRITING_FILE; 1211 1211 1212 1212 CGImageRef cg_image_ref = CreateCGImageFromOSGData(osg_image); 1213 1213 if(NULL == cg_image_ref) … … 1216 1216 return WriteResult::ERROR_IN_WRITING_FILE; 1217 1217 } 1218 1218 1219 1219 CGImageDestinationAddImage(cg_dest_ref, cg_image_ref, NULL); 1220 1220 if(CGImageDestinationFinalize(cg_dest_ref)) … … 1226 1226 ret_val = WriteResult::ERROR_IN_WRITING_FILE; 1227 1227 } 1228 1228 1229 1229 CFRelease(cg_image_ref); 1230 1230 CFRelease(cg_dest_ref); 1231 1232 return WriteResult::FILE_SAVED; 1233 } 1234 1231 1232 return WriteResult::FILE_SAVED; 1233 } 1234 1235 1235 virtual WriteResult writeImage(const osg::Image& osg_image, std::ostream& fout, const osgDB::ReaderWriter::Options* the_options) const 1236 1236 { … … 1268 1268 ret_val = WriteResult::ERROR_IN_WRITING_FILE; 1269 1269 } 1270 1270 1271 1271 CFRelease(cg_image_ref); 1272 1272 CFRelease(cg_dest_ref); 1273 1273 1274 1274 return WriteResult::FILE_SAVED; 1275 1275 } … … 1292 1292 return writeImageFile(osg_image, full_file_name, the_options); 1293 1293 #else 1294 // Only here to help test ostream backend. The file version is better because 1294 // Only here to help test ostream backend. The file version is better because 1295 1295 // the filenname.extension could potentially be used by ImageIO to hint what the format type is. 1296 1296 osgDB::ofstream fout(file_name.c_str(), std::ios::out | std::ios::binary); 1297 1297 if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; 1298 1298 return writeImage(osg_image, fout, the_options); 1299 #endif 1299 #endif 1300 1300 } 1301 1301
