Blender V5.0
thumbnail_provider.mm
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#import <AppKit/NSImage.h>
6
7#include "BLI_fileops.h"
8#include "BLI_filereader.h"
10#include "blendthumb.hh"
11
12#include "thumbnail_provider.h"
70
72 private:
73 int src_fd = -1;
74
75 public:
76 explicit FileDescriptorRAII(const char *file_path)
77 {
78 src_fd = BLI_open(file_path, O_BINARY | O_RDONLY, 0);
79 }
80
82 {
83 if (good()) {
84 int ok = close(src_fd);
85 if (!ok) {
86 NSLog(@"Blender Thumbnailer Error: Failed to close the blend file.");
87 }
88 }
89 }
90
91 bool good()
92 {
93 return src_fd > 0;
94 }
95
96 int get()
97 {
98 return src_fd;
99 }
100};
101
102static NSError *create_nserror_from_string(NSString *errorStr)
103{
104 NSLog(@"Blender Thumbnailer Error: %@", errorStr);
105 return [NSError errorWithDomain:@"org.blenderfoundation.blender.thumbnailer"
106 code:-1
107 userInfo:@{NSLocalizedDescriptionKey : errorStr}];
108}
109
110static NSImage *generate_nsimage_for_file(const char *src_blend_path, NSError *error)
111{
112 /* Open source file `src_blend`. */
113 FileDescriptorRAII src_file_fd = FileDescriptorRAII(src_blend_path);
114 if (!src_file_fd.good()) {
115 error = create_nserror_from_string(@"Failed to open blend");
116 return nil;
117 }
118
119 FileReader *file_content = BLI_filereader_new_file(src_file_fd.get());
120 if (file_content == nullptr) {
121 error = create_nserror_from_string(@"Failed to read from blend");
122 return nil;
123 }
124
125 /* Extract thumbnail from file. */
126 Thumbnail thumb;
127 eThumbStatus err = blendthumb_create_thumb_from_file(file_content, &thumb);
128 if (err != BT_OK) {
129 error = create_nserror_from_string(@"Failed to create thumbnail from file");
130 return nil;
131 }
132
133 std::optional<blender::Vector<uint8_t>> png_buf_opt = blendthumb_create_png_data_from_thumb(
134 &thumb);
135 if (!png_buf_opt) {
136 error = create_nserror_from_string(@"Failed to create png data from thumbnail");
137 return nil;
138 }
139
140 NSData *ns_data = [NSData dataWithBytes:png_buf_opt->data() length:png_buf_opt->size()];
141 NSImage *ns_image = [[NSImage alloc] initWithData:ns_data];
142 return ns_image;
143}
144
145@implementation ThumbnailProvider
146
147- (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest *)request
148 completionHandler:(void (^)(QLThumbnailReply *_Nullable reply,
149 NSError *_Nullable error))handler
150{
151
152 NSLog(@"Generating thumbnail for %@", request.fileURL.path);
153 @autoreleasepool {
154 NSError *error = nil;
155 NSImage *image = generate_nsimage_for_file(request.fileURL.path.fileSystemRepresentation,
156 error);
157 if (image == nil || image.size.width <= 0 || image.size.height <= 0) {
158 handler(nil, error);
159 return;
160 }
161
162 const CGFloat width_ratio = request.maximumSize.width / image.size.width;
163 const CGFloat height_ratio = request.maximumSize.height / image.size.height;
164 const CGFloat scale_factor = MIN(width_ratio, height_ratio);
165
166 const NSSize context_size = NSMakeSize(image.size.width * scale_factor,
167 image.size.height * scale_factor);
168
169 const NSRect context_rect = NSMakeRect(0, 0, context_size.width, context_size.height);
170
171 QLThumbnailReply *thumbnailReply = [QLThumbnailReply replyWithContextSize:context_size
172 currentContextDrawingBlock:^BOOL {
173 [image drawInRect:context_rect];
174 /* Release the image that was strongly
175 * captured by this block. */
176 [image release];
177 return YES;
178 }];
179
180 /* Return the thumbnail reply. */
181 handler(thumbnailReply, nil);
182 }
183 NSLog(@"Thumbnail generation successfully completed");
184}
185
186@end
File and directory operations.
#define O_BINARY
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Wrapper for reading from various sources (e.g. raw files, compressed files, memory....
FileReader * BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT
eThumbStatus blendthumb_create_thumb_from_file(FileReader *rawfile, Thumbnail *thumb)
eThumbStatus
Definition blendthumb.hh:28
@ BT_OK
Definition blendthumb.hh:29
std::optional< blender::Vector< uint8_t > > blendthumb_create_png_data_from_thumb(const Thumbnail *thumb)
#define MIN(_a, _b)
FileDescriptorRAII(const char *file_path)
float length(VecOp< float, D >) RET
static void error(const char *str)
static NSError * create_nserror_from_string(NSString *errorStr)
static NSImage * generate_nsimage_for_file(const char *src_blend_path, NSError *error)