Compare commits

...

12 Commits

Author SHA1 Message Date
1d86819f49 Merge changes I1437390a,I10a20de5,I1ac777d1 into main
* changes:
  pngdec.c: add support for 'eXIf' tag
  pngdec.c: support ImageMagick app1 exif text data
  pngdec.c: add missing #ifdef for png_get_iCCP
2025-03-06 14:00:07 -08:00
743a5f092d enc_neon: enable vld1q_u8_x4 for clang & msvc
This restores the use of the function after
980b708e enc_neon: fix build w/aarch64 gcc < 9.4.0

The intrinsic was added to llvm for aarch64 in:
5e4ce1ae9dad Implement the newly added AArch64 ACLE functions for
             ld1/st1 with 2/3/4 vectors. The functions are like:
             vst1_s8_x2 ...
llvmorg-3.4.0-rc1~101
https://github.com/llvm/llvm-project/commit/5e4ce1ae9dad

Visual Studio 2019 and 2022 also support the function (2017 is still
disabled for this path due to it relying on arm64_neon.h).

Change-Id: I6ff10e22deb3968a48738a4458d2d3d55410b5ec
2025-03-05 16:56:20 -08:00
565da14882 pngdec.c: add support for 'eXIf' tag
Test file created with exiftool 12.76:

```
exiftool test_app1_exif.png -exif:all \
  -exif:DocumentName=test_multi_exif.png -o test_multi_exif.png
```

Bug: webp:398066379
Change-Id: I1437390a70f5708421683eb69c588624bb376baa
2025-03-05 13:54:09 -08:00
319860e919 pngdec.c: support ImageMagick app1 exif text data
Test file created with ImageMagick 6.9.13-12:

```
convert test_exif.png test_app1_exif.png
```

Bug: webp:398066379
Change-Id: I10a20de5699fabb0906045994d7d1f4b9e951973
2025-03-05 13:54:07 -08:00
815fc1e110 pngdec.c: add missing #ifdef for png_get_iCCP
png_get_iCCP is an optional part of the API. Protect its usage with
PNG_iCCP_SUPPORTED.

Change-Id: I1ac777d1c2a200bb3e1303b3d095cc0d67633bd4
2025-03-05 13:54:04 -08:00
980b708e2c enc_neon: fix build w/aarch64 gcc < 9.4.0
vld1q_u8_x4 was added for aarch64 in the gcc 9.4.0 release:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/ChangeLog;h=7558c0a369ea8c74a2b9369049a2d1cc187dc050;hb=13c83c4cc679ad5383ed57f359e53e8d518b7842#l2100

fixes:
src/dsp/enc_neon.c: In function 'Intra4Preds_NEON':
src/dsp/enc_neon.c:974:37: warning: implicit declaration of function
  'vld1q_u8_x4'; did you mean 'vld1q_u8_x2'?
  [-Wimplicit-function-declaration]

Bug: webp:398288323
Change-Id: Ic6e408065a375c945cc8691bd16a9f5d5642cfa2
2025-02-27 19:07:50 -08:00
73b728cbb9 cmake: bump minimum version to 3.16
This matches the current support matrix (from 2024-12-17) [1] and quiets
a warning from recent (3.31.5) versions of cmake:

CMake Deprecation Warning at CMakeLists.txt:12 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version
  of CMake.

Explicit setting of CMP0072 is also removed; it was added in 3.11.

[1]: https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md

Bug: webp:397130631
Change-Id: Ic844dadf983a82674990edbddbfc54329df12eb7
Fixed: webp:397130631
2025-02-20 12:32:08 -08:00
6a22b6709c Add a function to validate a WebPDecoderConfig
This echoes WebPValidateConfig for encoding.

Change-Id: Ib404d55c7af4d0755644879ec491e3998e6b5e8d
2025-01-30 10:10:08 +01:00
7ed2b10ef0 Use consistently signed stride types.
The stride can be negative when asked for a flipped image.

Change-Id: I049e8027c769186274a6a3049949f3fcaae7d2e9
2025-01-30 00:12:28 +01:00
654bfb040c Avoid nullptr arithmetic in VP8BitReaderSetBuffer
When start is nullptr, the IO is not used afterwards
anyway, so there is not risk.

Change-Id: I0a828aec85c6e228e95dfed4a40d348275a7c577
2025-01-30 00:12:15 +01:00
f8f2410710 Fix potential "divide by zero" in examples found by coverity
Change-Id: Ic41f9cb2ac24450986cd061db718953276eee080
2025-01-16 18:02:41 +01:00
2af6c034ac Merge tag 'v1.5.0'
libwebp-1.5.0

- 12/19/2024 version 1.5.0
  This is a binary compatible release.
  API changes:
    - `cross_color_transform_bits` added to WebPAuxStats
  * minor lossless encoder speed and compression improvements
  * lossless encoding does not use floats anymore
  * additional Arm optimizations for lossy & lossless + general code generation
    improvements
  * improvements to WASM performance (#643)
  * improvements and corrections in webp-container-spec.txt and
    webp-lossless-bitstream-spec.txt (#646, #355607636)
  * further security related hardening and increased fuzzing coverage w/fuzztest
    (oss-fuzz: #382816119, #70112, #70102, #69873, #69825, #69508, #69208)
  * miscellaneous warning, bug & build fixes (#499, #562, #381372617,
    #381109771, #42340561, #375011696, #372109644, chromium: #334120888)
  Tool updates:
    * gif2webp: add -sharp_yuv & -near_lossless
    * img2webp: add -exact & -noexact
    * exit codes normalized; running an example program with no
      arguments will output its help and exit with an error (#42340557,
      #381372617)

Bug: b:336795049,webp:380121350

* tag 'v1.5.0':
  update ChangeLog
  update NEWS
  tests/fuzzer/*: add missing <string_view> include
  fuzz_utils.cc: fix build error w/WEBP_REDUCE_SIZE
  mux_demux_api_fuzzer.cc: fix -Wshadow warning
  update ChangeLog
  update NEWS
  bump version to 1.5.0
  update AUTHORS

Change-Id: I076b197fac29230bc61bc5f06e950d83d058a737
2024-12-19 18:19:10 -08:00
11 changed files with 141 additions and 42 deletions

View File

@ -9,11 +9,7 @@
if(APPLE) if(APPLE)
cmake_minimum_required(VERSION 3.17) cmake_minimum_required(VERSION 3.17)
else() else()
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.16)
endif()
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
endif() endif()
project(WebP C) project(WebP C)

View File

@ -771,6 +771,7 @@ void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
*psnr = 99.; // PSNR when images are identical. *psnr = 99.; // PSNR when images are identical.
} else { } else {
sse /= stride * height; sse /= stride * height;
assert(sse != 0.0);
*psnr = 4.3429448 * log(255. * 255. / sse); *psnr = 4.3429448 * log(255. * 255. / sse);
} }
} }

View File

@ -139,6 +139,8 @@ static const struct {
{ "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) }, { "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) },
// Exiftool puts exif data in APP1 chunk, too. // Exiftool puts exif data in APP1 chunk, too.
{ "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) }, { "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) },
// ImageMagick uses lowercase app1.
{ "Raw profile type app1", ProcessRawProfile, METADATA_OFFSET(exif) },
// XMP Specification Part 3, Section 3 #PNG // XMP Specification Part 3, Section 3 #PNG
{ "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) }, { "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) },
{ NULL, NULL, 0 }, { NULL, NULL, 0 },
@ -159,6 +161,20 @@ static int ExtractMetadataFromPNG(png_structp png,
png_textp text = NULL; png_textp text = NULL;
const png_uint_32 num = png_get_text(png, info, &text, NULL); const png_uint_32 num = png_get_text(png, info, &text, NULL);
png_uint_32 i; png_uint_32 i;
#ifdef PNG_eXIf_SUPPORTED
// Look for an 'eXIf' tag. Preference is given to this tag as it's newer
// than the TextualData tags.
{
png_bytep exif;
png_uint_32 len;
if (png_get_eXIf_1(png, info, &len, &exif) == PNG_INFO_eXIf) {
if (!MetadataCopy((const char*)exif, len, &metadata->exif)) return 0;
}
}
#endif // PNG_eXIf_SUPPORTED
// Look for EXIF / XMP metadata. // Look for EXIF / XMP metadata.
for (i = 0; i < num; ++i, ++text) { for (i = 0; i < num; ++i, ++text) {
int j; int j;
@ -192,6 +208,7 @@ static int ExtractMetadataFromPNG(png_structp png,
} }
} }
} }
#ifdef PNG_iCCP_SUPPORTED
// Look for an ICC profile. // Look for an ICC profile.
{ {
png_charp name; png_charp name;
@ -208,6 +225,7 @@ static int ExtractMetadataFromPNG(png_structp png,
if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0; if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0;
} }
} }
#endif // PNG_iCCP_SUPPORTED
} }
return 1; return 1;
} }

View File

@ -26,10 +26,9 @@ static const uint8_t kModeBpp[MODE_LAST] = {
4, 4, 4, 2, // pre-multiplied modes 4, 4, 4, 2, // pre-multiplied modes
1, 1 }; 1, 1 };
// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
// Convert to an integer to handle both the unsigned/signed enum cases // Convert to an integer to handle both the unsigned/signed enum cases
// without the need for casting to remove type limit warnings. // without the need for casting to remove type limit warnings.
static int IsValidColorspace(int webp_csp_mode) { int IsValidColorspace(int webp_csp_mode) {
return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
} }

View File

@ -51,4 +51,7 @@ enum { MB_FEATURE_TREE_PROBS = 3,
NUM_PROBAS = 11 NUM_PROBAS = 11
}; };
// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
int IsValidColorspace(int webp_csp_mode);
#endif // WEBP_DEC_COMMON_DEC_H_ #endif // WEBP_DEC_COMMON_DEC_H_

View File

@ -12,7 +12,9 @@
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include <assert.h> #include <assert.h>
#include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/vp8i_dec.h" #include "src/dec/vp8i_dec.h"
#include "src/dec/webpi_dec.h" #include "src/dec/webpi_dec.h"
#include "src/dsp/dsp.h" #include "src/dsp/dsp.h"
@ -25,9 +27,9 @@
static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
WebPDecBuffer* output = p->output; WebPDecBuffer* output = p->output;
const WebPYUVABuffer* const buf = &output->u.YUVA; const WebPYUVABuffer* const buf = &output->u.YUVA;
uint8_t* const y_dst = buf->y + (size_t)io->mb_y * buf->y_stride; uint8_t* const y_dst = buf->y + (ptrdiff_t)io->mb_y * buf->y_stride;
uint8_t* const u_dst = buf->u + (size_t)(io->mb_y >> 1) * buf->u_stride; uint8_t* const u_dst = buf->u + (ptrdiff_t)(io->mb_y >> 1) * buf->u_stride;
uint8_t* const v_dst = buf->v + (size_t)(io->mb_y >> 1) * buf->v_stride; uint8_t* const v_dst = buf->v + (ptrdiff_t)(io->mb_y >> 1) * buf->v_stride;
const int mb_w = io->mb_w; const int mb_w = io->mb_w;
const int mb_h = io->mb_h; const int mb_h = io->mb_h;
const int uv_w = (mb_w + 1) / 2; const int uv_w = (mb_w + 1) / 2;
@ -42,7 +44,7 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
WebPDecBuffer* const output = p->output; WebPDecBuffer* const output = p->output;
WebPRGBABuffer* const buf = &output->u.RGBA; WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const dst = buf->rgba + (size_t)io->mb_y * buf->stride; uint8_t* const dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride;
WebPSamplerProcessPlane(io->y, io->y_stride, WebPSamplerProcessPlane(io->y, io->y_stride,
io->u, io->v, io->uv_stride, io->u, io->v, io->uv_stride,
dst, buf->stride, io->mb_w, io->mb_h, dst, buf->stride, io->mb_w, io->mb_h,
@ -57,7 +59,7 @@ static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_lines_out = io->mb_h; // a priori guess int num_lines_out = io->mb_h; // a priori guess
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + (size_t)io->mb_y * buf->stride; uint8_t* dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride;
WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
const uint8_t* cur_y = io->y; const uint8_t* cur_y = io->y;
const uint8_t* cur_u = io->u; const uint8_t* cur_u = io->u;
@ -128,7 +130,7 @@ static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
const WebPYUVABuffer* const buf = &p->output->u.YUVA; const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int mb_w = io->mb_w; const int mb_w = io->mb_w;
const int mb_h = io->mb_h; const int mb_h = io->mb_h;
uint8_t* dst = buf->a + (size_t)io->mb_y * buf->a_stride; uint8_t* dst = buf->a + (ptrdiff_t)io->mb_y * buf->a_stride;
int j; int j;
(void)expected_num_lines_out; (void)expected_num_lines_out;
assert(expected_num_lines_out == mb_h); assert(expected_num_lines_out == mb_h);
@ -181,8 +183,8 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
(colorspace == MODE_ARGB || colorspace == MODE_Argb); (colorspace == MODE_ARGB || colorspace == MODE_Argb);
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows; int num_rows;
const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride;
uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3); uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3);
const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w, const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w,
num_rows, dst, buf->stride); num_rows, dst, buf->stride);
@ -205,8 +207,8 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
const WEBP_CSP_MODE colorspace = p->output->colorspace; const WEBP_CSP_MODE colorspace = p->output->colorspace;
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
int num_rows; int num_rows;
const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1) #if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba; uint8_t* alpha_dst = base_rgba;
#else #else
@ -271,9 +273,9 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
int expected_num_lines_out) { int expected_num_lines_out) {
const WebPYUVABuffer* const buf = &p->output->u.YUVA; const WebPYUVABuffer* const buf = &p->output->u.YUVA;
uint8_t* const dst_a = buf->a + (size_t)p->last_y * buf->a_stride; uint8_t* const dst_a = buf->a + (ptrdiff_t)p->last_y * buf->a_stride;
if (io->a != NULL) { if (io->a != NULL) {
uint8_t* const dst_y = buf->y + (size_t)p->last_y * buf->y_stride; uint8_t* const dst_y = buf->y + (ptrdiff_t)p->last_y * buf->y_stride;
const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a);
assert(expected_num_lines_out == num_lines_out); assert(expected_num_lines_out == num_lines_out);
if (num_lines_out > 0) { // unmultiply the Y if (num_lines_out > 0) { // unmultiply the Y
@ -362,7 +364,7 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
const WebPYUV444Converter convert = const WebPYUV444Converter convert =
WebPYUV444Converters[p->output->colorspace]; WebPYUV444Converters[p->output->colorspace];
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* dst = buf->rgba + (size_t)y_pos * buf->stride; uint8_t* dst = buf->rgba + (ptrdiff_t)y_pos * buf->stride;
int num_lines_out = 0; int num_lines_out = 0;
// For RGB rescaling, because of the YUV420, current scan position // For RGB rescaling, because of the YUV420, current scan position
// U/V can be +1/-1 line from the Y one. Hence the double test. // U/V can be +1/-1 line from the Y one. Hence the double test.
@ -389,14 +391,14 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
while (j < mb_h) { while (j < mb_h) {
const int y_lines_in = const int y_lines_in =
WebPRescalerImport(p->scaler_y, mb_h - j, WebPRescalerImport(p->scaler_y, mb_h - j,
io->y + (size_t)j * io->y_stride, io->y_stride); io->y + (ptrdiff_t)j * io->y_stride, io->y_stride);
j += y_lines_in; j += y_lines_in;
if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) {
const int u_lines_in = WebPRescalerImport( const int u_lines_in = WebPRescalerImport(
p->scaler_u, uv_mb_h - uv_j, io->u + (size_t)uv_j * io->uv_stride, p->scaler_u, uv_mb_h - uv_j, io->u + (ptrdiff_t)uv_j * io->uv_stride,
io->uv_stride); io->uv_stride);
const int v_lines_in = WebPRescalerImport( const int v_lines_in = WebPRescalerImport(
p->scaler_v, uv_mb_h - uv_j, io->v + (size_t)uv_j * io->uv_stride, p->scaler_v, uv_mb_h - uv_j, io->v + (ptrdiff_t)uv_j * io->uv_stride,
io->uv_stride); io->uv_stride);
(void)v_lines_in; // remove a gcc warning (void)v_lines_in; // remove a gcc warning
assert(u_lines_in == v_lines_in); assert(u_lines_in == v_lines_in);
@ -409,7 +411,7 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride;
const WEBP_CSP_MODE colorspace = p->output->colorspace; const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int alpha_first = const int alpha_first =
(colorspace == MODE_ARGB || colorspace == MODE_Argb); (colorspace == MODE_ARGB || colorspace == MODE_Argb);
@ -437,7 +439,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
int max_lines_out) { int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA; const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride;
#if (WEBP_SWAP_16BIT_CSP == 1) #if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba; uint8_t* alpha_dst = base_rgba;
#else #else
@ -476,7 +478,7 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
int lines_left = expected_num_out_lines; int lines_left = expected_num_out_lines;
const int y_end = p->last_y + lines_left; const int y_end = p->last_y + lines_left;
while (lines_left > 0) { while (lines_left > 0) {
const int64_t row_offset = (int64_t)scaler->src_y - io->mb_y; const int64_t row_offset = (ptrdiff_t)scaler->src_y - io->mb_y;
WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y,
io->a + row_offset * io->width, io->width); io->a + row_offset * io->width, io->width);
lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left);

View File

@ -13,6 +13,7 @@
// Jyrki Alakuijala (jyrki@google.com) // Jyrki Alakuijala (jyrki@google.com)
#include <assert.h> #include <assert.h>
#include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/alphai_dec.h" #include "src/dec/alphai_dec.h"
@ -624,8 +625,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
int num_lines_in = 0; int num_lines_in = 0;
int num_lines_out = 0; int num_lines_out = 0;
while (num_lines_in < mb_h) { while (num_lines_in < mb_h) {
uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride; uint8_t* const row_in = in + (ptrdiff_t)num_lines_in * in_stride;
uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride; uint8_t* const row_out = out + (ptrdiff_t)num_lines_out * out_stride;
const int lines_left = mb_h - num_lines_in; const int lines_left = mb_h - num_lines_in;
const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
int lines_imported; int lines_imported;
@ -827,7 +828,7 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
const WebPRGBABuffer* const buf = &output->u.RGBA; const WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const rgba = uint8_t* const rgba =
buf->rgba + (int64_t)dec->last_out_row_ * buf->stride; buf->rgba + (ptrdiff_t)dec->last_out_row_ * buf->stride;
const int num_rows_out = const int num_rows_out =
#if !defined(WEBP_REDUCE_SIZE) #if !defined(WEBP_REDUCE_SIZE)
io->use_scaling ? io->use_scaling ?

View File

@ -13,13 +13,15 @@
#include <stdlib.h> #include <stdlib.h>
#include "src/dec/common_dec.h"
#include "src/dec/vp8_dec.h" #include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h" #include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h" #include "src/dec/vp8li_dec.h"
#include "src/dec/webpi_dec.h" #include "src/dec/webpi_dec.h"
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG
#include "src/webp/decode.h" #include "src/webp/decode.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG
#include "src/webp/types.h" #include "src/webp/types.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -747,6 +749,61 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
return 1; return 1;
} }
static int WebPCheckCropDimensionsBasic(int x, int y, int w, int h) {
return !(x < 0 || y < 0 || w <= 0 || h <= 0);
}
int WebPValidateDecoderConfig(const WebPDecoderConfig* config) {
const WebPDecoderOptions* options;
if (config == NULL) return 0;
if (!IsValidColorspace(config->output.colorspace)) {
return 0;
}
options = &config->options;
// bypass_filtering, no_fancy_upsampling, use_cropping, use_scaling,
// use_threads, flip can be any integer and are interpreted as boolean.
// Check for cropping.
if (options->use_cropping && !WebPCheckCropDimensionsBasic(
options->crop_left, options->crop_top,
options->crop_width, options->crop_height)) {
return 0;
}
// Check for scaling.
if (options->use_scaling &&
(options->scaled_width < 0 || options->scaled_height < 0 ||
(options->scaled_width == 0 && options->scaled_height == 0))) {
return 0;
}
// In case the WebPBitstreamFeatures has been filled in, check further.
if (config->input.width > 0 || config->input.height > 0) {
int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height;
if (options->use_cropping &&
!WebPCheckCropDimensions(config->input.width, config->input.height,
options->crop_left, options->crop_top,
options->crop_width, options->crop_height)) {
return 0;
}
if (options->use_scaling && !WebPRescalerGetScaledDimensions(
config->input.width, config->input.height,
&scaled_width, &scaled_height)) {
return 0;
}
}
// Check for dithering.
if (options->dithering_strength < 0 || options->dithering_strength > 100 ||
options->alpha_dithering_strength < 0 ||
options->alpha_dithering_strength > 100) {
return 0;
}
return 1;
}
VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
WebPBitstreamFeatures* features, WebPBitstreamFeatures* features,
int version) { int version) {
@ -806,8 +863,8 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
int WebPCheckCropDimensions(int image_width, int image_height, int WebPCheckCropDimensions(int image_width, int image_height,
int x, int y, int w, int h) { int x, int y, int w, int h) {
return !(x < 0 || y < 0 || w <= 0 || h <= 0 || return WebPCheckCropDimensionsBasic(x, y, w, h) &&
x >= image_width || w > image_width || w > image_width - x || !(x >= image_width || w > image_width || w > image_width - x ||
y >= image_height || h > image_height || h > image_height - y); y >= image_height || h > image_height || h > image_height - y);
} }

View File

@ -945,6 +945,18 @@ static int Quantize2Blocks_NEON(int16_t in[32], int16_t out[32],
vst1q_u8(dst, r); \ vst1q_u8(dst, r); \
} while (0) } while (0)
static WEBP_INLINE uint8x16x4_t Vld1qU8x4(const uint8_t* ptr) {
#if LOCAL_CLANG_PREREQ(3, 4) || LOCAL_GCC_PREREQ(9, 4) || defined(_MSC_VER)
return vld1q_u8_x4(ptr);
#else
uint8x16x4_t res;
INIT_VECTOR4(res,
vld1q_u8(ptr + 0 * 16), vld1q_u8(ptr + 1 * 16),
vld1q_u8(ptr + 2 * 16), vld1q_u8(ptr + 3 * 16));
return res;
#endif
}
static void Intra4Preds_NEON(uint8_t* WEBP_RESTRICT dst, static void Intra4Preds_NEON(uint8_t* WEBP_RESTRICT dst,
const uint8_t* WEBP_RESTRICT top) { const uint8_t* WEBP_RESTRICT top) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
@ -971,9 +983,9 @@ static void Intra4Preds_NEON(uint8_t* WEBP_RESTRICT dst,
30, 30, 30, 30, 0, 0, 0, 0, 21, 22, 23, 24, 16, 16, 16, 16 30, 30, 30, 30, 0, 0, 0, 0, 21, 22, 23, 24, 16, 16, 16, 16
}; };
const uint8x16x4_t lookup_avgs1 = vld1q_u8_x4(kLookupTbl1); const uint8x16x4_t lookup_avgs1 = Vld1qU8x4(kLookupTbl1);
const uint8x16x4_t lookup_avgs2 = vld1q_u8_x4(kLookupTbl2); const uint8x16x4_t lookup_avgs2 = Vld1qU8x4(kLookupTbl2);
const uint8x16x4_t lookup_avgs3 = vld1q_u8_x4(kLookupTbl3); const uint8x16x4_t lookup_avgs3 = Vld1qU8x4(kLookupTbl3);
const uint8x16_t preload = vld1q_u8(top - 5); const uint8x16_t preload = vld1q_u8(top - 5);
uint8x16x2_t qcombined; uint8x16x2_t qcombined;

View File

@ -15,6 +15,8 @@
#include "src/webp/config.h" #include "src/webp/config.h"
#endif #endif
#include <stddef.h>
#include "src/dsp/cpu.h" #include "src/dsp/cpu.h"
#include "src/utils/bit_reader_inl_utils.h" #include "src/utils/bit_reader_inl_utils.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
@ -25,11 +27,12 @@
void VP8BitReaderSetBuffer(VP8BitReader* const br, void VP8BitReaderSetBuffer(VP8BitReader* const br,
const uint8_t* const start, const uint8_t* const start,
size_t size) { size_t size) {
br->buf_ = start; if (start != NULL) {
br->buf_end_ = start + size; br->buf_ = start;
br->buf_max_ = br->buf_end_ = start + size;
(size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 br->buf_max_ =
: start; (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 : start;
}
} }
void VP8InitBitReader(VP8BitReader* const br, void VP8InitBitReader(VP8BitReader* const br,

View File

@ -20,7 +20,7 @@
extern "C" { extern "C" {
#endif #endif
#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) #define WEBP_DECODER_ABI_VERSION 0x0210 // MAJOR(8b) + MINOR(8b)
// Note: forward declaring enumerations is not allowed in (strict) C and C++, // Note: forward declaring enumerations is not allowed in (strict) C and C++,
// the types are left here for reference. // the types are left here for reference.
@ -451,7 +451,9 @@ struct WebPDecoderOptions {
// Will be snapped to even values. // Will be snapped to even values.
int crop_width, crop_height; // dimension of the cropping area int crop_width, crop_height; // dimension of the cropping area
int use_scaling; // if true, scaling is applied _afterward_ int use_scaling; // if true, scaling is applied _afterward_
int scaled_width, scaled_height; // final resolution int scaled_width, scaled_height; // final resolution. if one is 0, it is
// guessed from the other one to keep the
// original ratio.
int use_threads; // if true, use multi-threaded decoding int use_threads; // if true, use multi-threaded decoding
int dithering_strength; // dithering strength (0=Off, 100=full) int dithering_strength; // dithering strength (0=Off, 100=full)
int flip; // if true, flip output vertically int flip; // if true, flip output vertically
@ -479,6 +481,11 @@ WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig(
return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION);
} }
// Returns true if 'config' is non-NULL and all configuration parameters are
// within their valid ranges.
WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig(
const WebPDecoderConfig* config);
// Instantiate a new incremental decoder object with the requested // Instantiate a new incremental decoder object with the requested
// configuration. The bitstream can be passed using 'data' and 'data_size' // configuration. The bitstream can be passed using 'data' and 'data_size'
// parameter, in which case the features will be parsed and stored into // parameter, in which case the features will be parsed and stored into