Re: What's the best way to produce thumbnails?
I managed to solve my problem using resource forks.
If you look in the resource fork of adobe saved files (such as .eps which is what I'm specifically programming for) there's a PICT representation of each file that you can extract which is much smaller than the original file. Using that PICT data you can import as image in Carbon/Cocoa framework and then save as a resized jpeg file very quickly, for the generation of thumbnails. I am including the code here:
//
// main.m
// imageconverter2
//
// Created by James Constantino on 8/5/08.
// Copyright __MyCompanyName__ 2008. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#import <ApplicationServices/ApplicationServices.h>
@interface NSImage (Extras)
// creates a copy of the current image while maintaining
// proportions. also centers image, if necessary
- (NSImage*)imageByScalingProportionallyToSize
NSSize)aSize;
@end
@implementation NSImage (Extras)
- (NSImage*)imageByScalingProportionallyToSize
NSSize)targetSize
{
NSImage* sourceImage = self;
NSImage* newImage = nil;
NSAutoreleasePool* poool = [[NSAutoreleasePool alloc] init];
if ([sourceImage isValid])
{
NSSize imageSize = [sourceImage size];
float width = imageSize.width;
float height = imageSize.height;
float targetWidth = targetSize.width;
float targetHeight = targetSize.height;
// scaleFactor will be the fraction that we'll
// use to adjust the size. For example, if we shrink
// an image by half, scaleFactor will be 0.5. the
// scaledWidth and scaledHeight will be the original,
// multiplied by the scaleFactor.
//
// IMPORTANT: the "targetHeight" is the size of the space
// we're drawing into. The "scaledHeight" is the height that
// the image actually is drawn at, once we take into
// account the ideal of maintaining proportions
float scaleFactor = 0.0;
float scaledWidth = targetWidth;
float scaledHeight = targetHeight;
NSPoint thumbnailPoint = NSMakePoint(0,0);
// since not all images are square, we want to scale
// proportionately. To do this, we find the longest
// edge and use that as a guide.
if ( NSEqualSizes( imageSize, targetSize ) == NO )
{
// use the longeset edge as a guide. if the
// image is wider than tall, we'll figure out
// the scale factor by dividing it by the
// intended width. Otherwise, we'll use the
// height.
float widthFactor = targetWidth / width;
float heightFactor = targetHeight / height;
if ( widthFactor < heightFactor )
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
// ex: 500 * 0.5 = 250 (newWidth)
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the thumbnail in the frame. if
// wider than tall, we need to adjust the
// vertical drawing point (y axis)
if ( widthFactor < heightFactor )
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
else if ( widthFactor > heightFactor )
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
// create a new image to draw into
newImage = [[NSImage alloc] initWithSize:targetSize];
// once focus is locked, all drawing goes into this NSImage instance
// directly, not to the screen. It also receives its own graphics
// context.
//
// Also, keep in mind that we're doing this in a background thread.
// You only want to draw to the screen in the main thread, but
// drawing to an offscreen image is (apparently) okay.
[newImage lockFocus];
NSRect thumbnailRect;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect: thumbnailRect
fromRect: NSZeroRect
operation: NSCompositeSourceOver
fraction: 1.0];
[newImage unlockFocus];
}
[poool release];
return [newImage autorelease];
}
@end
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSApp = [NSApplication sharedApplication];
NSString *filePath = [[NSString alloc] init];
NSString *outPath = [[NSString alloc] init];
NSData *photoData = [[NSData alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
if ([args count]>1) {
filePath = [args objectAtIndex:1];
if ([args count]>2) {
outPath = [args objectAtIndex:2];
}
else outPath = @"/Users/jamesc/desktop/temporarypic.jpg";
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:filePath]) {
NSLog(@"Image does not already exist!");
}
[fileManager release];
}
else filePath = nil;
NSLog(@"view should show %@",filePath);
char filepth[256];
strcpy(filepth, [filePath cString]);
FSSpec ResFileSpec;
FSRef ResFileRef;
OSErr err;
err = FSPathMakeRef((const UInt8*)filepth, &ResFileRef, false);
OSErr SpecErr;
SpecErr = FSGetCatalogInfo(&ResFileRef, kFSCatInfoNone, NULL, NULL, &ResFileSpec, NULL);
short Ref;
Ref = FSpOpenResFile(&ResFileSpec, fsRdWrPerm);
OSErr ResErr = ResError();
NSLog(@"ResErr is: %i",ResErr);
NSLog(@"Ref is: %i",Ref);
//if (ResErr < 0) return(ResErr);
//else return Ref;
OSType resTypePict = 'PICT';
UseResFile(Ref);
Handle theResHandle = Get1Resource(resTypePict, 256); // Where TYPE_DESC is a constant defined to equal the dësc ResType, which happens to be 1687253859.
NSData *theResourceData;
theResourceData = [[NSData alloc] initWithBytes:*theResHandle length:GetMaxResourceSize(theResHandle)];
NSImage *imageFromBundle = [[NSImage alloc] initWithData:theResourceData];
if ([imageFromBundle isValid])
{
//NSImage* thumbnail = [imageFromBundle imageByScalingProportionallyToSize:NSMakeSize(150,150)];
NSImage* thumbnail = imageFromBundle;
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:[thumbnail TIFFRepresentation]];
[thumbnail release];
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
photoData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
[imageProps release];
[imageRep release];
//save file
[photoData writeToFile
utPath atomically:NO];
[photoData release];
}
else NSLog(@"imagefromBundle is not valid");
[imageFromBundle release];
[NSApp release];
[pool drain];
return(EXIT_SUCCESS);
}