Thumbnail preview
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
540A649E22EE78B200470937 /* GeneratePreviewForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */; };
|
||||
540A64A022EE78B200470937 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649F22EE78B200470937 /* main.c */; };
|
||||
541EF8B322EEFBEA00C415AA /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = 541EF8B122EEFB2300C415AA /* style.css */; };
|
||||
54A75F6023D1269200754813 /* style-thumb.css in Resources */ = {isa = PBXBuildFile; fileRef = 54A75F5F23D1269100754813 /* style-thumb.css */; };
|
||||
54BFFC1123D09E7300012FBB /* opml-lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 54BFFC0F23D09E7300012FBB /* opml-lib.h */; };
|
||||
54BFFC1223D09E7300012FBB /* opml-lib.m in Sources */ = {isa = PBXBuildFile; fileRef = 54BFFC1023D09E7300012FBB /* opml-lib.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -22,7 +23,8 @@
|
||||
540A649F22EE78B200470937 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
|
||||
540A64A122EE78B200470937 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
541EF8B122EEFB2300C415AA /* style.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = style.css; sourceTree = "<group>"; };
|
||||
54BFFC0423D0988A00012FBB /* sample.opml */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample.opml; sourceTree = SOURCE_ROOT; };
|
||||
54A75F5F23D1269100754813 /* style-thumb.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "style-thumb.css"; sourceTree = "<group>"; };
|
||||
54BFFC0423D0988A00012FBB /* sample.opml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = sample.opml; sourceTree = SOURCE_ROOT; };
|
||||
54BFFC0F23D09E7300012FBB /* opml-lib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "opml-lib.h"; sourceTree = "<group>"; };
|
||||
54BFFC1023D09E7300012FBB /* opml-lib.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "opml-lib.m"; sourceTree = "<group>"; };
|
||||
54FB05D22305C8F400A088AD /* QLOPML.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLOPML.entitlements; sourceTree = "<group>"; };
|
||||
@@ -66,6 +68,7 @@
|
||||
540A649F22EE78B200470937 /* main.c */,
|
||||
540A64A122EE78B200470937 /* Info.plist */,
|
||||
541EF8B122EEFB2300C415AA /* style.css */,
|
||||
54A75F5F23D1269100754813 /* style-thumb.css */,
|
||||
54BFFC0423D0988A00012FBB /* sample.opml */,
|
||||
);
|
||||
path = QLOPML;
|
||||
@@ -147,6 +150,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54A75F6023D1269200754813 /* style-thumb.css in Resources */,
|
||||
541EF8B322EEFBEA00C415AA /* style.css in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -14,9 +14,8 @@ void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview);
|
||||
|
||||
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
|
||||
{
|
||||
// qlmanage -r && qlmanage -p test.opml -o tmp/ && edit tmp/test.opml.qlpreview/Preview.html
|
||||
CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview);
|
||||
CFDataRef data = renderOPML(url, bundle);
|
||||
CFDataRef data = generateHTML(url, bundle, false);
|
||||
if (data) {
|
||||
QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeHTML, NULL);
|
||||
CFRelease(data);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <QuickLook/QuickLook.h>
|
||||
#include "opml-lib.h"
|
||||
|
||||
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize);
|
||||
void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail);
|
||||
@@ -13,10 +14,27 @@ void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbn
|
||||
|
||||
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize)
|
||||
{
|
||||
// TODO: generate icon with feed count?
|
||||
// CGImageRef image = CGImageCreate...
|
||||
// QLThumbnailRequestSetImage(thumbnail, image, NULL);
|
||||
// test with:
|
||||
// rm -rf ~/Library/QuickLook/QLOPML.qlgenerator && qlmanage -r && rsync -a ~/Library/Developer/Xcode/DerivedData/QLOPML-*/Build/Products/Debug/QLOPML.qlgenerator ~/Library/QuickLook/ && qlmanage -t sample.opml -s 512 -i
|
||||
CFBundleRef bundle = QLThumbnailRequestGetGeneratorBundle(thumbnail);
|
||||
CFDataRef data = generateHTML(url, bundle, true);
|
||||
if (data) {
|
||||
QLThumbnailRequestSetThumbnailWithDataRepresentation(thumbnail, data, kUTTypeHTML, NULL, NULL);
|
||||
CFRelease(data);
|
||||
}
|
||||
return noErr;
|
||||
|
||||
// CGSize thumbSize = CGSizeMake(maxSize.width * (600/800.0), maxSize.height);
|
||||
// // Draw the webview in the correct context
|
||||
// CGContextRef context = QLThumbnailRequestCreateContext(thumbnail, thumbSize, false, NULL);
|
||||
//
|
||||
// if (context) {
|
||||
// CFBundleRef bundle = QLThumbnailRequestGetGeneratorBundle(thumbnail);
|
||||
// renderThumbnail(url, bundle, context, maxSize);
|
||||
// QLThumbnailRequestFlushContext(thumbnail, context);
|
||||
// CFRelease(context);
|
||||
// }
|
||||
// return noErr;
|
||||
}
|
||||
|
||||
void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2</string>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CFPlugInDynamicRegisterFunction</key>
|
||||
@@ -49,7 +49,7 @@
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2019 relikd. Public Domain.</string>
|
||||
<key>QLNeedsToBeRunInMainThread</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>QLPreviewHeight</key>
|
||||
<real>600</real>
|
||||
<key>QLPreviewWidth</key>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef opml_lib_h
|
||||
#define opml_lib_h
|
||||
|
||||
CFDataRef renderOPML(CFURLRef url, CFBundleRef bundle);
|
||||
CFDataRef generateHTML(CFURLRef url, CFBundleRef bundle, Boolean thumb);
|
||||
//void renderThumbnail(CFURLRef url, CFBundleRef bundle, CGContextRef context, CGSize maxSize);
|
||||
|
||||
#endif /* opml_lib_h */
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
//#import <CoreFoundation/CoreFoundation.h>
|
||||
//#import <CoreServices/CoreServices.h>
|
||||
//#import <QuickLook/QuickLook.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
//#import <WebKit/WebKit.h>
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// |
|
||||
@@ -28,9 +26,11 @@ NSXMLElement* section(NSString *title, NSString *container, NSXMLElement *parent
|
||||
return div;
|
||||
}
|
||||
|
||||
void appendNode(NSXMLElement *child, NSXMLElement *parent) {
|
||||
void appendNode(NSXMLElement *child, NSXMLElement *parent, Boolean thumb) {
|
||||
|
||||
if ([child.name isEqualToString:@"head"]) {
|
||||
if (thumb)
|
||||
return;
|
||||
NSXMLElement *dl = section(@"Metadata:", @"dl", parent);
|
||||
for (NSXMLElement *head in child.children) {
|
||||
make(@"dt", head.name, dl);
|
||||
@@ -40,35 +40,37 @@ void appendNode(NSXMLElement *child, NSXMLElement *parent) {
|
||||
}
|
||||
|
||||
if ([child.name isEqualToString:@"body"]) {
|
||||
parent = section(@"Content:", @"ul", parent);
|
||||
parent = thumb ? make(@"ul", nil, parent) : section(@"Content:", @"ul", parent);
|
||||
|
||||
} else if ([child.name isEqualToString:@"outline"]) {
|
||||
if ([child attributeForName:@"separator"].stringValue) {
|
||||
make(@"hr", nil, parent);
|
||||
} else {
|
||||
NSString *desc = [child attributeForName:@"title"].stringValue;
|
||||
NSString *xmlUrl = [child attributeForName:@"xmlUrl"].stringValue;
|
||||
if (!desc || desc.length == 0)
|
||||
desc = [child attributeForName:@"text"].stringValue;
|
||||
// refreshInterval
|
||||
NSXMLElement *li = make(@"li", desc, parent);
|
||||
if (!thumb) {
|
||||
NSString *xmlUrl = [child attributeForName:@"xmlUrl"].stringValue;
|
||||
if (xmlUrl && xmlUrl.length > 0) {
|
||||
[li addChild:[NSXMLNode textWithStringValue:@" — "]];
|
||||
attribute(make(@"a", xmlUrl, li), @"href", xmlUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (child.childCount > 0) {
|
||||
parent = make(@"ul", nil, parent);
|
||||
}
|
||||
}
|
||||
for (NSXMLElement *c in child.children) {
|
||||
appendNode(c, parent);
|
||||
appendNode(c, parent, thumb);
|
||||
}
|
||||
}
|
||||
|
||||
CFDataRef renderOPML(CFURLRef url, CFBundleRef bundle) {
|
||||
NSData* generateHTMLData(NSURL *url, CFBundleRef bundle, Boolean thumb) {
|
||||
NSError *err;
|
||||
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL:(__bridge NSURL*)url options:0 error:&err];
|
||||
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err];
|
||||
if (err || !doc) {
|
||||
printf("ERROR: %s\n", err.description.UTF8String);
|
||||
return nil;
|
||||
@@ -78,15 +80,40 @@ CFDataRef renderOPML(CFURLRef url, CFBundleRef bundle) {
|
||||
NSXMLElement *head = make(@"head", nil, html);
|
||||
make(@"title", @"OPML file", head);
|
||||
|
||||
CFURLRef path = CFBundleCopyResourceURL(bundle, CFSTR("style"), CFSTR("css"), NULL);
|
||||
CFURLRef path = CFBundleCopyResourceURL(bundle, thumb ? CFSTR("style-thumb") : CFSTR("style"), CFSTR("css"), NULL);
|
||||
NSString *data = [NSString stringWithContentsOfFile:CFBridgingRelease(path) encoding:NSUTF8StringEncoding error:nil];
|
||||
make(@"style", data, head);
|
||||
|
||||
NSXMLElement *body = make(@"body", nil, html);
|
||||
|
||||
for (NSXMLElement *child in doc.children) {
|
||||
appendNode(child, body);
|
||||
appendNode(child, body, thumb);
|
||||
}
|
||||
NSXMLDocument *xml = [NSXMLDocument documentWithRootElement:html];
|
||||
return CFBridgingRetain([xml XMLDataWithOptions:NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement]);
|
||||
return [xml XMLDataWithOptions:NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement];
|
||||
}
|
||||
|
||||
CFDataRef generateHTML(CFURLRef url, CFBundleRef bundle, Boolean thumb) {
|
||||
return CFBridgingRetain(generateHTMLData((__bridge NSURL*)url, bundle, thumb));
|
||||
}
|
||||
|
||||
/*void renderThumbnail(CFURLRef url, CFBundleRef bundle, CGContextRef context, CGSize maxSize) {
|
||||
NSData *data = generateHTMLData((__bridge NSURL*)url, bundle, true);
|
||||
if (data) {
|
||||
CGRect rect = CGRectMake(0, 0, 600, 800);
|
||||
float scale = maxSize.height / rect.size.height;
|
||||
|
||||
WebView *webView = [[WebView alloc] initWithFrame:rect];
|
||||
[webView.mainFrame.frameView scaleUnitSquareToSize:CGSizeMake(scale, scale)];
|
||||
[webView.mainFrame.frameView setAllowsScrolling:NO];
|
||||
[webView.mainFrame loadData:data MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:nil];
|
||||
|
||||
while ([webView isLoading])
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
|
||||
[webView display];
|
||||
|
||||
NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)context
|
||||
flipped:webView.isFlipped];
|
||||
[webView displayRectIgnoringOpacity:webView.bounds inContext:gc];
|
||||
}
|
||||
}*/
|
||||
|
||||
4
QLOPML/style-thumb.css
Normal file
4
QLOPML/style-thumb.css
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
* { font-family: Courier; }
|
||||
body { padding: 10px; margin-left: -1.5em; }
|
||||
ul { padding: 0 0 1em 1.5em; list-style-type: none; }
|
||||
Reference in New Issue
Block a user