diff options
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/CMakeLists.txt | 13 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf_types.h | 3 | ||||
-rw-r--r-- | source/blender/imbuf/intern/IMB_filetype.h | 13 | ||||
-rw-r--r-- | source/blender/imbuf/intern/filetype.c | 14 | ||||
-rw-r--r-- | source/blender/imbuf/intern/util.c | 13 | ||||
-rw-r--r-- | source/blender/imbuf/intern/webp.c | 129 |
6 files changed, 180 insertions, 5 deletions
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index 25961e6e1d5..e46326467cc 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -174,6 +174,19 @@ if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() +if(WITH_IMAGE_WEBP) + list(APPEND SRC + intern/webp.c + ) + list(APPEND INC_SYS + ${WEBP_INCLUDE_DIRS} + ) + list(APPEND LIB + ${WEBP_LIBRARIES} + ) + add_definitions(-DWITH_WEBP) +endif() + list(APPEND INC ../../../intern/opencolorio ) diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 98b7cc6e87f..934163846e4 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -80,6 +80,9 @@ enum eImbFileType { #ifdef WITH_DDS IMB_FTYPE_DDS = 13, #endif +#ifdef WITH_WEBP + IMB_FTYPE_WEBP = 14, +#endif }; /* Only for readability. */ diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 035c5b10c60..31f8b3a9505 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -238,3 +238,16 @@ void imb_loadtiletiff( bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags); /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Format: TIFF (#IMB_FTYPE_WEBP) + * \{ */ + +bool imb_is_a_webp(const unsigned char *buf, size_t size); +struct ImBuf *imb_loadwebp(const unsigned char *mem, + size_t size, + int flags, + char colorspace[IM_MAX_SPACE]); +bool imb_savewebp(struct ImBuf *ibuf, const char *name, int flags); + +/** \} */ diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index 60442f97885..548bc9e120c 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -197,6 +197,20 @@ const ImFileType IMB_FILE_TYPES[] = { .default_save_role = COLOR_ROLE_DEFAULT_FLOAT, }, #endif +#ifdef WITH_WEBP + { + .init = NULL, + .exit = NULL, + .is_a = imb_is_a_webp, + .load = imb_loadwebp, + .load_filepath = NULL, + .save = imb_savewebp, + .load_tile = NULL, + .flag = 0, + .filetype = IMB_FTYPE_WEBP, + .default_save_role = COLOR_ROLE_DEFAULT_BYTE, + }, +#endif {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}, }; diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 241f1a736f4..45b50c866fe 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -41,12 +41,12 @@ #define UTIL_DEBUG 0 const char *imb_ext_image[] = { - ".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba", + ".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba", #ifdef WITH_TIFF - ".tif", ".tiff", ".tx", + ".tif", ".tiff", ".tx", #endif #ifdef WITH_OPENJPEG - ".jp2", ".j2c", + ".jp2", ".j2c", #endif #ifdef WITH_HDR ".hdr", @@ -55,13 +55,16 @@ const char *imb_ext_image[] = { ".dds", #endif #ifdef WITH_CINEON - ".dpx", ".cin", + ".dpx", ".cin", #endif #ifdef WITH_OPENEXR ".exr", #endif #ifdef WITH_OPENIMAGEIO - ".psd", ".pdd", ".psb", + ".psd", ".pdd", ".psb", +#endif +#ifdef WITH_WEBP + ".webp", #endif NULL, }; diff --git a/source/blender/imbuf/intern/webp.c b/source/blender/imbuf/intern/webp.c new file mode 100644 index 00000000000..1070920e458 --- /dev/null +++ b/source/blender/imbuf/intern/webp.c @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file blender/imbuf/intern/webp.c + * \ingroup imbuf + */ + +#include <stdio.h> +#include <stdlib.h> +#include <webp/decode.h> +#include <webp/encode.h> + +#include "BLI_fileops.h" +#include "BLI_utildefines.h" + +#include "IMB_colormanagement.h" +#include "IMB_colormanagement_intern.h" +#include "IMB_filetype.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "MEM_guardedalloc.h" + +bool imb_is_a_webp(const unsigned char *buf, size_t size) +{ + if (WebPGetInfo(buf, size, NULL, NULL)) { + return true; + } + return false; +} + +ImBuf *imb_loadwebp(const unsigned char *mem, + size_t size, + int flags, + char colorspace[IM_MAX_SPACE]) +{ + if (!imb_is_a_webp(mem, size)) { + return NULL; + } + + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); + + WebPBitstreamFeatures features; + if (WebPGetFeatures(mem, size, &features) != VP8_STATUS_OK) { + fprintf(stderr, "WebP: Failed to parse features\n"); + return NULL; + } + + const int planes = features.has_alpha ? 32 : 24; + ImBuf *ibuf = IMB_allocImBuf(features.width, features.height, planes, 0); + + if (ibuf == NULL) { + fprintf(stderr, "WebP: Failed to allocate image memory\n"); + return NULL; + } + + if ((flags & IB_test) == 0) { + ibuf->ftype = IMB_FTYPE_WEBP; + imb_addrectImBuf(ibuf); + /* Flip the image during decoding to match Blender. */ + unsigned char *last_row = (unsigned char *)(ibuf->rect + (ibuf->y - 1) * ibuf->x); + if (WebPDecodeRGBAInto(mem, size, last_row, (size_t)(ibuf->x) * ibuf->y * 4, -4 * ibuf->x) == + NULL) { + fprintf(stderr, "WebP: Failed to decode image\n"); + } + } + + return ibuf; +} + +bool imb_savewebp(struct ImBuf *ibuf, const char *name, int UNUSED(flags)) +{ + const int bytesperpixel = (ibuf->planes + 7) >> 3; + unsigned char *encoded_data, *last_row; + size_t encoded_data_size; + + if (bytesperpixel == 3) { + /* We must convert the ImBuf RGBA buffer to RGB as WebP expects a RGB buffer. */ + const size_t num_pixels = ibuf->x * ibuf->y; + const uint8_t *rgba_rect = (uint8_t *)ibuf->rect; + uint8_t *rgb_rect = MEM_mallocN(sizeof(uint8_t) * num_pixels * 3, "webp rgb_rect"); + for (int i = 0; i < num_pixels; i++) { + rgb_rect[i * 3 + 0] = rgba_rect[i * 4 + 0]; + rgb_rect[i * 3 + 1] = rgba_rect[i * 4 + 1]; + rgb_rect[i * 3 + 2] = rgba_rect[i * 4 + 2]; + } + + last_row = (unsigned char *)(rgb_rect + (ibuf->y - 1) * ibuf->x * 3); + MEM_freeN(rgb_rect); + + if (ibuf->foptions.quality == 100.0f) { + encoded_data_size = WebPEncodeLosslessRGB( + last_row, ibuf->x, ibuf->y, -3 * ibuf->x, &encoded_data); + } + else { + encoded_data_size = WebPEncodeRGB( + last_row, ibuf->x, ibuf->y, -3 * ibuf->x, ibuf->foptions.quality, &encoded_data); + } + } + else if (bytesperpixel == 4) { + last_row = (unsigned char *)(ibuf->rect + (ibuf->y - 1) * ibuf->x); + + if (ibuf->foptions.quality == 100.0f) { + encoded_data_size = WebPEncodeLosslessRGBA( + last_row, ibuf->x, ibuf->y, -4 * ibuf->x, &encoded_data); + } + else { + encoded_data_size = WebPEncodeRGBA( + last_row, ibuf->x, ibuf->y, -4 * ibuf->x, ibuf->foptions.quality, &encoded_data); + } + } + else { + fprintf(stderr, "WebP: Unsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name); + return false; + } + + if (encoded_data != NULL) { + FILE *fp = BLI_fopen(name, "wb"); + if (!fp) { + free(encoded_data); + fprintf(stderr, "WebP: Cannot open file for writing: '%s'\n", name); + return false; + } + fwrite(encoded_data, encoded_data_size, 1, fp); + free(encoded_data); + fclose(fp); + } + + return true; +} |