Created
October 4, 2016 00:31
-
-
Save rsms/206eca5c41ab565153ee8ca11620ffe3 to your computer and use it in GitHub Desktop.
QuickLook icon generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <Foundation/Foundation.h> | |
#include "common.h" | |
@interface IconRequest : NSObject | |
@property (readonly) BOOL canceled; | |
@property (readonly) CGImageRef image; // null if canceled or failed | |
- (void)cancel; | |
@end | |
struct IconStore { | |
IconStore(){} | |
IconRequest* requestIcon(NSString* path, | |
double scaleFactor, | |
double maxWidthPt, | |
double maxHeightPt, | |
void(^cb)(IconRequest*)); | |
}; | |
extern IconStore iconStore; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "IconStore.h" | |
#import <AppKit/AppKit.h> | |
#import <QuickLook/QuickLook.h> | |
IconStore iconStore; | |
@interface IconRequest (Internal) | |
- (instancetype)initWithRequestID:(QLThumbnailRef)requestID; | |
- (void)nullRequestID; | |
- (void)setIsCanceled; | |
- (void)setImage:(CGImageRef)img; | |
@end | |
IconRequest* IconStore::requestIcon(NSString* path, | |
double scaleFactor, | |
double maxWidthPt, | |
double maxHeightPt, | |
void(^cb)(IconRequest*)) | |
{ | |
// [BUG] Don't use kQLThumbnailOptionIconModeKey — it will cause random failures. | |
auto options = @{ | |
(__bridge NSString*)kQLThumbnailOptionScaleFactorKey: @(scaleFactor), | |
}; | |
auto cfurl = (__bridge CFURLRef)[NSURL fileURLWithPath:path]; | |
QLThumbnailRef thumb = QLThumbnailCreate(kCFAllocatorDefault, cfurl, {maxWidthPt,maxHeightPt}, (__bridge CFDictionaryRef)options); | |
auto req = [[IconRequest alloc] initWithRequestID:thumb]; | |
CFRelease(thumb); // now solely referenced by `req` | |
QLThumbnailDispatchAsync(thumb, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
if (QLThumbnailIsCancelled(thumb)) { | |
dispatch_async(dispatch_get_main_queue(), ^{ | |
[req setIsCanceled]; | |
cb(req); | |
}); | |
} else { | |
auto img = QLThumbnailCopyImage(thumb); | |
dispatch_async(dispatch_get_main_queue(), ^{ | |
[req setImage:img]; | |
if (img) { | |
CGImageRelease(img); | |
} | |
cb(req); | |
}); | |
} | |
}); | |
return req; | |
} | |
@implementation IconRequest { | |
@public | |
QLThumbnailRef _requestID; | |
BOOL _isCanceled; | |
CGImageRef _img; | |
} | |
@synthesize canceled = _isCanceled; | |
@synthesize image = _img; | |
- (instancetype)initWithRequestID:(QLThumbnailRef)requestID { | |
self = [super init]; | |
_requestID = requestID; | |
_isCanceled = NO; | |
CFRetain(_requestID); | |
return self; | |
} | |
- (void)dealloc { | |
if (_requestID) { | |
CFRelease((QLThumbnailRef)_requestID); | |
} | |
if (_img) { | |
CGImageRelease(_img); | |
} | |
} | |
- (void)cancel { | |
_isCanceled = YES; | |
if (_requestID) { | |
QLThumbnailCancel((QLThumbnailRef)_requestID); | |
CFRelease((QLThumbnailRef)_requestID); | |
_requestID = nullptr; | |
} | |
} | |
- (void)nullRequestID { | |
if (_requestID) { | |
CFRelease((QLThumbnailRef)_requestID); | |
_requestID = nullptr; | |
} | |
} | |
- (void)setIsCanceled { | |
_isCanceled = YES; | |
} | |
- (void)setImage:(CGImageRef)img { | |
auto oldImg = _img; | |
_img = img; | |
if (_img) { | |
CGImageRetain(_img); | |
} | |
if (oldImg) { | |
CGImageRelease(oldImg); | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment