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. Listing 7-1 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 Listing 7-2 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:(__bridge NSString *)kUTTypePDF conformsToType:typeName]) |
|| [typeName isEqualToString:NSPDFPboardType]) { |
data = [SKTRenderingView pdfDataWithGraphics:graphics]; |
} else { |
NSParameterAssert((useTypeConformance && [workspace type:(__bridge 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]; |
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 Listing 7-3. (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) |
{ |
@autoreleasepool { |
SKTDrawDocument* document = [[SKTDrawDocument alloc] init]; |
if (![document readFromURL:(__bridge NSURL *)url |
ofType:(__bridge NSString *)contentTypeUTI]) { |
return noErr; |
} |
if ([document respondsToSelector:@selector(thumbnail)]) { // runtime verification |
NSData *tiffData = [document thumbnail]; |
if (tiffData != nil) { |
NSDictionary *props = [NSDictionary dictionaryWithObject:@"public.tiff" forKey:(__bridge NSString *)kCGImageSourceTypeIdentifierHint]; |
QLThumbnailRequestSetImageWithData(thumbnail, (__bridge CFDataRef)tiffData, (__bridge CFDictionaryRef)props); |
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); |
} |
} |
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.
Copyright © 2013 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2013-12-16