#include #include #include #import #include "ddjvuRef.h" /* ----------------------------------------------------------------------------- Generate a preview for file This function's job is to create preview for designated file ----------------------------------------------------------------------------- */ OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) { CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview); char *ddjvu = ddjvuPath(bundle); if (ddjvu != NULL) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSDictionary *domain = [defaults persistentDomainForName:@"org.djvu.qlgenerator"]; CFUUIDRef uuid = NULL; CFStringRef uuidString; BOOL debug = FALSE; NSString *tmpPath = nil; if (domain && [domain objectForKey:@"previewpages"]) if ([[domain objectForKey:@"previewpages"] intValue] == 0) goto poppool; if (domain && [domain objectForKey:@"debug"]) { debug = [[domain objectForKey:@"debug"] boolValue]; } uuid = CFUUIDCreate(kCFAllocatorDefault); if (uuid) { uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuid); if (uuidString) { tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat:@"djvuql-%@", uuidString]]; CFRelease(uuidString); } CFRelease(uuid); } if (tmpPath) { const char *cmd = NULL; CFStringRef cmdRef; int page = 0; int pages = 1; int maxpages = 5; int width = 612; // default 8.5x11 in points int height = 792; CGSize size; MDItemRef mditem = NULL; NSString *source = (NSString *)CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); NSString *dest = nil; NSFileManager *fmgr = [NSFileManager defaultManager]; [fmgr createDirectoryAtPath:tmpPath attributes:nil]; mditem = MDItemCreate(kCFAllocatorDefault, (CFStringRef)source); if (mditem) { CFTypeRef ref = NULL; ref = MDItemCopyAttribute(mditem, kMDItemNumberOfPages); if (ref) { CFNumberGetValue(ref, kCFNumberIntType, &pages); CFRelease(ref); } ref = MDItemCopyAttribute(mditem, kMDItemPageWidth); if (ref) { CFNumberGetValue(ref, kCFNumberIntType, &width); CFRelease(ref); } ref = MDItemCopyAttribute(mditem, kMDItemPageHeight); if (ref) { CFNumberGetValue(ref, kCFNumberIntType, &height); CFRelease(ref); } CFRelease(mditem); } if (domain && [domain objectForKey:@"previewpages"]) maxpages = [[domain objectForKey:@"previewpages"] intValue]; if (debug) { NSLog(@"metadata: pages=%d, width=%d, height=%d", pages, width, height); NSLog(@"maxpages=%d", maxpages); } CGRect rect = CGRectMake(0, 0, width, height); CGContextRef c; c = QLPreviewRequestCreatePDFContext(preview, &rect, NULL, NULL); page = 0; do { page++; dest = [tmpPath stringByAppendingPathComponent:[[source lastPathComponent] stringByAppendingFormat:@"_t_p%04d.tiff", page]]; size = CGSizeMake(width, height); cmdRef = CFStringCreateWithFormat(NULL, NULL, CFSTR("\"%s\" -format=tiff -page=%d -size=%dx%d \"%s\" \"%s\""), ddjvu, page, width, height, [source fileSystemRepresentation], [dest fileSystemRepresentation]); cmd = CFStringGetCStringPtr(cmdRef, CFStringGetSystemEncoding()); if (cmd != NULL) { if (debug) NSLog(@"%s", cmd); if ((system(cmd) == 0) && ([fmgr fileExistsAtPath:dest])) { NSURL *durl = [NSURL fileURLWithPath:dest]; CGImageSourceRef sourceRef; sourceRef = CGImageSourceCreateWithURL((CFURLRef)durl, NULL); if(sourceRef) { CGImageRef imageRef = NULL; imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, NULL); if (imageRef) { CGFloat offset = height * (page-1); CGRectOffset(rect, 0.0, offset); CGPDFContextBeginPage(c, NULL); CGContextSaveGState(c); CGContextDrawImage(c, rect, imageRef); if (page == maxpages && maxpages < pages) { CGAffineTransform m; CFURLRef more = CFBundleCopyResourceURL(bundle, CFSTR("more_pages"), CFSTR("pdf"), NULL); CGPDFDocumentRef doc = CGPDFDocumentCreateWithURL(more); CGPDFPageRef pdf = CGPDFDocumentGetPage(doc, 1); CGFloat offset = height * page; CGRectOffset(rect, 0.0, offset); CGContextSaveGState(c); m = CGPDFPageGetDrawingTransform(pdf, kCGPDFMediaBox, rect, 0, true); CGContextConcatCTM(c, m); CGContextDrawPDFPage(c, pdf); CGContextRestoreGState(c); CFRelease(doc); } CGContextRestoreGState(c); CGPDFContextEndPage(c); CFRelease(imageRef); } CFRelease(sourceRef); } } } CFRelease(cmdRef); } while (page < pages && page < maxpages); CGPDFContextClose(c); QLPreviewRequestFlushContext(preview, c); CFRelease(c); [fmgr removeFileAtPath:tmpPath handler:nil]; [source release]; } poppool: [pool release]; } return noErr; } void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) { // implement only if supported }