/XeeImageIOLoader.m

https://code.google.com/p/xee/ · Objective C · 284 lines · 221 code · 60 blank · 3 comment · 40 complexity · f3e144a5e485e3aa3fac258e8dc16346 MD5 · raw file

  1. #import "XeeImageIOLoader.h"
  2. #import "XeeCGImage.h"
  3. @implementation XeeImageIOImage
  4. static size_t XeeImageIOGetBytes(void *info, void *buffer, size_t count) { return [(CSHandle *)info readAtMost:count toBuffer:buffer]; }
  5. static void XeeImageIOSkipBytes(void *info, size_t count) { [(CSHandle *)info skipBytes:count]; }
  6. static void XeeImageIORewind(void *info) { [(CSHandle *)info seekToFileOffset:0]; }
  7. static void XeeImageIOReleaseInfo(void *info) { [(CSHandle *)info release]; }
  8. +(NSArray *)fileTypes
  9. {
  10. return [NSBitmapImageRep imageFileTypes];
  11. }
  12. +(BOOL)canOpenFile:(NSString *)name firstBlock:(NSData *)block attributes:(NSDictionary *)attributes
  13. {
  14. return floor(NSAppKitVersionNumber)>NSAppKitVersionNumber10_3;
  15. }
  16. -(SEL)initLoader
  17. {
  18. source=NULL;
  19. NSMutableDictionary *options=[NSMutableDictionary dictionaryWithObjectsAndKeys:
  20. [NSNumber numberWithBool:YES],kCGImageSourceShouldAllowFloat,
  21. nil];
  22. if(ref)
  23. {
  24. NSString *type=[(NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
  25. (CFStringRef)[[self filename] pathExtension],CFSTR("public.data")) autorelease];
  26. //if([type isEqual:(NSString *)kUTTypePICT]) return NULL;
  27. [options setObject:type forKey:(NSString *)kCGImageSourceTypeIdentifierHint];
  28. }
  29. // CGDataProviderRef provider=CGDataProviderCreateWithURL((CFURLRef)[NSURL fileURLWithPath:[self filename]]);
  30. CGDataProviderCallbacks callbacks=
  31. { XeeImageIOGetBytes,XeeImageIOSkipBytes,XeeImageIORewind,XeeImageIOReleaseInfo };
  32. CGDataProviderRef provider=CGDataProviderCreate([[self handle] retain],&callbacks);
  33. if(!provider) return NULL;
  34. source=CGImageSourceCreateWithDataProvider(provider,(CFDictionaryRef)options);
  35. CGDataProviderRelease(provider);
  36. if(!source) return NULL;
  37. NSDictionary *cgproperties=[(id)CGImageSourceCopyPropertiesAtIndex(source,0,(CFDictionaryRef)options) autorelease];
  38. if(!cgproperties) return NULL;
  39. width=[[cgproperties objectForKey:(NSString *)kCGImagePropertyPixelWidth] intValue];
  40. height=[[cgproperties objectForKey:(NSString *)kCGImagePropertyPixelHeight] intValue];
  41. [self setDepthForImage:self properties:cgproperties];
  42. [self setFormat:[self formatForType:(NSString *)CGImageSourceGetType(source)]];
  43. NSNumber *orientnum=[cgproperties objectForKey:(NSString *)kCGImagePropertyOrientation];
  44. if(orientnum) [self setCorrectOrientation:[orientnum intValue]];
  45. [properties addObjectsFromArray:[self convertCGProperties:cgproperties]];
  46. current_image=0;
  47. if(thumbonly) return @selector(loadThumbnail);
  48. return @selector(loadImage);
  49. }
  50. -(void)deallocLoader
  51. {
  52. if(source) CFRelease(source);
  53. }
  54. -(SEL)loadImage
  55. {
  56. int count=CGImageSourceGetCount(source);
  57. if(current_image==count) return @selector(loadThumbnail);
  58. NSDictionary *options=[NSDictionary dictionaryWithObjectsAndKeys:
  59. [NSNumber numberWithBool:YES],kCGImageSourceShouldAllowFloat,
  60. [NSNumber numberWithBool:NO],kCGImageSourceShouldCache,
  61. nil];
  62. CGImageRef cgimage=CGImageSourceCreateImageAtIndex(source,current_image++,(CFDictionaryRef)options);
  63. if(!cgimage) return @selector(loadImage);
  64. NSDictionary *cgproperties=[(id)CGImageSourceCopyPropertiesAtIndex(source,current_image-1,(CFDictionaryRef)options) autorelease];
  65. CFStringRef colormodel=(CFStringRef)[cgproperties objectForKey:(NSString *)kCGImagePropertyColorModel];
  66. NSNumber *isindexed=[cgproperties objectForKey:(NSString *)kCGImagePropertyIsIndexed];
  67. NSNumber *hasalpha=[cgproperties objectForKey:(NSString *)kCGImagePropertyHasAlpha];
  68. //int framedepth=[[cgproperties objectForKey:(NSString *)kCGImagePropertyDepth] intValue];
  69. XeeBitmapImage *image=nil;
  70. if(colormodel!=kCGImagePropertyColorModelCMYK&&colormodel!=kCGImagePropertyColorModelLab
  71. &&!(isindexed&&[isindexed boolValue]))
  72. {
  73. image=[[[XeeCGImage alloc] initWithCGImage:cgimage] autorelease];
  74. NSNumber *photometric=[[cgproperties objectForKey:@"{TIFF}"] objectForKey:@"PhotometricInterpretation"];
  75. if(photometric&&[photometric intValue]==0) [(XeeCGImage *)image invertImage];
  76. }
  77. if(!image)
  78. {
  79. int type;
  80. if(hasalpha&&[hasalpha boolValue]) type=XeeBitmapTypePremultipliedARGB8;
  81. else if(colormodel==kCGImagePropertyColorModelGray) type=XeeBitmapTypeLuma8;
  82. else type=XeeBitmapTypeNRGB8;
  83. int pixelwidth=CGImageGetWidth(cgimage);
  84. int pixelheight=CGImageGetHeight(cgimage);
  85. image=[[[XeeBitmapImage alloc] initWithType:type width:pixelwidth height:pixelheight] autorelease];
  86. if(image)
  87. {
  88. CGContextRef cgcontext=[image createCGContext];
  89. if(cgcontext)
  90. {
  91. CGContextDrawImage(cgcontext,CGRectMake(0,0,pixelwidth,pixelheight),cgimage);
  92. CGContextRelease(cgcontext);
  93. }
  94. else image=nil;
  95. }
  96. }
  97. CGImageRelease(cgimage);
  98. if(!image) return @selector(loadImage);
  99. [self setDepthForImage:image properties:cgproperties];
  100. NSNumber *orientnum=[cgproperties objectForKey:(NSString *)kCGImagePropertyOrientation];
  101. if(orientnum) [image setCorrectOrientation:[orientnum intValue]];
  102. [self addSubImage:image];
  103. [image setCompleted];
  104. return @selector(loadImage);
  105. }
  106. -(SEL)loadThumbnail
  107. {
  108. loaded=!thumbonly;
  109. NSDictionary *options=[NSDictionary dictionaryWithObjectsAndKeys:
  110. [NSNumber numberWithBool:NO],kCGImageSourceShouldCache,
  111. [NSNumber numberWithBool:thumbonly],kCGImageSourceCreateThumbnailFromImageIfAbsent,
  112. nil];
  113. CGImageRef cgimage=CGImageSourceCreateThumbnailAtIndex(source,0,(CFDictionaryRef)options);
  114. if(!cgimage) return NULL;
  115. NSDictionary *cgproperties=[(id)CGImageSourceCopyPropertiesAtIndex(source,0,(CFDictionaryRef)options) autorelease];
  116. XeeCGImage *image=[[[XeeCGImage alloc] initWithCGImage:cgimage] autorelease];
  117. NSNumber *photometric=[[cgproperties objectForKey:@"{TIFF}"] objectForKey:@"PhotometricInterpretation"];
  118. if(photometric&&[photometric intValue]==0) [image invertImage];
  119. CGImageRelease(cgimage);
  120. if(!image) return NULL;
  121. [self setDepthForImage:image properties:cgproperties];
  122. [self addSubImage:image];
  123. [image setCompleted];
  124. loaded=YES;
  125. return NULL;
  126. }
  127. -(void)setDepthForImage:(XeeImage *)image properties:(NSDictionary *)cgproperties
  128. {
  129. CFStringRef colormodel=(CFStringRef)[cgproperties objectForKey:(NSString *)kCGImagePropertyColorModel];
  130. NSNumber *indexednum=[cgproperties objectForKey:(NSString *)kCGImagePropertyIsIndexed];
  131. NSNumber *floatnum=[cgproperties objectForKey:(NSString *)kCGImagePropertyIsFloat];
  132. NSNumber *alphanum=[cgproperties objectForKey:(NSString *)kCGImagePropertyHasAlpha];
  133. int framedepth=[[cgproperties objectForKey:(NSString *)kCGImagePropertyDepth] intValue];
  134. BOOL isindexed=indexednum&&[indexednum boolValue];
  135. BOOL isfloat=floatnum&&[floatnum boolValue];
  136. BOOL hasalpha=alphanum&&[alphanum boolValue];
  137. if(isindexed) [image setDepthIndexed:1<<framedepth];
  138. else if(colormodel==kCGImagePropertyColorModelGray) [image setDepthGrey:framedepth alpha:hasalpha floating:isfloat];
  139. else if(colormodel==kCGImagePropertyColorModelRGB) [image setDepthRGB:framedepth alpha:hasalpha floating:isfloat];
  140. else if(colormodel==kCGImagePropertyColorModelCMYK) [image setDepthCMYK:framedepth alpha:hasalpha];
  141. else if(colormodel==kCGImagePropertyColorModelLab) [image setDepthLab:framedepth alpha:hasalpha];
  142. }
  143. -(NSString *)formatForType:(NSString *)type
  144. {
  145. static NSDictionary *formatdict=nil;
  146. if(!formatdict) formatdict=[[NSDictionary dictionaryWithObjectsAndKeys:
  147. @"TIFF",@"public.tiff",
  148. @"BMP",@"com.microsoft.bmp",
  149. @"GIF",@"com.compuserve.gif",
  150. @"JPEG",@"public.jpeg",
  151. @"PICT",@"com.apple.pict",
  152. @"PNG",@"public.png",
  153. @"QTIF",@"com.apple.quicktime-image",
  154. @"TGA",@"com.truevision.tga-image",
  155. @"SGI",@"com.sgi.sgi-image",
  156. @"PSD",@"com.adobe.photoshop-image",
  157. @"PNTG",@"com.apple.macpaint-image",
  158. @"FPX",@"com.kodak.flashpix-image",
  159. @"JPEG2000",@"public.jpeg-2000",
  160. @"ICO",@"com.microsoft.ico",
  161. @"XBM",@"public.xbitmap-image",
  162. @"EXR",@"com.ilm.openexr-image",
  163. @"Fax",@"public.fax",
  164. @"Icns",@"com.apple.icns",
  165. @"Radiance",@"public.radiance",
  166. @"PCX",@"cx.c3.pcx",
  167. @"IFF ILBM",@"com.ea.iff-ilbm",
  168. @"DNG",@"com.adobe.raw-image",
  169. @"Leica",@"com.leica.raw-image",
  170. @"RAW",@"com.panasonic.raw-image",
  171. @"DCR",@"com.kodak.raw-image",
  172. @"CR2",@"com.canon.cr2-raw-image",
  173. @"CRW",@"com.canon.crw-raw-image",
  174. @"MRW",@"com.konicaminolta.raw-image",
  175. @"RAF",@"com.fuji.raw-image",
  176. @"NEF",@"com.nikon.raw-image",
  177. @"ORF",@"com.olympus.raw-image",
  178. @"SRF",@"com.sony.raw-image",
  179. @"PEF",@"com.pentax.raw-image",
  180. nil] retain];
  181. NSString *shortformat=[formatdict objectForKey:type];
  182. if(shortformat) return shortformat;
  183. else return type;
  184. }
  185. -(NSArray *)convertCGProperties:(NSDictionary *)cgproperties
  186. {
  187. NSMutableArray *array=[NSMutableArray array];
  188. NSBundle *imageio=[NSBundle bundleWithIdentifier:@"com.apple.ImageIO.framework"];
  189. NSEnumerator *enumerator=[cgproperties keyEnumerator];
  190. NSString *key;
  191. while(key=[enumerator nextObject])
  192. {
  193. id value=[cgproperties objectForKey:key];
  194. if(![value isKindOfClass:[NSDictionary class]]) continue;
  195. NSString *keyname=[imageio localizedStringForKey:key value:key table:@"CGImageSource"];
  196. [array addObject:[XeePropertyItem itemWithLabel:keyname
  197. value:[self convertCGPropertyValues:value imageIOBundle:imageio]
  198. identifier:[NSString stringWithFormat:@"%@.%@",@"imageio",key]]];
  199. }
  200. [array sortUsingSelector:@selector(compare:)];
  201. [array addObject:[XeePropertyItem itemWithLabel:
  202. NSLocalizedString(@"More properties",@"More properties (from ImageIO.framework) section title")
  203. value:[self convertCGPropertyValues:cgproperties imageIOBundle:imageio]]];
  204. return array;
  205. }
  206. -(NSArray *)convertCGPropertyValues:(NSDictionary *)cgproperties imageIOBundle:(NSBundle *)imageio
  207. {
  208. NSMutableArray *array=[NSMutableArray array];
  209. NSEnumerator *enumerator=[cgproperties keyEnumerator];
  210. NSString *key;
  211. while(key=[enumerator nextObject])
  212. {
  213. id value=[cgproperties objectForKey:key];
  214. key=[imageio localizedStringForKey:key value:key table:@"CGImageSource"];
  215. if([value isKindOfClass:[NSDictionary class]]) continue;
  216. else if([value isKindOfClass:[NSArray class]])
  217. [array addObjectsFromArray:[XeePropertyItem itemsWithLabel:key valueArray:value]];
  218. else
  219. [array addObject:[XeePropertyItem itemWithLabel:key value:value]];
  220. }
  221. [array sortUsingSelector:@selector(compare:)];
  222. return array;
  223. }
  224. @end