Blob Blame History Raw
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>
#import <Cocoa/Cocoa.h>

#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
}