macOS/QuickLook: support rich thumbnail #107072
|
@ -57,12 +57,12 @@ if(UNIX AND NOT APPLE)
|
|||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(SRC
|
||||
set(SRC_APPEX
|
||||
src/ThumbnailProvider.mm
|
||||
src/ThumbnailProvider.h
|
||||
)
|
||||
|
||||
add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC})
|
||||
add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC} ${SRC_APPEX})
|
||||
setup_platform_linker_flags(blender-thumbnailer)
|
||||
target_link_libraries(blender-thumbnailer
|
||||
bf_blenlib
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
|
||||
#include "ThumbnailProvider.h"
|
||||
|
||||
#include <AppKit/NSImage.h>
|
||||
#include <CoreGraphics/CGDataProvider.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_filereader.h"
|
||||
#include "blendthumb.hh"
|
||||
|
||||
/**
|
||||
* This section intends to list the important steps for creating a thumbnail extension.
|
||||
* qlgenerator has been deprecated and removed in platforms we support. App extensions are the way
|
||||
|
@ -38,17 +47,88 @@
|
|||
*
|
||||
* # Troubleshooting
|
||||
* - Is it registered with lsregister and there isn't a conflict with another plugin taking
|
||||
* precendence?
|
||||
* - Is it codesigned and sandboxed?
|
||||
* precendence? `lsregister -dump | grep Blender.app/`
|
||||
* - Is it codesigned and sandboxed? `codesign -d --entitlements - /path/to/plugin`
|
||||
* - Sometimes blender-thumbnailer running in background can be killed.
|
||||
* - qlmanage -r && killall Finder
|
||||
* - lsregister -dump | grep Blender.app/
|
||||
*
|
||||
* # Triggering a thumbnail
|
||||
* - qlmanage -t /path/to/file.blend
|
||||
* - qlmanage -t -s 512 -o /tmp/ /path/to/file.blend
|
||||
*/
|
||||
|
||||
class FileReaderRAII {
|
||||
int src_file_ = -1;
|
||||
|
||||
public:
|
||||
explicit FileReaderRAII(int src_file) : src_file_(src_file) {}
|
||||
~FileReaderRAII()
|
||||
{
|
||||
if (src_file_ != -1) {
|
||||
close(src_file_);
|
||||
}
|
||||
}
|
||||
|
||||
bool good()
|
||||
{
|
||||
return src_file_ != -1;
|
||||
}
|
||||
|
||||
int get()
|
||||
{
|
||||
return src_file_;
|
||||
}
|
||||
};
|
||||
|
||||
static NSError *createErrorFromStr(NSString *errorStr)
|
||||
{
|
||||
NSLog(@"Blender Thumbnailer Error: %@", errorStr);
|
||||
return [NSError errorWithDomain:@"com.blenderfoundation.blender.thumbnailer"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey : errorStr}];
|
||||
}
|
||||
|
||||
static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **error)
|
||||
{
|
||||
|
||||
/* Open source file `src_blend`. */
|
||||
FileReaderRAII src_file_fd = FileReaderRAII(BLI_open(src_blend_path, O_BINARY | O_RDONLY, 0));
|
||||
if (!src_file_fd.good()) {
|
||||
*error = createErrorFromStr(@"Failed to open blend");
|
||||
return nil;
|
||||
}
|
||||
|
||||
FileReader *file_content = BLI_filereader_new_file(src_file_fd.get());
|
||||
if (file_content == nullptr) {
|
||||
*error = createErrorFromStr(@"Failed to read from blend");
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* Extract thumbnail from file. */
|
||||
Thumbnail thumb;
|
||||
eThumbStatus err = blendthumb_create_thumb_from_file(file_content, &thumb);
|
||||
if (err != BT_OK) {
|
||||
*error = createErrorFromStr(@"Failed to create thumbnail from file");
|
||||
return nil;
|
||||
}
|
||||
|
||||
std::optional<blender::Vector<uint8_t>> png_buf_opt = blendthumb_create_png_data_from_thumb(
|
||||
&thumb);
|
||||
if (!png_buf_opt) {
|
||||
*error = createErrorFromStr(@"Failed to create png data from thumbnail");
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [NSData dataWithBytes:png_buf_opt->data() length:png_buf_opt->size()];
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
|
||||
CGImageRef image = CGImageCreateWithPNGDataProvider(
|
||||
provider, nullptr, true, kCGRenderingIntentDefault);
|
||||
CGDataProviderRelease(provider);
|
||||
NSImage *uiimage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize];
|
||||
CGImageRelease(image);
|
||||
CGDataProviderRelease(provider);
|
||||
return uiimage;
|
||||
}
|
||||
|
||||
@implementation ThumbnailProvider
|
||||
|
||||
- (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest *)request
|
||||
|
@ -56,13 +136,24 @@
|
|||
NSError *_Nullable error))handler
|
||||
{
|
||||
|
||||
NSLog(@"hello world from blender");
|
||||
NSURL *foo = [[NSURL alloc] initFileURLWithFileSystemRepresentation:""
|
||||
isDirectory:NO
|
||||
relativeToURL:nil];
|
||||
QLThumbnailReply *reply = [QLThumbnailReply replyWithImageFileURL:foo];
|
||||
|
||||
handler(reply, nil);
|
||||
NSLog(@"Generating thumbnail for %@", request.fileURL.path);
|
||||
@autoreleasepool {
|
||||
NSError *error = nil;
|
||||
NSImage *image = generateNSImageForFile(request.fileURL.path.UTF8String, &error);
|
||||
if (image == nil) {
|
||||
handler(nil, error);
|
||||
return;
|
||||
}
|
||||
handler([QLThumbnailReply replyWithContextSize:request.maximumSize
|
||||
currentContextDrawingBlock:^BOOL {
|
||||
[image drawInRect:NSMakeRect(0,
|
||||
0,
|
||||
request.maximumSize.width,
|
||||
request.maximumSize.height)];
|
||||
return YES;
|
||||
}],
|
||||
nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in New Issue