macOS/QuickLook: support rich thumbnail #107072
|
@ -7,8 +7,5 @@
|
|||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
ankitm marked this conversation as resolved
Outdated
|
||||
<!-- Is needed for debugging the process -->
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -38,9 +38,24 @@ if(WIN32)
|
|||
|
||||
target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib)
|
||||
set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
elseif(APPLE)
|
||||
# -----------------------------------------------------------------------------
|
||||
ankitm marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
Code is more clearly mutually exclusive if you use:
Code is more clearly mutually exclusive if you use:
```
if(WIN32)
..
elseif(APPLE)
...
elseif(UNIX)
...
endif()
```
|
||||
# Build `blender-thumbnailer.appex` app extension.
|
||||
set(SRC_APPEX
|
||||
src/thumbnail_provider.mm
|
||||
src/thumbnail_provider.h
|
||||
)
|
||||
|
||||
add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC} ${SRC_APPEX})
|
||||
setup_platform_linker_flags(blender-thumbnailer)
|
||||
target_link_libraries(blender-thumbnailer
|
||||
bf_blenlib
|
||||
# Avoid linker error about undefined _main symbol.
|
||||
"-e _NSExtensionMain"
|
||||
"-framework QuickLookThumbnailing"
|
||||
)
|
||||
elseif(UNIX)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build `blender-thumbnailer` executable
|
||||
|
||||
|
@ -55,22 +70,3 @@ if(UNIX AND NOT APPLE)
|
|||
target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(SRC_APPEX
|
||||
src/ThumbnailProvider.mm
|
||||
src/ThumbnailProvider.h
|
||||
)
|
||||
|
||||
add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC} ${SRC_APPEX})
|
||||
setup_platform_linker_flags(blender-thumbnailer)
|
||||
target_link_libraries(blender-thumbnailer
|
||||
bf_blenlib
|
||||
# Avoid linker error about undefined _main symbol.
|
||||
"-e _NSExtensionMain"
|
||||
"-framework QuickLookThumbnailing"
|
||||
)
|
||||
if(DEFINED PTHREADS_LIBRARIES)
|
||||
target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
@ -10,4 +11,4 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
#include "ThumbnailProvider.h"
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <AppKit/NSImage.h>
|
||||
#include <CoreGraphics/CGDataProvider.h>
|
||||
|
@ -8,8 +7,10 @@
|
|||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_filereader.h"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "blendthumb.hh"
|
||||
|
||||
#include "thumbnail_provider.h"
|
||||
/**
|
||||
* 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
|
||||
|
@ -36,18 +37,18 @@
|
|||
* /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister
|
||||
*
|
||||
* # Debugging
|
||||
* Since read-only entitlement is there, creating files to log is not possible. So NSLOG and
|
||||
* Since read-only entitlement is there, creating files to log is not possible. So NSLog and
|
||||
* viewing it in Console.app (after triggering a thumbnail) is the way to go. Interesting processes
|
||||
* are: qlmanage, quicklookd, kernel, blender-thumbnailer, secinitd,
|
||||
* com.apple.quicklook.ThumbnailsAgent
|
||||
*
|
||||
* LLDB/ Xcode etc., debuggers can be used to get extra logs than CLI invocation but breakpoints
|
||||
* still are a painpoint. /usr/bin/qlmanage is the target executable. Other args to qlmanage
|
||||
* still are a pain point. /usr/bin/qlmanage is the target executable. Other args to qlmanage
|
||||
* follow.
|
||||
*
|
||||
* # Troubleshooting
|
||||
* - Is it registered with lsregister and there isn't a conflict with another plugin taking
|
||||
* precendence? `lsregister -dump | grep Blender.app/`
|
||||
* precedence? `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
|
||||
|
@ -57,14 +58,18 @@
|
|||
* - qlmanage -t -s 512 -o /tmp/ /path/to/file.blend
|
||||
*/
|
||||
|
||||
class FileReaderRAII {
|
||||
class FileDescriptorRAII : blender::NonCopyable, blender::NonMovable {
|
||||
int src_file_ = -1;
|
||||
|
||||
public:
|
||||
explicit FileReaderRAII(int src_file) : src_file_(src_file) {}
|
||||
~FileReaderRAII()
|
||||
explicit FileDescriptorRAII(const char *file_path)
|
||||
{
|
||||
if (src_file_ != -1) {
|
||||
src_file_ = BLI_open(file_path, O_BINARY | O_RDONLY, 0);
|
||||
}
|
||||
|
||||
~FileDescriptorRAII()
|
||||
{
|
||||
if (good()) {
|
||||
close(src_file_);
|
||||
}
|
||||
}
|
||||
|
@ -80,27 +85,26 @@ class FileReaderRAII {
|
|||
}
|
||||
};
|
||||
|
||||
static NSError *createErrorFromStr(NSString *errorStr)
|
||||
static NSError *create_nserror_from_string(NSString *errorStr)
|
||||
{
|
||||
NSLog(@"Blender Thumbnailer Error: %@", errorStr);
|
||||
return [NSError errorWithDomain:@"com.blenderfoundation.blender.thumbnailer"
|
||||
return [NSError errorWithDomain:@"org.blenderfoundation.blender.thumbnailer"
|
||||
code:-1
|
||||
userInfo:@{NSLocalizedDescriptionKey : errorStr}];
|
||||
}
|
||||
|
||||
static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **error)
|
||||
static NSImage *generate_nsimage_for_file(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));
|
||||
FileDescriptorRAII src_file_fd = FileDescriptorRAII(src_blend_path);
|
||||
if (!src_file_fd.good()) {
|
||||
*error = createErrorFromStr(@"Failed to open blend");
|
||||
*error = create_nserror_from_string(@"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");
|
||||
*error = create_nserror_from_string(@"Failed to read from blend");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -108,25 +112,27 @@ static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **err
|
|||
Thumbnail thumb;
|
||||
eThumbStatus err = blendthumb_create_thumb_from_file(file_content, &thumb);
|
||||
if (err != BT_OK) {
|
||||
*error = createErrorFromStr(@"Failed to create thumbnail from file");
|
||||
*error = create_nserror_from_string(@"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");
|
||||
*error = create_nserror_from_string(@"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);
|
||||
NSData *ns_data = [NSData dataWithBytesNoCopy:png_buf_opt->data() length:png_buf_opt->size()];
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)ns_data);
|
||||
CGColorRenderingIntent intent = kCGRenderingIntentDefault;
|
||||
bool shouldInterpolate = true;
|
||||
CGFloat *decode = nullptr;
|
||||
CGImageRef image_ref = CGImageCreateWithPNGDataProvider(
|
||||
provider, decode, shouldInterpolate, intent);
|
||||
NSImage *ns_image = [[NSImage alloc] initWithCGImage:image_ref size:NSZeroSize];
|
||||
CGImageRelease(image_ref);
|
||||
CGDataProviderRelease(provider);
|
||||
NSImage *uiimage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize];
|
||||
CGImageRelease(image);
|
||||
CGDataProviderRelease(provider);
|
||||
return uiimage;
|
||||
return ns_image;
|
||||
}
|
||||
|
||||
@implementation ThumbnailProvider
|
||||
|
@ -139,21 +145,21 @@ static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **err
|
|||
NSLog(@"Generating thumbnail for %@", request.fileURL.path);
|
||||
@autoreleasepool {
|
||||
NSError *error = nil;
|
||||
NSImage *image = generateNSImageForFile(request.fileURL.path.UTF8String, &error);
|
||||
if (image == nil) {
|
||||
NSImage *ns_image = generate_nsimage_for_file(request.fileURL.path.UTF8String, &error);
|
||||
if (ns_image == nil) {
|
||||
handler(nil, error);
|
||||
return;
|
||||
}
|
||||
handler([QLThumbnailReply replyWithContextSize:request.maximumSize
|
||||
currentContextDrawingBlock:^BOOL {
|
||||
[image drawInRect:NSMakeRect(0,
|
||||
0,
|
||||
request.maximumSize.width,
|
||||
request.maximumSize.height)];
|
||||
[ns_image drawInRect:NSMakeRect(0,
|
||||
0,
|
||||
request.maximumSize.width,
|
||||
request.maximumSize.height)];
|
||||
return YES;
|
||||
}],
|
||||
nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
Loading…
Reference in New Issue
Inconsistent indentation.