Mac OS X Reference Library Apple Developer
Search

Saving Previews and Thumbnails in the Document

As one approach for providing thumbnail and preview data to Quick Look, the application can store that data as part of the document data. The generator can then access it and return it to Quick Look in a call to QLThumbnailRequestSetImageWithData or QLPreviewRequestSetDataRepresentation. This approach permits a quick response time for the generator, but at the expense of a larger document file.

To illustrate how your generator might provide previews and thumbnails using this approach, the following listings show modifications to the code for the Sketch application that writes a thumbnail image as part of the document data. “Sketch example project: adding a thumbnail property” shows how you might define a property of the NSDocument subclass to hold the image data.

Listing 7-1  Sketch example project: adding a thumbnail property

@interface SKTDrawDocument : NSDocument {
    @private
    NSMutableArray *_graphics;
    // ...other instance variables here...
    NSData *_thumbnail;
}
// ...existing methods here...
- (NSData *)thumbnail;

Implement the thumbnail accessor method to return the thumbnail image. To the the NSDocument method that prepares the document data for writing out to a file (dataOfType:error:) are added the lines of code in “Sketch example project: including the thumbnail with the document data” indicated by the “new” labels.

Listing 7-2  Sketch example project: including the thumbnail with the document data

static NSString *SKTThumbnailImageKey = @"SketchThumbnail";                   // new
 
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    NSData *data,;
    NSArray *graphics = [self graphics];
    NSPrintInfo *printInfo = [self printInfo];
    NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
    BOOL useTypeConformance = [workspace respondsToSelector:@selector(type:conformsToType:)];
    if ((useTypeConformance && [workspace type:SKTDrawDocumentNewTypeName conformsToType:typeName]) || [typeName isEqualToString:SKTDrawDocumentOldTypeName]) {
        NSData *tiffRep;                                                     // new
        NSMutableDictionary *properties = [NSMutableDictionary dictionary];
        [properties setObject:[NSNumber numberWithInt:SKTDrawDocumentCurrentVersion] forKey:SKTDrawDocumentVersionKey];
        [properties setObject:[SKTGraphic propertiesWithGraphics:graphics] forKey:SKTDrawDocumentGraphicsKey];
        [properties setObject:[NSArchiver archivedDataWithRootObject:printInfo] forKey:SKTDrawDocumentPrintInfoKey];
        tiffRep = [self TIFFDataWithGraphics:graphics error:outError];        // new
        [properties setObject:tiffRep forKey:SKTThumbnailImageKey];           // new
        data = [NSPropertyListSerialization dataFromPropertyList:properties format:NSPropertyListBinaryFormat_v1_0 errorDescription:NULL];
    } else if ((useTypeConformance && [workspace type:(NSString *)kUTTypePDF conformsToType:typeName]) || [typeName isEqualToString:NSPDFPboardType]) {
    data = [SKTRenderingView pdfDataWithGraphics:graphics];
    } else {
    NSParameterAssert((useTypeConformance && [workspace type:(NSString *)kUTTypeTIFF conformsToType:typeName]) || [typeName isEqualToString:NSTIFFPboardType]);
        data = [SKTRenderingView tiffDataWithGraphics:graphics error:outError];
    }
    return data;
}

In the corresponding NSDocument method for reading document data back in (readFromData:ofType:error:) “unpack” the thumbnail from the dictionary of document properties:

_thumbnail = [[properties objectForKey:SKTThumbnailImageKey] retain];

Now implementing the generator for Sketch is a simple matter of accessing the thumbnail image data and passing it to Quick Look in a call to QLThumbnailRequestSetImageWithData, as shown in “Returning the stored thumbnail image to Quick Look.” (For previews, the corresponding function is QLPreviewRequestSetDataRepresentation.)

Listing 7-3  Returning the stored thumbnail image to Quick Look

OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize)
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    SKTDrawDocument* document = [[[SKTDrawDocument alloc] init] autorelease];
    if(![document readFromURL:(NSURL *)url ofType:(NSString *)contentTypeUTI]) {
        [pool release];
        return noErr;
    }
    if ([document respondsToSelector:@selector(thumbnail)]) {  // runtime verification
        NSData *tiffData = [document thumbnail];
        if (tiffData != nil) {
            NSDictionary *props = [NSDictionary dictionaryWithObject:@"public.tiff" forKey:(NSString *)kCGImageSourceTypeIdentifierHint];
            QLThumbnailRequestSetImageWithData(thumbnail, (CFDataRef)tiffData, (CFDictionaryRef)props);
            [pool release];
            return noErr;
        }
    }
    NSSize canvasSize = [document canvasSize];
    CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, *(CGSize *)&canvasSize, false, NULL);
    if(cgContext) {
        NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)cgContext flipped:YES];
        if(context) {
            [document drawDocumentInContext:context];
        }
        QLThumbnailRequestFlushContext(thumbnail, cgContext);
        CFRelease(cgContext);
    }
    [pool release];
    return noErr;
}

In the call to QLThumbnailRequestSetImageWithData, the generator indicates the image format to Quick Look with the kCGImageSourceTypeIdentifierHint property. Note that this example checks whether the class of the document object implements the thumbnail accessor method (to exclude prior versions of the application) and, if so, it checks whether thumbnail data is returned. If it isn’t, it draws the thumbnail image in a Quick Look–provided graphics context.




Last updated: 2009-07-20

Did this document help you? Yes It's good, but... Not helpful...