From a012d721a3075328f675d82f4a760b81389bf8df Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sun, 22 Jan 2017 00:10:27 +0200 Subject: [PATCH] Added a Preview generator for Quick Look, so QL framework won't "ban" our plugin for failing to generate these. --- QuickLook/GenerateThumbnailForURL.m | 96 ---------------------- QuickLook/generator.m | 118 ++++++++++++++++++++++++++++ QuickLook/main.c | 3 +- 3 files changed, 120 insertions(+), 97 deletions(-) delete mode 100644 QuickLook/GenerateThumbnailForURL.m create mode 100644 QuickLook/generator.m diff --git a/QuickLook/GenerateThumbnailForURL.m b/QuickLook/GenerateThumbnailForURL.m deleted file mode 100644 index 13e9e2f..0000000 --- a/QuickLook/GenerateThumbnailForURL.m +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include "get_image_for_rom.h" - -/* ----------------------------------------------------------------------------- - Generate a thumbnail for file - - This function's job is to create thumbnail for designated file as fast as possible - ----------------------------------------------------------------------------- */ - -OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) -{ - @autoreleasepool { - /* Load the template NSImages when generating the first thumbnail */ - static NSImage *template = nil; - static NSImage *templateUniversal = nil; - static NSImage *templateColor = nil; - static NSBundle *bundle = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - bundle = [NSBundle bundleWithIdentifier:@"com.github.liji32.sameboy.previewer"]; - template = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CartridgeTemplate" ofType:@"png"]]; - templateUniversal = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"UniversalCartridgeTemplate" ofType:@"png"]]; - templateColor = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"ColorCartridgeTemplate" ofType:@"png"]]; - }); - - uint32_t bitmap[160*144]; - uint8_t cgbFlag = 0; - - /* The cgb_boot_fast boot ROM skips the boot animation */ - if (get_image_for_rom([[(__bridge NSURL *)url path] UTF8String], - [[bundle pathForResource:@"cgb_boot_fast" ofType:@"bin"] UTF8String], - bitmap, &cgbFlag, (cancel_callback_t)QLThumbnailRequestIsCancelled, thumbnail)) { - return noErr; - } - - /* Convert the screenshot to a CGImageRef */ - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmap, sizeof(bitmap), NULL); - CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); - CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; - CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; - - CGImageRef iref = CGImageCreate(160, - 144, - 8, - 32, - 4 * 160, - colorSpaceRef, - bitmapInfo, - provider, - NULL, - YES, - renderingIntent); - - - /* Draw the icon */ - CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, [template size], false, (__bridge CFDictionaryRef)(@{@"IconFlavor" : @(0)})); - if (cgContext) { - NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)cgContext flipped:NO]; - if (context) { - [NSGraphicsContext setCurrentContext:context]; - - /* Use the CGB flag to determine the cartrdige "look": - - DMG cartridges are grey - - CGB cartrdiges are transparent - - CGB cartridges that support DMG systems are black - */ - NSImage *effectiveTemplate = nil; - switch (cgbFlag) { - case 0xC0: - effectiveTemplate = templateColor; - break; - case 0x80: - effectiveTemplate = templateUniversal; - break; - default: - effectiveTemplate = template; - } - - /* Convert the screenshot to a magnified NSImage */ - NSImage *screenshot = [[NSImage alloc] initWithCGImage:iref size:NSMakeSize(640, 576)]; - /* Draw the screenshot */ - [screenshot drawInRect:NSMakeRect(192, 150, 640, 576)]; - /* Mask it with the template (The middle part of the template image is transparent) */ - [effectiveTemplate drawInRect:(NSRect){{0,0},template.size}]; - } - QLThumbnailRequestFlushContext(thumbnail, cgContext); - CFRelease(cgContext); - } - - CGColorSpaceRelease(colorSpaceRef); - CGDataProviderRelease(provider); - CGImageRelease(iref); - } - return noErr; -} \ No newline at end of file diff --git a/QuickLook/generator.m b/QuickLook/generator.m new file mode 100644 index 0000000..1b23532 --- /dev/null +++ b/QuickLook/generator.m @@ -0,0 +1,118 @@ +#include +#include +#include "get_image_for_rom.h" + +static OSStatus render(CGContextRef cgContext, CFURLRef url, cancel_callback_t cancelCallback, void *cancelData, bool showBorder) +{ + /* Load the template NSImages when generating the first thumbnail */ + static NSImage *template = nil; + static NSImage *templateUniversal = nil; + static NSImage *templateColor = nil; + static NSBundle *bundle = nil; + static dispatch_once_t onceToken; + if (showBorder) { + dispatch_once(&onceToken, ^{ + bundle = [NSBundle bundleWithIdentifier:@"com.github.liji32.sameboy.previewer"]; + template = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CartridgeTemplate" ofType:@"png"]]; + templateUniversal = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"UniversalCartridgeTemplate" ofType:@"png"]]; + templateColor = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"ColorCartridgeTemplate" ofType:@"png"]]; + }); + } + uint32_t bitmap[160*144]; + uint8_t cgbFlag = 0; + + /* The cgb_boot_fast boot ROM skips the boot animation */ + if (get_image_for_rom([[(__bridge NSURL *)url path] UTF8String], + [[bundle pathForResource:@"cgb_boot_fast" ofType:@"bin"] UTF8String], + bitmap, &cgbFlag, cancelCallback, cancelData)) { + return -1; + } + + /* Convert the screenshot to a CGImageRef */ + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmap, sizeof(bitmap), NULL); + CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; + CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; + + CGImageRef iref = CGImageCreate(160, + 144, + 8, + 32, + 4 * 160, + colorSpaceRef, + bitmapInfo, + provider, + NULL, + YES, + renderingIntent); + CGContextSetInterpolationQuality(cgContext, kCGInterpolationNone); + NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)cgContext flipped:NO]; + [NSGraphicsContext setCurrentContext:context]; + + + /* Convert the screenshot to a magnified NSImage */ + NSImage *screenshot = [[NSImage alloc] initWithCGImage:iref size:NSMakeSize(160, 144)]; + /* Draw the screenshot */ + if (showBorder) { + [screenshot drawInRect:NSMakeRect(192, 150, 640, 576)]; + } + else { + [screenshot drawInRect:NSMakeRect(0, 0, 640, 576)]; + } + + if (showBorder) { + /* Use the CGB flag to determine the cartrdige "look": + - DMG cartridges are grey + - CGB cartrdiges are transparent + - CGB cartridges that support DMG systems are black + */ + NSImage *effectiveTemplate = nil; + switch (cgbFlag) { + case 0xC0: + effectiveTemplate = templateColor; + break; + case 0x80: + effectiveTemplate = templateUniversal; + break; + default: + effectiveTemplate = template; + } + + /* Mask it with the template (The middle part of the template image is transparent) */ + [effectiveTemplate drawInRect:(NSRect){{0,0},template.size}]; + } + + CGColorSpaceRelease(colorSpaceRef); + CGDataProviderRelease(provider); + CGImageRelease(iref); + + return noErr; +} + +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) +{ + @autoreleasepool { + CGContextRef cgContext = QLPreviewRequestCreateContext(preview, ((NSSize){640, 576}), true, nil); + if (render(cgContext, url, (cancel_callback_t)QLPreviewRequestIsCancelled, preview, false) == noErr) { + QLPreviewRequestFlushContext(preview, cgContext); + CGContextRelease(cgContext); + return noErr; + } + CGContextRelease(cgContext); + return -1; + } +} + +OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) +{ + @autoreleasepool { + CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, ((NSSize){1024, 1024}), true, (__bridge CFDictionaryRef)(@{@"IconFlavor" : @(0)})); + if (render(cgContext, url, (cancel_callback_t)QLThumbnailIsCancelled, thumbnail, true) == noErr) { + QLThumbnailRequestFlushContext(thumbnail, cgContext); + CGContextRelease(cgContext); + return noErr; + } + CGContextRelease(cgContext); + return -1; + } +} \ No newline at end of file diff --git a/QuickLook/main.c b/QuickLook/main.c index 7998fb5..8566e32 100644 --- a/QuickLook/main.c +++ b/QuickLook/main.c @@ -24,8 +24,8 @@ // typedefs // ----------------------------------------------------------------------------- -// The thumbnail generation function to be implemented in GenerateThumbnailForURL.c OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); // The layout for an instance of QuickLookGeneratorPlugIn typedef struct __QuickLookGeneratorPluginType @@ -133,6 +133,7 @@ HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *p * return good status. */ ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GenerateThumbnailForURL = GenerateThumbnailForURL; + ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GeneratePreviewForURL = GeneratePreviewForURL; ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType*)thisInstance)->conduitInterface)->AddRef(thisInstance); *ppv = thisInstance; CFRelease(interfaceID);