QLThumbnailImageCreate does not include images used in HTML files - macos

I'm trying to figure an easy way to create screenshots at 1200x800 from nearly one hundred HTML files using QuickLook. This line pretty much sums up with I'm doing:
CGImageRef imageRef = QLThumbnailImageCreate(NULL, (__bridge CFURLRef) [NSURL fileURLWithPath:layoutHtml isDirectory:NO], CGSizeMake(1280 , 800), (__bridge CFDictionaryRef) #{ (NSString*) kQLThumbnailOptionIconModeKey:#(NO)});
Unfortunately the create image does not contain any images used in the HTML file, I only get the question mark "image not found" placeholder. When I use QuickLook from the Finder, images get loaded.
Any ideas on how I could convince QLThumbnailImageCreate to include images?
Thanks,
Ilja

I don't think this is possible unless there is hidden Preview Property.
The Generating Enriched HTML also does not mention anything about loading external resources, only kQLPreviewPropertyAttachmentsKey which requires the HTML to use the cid:identifier URL scheme.
There is webkit2png which is a python script that does what you need. Searching for WebKit screenshot solution also brings up some Cocoa code snippets.

Related

Strip Images from Pasteboard

Can someone please guide how I can strip images from attributed text on the pasteboard?
EXAMPLE
I have a UITextView that supports NSAttributedString. If I allow a user to paste something from the pasteboard that includes an image (say a picture and some text that was copied from a web page in the Safari app), it will crash my app when I try to save it:
*** Assertion failure in -[NSHTMLReader _addAttachmentForElement:URL:needsParagraph:usePlaceholder:], /SourceCache/UIFoundation_Sim/UIFoundation-78/UIFoundation/TextSystem/NSHTMLReader.m:1478
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unable to find missing_image.tiff!'
This only occurs when an image is part of the source copy. Why it refers to tiff I don't know, as the source images I've been testing with are jpg and png.
As described in a related post with slightly different goal, my workaround to avoid the crash is to force the pasteboard to a regular string:
- (void)paste:(id)sender
{
UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
NSString *string = pasteBoard.string;
[self insertText:string];
}
This does prevent a crash, but it also prevents the user from pasting any formatted text. Say bold, or italic that may have come from the Mail app.
So best I can tell, I need to strip any images from the pasteboard so as to allow the text formatting to be retained. Thanks for your help.

Displaying full-sized camera raw files in OSX

This has been driving me mad for months: I have a little app to preview camera raw images. As the files in question can be quite big and stored on a slow network drive I wanted to offer the user a chance to stop the loading of the image.
Handily I found this thread:
Cancel NSData initWithContentsOfURL in NSOperation
and am using Nick's great convenience method to cache the data and be able to issue a cancel request halfway through.
Anyway, once I have the data I use:
NSImage *sourceImage = [[NSImage alloc]initWithData:data];
The problem comes when looking at Nikon .NEF files; sourceImage returns only a thumbnail and not the full size. Displaying Canon .CR2 files and in fact, any other .TIFF's and .JPEG's seems fine and sourceImage is the expected size. I've checked the amount of data that is being loaded (with NSLog and [data length]) and it does seem that all of the Nikon files' 12mb is there for the -initWithData:
If I use
NSImage *sourceImage = [[NSImage alloc]initWithContentsOfURL:myNEFURL];
then I get the full sized image of the Nikon files but of course the app blocks.
So after poking around for what is beginning to feel like my entire life I think I know that the problem is related to the Nikon's metadata stating that the file's DPI is 300 whereas Canon et al is 72.
I hoped a solution would be to lazily access the file with:
NSImage*tempImg = [[NSImage alloc] initByReferencingURL:myNEFURL];
and having seen similar postings here and elsewhere I found a common possible answer of simply
[sourceImage setSize:tempImg.size];
but of course this just resizes the tiny thumbnail up to 3000x2000 or thereabouts.
I've been messing with the following hoping that they would provide a way to get the big picture from the .NEF:
CGImageSourceRef isr = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
CGImageRef isrRef = CGImageSourceCreateImageAtIndex(isr, 0, NULL);
and
NSBitmapImageRep *bitMapIR = [[NSBitmapImageRep alloc] initWithData:data];
But checking the sizes on these show similar thumbnail widths and heights. In fact, isrRef returns an even smaller thumbnail, one that is 4.2 times smaller. Perhaps worth noting that 300 / 72 == 4.2, so isrRef is taking account of the DPI on an image where the DPI (possibly) has already been observed.
Please! Can someone [nicely] put me out of my misery and help me get the full-sized image from the loaded data?!?! Currently, I'm special-case'ing the NEF files with a case insensitive search on the file extension and then loading the URL with the blocking methods. I have to take a hit on the app blocking and the search can't be fool-proof in the long run.
As an aside: is this actually a bug in the OS? It does seem like NSImage's -initWithData: and -initWithContentsOfURL: methods use different engines to actually render the image. Would it not be reasonable to have assumed that -initWithURL: simply loads the data which then gets rendered just as though it had been presented to the class with -initWithData: ?
It's a bug - confirmed when I did a DTS. Apparently I need to file a bug report. Currently the only way is to use the NSURL methods. Instead of checking the file extension I should probably traverse the meta dictionaries and check the manufacturer's entry for "Nikon", though...

The proper way to insert an image in memory into Webview in Cocoa?

I have an image of a graph generated using the Core-Plot framework. I'd like to be able to insert the image into a custom report which is held in a Webview.
Is there an advised or best practise way of doing this. i.e. if the image needs to be saved to disk as a temporay file, where should the image be placed? When should the image be deleted etc.?
Assuming you control all the html that's to be rendered in the webview, I'd suggest saving a sort of local web archive, with the html, image and any other resources all in the same place, making your custom report's rendering much less prone to breaking. (You could even make it a supported bundle document type, if you get that far along.)
If you just need to have the file available for a one-time rendering of a modified html document, I suggest using the NSTemporaryDirectory() path:
NSData *imageData = ...;
NSString *temporaryImagePath = NSTemporaryDirectory();
NSError *error = nil;
temporaryImagePath = [ temporaryImagePath stringByAppendingPathComponent: #"img.jpg" ];
[ imageData writeToFile: temporaryImagePath options: NSDataWritingAtomic error: &error ];

Getting a CGImageRef out of a PDFDocument

I have a PDFDocument (made up of PDFPages ofcourse) and I need a CGImageRef to stick into my IKImageView.
Currently, I get the datarepresentation from the PDFPage, put it into an NSImage, then get the TIFFRepresentation of the NSImage, put it into a CGImageSource, and then get the CGImage out of the source.
That seemsneedlessly complicated, going through two NSData steps...
However, when I try to put the PDF data directly into the CGImageSource, even though that APPEARS to work, when I get the CGImage out, it is always NULL. is there something specific I should be doing to get this to work?
In Snow Leopard there is a method -[NSImage CGImageForProposedRect:context:hints:]. Or you could draw the page into a CGBitmapContext and use CGBitmapContextCreateImage.
Look at the CreatePDFPageImage function in my CGPDFAdditions code. I think that's exactly what you need.
Try feeding the data for the PDF document (as opposed to a single page) into the CGImageSource. Images from the source should correspond to pages in the document.

Mac Quick Look Preview in an NSView or NSImage?

I am looking for a way (public or otherwise) to get an NSView, NSImage, CGImageRef, etc that shows the QuickLook preview for a file. Essentially the equivalent of QLThumbnailImageCreate() but for the preview.
The public APIs I can find do not support this. They allow the creation of a thumbnail image or a QLPreviewPanel. The panel does in fact display the quick look preview, but I cannot get access to the preview's appearance to embed it in other views, nor can I display multiple previews at once.
For background, I am writing an app where users can embed links to other files that should be displayed inline, kind of like an <img> tag in HTML. For images like JPGs and PDFs it's easy to figure out what to display. I thought that for other formats I would use Quick Look to generate a nice visual representation of the file's contents. This way the set of formats supported by my application would be easily extensible (just download new Quick Look generators).
I looked into this extensively once a while back and was not able to find an easy way to do it. Depending on the type of file, QuickLook generates different kinds of output. For example, for iWork files, the generator makes HTML that it displays in a WebView. For other types it returns different types of data.
I never ended up using the code, but here's some code I dug up and some private APIs that might be handy:
id QLPreviewCreate(CFAllocatorRef allocator, CFURLRef url, CFDictionaryRef options);
id QLPreviewCopyBitmapImage(id preview);
id QLPreviewCopyData(id preview);
NSString* QLPreviewGetPreviewType(id preview);
id QLPreviewCopyProperties(id preview);
- (NSData *)getDataForFile:(NSString *)path
{
NSURL *fileURL = [NSURL fileURLWithPath:path];
id preview = QLPreviewCreate(kCFAllocatorDefault, fileURL, 0);
if (preview)
{
NSString* previewType = QLPreviewGetPreviewType(preview);
if ([previewType isEqualToString:#"public.webcontent"])
{
// this preview is HTML data
return QLPreviewCopyData(preview);
}
else
{
NSLog(#"this type is: %#", previewType);
// do something else
}
}
return nil;
}

Resources