Blender V4.3
webp.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#ifdef _WIN32
10# include <io.h>
11#else
12# include <unistd.h>
13#endif
14
15#include <cstdio>
16#include <cstdlib>
17#include <fcntl.h>
18#include <webp/decode.h>
19#include <webp/encode.h>
20
21#include "BLI_fileops.h"
22#include "BLI_mmap.h"
23#include "BLI_utildefines.h"
24
25#include "IMB_allocimbuf.hh"
27#include "IMB_filetype.hh"
28#include "IMB_imbuf.hh"
29#include "IMB_imbuf_types.hh"
30
31#include "MEM_guardedalloc.h"
32
33bool imb_is_a_webp(const uchar *buf, size_t size)
34{
35 if (WebPGetInfo(buf, size, nullptr, nullptr)) {
36 return true;
37 }
38 return false;
39}
40
41ImBuf *imb_loadwebp(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
42{
43 if (!imb_is_a_webp(mem, size)) {
44 return nullptr;
45 }
46
48
49 WebPBitstreamFeatures features;
50 if (WebPGetFeatures(mem, size, &features) != VP8_STATUS_OK) {
51 fprintf(stderr, "WebP: Failed to parse features\n");
52 return nullptr;
53 }
54
55 const int planes = features.has_alpha ? 32 : 24;
56 ImBuf *ibuf = IMB_allocImBuf(features.width, features.height, planes, 0);
57
58 if (ibuf == nullptr) {
59 fprintf(stderr, "WebP: Failed to allocate image memory\n");
60 return nullptr;
61 }
62
63 if ((flags & IB_test) == 0) {
64 ibuf->ftype = IMB_FTYPE_WEBP;
65 imb_addrectImBuf(ibuf);
66 /* Flip the image during decoding to match Blender. */
67 uchar *last_row = ibuf->byte_buffer.data + 4 * (ibuf->y - 1) * ibuf->x;
68 if (WebPDecodeRGBAInto(mem, size, last_row, size_t(ibuf->x) * ibuf->y * 4, -4 * ibuf->x) ==
69 nullptr)
70 {
71 fprintf(stderr, "WebP: Failed to decode image\n");
72 }
73 }
74
75 return ibuf;
76}
77
79 const int /*flags*/,
80 const size_t max_thumb_size,
81 char colorspace[],
82 size_t *r_width,
83 size_t *r_height)
84{
85 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
86 if (file == -1) {
87 return nullptr;
88 }
89
91 BLI_mmap_file *mmap_file = BLI_mmap_open(file);
93 close(file);
94 if (mmap_file == nullptr) {
95 return nullptr;
96 }
97
98 const uchar *data = static_cast<const uchar *>(BLI_mmap_get_pointer(mmap_file));
99 const size_t data_size = BLI_mmap_get_length(mmap_file);
100
101 WebPDecoderConfig config;
102 if (!data || !WebPInitDecoderConfig(&config) ||
103 WebPGetFeatures(data, data_size, &config.input) != VP8_STATUS_OK)
104 {
105 fprintf(stderr, "WebP: Invalid file\n");
107 BLI_mmap_free(mmap_file);
109 return nullptr;
110 }
111
112 /* Return full size of the image. */
113 *r_width = size_t(config.input.width);
114 *r_height = size_t(config.input.height);
115
116 const float scale = float(max_thumb_size) / std::max(config.input.width, config.input.height);
117 const int dest_w = std::max(int(config.input.width * scale), 1);
118 const int dest_h = std::max(int(config.input.height * scale), 1);
119
121 ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rect);
122 if (ibuf == nullptr) {
123 fprintf(stderr, "WebP: Failed to allocate image memory\n");
125 BLI_mmap_free(mmap_file);
127 return nullptr;
128 }
129
130 config.options.no_fancy_upsampling = 1;
131 config.options.use_scaling = 1;
132 config.options.scaled_width = dest_w;
133 config.options.scaled_height = dest_h;
134 config.options.bypass_filtering = 1;
135 config.options.use_threads = 0;
136 config.options.flip = 1;
137 config.output.is_external_memory = 1;
138 config.output.colorspace = MODE_RGBA;
139 config.output.u.RGBA.rgba = ibuf->byte_buffer.data;
140 config.output.u.RGBA.stride = 4 * ibuf->x;
141 config.output.u.RGBA.size = size_t(config.output.u.RGBA.stride * ibuf->y);
142
143 if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) {
144 fprintf(stderr, "WebP: Failed to decode image\n");
146 BLI_mmap_free(mmap_file);
148 return nullptr;
149 }
150
151 /* Free the output buffer. */
152 WebPFreeDecBuffer(&config.output);
153
155 BLI_mmap_free(mmap_file);
157
158 return ibuf;
159}
160
161bool imb_savewebp(ImBuf *ibuf, const char *filepath, int /*flags*/)
162{
163 const int bytesperpixel = (ibuf->planes + 7) >> 3;
164 uchar *encoded_data, *last_row;
165 size_t encoded_data_size;
166
167 if (bytesperpixel == 3) {
168 /* We must convert the ImBuf RGBA buffer to RGB as WebP expects a RGB buffer. */
169 const size_t num_pixels = ibuf->x * ibuf->y;
170 const uint8_t *rgba_rect = ibuf->byte_buffer.data;
171 uint8_t *rgb_rect = static_cast<uint8_t *>(
172 MEM_mallocN(sizeof(uint8_t) * num_pixels * 3, "webp rgb_rect"));
173 for (int i = 0; i < num_pixels; i++) {
174 rgb_rect[i * 3 + 0] = rgba_rect[i * 4 + 0];
175 rgb_rect[i * 3 + 1] = rgba_rect[i * 4 + 1];
176 rgb_rect[i * 3 + 2] = rgba_rect[i * 4 + 2];
177 }
178
179 last_row = (uchar *)(rgb_rect + (ibuf->y - 1) * ibuf->x * 3);
180
181 if (ibuf->foptions.quality == 100.0f) {
182 encoded_data_size = WebPEncodeLosslessRGB(
183 last_row, ibuf->x, ibuf->y, -3 * ibuf->x, &encoded_data);
184 }
185 else {
186 encoded_data_size = WebPEncodeRGB(
187 last_row, ibuf->x, ibuf->y, -3 * ibuf->x, ibuf->foptions.quality, &encoded_data);
188 }
189 MEM_freeN(rgb_rect);
190 }
191 else if (bytesperpixel == 4) {
192 last_row = ibuf->byte_buffer.data + 4 * (ibuf->y - 1) * ibuf->x;
193
194 if (ibuf->foptions.quality == 100.0f) {
195 encoded_data_size = WebPEncodeLosslessRGBA(
196 last_row, ibuf->x, ibuf->y, -4 * ibuf->x, &encoded_data);
197 }
198 else {
199 encoded_data_size = WebPEncodeRGBA(
200 last_row, ibuf->x, ibuf->y, -4 * ibuf->x, ibuf->foptions.quality, &encoded_data);
201 }
202 }
203 else {
204 fprintf(
205 stderr, "WebP: Unsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, filepath);
206 return false;
207 }
208
209 if (encoded_data != nullptr) {
210 FILE *fp = BLI_fopen(filepath, "wb");
211 if (!fp) {
212 free(encoded_data);
213 fprintf(stderr, "WebP: Cannot open file for writing: '%s'\n", filepath);
214 return false;
215 }
216 fwrite(encoded_data, encoded_data_size, 1, fp);
217 free(encoded_data);
218 fclose(fp);
219 }
220
221 return true;
222}
File and directory operations.
#define O_BINARY
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_kdtree_nd_ free(KDTree *tree)
void * BLI_mmap_get_pointer(BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT
Definition BLI_mmap.c:211
void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1)
Definition BLI_mmap.c:221
BLI_mmap_file * BLI_mmap_open(int fd) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_mmap.c:132
size_t BLI_mmap_get_length(const BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT
Definition BLI_mmap.c:216
unsigned char uchar
@ COLOR_ROLE_DEFAULT_BYTE
#define IM_MAX_SPACE
Definition IMB_imbuf.hh:49
bool imb_addrectImBuf(ImBuf *ibuf, bool initialize_pixels=true)
Contains defines and structs used throughout the imbuf module.
@ IB_test
@ IB_rect
Read Guarded memory(de)allocation.
void imb_mmap_lock()
Definition allocimbuf.cc:56
void imb_mmap_unlock()
Definition allocimbuf.cc:61
void colorspace_set_default_role(char *colorspace, int size, int role)
draw_view in_light_buf[] float
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
unsigned char uint8_t
Definition stdint.h:78
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
bool imb_savewebp(ImBuf *ibuf, const char *filepath, int)
Definition webp.cc:161
ImBuf * imb_load_filepath_thumbnail_webp(const char *filepath, const int, const size_t max_thumb_size, char colorspace[], size_t *r_width, size_t *r_height)
Definition webp.cc:78
bool imb_is_a_webp(const uchar *buf, size_t size)
Definition webp.cc:33
ImBuf * imb_loadwebp(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
Definition webp.cc:41