This is MiscImageDecoderController.m in view mode; [Download] [Up]
/* MiscImageDecoderController.m Copyright 1996 Netsurfer Inc. This notice may not be removed from this source code. The use and distribution of this software is governed by the terms of the MiscKit license agreement. Refer to the license document included with the MiscKit distribution for the terms. Author: <bbum@friday.com> Converted to OpenStep, September 1996, Uwe Hoffmann. */ #import <AppKit/AppKit.h> #import "MiscImageDecoderController.h" #import "MiscImageDecoder.h" #import "MiscJPEGDecoder.h" #import "MiscGIFDecoder.h" #import "MiscTIFFDecoder.h" #import "MiscPNGDecoder.h" #ifdef VERBOSE #undef VERBOSE #undef METHOD #undef METHODnl #endif #define VERBOSE if(_SIDFlags.verboseMode) #define METHOD NSLog(@"[%@ %s%@] ", \ [[self class] description], \ (self == (id)[self class]) ? "+" : "-", \ NSStringFromSelector(_cmd)) #define METHODnl NSLog(@"[%@ %s%@]\n", \ [[self class] description], \ (self == (id)[self class]) ? "+" : "-", \ NSStringFromSelector(_cmd)) @implementation MiscImageDecoderController /*"An instance of this class is a controller for image decoding which can be used to decode any of a number of different image formats depending on what decoder classes have been registered with the controller instance. Given an arbitrary path or data object, an instance of #MiscImageDecoder will determine the type of the image, attempt to decode it, and, upon success, will return an instance of #NSBitmapImageRep containing the decoded image. Instances are designed to be used in a multi-threaded context. Any instance can be decoding image in any thread of execution while other instances are simultaneously decoding images. A single instance %{cannot} decode multiple images from different threads; to attempt this guarantees catastrophic failure of the environment. #{Registrering Custom Decoders} A class can register to be a potential decoder by calling #{MiscImageDecoderController}'s #{-addDecoderClass:} method. When instantiated, an instance of MiscImageDecoderController automatically registers the #{MiscGIFDecoder}, #{MiscPNGDecoder} and #{MiscJPEGDecoder} classes. #{How Image Formats Are Determined} The #{-decodeFromData:...} methods determine the contents of the data object by calling {+canLoadFromData:} within each potentially eligible decoder's class. The first decoder to return YES decodes the data object. #{-decodeFromFile:...} and friends try to determine the image type by looking up the file's extension in the #{decoderByType} dictionary. If not found, the data is mapped into memory and passed to #{-decodeFromData:...}. "*/ + sharedInstance /*"Returns an shared instance of MiscImageDecoderController."*/ { static id sharedInstance = nil; if(!sharedInstance) sharedInstance = [[self alloc] init]; return sharedInstance; } - init /*"Designated intializer. Adds decoder classes for the JPEG, GIF and PNG formats."*/ { _SIDFlags.verboseMode = NO; _SIDFlags.spewStderr = NO; lastImageCorrupt = NO; errorDelegate = nil; decoderByType = [[NSMutableDictionary allocWithZone:[self zone]] init]; decoderClassByType = [[NSMutableDictionary allocWithZone:[self zone]] init]; decoderList = [[NSMutableArray allocWithZone:[self zone]] init]; [self addDecoderClass:[MiscGIFDecoder class]]; [self addDecoderClass:[MiscJPEGDecoder class]]; [self addDecoderClass:[MiscPNGDecoder class]]; [self addDecoderClass:[MiscTIFFDecoder class]]; return self; } - (void)dealloc { [decoderByType release]; [decoderClassByType release]; [decoderList release]; return [super dealloc]; } - (NSArray *)imageUnfilteredFileTypes /*"Returns an array of strings containing all of the image types an instance of MiscImageDecoderController can decode."*/ { return [decoderByType allKeys]; } - (BOOL)canInitWithData:(NSData *)data /*"Returns YES if the controller thinks it can decode the data. The receiver forwards data to each specific format decoding class, if any return YES, this method immediately returns YES."*/ { NSParameterAssert(data); return [self decoderForData:data] ? YES : NO; } - (MiscImageDecoder *)decoderForType:(NSString *)imageType /*"Returns the decoder for images of type imageType. This can be used to customize the particular image decoder."*/ { NSParameterAssert(imageType); VERBOSE { METHODnl; NSLog(@"%@", imageType); } return (MiscImageDecoder *)[decoderByType objectForKey:imageType]; } - (Class)decoderClassForType:(NSString *)imageType /*"Returns the decoder class for images of type imageType. This can be used to customize the particular image decoder."*/ { NSParameterAssert(imageType); VERBOSE { METHODnl; NSLog(@"%@", imageType); } return (Class)[decoderClassByType objectForKey:imageType]; } - (MiscImageDecoder *)decoderForData:(NSData *)data /*"Returns the decoder object that should be used to decode data. If an appropriate decoder object is not available, returns nil."*/ { unsigned int i,n; MiscImageDecoder *decoder; NSParameterAssert(data); n = [decoderList count]; for(i = 0; i < n; i++){ decoder = (MiscImageDecoder *)[decoderList objectAtIndex:i]; if([[decoder class] canInitWithData:data]) return decoder; } return nil; } - (Class)decoderClassForData:(NSData *)data /*"Returns the decoder Class used to decode data. If no class is available, returns nil."*/ { return [[self decoderForData:data] class]; } - (void)addDecoderClass:aClass /*"Adds aClass as a possible decoder."*/ { MiscImageDecoder *newDecoder; unsigned int i,n; NSArray *decoderTypes; NSString *theType; VERBOSE { METHOD; } if(!aClass || [aClass isKindOfClass:[MiscImageDecoder class]]) return; newDecoder = (MiscImageDecoder *)[[aClass allocWithZone:[self zone]] init]; decoderTypes = [aClass imageUnfilteredFileTypes]; n = [decoderTypes count]; for(i = 0; i < n; i++){ theType = [decoderTypes objectAtIndex:i]; VERBOSE { METHODnl; NSLog(@"Adding type: %@", theType); } [decoderByType setObject:newDecoder forKey:theType]; [decoderClassByType setObject:aClass forKey:theType]; } // add to decoderList [decoderList addObject:newDecoder]; [newDecoder setImageDepth:imageDepth]; [newDecoder setVerboseMode:_SIDFlags.verboseMode]; [newDecoder setErrorDelegate:self]; [newDecoder release]; } - (NSBitmapImageRep *)decodeFromFile:(NSString *)filePath /*" Attempts to decode the data in filePath as an image. Uses the filePath's extension to determine the image type. If it fails to find a decoder given the filePath's extension, the method maps the filePath and calls {-decodeFromData:} in hopes that one of the image decoders will decide it can decode the data contents. Returns the decoded image upon success and nil upon failure. This method is a cover for #{-decodeFromFile:withDecoder:}. "*/ { return [self decodeFromFile:filePath withDecoder:nil]; } - (NSBitmapImageRep *)decodeFromFile:(NSString *)filePath withDecoder:(MiscImageDecoder *)aDecoder /*" Attempts to decode the contents of filePath using aDecoder. If aDecoder is not defined, the method will try to identify the decoder to be used from filePath's extension. If that fails, this method will map the file and pass control #{-decodeFromData:...}. Returns the decoded image upon success or nil upon failure."*/ { MiscImageDecoder *decoder; NSBitmapImageRep *result; NSParameterAssert(filePath); VERBOSE { METHODnl; NSLog(filePath); } if(aDecoder) { result = [aDecoder decodeFromFile:filePath]; lastImageCorrupt = [aDecoder lastImageCorrupt]; return result; } decoder = (MiscImageDecoder *)[decoderByType objectForKey:[filePath pathExtension]]; if(decoder) { result = [decoder decodeFromFile:filePath]; lastImageCorrupt = [decoder lastImageCorrupt]; return result; } return [self decodeFromData:[NSData dataWithContentsOfMappedFile:filePath] withDecoder:nil]; } - (NSBitmapImageRep *)decodeFromData:(NSData *)data /*"This method is a cover for #{-decodeFromData:withDecoder:}."*/ { return [self decodeFromData:data withDecoder:nil]; } - (NSBitmapImageRep *)decodeFromData:(NSData *)data withDecoder:(MiscImageDecoder *)aDecoder /*" Decodes the contents of data using the decoder aDecoder. If aDecoder is not defined, this method determines the decoder using the #{-decoderForData:} method. Returns the decoded image upon success, or nil upon failure. "*/ { MiscImageDecoder *decoder; NSBitmapImageRep *result; NSParameterAssert(data); decoder = aDecoder ? aDecoder : [self decoderForData:data]; if(!decoder){ lastImageCorrupt = YES; return nil; } result = [decoder decodeFromData:data]; lastImageCorrupt = [decoder lastImageCorrupt]; return result; } - (void)setImageDepth:(NSWindowDepth)aDepth /*" Sets the target image depth to aDepth. Some of the image decoders can optimize the decoding process to a specific depth. This method will propagate aDepth to all decoders using the #{setImageDepth} method; whether or not a decoder can actually decode to that depth is entirely up to the decoder. Generally, image decoders default to producing 24-bit deep images. "*/ { unsigned int i,n; n = [decoderList count]; imageDepth = aDepth; for(i = 0; i < n ;i++) [[decoderList objectAtIndex:i] setImageDepth:imageDepth]; } - (NSWindowDepth)imageDepth /*"Returns the image depth of the receiver."*/ { return imageDepth; } - (BOOL)lastImageCorrupt /*"Returns YES if last the image that was decoded contained some kind of error."*/ { return lastImageCorrupt; } - (NSArray *)decoderArray /*"Returns the array of decoders controlled by the receiver."*/ { return decoderList; } - (NSDictionary *)decoderByType /*"Returns the decoder by type dictionary of the receiver."*/ { return decoderByType; } - (NSDictionary *)decoderClassByType /*"Returns the decoder class by type dictionary of the receiver."*/ { return decoderClassByType; } - (BOOL)verboseMode /*"Returns YES if verbose mode is enabled. Default is NO."*/ { return _SIDFlags.verboseMode; } - (void)setVerboseMode:(BOOL)aFlag /*"Enabled/disables verbose mode. Verbose mode spews a HUGE quantity of state information to stderr."*/ { unsigned int i,n; n = [decoderList count]; _SIDFlags.verboseMode = aFlag; for(i = 0; i < n ;i++) [[decoderList objectAtIndex:i] setVerboseMode:aFlag]; } - (void)setSpewToNSLog:(BOOL) aFlag /*" * If aFlag is YES, error messages geneerated by decoders will be printed * via NXLogError(). "*/ { _SIDFlags.spewStderr = aFlag; } - (BOOL)spewToNSLog /*"Returns YES if error messages will be printed to the console/stderr. Default is NO."*/ { return _SIDFlags.spewStderr; } - (void)setErrorDelegate:(id <MiscImageDecoderErrorDelegate>)aDelegate /*" Sets the error delegate to aDelegate. aDelegate's implementation of #{-decoder:spewMessage:withSeverity:} will be invoked whenever a decoder generates an error message. "*/ { errorDelegate = aDelegate; } - (id <MiscImageDecoderErrorDelegate>)errorDelegate /*"Returns the image decoder's error delegate."*/ { return errorDelegate; } - (void)decoder:(MiscImageDecoder *)aDecoder spewMessage:(NSString *)errMsg withSeverity:(MiscImageDecoderErrorSeverity)aSeverity; /*" Invoked whenever a decoder generates an error. If #errorDelegate has been set, it will be notified of the error message via the #{-decoder:spewMessage:withSeverity:} method. If #spewToStderr has been enabled, the message will be printed via the #{NSLog()} function. "*/ { if(errorDelegate) [errorDelegate decoder:aDecoder spewMessage:errMsg withSeverity:aSeverity]; if(_SIDFlags.spewStderr) NSLog(@"*** Image Decoder Msg *** {%@}", errMsg); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.