diff --git a/src/imageio/imageio_webp.c b/src/imageio/imageio_webp.c index 0f245bd33eb2..7ab6655c300b 100644 --- a/src/imageio/imageio_webp.c +++ b/src/imageio/imageio_webp.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2022-2023 darktable developers. + Copyright (C) 2022-2024 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,8 +16,6 @@ along with darktable. If not, see . */ -#include - #include #include @@ -27,9 +25,7 @@ dt_imageio_retval_t dt_imageio_open_webp(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf) { - int w, h; - WebPMux *mux; - WebPData wp_data; + int width, height; WebPData icc_profile; FILE *f = g_fopen(filename, "rb"); @@ -55,7 +51,7 @@ dt_imageio_retval_t dt_imageio_open_webp(dt_image_t *img, const char *filename, fclose(f); // WebPGetInfo should tell us the image dimensions needed for darktable image buffer allocation - if(!WebPGetInfo(read_buffer, filesize, &w, &h)) + if(!WebPGetInfo(read_buffer, filesize, &width, &height)) { // If we couldn't get the webp metadata, then the file we're trying to read is most likely in // a different format (darktable just trying different loaders until it finds the right one). @@ -63,8 +59,22 @@ dt_imageio_retval_t dt_imageio_open_webp(dt_image_t *img, const char *filename, g_free(read_buffer); return DT_IMAGEIO_LOAD_FAILED; } - img->width = w; - img->height = h; + + // The maximum pixel dimensions of a WebP image is 16383 x 16383, + // so the number of pixels will never overflow int + const int npixels = width * height; + + uint8_t *int_RGBA_buf = dt_alloc_align_uint8(npixels * 4); + int_RGBA_buf = WebPDecodeRGBAInto(read_buffer, filesize, int_RGBA_buf, npixels * 4, width * 4); + if(!int_RGBA_buf) + { + g_free(read_buffer); + dt_print(DT_DEBUG_ALWAYS,"[webp_open] failed to decode file: %s\n", filename); + return DT_IMAGEIO_LOAD_FAILED; + } + + img->width = width; + img->height = height; img->buf_dsc.channels = 4; img->buf_dsc.datatype = TYPE_FLOAT; @@ -72,36 +82,30 @@ dt_imageio_retval_t dt_imageio_open_webp(dt_image_t *img, const char *filename, if(!mipbuf) { g_free(read_buffer); + dt_free_align(int_RGBA_buf); dt_print(DT_DEBUG_ALWAYS, "[webp_open] could not alloc full buffer for image: %s\n", img->filename); return DT_IMAGEIO_CACHE_FULL; } - uint8_t *int_RGBA_buf = WebPDecodeRGBA(read_buffer, filesize, &w, &h); - if(!int_RGBA_buf) - { - g_free(read_buffer); - dt_print(DT_DEBUG_ALWAYS,"[webp_open] failed to decode file: %s\n", filename); - return DT_IMAGEIO_LOAD_FAILED; - } - - uint8_t intval; - float floatval; - #ifdef _OPENMP -#pragma omp parallel for private(intval, floatval) +#pragma omp parallel for default(none) \ + schedule(static) \ + dt_omp_firstprivate(npixels, int_RGBA_buf, mipbuf) #endif - for(int i=0; i < w*h*4; i++) + for(int i = 0; i < npixels; i++) { - intval = *(int_RGBA_buf+i); - floatval = intval / 255.f; - *(mipbuf+i) = floatval; + dt_aligned_pixel_t pix = {0.0f, 0.0f, 0.0f, 0.0f}; + for_three_channels(c) + pix[c] = *(int_RGBA_buf + i * 4 + c) / 255.f; + copy_pixel_nontemporal(&mipbuf[i * 4], pix); } - WebPFree(int_RGBA_buf); + dt_free_align(int_RGBA_buf); + WebPData wp_data; wp_data.bytes = (uint8_t *)read_buffer; wp_data.size = filesize; - mux = WebPMuxCreate(&wp_data, 0); // 0 = data will NOT be copied to the mux object + WebPMux *mux = WebPMuxCreate(&wp_data, 0); // 0 = data will NOT be copied to the mux object if(mux) {