Xcode Objective-C: Download a custom font and display it in a UILabel - objective-c

First of all: Is it possible to download a custom font and display it in a UILabel?
I'm using this code to download a custom font from internet and display it in a UILabel but it does not work.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize txt_UserName;
- (void)viewDidLoad {
[super viewDidLoad];
// 1
NSString *dataUrl = #"https://dl.dafont.com/dl/?f=stars_fighters";
NSURL *url = [NSURL URLWithString:dataUrl];
// 2
NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// 4: Handle response here
if (error == nil) {
NSLog(#"no error!");
if (data != nil) {
NSLog(#"There is data!");
[self loadFont:data];
}
} else {
NSLog(#"%#", error.localizedDescription);
}
}];
// 3
[downloadTask resume];
}
- (void)loadFont:(NSData *)data
{
NSData *inData = data;
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if(!CTFontManagerRegisterGraphicsFont(font, &error)){
CFStringRef errorDescription = CFErrorCopyDescription(error);
NSLog(#"Failed to load font: %#", errorDescription);
// CFRelease(errorDescription);
}
// CFRelease(font);
// CFRelease(provider);
CTFontRef ctFont = CTFontCreateWithGraphicsFont(font, 30, NULL, NULL);
UIFont *uiFont = CFBridgingRelease(ctFont);
dispatch_async(dispatch_get_main_queue(), ^{
[self.txt_UserName setFont:uiFont];
});
[self fontTest];
}
- (void)fontTest
{
NSArray *fontFamilies = [UIFont familyNames];
for (int i = 0; i < [fontFamilies count]; i++) {
NSString *fontFamily = [fontFamilies objectAtIndex:i];
NSArray *fontNames = [UIFont fontNamesForFamilyName:[fontFamilies objectAtIndex:i]];
NSLog (#"%#: %#", fontFamily, fontNames);
}
}
#end
Anyway I'm getting this error: Failed to load font: The operation couldn’t be completed. Invalid argument
At the place of the custom font I get a default iOS font.

Of course it's possible to download a custom font and display it in a UILabel,here is my code that works well:
step 1: Assuming the font file has been saved in the sandbox path Documents / StarsFighters.ttf, load the font and get font name(in YOUR_CLASS .m file):
+ (NSString *)loadFontAndReturnFontName {
NSString *imgFilePath = [NSString stringWithFormat:#"%#/Documents/StarsFighters.ttf",NSHomeDirectory()];
NSURL *fontUrl = [NSURL fileURLWithPath:imgFilePath];
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)fontUrl);
CGFontRef fontRef = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider);
CTFontManagerRegisterGraphicsFont(fontRef, NULL);
NSString *fontName = CFBridgingRelease(CGFontCopyPostScriptName(fontRef));
return fontName;
}
step2: use custom font
NSString *fontname = [YOUR_CLASS loadFontAndReturnFontName];
//fontname is #"StarsFighters",best set it to a global variable or save it
YOUR_LABEL.font = [UIFont fontWithName:fontname size:18.0];

Related

Importing SimpleAuth ForSquareWeb - 9 build time errors

I'm relatively new to objective-c and hardly know much of swift.
I've been trying to make an app which will implement simpleAuth in order to create a link to the ForsquareWeb API.
I'm using cocoapods and have imported the SimpleAuth related files into my product.
Every file seems to be fine except the SimpleAuth target, specifically the SimpleAuthForSquareWebProvider.m file. This is what the file itself looks like;
//
// SimpleAuthFoursquareWebProvider.m
// SimpleAuth
//
// Created by Julien Seren-Rosso on 23/01/2014.
// Copyright (c) 2014 Byliner, Inc. All rights reserved.
//
#import "SimpleAuthFoursquareWebProvider.h"
#import "SimpleAuthFoursquareWebLoginViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
#import "UIViewController+SimpleAuthAdditions.h"
#implementation SimpleAuthFoursquareWebProvider
#pragma mark - SimpleAuthProvider
+ (NSString *)type {
return #"foursquare-web";
}
+ (NSDictionary *)defaultOptions {
// Default present block
SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) {
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller];
navigation.modalPresentationStyle = UIModalPresentationFormSheet;
UIViewController *presented = [UIViewController SimpleAuth_presentedViewController];
[presented presentViewController:navigation animated:YES completion:nil];
};
// Default dismiss block
SimpleAuthInterfaceHandler dismissBlock = ^(id controller) {
[controller dismissViewControllerAnimated:YES completion:nil];
};
NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]];
options[SimpleAuthPresentInterfaceBlockKey] = presentBlock;
options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock;
return options;
}
- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion {
[[[self accessToken]
flattenMap:^RACStream *(NSString *response) {
NSArray *signals = #[
[self accountWithAccessToken:response],
[RACSignal return:response]
];
return [self rac_liftSelector:#selector(dictionaryWithAccount:accessToken:) withSignalsFromArray:signals];
}]
subscribeNext:^(NSDictionary *response) {
completion(response, nil);
}
error:^(NSError *error) {
completion(nil, error);
}];
}
#pragma mark - Private
- (RACSignal *)accessToken {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
dispatch_async(dispatch_get_main_queue(), ^{
SimpleAuthFoursquareWebLoginViewController *login = [[SimpleAuthFoursquareWebLoginViewController alloc] initWithOptions:self.options];
login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) {
SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey];
dismissBlock(login);
// Parse URL
NSString *fragment = [URL fragment];
NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment];
NSString *token = dictionary[#"access_token"];
// Check for error
if (![token length]) {
[subscriber sendError:error];
return;
}
// Send completion
[subscriber sendNext:token];
[subscriber sendCompleted];
};
SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey];
block(login);
});
return nil;
}];
}
- (RACSignal *)accountWithAccessToken:(NSString *)accessToken {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSDictionary *parameters = #{ #"oauth_token" : accessToken };
NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters];
NSString *URLString = [NSString stringWithFormat:#"https://api.foursquare.com/v2/users/self?v=20140210&%#", query];
NSURL *URL = [NSURL URLWithString:URLString];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)];
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if ([indexSet containsIndex:statusCode] && data) {
NSError *parseError = nil;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError];
if (dictionary) {
[subscriber sendNext:dictionary];
[subscriber sendCompleted];
}
else {
[subscriber sendError:parseError];
}
}
else {
[subscriber sendError:connectionError];
}
}];
return nil;
}];
}
- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSString *)accessToken {
NSMutableDictionary *dictionary = [NSMutableDictionary new];
NSDictionary *userData = account[#"response"][#"user"];
// Provider
dictionary[#"provider"] = [[self class] type];
// Credentials
dictionary[#"credentials"] = #{
#"token" : accessToken
};
// User ID
dictionary[#"uid"] = userData[#"id"];
// Raw response
dictionary[#"extra"] = #{
#"raw_info" : userData
};
// User info
NSMutableDictionary *user = [NSMutableDictionary new];
if (userData[#"contact"][#"email"]) {
user[#"email"] = userData[#"contact"][#"email"];
}
if (userData[#"firstName"]) {
user[#"first_name"] = userData[#"firstName"];
}
if (userData[#"lastName"]) {
user[#"last_name"] = userData[#"lastName"];
}
user[#"name"] = [NSString stringWithFormat:#"%# %#", user[#"first_name"], user[#"last_name"]];
user[#"gender"] = userData[#"gender"];
if ([userData[#"photo"] isKindOfClass:NSDictionary.class]) {
user[#"image"] = [NSString stringWithFormat:#"%#500x500%#", userData[#"photo"][#"prefix"], userData[#"photo"][#"suffix"]];
} else if ([userData[#"photo"] isKindOfClass:NSString.class]) {
user[#"image"] = userData[#"photo"];
}
if (userData[#"photo"]) {
user[#"photo"] = userData[#"photo"];
}
if (userData[#"homeCity"]) {
NSString *homecity = [[userData[#"homeCity"] componentsSeparatedByString:#","] firstObject];
user[#"location"] = homecity;
}
user[#"urls"] = #{
#"Foursquare" : [NSString stringWithFormat:#"https://foursquare.com/user/%#", userData[#"id"]],
};
dictionary[#"info"] = user;
return dictionary;
}
#end
I think it would be easier to show you just a screen shot of the errors and where they're arising in the code itself;
I would really appreciate some insight into where the problem lies. I'm not sure why many of the errors say use of undeclared identifiers, are the imported files not correct?
After trying to re-install the pod file as it was suggested a class hadn't been installed I still have the same problem. Here are screen shots of my podfile and the terminals output when installing the pods;
I just used the Cocoapods application rather than terminal. I got additional information when clicking install.
"[!] The dPicDid [Debug] target overrides the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting defined in `Pods/Target Support Files/Pods-dPicDid/Pods-dPicDid.debug.xcconfig'. This can lead to problems with the CocoaPods installation
[!] The dPicDid [Release] target overrides the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting defined in Pods/Target Support Files/Pods-dPicDid/Pods-dPicDid.release.xcconfig'. This can lead to problems with the CocoaPods installation
- Use the$(inherited)flag, or
- Remove the build settings from the target.
- Use the$(inherited)` flag, or
- Remove the build settings from the target.

uiWebView printing a pdf

Inside of uiwebview, what is a good way print a pdf document?
The pdf is accessible via a url or it can be loaded inside of an iframe.
Using the standard javascript widnow.print() functions will not work.
I am considering using a javascript bridge such as:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *URL = [request URL];
if ([[URL scheme] isEqualToString:#"native"]) {
NSString *urlString = [[request URL] absoluteString];
NSArray *urlParts = [urlString componentsSeparatedByString:#":"];
NSString *cmd = [urlParts objectAtIndex:1];
if ( [cmd isEqualToString:#"printPdf"] ) {
// [self dosomething];
}
}
return YES;
}
At this point I need some sort of xcode function which accept a path to the pdf and send it the airPrinter.
Is this a good approach? I am searching examples of how to print a pdf inside a uiWebView.
As I've earned the tumbleweed badge for no up votes and no responses, I'll post my solution.
This fetches the pdf doc and opens the airPrint dialog--all within a uiWebView.
So if IOS would simply allow the javascript window.print() to function inside of uiWebView, my app would not be setting in the app store waiting for approval and re-release.
Anyway, here's a working solution:
- (void)printInit:(NSString *)parm {
UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
if(!controller){
NSLog(#"Couldn't get shared UIPrintInteractionController!");
return;
}
NSString *base = #"https://someurl.com/";
NSString *ustr = [base stringByAppendingString:parm];
//NSURL *url = [NSURL fileURLWithPath:ustr];
NSURL *url = [NSURL URLWithString:ustr];
NSData *thePdf = [NSData dataWithContentsOfURL:url];
controller.printingItem = thePdf;
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
printInfo.jobName = #"PDFDoc";
controller.printInfo = printInfo;
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
if (!completed && error) {
NSLog(#"FAILED! error = %#",[error localizedDescription]);
}
};
CGRect rect = CGRectMake(310, 5, 100, 5);
[controller presentFromRect:rect inView:self.webView animated:YES completionHandler:completionHandler];
}

iOS 7 NSURLSession Download multiple files in Background

I want to download a List of files using NSUrlSession.
I have a variable for counting the successful downloads #property (nonatomic) int downloadsSuccessfulCounter;. While the files are being downloaded I disable the Download Button. When the counter is equal to the download list size, I enable the button again and set the counter to 0. I do this in the method:
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
...
[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
downloadsSuccessfulCounter++;
if(downloadsSuccessfulCounter == self.downloadList.count) {
NSLog(#"All downloads finished");
[self.syncButton setEnabled:YES];
downloadsSuccessfulCounter = 0;
}
}];
}
Everything is working fine, but when I open again the ViewController I get the message A background URLSession with identifier com.myApp already exists!. The counter is not set to 0 and the UI elements (UIButtons, UILabels) are not responding.
I guess the problem is because the NSURLSession is still open but I'm not really sure about how it works.
I have tried all the tutorials, but 99% of them are only for downloading 1 file, not more than 1...
Any ideas?
Here is my code:
...
#property (nonatomic, strong) NSURLSession *session;
...
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.downloadList = [[NSMutableArray alloc] init];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.myApp"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
}
When I press the Download ButtonI call this method (
I have a Downloadable object which contains a NSURLSessionDownloadTask):
-(void)startDownload {
for (int i=0; i<[self.downloadList count]; i++) {
Downloadable *d = [self.downloadList objectAtIndex:i];
if (!d.isDownloading) {
if (d.taskIdentifier == -1) {
d.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:d.downloadSource]];
}else {
d.downloadTask = [self.session downloadTaskWithResumeData:fdi.taskResumeData];
}
d.taskIdentifier = d.downloadTask.taskIdentifier;
[d.downloadTask resume];
d.isDownloading = YES;
}
}
}
When the app is in Background:
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
appDelegate.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler();
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"All files downloaded";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}];
}
}
}];
}
So, as I mentioned in my comments, the issue is that each File requires a unique NSURLSession, and each NSURLSession requires a NSURLSessionConfiguration with a unique identifier.
I think that you were close - and probably more proper than me in certain aspects...
You just need to create a structure to pass unique IDs into unique Configurations, to populate unique Sessions (say that 10x fast).
Here's what I did:
/*
* Retrieves the List of Files to Download
* Also uses the size of that list to instantiate items
* In my case, I load a character returned text file with the names of the files that I want to download
*/
- (void) getMediaList {
NSString *list = #"http://myserver/media_list.txt";
NSURLSession *session = [NSURLSession sharedSession]; // <-- BASIC session
[[session dataTaskWithURL:[NSURL URLWithString:list]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *stringFromData = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
// Populate Arrays
REMOTE_MEDIA_FILE_PATHS = [stringFromData componentsSeparatedByString:#"\n"];
[self instantiateURLSessions:[REMOTE_MEDIA_FILE_PATHS count]];
// Start First File
[self getFile:[REMOTE_MEDIA_FILE_PATHS objectAtIndex:downloadCounter]:downloadCounter]; // this variable is 0 at the start
}]
resume];
}
/*
* This sets Arrays of Configurations and Sessions to the proper size
* It also gives a unique ID to each one
*/
- (void) instantiateURLSessions : (int) size {
NSMutableArray *configurations = [NSMutableArray array];
NSMutableArray *sessions = [NSMutableArray array];
for (int i = 0; i < size; i++) {
NSString *index = [NSString stringWithFormat:#"%i", i];
NSString *UniqueIdentifier = #"MyAppBackgroundSessionIdentifier_";
UniqueIdentifier = [UniqueIdentifier stringByAppendingString:index];
[configurations addObject: [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:UniqueIdentifier]];
[sessions addObject:[NSURLSession sessionWithConfiguration: [configurations objectAtIndex:i] delegate: self delegateQueue: [NSOperationQueue mainQueue]]];
}
NSURL_BACKGROUND_CONFIGURATIONS = [NSArray arrayWithArray:configurations];
NSURL_BACKGROUND_SESSIONS = [NSArray arrayWithArray:sessions];
}
/*
* This sets up the Download task for each file, based off of the index of the array
* It also concatenates the path to the actual file
*/
- (void) getFile : (NSString*) file :(int) index {
NSString *fullPathToFile = REMOTE_MEDIA_PATH; // Path To Server With Files
fullPathToFile = [fullPathToFile stringByAppendingString:file];
NSURL *url = [NSURL URLWithString:fullPathToFile];
NSURLSessionDownloadTask *downloadTask = [[NSURL_BACKGROUND_SESSIONS objectAtIndex:index ] downloadTaskWithURL: url];
[downloadTask resume];
}
/*
* Finally, in my delegate method, upon the completion of the download (after the file is moved from the temp data), I check if I am done and if not call the getFiles method again with the updated counter for the index
*/
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
// Get the documents directory URL
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:LOCAL_MEDIA_PATH];
NSURL *customDirectory = [NSURL fileURLWithPath:dataPath];
// Get the file name and create a destination URL
NSString *sendingFileName = [downloadTask.originalRequest.URL lastPathComponent];
NSURL *destinationUrl = [customDirectory URLByAppendingPathComponent:sendingFileName];
// Move the file
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager moveItemAtURL:location toURL:destinationUrl error: &error]) {
// List
[self listCustomDirectory];
if(downloadCounter < [REMOTE_MEDIA_FILE_PATHS count] -1) {
// Increment Counter
downloadCounter++;
// Start Next File
[self getFile:[REMOTE_MEDIA_FILE_PATHS objectAtIndex:downloadCounter]:downloadCounter];
}
else {
// FINISH YOUR OPERATION / NOTIFY USER / ETC
}
}
else {
NSLog(#"Damn. Error %#", error);
// Do Something Intelligent Here
}
}

Cacheing UIImage as NSData and getting it back

I'm trying to cache images I load from Flickr. If I load the same image, I'm hoping to use the cached version instead. For some reason, when I download an image from the internet, it works, but if I load it from my cache, it displays a blank image. I checked cacheData, and it has the same amount of bits as the image I put in, so it appears loading the file is working.
Here is how I cache images:
+ (void)cachePhoto:(NSData *)photo withKey:(NSString *)key {
if (photo) {
NSArray * urlArray = [fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSURL * targetDirectory = (NSURL *)[urlArray objectAtIndex:0];
targetDirectory = [targetDirectory URLByAppendingPathComponent:key];
[photo writeToURL:targetDirectory atomically:YES];
[cachedPhotos addObject:key];
NSLog(#"target url %#", targetDirectory);
}
}
+ (NSData *)photoInCache:(NSString *)key {
if ([cachedPhotos containsObject:key]) {
NSString * path = [[cacheDirectory URLByAppendingPathComponent:key] path];
NSLog(#"path: %#", path);
return [fileManager contentsAtPath:path];
} else {
return nil;
}
}
And my code to get it back:
NSData * cacheData = [PhotoCache photoInCache:key];
if (cacheData) {
self.imageView.image = [UIImage imageWithData:cacheData];
[spinner stopAnimating];
NSLog(#"used cached image");
} else {
dispatch_queue_t downloadQueue = dispatch_queue_create("get photo from flickr", NULL);
dispatch_async(downloadQueue, ^{
NSData * imageData = [[NSData alloc] initWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
[spinner stopAnimating];
self.imageView.image = [UIImage imageWithData:imageData];
[PhotoCache cachePhoto:imageData
withKey:key];
});
});
}
I figured it out - I was loading the image into the imageView in my prepareForSegue, where the ImageView was not yet loaded. I loaded the image in viewDidLoad and it worked. I also had to use UIImagePNGRepresentation, like suggested in the comments.

Remove curled corner from qlgenerator thumbnail

How do I remove the curled icon a thumbnail create in a quicklook plugin?
Screenshot of current icon:
Screenshot of what I want:
GeneratePreviewForURL.m:
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>
#import "GenerateIcon.h"
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options);
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
/* -----------------------------------------------------------------------------
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)
{
// To complete your generator please implement the function GeneratePreviewForURL in GeneratePreviewForURL.c
[GenerateIcon generatePreviewWithRef:preview URL:url];
return noErr;
}
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview)
{
// Implement only if supported
}
GenerateIcon.m:
//
// GenerateIcon.m
// Windows Binary Icon
//
// Created by Asger Hautop Drewsen on 2/5/12.
// Copyright (c) 2012 Asger Drewsen. All rights reserved.
//
#import "GenerateIcon.h"
#implementation GenerateIcon
+(void) generateThumbnailWithRef:(QLThumbnailRequestRef)requestRef URL:(CFURLRef)url
{
[GenerateIcon generateMultiWithThumbnailRef:requestRef PreviewRef:nil URL:url];
}
+(void) generatePreviewWithRef:(QLPreviewRequestRef)requestRef URL:(CFURLRef)url
{
[GenerateIcon generateMultiWithThumbnailRef:nil PreviewRef:requestRef URL:url];
}
+(void) generateMultiWithThumbnailRef:(QLThumbnailRequestRef)thumbnail PreviewRef:(QLPreviewRequestRef)preview URL:(CFURLRef)url
{
#autoreleasepool {
NSString * tempDir = NSTemporaryDirectory();
if (tempDir == nil)
tempDir = #"/tmp";
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSString *directory = [tempDir stringByAppendingFormat: [NSString stringWithFormat:#"%#-%.0f", #"exe-icons", [NSDate timeIntervalSinceReferenceDate] * 1000.0]];
//NSString *directory = [tempDir stringByAppendingPathComponent:#"com.tyilo.exe-icons"];
/*for (NSString *file in [fileManager contentsOfDirectoryAtPath:directory error:nil])
{
[fileManager removeItemAtPath:file error:nil];
}*/
[fileManager createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:nil];
[[NSTask launchedTaskWithLaunchPath:#"/usr/local/bin/wrestool" arguments:[NSArray arrayWithObjects:
#"-t",
#"group_icon",
#"-o",
directory,
#"-x",
[(__bridge NSURL *)url path],
nil]] waitUntilExit];
NSArray *icons = [fileManager contentsOfDirectoryAtPath:directory error:nil];
if (icons.count > 0)
{
NSImage *image = [[NSImage alloc] initWithContentsOfFile:[directory stringByAppendingPathComponent: [icons objectAtIndex:0]]];
NSData *thumbnailData = [image TIFFRepresentation];
CGSize size = image.size;
NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:size.width],kQLPreviewPropertyWidthKey,
[NSNumber numberWithInt:size.height],kQLPreviewPropertyHeightKey,
nil];
CGContextRef CGContext;
if (thumbnail)
{
CGContext = QLThumbnailRequestCreateContext(thumbnail, size, TRUE, (__bridge CFDictionaryRef)properties);
}
else
{
CGContext = QLPreviewRequestCreateContext(preview, size, TRUE, (__bridge CFDictionaryRef)properties);
}
if(CGContext) {
NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)CGContext flipped:size.width > size.height];
if(context) {
//These two lines of code are just good safe programming…
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:context];
NSBitmapImageRep *thumbnailBitmap = [NSBitmapImageRep imageRepWithData:thumbnailData];
[thumbnailBitmap draw];
//This line sets the context back to what it was when we're done
[NSGraphicsContext restoreGraphicsState];
}
// When we are done with our drawing code QLThumbnailRequestFlushContext() is called to flush the context
if (thumbnail)
{
QLThumbnailRequestFlushContext(thumbnail, CGContext);
}
else
{
QLPreviewRequestFlushContext(preview, CGContext);
}
// Release the CGContext
CFRelease(CGContext);
}
/*NSLog(#"%#", [directory stringByAppendingPathComponent: [icons objectAtIndex:0]]);
CGImageRef image = (__bridge CGImageRef) [[NSImage alloc] initByReferencingFile:[directory stringByAppendingPathComponent: [icons objectAtIndex:0]]];
QLThumbnailRequestSetImage(thumbnail, image, properties);*/
}
else
{
NSLog(#"Failed to generate thumbnail!");
}
}
}
#end
Edit: Added screenshots.
You need to add the undocumented "IconFlavor" key to the properties dictionary that you supply to QLThumbnailRequestCreateContext() or QLThumbnailRequestSetXXX(), and give it the value 1 for minimal decoration.
See here for an example. At the top of that file are some other values I've discovered for "IconFlavour".
The aspect of your icons is automatically chosen by Quick Look and there is no public way to customize that. What is your type conformance tree?
For more information on UTIs see Uniform Type Identifiers Overview. Note that your type conformance tree won't necessarily translate to what you want from Quick Look but at least you will have a sane starting point.