Blender V4.5
format_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
8
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
24#include "IMB_allocimbuf.hh"
26#include "IMB_filetype.hh"
27#include "IMB_imbuf.hh"
28#include "IMB_imbuf_types.hh"
29
30#include "MEM_guardedalloc.h"
31
32bool imb_is_a_webp(const uchar *mem, size_t size)
33{
34 if (WebPGetInfo(mem, size, nullptr, nullptr)) {
35 return true;
36 }
37 return false;
38}
39
40ImBuf *imb_loadwebp(const uchar *mem, size_t size, int flags, ImFileColorSpace & /*r_colorspace*/)
41{
42 if (!imb_is_a_webp(mem, size)) {
43 return nullptr;
44 }
45
46 WebPBitstreamFeatures features;
47 if (WebPGetFeatures(mem, size, &features) != VP8_STATUS_OK) {
48 fprintf(stderr, "WebP: Failed to parse features\n");
49 return nullptr;
50 }
51
52 const int planes = features.has_alpha ? 32 : 24;
53 ImBuf *ibuf = IMB_allocImBuf(features.width, features.height, planes, 0);
54
55 if (ibuf == nullptr) {
56 fprintf(stderr, "WebP: Failed to allocate image memory\n");
57 return nullptr;
58 }
59
60 if ((flags & IB_test) == 0) {
61 ibuf->ftype = IMB_FTYPE_WEBP;
63 /* Flip the image during decoding to match Blender. */
64 uchar *last_row = ibuf->byte_buffer.data + (4 * size_t(ibuf->y - 1) * size_t(ibuf->x));
65 if (WebPDecodeRGBAInto(mem, size, last_row, size_t(ibuf->x) * ibuf->y * 4, -4 * ibuf->x) ==
66 nullptr)
67 {
68 fprintf(stderr, "WebP: Failed to decode image\n");
69 }
70 }
71
72 return ibuf;
73}
74
76 const int /*flags*/,
77 const size_t max_thumb_size,
78 ImFileColorSpace & /*r_colorspace*/,
79 size_t *r_width,
80 size_t *r_height)
81{
82 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
83 if (file == -1) {
84 return nullptr;
85 }
86
88 BLI_mmap_file *mmap_file = BLI_mmap_open(file);
90 close(file);
91 if (mmap_file == nullptr) {
92 return nullptr;
93 }
94
95 const uchar *data = static_cast<const uchar *>(BLI_mmap_get_pointer(mmap_file));
96 const size_t data_size = BLI_mmap_get_length(mmap_file);
97
98 WebPDecoderConfig config;
99 if (!data || !WebPInitDecoderConfig(&config) ||
100 WebPGetFeatures(data, data_size, &config.input) != VP8_STATUS_OK)
101 {
102 fprintf(stderr, "WebP: Invalid file\n");
104 BLI_mmap_free(mmap_file);
106 return nullptr;
107 }
108
109 /* Return full size of the image. */
110 *r_width = size_t(config.input.width);
111 *r_height = size_t(config.input.height);
112
113 const float scale = float(max_thumb_size) / std::max(config.input.width, config.input.height);
114 const int dest_w = std::max(int(config.input.width * scale), 1);
115 const int dest_h = std::max(int(config.input.height * scale), 1);
116
117 ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_byte_data);
118 if (ibuf == nullptr) {
119 fprintf(stderr, "WebP: Failed to allocate image memory\n");
121 BLI_mmap_free(mmap_file);
123 return nullptr;
124 }
125
126 config.options.no_fancy_upsampling = 1;
127 config.options.use_scaling = 1;
128 config.options.scaled_width = dest_w;
129 config.options.scaled_height = dest_h;
130 config.options.bypass_filtering = 1;
131 config.options.use_threads = 0;
132 config.options.flip = 1;
133 config.output.is_external_memory = 1;
134 config.output.colorspace = MODE_RGBA;
135 config.output.u.RGBA.rgba = ibuf->byte_buffer.data;
136 config.output.u.RGBA.stride = 4 * ibuf->x;
137 config.output.u.RGBA.size = size_t(config.output.u.RGBA.stride) * size_t(ibuf->y);
138
139 if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) {
140 fprintf(stderr, "WebP: Failed to decode image\n");
141 IMB_freeImBuf(ibuf);
142
144 BLI_mmap_free(mmap_file);
146 return nullptr;
147 }
148
149 /* Free the output buffer. */
150 WebPFreeDecBuffer(&config.output);
151
153 BLI_mmap_free(mmap_file);
155
156 return ibuf;
157}
158
159bool imb_savewebp(ImBuf *ibuf, const char *filepath, int /*flags*/)
160{
161 const uint limit = 16383;
162 if (ibuf->x > limit || ibuf->y > limit) {
163 fprintf(stderr, "WebP: image x/y exceeds %u\n", limit);
164 return false;
165 }
166
167 const int bytesperpixel = (ibuf->planes + 7) >> 3;
168 uchar *encoded_data, *last_row;
169 size_t encoded_data_size;
170
171 if (bytesperpixel == 3) {
172 /* We must convert the ImBuf RGBA buffer to RGB as WebP expects a RGB buffer. */
173 const size_t num_pixels = IMB_get_pixel_count(ibuf);
174 const uint8_t *rgba_rect = ibuf->byte_buffer.data;
175 uint8_t *rgb_rect = MEM_malloc_arrayN<uint8_t>(num_pixels * 3, "webp rgb_rect");
176 for (size_t i = 0; i < num_pixels; i++) {
177 rgb_rect[i * 3 + 0] = rgba_rect[i * 4 + 0];
178 rgb_rect[i * 3 + 1] = rgba_rect[i * 4 + 1];
179 rgb_rect[i * 3 + 2] = rgba_rect[i * 4 + 2];
180 }
181
182 last_row = (uchar *)(rgb_rect + (size_t(ibuf->y - 1) * size_t(ibuf->x) * 3));
183
184 if (ibuf->foptions.quality == 100.0f) {
185 encoded_data_size = WebPEncodeLosslessRGB(
186 last_row, ibuf->x, ibuf->y, -3 * ibuf->x, &encoded_data);
187 }
188 else {
189 encoded_data_size = WebPEncodeRGB(
190 last_row, ibuf->x, ibuf->y, -3 * ibuf->x, ibuf->foptions.quality, &encoded_data);
191 }
192 MEM_freeN(rgb_rect);
193 }
194 else if (bytesperpixel == 4) {
195 last_row = ibuf->byte_buffer.data + 4 * size_t(ibuf->y - 1) * size_t(ibuf->x);
196
197 if (ibuf->foptions.quality == 100.0f) {
198 encoded_data_size = WebPEncodeLosslessRGBA(
199 last_row, ibuf->x, ibuf->y, -4 * ibuf->x, &encoded_data);
200 }
201 else {
202 encoded_data_size = WebPEncodeRGBA(
203 last_row, ibuf->x, ibuf->y, -4 * ibuf->x, ibuf->foptions.quality, &encoded_data);
204 }
205 }
206 else {
207 fprintf(
208 stderr, "WebP: Unsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, filepath);
209 return false;
210 }
211
212 if (encoded_data != nullptr) {
213 FILE *fp = BLI_fopen(filepath, "wb");
214 if (!fp) {
215 free(encoded_data);
216 fprintf(stderr, "WebP: Cannot open file for writing: '%s'\n", filepath);
217 return false;
218 }
219 fwrite(encoded_data, encoded_data_size, 1, fp);
220 free(encoded_data);
221 fclose(fp);
222 }
223
224 return true;
225}
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.cc:212
void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1)
Definition BLI_mmap.cc:227
BLI_mmap_file * BLI_mmap_open(int fd) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_mmap.cc:133
size_t BLI_mmap_get_length(const BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT
Definition BLI_mmap.cc:217
unsigned char uchar
unsigned int uint
bool IMB_alloc_byte_pixels(ImBuf *ibuf, bool initialize_pixels=true)
void IMB_freeImBuf(ImBuf *ibuf)
size_t IMB_get_pixel_count(const ImBuf *ibuf)
Get the length of the data of the given image buffer in pixels.
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
@ IB_byte_data
@ IB_test
Read Guarded memory(de)allocation.
void imb_mmap_lock()
Definition allocimbuf.cc:46
void imb_mmap_unlock()
Definition allocimbuf.cc:51
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
bool imb_is_a_webp(const uchar *mem, size_t size)
ImBuf * imb_loadwebp(const uchar *mem, size_t size, int flags, ImFileColorSpace &)
ImBuf * imb_load_filepath_thumbnail_webp(const char *filepath, const int, const size_t max_thumb_size, ImFileColorSpace &, size_t *r_width, size_t *r_height)
bool imb_savewebp(ImBuf *ibuf, const char *filepath, int)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
i
Definition text_draw.cc:230