1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-09-10 09:29:49 +03:00
61 changed files with 995 additions and 678 deletions
+33
View File
@@ -6196,6 +6196,39 @@ Version 1.6.43 [February 23, 2024]
consistency verification and text linting.
Added version consistency verification to pngtest.c also.
Version 1.6.44 [September 12, 2024]
Hardened calculations in chroma handling to prevent overflows, and
relaxed a constraint in cHRM validation to accomodate the standard
ACES AP1 set of color primaries.
(Contributed by John Bowler)
Removed the ASM implementation of ARM Neon optimizations and updated
the build accordingly. Only the remaining C implementation shall be
used from now on, thus ensuring the support of the PAC/BTI security
features on ARM64.
(Contributed by Ross Burton and John Bowler)
Fixed the pickup of the PNG_HARDWARE_OPTIMIZATIONS option in the
CMake build on FreeBSD/amd64. This is an important performance fix
on this platform.
Applied various fixes and improvements to the CMake build.
(Contributed by Eric Riff, Benjamin Buch and Erik Scholz)
Added fuzzing targets for the simplified read API.
(Contributed by Mikhail Khachayants)
Fixed a build error involving pngtest.c under a custom config.
This was a regression introduced in a code cleanup in libpng-1.6.43.
(Contributed by Ben Wagner)
Fixed and improved the config files for AppVeyor CI and Travis CI.
Version 1.6.45 [January 7, 2025]
Added support for the cICP chunk.
(Contributed by Lucas Chollet and John Bowler)
Adjusted and improved various checks in colorspace calculations.
(Contributed by John Bowler)
Rearranged the write order of colorspace chunks for better conformance
with the PNG v3 draft specification.
(Contributed by John Bowler)
Raised the minimum required CMake version from 3.6 to 3.14.
Forked off a development branch for libpng version 1.8.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
Subscription is required; visit
https://lists.sourceforge.net/lists/listinfo/png-mng-implement
+2 -2
View File
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
PNG Reference Library License version 2
---------------------------------------
* Copyright (c) 1995-2024 The PNG Reference Library Authors.
* Copyright (c) 2018-2024 Cosmin Truta.
* Copyright (c) 1995-2025 The PNG Reference Library Authors.
* Copyright (c) 2018-2025 Cosmin Truta.
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* Copyright (c) 1996-1997 Andreas Dilger.
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+1 -3
View File
@@ -1,4 +1,4 @@
README for libpng version 1.6.43
README for libpng version 1.6.45
================================
See the note about version numbers near the top of `png.h`.
@@ -157,8 +157,6 @@ Files included in this distribution
"PNG: The Definitive Guide" by Greg Roelofs,
O'Reilly, 1999
libtests/ => Test programs
oss-fuzz/ => Files used by the OSS-Fuzz project for fuzz-testing
libpng
pngexif/ => Program to inspect the EXIF information in PNG files
pngminim/ => Minimal decoder, encoder, and progressive decoder
programs demonstrating the use of pngusr.dfa
-1
View File
@@ -1,4 +1,3 @@
/* arm_init.c - NEON optimised filter functions
*
* Copyright (c) 2018-2022 Cosmin Truta
+37 -230
View File
@@ -1,253 +1,60 @@
/* filter_neon.S - NEON optimised filter functions
/* filter_neon.S - placeholder file
*
* Copyright (c) 2018 Cosmin Truta
* Copyright (c) 2014,2017 Glenn Randers-Pehrson
* Written by Mans Rullgard, 2011.
* Copyright (c) 2024 Cosmin Truta
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*/
/* IMPORTANT NOTE:
*
* Historically, the hand-coded assembler implementation of Neon optimizations
* in this module had not been in sync with the intrinsics-based implementation
* in filter_neon_intrinsics.c and palette_neon_intrinsics.c, at least since
* the introduction of riffled palette optimizations. Moreover, the assembler
* code used to work on 32-bit ARM only, and it caused problems, even if empty,
* on 64-bit ARM.
*
* All references to this module from our internal build scripts and projects
* have been removed.
*
* For the external projects that might still expect this module to be present,
* we leave this stub in place, for the remaining lifetime of libpng-1.6.x.
* Everything should continue to function normally, as long as there are no
* deliberate attempts to use the old hand-made assembler code. A build error
* will be raised otherwise.
*/
/* This is required to get the symbol renames, which are #defines, and the
* definitions (or not) of PNG_ARM_NEON_OPT and PNG_ARM_NEON_IMPLEMENTATION.
*/
#define PNG_VERSION_INFO_ONLY
#include "../pngpriv.h"
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
#endif
#ifdef PNG_READ_SUPPORTED
/* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for
* ARM64). The code in arm/filter_neon_intrinsics.c supports ARM64, however it
* only works if -mfpu=neon is specified on the GCC command line. See pngpriv.h
* for the logic which sets PNG_USE_ARM_NEON_ASM:
*/
#if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */
#if PNG_ARM_NEON_OPT > 0
#ifdef __ELF__
# define ELF
#if defined(__clang__)
#define GNUC_VERSION 0 /* not gcc, although it might pretend to be */
#elif defined(__GNUC__)
#define GNUC_MAJOR (__GNUC__ + 0)
#define GNUC_MINOR (__GNUC_MINOR__ + 0)
#define GNUC_PATCHLEVEL (__GNUC_PATCHLEVEL__ + 0)
#define GNUC_VERSION (GNUC_MAJOR * 10000 + GNUC_MINOR * 100 + GNUC_PATCHLEVEL)
#else
# define ELF @
#define GNUC_VERSION 0 /* not gcc */
#endif
.arch armv7-a
.fpu neon
#if (GNUC_VERSION > 0) && (GNUC_VERSION < 40300)
#error "PNG_ARM_NEON is not supported with gcc versions earlier than 4.3.0"
#elif GNUC_VERSION == 40504
#error "PNG_ARM_NEON is not supported with gcc version 4.5.4"
#else
#error "Please use 'arm/*_neon_intrinsics.c' for PNG_ARM_NEON support"
#endif
.macro func name, export=0
.macro endfunc
ELF .size \name, . - \name
.endfunc
.purgem endfunc
.endm
.text
/* Explicitly specifying alignment here because some versions of
* GAS don't align code correctly. This is harmless in correctly
* written versions of GAS.
*/
.align 2
.if \export
.global \name
.endif
ELF .type \name, STT_FUNC
.func \name
\name:
.endm
func png_read_filter_row_sub4_neon, export=1
ldr r3, [r0, #4] @ rowbytes
vmov.i8 d3, #0
1:
vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
vadd.u8 d0, d3, d4
vadd.u8 d1, d0, d5
vadd.u8 d2, d1, d6
vadd.u8 d3, d2, d7
vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
subs r3, r3, #16
bgt 1b
bx lr
endfunc
func png_read_filter_row_sub3_neon, export=1
ldr r3, [r0, #4] @ rowbytes
vmov.i8 d3, #0
mov r0, r1
mov r2, #3
mov r12, #12
vld1.8 {q11}, [r0], r12
1:
vext.8 d5, d22, d23, #3
vadd.u8 d0, d3, d22
vext.8 d6, d22, d23, #6
vadd.u8 d1, d0, d5
vext.8 d7, d23, d23, #1
vld1.8 {q11}, [r0], r12
vst1.32 {d0[0]}, [r1,:32], r2
vadd.u8 d2, d1, d6
vst1.32 {d1[0]}, [r1], r2
vadd.u8 d3, d2, d7
vst1.32 {d2[0]}, [r1], r2
vst1.32 {d3[0]}, [r1], r2
subs r3, r3, #12
bgt 1b
bx lr
endfunc
func png_read_filter_row_up_neon, export=1
ldr r3, [r0, #4] @ rowbytes
1:
vld1.8 {q0}, [r1,:128]
vld1.8 {q1}, [r2,:128]!
vadd.u8 q0, q0, q1
vst1.8 {q0}, [r1,:128]!
subs r3, r3, #16
bgt 1b
bx lr
endfunc
func png_read_filter_row_avg4_neon, export=1
ldr r12, [r0, #4] @ rowbytes
vmov.i8 d3, #0
1:
vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
vhadd.u8 d0, d3, d16
vadd.u8 d0, d0, d4
vhadd.u8 d1, d0, d17
vadd.u8 d1, d1, d5
vhadd.u8 d2, d1, d18
vadd.u8 d2, d2, d6
vhadd.u8 d3, d2, d19
vadd.u8 d3, d3, d7
vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
subs r12, r12, #16
bgt 1b
bx lr
endfunc
func png_read_filter_row_avg3_neon, export=1
push {r4,lr}
ldr r12, [r0, #4] @ rowbytes
vmov.i8 d3, #0
mov r0, r1
mov r4, #3
mov lr, #12
vld1.8 {q11}, [r0], lr
1:
vld1.8 {q10}, [r2], lr
vext.8 d5, d22, d23, #3
vhadd.u8 d0, d3, d20
vext.8 d17, d20, d21, #3
vadd.u8 d0, d0, d22
vext.8 d6, d22, d23, #6
vhadd.u8 d1, d0, d17
vext.8 d18, d20, d21, #6
vadd.u8 d1, d1, d5
vext.8 d7, d23, d23, #1
vld1.8 {q11}, [r0], lr
vst1.32 {d0[0]}, [r1,:32], r4
vhadd.u8 d2, d1, d18
vst1.32 {d1[0]}, [r1], r4
vext.8 d19, d21, d21, #1
vadd.u8 d2, d2, d6
vhadd.u8 d3, d2, d19
vst1.32 {d2[0]}, [r1], r4
vadd.u8 d3, d3, d7
vst1.32 {d3[0]}, [r1], r4
subs r12, r12, #12
bgt 1b
pop {r4,pc}
endfunc
.macro paeth rx, ra, rb, rc
vaddl.u8 q12, \ra, \rb @ a + b
vaddl.u8 q15, \rc, \rc @ 2*c
vabdl.u8 q13, \rb, \rc @ pa
vabdl.u8 q14, \ra, \rc @ pb
vabd.u16 q15, q12, q15 @ pc
vcle.u16 q12, q13, q14 @ pa <= pb
vcle.u16 q13, q13, q15 @ pa <= pc
vcle.u16 q14, q14, q15 @ pb <= pc
vand q12, q12, q13 @ pa <= pb && pa <= pc
vmovn.u16 d28, q14
vmovn.u16 \rx, q12
vbsl d28, \rb, \rc
vbsl \rx, \ra, d28
.endm
func png_read_filter_row_paeth4_neon, export=1
ldr r12, [r0, #4] @ rowbytes
vmov.i8 d3, #0
vmov.i8 d20, #0
1:
vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
paeth d0, d3, d16, d20
vadd.u8 d0, d0, d4
paeth d1, d0, d17, d16
vadd.u8 d1, d1, d5
paeth d2, d1, d18, d17
vadd.u8 d2, d2, d6
paeth d3, d2, d19, d18
vmov d20, d19
vadd.u8 d3, d3, d7
vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
subs r12, r12, #16
bgt 1b
bx lr
endfunc
func png_read_filter_row_paeth3_neon, export=1
push {r4,lr}
ldr r12, [r0, #4] @ rowbytes
vmov.i8 d3, #0
vmov.i8 d4, #0
mov r0, r1
mov r4, #3
mov lr, #12
vld1.8 {q11}, [r0], lr
1:
vld1.8 {q10}, [r2], lr
paeth d0, d3, d20, d4
vext.8 d5, d22, d23, #3
vadd.u8 d0, d0, d22
vext.8 d17, d20, d21, #3
paeth d1, d0, d17, d20
vst1.32 {d0[0]}, [r1,:32], r4
vext.8 d6, d22, d23, #6
vadd.u8 d1, d1, d5
vext.8 d18, d20, d21, #6
paeth d2, d1, d18, d17
vext.8 d7, d23, d23, #1
vld1.8 {q11}, [r0], lr
vst1.32 {d1[0]}, [r1], r4
vadd.u8 d2, d2, d6
vext.8 d19, d21, d21, #1
paeth d3, d2, d19, d18
vst1.32 {d2[0]}, [r1], r4
vmov d4, d19
vadd.u8 d3, d3, d7
vst1.32 {d3[0]}, [r1], r4
subs r12, r12, #12
bgt 1b
pop {r4,pc}
endfunc
#endif /* PNG_ARM_NEON_OPT > 0 */
#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */
#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 */
#endif /* READ */
-1
View File
@@ -1,4 +1,3 @@
/* filter_neon_intrinsics.c - NEON optimised filter functions
*
* Copyright (c) 2018 Cosmin Truta
+1 -2
View File
@@ -1,4 +1,3 @@
/* palette_neon_intrinsics.c - NEON optimised palette expansion functions
*
* Copyright (c) 2018-2019 Cosmin Truta
@@ -64,7 +63,7 @@ png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info,
{
png_uint_32 row_width = row_info->width;
const png_uint_32 *riffled_palette =
(const png_uint_32 *)png_ptr->riffled_palette;
png_aligncastconst(png_const_uint_32p, png_ptr->riffled_palette);
const png_uint_32 pixels_per_chunk = 4;
png_uint_32 i;
-1
View File
@@ -1,4 +1,3 @@
/* filter_sse2_intrinsics.c - SSE2 optimized filter functions
*
* Copyright (c) 2018 Cosmin Truta
-1
View File
@@ -1,4 +1,3 @@
/* intel_init.c - SSE2 optimized filter functions
*
* Copyright (c) 2018 Cosmin Truta
+22 -23
View File
@@ -1,4 +1,3 @@
/* filter_msa_intrinsics.c - MSA optimised filter functions
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -47,7 +46,7 @@
uint8_t *psrc_lw_m = (uint8_t *) (psrc); \
uint32_t val_m; \
\
asm volatile ( \
__asm__ volatile ( \
"lw %[val_m], %[psrc_lw_m] \n\t" \
\
: [val_m] "=r" (val_m) \
@@ -62,7 +61,7 @@
uint8_t *pdst_sh_m = (uint8_t *) (pdst); \
uint16_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"sh %[val_m], %[pdst_sh_m] \n\t" \
\
: [pdst_sh_m] "=m" (*pdst_sh_m) \
@@ -75,7 +74,7 @@
uint8_t *pdst_sw_m = (uint8_t *) (pdst); \
uint32_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"sw %[val_m], %[pdst_sw_m] \n\t" \
\
: [pdst_sw_m] "=m" (*pdst_sw_m) \
@@ -83,20 +82,20 @@
); \
}
#if (__mips == 64)
#if __mips == 64
#define SD(val, pdst) \
{ \
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
uint64_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"sd %[val_m], %[pdst_sd_m] \n\t" \
\
: [pdst_sd_m] "=m" (*pdst_sd_m) \
: [val_m] "r" (val_m) \
); \
}
#else
#else
#define SD(val, pdst) \
{ \
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
@@ -108,17 +107,17 @@
SW(val0_m, pdst_sd_m); \
SW(val1_m, pdst_sd_m + 4); \
}
#endif
#endif /* __mips == 64 */
#else
#define MSA_SRLI_B(a, b) (a >> b)
#if (__mips_isa_rev >= 6)
#if __mips_isa_rev >= 6
#define LW(psrc) \
( { \
uint8_t *psrc_lw_m = (uint8_t *) (psrc); \
uint32_t val_m; \
\
asm volatile ( \
__asm__ volatile ( \
"lw %[val_m], %[psrc_lw_m] \n\t" \
\
: [val_m] "=r" (val_m) \
@@ -133,7 +132,7 @@
uint8_t *pdst_sh_m = (uint8_t *) (pdst); \
uint16_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"sh %[val_m], %[pdst_sh_m] \n\t" \
\
: [pdst_sh_m] "=m" (*pdst_sh_m) \
@@ -146,7 +145,7 @@
uint8_t *pdst_sw_m = (uint8_t *) (pdst); \
uint32_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"sw %[val_m], %[pdst_sw_m] \n\t" \
\
: [pdst_sw_m] "=m" (*pdst_sw_m) \
@@ -154,20 +153,20 @@
); \
}
#if (__mips == 64)
#if __mips == 64
#define SD(val, pdst) \
{ \
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
uint64_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"sd %[val_m], %[pdst_sd_m] \n\t" \
\
: [pdst_sd_m] "=m" (*pdst_sd_m) \
: [val_m] "r" (val_m) \
); \
}
#else
#else
#define SD(val, pdst) \
{ \
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
@@ -179,14 +178,14 @@
SW(val0_m, pdst_sd_m); \
SW(val1_m, pdst_sd_m + 4); \
}
#endif
#else // !(__mips_isa_rev >= 6)
#endif /* __mips == 64 */
#else
#define LW(psrc) \
( { \
uint8_t *psrc_lw_m = (uint8_t *) (psrc); \
uint32_t val_m; \
\
asm volatile ( \
__asm__ volatile ( \
"ulw %[val_m], %[psrc_lw_m] \n\t" \
\
: [val_m] "=r" (val_m) \
@@ -201,7 +200,7 @@
uint8_t *pdst_sh_m = (uint8_t *) (pdst); \
uint16_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"ush %[val_m], %[pdst_sh_m] \n\t" \
\
: [pdst_sh_m] "=m" (*pdst_sh_m) \
@@ -214,7 +213,7 @@
uint8_t *pdst_sw_m = (uint8_t *) (pdst); \
uint32_t val_m = (val); \
\
asm volatile ( \
__asm__ volatile ( \
"usw %[val_m], %[pdst_sw_m] \n\t" \
\
: [pdst_sw_m] "=m" (*pdst_sw_m) \
@@ -222,7 +221,7 @@
); \
}
#define SD(val, pdst) \
#define SD(val, pdst) \
{ \
uint8_t *pdst_sd_m = (uint8_t *) (pdst); \
uint32_t val0_m, val1_m; \
@@ -238,14 +237,14 @@
{ \
uint8_t *pdst_m = (uint8_t *) (pdst); \
\
asm volatile ( \
__asm__ volatile ( \
"usw $0, %[pdst_m] \n\t" \
\
: [pdst_m] "=m" (*pdst_m) \
: \
); \
}
#endif // (__mips_isa_rev >= 6)
#endif /* __mips_isa_rev >= 6 */
#endif
#define LD_B(RTYPE, psrc) *((RTYPE *) (psrc))
-1
View File
@@ -1,4 +1,3 @@
/* mips_init.c - MSA optimised filter functions
*
* Copyright (c) 2018-2024 Cosmin Truta
+183 -85
View File
@@ -1,7 +1,6 @@
/* png.c - location for general purpose libpng functions
*
* Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,7 +13,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
typedef png_libpng_version_1_6_43 Your_png_h_is_not_version_1_6_43;
typedef png_libpng_version_1_6_45 Your_png_h_is_not_version_1_6_45;
/* Tells libpng that we have already handled the first "num_bytes" bytes
* of the PNG file signature. If the PNG data is embedded into another
@@ -794,8 +793,8 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
"libpng version 1.6.43" PNG_STRING_NEWLINE \
"Copyright (c) 2018-2024 Cosmin Truta" PNG_STRING_NEWLINE \
"libpng version 1.6.45" PNG_STRING_NEWLINE \
"Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -1203,6 +1202,68 @@ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
#endif /* GAMMA */
#ifdef PNG_COLORSPACE_SUPPORTED
static png_int_32
png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error)
{
/* Safely add two fixed point values setting an error flag and returning 0.5
* on overflow.
* IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
* relying on addition of two positive values producing a negative one is not
* safe.
*/
if (addend0 > 0)
{
if (0x7fffffff - addend0 >= addend1)
return addend0+addend1;
}
else if (addend0 < 0)
{
if (-0x7fffffff - addend0 <= addend1)
return addend0+addend1;
}
else
return addend1;
*error = 1;
return PNG_FP_1/2;
}
static png_int_32
png_fp_sub(png_int_32 addend0, png_int_32 addend1, int *error)
{
/* As above but calculate addend0-addend1. */
if (addend1 > 0)
{
if (-0x7fffffff + addend1 <= addend0)
return addend0-addend1;
}
else if (addend1 < 0)
{
if (0x7fffffff + addend1 >= addend0)
return addend0-addend1;
}
else
return addend0;
*error = 1;
return PNG_FP_1/2;
}
static int
png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1,
png_int_32 addend2)
{
/* Safely add three integers. Returns 0 on success, 1 on overflow. Does not
* set the result on overflow.
*/
int error = 0;
int result = png_fp_add(*addend0_and_result,
png_fp_add(addend1, addend2, &error),
&error);
if (!error) *addend0_and_result = result;
return error;
}
/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
* cHRM, as opposed to using chromaticities. These internal APIs return
* non-zero on a parameter error. The X, Y and Z values are required to be
@@ -1211,38 +1272,60 @@ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
static int
png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
{
png_int_32 d, dwhite, whiteX, whiteY;
png_int_32 d, dred, dgreen, dblue, dwhite, whiteX, whiteY;
d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z;
if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)
/* 'd' in each of the blocks below is just X+Y+Z for each component,
* x, y and z are X,Y,Z/(X+Y+Z).
*/
d = XYZ->red_X;
if (png_safe_add(&d, XYZ->red_Y, XYZ->red_Z))
return 1;
if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)
dred = d;
if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, dred) == 0)
return 1;
if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, dred) == 0)
return 1;
d = XYZ->green_X;
if (png_safe_add(&d, XYZ->green_Y, XYZ->green_Z))
return 1;
dgreen = d;
if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, dgreen) == 0)
return 1;
if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, dgreen) == 0)
return 1;
d = XYZ->blue_X;
if (png_safe_add(&d, XYZ->blue_Y, XYZ->blue_Z))
return 1;
dblue = d;
if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, dblue) == 0)
return 1;
if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, dblue) == 0)
return 1;
/* The reference white is simply the sum of the end-point (X,Y,Z) vectors so
* the fillowing calculates (X+Y+Z) of the reference white (media white,
* encoding white) itself:
*/
d = dblue;
if (png_safe_add(&d, dred, dgreen))
return 1;
dwhite = d;
whiteX = XYZ->red_X;
whiteY = XYZ->red_Y;
d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z;
if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)
return 1;
if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)
return 1;
dwhite += d;
whiteX += XYZ->green_X;
whiteY += XYZ->green_Y;
d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z;
if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)
return 1;
if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)
return 1;
dwhite += d;
whiteX += XYZ->blue_X;
whiteY += XYZ->blue_Y;
/* The reference white is simply the sum of the end-point (X,Y,Z) vectors,
* thus:
/* Find the white X,Y values from the sum of the red, green and blue X,Y
* values.
*/
d = XYZ->red_X;
if (png_safe_add(&d, XYZ->green_X, XYZ->blue_X))
return 1;
whiteX = d;
d = XYZ->red_Y;
if (png_safe_add(&d, XYZ->green_Y, XYZ->blue_Y))
return 1;
whiteY = d;
if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0)
return 1;
if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)
@@ -1261,15 +1344,24 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
* have end points with 0 tristimulus values (these are impossible end
* points, but they are used to cover the possible colors). We check
* xy->whitey against 5, not 0, to avoid a possible integer overflow.
*
* The limits here will *not* accept ACES AP0, where bluey is -7700
* (-0.0770) because the PNG spec itself requires the xy values to be
* unsigned. whitey is also required to be 5 or more to avoid overflow.
*
* Instead the upper limits have been relaxed to accomodate ACES AP1 where
* redz ends up as -600 (-0.006). ProPhotoRGB was already "in range."
* The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy.
*/
if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1;
if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;
if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;
if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;
if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1;
if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;
if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;
if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1;
const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10);
if (xy->redx < 0 || xy->redx > fpLimit) return 1;
if (xy->redy < 0 || xy->redy > fpLimit-xy->redx) return 1;
if (xy->greenx < 0 || xy->greenx > fpLimit) return 1;
if (xy->greeny < 0 || xy->greeny > fpLimit-xy->greenx) return 1;
if (xy->bluex < 0 || xy->bluex > fpLimit) return 1;
if (xy->bluey < 0 || xy->bluey > fpLimit-xy->bluex) return 1;
if (xy->whitex < 0 || xy->whitex > fpLimit) return 1;
if (xy->whitey < 5 || xy->whitey > fpLimit-xy->whitex) return 1;
/* The reverse calculation is more difficult because the original tristimulus
* value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
@@ -1414,18 +1506,23 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
* (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
*
* Accuracy:
* The input values have 5 decimal digits of accuracy. The values are all in
* the range 0 < value < 1, so simple products are in the same range but may
* need up to 10 decimal digits to preserve the original precision and avoid
* underflow. Because we are using a 32-bit signed representation we cannot
* match this; the best is a little over 9 decimal digits, less than 10.
* The input values have 5 decimal digits of accuracy.
*
* In the previous implementation the values were all in the range 0 < value
* < 1, so simple products are in the same range but may need up to 10
* decimal digits to preserve the original precision and avoid underflow.
* Because we are using a 32-bit signed representation we cannot match this;
* the best is a little over 9 decimal digits, less than 10.
*
* This range has now been extended to allow values up to 1.1, or 110,000 in
* fixed point.
*
* The approach used here is to preserve the maximum precision within the
* signed representation. Because the red-scale calculation above uses the
* difference between two products of values that must be in the range -1..+1
* it is sufficient to divide the product by 7; ceil(100,000/32767*2). The
* factor is irrelevant in the calculation because it is applied to both
* numerator and denominator.
* difference between two products of values that must be in the range
* -1.1..+1.1 it is sufficient to divide the product by 8;
* ceil(121,000/32767*2). The factor is irrelevant in the calculation
* because it is applied to both numerator and denominator.
*
* Note that the values of the differences of the products of the
* chromaticities in the above equations tend to be small, for example for
@@ -1447,49 +1544,61 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
* Adobe Wide Gamut RGB
* 0.258728243040113 0.724682314948566 0.016589442011321
*/
/* By the argument, above overflow should be impossible here. The return
* value of 2 indicates an internal error to the caller.
int error = 0;
/* By the argument above overflow should be impossible here, however the
* code now simply returns a failure code. The xy subtracts in the arguments
* to png_muldiv are *not* checked for overflow because the checks at the
* start guarantee they are in the range 0..110000 and png_fixed_point is a
* 32-bit signed number.
*/
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0)
return 2;
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)
return 2;
denominator = left - right;
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0)
return 1;
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) == 0)
return 1;
denominator = png_fp_sub(left, right, &error);
if (error) return 1;
/* Now find the red numerator. */
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
return 2;
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
return 2;
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
return 1;
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) == 0)
return 1;
/* Overflow is possible here and it indicates an extreme set of PNG cHRM
* chunk values. This calculation actually returns the reciprocal of the
* scale value because this allows us to delay the multiplication of white-y
* into the denominator, which tends to produce a small number.
*/
if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 ||
if (png_muldiv(&red_inverse, xy->whitey, denominator,
png_fp_sub(left, right, &error)) == 0 || error ||
red_inverse <= xy->whitey /* r+g+b scales = white scale */)
return 1;
/* Similarly for green_inverse: */
if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
return 2;
if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
return 2;
if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||
if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0)
return 1;
if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
return 1;
if (png_muldiv(&green_inverse, xy->whitey, denominator,
png_fp_sub(left, right, &error)) == 0 || error ||
green_inverse <= xy->whitey)
return 1;
/* And the blue scale, the checks above guarantee this can't overflow but it
* can still produce 0 for extreme cHRM values.
*/
blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) -
png_reciprocal(green_inverse);
if (blue_scale <= 0)
blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey),
png_reciprocal(red_inverse), &error),
png_reciprocal(green_inverse), &error);
if (error || blue_scale <= 0)
return 1;
/* And fill in the png_XYZ: */
/* And fill in the png_XYZ. Again the subtracts are safe because of the
* checks on the xy values at the start (the subtracts just calculate the
* corresponding z values.)
*/
if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0)
return 1;
if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0)
@@ -1520,25 +1629,14 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
static int
png_XYZ_normalize(png_XYZ *XYZ)
{
png_int_32 Y;
png_int_32 Y, Ytemp;
if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 ||
XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||
XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)
/* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. */
Ytemp = XYZ->red_Y;
if (png_safe_add(&Ytemp, XYZ->green_Y, XYZ->blue_Y))
return 1;
/* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1.
* IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
* relying on addition of two positive values producing a negative one is not
* safe.
*/
Y = XYZ->red_Y;
if (0x7fffffff - Y < XYZ->green_X)
return 1;
Y += XYZ->green_Y;
if (0x7fffffff - Y < XYZ->blue_X)
return 1;
Y += XYZ->blue_Y;
Y = Ytemp;
if (Y != PNG_FP_1)
{
+29 -18
View File
@@ -1,9 +1,8 @@
/* png.h - header file for PNG reference library
*
* libpng version 1.6.43
* libpng version 1.6.45
*
* Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -15,7 +14,7 @@
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
* Glenn Randers-Pehrson
* libpng versions 1.6.36, December 2018, through 1.6.43, February 2024:
* libpng versions 1.6.36, December 2018, through 1.6.45, January 2025:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -27,8 +26,8 @@
* PNG Reference Library License version 2
* ---------------------------------------
*
* * Copyright (c) 1995-2024 The PNG Reference Library Authors.
* * Copyright (c) 2018-2024 Cosmin Truta.
* * Copyright (c) 1995-2025 The PNG Reference Library Authors.
* * Copyright (c) 2018-2025 Cosmin Truta.
* * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* * Copyright (c) 1996-1997 Andreas Dilger.
* * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +238,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
* 1.6.43 16 10643 16.so.16.43[.0]
* 1.6.45 16 10645 16.so.16.45[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -275,7 +274,7 @@
*/
/* Version information for png.h - this should match the version in png.c */
#define PNG_LIBPNG_VER_STRING "1.6.43"
#define PNG_LIBPNG_VER_STRING "1.6.45"
#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
/* The versions of shared library builds should stay in sync, going forward */
@@ -286,18 +285,18 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
#define PNG_LIBPNG_VER_RELEASE 43
#define PNG_LIBPNG_VER_RELEASE 45
/* This should be zero for a public release, or non-zero for a
* development version.
*/
#define PNG_LIBPNG_VER_BUILD 0
#define PNG_LIBPNG_VER_BUILD 0
/* Release Status */
#define PNG_LIBPNG_BUILD_ALPHA 1
#define PNG_LIBPNG_BUILD_BETA 2
#define PNG_LIBPNG_BUILD_RC 3
#define PNG_LIBPNG_BUILD_STABLE 4
#define PNG_LIBPNG_BUILD_ALPHA 1
#define PNG_LIBPNG_BUILD_BETA 2
#define PNG_LIBPNG_BUILD_RC 3
#define PNG_LIBPNG_BUILD_STABLE 4
#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7
/* Release-Specific Flags */
@@ -317,7 +316,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
#define PNG_LIBPNG_VER 10643 /* 1.6.43 */
#define PNG_LIBPNG_VER 10645 /* 1.6.45 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -427,7 +426,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
typedef char* png_libpng_version_1_6_43;
typedef char* png_libpng_version_1_6_45;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -745,6 +744,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
#define PNG_INFO_cICP 0x20000U
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -824,7 +824,7 @@ typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp,
* your compiler. This may be very difficult - try using a different compiler
* to build the library!
*/
PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);
PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef);
#endif
/* Transform masks for the high-level interface */
@@ -1974,6 +1974,17 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
png_fixed_point int_blue_Z))
#endif
#ifdef PNG_cICP_SUPPORTED
PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr,
png_inforp info_ptr, png_bytep colour_primaries,
png_bytep transfer_function, png_bytep matrix_coefficients,
png_bytep video_full_range_flag));
PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr,
png_inforp info_ptr, png_byte colour_primaries,
png_byte transfer_function, png_byte matrix_coefficients,
png_byte video_full_range_flag));
#endif
#ifdef PNG_eXIf_SUPPORTED
PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,
png_inforp info_ptr, png_bytep *exif));
@@ -3238,7 +3249,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
* one to use is one more than this.)
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
PNG_EXPORT_LAST_ORDINAL(249);
PNG_EXPORT_LAST_ORDINAL(251);
#endif
#ifdef __cplusplus
+5 -6
View File
@@ -1,9 +1,8 @@
/* pngconf.h - machine-configurable file for libpng
*
* libpng version 1.6.43
* libpng version 1.6.45
*
* Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -88,7 +87,7 @@
/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect
* against legacy (pre ISOC90) compilers that did not understand function
* prototypes. It is not required for modern C compilers.
* prototypes. [Deprecated.]
*/
#ifndef PNGARG
# define PNGARG(arglist) arglist
@@ -298,7 +297,7 @@
#ifndef PNG_EXPORTA
# define PNG_EXPORTA(ordinal, type, name, args, attributes) \
PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), PNGARG(args), \
PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), args, \
PNG_LINKAGE_API attributes)
#endif
@@ -316,7 +315,7 @@
#endif
#ifndef PNG_CALLBACK
# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args)
# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) args
#endif
/* Support for compiler specific function attributes. These are used
-1
View File
@@ -1,4 +1,3 @@
/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
*
* Copyright (c) 2018 Cosmin Truta
+5 -5
View File
@@ -1,4 +1,3 @@
/* pngerror.c - stub functions for i/o and memory allocation
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -20,13 +19,14 @@
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,
png_const_charp error_message)),PNG_NORETURN);
static PNG_FUNCTION(void /* PRIVATE */,
png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
PNG_NORETURN);
#ifdef PNG_WARNINGS_SUPPORTED
static void /* PRIVATE */
png_default_warning PNGARG((png_const_structrp png_ptr,
png_const_charp warning_message));
png_default_warning(png_const_structrp png_ptr,
png_const_charp warning_message);
#endif /* WARNINGS */
/* This function is called whenever there is a fatal error. This function
+25 -1
View File
@@ -1,4 +1,3 @@
/* pngget.c - retrieval of values from info struct
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -785,6 +784,31 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
}
#endif
#ifdef PNG_cICP_SUPPORTED
png_uint_32 PNGAPI
png_get_cICP(png_const_structrp png_ptr,
png_inforp info_ptr, png_bytep colour_primaries,
png_bytep transfer_function, png_bytep matrix_coefficients,
png_bytep video_full_range_flag)
{
png_debug1(1, "in %s retrieval function", "cICP");
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_cICP) != 0 &&
colour_primaries != NULL && transfer_function != NULL &&
matrix_coefficients != NULL && video_full_range_flag != NULL)
{
*colour_primaries = info_ptr->cicp_colour_primaries;
*transfer_function = info_ptr->cicp_transfer_function;
*matrix_coefficients = info_ptr->cicp_matrix_coefficients;
*video_full_range_flag = info_ptr->cicp_video_full_range_flag;
return (PNG_INFO_cICP);
}
return (0);
}
#endif
#ifdef PNG_eXIf_SUPPORTED
png_uint_32 PNGAPI
png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
+8 -1
View File
@@ -1,4 +1,3 @@
/* pnginfo.h - header file for PNG reference library
*
* Copyright (c) 2018 Cosmin Truta
@@ -101,6 +100,14 @@ struct png_info_def
png_colorspace colorspace;
#endif
#ifdef PNG_cICP_SUPPORTED
/* cICP chunk data */
png_byte cicp_colour_primaries;
png_byte cicp_transfer_function;
png_byte cicp_matrix_coefficients;
png_byte cicp_video_full_range_flag;
#endif
#ifdef PNG_iCCP_SUPPORTED
/* iCCP chunk data. */
png_charp iccp_name; /* profile name */
+10 -2
View File
@@ -1,8 +1,8 @@
/* pnglibconf.h - library build configuration */
/* libpng version 1.6.37 */
/* libpng version 1.6.45 */
/* Copyright (c) 2018-2019 Cosmin Truta */
/* Copyright (c) 2018-2025 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
/* This code is released under the libpng license. */
@@ -27,6 +27,7 @@
#define PNG_COLORSPACE_SUPPORTED
#define PNG_CONSOLE_IO_SUPPORTED
#define PNG_CONVERT_tIME_SUPPORTED
/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/
#define PNG_EASY_ACCESS_SUPPORTED
/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
#define PNG_ERROR_TEXT_SUPPORTED
@@ -41,6 +42,10 @@
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_INFO_IMAGE_SUPPORTED
#define PNG_IO_STATE_SUPPORTED
/*#undef PNG_MIPS_MMI_API_SUPPORTED*/
/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/
/*#undef PNG_MIPS_MSA_API_SUPPORTED*/
/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/
#define PNG_MNG_FEATURES_SUPPORTED
#define PNG_POINTER_INDEXING_SUPPORTED
/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/
@@ -83,6 +88,7 @@
#define PNG_READ_USER_TRANSFORM_SUPPORTED
#define PNG_READ_bKGD_SUPPORTED
#define PNG_READ_cHRM_SUPPORTED
#define PNG_READ_cICP_SUPPORTED
#define PNG_READ_eXIf_SUPPORTED
#define PNG_READ_gAMA_SUPPORTED
#define PNG_READ_hIST_SUPPORTED
@@ -153,6 +159,7 @@
#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
#define PNG_WRITE_bKGD_SUPPORTED
#define PNG_WRITE_cHRM_SUPPORTED
#define PNG_WRITE_cICP_SUPPORTED
#define PNG_WRITE_eXIf_SUPPORTED
#define PNG_WRITE_gAMA_SUPPORTED
#define PNG_WRITE_hIST_SUPPORTED
@@ -171,6 +178,7 @@
#define PNG_WRITE_zTXt_SUPPORTED
#define PNG_bKGD_SUPPORTED
#define PNG_cHRM_SUPPORTED
#define PNG_cICP_SUPPORTED
#define PNG_eXIf_SUPPORTED
#define PNG_gAMA_SUPPORTED
#define PNG_hIST_SUPPORTED
-1
View File
@@ -1,4 +1,3 @@
/* pngmem.c - stub functions for memory allocation
*
* Copyright (c) 2018 Cosmin Truta
+23 -22
View File
@@ -1,4 +1,3 @@
/* pngpread.c - read a png file in push mode
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -32,6 +31,21 @@ if (png_ptr->push_length + 4 > png_ptr->buffer_size) \
if (png_ptr->buffer_size < N) \
{ png_push_save_buffer(png_ptr); return; }
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
/* TODO: Move these arrays to a common utility module to avoid duplication. */
#endif
void PNGAPI
png_process_data(png_structrp png_ptr, png_inforp info_ptr,
png_bytep buffer, size_t buffer_size)
@@ -294,6 +308,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
#ifdef PNG_READ_cICP_SUPPORTED
else if (png_ptr->chunk_name == png_cICP)
{
PNG_PUSH_SAVE_BUFFER_IF_FULL
png_handle_cICP(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
#ifdef PNG_READ_eXIf_SUPPORTED
else if (png_ptr->chunk_name == png_eXIf)
@@ -976,27 +998,6 @@ png_push_process_row(png_structrp png_ptr)
void /* PRIVATE */
png_read_push_finish_row(png_structrp png_ptr)
{
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
static const png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
/* Height of interlace block. This is not currently used - if you need
* it, uncomment it here and in png.h
static const png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
*/
#endif
png_ptr->row_number++;
if (png_ptr->row_number < png_ptr->num_rows)
return;
+12 -42
View File
@@ -1,4 +1,3 @@
/* pngpriv.h - private declarations for use inside libpng
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -140,47 +139,6 @@
* callbacks to do this.
*/
# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon
/* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used
* if possible - if __ARM_NEON__ is set and the compiler version is not known
* to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can
* be:
*
* 1 The intrinsics code (the default with __ARM_NEON__)
* 2 The hand coded assembler (the default without __ARM_NEON__)
*
* It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however
* this is *NOT* supported and may cease to work even after a minor revision
* to libpng. It *is* valid to do this for testing purposes, e.g. speed
* testing or a new compiler, but the results should be communicated to the
* libpng implementation list for incorporation in the next minor release.
*/
# ifndef PNG_ARM_NEON_IMPLEMENTATION
# if defined(__ARM_NEON__) || defined(__ARM_NEON)
# if defined(__clang__)
/* At present it is unknown by the libpng developers which versions
* of clang support the intrinsics, however some or perhaps all
* versions do not work with the assembler so this may be
* irrelevant, so just use the default (do nothing here.)
*/
# elif defined(__GNUC__)
/* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to
* work, so if this *is* GCC, or G++, look for a version >4.5
*/
# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
# define PNG_ARM_NEON_IMPLEMENTATION 2
# endif /* no GNUC support */
# endif /* __GNUC__ */
# else /* !defined __ARM_NEON__ */
/* The 'intrinsics' code simply won't compile without this -mfpu=neon:
*/
# if !defined(__aarch64__) && !defined(_M_ARM64)
/* The assembler code currently does not work on ARM64 */
# define PNG_ARM_NEON_IMPLEMENTATION 2
# endif /* __aarch64__ */
# endif /* __ARM_NEON__ */
# endif /* !PNG_ARM_NEON_IMPLEMENTATION */
# ifndef PNG_ARM_NEON_IMPLEMENTATION
/* Use the intrinsics code by default. */
# define PNG_ARM_NEON_IMPLEMENTATION 1
@@ -876,6 +834,7 @@
#define png_PLTE PNG_U32( 80, 76, 84, 69)
#define png_bKGD PNG_U32( 98, 75, 71, 68)
#define png_cHRM PNG_U32( 99, 72, 82, 77)
#define png_cICP PNG_U32( 99, 73, 67, 80)
#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */
#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */
#define png_gAMA PNG_U32(103, 65, 77, 65)
@@ -1172,6 +1131,12 @@ PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr,
/* The xy value must have been previously validated */
#endif
#ifdef PNG_WRITE_cICP_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr,
png_byte colour_primaries, png_byte transfer_function,
png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY);
#endif
#ifdef PNG_WRITE_sRGB_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,
int intent),PNG_EMPTY);
@@ -1515,6 +1480,11 @@ PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
#endif
#ifdef PNG_READ_cICP_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_handle_cICP,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
#endif
#ifdef PNG_READ_eXIf_SUPPORTED
PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr,
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
+11 -2
View File
@@ -1,7 +1,6 @@
/* pngread.c - read a PNG file
*
* Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -175,6 +174,11 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_cICP_SUPPORTED
else if (chunk_name == png_cICP)
png_handle_cICP(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_eXIf_SUPPORTED
else if (chunk_name == png_eXIf)
png_handle_eXIf(png_ptr, info_ptr, length);
@@ -852,6 +856,11 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_cICP_SUPPORTED
else if (chunk_name == png_cICP)
png_handle_cICP(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_eXIf_SUPPORTED
else if (chunk_name == png_eXIf)
png_handle_eXIf(png_ptr, info_ptr, length);
-1
View File
@@ -1,4 +1,3 @@
/* pngrio.c - functions for data input
*
* Copyright (c) 2018 Cosmin Truta
-1
View File
@@ -1,4 +1,3 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
* Copyright (c) 2018-2024 Cosmin Truta
+56 -33
View File
@@ -1,4 +1,3 @@
/* pngrutil.c - utilities to read a PNG file
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -18,6 +17,21 @@
#ifdef PNG_READ_SUPPORTED
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
/* TODO: Move these arrays to a common utility module to avoid duplication. */
#endif
png_uint_32 PNGAPI
png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
{
@@ -2032,6 +2046,47 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
#endif
#ifdef PNG_READ_cICP_SUPPORTED
void /* PRIVATE */
png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[4];
png_debug(1, "in png_handle_cICP");
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
png_chunk_error(png_ptr, "missing IHDR");
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cICP) != 0)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
else if (length != 4)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 4);
if (png_crc_finish(png_ptr, 0) != 0)
return;
png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]);
}
#endif
#ifdef PNG_READ_eXIf_SUPPORTED
void /* PRIVATE */
png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
@@ -3684,10 +3739,6 @@ void /* PRIVATE */
png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
png_uint_32 transformations /* Because these may affect the byte layout */)
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Offset to next interlace block */
static const unsigned int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
png_debug(1, "in png_do_read_interlace");
if (row != NULL && row_info != NULL)
{
@@ -4325,20 +4376,6 @@ png_read_finish_IDAT(png_structrp png_ptr)
void /* PRIVATE */
png_read_finish_row(png_structrp png_ptr)
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
png_debug(1, "in png_read_finish_row");
png_ptr->row_number++;
if (png_ptr->row_number < png_ptr->num_rows)
@@ -4390,20 +4427,6 @@ png_read_finish_row(png_structrp png_ptr)
void /* PRIVATE */
png_read_start_row(png_structrp png_ptr)
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
unsigned int max_pixel_depth;
size_t row_bytes;
+28 -2
View File
@@ -1,7 +1,6 @@
/* pngset.c - storage of image information into info struct
*
* Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -134,6 +133,32 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
#endif /* cHRM */
#ifdef PNG_cICP_SUPPORTED
void PNGAPI
png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr,
png_byte colour_primaries, png_byte transfer_function,
png_byte matrix_coefficients, png_byte video_full_range_flag)
{
png_debug1(1, "in %s storage function", "cICP");
if (png_ptr == NULL || info_ptr == NULL)
return;
info_ptr->cicp_colour_primaries = colour_primaries;
info_ptr->cicp_transfer_function = transfer_function;
info_ptr->cicp_matrix_coefficients = matrix_coefficients;
info_ptr->cicp_video_full_range_flag = video_full_range_flag;
if (info_ptr->cicp_matrix_coefficients != 0)
{
png_warning(png_ptr, "Invalid cICP matrix coefficients");
return;
}
info_ptr->valid |= PNG_INFO_cICP;
}
#endif /* cICP */
#ifdef PNG_eXIf_SUPPORTED
void PNGAPI
png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
@@ -1395,6 +1420,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
static const png_byte chunks_to_ignore[] = {
98, 75, 71, 68, '\0', /* bKGD */
99, 72, 82, 77, '\0', /* cHRM */
99, 73, 67, 80, '\0', /* cICP */
101, 88, 73, 102, '\0', /* eXIf */
103, 65, 77, 65, '\0', /* gAMA */
104, 73, 83, 84, '\0', /* hIST */
-1
View File
@@ -1,4 +1,3 @@
/* pngstruct.h - header file for PNG reference library
*
* Copyright (c) 2018-2022 Cosmin Truta
-1
View File
@@ -1,4 +1,3 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
* Copyright (c) 2018-2024 Cosmin Truta
-1
View File
@@ -1,4 +1,3 @@
/* pngwio.c - functions for data output
*
* Copyright (c) 2018 Cosmin Truta
+58 -27
View File
@@ -1,7 +1,6 @@
/* pngwrite.c - general routines to write a PNG file
*
* Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -128,29 +127,61 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
* the application continues writing the PNG. So check the 'invalid'
* flag here too.
*/
#ifdef PNG_GAMMA_SUPPORTED
# ifdef PNG_WRITE_gAMA_SUPPORTED
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&
(info_ptr->valid & PNG_INFO_gAMA) != 0)
png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
# endif
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
/* Write unknown chunks first; PNG v3 establishes a precedence order
* for colourspace chunks. It is certain therefore that new
* colourspace chunks will have a precedence and very likely it will be
* higher than all known so far. Writing the unknown chunks here is
* most likely to present the chunks in the most convenient order.
*
* FUTURE: maybe write chunks in the order the app calls png_set_chnk
* to give the app control.
*/
write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
#endif
#ifdef PNG_WRITE_sBIT_SUPPORTED
/* PNG v3: a streaming app will need to see this before cICP because
* the information is helpful in handling HLG encoding (which is
* natively 10 bits but gets expanded to 16 in PNG.)
*
* The app shouldn't care about the order ideally, but it might have
* no choice. In PNG v3, apps are allowed to reject PNGs where the
* APNG chunks are out of order so it behooves libpng to be nice here.
*/
if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
#endif
/* PNG v3: the July 2004 version of the TR introduced the concept of colour
* space priority. As above it therefore behooves libpng to write the colour
* space chunks in the priority order so that a streaming app need not buffer
* them.
*/
#ifdef PNG_COLORSPACE_SUPPORTED
/* Write only one of sRGB or an ICC profile. If a profile was supplied
* and it matches one of the known sRGB ones issue a warning.
# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */
if ((info_ptr->valid & PNG_INFO_cICP) != 0)
{
png_write_cICP(png_ptr,
info_ptr->cicp_colour_primaries,
info_ptr->cicp_transfer_function,
info_ptr->cicp_matrix_coefficients,
info_ptr->cicp_video_full_range_flag);
}
# endif
/* PNG v3 change: it is now permitted to write both sRGB and ICC profiles,
* however because the libpng code auto-generates an sRGB for the
* corresponding ICC profiles and because PNG v2 disallowed this we need
* to only write one.
*
* Remove the PNG v2 warning about writing an sRGB ICC profile as well
* because it's invalid with PNG v3.
*/
# ifdef PNG_WRITE_iCCP_SUPPORTED
# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->valid & PNG_INFO_iCCP) != 0)
{
# ifdef PNG_WRITE_sRGB_SUPPORTED
if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
png_app_warning(png_ptr,
"profile matches sRGB but writing iCCP instead");
# endif
png_write_iCCP(png_ptr, info_ptr->iccp_name,
info_ptr->iccp_profile);
}
@@ -159,20 +190,24 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
# endif
# endif
# ifdef PNG_WRITE_sRGB_SUPPORTED
# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->valid & PNG_INFO_sRGB) != 0)
png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
# endif /* WRITE_sRGB */
#endif /* COLORSPACE */
#ifdef PNG_WRITE_sBIT_SUPPORTED
if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
#ifdef PNG_GAMMA_SUPPORTED
# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&
(info_ptr->valid & PNG_INFO_gAMA) != 0)
png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
# endif
#endif
#ifdef PNG_COLORSPACE_SUPPORTED
# ifdef PNG_WRITE_cHRM_SUPPORTED
# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&
(info_ptr->valid & PNG_INFO_cHRM) != 0)
@@ -180,10 +215,6 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
# endif
#endif
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
#endif
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
}
}
-1
View File
@@ -1,4 +1,3 @@
/* pngwtran.c - transforms the data in a row for PNG writers
*
* Copyright (c) 2018 Cosmin Truta
+41 -41
View File
@@ -1,4 +1,3 @@
/* pngwutil.c - utilities to write a PNG file
*
* Copyright (c) 2018-2024 Cosmin Truta
@@ -9,12 +8,30 @@
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
* This file contains routines that are only called from within
* libpng itself during the course of writing an image.
*/
#include "pngpriv.h"
#ifdef PNG_WRITE_SUPPORTED
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
/* TODO: Move these arrays to a common utility module to avoid duplication. */
#endif
#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
/* Place a 32-bit number into a buffer in PNG byte order. We work
* with unsigned numbers for convenience, although one supported
@@ -1471,6 +1488,29 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
}
#endif
#ifdef PNG_WRITE_cICP_SUPPORTED
/* Write the cICP data */
void /* PRIVATE */
png_write_cICP(png_structrp png_ptr,
png_byte colour_primaries, png_byte transfer_function,
png_byte matrix_coefficients, png_byte video_full_range_flag)
{
png_byte buf[4];
png_debug(1, "in png_write_cICP");
png_write_chunk_header(png_ptr, png_cICP, 4);
buf[0] = colour_primaries;
buf[1] = transfer_function;
buf[2] = matrix_coefficients;
buf[3] = video_full_range_flag;
png_write_chunk_data(png_ptr, buf, 4);
png_write_chunk_end(png_ptr);
}
#endif
#ifdef PNG_WRITE_eXIf_SUPPORTED
/* Write the Exif data */
void /* PRIVATE */
@@ -1889,22 +1929,6 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
void /* PRIVATE */
png_write_start_row(png_structrp png_ptr)
{
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
#endif
png_alloc_size_t buf_size;
int usr_pixel_depth;
@@ -2004,22 +2028,6 @@ png_write_start_row(png_structrp png_ptr)
void /* PRIVATE */
png_write_finish_row(png_structrp png_ptr)
{
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */
static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
#endif
png_debug(1, "in png_write_finish_row");
/* Next row */
@@ -2095,14 +2103,6 @@ png_write_finish_row(png_structrp png_ptr)
void /* PRIVATE */
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
png_debug(1, "in png_do_write_interlace");
/* We don't have to do anything on the last pass (6) */
-1
View File
@@ -1,4 +1,3 @@
/* powerpc_init.c - POWERPC optimised filter functions
*
* Copyright (c) 2018 Cosmin Truta
-1
View File
@@ -1552,7 +1552,6 @@ if(WITH_FFMPEG OR HAVE_FFMPEG)
status(" avformat:" FFMPEG_libavformat_VERSION THEN "YES (${FFMPEG_libavformat_VERSION})" ELSE NO)
status(" avutil:" FFMPEG_libavutil_VERSION THEN "YES (${FFMPEG_libavutil_VERSION})" ELSE NO)
status(" swscale:" FFMPEG_libswscale_VERSION THEN "YES (${FFMPEG_libswscale_VERSION})" ELSE NO)
status(" avresample:" FFMPEG_libavresample_VERSION THEN "YES (${FFMPEG_libavresample_VERSION})" ELSE NO)
if(OPENCV_FFMPEG_ENABLE_LIBAVDEVICE)
status(" avdevice:" FFMPEG_libavdevice_VERSION THEN "YES (${FFMPEG_libavdevice_VERSION})" ELSE NO)
endif()
+1
View File
@@ -388,6 +388,7 @@ macro(ocv_nvcc_flags)
endif()
if(WIN32)
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler=/wd4505)
if (NOT (CUDA_VERSION VERSION_LESS "11.2"))
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcudafe --display_error_number --diag-suppress 1394,1388)
endif()
+20 -7
View File
@@ -1310,13 +1310,26 @@
title = {QR Factorization},
url = {https://www.seas.ucla.edu/~vandenbe/133A/lectures/qr.pdf}
}
@inproceedings{wang2016iros,
author = {John Wang and Edwin Olson},
title = {{AprilTag} 2: Efficient and robust fiducial detection},
booktitle = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent Robots and Systems {(IROS)}},
year = {2016},
month = {October},
url = {https://april.eecs.umich.edu/pdfs/wang2016iros.pdf}
@inproceedings{Viola01,
author = {Viola, Paul and Jones, Michael J.},
title = {Rapid object detection using a boosted cascade of simple features},
booktitle = {Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on},
year = {2001},
pages = {I--511},
volume = {1},
publisher = {IEEE},
url = {https://www.researchgate.net/publication/3940582_Rapid_Object_Detection_using_a_Boosted_Cascade_of_Simple_Features}
}
@article{Viola04,
author = {Viola, Paul and Jones, Michael J.},
title = {Robust real-time face detection},
journal = {International Journal of Computer Vision},
year = {2004},
volume = {57},
number = {2},
pages = {137--154},
publisher = {Kluwer Academic Publishers},
url = {https://www.face-rec.org/algorithms/Boosting-Ensemble/16981346.pdf}
}
@misc{Welch95,
author = {Welch, Greg and Bishop, Gary},
@@ -26,7 +26,7 @@ Other organizations and people maintain their own binary distributions of OpenCV
- System packages in popular Linux distributions (https://pkgs.org/search/?q=opencv)
- PyPI (https://pypi.org/search/?q=opencv)
- Conda (https://anaconda.org/search?q=opencv)
- Conan (https://github.com/conan-community/conan-opencv)
- Conan (https://conan.io/center/recipes/opencv)
- vcpkg (https://github.com/microsoft/vcpkg/tree/master/ports/opencv)
- NuGet (https://www.nuget.org/packages?q=opencv)
- Brew (https://formulae.brew.sh/formula/opencv)
@@ -0,0 +1,38 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_CUDA_CUDA_COMPAT_HPP
#define OPENCV_CUDA_CUDA_COMPAT_HPP
#include <cuda.h>
namespace cv { namespace cuda { namespace device { namespace compat
{
#if CUDA_VERSION >= 13000
using ulonglong4 = ::ulonglong4_16a;
using double4 = ::double4_16a;
__host__ __device__ __forceinline__
double4 make_double4(double x, double y, double z, double w)
{
return ::make_double4_16a(x, y, z, w);
}
#else
using ulonglong4 = ::ulonglong4;
using double4 = ::double4;
__host__ __device__ __forceinline__
double4 make_double4(double x, double y, double z, double w)
{
return ::make_double4(x, y, z, w);
}
#endif
using ulonglong4Compat = ulonglong4;
using double4Compat = double4;
__host__ __device__ __forceinline__
double4Compat make_double4_compat(double x, double y, double z, double w)
{
return make_double4(x, y, z, w);
}
}}}}
#endif // OPENCV_CUDA_CUDA_COMPAT_HPP
@@ -45,6 +45,7 @@
#include "vec_traits.hpp"
#include "saturate_cast.hpp"
#include "cuda_compat.hpp"
/** @file
* @deprecated Use @ref cudev instead.
@@ -54,6 +55,8 @@
namespace cv { namespace cuda { namespace device
{
using cv::cuda::device::compat::double4;
using cv::cuda::device::compat::make_double4;
// saturate_cast
@@ -44,6 +44,7 @@
#define OPENCV_CUDA_VEC_TRAITS_HPP
#include "common.hpp"
#include "cuda_compat.hpp"
/** @file
* @deprecated Use @ref cudev instead.
@@ -53,6 +54,9 @@
namespace cv { namespace cuda { namespace device
{
using cv::cuda::device::compat::double4;
using cv::cuda::device::compat::make_double4;
template<typename T, int N> struct TypeVec;
struct __align__(8) uchar8
+5 -3
View File
@@ -51,10 +51,12 @@
#include "opencv2/core/cuda.hpp"
#include "opencv2/cudev.hpp"
#include "opencv2/core/cuda/utility.hpp"
#include "opencv2/core/cuda/cuda_compat.hpp"
using namespace cv;
using namespace cv::cuda;
using namespace cv::cudev;
using cv::cuda::device::compat::double4Compat;
device::ThrustAllocator::~ThrustAllocator()
{
@@ -343,7 +345,7 @@ void cv::cuda::GpuMat::copyTo(OutputArray _dst, InputArray _mask, Stream& stream
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{copyWithMask<double>, copyWithMask<double2>, copyWithMask<double3>, copyWithMask<double4>}
{copyWithMask<double>, copyWithMask<double2>, copyWithMask<double3>, copyWithMask<double4Compat>}
};
if (mask.channels() == channels())
@@ -426,7 +428,7 @@ GpuMat& cv::cuda::GpuMat::setTo(Scalar value, Stream& stream)
{setToWithOutMask<short>,setToWithOutMask<short2>,setToWithOutMask<short3>,setToWithOutMask<short4>},
{setToWithOutMask<int>,setToWithOutMask<int2>,setToWithOutMask<int3>,setToWithOutMask<int4>},
{setToWithOutMask<float>,setToWithOutMask<float2>,setToWithOutMask<float3>,setToWithOutMask<float4>},
{setToWithOutMask<double>,setToWithOutMask<double2>,setToWithOutMask<double3>,setToWithOutMask<double4>}
{setToWithOutMask<double>,setToWithOutMask<double2>,setToWithOutMask<double3>,setToWithOutMask<double4Compat>}
};
funcs[depth()][channels() - 1](*this, value, stream);
@@ -457,7 +459,7 @@ GpuMat& cv::cuda::GpuMat::setTo(Scalar value, InputArray _mask, Stream& stream)
{setToWithMask<short>,setToWithMask<short2>,setToWithMask<short3>,setToWithMask<short4>},
{setToWithMask<int>,setToWithMask<int2>,setToWithMask<int3>,setToWithMask<int4>},
{setToWithMask<float>,setToWithMask<float2>,setToWithMask<float3>,setToWithMask<float4>},
{setToWithMask<double>,setToWithMask<double2>,setToWithMask<double3>,setToWithMask<double4>}
{setToWithMask<double>,setToWithMask<double2>,setToWithMask<double3>,setToWithMask<double4Compat>}
};
funcs[depth()][channels() - 1](*this, mask, value, stream);
+5
View File
@@ -3499,8 +3499,10 @@ struct Kernel::Impl
void addUMat(const UMat& m, bool dst)
{
// TSAN false positive: see #27638
CV_Assert(nu < MAX_ARRS && m.u && m.u->urefcount > 0);
u[nu] = m.u;
// TSAN false positive: see #27638
CV_XADD(&m.u->urefcount, 1);
nu++;
if(dst && m.u->tempUMat())
@@ -5651,6 +5653,7 @@ public:
if(!u)
return;
// Next two lines: TSAN false positive: see #27638
CV_Assert(u->urefcount == 0);
CV_Assert(u->refcount == 0 && "UMat deallocation error: some derived Mat is still alive");
@@ -6583,11 +6586,13 @@ public:
void flushCleanupQueue() const
{
// TSAN false positive: see #27638
if (!cleanupQueue.empty())
{
std::deque<UMatData*> q;
{
cv::AutoLock lock(cleanupQueueMutex);
// TSAN false positive: see #27638
q.swap(cleanupQueue);
}
for (std::deque<UMatData*>::const_iterator i = q.begin(); i != q.end(); ++i)
+4 -1
View File
@@ -11,6 +11,7 @@
#include "memory.hpp"
#include "../cuda4dnn/csl/pointer.hpp"
#include "opencv2/core/cuda/cuda_compat.hpp"
#include <type_traits>
@@ -34,9 +35,11 @@ namespace cv { namespace dnn { namespace cuda4dnn { namespace csl { namespace de
* v_store(output_vPtr, vec);
*/
using cv::cuda::device::compat::ulonglong4Compat;
namespace detail {
template <size_type N> struct raw_type_ { };
template <> struct raw_type_<256> { typedef ulonglong4 type; };
template <> struct raw_type_<256> { typedef ulonglong4Compat type; };
template <> struct raw_type_<128> { typedef uint4 type; };
template <> struct raw_type_<64> { typedef uint2 type; };
template <> struct raw_type_<32> { typedef uint1 type; };
+28 -28
View File
@@ -232,7 +232,7 @@ Mat Diagonal(const Mat& input, int dim1, int dim2)
}
}
// Permutate the input so that the dims from which we need the diagonal forms the innermost dims
// Permute the input so that the dims from which we need the diagonal form the innermost dims
Mat transposed = Transpose(input, input_dims, permutation);
// Parse the diagonal from the innermost dims
@@ -246,7 +246,7 @@ Mat Diagonal(const Mat& input, int dim1, int dim2)
reverse_permutation[perm] = iter++;
}
// Permutate using the reverse permutation to get back the original axes ordering
// Permute using the reverse permutation to get back the original axes ordering
// (Pass in CPU Transpose function here as this Diagonal method will only be used for CPU based diagonal parsing)
output = Transpose(output, shape(output), reverse_permutation);
} else {
@@ -299,19 +299,19 @@ public:
// Preprocessed inputs
std::vector<Mat> preProcessedInputs;
// This is container for preporcessed inputs
// This container holds preprocessed inputs
std::vector<MatShape> homogenizedInputDims;
// Collect outpus dimentions
MatShape einsumOutDims; // vector to store output dimentions
// Collect output dimensions
MatShape einsumOutDims; // vector to store output dimensions
// These hold equation subring, left hand side and right it of
// These hold equation substrings: the left-hand side, right-hand side, and the full equation
String lhs_eq, rhs_eq, equation;
// Holds token from left hand side of the equation
// Holds tokens from the left-hand side of the equation
std::vector<String> lhs_eq_tokens;
// Idicates if equation substring is defined in explit way such as "ij, jk->ik"
// Indicates if the equation substring is defined in an explicit way such as "ij, jk->ik"
// as opposed to "ij->"
bool explicitEquation = false;
@@ -330,14 +330,14 @@ public:
// A value of -1 means the corresponding subscript index is not found in the output
std::vector<int> subscriptIndicesToOutputIndices;
// Hold max number of alphabetic numbers
// Holds the max number of alphabetic characters
static const size_t numOfLetters = 52;
// Stores the count corresponding to each letter encountered
// A value of `0` indicates that the corresponding letter hasn't been seen at all
std::array<int, numOfLetters> letter2count;
// Hold the assigned index corresponding to the letter seen
// Holds the assigned index corresponding to the letter seen
// `-1` means the corresponding letter wasn't seen at all
std::array<int, numOfLetters> letter2index;
@@ -363,7 +363,7 @@ public:
void calculateOutputShape();
void preProcessInputs(InputArrayOfArrays& inputs);
Mat reduceSum(Mat& src, MatShape& reduceAxis);
Mat FinalizeOutput(const Mat& candidateOuput, const MatShape& ordered_subscript_indices_in_candidate);
Mat FinalizeOutput(const Mat& candidateOutput, const MatShape& ordered_subscript_indices_in_candidate);
Mat pairwiseOperandProcess(
const Mat& left,
const MatShape& leftShapeOverride,
@@ -410,8 +410,8 @@ public:
letter2count.fill(0);
letter2index.fill(-1);
// parser equation and extract tokens from the equation
// save token to lhs_eq_tokens variable
// parse equation and extract tokens from the equation
// save tokens to lhs_eq_tokens vector
parseEquation(equation); // TODO: return lhs_eq_tokens
}
@@ -420,7 +420,7 @@ public:
backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;
}
// getMeoryShapes
// getMemoryShapes
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
@@ -456,7 +456,7 @@ public:
{
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
CV_CheckEQ((size_t)inputs_arr.total(), (size_t)numInputs, "Number of inputs in forward and inputs during graph constructions do not match");
CV_CheckEQ((size_t)inputs_arr.total(), (size_t)numInputs, "Number of inputs in forward and inputs during graph construction do not match");
if (inputs_arr.depth() == CV_16F)
{
@@ -546,14 +546,14 @@ public:
}
}
// check of product of output dimentions and computed output dimentions match
// check that product of output dimensions and computed output dimensions match
size_t reqProd = std::accumulate(einsumOutDims.begin(), einsumOutDims.end(), 1, std::multiplies<int>());
MatShape realOutputDims = shape(result);
size_t realProd = std::accumulate(realOutputDims.begin(), realOutputDims.end(), 1, std::multiplies<int>());
CV_CheckEQ(reqProd, realProd, "Real output can not be shaped in to required output");
// reduce dimentions
// reduce dimensions
result = result.reshape(1, einsumOutDims.size(), einsumOutDims.data());
result.copyTo(outputs[0]);
} // forward
@@ -630,20 +630,20 @@ void LayerEinsumImpl::preProcessInputs(InputArrayOfArrays& inputs_arr)
// same axes order
MatShape homogenizedInputDims_(numLetterIndices, 1);
int dimIndexInIreprocessedInput = 0;
int dimIndexInPreprocessedInput = 0;
int dimIndexInOriginalInput = 0;
for (const auto& subscriptIndex : currSubscriptIndices)
{
if(subscriptIndicesToInputIndex[subscriptIndex] == -1){
subscriptIndicesToInputIndex[subscriptIndex] = dimIndexInIreprocessedInput++;
subscriptIndicesToInputIndex[subscriptIndex] = dimIndexInPreprocessedInput++;
homogenizedInputDims_[subscriptIndex] = input_dims[dimIndexInOriginalInput];
} else {
// Call diagonal
preprocessed = Diagonal(
!preprocessed.empty() ? preprocessed : inputs[inputIter],
subscriptIndicesToInputIndex[subscriptIndex],
dimIndexInIreprocessedInput);
dimIndexInPreprocessedInput);
}
++dimIndexInOriginalInput;
}
@@ -686,7 +686,7 @@ void LayerEinsumImpl::parseEquation(String equation)
std::size_t arrow_idx = equation.find("->");
if (arrow_idx != std::string::npos)
{
// split left and righ hand sides of the equation
// split left- and right-hand sides of the equation
lhs_eq = equation.substr(0, arrow_idx);
rhs_eq = equation.substr(arrow_idx + 2);
explicitEquation = true;
@@ -762,7 +762,7 @@ void LayerEinsumImpl::calculateOutputShape()
CV_CheckNE(letterIndex, -1,
"The only permissible subscript labels are lowercase letters (a-z) and uppercase letters (A-Z).");
CV_CheckEQ(outputLetterToCount[letterIndex], 0,
"Output subscript constains repeated letters");
"Output subscript contains repeated letters");
++outputLetterToCount[letterIndex];
auto mappedIndex = letter2index[letterIndex];
@@ -770,7 +770,7 @@ void LayerEinsumImpl::calculateOutputShape()
CV_CheckNE(mappedIndex, -1,
"Output subscript has letters that were not encountered in the inputs");
// Push output dimention
// Push output dimension
// Einsum layer only has one output vector
einsumOutDims.emplace_back(subscriptIndicesToDimValue[mappedIndex]);
@@ -797,7 +797,7 @@ void LayerEinsumImpl::validateOutputSubscript()
if(rhs_eq.find("...") == std::string::npos)
{
CV_Error(Error::StsError,
"Provided output subscript does not include ellipsis while Inputs subscrits constain ellipsis");
"Provided output subscript does not include ellipsis while input subscripts contain ellipsis");
}
}
}
@@ -1006,7 +1006,7 @@ void LayerEinsumImpl::processEquation(const std::vector<MatShape>& inputs)
CV_Error(Error::StsError, cv::format("Einsum operands can not be broadcasted."
"Check input shapes/equation passed."
"Input shape of operand [%d]", inputIdx) +
cv::format(" is incompatible in the dimention [%zu].", static_cast<size_t>(dim_count)));
cv::format(" is incompatible in the dimension [%zu].", static_cast<size_t>(dim_count)));
}
}
}
@@ -1113,7 +1113,7 @@ Mat LayerEinsumImpl::pairwiseOperandProcess(
Mat currentLeft;
Mat currentRight;
CV_CheckEQ(leftRank, rightRank, "Raks of pair-wise operands must be equal");
CV_CheckEQ(leftRank, rightRank, "Ranks of pair-wise operands must be equal");
// Following vectors hold:
// lro: dim indices that are present in left, right, and reduce_dims
@@ -1192,7 +1192,7 @@ Mat LayerEinsumImpl::pairwiseOperandProcess(
}
// Permutate the left operand so that the axes order go like this: [lro, lo, reduce_dims, ro]
// Permute the left operand so that the axes order go like this: [lro, lo, reduce_dims, ro]
MatShape reshaped_dims;
std::vector<size_t> left_permutation;
left_permutation.reserve(lro.size() + lo.size() + reduceDims.size() + ro.size());
@@ -1225,7 +1225,7 @@ Mat LayerEinsumImpl::pairwiseOperandProcess(
}
}
// Permutate the right operand so that the axes order go like this: [lro, reduce_dims, ro, lo]
// Permute the right operand so that the axes order go like this: [lro, reduce_dims, ro, lo]
std::vector<size_t> right_permutation;
right_permutation.reserve(lro.size() + lo.size() + reduceDims.size() + ro.size());
right_permutation.insert(right_permutation.end(), lro.begin(), lro.end());
@@ -54,12 +54,12 @@ public:
#define FLANN_THROW(TYPE, STR) throw FLANNException(STR)
//! @endcond
#else
#define FLANN_THROW(TYPE, STR) CV_Error(TYPE, STR)
#endif
//! @endcond
#endif /* OPENCV_FLANN_GENERAL_H_ */
@@ -119,6 +119,7 @@ enum ImwriteFlags {
IMWRITE_JPEGXL_EFFORT = 641,//!< For JPEG XL, encoder effort/speed level without affecting decoding speed; it is between 1 (fastest) and 10 (slowest). Default is 7.
IMWRITE_JPEGXL_DISTANCE = 642,//!< For JPEG XL, distance level for lossy compression: target max butteraugli distance, lower = higher quality, 0 = lossless; range: 0 .. 25. Default is 1.
IMWRITE_JPEGXL_DECODING_SPEED = 643,//!< For JPEG XL, decoding speed tier for the provided options; minimum is 0 (slowest to decode, best quality/density), and maximum is 4 (fastest to decode, at the cost of some quality/density). Default is 0.
IMWRITE_BMP_COMPRESSION = 768, //!< For BMP, use to specify compress parameter for 32bpp image. Default is IMWRITE_BMP_COMPRESSION_BITFIELDS. See cv::ImwriteBMPCompressionFlags.
IMWRITE_GIF_LOOP = 1024, //!< Not functional since 4.12.0. Replaced by cv::Animation::loop_count.
IMWRITE_GIF_SPEED = 1025, //!< Not functional since 4.12.0. Replaced by cv::Animation::durations.
IMWRITE_GIF_QUALITY = 1026, //!< For GIF, it can be a quality from 1 to 8. Default is 2. See cv::ImwriteGifCompressionFlags.
@@ -184,7 +185,7 @@ enum ImwriteTiffResolutionUnitFlags {
};
enum ImwriteEXRTypeFlags {
/*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */
// IMWRITE_EXR_TYPE_UNIT = 0, // not supported
IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16)
IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default)
};
@@ -245,6 +246,12 @@ enum ImwriteHDRCompressionFlags {
IMWRITE_HDR_COMPRESSION_RLE = 1
};
//! Imwrite BMP specific values for IMWRITE_BMP_COMPRESSION parameter key.
enum ImwriteBMPCompressionFlags {
IMWRITE_BMP_COMPRESSION_RGB = 0, //!< Use BI_RGB. OpenCV v4.12.0 or before supports to encode with this compression only.
IMWRITE_BMP_COMPRESSION_BITFIELDS = 3, //!< Use BI_BITFIELDS. OpenCV v4.13.0 or later can support to encode with this compression. (only for 32 BPP images)
};
//! Imwrite GIF specific values for IMWRITE_GIF_QUALITY parameter key, if larger than 3, then its related to the size of the color table.
enum ImwriteGIFCompressionFlags {
IMWRITE_GIF_FAST_NO_DITHER = 1,
@@ -264,8 +271,9 @@ enum ImageMetadataType
IMAGE_METADATA_EXIF = 0, // EXIF metadata (e.g., camera info, GPS, orientation)
IMAGE_METADATA_XMP = 1, // XMP metadata (eXtensible Metadata Platform - Adobe format)
IMAGE_METADATA_ICCP = 2, // ICC Profile (color profile for color management)
IMAGE_METADATA_CICP = 3, // cICP Profile (video signal type)
IMAGE_METADATA_MAX = 2 // Highest valid index (usually used for bounds checking)
IMAGE_METADATA_MAX = 3 // Highest valid index (usually used for bounds checking)
};
//! @} imgcodecs_flags
@@ -498,6 +506,11 @@ filename extension (see cv::imread for the list of extensions). In general, only
single-channel or 3-channel (with 'BGR' channel order) images
can be saved using this function, with these exceptions:
- With BMP encoder, 8-bit unsigned (CV_8U) images can be saved.
- BMP images with an alpha channel can be saved using this function.
To achieve this, create an 8-bit 4-channel (CV_8UC4) BGRA image, ensuring the alpha channel is the last component.
Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255.
OpenCV v4.13.0 or later use BI_BITFIELDS compression as default. See IMWRITE_BMP_COMPRESSION.
- With OpenEXR encoder, only 32-bit float (CV_32F) images can be saved. More than 4 channels can be saved. (imread can load it then.)
- 8-bit unsigned (CV_8U) images are not supported.
- With Radiance HDR encoder, non 64-bit float (CV_64F) images can be saved.
+57 -3
View File
@@ -42,6 +42,7 @@
#include "precomp.hpp"
#include "grfmt_bmp.hpp"
#include "opencv2/core/utils/logger.hpp"
namespace cv
{
@@ -603,6 +604,7 @@ BmpEncoder::BmpEncoder()
{
m_description = "Windows bitmap (*.bmp;*.dib)";
m_buf_supported = true;
m_supported_encode_key = {IMWRITE_BMP_COMPRESSION};
}
@@ -615,11 +617,12 @@ ImageEncoder BmpEncoder::newEncoder() const
return makePtr<BmpEncoder>();
}
bool BmpEncoder::write( const Mat& img, const std::vector<int>& )
bool BmpEncoder::write( const Mat& img, const std::vector<int>& params )
{
int width = img.cols, height = img.rows, channels = img.channels();
int fileStep = (width*channels + 3) & -4;
uchar zeropad[] = "\0\0\0\0";
WLByteStream strm;
if( m_buf )
@@ -630,7 +633,35 @@ bool BmpEncoder::write( const Mat& img, const std::vector<int>& )
else if( !strm.open( m_filename ))
return false;
int bitmapHeaderSize = 40;
// sRGB colorspace requires BITMAPV5HEADER.
// See https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv5header
bool useV5BitFields = true;
for(size_t i = 0 ; i < params.size(); i++)
{
const int value = params[i+1];
switch(params[i])
{
case IMWRITE_BMP_COMPRESSION:
{
switch(value) {
case IMWRITE_BMP_COMPRESSION_RGB:
useV5BitFields = false;
break;
case IMWRITE_BMP_COMPRESSION_BITFIELDS:
useV5BitFields = true;
break;
default:
useV5BitFields = true;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_BMP_COMPRESSION must be one of ImwriteBMPCompressionFlags. It is fallbacked to true", value));
break;
}
}
break;
}
}
useV5BitFields &= (channels == 4); // BMP_BITFIELDS requires 32 bit per pixel.
int bitmapHeaderSize = useV5BitFields ? 124 : 40;
int paletteSize = channels > 1 ? 0 : 1024;
int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
size_t fileSize = (size_t)fileStep*height + headerSize;
@@ -653,13 +684,36 @@ bool BmpEncoder::write( const Mat& img, const std::vector<int>& )
CHECK_WRITE(strm.putDWord( height ));
CHECK_WRITE(strm.putWord( 1 ));
CHECK_WRITE(strm.putWord( channels << 3 ));
CHECK_WRITE(strm.putDWord( BMP_RGB ));
CHECK_WRITE(strm.putDWord( useV5BitFields ? BMP_BITFIELDS : BMP_RGB ));
CHECK_WRITE(strm.putDWord( 0 ));
CHECK_WRITE(strm.putDWord( 0 ));
CHECK_WRITE(strm.putDWord( 0 ));
CHECK_WRITE(strm.putDWord( 0 ));
CHECK_WRITE(strm.putDWord( 0 ));
if( useV5BitFields )
{
CHECK_WRITE(strm.putDWord( 0x00FF0000 )); // bV5RedMask
CHECK_WRITE(strm.putDWord( 0x0000FF00 )); // bV5GreenMask
CHECK_WRITE(strm.putDWord( 0x000000FF )); // bV5BlueMask
CHECK_WRITE(strm.putDWord( 0xFF000000 )); // bV5AlphaMask
CHECK_WRITE(strm.putBytes( "BGRs", 4)); // bV5CSType (sRGB)
{ // bV5Endpoints
for(int index_rgb = 0; index_rgb < 3; index_rgb ++ ){ // Red/Green/Blue
CHECK_WRITE(strm.putDWord( 0 )); // ciexyzX
CHECK_WRITE(strm.putDWord( 0 )); // ciexyzY
CHECK_WRITE(strm.putDWord( 0 )); // ciexyzZ
}
}
CHECK_WRITE(strm.putDWord( 0 )); // bV5GammaRed
CHECK_WRITE(strm.putDWord( 0 )); // bV5GammaGreen
CHECK_WRITE(strm.putDWord( 0 )); // bV5GammaBlue
CHECK_WRITE(strm.putDWord( 0 )); // bV5Intent
CHECK_WRITE(strm.putDWord( 0 )); // bV5ProfileData
CHECK_WRITE(strm.putDWord( 0 )); // bV5ProfileSize
CHECK_WRITE(strm.putDWord( 0 )); // bV5Reserved
}
if( channels == 1 )
{
FillGrayPalette( palette, 8 );
+11
View File
@@ -901,6 +901,7 @@ PngEncoder::PngEncoder()
m_support_metadata[IMAGE_METADATA_EXIF] = true;
m_support_metadata[IMAGE_METADATA_XMP] = true;
m_support_metadata[IMAGE_METADATA_ICCP] = true;
m_support_metadata[IMAGE_METADATA_CICP] = true;
op_zstream1.zalloc = NULL;
op_zstream2.zalloc = NULL;
next_seq_num = 0;
@@ -1116,6 +1117,16 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
#endif
static_cast<png_uint_32>(iccp.size()));
}
std::vector<uchar>& cicp = m_metadata[IMAGE_METADATA_CICP];
if (!cicp.empty()) {
#ifdef PNG_cICP_SUPPORTED
CV_CheckEQ((size_t)4, cicp.size(), "The cICP chunk consists of four 1-byte unsigned integers");
png_set_cICP(png_ptr, info_ptr, cicp[0], cicp[1], cicp[2], cicp[3]);
#else
CV_LOG_WARNING(NULL, "Libpng is too old and does not support cICP.");
#endif
}
}
png_write_info( png_ptr, info_ptr );
+59 -1
View File
@@ -360,7 +360,16 @@ TEST(Imgcodecs_Bmp, read_32bit_rgb)
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_32bit_rgb.bmp";
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
Mat img;
ASSERT_NO_THROW(img = cv::imread(filenameInput));
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_8UC3, img.type());
ASSERT_NO_THROW(img = cv::imread(filenameInput, IMREAD_UNCHANGED));
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_8UC3, img.type());
ASSERT_NO_THROW(img = cv::imread(filenameInput, IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH));
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_8UC3, img.type());
}
@@ -427,6 +436,55 @@ TEST(Imgcodecs_Bmp, rgba_scale)
ASSERT_EQ(data[0], 255);
}
typedef testing::TestWithParam<ImwriteBMPCompressionFlags> Imgcodecs_bmp_compress;
TEST_P(Imgcodecs_bmp_compress, rgba32bpp)
{
const ImwriteBMPCompressionFlags comp = GetParam();
RNG rng = theRNG();
Mat src(256, 256, CV_8UC4);
rng.fill(src, RNG::UNIFORM, Scalar(0,0,0,0), Scalar(255,255,255,255));
vector<uint8_t> buf;
bool ret = false;
ASSERT_NO_THROW(ret = cv::imencode(".bmp", src, buf, {IMWRITE_BMP_COMPRESSION, static_cast<int>(comp)}));
ASSERT_TRUE(ret);
ASSERT_EQ(buf[0x0e], comp == IMWRITE_BMP_COMPRESSION_RGB ? 40 : 124 ); // the size of header
ASSERT_EQ(buf[0x0f], 0);
ASSERT_EQ(buf[0x1c], 32); // the number of bits per pixel = 32
ASSERT_EQ(buf[0x1d], 0);
ASSERT_EQ(buf[0x1e], static_cast<int>(comp)); // the compression method
ASSERT_EQ(buf[0x1f], 0);
ASSERT_EQ(buf[0x20], 0);
ASSERT_EQ(buf[0x21], 0);
Mat dst;
ASSERT_NO_THROW(dst = cv::imdecode(buf, IMREAD_UNCHANGED));
ASSERT_FALSE(dst.empty());
if(comp == IMWRITE_BMP_COMPRESSION_RGB)
{
// If BI_RGB is used, output BMP file stores RGB image.
ASSERT_EQ(CV_8UC3, dst.type());
Mat srcBGR;
cv::cvtColor(src, srcBGR, cv::COLOR_BGRA2BGR);
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), srcBGR, dst);
}
else
{
// If BI_BITFIELDS is used, output BMP file stores RGBA image.
ASSERT_EQ(CV_8UC4, dst.type());
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, dst);
}
}
INSTANTIATE_TEST_CASE_P(All,
Imgcodecs_bmp_compress,
testing::Values(
IMWRITE_BMP_COMPRESSION_RGB,
IMWRITE_BMP_COMPRESSION_BITFIELDS));
#ifdef HAVE_IMGCODEC_HDR
TEST(Imgcodecs_Hdr, regression)
{
+17
View File
@@ -80,6 +80,23 @@ void PrintTo(const ImreadModes& val, std::ostream* os)
*os << "IMREAD_UNKNOWN(" << (int)v << ")";
}
static inline
void PrintTo(const ImwriteBMPCompressionFlags& val, std::ostream* os)
{
switch(val)
{
case IMWRITE_BMP_COMPRESSION_RGB:
*os << "IMWRITE_BMP_COMPRESSION_RGB";
break;
case IMWRITE_BMP_COMPRESSION_BITFIELDS:
*os << "IMWRITE_BMP_COMPRESSION_BITFIELDS";
break;
default:
*os << "IMWRITE_BMP_COMPRESSION_UNKNOWN(" << (int)val << ")";
break;
}
}
} // namespace
#endif
@@ -410,7 +410,16 @@ static bool ipp_bilateralFilter(Mat &src, Mat &dst, int d, double sigmaColor, do
if(!ok)
return false;
parallel_for_(range, invoker, threads*4);
// Tile height can't be smaller than the radius.
// Otherwise, the second tile has mixed top border (pixels from both
// inmem and outside should be used), which is not supported in IPP.
int maxTiles = (int)iwDst.m_size.height / radius;
int numTiles = threads * 4;
if (numTiles > maxTiles) {
// Keep the tiles number as multiple of threads for the better workload balance.
numTiles = (maxTiles / threads) * threads;
}
parallel_for_(range, invoker, numTiles);
if(!ok)
return false;
+24 -35
View File
@@ -8,31 +8,22 @@
namespace opencv_test { namespace {
// return true if point lies inside ellipse
static bool check_pt_in_ellipse(const Point2f& pt, const RotatedRect& el) {
Point2f to_pt = pt - el.center;
double el_angle = el.angle * CV_PI / 180;
static double algebraic_dist(const Point2f& pt, const RotatedRect& el) {
const Point2d to_pt = pt - el.center;
const double el_angle = el.angle * CV_PI / 180;
const Point2d to_pt_el(
to_pt.x * cos(-el_angle) - to_pt.y * sin(-el_angle),
to_pt.x * sin(-el_angle) + to_pt.y * cos(-el_angle));
const double pt_angle = atan2(to_pt_el.y / el.size.height, to_pt_el.x / el.size.width);
const double x_dist = 0.5 * el.size.width * cos(pt_angle);
const double y_dist = 0.5 * el.size.height * sin(pt_angle);
double el_dist = sqrt(x_dist * x_dist + y_dist * y_dist);
return cv::norm(to_pt) < el_dist;
return normL2Sqr<double>(Point2d(2 * to_pt_el.x / el.size.width, 2 * to_pt_el.y / el.size.height)) - 1;
}
// Return true if mass center of fitted points lies inside ellipse
static bool fit_and_check_ellipse(const vector<Point2f>& pts) {
RotatedRect ellipse = fitEllipseDirect(pts); // fitEllipseAMS() also works fine
Point2f mass_center;
for (size_t i = 0; i < pts.size(); i++) {
mass_center += pts[i];
static double rms_algebraic_dist(const vector<Point2f>& pts, const RotatedRect& el) {
double sum_algebraic_dists_sqr = 0;
for (const auto& pt : pts) {
const auto pt_algebraic_dist = algebraic_dist(pt, el);
sum_algebraic_dists_sqr += pt_algebraic_dist * pt_algebraic_dist;
}
mass_center /= (float)pts.size();
return check_pt_in_ellipse(mass_center, ellipse);
return sqrt(sum_algebraic_dists_sqr / pts.size());
}
TEST(Imgproc_FitEllipse_Issue_4515, accuracy) {
@@ -50,7 +41,8 @@ TEST(Imgproc_FitEllipse_Issue_4515, accuracy) {
pts.push_back(Point2f(333, 319));
pts.push_back(Point2f(333, 320));
EXPECT_TRUE(fit_and_check_ellipse(pts));
const RotatedRect ellipse = fitEllipseDirect(pts); // fitEllipseAMS() also works fine
EXPECT_LT(rms_algebraic_dist(pts, ellipse), 1e-1);
}
TEST(Imgproc_FitEllipse_Issue_6544, accuracy) {
@@ -66,18 +58,17 @@ TEST(Imgproc_FitEllipse_Issue_6544, accuracy) {
pts.push_back(Point2f(929.145f, 744.976f));
pts.push_back(Point2f(917.474f, 791.823f));
EXPECT_TRUE(fit_and_check_ellipse(pts));
const RotatedRect ellipse = fitEllipseDirect(pts); // fitEllipseAMS() also works fine
EXPECT_LT(rms_algebraic_dist(pts, ellipse), 5e-2);
}
TEST(Imgproc_FitEllipse_Issue_10270, accuracy) {
vector<Point2f> pts;
float scale = 1;
Point2f shift(0, 0);
pts.push_back(Point2f(0, 1)*scale+shift);
pts.push_back(Point2f(0, 2)*scale+shift);
pts.push_back(Point2f(0, 3)*scale+shift);
pts.push_back(Point2f(2, 3)*scale+shift);
pts.push_back(Point2f(0, 4)*scale+shift);
pts.push_back(Point2f(0, 1));
pts.push_back(Point2f(0, 2));
pts.push_back(Point2f(0, 3));
pts.push_back(Point2f(2, 3));
pts.push_back(Point2f(0, 4));
// check that we get almost vertical ellipse centered around (1, 3)
RotatedRect e = fitEllipse(pts);
@@ -89,13 +80,11 @@ TEST(Imgproc_FitEllipse_Issue_10270, accuracy) {
TEST(Imgproc_FitEllipse_JavaCase, accuracy) {
vector<Point2f> pts;
float scale = 1;
Point2f shift(0, 0);
pts.push_back(Point2f(0, 0)*scale+shift);
pts.push_back(Point2f(1, 1)*scale+shift);
pts.push_back(Point2f(-1, 1)*scale+shift);
pts.push_back(Point2f(-1, -1)*scale+shift);
pts.push_back(Point2f(1, -1)*scale+shift);
pts.push_back(Point2f(0, 0));
pts.push_back(Point2f(1, 1));
pts.push_back(Point2f(-1, 1));
pts.push_back(Point2f(-1, -1));
pts.push_back(Point2f(1, -1));
// check that we get almost circle centered around (0, 0)
RotatedRect e = fitEllipse(pts);
+2 -1
View File
@@ -16,7 +16,8 @@
title = {{AprilTag} 2: Efficient and robust fiducial detection},
booktitle = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent Robots and Systems {(IROS)}},
year = {2016},
month = {October}
month = {October},
url = {https://april.eecs.umich.edu/pdfs/wang2016iros.pdf}
}
@mastersthesis{Xiangmin2015research,
+12 -4
View File
@@ -270,10 +270,12 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
const int sz2 = 4; // Scalar has 4 elements.
m = Mat::zeros(sz2, 1, CV_64F);
// Fill the Mat with array elements
bool filled = true;
const char *base_ptr = PyArray_BYTES(oarr);
for(int i = 0; i < sz; i++ )
for(int i = 0; i < sz && filled; i++ )
{
PyObject* oi = PyArray_GETITEM(oarr, base_ptr + step[0] * i);
PyObject* oi = PyArray_GETITEM(oarr, base_ptr + step[0] * i); // new object
if( PyInt_Check(oi) )
m.at<double>(i) = (double)PyInt_AsLong(oi);
else if( PyFloat_Check(oi) )
@@ -282,10 +284,16 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
{
failmsg("%s has some non-numerical elements", info.name);
m.release();
return false;
filled = false;
}
Py_DECREF(oi);
}
return true;
if(needcopy)
Py_DECREF(o);
return filled;
}
// handle degenerate case
@@ -188,7 +188,7 @@ public:
protected:
template<class Compensator>
void feed(const std::vector<Point> &corners, const std::vector<UMat> &images,
void feedWithStrategy(const std::vector<Point> &corners, const std::vector<UMat> &images,
const std::vector<std::pair<UMat,uchar> > &masks);
private:
@@ -460,7 +460,7 @@ void ChannelsCompensator::setMatGains(std::vector<Mat>& umv)
template<class Compensator>
void BlocksCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images,
void BlocksCompensator::feedWithStrategy(const std::vector<Point> &corners, const std::vector<UMat> &images,
const std::vector<std::pair<UMat,uchar> > &masks)
{
CV_Assert(corners.size() == images.size() && images.size() == masks.size());
@@ -605,13 +605,13 @@ void BlocksCompensator::setMatGains(std::vector<Mat>& umv)
void BlocksGainCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images,
const std::vector<std::pair<UMat,uchar> > &masks)
{
BlocksCompensator::feed<GainCompensator>(corners, images, masks);
BlocksCompensator::feedWithStrategy<GainCompensator>(corners, images, masks);
}
void BlocksChannelsCompensator::feed(const std::vector<Point> &corners, const std::vector<UMat> &images,
const std::vector<std::pair<UMat,uchar> > &masks)
{
BlocksCompensator::feed<ChannelsCompensator>(corners, images, masks);
BlocksCompensator::feedWithStrategy<ChannelsCompensator>(corners, images, masks);
}
@@ -27,11 +27,6 @@ set(_used_ffmpeg_libraries ${_required_ffmpeg_libraries})
if(NOT HAVE_FFMPEG AND PKG_CONFIG_FOUND)
ocv_check_modules(FFMPEG libavcodec libavformat libavutil libswscale)
if(FFMPEG_FOUND)
ocv_check_modules(FFMPEG_libavresample libavresample) # optional
if(FFMPEG_libavresample_FOUND)
list(APPEND FFMPEG_LIBRARIES ${FFMPEG_libavresample_LIBRARIES})
list(APPEND _used_ffmpeg_libraries libavresample)
endif()
if(OPENCV_FFMPEG_ENABLE_LIBAVDEVICE)
ocv_check_modules(FFMPEG_libavdevice libavdevice) # optional
if(FFMPEG_libavdevice_FOUND)
@@ -60,7 +55,6 @@ if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER)
set(_min_libavformat_version 54.20.4)
set(_min_libavutil_version 52.3.0)
set(_min_libswscale_version 2.1.1)
set(_min_libavresample_version 1.0.1)
set(_min_libavdevice_version 53.2.0)
foreach(ffmpeg_lib ${_used_ffmpeg_libraries})
if(FFMPEG_${ffmpeg_lib}_VERSION VERSION_LESS _min_${ffmpeg_lib}_version)
@@ -77,7 +71,6 @@ if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER)
unset(_min_libavformat_version)
unset(_min_libavutil_version)
unset(_min_libswscale_version)
unset(_min_libavresample_version)
unset(_min_libavdevice_version)
endif()
@@ -81,7 +81,7 @@ Use 3rd party drivers or cameras
Many industrial cameras or some video I/O devices don't provide standard driver interfaces
for the operating system. Thus you can't use VideoCapture or VideoWriter with these devices.
To get access to their devices, manufactures provide their own C++ API and library that you have to
To get access to their devices, manufacturers provide their own C++ API and library that you have to
include and link with your OpenCV application.
It is a common case that these libraries read/write images from/to a memory buffer. If so, it is possible to make a `Mat` header for memory buffer (user-allocated data) and process it
@@ -15,7 +15,6 @@ message(STATUS "FFMPEG_libavcodec_VERSION=${FFMPEG_libavcodec_VERSION}")
message(STATUS "FFMPEG_libavformat_VERSION=${FFMPEG_libavformat_VERSION}")
message(STATUS "FFMPEG_libavutil_VERSION=${FFMPEG_libavutil_VERSION}")
message(STATUS "FFMPEG_libswscale_VERSION=${FFMPEG_libswscale_VERSION}")
message(STATUS "FFMPEG_libavresample_VERSION=${FFMPEG_libavresample_VERSION}")
if(OPENCV_FFMPEG_ENABLE_LIBAVDEVICE)
message(STATUS "FFMPEG_libavdevice_VERSION=${FFMPEG_libavdevice_VERSION}")
endif()
+82 -14
View File
@@ -607,6 +607,7 @@ struct CvCapture_FFMPEG
int hw_device;
int use_opencl;
int extraDataIdx;
int requestedThreads;
};
void CvCapture_FFMPEG::init()
@@ -658,6 +659,7 @@ void CvCapture_FFMPEG::init()
hw_device = -1;
use_opencl = 0;
extraDataIdx = 1;
requestedThreads = cv::getNumberOfCPUs();
}
@@ -686,7 +688,7 @@ void CvCapture_FFMPEG::close()
{
#ifdef CV_FFMPEG_CODECPAR
// avcodec_close removed in FFmpeg release 8.0
# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(62, 11, 100))
# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(61, 9, 108))
avcodec_close( context );
# endif
#endif
@@ -993,13 +995,7 @@ inline void fill_codec_context(AVCodecContext * enc, AVDictionary * dict)
if (!enc->thread_count)
{
int nCpus = cv::getNumberOfCPUs();
int requestedThreads = std::min(nCpus, 16); // [OPENCV:FFMPEG:24] Application has requested XX threads. Using a thread count greater than 16 is not recommended.
std::string threads_option = utils::getConfigurationParameterString("OPENCV_FFMPEG_THREADS");
if (!threads_option.empty())
{
requestedThreads = atoi(threads_option.c_str());
}
enc->thread_count = requestedThreads;
enc->thread_count = std::min(nCpus, 16); // [OPENCV:FFMPEG:24] Application has requested XX threads. Using a thread count greater than 16 is not recommended.
}
AVDictionaryEntry* avdiscard_entry = av_dict_get(dict, "avdiscard", NULL, 0);
@@ -1120,7 +1116,7 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr<IStreamReader>& str
#endif
if (params.has(CAP_PROP_N_THREADS))
{
nThreads = params.get<int>(CAP_PROP_N_THREADS);
nThreads = requestedThreads = params.get<int>(CAP_PROP_N_THREADS);
}
if (params.warnUnusedParameters())
{
@@ -1129,6 +1125,15 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr<IStreamReader>& str
}
}
if (params.empty() || !params.has(CAP_PROP_N_THREADS))
{
std::string threads_option = utils::getConfigurationParameterString("OPENCV_FFMPEG_THREADS");
if (!threads_option.empty())
{
nThreads = requestedThreads = atoi(threads_option.c_str());
}
}
#if USE_AV_INTERRUPT_CALLBACK
/* interrupt callback */
interrupt_metadata.timeout_after_ms = open_timeout;
@@ -1719,7 +1724,17 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step,
if (!sw_picture || !sw_picture->data[0])
return false;
CV_LOG_DEBUG(NULL, "Input picture format: " << av_get_pix_fmt_name((AVPixelFormat)sw_picture->format));
#if LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(56, 72, 0)
const char* color_space_name = av_color_space_name(sw_picture->colorspace);
#else
const char* color_space_name = av_get_colorspace_name(sw_picture->colorspace);
#endif
CV_LOG_DEBUG(NULL, "Input picture format: " << av_get_pix_fmt_name((AVPixelFormat)sw_picture->format)
<< ", colorspace: " << color_space_name
<< ", range: " << av_color_range_name(sw_picture->color_range)
<< ", primaries: " << av_color_primaries_name(sw_picture->color_primaries)
<< ", transfer: " << av_color_transfer_name(sw_picture->color_trc)
);
const AVPixelFormat result_format = convertRGB ? AV_PIX_FMT_BGR24 : (AVPixelFormat)sw_picture->format;
switch (result_format)
{
@@ -1739,6 +1754,51 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step,
frame.height != video_st->CV_FFMPEG_CODEC_FIELD->height ||
frame.data == NULL )
{
#if LIBSWSCALE_BUILD >= CALC_FFMPEG_VERSION(6, 4, 100)
int buffer_width = video_st->CV_FFMPEG_CODEC_FIELD->width;
int buffer_height = video_st->CV_FFMPEG_CODEC_FIELD->height;
// Reproduce sws_getCachedContext but with threads option
int64_t src_h_chr_pos = -513, dst_h_chr_pos = -513,
src_v_chr_pos = -513, dst_v_chr_pos = -513;
if (img_convert_ctx)
{
av_opt_get_int(img_convert_ctx, "src_h_chr_pos", 0, &src_h_chr_pos);
av_opt_get_int(img_convert_ctx, "src_v_chr_pos", 0, &src_v_chr_pos);
av_opt_get_int(img_convert_ctx, "dst_h_chr_pos", 0, &dst_h_chr_pos);
av_opt_get_int(img_convert_ctx, "dst_v_chr_pos", 0, &dst_v_chr_pos);
sws_freeContext(img_convert_ctx);
img_convert_ctx = NULL;
}
img_convert_ctx = sws_alloc_context();
if (img_convert_ctx == NULL)
return false;//CV_Error(0, "Cannot initialize the conversion context!");
av_opt_set_int(img_convert_ctx, "sws_flags", SWS_BICUBIC, 0);
av_opt_set_int(img_convert_ctx, "threads", requestedThreads, 0);
if (swscale_version() < CALC_FFMPEG_VERSION(8, 12, 100))
{
av_opt_set_int(img_convert_ctx, "src_h_chr_pos", src_h_chr_pos, 0);
av_opt_set_int(img_convert_ctx, "src_v_chr_pos", src_v_chr_pos, 0);
av_opt_set_int(img_convert_ctx, "dst_h_chr_pos", dst_h_chr_pos, 0);
av_opt_set_int(img_convert_ctx, "dst_v_chr_pos", dst_v_chr_pos, 0);
av_opt_set_int(img_convert_ctx, "srcw", buffer_width, 0);
av_opt_set_int(img_convert_ctx, "srch", buffer_height, 0);
av_opt_set_int(img_convert_ctx, "dstw", buffer_width, 0);
av_opt_set_int(img_convert_ctx, "dsth", buffer_height, 0);
av_opt_set_pixel_fmt(img_convert_ctx, "src_format", (AVPixelFormat)sw_picture->format, 0);
av_opt_set_pixel_fmt(img_convert_ctx, "dst_format", result_format, 0);
av_opt_set_double(img_convert_ctx, "param0", SWS_PARAM_DEFAULT, 0);
av_opt_set_double(img_convert_ctx, "param1", SWS_PARAM_DEFAULT, 0);
if (sws_init_context(img_convert_ctx, NULL, NULL) < 0) {
sws_freeContext(img_convert_ctx);
img_convert_ctx = NULL;
}
}
#else
// Some sws_scale optimizations have some assumptions about alignment of data/step/width/height
// Also we use coded_width/height to workaround problem with legacy ffmpeg versions (like n0.8)
int buffer_width = context->coded_width, buffer_height = context->coded_height;
@@ -1752,6 +1812,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step,
SWS_BICUBIC,
NULL, NULL, NULL
);
#endif
if (img_convert_ctx == NULL)
return false;//CV_Error(0, "Cannot initialize the conversion context!");
@@ -1781,6 +1842,9 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step,
frame.step = rgb_picture.linesize[0];
}
#if LIBSWSCALE_BUILD >= CALC_FFMPEG_VERSION(6, 4, 100)
sws_scale_frame(img_convert_ctx, &rgb_picture, sw_picture);
#else
sws_scale(
img_convert_ctx,
sw_picture->data,
@@ -1789,6 +1853,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step,
rgb_picture.data,
rgb_picture.linesize
);
#endif
*data = frame.data;
*step = frame.step;
@@ -2009,7 +2074,7 @@ void CvCapture_FFMPEG::get_rotation_angle()
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(57, 68, 100)
const uint8_t *data = 0;
// av_stream_get_side_data removed in FFmpeg release 8.0
# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(62, 11, 100))
# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(61, 9, 108))
data = av_stream_get_side_data(video_st, AV_PKT_DATA_DISPLAYMATRIX, NULL);
# else
AVPacketSideData* sd = video_st->codecpar->coded_side_data;
@@ -2017,7 +2082,10 @@ void CvCapture_FFMPEG::get_rotation_angle()
if (sd && nb_sd > 0)
{
const AVPacketSideData* mtx = av_packet_side_data_get(sd, nb_sd, AV_PKT_DATA_DISPLAYMATRIX);
data = mtx->data;
if (mtx)
{
data = mtx->data;
}
}
# endif
if (data)
@@ -2519,9 +2587,9 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
if (!encode_video) {
CV_Assert(cn == 1 && ((width > 0 && height == 1) || (width == 1 && height > 0 && step == 1)));
const bool set_key_frame = key_frame ? key_frame : idr_period ? frame_idx % idr_period == 0 : 1;
bool ret = icv_av_encapsulate_video_FFMPEG(oc, video_st, context, (uint8_t*)data, width, frame_idx, pts_index, b_frame_dts_delay, set_key_frame);
int ret = icv_av_encapsulate_video_FFMPEG(oc, video_st, context, (uint8_t*)data, width, frame_idx, pts_index, b_frame_dts_delay, set_key_frame);
frame_idx++;
return ret;
return ret == 0;
}
// check parameters