diff --git a/3rdparty/libpng/CMakeLists.txt b/3rdparty/libpng/CMakeLists.txt index d05031b9f5..4749c67b18 100644 --- a/3rdparty/libpng/CMakeLists.txt +++ b/3rdparty/libpng/CMakeLists.txt @@ -55,8 +55,12 @@ if(TARGET_ARCH MATCHES "^(ARM|arm|aarch)") elseif(NOT PNG_ARM_NEON STREQUAL "off") list(APPEND lib_srcs arm/arm_init.c arm/filter_neon_intrinsics.c arm/palette_neon_intrinsics.c) if(NOT MSVC) - enable_language(ASM) - list(APPEND lib_srcs arm/filter_neon.S) + if(CMAKE_SYSTEM_NAME STREQUAL "QNX") + message(STATUS "Skipping arm/filter_neon.S on QNX") + else() + enable_language(ASM) + list(APPEND lib_srcs arm/filter_neon.S) + endif() endif() if(PNG_ARM_NEON STREQUAL "on") add_definitions(-DPNG_ARM_NEON_OPT=2) diff --git a/3rdparty/libtiff/CMakeLists.txt b/3rdparty/libtiff/CMakeLists.txt index b872ec4f48..95936f74eb 100644 --- a/3rdparty/libtiff/CMakeLists.txt +++ b/3rdparty/libtiff/CMakeLists.txt @@ -359,7 +359,7 @@ endif() set(LIBTIFF_MAJOR_VERSION "4") set(LIBTIFF_MINOR_VERSION "7") -set(LIBTIFF_MICRO_VERSION "0") +set(LIBTIFF_MICRO_VERSION "1") set(LIBTIFF_VERSION "${LIBTIFF_MAJOR_VERSION}.${LIBTIFF_MINOR_VERSION}.${LIBTIFF_MICRO_VERSION}") file(READ "RELEASE-DATE" LIBTIFF_RELEASE_DATE content) @@ -480,4 +480,4 @@ if(NOT BUILD_SHARED_LIBS) ocv_install_target(${TIFF_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev OPTIONAL) endif() -ocv_install_3rdparty_licenses(libtiff COPYRIGHT) +ocv_install_3rdparty_licenses(libtiff LICENSE.md) diff --git a/3rdparty/libtiff/COPYRIGHT b/3rdparty/libtiff/COPYRIGHT deleted file mode 100644 index 8282186151..0000000000 --- a/3rdparty/libtiff/COPYRIGHT +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 1988-1997 Sam Leffler -Copyright (c) 1991-1997 Silicon Graphics, Inc. - -Permission to use, copy, modify, distribute, and sell this software and -its documentation for any purpose is hereby granted without fee, provided -that (i) the above copyright notices and this permission notice appear in -all copies of the software and related documentation, and (ii) the names of -Sam Leffler and Silicon Graphics may not be used in any advertising or -publicity relating to the software without the specific, prior written -permission of Sam Leffler and Silicon Graphics. - -THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, -EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY -WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR -ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, -OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF -LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -OF THIS SOFTWARE. diff --git a/3rdparty/libtiff/ChangeLog b/3rdparty/libtiff/ChangeLog index a6ab18783c..9079ce34c7 100644 --- a/3rdparty/libtiff/ChangeLog +++ b/3rdparty/libtiff/ChangeLog @@ -1,3 +1,1282 @@ +2025-09-11 Even Rouault + + Merge branch 'raw2tiff-742' into 'master' + raw2tiff: close input file before exit; issue #742 + + See merge request libtiff/libtiff!761 + +2025-09-08 Lee Howard + + raw2tiff: close input file before exit; issue #742. + +2025-09-06 Even Rouault + + Merge branch 'doc_add_LZW_BSD_license_to_LICENSE_md_issue_431' into 'master' + Add BSD license for Lempel-Ziv & Welch compression (tif_lzw.c) to LICENSE.md + + Closes #431 + + See merge request libtiff/libtiff!760 + +2025-09-06 Even Rouault + + Merge branch 'formatting_issues' into 'master' + Fix formatting issues + + See merge request libtiff/libtiff!759 + +2025-09-05 Even Rouault + + Fix formatting issues. + +2025-09-05 Even Rouault + + Merge branch 'tiff2pdf-741' into 'master' + avoid null pointer dereference, tiff2pdf #741 + + See merge request libtiff/libtiff!758 + +2025-09-05 Lee Howard + + tiff2pdf: avoid null pointer dereference. + Fixes #741 + +2025-09-05 Even Rouault + + Merge branch 'tiffcrop-740' into 'master' + avoid buffer overflow in tiffcrop #740 + + See merge request libtiff/libtiff!757 + +2025-09-05 Lee Howard + + tiffcrop: avoid buffer overflow. + Fixes #740 + +2025-09-05 Even Rouault + + Merge branch 'tiffmedian-735' into 'master' + close tiffmedian input file - #735 + + See merge request libtiff/libtiff!756 + +2025-09-05 Lee Howard + + tiffmedian: close input file. + Fixes #735 + +2025-09-05 Even Rouault + + Merge branch 'tiffcrop-734' into 'master' + Tiffcrop 734 + + See merge request libtiff/libtiff!755 + +2025-09-05 Lee Howard + + tiffcrop: avoid nullptr dereference. + Fixes #734 + +2025-09-05 Even Rouault + + Merge branch 'tiffdither-733' into 'master' + avoid out-of-bounds read identified in #733 + + See merge request libtiff/libtiff!754 + +2025-09-05 Lee Howard + + tiffdither: avoid out-of-bounds read identified in #733. + +2025-09-05 Even Rouault + + Merge branch 'tiffcrop-721' into 'master' + fix double-free and memory leak exposed by issue #721 + + See merge request libtiff/libtiff!753 + +2025-09-05 Lee Howard + + tiffcrop: fix double-free and memory leak exposed by issue #721. + +2025-09-04 Su_Laus + + Add BSD license for Lempel-Ziv & Welch compression (tif_lzw.c) to LICENSE.md + Closes #431 + +2025-09-04 Even Rouault + + Merge branch 'fix_54_read_CCITT_FAX_group3_without_EOL' into 'master' + tif_fax3: For fax group 3 data if no EOL is detected, reading is retried without synchronisation for EOLs. + + Closes #54 + + LibTIFF can write (encode) faxes of group 3 1d without EOL, but cannot read (decode) such files. This function has been added. + + See merge request libtiff/libtiff!752 + +2025-09-04 Su Laus + + tif_fax3: For fax group 3 data if no EOL is detected, reading is retried without synchronisation for EOLs. + Closes #54 + + LibTIFF can write (encode) faxes of group 3 1d without EOL, but cannot read (decode) such files. This function has been added. + +2025-09-04 Even Rouault + + Merge branch 'no-public-fix' into 'master' + tiffio.h: fix compilation with LOGLUV_PUBLIC=0 + + See merge request libtiff/libtiff!748 + +2025-08-19 Even Rouault + + Merge branch 'doc_returnvalue_mapproc_issue_#12' into 'master' + doc: update TIFFOpen.rst with the return values of mapproc and unmapproc. + + Closes #12 + + See merge request libtiff/libtiff!749 + +2025-08-19 Even Rouault + + Merge branch 'tiffcp_preset_level' into 'master' + tiffcp: fix setting compression level for lossless codecs + + Closes #730 + + See merge request libtiff/libtiff!750 + +2025-08-19 Jan Musinsky + + tiffcp: fix setting compression level for lossless codecs. + Closes #730 + +2025-08-17 Su_Laus + + doc: update TIFFOpen.rst with the return values of mapproc and unmapproc. + Closes #12 + +2025-08-12 Tim Blechmann + + tiffio.h: fix compilation with LOGLUV_PUBLIC=0. + LOGLUV_PUBLIC can be used to compile some functions with hidden + visibility. + However this functionality was broken (in clang), as LOGLUV_PUBLIC was + defined to 1 if it wasn't defined, as the extern declarations were still + visible by the compiler leading to "static declaration follows + non-static declaration" errors. + Changing the header from #ifdef to #if fixes the issue. + +2025-08-11 Even Rouault + + Merge branch 'fix_728_729_tiffcmp_memory_leak' into 'master' + tiffcmp: fix memory leak when second file cannot be opened. fix #728, #729 + + Closes #728 and #729 + + See merge request libtiff/libtiff!747 + +2025-08-08 Su_Laus + + tiffcmp: fix memory leak when second file cannot be opened. + Closes #728, #729 + +2025-08-08 Even Rouault + + Merge branch 'fix-issue-720' into 'master' + add assert for TIFFReadCustomDirectory infoarray check + + See merge request libtiff/libtiff!744 + +2025-08-08 Even Rouault + + Merge branch 'fix_718_tiff2ps_defer_strile_load' into 'master' + tiff2ps: check return of TIFFGetFiled() to fix #718 + + Closes #718 + + See merge request libtiff/libtiff!746 + +2025-08-02 Su_Laus + + tiff2ps: check return of TIFFGetFiled() for TIFFTAG_STRIPBYTECOUNTS and TIFFTAG_TILEBYTECOUNTS to avoid NULL pointer dereference. + Closes #718 + +2025-07-29 lxy <854071997@qq.com> + + add assert for TIFFReadCustomDirectory infoarray check. + +2025-07-11 Even Rouault + + Merge branch 'tif_jpeg_12_bit_bug_JPEGDecodeRaw_fix_717' into 'master' + tif_jpeg: Fix bug in JPEGDecodeRaw() if JPEG_LIB_MK1_OR_12BIT is defined. + + Closes #717 + + See merge request libtiff/libtiff!743 + +2025-07-11 Su_Laus + + tif_jpeg: Fix bug in JPEGDecodeRaw() if JPEG_LIB_MK1_OR_12BIT is defined for 8/12bit dual mode, introduced in libjpeg-turbo 2.2, which was actually released as 3.0. + Closes #717 + +2025-07-10 Even Rouault + + Merge branch 'tiffdump_coverity_fix' into 'master' + tiffdump: Fix coverity scan issue CID 1373365 tainted divisor. + + See merge request libtiff/libtiff!742 + +2025-07-06 Su_Laus + + tiffdump: Fix coverity scan issue CID 1373365: Passing tainted expression *datamem to PrintData, which uses it as a divisor or modulus. + +2025-07-05 Even Rouault + + Merge branch 'tiffcrop_coverity_scan_update' into 'master' + tiffcrop: Fix coverity scan issue CID 1655232 + + See merge request libtiff/libtiff!741 + +2025-07-02 Su_Laus + + tiffcrop: Fix coverity scan issue CID 1655232: Uninitialized variables (UNINIT) Using uninitialized value "crop.selections". + +2025-07-02 Even Rouault + + Merge branch 'fix_716_tiffcrop_memory_leak_on_error_exit' into 'master' + tiffcrop: close files and release memory on error exit, fix #716 + + Closes #716 + + See merge request libtiff/libtiff!740 + +2025-06-27 Su_Laus + + Close open TIFF files and release allocated buffers in tiffcrop before exiting in case of error to avoid memory leaks. + +2025-06-26 Even Rouault + + Merge branch 'fix_714' into 'master' + JPEGEncodeRaw(): error out if a previous scanline failed to be written, to... + + Closes #714 + + See merge request libtiff/libtiff!739 + +2025-06-25 Even Rouault + + JPEGEncodeRaw(): error out if a previous scanline failed to be written, to avoid out-of-bounds access + Fixes #714 + +2025-06-25 Even Rouault + + Merge branch 'improve_TIFFReadRGBAImage' into 'master' + Improve TIFFReadRGBAImage and avoid buffer overflows. + + See merge request libtiff/libtiff!738 + +2025-06-25 Su Laus + + Improve TIFFReadRGBAImage and avoid buffer overflows. + * Raster width can now be larger than image width. + * Only image data are copied to raster buffer if tiles are padded. + * Avoid buffer overflow if col_offset \> 0. + * If row_offset \> 0 do not try to read after last row - avoiding warnings. + * Feature "col_offset" and "row_offset" now works as expected. + +2025-06-25 Even Rouault + + Merge branch 'thumbnail-715' into 'master' + Fix for thumbnail issue #715 + + See merge request libtiff/libtiff!737 + +2025-06-25 Lee Howard + + Fix for thumbnail issue #715. + +2025-06-25 Even Rouault + + Merge branch 'issue-711' into 'master' + Fix for issue #711 + + See merge request libtiff/libtiff!735 + +2025-06-25 Lee Howard + + TIFFUnlinkDirectory() and TIFFWriteDirectorySec(): clear tif_rawcp when clearing tif_rawdata + Fix for issue #711 + +2025-06-25 Even Rouault + + Merge branch 'tiff_itrunc_rand' into 'master' + tiff_itrunc(): don't use rand() to please Coverity Scan + + See merge request libtiff/libtiff!733 + +2025-06-12 Even Rouault + + tiff_itrunc(): don't use rand() to please Coverity Scan. + +2025-06-12 Even Rouault + + Merge branch 'tiff-static' into 'master' + Add build option tiff-static, fixes #709 + + Closes #709 + + See merge request libtiff/libtiff!731 + +2025-06-12 Demetrius flavious + + CMake: Add build option tiff-static, fixes #709. + +2025-06-11 Even Rouault + + Merge branch 'fix_704_TIFFReadRGBAImage_crash' into 'master' + tif_getimage.c: Fix buffer underflow crash for less raster rows at TIFFReadRGBAImageOriented() + + Closes #704 + + See merge request libtiff/libtiff!732 + +2025-06-11 Su Laus + + tif_getimage.c: Fix buffer underflow crash for less raster rows at TIFFReadRGBAImageOriented() + +2025-06-06 Even Rouault + + Merge branch 'coverity_fixes' into 'master' + tif_zip.c: changes to please Coverity Scan + + See merge request libtiff/libtiff!730 + +2025-06-06 Even Rouault + + tif_zip.c: changes to please Coverity Scan. + +2025-06-03 Even Rouault + + Merge branch 'mkg3states' into 'master' + Move mkg3states under libtiff/tools, fixes #708 + + Closes #708 + + See merge request libtiff/libtiff!728 + +2025-06-03 Even Rouault + + Merge branch 'fix_MSVC_warnings_in_some_tools' into 'master' + Fixing MSVC compiler warnings in some tools. + + See merge request libtiff/libtiff!729 + +2025-06-03 Su Laus + + Fixing MSVC compiler warnings in some tools. + +2025-05-27 Lior Lahav + + Move mkg3states under libtiff/tools, fixes #708. + +2025-05-25 Even Rouault + + Merge branch 'cmake3.10' into 'master' + Fixed: CMake 4.0 warning when minimum required version is < 3.10 + + See merge request libtiff/libtiff!726 + +2025-05-25 Even Rouault + + Merge branch 'fix_MSVC_warnings_in_some_test_progs' into 'master' + Fixing MSVC compiler warnings in some test programs. + + See merge request libtiff/libtiff!725 + +2025-05-25 Su Laus + + Fixing MSVC compiler warnings in some test programs. + +2025-05-25 Even Rouault + + Merge branch 'predict_speedup' into 'master' + tif_predict.c: speed-up decompression in some cases + + See merge request libtiff/libtiff!724 + +2025-05-25 Even Rouault + + Merge branch 'tiffmedian-707' into 'master' + Tiffmedian 707 + + See merge request libtiff/libtiff!727 + +2025-05-25 Lee Howard + + conflict resolution. + + Fix tiffmedian bug #707. + +2025-05-24 Lior Lahav + + Fixed: CMake 4.0 warning when minimum required version is < 3.10. + +2025-05-23 Even Rouault + + tif_predict.c: speed-up decompression in some cases. + - Predictor=2 on Byte datatype with some loop unrolling + - Predictor=3 on Float32 datatype with some loop unrolling and SSE2 in the interleaving phae + + Tested on: + - https://rockyweb.usgs.gov/vdelivery/Datasets/Staged/Elevation/1m/Projects/WA_FEMAHQ_2018_D18/TIFF/USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif + USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif: 10012x10012, single band, Float32, LZW-compressed, Predictor=3, 316 MiB + + - and hillshade_predict.tif: 10012x10012, single band, Byte, ZSTD-compressed, Predictor=2, 63 MiB + (result of gdaldem hillshade USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif hillshade_predict.tif -co COMPRESS=ZSTD -co PREDICTOR=2) + + master: + ``` + $ hyperfine --warmup 2 -- "gdal raster convert hillshade_predict.tif foo --of mem -q" + Benchmark #1: gdal raster convert hillshade_predict.tif foo --of mem -q + Time (mean ± σ): 512.1 ms ± 2.0 ms [User: 413.1 ms, System: 98.3 ms] + Range (min … max): 509.6 ms … 516.4 ms + + $ hyperfine --warmup 2 -- "gdal raster convert USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif foo --of mem" + Benchmark #1: gdal raster convert USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif foo --of mem + Time (mean ± σ): 2.126 s ± 0.027 s [User: 1.844 s, System: 0.280 s] + Range (min … max): 2.098 s … 2.194 s + ``` + + this PR: + ``` + $ hyperfine --warmup 2 -- "gdal raster convert hillshade_predict.tif foo --of mem" + Benchmark #1: gdal raster convert hillshade_predict.tif foo --of mem + Time (mean ± σ): 384.3 ms ± 1.9 ms [User: 285.1 ms, System: 98.3 ms] + Range (min … max): 381.6 ms … 387.4 ms + + $ hyperfine --warmup 2 -- "gdal raster convert USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif foo --of mem" + Benchmark #1: gdal raster convert USGS_1M_10_x56y512_WA_FEMAHQ_2018_D18.tif foo --of mem + Time (mean ± σ): 1.489 s ± 0.004 s [User: 1.201 s, System: 0.286 s] + Range (min … max): 1.484 s … 1.498 s + ``` + +2025-05-22 Even Rouault + + Merge branch 'tiffdither-703' into 'master' + Don't skip the first line of the input image. Addresses issue #703 + + Closes #703 + + See merge request libtiff/libtiff!723 + +2025-05-22 Lee Howard + + tiffdither/tiffmedian: Don't skip the first line of the input image. Addresses issue #703 + +2025-05-22 Even Rouault + + Merge branch 'fix_682_tiff2rgba_size_t_overflow' into 'master' + tiff2rgba: fix #682 buffer overflow + + Closes #682 + + See merge request libtiff/libtiff!722 + +2025-05-22 Even Rouault + + Merge branch 'fix_MSVC_warnings_in_addtiffo' into 'master' + Fixing MSVC compiler warnings in addtiffo. + + See merge request libtiff/libtiff!717 + +2025-05-22 Su Laus + + Fixing MSVC compiler warnings in addtiffo. + +2025-05-19 Lee Howard + + Don't skip the first line of the input image. Addresses issue #703. + +2025-05-17 Su_Laus + + tiff2rgba: fix some "a partial expression can generate an overflow before it is assigned to a broader type" warnings. + Closes #682 + +2025-05-11 Even Rouault + + Merge branch 'master' into 'master' + oss-fuzz: fix memory leak in fuzz target + + See merge request libtiff/libtiff!721 + +2025-05-11 Yuntong Zhang + + oss-fuzz: fix memory leak in fuzz target. + Fixes: https://issues.oss-fuzz.com/issues/385176300 + +2025-05-02 Even Rouault + + Merge branch 'spelling' into 'master' + Spelling fixes. + + See merge request libtiff/libtiff!720 + +2025-05-02 Kurt Schwehr + + Spelling fixes. + Most found with codespell version 2.4.1. + +2025-04-30 Even Rouault + + Merge branch 'configure-ac-syntax-ac-2-71' into 'master' + configure.ac: Syntax updates for Autoconf 2.71 + + See merge request libtiff/libtiff!719 + +2025-04-29 Bob Friesenhahn + + Merge branch 'defines' into 'master' + Move several defines into tif_config.h + + See merge request libtiff/libtiff!664 + +2025-04-29 Bob Friesenhahn + + Merge branch '672-simplify-and-soften-autogen-sh' into 'master' + Resolve "Build fails when https://git.savannah.gnu.org/ is down" + + Closes #672 + + See merge request libtiff/libtiff!718 + +2025-04-29 Bob Friesenhahn + + autogen.sh: Enable verbose wget. + + configure.ac: Syntax updates for Autoconf 2.71. + + autogen.sh: Re-implement based on autoreconf. Failure to update config.guess/config.sub does not return error. + +2025-04-19 Even Rouault + + Merge branch 'fix_698' into 'master' + LZWDecode(): avoid nullptr dereference when trying to read again after... + + Closes #698 + + See merge request libtiff/libtiff!716 + +2025-04-18 Even Rouault + + Merge branch 'fix-684' into 'master' + Fix for buffer underflow + + Closes #684 + + See merge request libtiff/libtiff!713 + +2025-04-18 Timothy Lyanguzov + + Fix for buffer underflow. + +2025-04-18 Even Rouault + + LZWDecode(): avoid nullptr dereference when trying to read again after end-of-information marker has been found with remaining output bytes (fixes #698) + +2025-04-18 Even Rouault + + Merge branch 'correct_not_HAVE_IEEEFP_issue_699' into 'master' + Correct passing arguments to TIFFCvtIEEEFloatToNative().. if HAVE_IEEEFP is not defined. + + See merge request libtiff/libtiff!715 + +2025-04-17 Su_Laus + + Correct passing arguments to TIFFCvtIEEEFloatToNative() and TIFFCvtIEEEDoubleToNative() if HAVE_IEEEFP is not defined. + See #699 + +2025-04-16 Even Rouault + + Merge branch 'integer_overflow_gtTileContig_issue_79' into 'master' + Update some integer overflow checks in tif_getimage.c + + Closes #79 + + See merge request libtiff/libtiff!711 + +2025-04-14 Su_Laus + + Update some integer overflow checks in tif_getimage.c. + Closes #79 + +2025-04-14 Even Rouault + + Merge branch 'fix_issue_5_write_buffer_overwriting_compression_with_prediction' into 'master' + tif_predict.c: Don’t overwrite input buffer of TIFFWriteScanline() if prediction. + + Closes #5 + + See merge request libtiff/libtiff!712 + +2025-04-13 Su_Laus + + tif_predict.c: Don’t overwrite input buffer of TIFFWriteScanline() if "prediction" is enabled. Use extra working buffer in PredictorEncodeRow(). + Closes #5 + +2025-04-11 Even Rouault + + Merge branch 'doc_remove_dead_awaresystems_link' into 'master' + doc: Remove dead links to no more existing Awaresystems web-site. + + See merge request libtiff/libtiff!705 + +2025-04-11 Even Rouault + + Merge branch 'notes_for_allocating_TIFFYCbCrToRGB_structure_issue_681' into 'master' + doc: Added hints for correct allocation of TIFFYCbCrtoRGB structure and its associated buffers. + + Closes #681 + + See merge request libtiff/libtiff!709 + +2025-04-11 Even Rouault + + Merge branch 'doc_add_multi_page_reference_issue_43' into 'master' + doc: Added chapter to "Using the TIFF Library" for multi page + + Closes #43 + + See merge request libtiff/libtiff!710 + +2025-04-10 Su_Laus + + doc: Added chapter to "Using the TIFF Library" with links to handling multi-page TIFF and custom directories. + Closes #43 + +2025-04-09 Su_Laus + + doc: Added hints for correct allocation of TIFFYCbCrtoRGB structure and its associated buffers. + Closes #681 + +2025-04-03 Su_Laus + + Replace some last links and remove last todos. + +2025-04-02 Even Rouault + + Merge branch 'CheckReachedCounters_static' into 'master' + tif_fax3.c: add missing static qualifier in front of CheckReachedCounters() (master only) + + See merge request libtiff/libtiff!708 + +2025-04-02 Even Rouault + + tif_fax3.c: add missing static qualifier in front of CheckReachedCounters() (master only) + +2025-04-01 Su_Laus + + References to codec libraries updated and missing codec compile defines (tiffconf.h) added. + +2025-04-01 Even Rouault + + Merge branch 'fix-676' into 'master' + Fix memory leak in _TIFFSetDefaultCompressionState + + Closes #676 + + See merge request libtiff/libtiff!707 + +2025-04-01 Timothy Lyanguzov + + Fix memory leak in _TIFFSetDefaultCompressionState. + `_TIFFSetDefaultCompressionState` does not clean up before setting default state + + follow up for !563 + fixes #676 + +2025-03-31 Even Rouault + + Merge branch 'tiffcp_integer_overflow_check_issue_546' into 'master' + tiffcp: Improve non-secure integer overflow check. Closes #546 + + Closes #546 + + See merge request libtiff/libtiff!698 + +2025-03-31 Su_Laus + + Improve non-secure integer overflow check (comparison of division result with multiplicant) at compiler optimisation in tiffcp, rgb2ycbcr and tiff2rgba. + Closes #546 + +2025-03-28 Even Rouault + + Merge branch 'zlib_solo' into 'master' + zip: Provide zlib allocation functions. + + See merge request libtiff/libtiff!706 + +2025-03-28 Even Rouault + + Merge branch 'fix_670_tif_fax3_EOL_error_count_reached' into 'master' + tif_fax3.c: error out after a number of times end-of-line or unexpected code words + + Closes #670 + + See merge request libtiff/libtiff!703 + +2025-03-28 Even Rouault + + Merge branch 'fix-test-tiffcrop-tiffcp-32bpp-None-jpeg-race' into 'master' + test: Fix race condition in {tiffcrop,tiffcp}-32bpp-None-jpeg.sh tests + + See merge request libtiff/libtiff!701 + +2025-03-28 Even Rouault + + Merge branch 'doc_update_TIFFSetWriteOffset' into 'master' + doc: Clarify TIFFSetWriteOffset() only sets offset for image data and not for IFD data. + + See merge request libtiff/libtiff!699 + +2025-03-28 Even Rouault + + Merge branch 'coverity_fixes_in_tools' into 'master' + Silence some Coverity Scan warnigs and mark already dismissed ones. + + See merge request libtiff/libtiff!696 + +2025-03-25 Nikolay Sivov + + zip: Provide zlib allocation functions. + Otherwise for zlib built with -DZ_SOLO inflating will fail. + +2025-03-23 Su_Laus + + Updating BigTIFF specification and some miscelaneous editions. + +2025-03-20 Su_Laus + + doc: Remove dead links to no more existing Awaresystems web-site. + +2025-03-19 Roger Leigh + + Merge branch 'bugfix/issue_674-export_tiffxx_cmake_target' into 'master' + Export tiffxx cmake target (issue #674) + + See merge request libtiff/libtiff!704 + +2025-03-18 Daniel Moreno + + Export tiffxx cmake target (issue #674) + +2025-03-04 Su_Laus + + tif_fax3.c: error out after a number of times end-of-line or unexpected bad code words have been reached. + Closes #670 + +2025-03-03 Bob Friesenhahn + + Merge branch 'fix_665_memory_leak' into 'master' + Fix memory leak of issue # 665 (td_stripbytecount_p and td_stripoffset_p in TIFFSetupStrips()) + + Closes #665 + + See merge request libtiff/libtiff!697 + +2025-03-03 Su Laus + + Fix memory leak of issue # 665 (td_stripbytecount_p and td_stripoffset_p in TIFFSetupStrips()) + +2025-02-26 Gabi Falk + + test: Fix race condition in {tiffcrop,tiffcp}-32bpp-None-jpeg.sh tests. + These tests used the same output path, which could cause failures + when run in parallel. These were the only tests with a conflicting + outfile= parameter. + + Link: https://bugs.gentoo.org/943020 + +2025-02-25 Bob Friesenhahn + + Merge branch 'doc_re_entrancy_and_thread_safety_see_667' into 'master' + doc: Update documentation on re-entrancy and thread safety. + + Closes #667 + + See merge request libtiff/libtiff!700 + +2025-02-25 Su Laus + + doc: Update documentation on re-entrancy and thread safety. + +2025-02-23 Su_Laus + + doc/functions/TIFFWriteDirectory.rst: Clarify TIFFSetWriteOffset() only sets offset for image data and not for IFD data. + +2025-02-16 Su_Laus + + Silence some Coverity Scan warnigs and mark already dismissed ones. Guard all code related to CHUNKY_STRIP_READ_SUPPORT. + +2025-02-11 Even Rouault + + Merge branch 'doc_remove_deprecated_type_definitions' into 'master' + doc: Update the documentation to reflect deprecated typedefs + + See merge request libtiff/libtiff!694 + +2025-02-11 Su Laus + + doc: Update the documentation to reflect deprecated typedefs. + +2025-02-09 Su_Laus + + Silence some Coverity Scan warnigs and mark already dismissed ones. + +2025-01-30 Su Laus + + Merge branch 'patch-1' into 'master' + Doc: Fix return type of TIFFReadEncodedTile() + + See merge request libtiff/libtiff!693 + +2025-01-25 Mark Riehm + + Doc: Fix return type of TIFFReadEncodedTile() + +2025-01-14 Even Rouault + + Merge branch 'coverity_1638738' into 'master' + TIFFSetSubDirectory(): check _TIFFCheckDirNumberAndOffset() return + + See merge request libtiff/libtiff!692 + +2025-01-12 Even Rouault + + TIFFSetSubDirectory(): check _TIFFCheckDirNumberAndOffset() return. + Fix Coverity Scan: + ``` + CID 1638738: Error handling issues (CHECKED_RETURN) + Calling "_TIFFCheckDirNumberAndOffset" without checking return value (as is done elsewhere 4 out of 5 times). + ``` + +2025-01-12 Even Rouault + + Merge branch 'remove_get_field_type_from_structure' into 'master' + Remove get_field_type form TIFFField structure because it is not used anymore + + See merge request libtiff/libtiff!691 + +2025-01-09 Su_Laus + + Remove get_field_type form TIFFField structure because it is not used anymore and rename other parameter to set_get_field_type. + +2025-01-06 Even Rouault + + Merge branch 'doc_update_adding_new_tags_fix_642' into 'master' + doc: Update "Defining New TIFF Tags" description. See also #642. + + Closes #642 + + See merge request libtiff/libtiff!655 + +2025-01-06 Su Laus + + doc: Update "Defining New TIFF Tags" description. See also #642. + +2025-01-01 Even Rouault + + Merge branch 'fax_encode_sample_per_pixel_warning' into 'master' + tif_fax3.c: Error out for CCITT fax encoding if SamplesPerPixel is not equal 1 and PlanarConfiguration = Contiguous + + Closes #26 + + See merge request libtiff/libtiff!687 + +2025-01-01 Su Laus + + tif_fax3.c: Error out for CCITT fax encoding if SamplesPerPixel is not equal 1 and PlanarConfiguration = Contiguous + +2024-12-31 Even Rouault + + Merge branch 'fix_663' into 'master' + _TIFFVSetField(): fix potential use of unallocated memory (out-of-bounds read... + + Closes #663 + + See merge request libtiff/libtiff!689 + +2024-12-30 Even Rouault + + _TIFFVSetField(): fix potential use of unallocated memory (out-of-bounds read / nullptr dereference) in case of out-of-memory situation when dealing with custom tags + Fixes #663 + +2024-12-30 Even Rouault + + Merge branch 'master' into 'master' + Improved oss-fuzz fuzzer tiff_read_rgba_fuzzer.cc + + See merge request libtiff/libtiff!688 + +2024-12-30 Fabio Gritti + + Improved oss-fuzz fuzzer tiff_read_rgba_fuzzer.cc. + +2024-12-30 Even Rouault + + Merge branch 'LINKER_LANGUAGE' into 'master' + Set LINKER_LANGUAGE for C targets with C++ deps + + See merge request libtiff/libtiff!685 + +2024-12-30 Even Rouault + + Merge branch 'merge_multiple_functions_implemented_twice_#154' into 'master' + Merge several functions implemented twice in different modules, see #154 + + Closes #154 + + See merge request libtiff/libtiff!681 + +2024-12-30 Su Laus + + Merge several functions implemented twice in different modules, see #154 + +2024-12-19 Alyssa Ross + + Set LINKER_LANGUAGE for C targets with C++ deps. + When C and C++ code are being linked together, a C++ compiler has to + be used. In my experience, this doesn't always cause problems, but it + tends to when doing static builds. + + Without this change, I got build failures when I had lerc enabled: + + cd /build/source/build/tools && /nix/store/6941y72hx1k8rxiygm4iin16i4zhcdqr-cmake-3.30.5/bin/cmake -E cmake_link_script CMakeFiles/fax2ps.dir/link.txt --verbose=1 + /nix/store/gb7zjcg4fh1mnd5qp4pkrlib55w6j42l-aarch64-unknown-linux-musl-gcc-wrapper-13.3.0/bin/aarch64-unknown-linux-musl-gcc -Wall -Winline -Wformat-security -Wpointer-arith -Wdisabled-optimization -Wno-unknown-pragmas -fstrict-aliasing -O3 -DNDEBUG CMakeFiles/fax2ps.dir/fax2ps.c.o -o fax2ps ../libtiff/libtiff.a -Wl,-Bdynamic /nix/store/n49vspyhaga9pabpqqcwm9rlam7r4152-zlib-static-aarch64-unknown-linux-musl-1.3.1/lib/libz.a /nix/store/k71jx85iin8bvgqs1viq263qp186nb9h-libdeflate-static-aarch64-unknown-linux-musl-1.22/lib/libdeflate.a /nix/store/kp6hkjfjdmd94crz6claldi5hg9z8r87-libjpeg-turbo-static-aarch64-unknown-linux-musl-3.0.4/lib/libjpeg.a /nix/store/h2f1h8bri9d0mvdrvn5ad94hy31dan2s-lerc-static-aarch64-unknown-linux-musl-4.0.0/lib/libLerc.a /nix/store/hjf3h5prgfdadv3wsj4172sdxrnycgba-xz-static-aarch64-unknown-linux-musl-5.6.3/lib/liblzma.a /nix/store/qh8h4fdsvhj75xliiqb71qrynnng51p2-zstd-static-aarch64-unknown-linux-musl-1.5.6/lib/libzstd.a /nix/store/002ykljzr16pfxnijq7x8hr4nbicg745-libwebp-static-aarch64-unknown-linux-musl-1.4.0/lib/libwebp.a /nix/store/002ykljzr16pfxnijq7x8hr4nbicg745-libwebp-static-aarch64-unknown-linux-musl-1.4.0/lib/libsharpyuv.a /nix/store/dnm541qbzfanx6r0kqbc2p4xfjiwl4sf-musl-static-aarch64-unknown-linux-musl-1.2.5/lib/libm.a -Wl,-Bstatic + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: /nix/store/h2f1h8bri9d0mvdrvn5ad94hy31dan2s-lerc-static-aarch64-unknown-linux-musl-4.0.0/lib/libLerc.a(Lerc.cpp.o): in function `std::vector >::operator=(std::vector > const&) [clone .isra.0]': + (.text+0x140): undefined reference to `operator new(unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: (.text+0x16c): undefined reference to `operator delete(void*, unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: (.text+0x26c): undefined reference to `std::__throw_bad_alloc()' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: /nix/store/h2f1h8bri9d0mvdrvn5ad94hy31dan2s-lerc-static-aarch64-unknown-linux-musl-4.0.0/lib/libLerc.a(Lerc.cpp.o): in function `LercNS::Lerc::GetRanges(unsigned char const*, unsigned int, int, LercNS::Lerc2::HeaderInfo const&, double*, double*, unsigned long)': + (.text+0x10a0): undefined reference to `operator delete(void*, unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: (.text+0x10b4): undefined reference to `operator delete(void*, unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: (.text+0x10c8): undefined reference to `operator delete(void*, unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: (.text+0x10ec): undefined reference to `operator delete(void*, unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: (.text+0x1100): undefined reference to `operator delete(void*, unsigned long)' + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: /nix/store/h2f1h8bri9d0mvdrvn5ad94hy31dan2s-lerc-static-aarch64-unknown-linux-musl-4.0.0/lib/libLerc.a(Lerc.cpp.o):(.text+0x1114): more undefined references to `operator delete(void*, unsigned long)' follow + /nix/store/ncvpwrpay6vvh9wwc6fq28lb9hip7chc-aarch64-unknown-linux-musl-binutils-2.43.1/bin/aarch64-unknown-linux-musl-ld: /nix/store/h2f1h8bri9d0mvdrvn5ad94hy31dan2s-lerc-static-aarch64-unknown-linux-musl-4.0.0/lib/libLerc.a(Lerc.cpp.o): in function `bool LercNS::Lerc::Convert(LercNS::CntZImage const&, signed char*, unsigned char*, bool)': + [1808 more lines of this ommitted] + collect2: error: ld returned 1 exit status + +2024-12-17 Even Rouault + + Merge branch 'read_only' into 'master' + Take into account PACKBITS_READ_ONLY, LZW_READ_ONLY, and LERC_READ_ONLY macros + + See merge request libtiff/libtiff!683 + +2024-12-17 Even Rouault + + Merge branch 'libtiff_predictor_3_inverted_endianness_write_fix' into 'master' + fix writing a Predictor=3 file with non-native endianness + + See merge request libtiff/libtiff!684 + +2024-12-17 Even Rouault + + fix writing a Predictor=3 file with non-native endianness. + + Take into account PACKBITS_READ_ONLY, LZW_READ_ONLY, and LERC_READ_ONLY macros + to disable compiling write-support for those codecs. + Also add missing casts in LERC codec. + +2024-12-16 Even Rouault + + Merge branch 'tif_lzw_packbits_null' into 'master' + tif_lzw.c / tif_packbits.c: use NULL instead of 0 + + See merge request libtiff/libtiff!682 + +2024-12-16 Even Rouault + + tif_lzw.c / tif_packbits.c: use NULL instead of 0. + +2024-12-09 Even Rouault + + Merge branch 'manpage_TIFFRGBAImage_#67_different_output_unassociated_alpha' into 'master' + manpage: doc/functions/TIFFRGBAImage.rst note added about un-associated alpha handling + + Closes #67 + + See merge request libtiff/libtiff!679 + +2024-12-09 Su Laus + + manpage: doc/functions/TIFFRGBAImage.rst note added about un-associated alpha handling + +2024-12-09 Even Rouault + + Merge branch 'tiff2pdf_division_by_zero_#654' into 'master' + tiff2pdf: check h_samp and v_samp for range 1 to 4 to avoid division by zero. + + Closes #654 + + See merge request libtiff/libtiff!680 + +2024-12-07 Su_Laus + + tiff2pdf: check h_samp and v_samp for range 1 to 4 to avoid division by zero. + Closes #654 + +2024-12-05 Even Rouault + + Merge branch 'master' into 'master' + CMake CMP0074 new policy. + + See merge request libtiff/libtiff!678 + +2024-12-04 榆柳松 + + CMake CMP0074 new policy. + +2024-12-04 Even Rouault + + Merge branch 'manpage_TIFFReadRGBAImage_orientation_fault' into 'master' + doc: TIFFReadRGBAImage.rst note about incorrect saving in raster for some TIFF orientations (5 to 8). + + Closes #76 and #77 + + See merge request libtiff/libtiff!675 + +2024-12-04 Even Rouault + + Merge branch 'TIFFRGBAImageOK_remove_unnecessary_calls' into 'master' + Remove unnecessary calls to TIFFRGBAImageOK() in tif_getimage.c + + Closes #175 + + See merge request libtiff/libtiff!677 + +2024-12-03 Su_Laus + + Remove unnecessary calls to TIFFRGBAImageOK() in tif_getimage.c. + Closes #175 + +2024-11-30 Roger Leigh + + Merge branch 'master' into 'master' + Rename cxx to tiff-cxx + + See merge request libtiff/libtiff!676 + +2024-11-30 榆柳松 + + Rename cxx to tiff-cxx,avoid overly mundane names. + +2024-11-29 Su_Laus + + manpage: doc/functions/TIFFRGBAImage.rst note added for incorrect saving of images with TIFF orientation from 5 (LeftTop) to 8 (LeftBottom) in the raster. + +2024-11-19 Even Rouault + + Merge branch 'fix_test_directory_for_big_endian_machines' into 'master' + Update test/test_directory.c not to fail on big-endian machines. Fix memory leaks + + Closes #652 et #656 + + See merge request libtiff/libtiff!673 + +2024-11-19 Su Laus + + Update test/test_directory.c not to fail on big-endian machines. Fix memory leaks + Closes #652 et #656 + +2024-11-08 Even Rouault + + Merge branch 'tiffdither_multi_page' into 'master' + tiffdither: process all pages in input TIFF file + + See merge request libtiff/libtiff!674 + +2024-11-08 Marco Rullo + + tiffdither: process all pages in input TIFF file. + +2024-10-30 Even Rouault + + Merge branch 'unknown_tag_warnings' into 'master' + No longer emit warnings about unknown tags by default, and add... + + See merge request libtiff/libtiff!463 + +2024-10-29 Even Rouault + + tiffinfo: add a -W switch to warn about unknown tags. + + No longer emit warnings about unknown tags by default, and add TIFFOpenOptionsSetWarnAboutUnknownTags() for explicit control + +2024-10-28 Even Rouault + + Merge branch 'COMPRESSION_JXL_DNG_1_7' into 'master' + tiff.h: add COMPRESSION_JXL_DNG_1_7=52546 as used for JPEGXL compression in... + + See merge request libtiff/libtiff!672 + +2024-10-27 Even Rouault + + Merge branch '532_MergeFields_with_FIELD_IGNORE' into 'master' + Issue #532: Updating TIFFMergeFieldInfo() with read_count=write_count=0 for FIELD_IGNORE. + + Closes #532 + + See merge request libtiff/libtiff!668 + +2024-10-27 Su Laus + + Issue #532: Updating TIFFMergeFieldInfo() with read_count=write_count=0 for FIELD_IGNORE. + Updating TIFFMergeFieldInfo() with read_count=write_count=0 for FIELD_IGNORE. + Improving handling when field_name = NULL. + + Closes #532 + + There was a regression in v4.7.0 related to re-opened issue https://gitlab.com/libtiff/libtiff/-/issues/532#note_2134433038 and following discussion. + +2024-10-27 Even Rouault + + tiff.h: add COMPRESSION_JXL_DNG_1_7=52546 as used for JPEGXL compression in the DNG 1.7 specification + +2024-10-23 Even Rouault + + Merge branch 'fix_651_bis' into 'master' + CMake: fix build with LLVM/Clang 17+ + + Closes #651 + + See merge request libtiff/libtiff!671 + +2024-10-21 Even Rouault + + Merge branch 'remove_useless_cmake_minimum_required' into 'master' + doc/CMakeLists.txt: remove useless cmake_minimum_required() + + See merge request libtiff/libtiff!670 + +2024-10-20 Daniel E @diizzyy + + CMake: fix build with LLVM/Clang 17+ + Fixes #651 + +2024-10-20 Even Rouault + + doc/CMakeLists.txt: remove useless cmake_minimum_required() + There's already one in top CMakeLists.txt (at 3.9.0 currently) + + Newer CMake versions throw this warning with current 3.2.0: + ``` + CMake Deprecation Warning at doc/CMakeLists.txt:27 (cmake_minimum_required): + Compatibility with CMake < 3.5 will be removed from a future version of + CMake. + Update the VERSION argument value or use a ... suffix to tell + CMake that the project does not need compatibility with older versions. + ``` + +2024-10-13 Even Rouault + + Merge branch 'tif_jpeg_65535' into 'master' + tif_jpeg.c: use JPEG_MAX_DIMENSION constant instead of hard-coded 65535 value + + See merge request libtiff/libtiff!658 + +2024-10-05 Even Rouault + + Merge branch 'fix_gdal_10875' into 'master' + TIFFDefaultTransferFunction(): give up beyond td_bitspersample = 24 + + See merge request libtiff/libtiff!665 + +2024-10-05 Even Rouault + + Merge branch 'ppm2tiff_fix_#467_10bit_packwords' into 'master' + ppm2tiff: Fix bug in `pack_words` trailing bytes + + Closes #467 + + See merge request libtiff/libtiff!666 + +2024-10-05 Even Rouault + + Merge branch 'master' into 'master' + Fix issue #649 in fax2ps caused by regression in commit... + + Closes #649 + + See merge request libtiff/libtiff!667 + +2024-10-05 Lee Howard + + Check TIFFTAG_TILELENGTH and TIFFTAGTILEWIDTH for valid input, addresses issue #650 + +2024-09-27 Lee Howard + + Fix issue #649 in fax2ps caused by regression in commit https://gitlab.com/libtiff/libtiff/-/commit/28c38d648b64a66c3218778c4745225fe3e3a06d where TIFFTAG_FAXFILLFUNC is being used rather than an output buffer. + +2024-09-27 Su_Laus + + ppm2tiff: Fix bug in `pack_words` trailing bytes, where last two bytes of each line were written wrongly. + Closes #467. + +2024-09-26 Even Rouault + + TIFFDefaultTransferFunction(): give up beyond td_bitspersample = 24. + This function tries to allocate (1 << td_bitspersample) bytes which may + results in denial of services if td_bitspersample is too large. + + Fixes https://github.com/OSGeo/gdal/issues/10875 + +2024-09-22 Even Rouault + + Merge branch 'theta682-fix-Oi-GFS' into 'master' + Fix parsing a private tag 0x80a6 + + Closes #647 + + See merge request libtiff/libtiff!661 + +2024-09-22 Timothy Lyanguzov + + Do not error out on a tag whose tag count value is zero, just issue a warning. + Fix parsing a private tag 0x80a6 + +2024-09-21 Benjamin Gilbert + + Define HAVE_JPEGTURBO_DUAL_MODE_8_12 in tif_config.h. + Remove special-case Autotools and CMake code to define it on the + compiler command line. + + Define LERC_STATIC in tif_config.h. + Remove special-case Autotools and CMake code to define it on the + compiler command line. + + CMake: set WORDS_BIGENDIAN via #cmakedefine. + Autotools sets WORDS_BIGENDIAN via tif_config.h, but the CMake equivalent + in tif_config.h.cmake.in is a no-op; CMake passes the define on the + compiler command line instead. For consistency, have CMake set the define + via tif_config.h. + +2024-09-21 Even Rouault + + Merge branch 'fix_648_ASCII_length_at_WriteDirectorySec_codec_part' into 'master' + Increment string length for ASCII tags in TIFFWriteDirectorySec() for codec... + + Closes #648 + + See merge request libtiff/libtiff!663 + +2024-09-21 Su_Laus + + Increment string length for ASCII tags in TIFFWriteDirectorySec() for codec tags defined with FIELD_xxx bits, as it is done for FIELD_CUSTOM tags. Fixes #648 + 2024-09-11 Even Rouault libtiff v4.7.0rc2 preparation @@ -469,9 +1748,9 @@ LERCDecode: zero-initialize output buffer if failure. - LZMADecode: zero-initialize (not-yet-written parts of) output buffer if failure, and handle repeated calls to decoding same tile/strip if previous failure occured + LZMADecode: zero-initialize (not-yet-written parts of) output buffer if failure, and handle repeated calls to decoding same tile/strip if previous failure occurred - TWebPDecode: zero-initialize output buffer if failure, and handle repeated calls to decoding same tile/strip if previous failure occured + TWebPDecode: zero-initialize output buffer if failure, and handle repeated calls to decoding same tile/strip if previous failure occurred ThunderDecode: zero-initialize (not-yet-written parts of) output buffer if failure @@ -479,7 +1758,7 @@ JBIGDecode: zero-initialize (not-yet-written parts of) output buffer if failure - ZIPDecode: zero-initialize (not-yet-written parts of) output buffer if failure, and handle repeated calls to decoding same tile/strip if previous failure occured + ZIPDecode: zero-initialize (not-yet-written parts of) output buffer if failure, and handle repeated calls to decoding same tile/strip if previous failure occurred LZWDecode: zero-initialize (not-yet-written parts of) output buffer if failure @@ -891,13 +2170,13 @@ 2024-04-25 Even Rouault Merge branch 'libjpeg_turbo_3_0' into 'master' - Change messages/comments refering libjpeg-turbo 2.2 to 3.0 + Change messages/comments referring libjpeg-turbo 2.2 to 3.0 See merge request libtiff/libtiff!584 2024-04-24 Even Rouault - Change messages/comments refering libjpeg-turbo 2.2 to 3.0. + Change messages/comments referring libjpeg-turbo 2.2 to 3.0. libjpeg-turbo 2.2 was actually released as 3.0. Reflect that 2024-04-22 Even Rouault @@ -1054,7 +2333,7 @@ The LERC codec up-to-now didn't do any special processing when writing a strile in a multi-band PlanarConfig=Contig file, resulting in corruptions. Now we generate a mask buffer in that situation. Actually, if the NaN values are not - at the same location accross bands, we need to write one mask-per-band, which + at the same location across bands, we need to write one mask-per-band, which requires liblerc >= 3.0, and in that situation change the LERC blob to multi-band instead of multi-depth/dim, with liblerc >= 3.0. When all bands have NaN values at the same location, we generate a single mask, which is compatible @@ -1102,7 +2381,7 @@ ^~~~~~~~ This updates the format specifiers from `PRIu16` to `PRIu32` for `tdir_t` - (which is a `typdef`ed `uint32_t`) and from `TIFF_SSIZE_FORMAT` to + (which is a `typedef`ed `uint32_t`) and from `TIFF_SSIZE_FORMAT` to `TIFF_SIZE_FORMAT` for `size_t`, which makes sense given that it's an unsigned type. @@ -1122,13 +2401,13 @@ 2024-03-14 Even Rouault Merge branch 'fix_wrong_return_TIFFIsBigTIFF_if_swapping_case' into 'master' - Fix wrong return of TIFFIsBigTIFF() in case byte-swapping is acitve + Fix wrong return of TIFFIsBigTIFF() in case byte-swapping is active See merge request libtiff/libtiff!567 2024-03-13 Su_Laus - Fix wrong return of TIFFIsBigTIFF() in case byte-swapping is acitve (i.e. little endian image on a big endian machine). + Fix wrong return of TIFFIsBigTIFF() in case byte-swapping is active (i.e. little endian image on a big endian machine). 2024-01-30 Even Rouault @@ -1263,7 +2542,7 @@ 2023-11-11 Even Rouault Merge branch 'manpage_621_TIFFOpenOptionsSetMaxSingleMemAlloc' into 'master' - manpage: Update TIFF documentation about TIFFOpenOptions.rst and memory limitting. + manpage: Update TIFF documentation about TIFFOpenOptions.rst and memory limiting. Closes #621 @@ -1351,7 +2630,7 @@ 2023-10-31 Even Rouault tif_dirread.c: only issue TIFFGetFileSize() for large enough RAM requests - Ammends 5320c9d89c054fa805d037d84c57da874470b01a + Amends 5320c9d89c054fa805d037d84c57da874470b01a This fixes a performance regression caught by the GDAL regression test suite. @@ -1421,7 +2700,7 @@ 2023-10-12 Even Rouault Merge branch 'tiffcp_cancel_ycbcr' into 'master' - tiffcp: replace PHOTOMETRIC_YCBCR with PHOTOMETRIC_RGB when outputing to... + tiffcp: replace PHOTOMETRIC_YCBCR with PHOTOMETRIC_RGB when outputting to... See merge request libtiff/libtiff!540 @@ -1445,7 +2724,7 @@ 2023-10-07 Even Rouault - tiffcp: replace PHOTOMETRIC_YCBCR with PHOTOMETRIC_RGB when outputing to compression != JPEG (refs #571) + tiffcp: replace PHOTOMETRIC_YCBCR with PHOTOMETRIC_RGB when outputting to compression != JPEG (refs #571) 2023-10-05 Even Rouault @@ -9779,14 +11058,14 @@ * libtiff/tif_pixarlog.c: PixarLogDecode(): resync tif_rawcp with next_in and tif_rawcc with avail_in at beginning and end of function, similarly to what is done in LZWDecode(). Likely needed so that it - works properly with latest chnges in tif_read.c in CHUNKY_STRIP_READ_SUPPORT + works properly with latest changes in tif_read.c in CHUNKY_STRIP_READ_SUPPORT mode. But untested... 2017-05-17 Even Rouault * libtiff/tif_lzw.c: update dec_bitsleft at beginning of LZWDecode(), and update tif_rawcc at end of LZWDecode(). This is needed to properly - work with the latest chnges in tif_read.c in CHUNKY_STRIP_READ_SUPPORT + work with the latest changes in tif_read.c in CHUNKY_STRIP_READ_SUPPORT mode. 2017-05-14 Even Rouault @@ -10209,7 +11488,7 @@ * tools/tiffdump.c (ReadDirectory): Remove uint32 cast to _TIFFmalloc() argument which resulted in Coverity report. Added - more mutiplication overflow checks. + more multiplication overflow checks. 2016-11-18 Even Rouault @@ -10726,7 +12005,7 @@ Builds with CMake 2.8.9 and newer. - Tar is now resquested to use POSIX PAX format. + Tar is now requested to use POSIX PAX format. 2015-08-31 Bob Friesenhahn @@ -10809,7 +12088,7 @@ 2015-08-23 Bob Friesenhahn - * libtiff/tiffiop.h: For MinGW comiles, make sure that build + * libtiff/tiffiop.h: For MinGW compiles, make sure that build supports necessary __MSVCRT_VERSION__ (at least at least 0x800). Otherwise large files can not be supported for POSIX-style I/O. @@ -16427,7 +17706,7 @@ btiff/tif_win32.c: Replace custom Win32 memory api with generic 2002-03-15 Andrey Kiselev * libtiff/: tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_dirread.c, - tif_dirwrite.c: Added routine TIFFDataWidth for detrmining + tif_dirwrite.c: Added routine TIFFDataWidth for determining TIFFDataType sizes instead of working with tiffDataWidth array directly. Should prevent out-of-borders bugs in case of unknown or broken data types. EstimateStripByteCounts routine modified, so it @@ -17241,7 +18520,7 @@ Tue Dec 21 14:01:51 1999 Frank Warmerdam Tue Dec 21 11:04:45 EST 1999 Mike Welles *** 3.5.4 release *** - * Aadded Pixar tag support. Contributed by Phil Beffery + * Added Pixar tag support. Contributed by Phil Beffery * Made one more change to tif_dir.c for removal of LZW compression. Also added notice when LZW compression invoked. diff --git a/3rdparty/libtiff/LICENSE.md b/3rdparty/libtiff/LICENSE.md new file mode 100644 index 0000000000..12d5ef2310 --- /dev/null +++ b/3rdparty/libtiff/LICENSE.md @@ -0,0 +1,49 @@ +# LibTIFF license + +Copyright © 1988-1997 Sam Leffler\ +Copyright © 1991-1997 Silicon Graphics, Inc. + +Permission to use, copy, modify, distribute, and sell this software and +its documentation for any purpose is hereby granted without fee, provided +that (i) the above copyright notices and this permission notice appear in +all copies of the software and related documentation, and (ii) the names of +Sam Leffler and Silicon Graphics may not be used in any advertising or +publicity relating to the software without the specific, prior written +permission of Sam Leffler and Silicon Graphics. + +THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR +ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF +LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +OF THIS SOFTWARE. + +# Lempel-Ziv & Welch Compression (tif_lzw.c) license +The code of tif_lzw.c is derived from the compress program whose code is +derived from software contributed to Berkeley by James A. Woods, +derived from original work by Spencer Thomas and Joseph Orost. + +The original Berkeley copyright notice appears below in its entirety: + +Copyright (c) 1985, 1986 The Regents of the University of California. +All rights reserved. + +This code is derived from software contributed to Berkeley by +James A. Woods, derived from original work by Spencer Thomas +and Joseph Orost. + +Redistribution and use in source and binary forms are permitted +provided that the above copyright notice and this paragraph are +duplicated in all such forms and that any documentation, +advertising materials, and other materials related to such +distribution and use acknowledge that the software was developed +by the University of California, Berkeley. The name of the +University may not be used to endorse or promote products derived +from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/3rdparty/libtiff/RELEASE-DATE b/3rdparty/libtiff/RELEASE-DATE index 2abf40291e..cc3bc45669 100644 --- a/3rdparty/libtiff/RELEASE-DATE +++ b/3rdparty/libtiff/RELEASE-DATE @@ -1 +1 @@ -20240911 +20250911 diff --git a/3rdparty/libtiff/tif_aux.c b/3rdparty/libtiff/tif_aux.c index e9606a42e0..31b240070c 100644 --- a/3rdparty/libtiff/tif_aux.c +++ b/3rdparty/libtiff/tif_aux.c @@ -131,7 +131,10 @@ static int TIFFDefaultTransferFunction(TIFF *tif, TIFFDirectory *td) tmsize_t i, n, nbytes; tf[0] = tf[1] = tf[2] = 0; - if (td->td_bitspersample >= sizeof(tmsize_t) * 8 - 2) + // Do not try to generate a default TransferFunction beyond 24 bits. + // This otherwise leads to insane amounts, resulting in denial of service + // See https://github.com/OSGeo/gdal/issues/10875 + if (td->td_bitspersample > 24) return 0; n = ((tmsize_t)1) << td->td_bitspersample; diff --git a/3rdparty/libtiff/tif_close.c b/3rdparty/libtiff/tif_close.c index d6bb7f1d7c..d498010740 100644 --- a/3rdparty/libtiff/tif_close.c +++ b/3rdparty/libtiff/tif_close.c @@ -48,7 +48,6 @@ void TIFFCleanup(TIFF *tif) */ if (tif->tif_mode != O_RDONLY) TIFFFlush(tif); - (*tif->tif_cleanup)(tif); TIFFFreeDirectory(tif); _TIFFCleanupIFDOffsetAndNumberMaps(tif); diff --git a/3rdparty/libtiff/tif_config.h.cmake.in b/3rdparty/libtiff/tif_config.h.cmake.in index 645cb6b321..8fc246630b 100644 --- a/3rdparty/libtiff/tif_config.h.cmake.in +++ b/3rdparty/libtiff/tif_config.h.cmake.in @@ -80,11 +80,17 @@ #cmakedefine HAVE_UNISTD_H 1 /* 8/12 bit libjpeg dual mode enabled */ -#cmakedefine JPEG_DUAL_MODE_8_12 1 1 +#cmakedefine JPEG_DUAL_MODE_8_12 1 + +/* 8/12 bit dual mode JPEG built into libjpeg-turbo 3.0+ */ +#cmakedefine HAVE_JPEGTURBO_DUAL_MODE_8_12 1 /* Support LERC compression */ #cmakedefine LERC_SUPPORT 1 +/* Define to 1 when building a static libtiff with LERC enabled. */ +#cmakedefine LERC_STATIC + /* 12bit libjpeg primary include file with path */ #define LIBJPEG_12_PATH "@LIBJPEG_12_PATH@" @@ -133,7 +139,7 @@ # endif #else # ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN +# cmakedefine WORDS_BIGENDIAN 1 # endif #endif diff --git a/3rdparty/libtiff/tif_dir.c b/3rdparty/libtiff/tif_dir.c index 459f9696fd..7421c738db 100644 --- a/3rdparty/libtiff/tif_dir.c +++ b/3rdparty/libtiff/tif_dir.c @@ -723,10 +723,9 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) { TIFFTagValue *new_customValues; - td->td_customValueCount++; new_customValues = (TIFFTagValue *)_TIFFreallocExt( tif, td->td_customValues, - sizeof(TIFFTagValue) * td->td_customValueCount); + sizeof(TIFFTagValue) * (td->td_customValueCount + 1)); if (!new_customValues) { TIFFErrorExtR(tif, module, @@ -737,6 +736,7 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) goto end; } + td->td_customValueCount++; td->td_customValues = new_customValues; tv = td->td_customValues + (td->td_customValueCount - 1); @@ -748,8 +748,8 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) /* * Set custom value ... save a copy of the custom tag value. */ - /*--: Rational2Double: For Rationals evaluate "set_field_type" to - * determine internal storage size. */ + /*--: Rational2Double: For Rationals evaluate "set_get_field_type" + * to determine internal storage size. */ tv_size = TIFFFieldSetGetSize(fip); if (tv_size == 0) { @@ -806,14 +806,13 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) if (tv->count == 0) { - status = 0; - TIFFErrorExtR(tif, module, - "%s: Null count for \"%s\" (type " - "%d, writecount %d, passcount %d)", - tif->tif_name, fip->field_name, - fip->field_type, fip->field_writecount, - fip->field_passcount); - goto end; + TIFFWarningExtR(tif, module, + "%s: Null count for \"%s\" (type " + "%d, writecount %d, passcount %d)", + tif->tif_name, fip->field_name, + fip->field_type, fip->field_writecount, + fip->field_passcount); + break; } tv->value = _TIFFCheckMalloc(tif, tv->count, tv_size, @@ -843,7 +842,7 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) fip->field_writecount == TIFF_SPP || tv->count > 1) { /*--: Rational2Double: For Rationals tv_size is set above to - * 4 or 8 according to fip->set_field_type! */ + * 4 or 8 according to fip->set_get_field_type! */ _TIFFmemcpy(tv->value, va_arg(ap, void *), tv->count * tv_size); /* Test here for too big values for LONG8, SLONG8 in @@ -978,7 +977,8 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) case TIFF_RATIONAL: case TIFF_SRATIONAL: /*-- Rational2Double: For Rationals tv_size is set - * above to 4 or 8 according to fip->set_field_type! + * above to 4 or 8 according to + * fip->set_get_field_type! */ { if (tv_size == 8) @@ -996,11 +996,11 @@ static int _TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) * default. */ if (tv_size != 4) { - TIFFErrorExtR( - tif, module, - "Rational2Double: .set_field_type " - "in not 4 but %d", - tv_size); + TIFFErrorExtR(tif, module, + "Rational2Double: " + ".set_get_field_type " + "in not 4 but %d", + tv_size); } } } @@ -1527,7 +1527,7 @@ static int _TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap) case TIFF_SRATIONAL: { /*-- Rational2Double: For Rationals evaluate - * "set_field_type" to determine internal + * "set_get_field_type" to determine internal * storage size and return value size. */ int tv_size = TIFFFieldSetGetSize(fip); if (tv_size == 8) @@ -1545,11 +1545,11 @@ static int _TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap) * default. */ if (tv_size != 4) { - TIFFErrorExtR( - tif, "_TIFFVGetField", - "Rational2Double: .set_field_type " - "in not 4 but %d", - tv_size); + TIFFErrorExtR(tif, "_TIFFVGetField", + "Rational2Double: " + ".set_get_field_type " + "in not 4 but %d", + tv_size); } } } @@ -1621,6 +1621,7 @@ void TIFFFreeDirectory(TIFF *tif) TIFFDirectory *td = &tif->tif_dir; int i; + (*tif->tif_cleanup)(tif); _TIFFmemset(td->td_fieldsset, 0, sizeof(td->td_fieldsset)); CleanupField(td_sminsamplevalue); CleanupField(td_smaxsamplevalue); @@ -2207,7 +2208,7 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff) _TIFFCleanupIFDOffsetAndNumberMaps(tif); tif->tif_curdir = 0; /* first directory of new chain */ /* add this offset to new IFD list */ - _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff); + retval = _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff); } /* To be able to return from SubIFD or custom-IFD to main-IFD */ tif->tif_setdirectory_force_absolute = TRUE; @@ -2336,12 +2337,12 @@ int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn) * means that the caller can only append to the directory * chain. */ - (*tif->tif_cleanup)(tif); if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfreeExt(tif, tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawcc = 0; + tif->tif_rawcp = NULL; tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = 0; } diff --git a/3rdparty/libtiff/tif_dir.h b/3rdparty/libtiff/tif_dir.h index ffad085e02..44270f7097 100644 --- a/3rdparty/libtiff/tif_dir.h +++ b/3rdparty/libtiff/tif_dir.h @@ -329,16 +329,15 @@ extern "C" struct _TIFFField { - uint32_t field_tag; /* field's tag */ - short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ - short field_writecount; /* write count/TIFF_VARIABLE */ - TIFFDataType field_type; /* type of associated data */ - uint32_t - field_anonymous; /* if true, this is a unknown / anonymous tag */ - TIFFSetGetFieldType set_field_type; /* type to be passed to TIFFSetField - and TIFFGetField*/ - TIFFSetGetFieldType get_field_type; /* not used */ - unsigned short field_bit; /* bit in fieldsset bit vector */ + uint32_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + uint32_t field_anonymous; /* if true, this is a unknown / + anonymous tag */ + TIFFSetGetFieldType set_get_field_type; /* type to be passed to + TIFFSetField, TIFFGetField */ + unsigned short field_bit; /* bit in fieldsset bit vector */ unsigned char field_oktochange; /* if true, can change while writing */ unsigned char field_passcount; /* if true, pass dir count on set */ char *field_name; /* ASCII name */ diff --git a/3rdparty/libtiff/tif_dirinfo.c b/3rdparty/libtiff/tif_dirinfo.c index 432e6e1e44..c038497cf4 100644 --- a/3rdparty/libtiff/tif_dirinfo.c +++ b/3rdparty/libtiff/tif_dirinfo.c @@ -54,10 +54,10 @@ static const TIFFFieldArray gpsFieldArray; /*--: Rational2Double: -- * The Rational2Double upgraded libtiff functionality allows the definition and * achievement of true double-precision accuracy for TIFF tags of RATIONAL type - * and field_bit=FIELD_CUSTOM using the set_field_type = TIFF_SETGET_DOUBLE. + * and field_bit=FIELD_CUSTOM using the set_get_field_type = TIFF_SETGET_DOUBLE. * Unfortunately, that changes the old implemented interface for TIFFGetField(). * In order to keep the old TIFFGetField() interface behavior those tags have to - * be redefined with set_field_type = TIFF_SETGET_FLOAT! + * be redefined with set_get_field_type = TIFF_SETGET_FLOAT! * * Rational custom arrays are already defined as _Cxx_FLOAT, thus can stay. * @@ -65,281 +65,281 @@ static const TIFFFieldArray gpsFieldArray; /* clang-format off */ /* for better readability of tag comments */ static const TIFFField tiffFields[] = { - {TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "SubfileType", NULL}, - {TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "OldSubfileType", NULL}, - {TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 0, 0, "ImageWidth", NULL}, - {TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 1, 0, "ImageLength", NULL}, - {TIFFTAG_BITSPERSAMPLE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_BITSPERSAMPLE, 0, 0, "BitsPerSample", NULL}, - {TIFFTAG_COMPRESSION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_COMPRESSION, 0, 0, "Compression", NULL}, - {TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PHOTOMETRIC, 0, 0, "PhotometricInterpretation", NULL}, - {TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_THRESHHOLDING, 1, 0, "Threshholding", NULL}, - {TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CellWidth", NULL}, - {TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CellLength", NULL}, - {TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_FILLORDER, 0, 0, "FillOrder", NULL}, - {TIFFTAG_DOCUMENTNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DocumentName", NULL}, - {TIFFTAG_IMAGEDESCRIPTION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageDescription", NULL}, - {TIFFTAG_MAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Make", NULL}, - {TIFFTAG_MODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Model", NULL}, - {TIFFTAG_STRIPOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "StripOffsets", NULL}, - {TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_ORIENTATION, 0, 0, "Orientation", NULL}, - {TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLESPERPIXEL, 0, 0, "SamplesPerPixel", NULL}, - {TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_ROWSPERSTRIP, 0, 0, "RowsPerStrip", NULL}, - {TIFFTAG_STRIPBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "StripByteCounts", NULL}, - {TIFFTAG_MINSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MINSAMPLEVALUE, 1, 0, "MinSampleValue", NULL}, - {TIFFTAG_MAXSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MAXSAMPLEVALUE, 1, 0, "MaxSampleValue", NULL}, - {TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "XResolution", NULL}, - {TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "YResolution", NULL}, - {TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PLANARCONFIG, 0, 0, "PlanarConfiguration", NULL}, - {TIFFTAG_PAGENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PageName", NULL}, - {TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "XPosition", NULL}, - {TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "YPosition", NULL}, - {TIFFTAG_FREEOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeOffsets", NULL}, - {TIFFTAG_FREEBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeByteCounts", NULL}, - {TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseUnit", NULL}, - {TIFFTAG_GRAYRESPONSECURVE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseCurve", NULL}, - {TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTIONUNIT, 1, 0, "ResolutionUnit", NULL}, - {TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_PAGENUMBER, 1, 0, "PageNumber", NULL}, - {TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "ColorResponseUnit", NULL}, - {TIFFTAG_TRANSFERFUNCTION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_TRANSFERFUNCTION, 1, 0, "TransferFunction", NULL}, - {TIFFTAG_SOFTWARE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Software", NULL}, - {TIFFTAG_DATETIME, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTime", NULL}, - {TIFFTAG_ARTIST, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Artist", NULL}, - {TIFFTAG_HOSTCOMPUTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "HostComputer", NULL}, - {TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhitePoint", NULL}, - {TIFFTAG_PRIMARYCHROMATICITIES, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PrimaryChromaticities", NULL}, - {TIFFTAG_COLORMAP, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_COLORMAP, 1, 0, "ColorMap", NULL}, - {TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_HALFTONEHINTS, 1, 0, "HalftoneHints", NULL}, - {TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileWidth", NULL}, - {TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileLength", NULL}, - {TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "TileOffsets", NULL}, - {TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "TileByteCounts", NULL}, - {TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_SUBIFD, 1, 1, "SubIFD", (TIFFFieldArray *)&tiffFieldArray}, - {TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL}, - {TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL}, - {TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_NUMBEROFINKS, 1, 0, "NumberOfInks", NULL}, - {TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL}, - {TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL}, - {TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL}, - {TIFFTAG_SAMPLEFORMAT, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "SampleFormat", NULL}, - {TIFFTAG_SMINSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMINSAMPLEVALUE, 1, 0, "SMinSampleValue", NULL}, - {TIFFTAG_SMAXSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMAXSAMPLEVALUE, 1, 0, "SMaxSampleValue", NULL}, - {TIFFTAG_CLIPPATH, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ClipPath", NULL}, - {TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL}, - {TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YClipPathUnits", NULL}, - {TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YCbCrCoefficients", NULL}, - {TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_YCBCRSUBSAMPLING, 0, 0, "YCbCrSubsampling", NULL}, - {TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_YCBCRPOSITIONING, 0, 0, "YCbCrPositioning", NULL}, - {TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_REFBLACKWHITE, 1, 0, "ReferenceBlackWhite", NULL}, - {TIFFTAG_XMLPACKET, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "XMLPacket", NULL}, + {TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_SUBFILETYPE, 1, 0, "SubfileType", NULL}, + {TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "OldSubfileType", NULL}, + {TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_IMAGEDIMENSIONS, 0, 0, "ImageWidth", NULL}, + {TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_IMAGEDIMENSIONS, 1, 0, "ImageLength", NULL}, + {TIFFTAG_BITSPERSAMPLE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_BITSPERSAMPLE, 0, 0, "BitsPerSample", NULL}, + {TIFFTAG_COMPRESSION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_COMPRESSION, 0, 0, "Compression", NULL}, + {TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_PHOTOMETRIC, 0, 0, "PhotometricInterpretation", NULL}, + {TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_THRESHHOLDING, 1, 0, "Threshholding", NULL}, + {TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CellWidth", NULL}, + {TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CellLength", NULL}, + {TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_FILLORDER, 0, 0, "FillOrder", NULL}, + {TIFFTAG_DOCUMENTNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DocumentName", NULL}, + {TIFFTAG_IMAGEDESCRIPTION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "ImageDescription", NULL}, + {TIFFTAG_MAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Make", NULL}, + {TIFFTAG_MODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Model", NULL}, + {TIFFTAG_STRIPOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "StripOffsets", NULL}, + {TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_ORIENTATION, 0, 0, "Orientation", NULL}, + {TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_SAMPLESPERPIXEL, 0, 0, "SamplesPerPixel", NULL}, + {TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_ROWSPERSTRIP, 0, 0, "RowsPerStrip", NULL}, + {TIFFTAG_STRIPBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "StripByteCounts", NULL}, + {TIFFTAG_MINSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_MINSAMPLEVALUE, 1, 0, "MinSampleValue", NULL}, + {TIFFTAG_MAXSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_MAXSAMPLEVALUE, 1, 0, "MaxSampleValue", NULL}, + {TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_RESOLUTION, 1, 0, "XResolution", NULL}, + {TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_RESOLUTION, 1, 0, "YResolution", NULL}, + {TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_PLANARCONFIG, 0, 0, "PlanarConfiguration", NULL}, + {TIFFTAG_PAGENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "PageName", NULL}, + {TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_POSITION, 1, 0, "XPosition", NULL}, + {TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_POSITION, 1, 0, "YPosition", NULL}, + {TIFFTAG_FREEOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeOffsets", NULL}, + {TIFFTAG_FREEBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeByteCounts", NULL}, + {TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseUnit", NULL}, + {TIFFTAG_GRAYRESPONSECURVE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseCurve", NULL}, + {TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_RESOLUTIONUNIT, 1, 0, "ResolutionUnit", NULL}, + {TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, FIELD_PAGENUMBER, 1, 0, "PageNumber", NULL}, + {TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "ColorResponseUnit", NULL}, + {TIFFTAG_TRANSFERFUNCTION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, FIELD_TRANSFERFUNCTION, 1, 0, "TransferFunction", NULL}, + {TIFFTAG_SOFTWARE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Software", NULL}, + {TIFFTAG_DATETIME, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DateTime", NULL}, + {TIFFTAG_ARTIST, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Artist", NULL}, + {TIFFTAG_HOSTCOMPUTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "HostComputer", NULL}, + {TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "WhitePoint", NULL}, + {TIFFTAG_PRIMARYCHROMATICITIES, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "PrimaryChromaticities", NULL}, + {TIFFTAG_COLORMAP, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, FIELD_COLORMAP, 1, 0, "ColorMap", NULL}, + {TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, FIELD_HALFTONEHINTS, 1, 0, "HalftoneHints", NULL}, + {TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_TILEDIMENSIONS, 0, 0, "TileWidth", NULL}, + {TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_TILEDIMENSIONS, 0, 0, "TileLength", NULL}, + {TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "TileOffsets", NULL}, + {TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "TileByteCounts", NULL}, + {TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, FIELD_SUBIFD, 1, 1, "SubIFD", (TIFFFieldArray *)&tiffFieldArray}, + {TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 0, 0, "InkSet", NULL}, + {TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, FIELD_INKNAMES, 1, 1, "InkNames", NULL}, + {TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_NUMBEROFINKS, 1, 0, "NumberOfInks", NULL}, + {TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, FIELD_CUSTOM, 0, 0, "DotRange", NULL}, + {TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL}, + {TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL}, + {TIFFTAG_SAMPLEFORMAT, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_SAMPLEFORMAT, 0, 0, "SampleFormat", NULL}, + {TIFFTAG_SMINSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, FIELD_SMINSAMPLEVALUE, 1, 0, "SMinSampleValue", NULL}, + {TIFFTAG_SMAXSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, FIELD_SMAXSAMPLEVALUE, 1, 0, "SMaxSampleValue", NULL}, + {TIFFTAG_CLIPPATH, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 0, 1, "ClipPath", NULL}, + {TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL}, + {TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 0, 0, "YClipPathUnits", NULL}, + {TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 0, 0, "YCbCrCoefficients", NULL}, + {TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, FIELD_YCBCRSUBSAMPLING, 0, 0, "YCbCrSubsampling", NULL}, + {TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_YCBCRPOSITIONING, 0, 0, "YCbCrPositioning", NULL}, + {TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_REFBLACKWHITE, 1, 0, "ReferenceBlackWhite", NULL}, + {TIFFTAG_XMLPACKET, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "XMLPacket", NULL}, /* begin SGI tags */ - {TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 0, "Matteing", NULL}, - {TIFFTAG_DATATYPE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "DataType", NULL}, - {TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDEPTH, 0, 0, "ImageDepth", NULL}, - {TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDEPTH, 0, 0, "TileDepth", NULL}, + {TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_EXTRASAMPLES, 0, 0, "Matteing", NULL}, + {TIFFTAG_DATATYPE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_SAMPLEFORMAT, 0, 0, "DataType", NULL}, + {TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_IMAGEDEPTH, 0, 0, "ImageDepth", NULL}, + {TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_TILEDEPTH, 0, 0, "TileDepth", NULL}, /* end SGI tags */ /* begin Pixar tags */ - {TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullWidth", NULL}, - {TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullLength", NULL}, - {TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureFormat", NULL}, - {TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureWrapModes", NULL}, - {TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL}, - {TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL}, - {TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL}, - {TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Copyright", NULL}, + {TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ImageFullWidth", NULL}, + {TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ImageFullLength", NULL}, + {TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "TextureFormat", NULL}, + {TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "TextureWrapModes", NULL}, + {TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL}, + {TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL}, + {TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL}, + {TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Copyright", NULL}, /* end Pixar tags */ - {TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "RichTIFFIPTC", NULL}, - {TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "Photoshop", NULL}, + {TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "RichTIFFIPTC", NULL}, + {TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "Photoshop", NULL}, /*--: EXIFIFD and GPSIFD specified as TIFF_LONG by Aware-Systems and not TIFF_IFD8 as in original LibTiff. However, for IFD-like tags, * libtiff uses the data type TIFF_IFD8 in tiffFields[]-tag definition combined with a special handling procedure in order to write either * a 32-bit value and the TIFF_IFD type-id into ClassicTIFF files or a 64-bit value and the TIFF_IFD8 type-id into BigTIFF files. */ - {TIFFTAG_EXIFIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EXIFIFDOffset", (TIFFFieldArray *)&exifFieldArray}, - {TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ICC Profile", NULL}, - {TIFFTAG_GPSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GPSIFDOffset", (TIFFFieldArray *)&gpsFieldArray}, - {TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvParams", NULL}, - {TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxSubAddress", NULL}, - {TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvTime", NULL}, - {TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxDcs", NULL}, - {TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "StoNits", NULL}, - {TIFFTAG_IMAGESOURCEDATA, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "Adobe Photoshop Document Data Block", NULL}, - {TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InteroperabilityIFDOffset", NULL}, + {TIFFTAG_EXIFIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, FIELD_CUSTOM, 1, 0, "EXIFIFDOffset", (TIFFFieldArray *)&exifFieldArray}, + {TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "ICC Profile", NULL}, + {TIFFTAG_GPSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, FIELD_CUSTOM, 1, 0, "GPSIFDOffset", (TIFFFieldArray *)&gpsFieldArray}, + {TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvParams", NULL}, + {TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxSubAddress", NULL}, + {TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvTime", NULL}, + {TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxDcs", NULL}, + {TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 0, 0, "StoNits", NULL}, + {TIFFTAG_IMAGESOURCEDATA, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "Adobe Photoshop Document Data Block", NULL}, + {TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, FIELD_CUSTOM, 0, 0, "InteroperabilityIFDOffset", NULL}, /* begin DNG tags */ - {TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DNGVersion", NULL}, - {TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DNGBackwardVersion", NULL}, - {TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL}, - {TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL}, - {TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CFAPlaneColor", NULL}, - {TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CFALayout", NULL}, - {TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LinearizationTable", NULL}, - {TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BlackLevelRepeatDim", NULL}, - {TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "BlackLevel", NULL}, - {TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "BlackLevelDeltaH", NULL}, - {TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "BlackLevelDeltaV", NULL}, - {TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "WhiteLevel", NULL}, - {TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultScale", NULL}, - {TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BestQualityScale", NULL}, - {TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultCropOrigin", NULL}, - {TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultCropSize", NULL}, - {TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix1", NULL}, - {TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix2", NULL}, - {TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration1", NULL}, - {TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration2", NULL}, - {TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix1", NULL}, - {TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix2", NULL}, - {TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AnalogBalance", NULL}, - {TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotNeutral", NULL}, - {TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "AsShotWhiteXY", NULL}, - {TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineExposure", NULL}, - {TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineNoise", NULL}, - {TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineSharpness", NULL}, - {TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BayerGreenSplit", NULL}, - {TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LinearResponseLimit", NULL}, - {TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraSerialNumber", NULL}, - {TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensInfo", NULL}, - {TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ChromaBlurRadius", NULL}, - {TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "AntiAliasStrength", NULL}, - {TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShadowScale", NULL}, - {TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "DNGPrivateData", NULL}, - {TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MakerNoteSafety", NULL}, - {TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant1", NULL}, - {TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant2", NULL}, - {TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RawDataUniqueID", NULL}, - {TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL}, - {TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileData", NULL}, - {TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ActiveArea", NULL}, - {TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MaskedAreas", NULL}, - {TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotICCProfile", NULL}, - {TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotPreProfileMatrix", NULL}, - {TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentICCProfile", NULL}, - {TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL}, - {TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, + {TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "DNGVersion", NULL}, + {TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "DNGBackwardVersion", NULL}, + {TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL}, + {TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL}, + {TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "CFAPlaneColor", NULL}, + {TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CFALayout", NULL}, + {TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_CUSTOM, 1, 1, "LinearizationTable", NULL}, + {TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, FIELD_CUSTOM, 1, 0, "BlackLevelRepeatDim", NULL}, + {TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "BlackLevel", NULL}, + {TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "BlackLevelDeltaH", NULL}, + {TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "BlackLevelDeltaV", NULL}, + {TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, FIELD_CUSTOM, 1, 1, "WhiteLevel", NULL}, + {TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "DefaultScale", NULL}, + {TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "BestQualityScale", NULL}, + {TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "DefaultCropOrigin", NULL}, + {TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "DefaultCropSize", NULL}, + {TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ColorMatrix1", NULL}, + {TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ColorMatrix2", NULL}, + {TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "CameraCalibration1", NULL}, + {TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "CameraCalibration2", NULL}, + {TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ReductionMatrix1", NULL}, + {TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ReductionMatrix2", NULL}, + {TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "AnalogBalance", NULL}, + {TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "AsShotNeutral", NULL}, + {TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "AsShotWhiteXY", NULL}, + {TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "BaselineExposure", NULL}, + {TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "BaselineNoise", NULL}, + {TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "BaselineSharpness", NULL}, + {TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "BayerGreenSplit", NULL}, + {TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "LinearResponseLimit", NULL}, + {TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "CameraSerialNumber", NULL}, + {TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "LensInfo", NULL}, + {TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ChromaBlurRadius", NULL}, + {TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "AntiAliasStrength", NULL}, + {TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ShadowScale", NULL}, + {TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "DNGPrivateData", NULL}, + {TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "MakerNoteSafety", NULL}, + {TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant1", NULL}, + {TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant2", NULL}, + {TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "RawDataUniqueID", NULL}, + {TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL}, + {TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "OriginalRawFileData", NULL}, + {TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "ActiveArea", NULL}, + {TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, FIELD_CUSTOM, 1, 1, "MaskedAreas", NULL}, + {TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "AsShotICCProfile", NULL}, + {TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "AsShotPreProfileMatrix", NULL}, + {TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "CurrentICCProfile", NULL}, + {TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL}, + {TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, #if 0 /* begin DNG 1.2.0.0 tags */ - {TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL}, - {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL}, - {TIFFTAG_PROFILECALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileCalibrationSignature", NULL}, - {TIFFTAG_EXTRACAMERAPROFILES, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ExtraCameraProfiles", NULL}, - {TIFFTAG_ASSHOTPROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotProfileName", NULL}, - {TIFFTAG_NOISEREDUCTIONAPPLIED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NoiseReductionApplied", NULL}, - {TIFFTAG_PROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileName", NULL}, - {TIFFTAG_PROFILEHUESATMAPDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapDims", NULL}, - {TIFFTAG_PROFILEHUESATMAPDATA1, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData1", NULL}, - {TIFFTAG_PROFILEHUESATMAPDATA2, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData2", NULL}, - {TIFFTAG_PROFILETONECURVE, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileToneCurve", NULL}, - {TIFFTAG_PROFILEEMBEDPOLICY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileEmbedPolicy", NULL}, - {TIFFTAG_PROFILECOPYRIGHT, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileCopyright", NULL}, - {TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix1", NULL}, - {TIFFTAG_FORWARDMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix2", NULL}, - {TIFFTAG_PREVIEWAPPLICATIONNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewApplicationName", NULL}, - {TIFFTAG_PREVIEWAPPLICATIONVERSION, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewApplicationVersion", NULL}, - {TIFFTAG_PREVIEWSETTINGSNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewSettingsName", NULL}, - {TIFFTAG_PREVIEWSETTINGSDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewSettingsDigest", NULL}, - {TIFFTAG_PREVIEWCOLORSPACE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewColorSpace", NULL}, - {TIFFTAG_PREVIEWDATETIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewDateTime", NULL}, - {TIFFTAG_RAWIMAGEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RawImageDigest", NULL}, - {TIFFTAG_ORIGINALRAWFILEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalRawFileDigest", NULL}, - {TIFFTAG_SUBTILEBLOCKSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubTileBlockSize", NULL}, - {TIFFTAG_ROWINTERLEAVEFACTOR, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RowInterleaveFactor", NULL}, - {TIFFTAG_PROFILELOOKTABLEDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileLookTableDims", NULL}, - {TIFFTAG_PROFILELOOKTABLEDATA, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileLookTableData", NULL}, + {TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL}, + {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL}, + {TIFFTAG_PROFILECALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "ProfileCalibrationSignature", NULL}, + {TIFFTAG_EXTRACAMERAPROFILES, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, FIELD_CUSTOM, 1, 1, "ExtraCameraProfiles", NULL}, + {TIFFTAG_ASSHOTPROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "AsShotProfileName", NULL}, + {TIFFTAG_NOISEREDUCTIONAPPLIED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "NoiseReductionApplied", NULL}, + {TIFFTAG_PROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "ProfileName", NULL}, + {TIFFTAG_PROFILEHUESATMAPDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapDims", NULL}, + {TIFFTAG_PROFILEHUESATMAPDATA1, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData1", NULL}, + {TIFFTAG_PROFILEHUESATMAPDATA2, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData2", NULL}, + {TIFFTAG_PROFILETONECURVE, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ProfileToneCurve", NULL}, + {TIFFTAG_PROFILEEMBEDPOLICY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ProfileEmbedPolicy", NULL}, + {TIFFTAG_PROFILECOPYRIGHT, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "ProfileCopyright", NULL}, + {TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ForwardMatrix1", NULL}, + {TIFFTAG_FORWARDMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ForwardMatrix2", NULL}, + {TIFFTAG_PREVIEWAPPLICATIONNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "PreviewApplicationName", NULL}, + {TIFFTAG_PREVIEWAPPLICATIONVERSION, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "PreviewApplicationVersion", NULL}, + {TIFFTAG_PREVIEWSETTINGSNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "PreviewSettingsName", NULL}, + {TIFFTAG_PREVIEWSETTINGSDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "PreviewSettingsDigest", NULL}, + {TIFFTAG_PREVIEWCOLORSPACE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "PreviewColorSpace", NULL}, + {TIFFTAG_PREVIEWDATETIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "PreviewDateTime", NULL}, + {TIFFTAG_RAWIMAGEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "RawImageDigest", NULL}, + {TIFFTAG_ORIGINALRAWFILEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "OriginalRawFileDigest", NULL}, + {TIFFTAG_SUBTILEBLOCKSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "SubTileBlockSize", NULL}, + {TIFFTAG_ROWINTERLEAVEFACTOR, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "RowInterleaveFactor", NULL}, + {TIFFTAG_PROFILELOOKTABLEDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "ProfileLookTableDims", NULL}, + {TIFFTAG_PROFILELOOKTABLEDATA, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ProfileLookTableData", NULL}, /* begin DNG 1.3.0.0 tags */ - {TIFFTAG_OPCODELIST1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList1", NULL}, - {TIFFTAG_OPCODELIST2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList2", NULL}, - {TIFFTAG_OPCODELIST3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList3", NULL}, - {TIFFTAG_NOISEPROFILE, -1, -1, TIFF_DOUBLE, 0, TIFF_SETGET_C16_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "NoiseProfile", NULL}, + {TIFFTAG_OPCODELIST1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "OpcodeList1", NULL}, + {TIFFTAG_OPCODELIST2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "OpcodeList2", NULL}, + {TIFFTAG_OPCODELIST3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "OpcodeList3", NULL}, + {TIFFTAG_NOISEPROFILE, -1, -1, TIFF_DOUBLE, 0, TIFF_SETGET_C16_DOUBLE, FIELD_CUSTOM, 1, 1, "NoiseProfile", NULL}, /* begin DNG 1.4.0.0 tags */ - {TIFFTAG_DEFAULTUSERCROP, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultUserCrop", NULL}, - {TIFFTAG_DEFAULTBLACKRENDER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultBlackRender", NULL}, - {TIFFTAG_BASELINEEXPOSUREOFFSET, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineExposureOffset", NULL}, - {TIFFTAG_PROFILELOOKTABLEENCODING, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileLookTableEncoding", NULL}, - {TIFFTAG_PROFILEHUESATMAPENCODING, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapEncoding", NULL}, - {TIFFTAG_ORIGINALDEFAULTFINALSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalDefaultFinalSize", NULL}, - {TIFFTAG_ORIGINALBESTQUALITYFINALSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalBestQualityFinalSize", NULL}, - {TIFFTAG_ORIGINALDEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalDefaultCropSize", NULL}, /* could also be rational */ - {TIFFTAG_NEWRAWIMAGEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NewRawImageDigest", NULL}, - {TIFFTAG_RAWTOPREVIEWGAIN, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RawToPreviewGain", NULL}, + {TIFFTAG_DEFAULTUSERCROP, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "DefaultUserCrop", NULL}, + {TIFFTAG_DEFAULTBLACKRENDER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "DefaultBlackRender", NULL}, + {TIFFTAG_BASELINEEXPOSUREOFFSET, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "BaselineExposureOffset", NULL}, + {TIFFTAG_PROFILELOOKTABLEENCODING, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ProfileLookTableEncoding", NULL}, + {TIFFTAG_PROFILEHUESATMAPENCODING, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapEncoding", NULL}, + {TIFFTAG_ORIGINALDEFAULTFINALSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "OriginalDefaultFinalSize", NULL}, + {TIFFTAG_ORIGINALBESTQUALITYFINALSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "OriginalBestQualityFinalSize", NULL}, + {TIFFTAG_ORIGINALDEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "OriginalDefaultCropSize", NULL}, /* could also be rational */ + {TIFFTAG_NEWRAWIMAGEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "NewRawImageDigest", NULL}, + {TIFFTAG_RAWTOPREVIEWGAIN, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "RawToPreviewGain", NULL}, /* begin DNG 1.5.0.0 tags */ - {TIFFTAG_DEPTHFORMAT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthFormat", NULL}, - {TIFFTAG_DEPTHNEAR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthNear", NULL}, - {TIFFTAG_DEPTHFAR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthFar", NULL}, - {TIFFTAG_DEPTHUNITS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthUnits", NULL}, - {TIFFTAG_DEPTHMEASURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthMeasureType", NULL}, - {TIFFTAG_ENHANCEPARAMS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EnhanceParams", NULL}, + {TIFFTAG_DEPTHFORMAT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "DepthFormat", NULL}, + {TIFFTAG_DEPTHNEAR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "DepthNear", NULL}, + {TIFFTAG_DEPTHFAR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "DepthFar", NULL}, + {TIFFTAG_DEPTHUNITS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "DepthUnits", NULL}, + {TIFFTAG_DEPTHMEASURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "DepthMeasureType", NULL}, + {TIFFTAG_ENHANCEPARAMS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "EnhanceParams", NULL}, /* begin DNG 1.6.0.0 tags */ - {TIFFTAG_PROFILEGAINTABLEMAP, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileGainTableMap", NULL}, - {TIFFTAG_SEMANTICNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SemanticName", NULL}, - {TIFFTAG_SEMANTICINSTANCEID, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SemanticInstanceID", NULL}, - {TIFFTAG_MASKSUBAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaskSubArea", NULL}, - {TIFFTAG_RGBTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "RGBTables", NULL}, - {TIFFTAG_CALIBRATIONILLUMINANT3, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant3", NULL}, - {TIFFTAG_COLORMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix3", NULL}, - {TIFFTAG_CAMERACALIBRATION3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration3", NULL}, - {TIFFTAG_REDUCTIONMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix3", NULL}, - {TIFFTAG_PROFILEHUESATMAPDATA3, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData3", NULL}, - {TIFFTAG_FORWARDMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix3", NULL}, - {TIFFTAG_ILLUMINANTDATA1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData1", NULL}, - {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL}, - {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL}, + {TIFFTAG_PROFILEGAINTABLEMAP, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "ProfileGainTableMap", NULL}, + {TIFFTAG_SEMANTICNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SemanticName", NULL}, + {TIFFTAG_SEMANTICINSTANCEID, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SemanticInstanceID", NULL}, + {TIFFTAG_MASKSUBAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "MaskSubArea", NULL}, + {TIFFTAG_RGBTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "RGBTables", NULL}, + {TIFFTAG_CALIBRATIONILLUMINANT3, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant3", NULL}, + {TIFFTAG_COLORMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ColorMatrix3", NULL}, + {TIFFTAG_CAMERACALIBRATION3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "CameraCalibration3", NULL}, + {TIFFTAG_REDUCTIONMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ReductionMatrix3", NULL}, + {TIFFTAG_PROFILEHUESATMAPDATA3, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData3", NULL}, + {TIFFTAG_FORWARDMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "ForwardMatrix3", NULL}, + {TIFFTAG_ILLUMINANTDATA1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "IlluminantData1", NULL}, + {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL}, + {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL}, /* end DNG tags */ #endif /* begin TIFF/EP tags */ - {TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL}, - {TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL}, + {TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL}, + {TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL}, #if 0 /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII. * LibTiff defines it as ASCII and converts RATIONAL to an ASCII string. */ - {TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL}, - {TIFFTAG_EP_INTERLACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP Interlace", NULL}, + {TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL}, + {TIFFTAG_EP_INTERLACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP Interlace", NULL}, /* TIFFTAG_EP_IPTC_NAA and TIFFTAG_RICHTIFFIPTC share the same tag number (33723) * LibTIFF type is UNDEFINED or BYTE, but often times incorrectly specified as LONG, because TIFF/EP (ISO/DIS 12234-2) specifies type LONG or ASCII. */ - {TIFFTAG_EP_TIMEZONEOFFSET, -1, -1, TIFF_SSHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP TimeZoneOffset", NULL}, - {TIFFTAG_EP_SELFTIMERMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SelfTimerMode", NULL}, - {TIFFTAG_EP_FLASHENERGY, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FlashEnergy", NULL}, - {TIFFTAG_EP_SPATIALFREQUENCYRESPONSE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SpatialFrequencyResponse", NULL}, - {TIFFTAG_EP_NOISE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP Noise", NULL}, - {TIFFTAG_EP_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneXResolution", NULL}, - {TIFFTAG_EP_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneYResolution", NULL}, - {TIFFTAG_EP_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneResolutionUnit", NULL}, - {TIFFTAG_EP_IMAGENUMBER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ImageNumber", NULL}, /* or SHORT */ - {TIFFTAG_EP_SECURITYCLASSIFICATION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SecurityClassification", NULL}, - {TIFFTAG_EP_IMAGEHISTORY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ImageHistory", NULL}, - {TIFFTAG_EP_EXPOSUREINDEX, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureIndex", NULL}, - {TIFFTAG_EP_STANDARDID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP StandardId", NULL}, - {TIFFTAG_EP_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SensingMethod", NULL}, + {TIFFTAG_EP_TIMEZONEOFFSET, -1, -1, TIFF_SSHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_CUSTOM, 1, 1, "EP TimeZoneOffset", NULL}, + {TIFFTAG_EP_SELFTIMERMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP SelfTimerMode", NULL}, + {TIFFTAG_EP_FLASHENERGY, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP FlashEnergy", NULL}, + {TIFFTAG_EP_SPATIALFREQUENCYRESPONSE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "EP SpatialFrequencyResponse", NULL}, + {TIFFTAG_EP_NOISE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "EP Noise", NULL}, + {TIFFTAG_EP_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "EP FocalPlaneXResolution", NULL}, + {TIFFTAG_EP_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "EP FocalPlaneYResolution", NULL}, + {TIFFTAG_EP_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP FocalPlaneResolutionUnit", NULL}, + {TIFFTAG_EP_IMAGENUMBER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "EP ImageNumber", NULL}, /* or SHORT */ + {TIFFTAG_EP_SECURITYCLASSIFICATION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "EP SecurityClassification", NULL}, + {TIFFTAG_EP_IMAGEHISTORY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "EP ImageHistory", NULL}, + {TIFFTAG_EP_EXPOSUREINDEX, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP ExposureIndex", NULL}, + {TIFFTAG_EP_STANDARDID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "EP StandardId", NULL}, + {TIFFTAG_EP_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP SensingMethod", NULL}, /* TIFF/EP tags equivalent to EXIF tags, sometimes defined differently. */ - {TIFFTAG_EP_EXPOSURETIME, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureTime", NULL}, /*N=1 or 2 */ - {TIFFTAG_EP_FNUMBER, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FNumber", NULL}, - {TIFFTAG_EP_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ExposureProgram", NULL}, - {TIFFTAG_EP_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SpectralSensitivity", NULL}, - {TIFFTAG_EP_ISOSPEEDRATINGS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ISOSpeedRatings", NULL}, - {TIFFTAG_EP_OECF, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP OptoelectricConversionFactor", NULL}, - {TIFFTAG_EP_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP DateTimeOriginal", NULL}, - {TIFFTAG_EP_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CompressedBitsPerPixel", NULL}, - {TIFFTAG_EP_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ShutterSpeedValue", NULL}, - {TIFFTAG_EP_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ApertureValue", NULL}, - {TIFFTAG_EP_BRIGHTNESSVALUE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP BrightnessValue", NULL}, - {TIFFTAG_EP_EXPOSUREBIASVALUE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureBiasValue", NULL}, /*N=1 or 2 */ - {TIFFTAG_EP_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP MaxApertureValue", NULL}, - {TIFFTAG_EP_SUBJECTDISTANCE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SubjectDistance", NULL}, - {TIFFTAG_EP_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP MeteringMode", NULL}, - {TIFFTAG_EP_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP LightSource", NULL}, - {TIFFTAG_EP_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP Flash", NULL}, - {TIFFTAG_EP_FOCALLENGTH, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FocalLength", NULL}, - {TIFFTAG_EP_SUBJECTLOCATION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SubjectLocation", NULL}, + {TIFFTAG_EP_EXPOSURETIME, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP ExposureTime", NULL}, /*N=1 or 2 */ + {TIFFTAG_EP_FNUMBER, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP FNumber", NULL}, + {TIFFTAG_EP_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP ExposureProgram", NULL}, + {TIFFTAG_EP_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "EP SpectralSensitivity", NULL}, + {TIFFTAG_EP_ISOSPEEDRATINGS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP ISOSpeedRatings", NULL}, + {TIFFTAG_EP_OECF, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, FIELD_CUSTOM, 1, 1, "EP OptoelectricConversionFactor", NULL}, + {TIFFTAG_EP_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "EP DateTimeOriginal", NULL}, + {TIFFTAG_EP_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "EP CompressedBitsPerPixel", NULL}, + {TIFFTAG_EP_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "EP ShutterSpeedValue", NULL}, + {TIFFTAG_EP_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "EP ApertureValue", NULL}, + {TIFFTAG_EP_BRIGHTNESSVALUE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP BrightnessValue", NULL}, + {TIFFTAG_EP_EXPOSUREBIASVALUE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP ExposureBiasValue", NULL}, /*N=1 or 2 */ + {TIFFTAG_EP_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "EP MaxApertureValue", NULL}, + {TIFFTAG_EP_SUBJECTDISTANCE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP SubjectDistance", NULL}, + {TIFFTAG_EP_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP MeteringMode", NULL}, + {TIFFTAG_EP_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP LightSource", NULL}, + {TIFFTAG_EP_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "EP Flash", NULL}, + {TIFFTAG_EP_FOCALLENGTH, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "EP FocalLength", NULL}, + {TIFFTAG_EP_SUBJECTLOCATION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_CUSTOM, 1, 1, "EP SubjectLocation", NULL}, /* end TIFF/EP tags */ #endif /* begin TIFF/FX tags */ - {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Indexed", NULL}, - {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GlobalParametersIFD", NULL}, - {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileType", NULL}, - {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FaxProfile", NULL}, - {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CodingMethods", NULL}, - {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "VersionYear", NULL}, - {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ModeNumber", NULL}, - {TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "Decode", NULL}, - {TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ImageBaseColor", NULL}, - {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "T82Options", NULL}, - {TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "StripRowCounts", NULL}, - {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageLayer", NULL}, + {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "Indexed", NULL}, + {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, FIELD_CUSTOM, 1, 0, "GlobalParametersIFD", NULL}, + {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ProfileType", NULL}, + {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, FIELD_CUSTOM, 1, 0, "FaxProfile", NULL}, + {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "CodingMethods", NULL}, + {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "VersionYear", NULL}, + {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, FIELD_CUSTOM, 1, 0, "ModeNumber", NULL}, + {TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, FIELD_CUSTOM, 1, 1, "Decode", NULL}, + {TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_CUSTOM, 1, 1, "ImageBaseColor", NULL}, + {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "T82Options", NULL}, + {TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, FIELD_CUSTOM, 1, 1, "StripRowCounts", NULL}, + {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, FIELD_CUSTOM, 1, 0, "ImageLayer", NULL}, /* end TIFF/FX tags */ /* begin pseudo tags */ }; @@ -348,91 +348,91 @@ static const TIFFField tiffFields[] = { * EXIF tags (Version 2.31, July 2016 plus version 2.32 May 2019) */ static const TIFFField exifFields[] = { - {EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureTime", NULL}, - {EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FNumber", NULL}, - {EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureProgram", NULL}, - {EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SpectralSensitivity", NULL}, + {EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ExposureTime", NULL}, + {EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "FNumber", NULL}, + {EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "ExposureProgram", NULL}, + {EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SpectralSensitivity", NULL}, /* After EXIF 2.2.1 ISOSpeedRatings is named PhotographicSensitivity. In addition, while "Count=Any", only 1 count should be used. */ - {EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ISOSpeedRatings", NULL}, - {EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OptoelectricConversionFactor", NULL}, - {EXIFTAG_SENSITIVITYTYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SensitivityType", NULL}, - {EXIFTAG_STANDARDOUTPUTSENSITIVITY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "StandardOutputSensitivity", NULL}, - {EXIFTAG_RECOMMENDEDEXPOSUREINDEX, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RecommendedExposureIndex", NULL}, - {EXIFTAG_ISOSPEED, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ISOSpeed", NULL}, - {EXIFTAG_ISOSPEEDLATITUDEYYY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ISOSpeedLatitudeyyy", NULL}, - {EXIFTAG_ISOSPEEDLATITUDEZZZ, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ISOSpeedLatitudezzz", NULL}, - {EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExifVersion", NULL}, - {EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeOriginal", NULL}, - {EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeDigitized", NULL}, - {EXIFTAG_OFFSETTIME, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OffsetTime", NULL}, - {EXIFTAG_OFFSETTIMEORIGINAL, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OffsetTimeOriginal", NULL}, - {EXIFTAG_OFFSETTIMEDIGITIZED, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OffsetTimeDigitized", NULL}, - {EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ComponentsConfiguration", NULL}, - {EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompressedBitsPerPixel", NULL}, - {EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShutterSpeedValue", NULL}, - {EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ApertureValue", NULL}, - {EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL}, - {EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL}, - {EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL}, + {EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_CUSTOM, 1, 1, "ISOSpeedRatings", NULL}, + {EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "OptoelectricConversionFactor", NULL}, + {EXIFTAG_SENSITIVITYTYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "SensitivityType", NULL}, + {EXIFTAG_STANDARDOUTPUTSENSITIVITY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "StandardOutputSensitivity", NULL}, + {EXIFTAG_RECOMMENDEDEXPOSUREINDEX, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "RecommendedExposureIndex", NULL}, + {EXIFTAG_ISOSPEED, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ISOSpeed", NULL}, + {EXIFTAG_ISOSPEEDLATITUDEYYY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ISOSpeedLatitudeyyy", NULL}, + {EXIFTAG_ISOSPEEDLATITUDEZZZ, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "ISOSpeedLatitudezzz", NULL}, + {EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "ExifVersion", NULL}, + {EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DateTimeOriginal", NULL}, + {EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DateTimeDigitized", NULL}, + {EXIFTAG_OFFSETTIME, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "OffsetTime", NULL}, + {EXIFTAG_OFFSETTIMEORIGINAL, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "OffsetTimeOriginal", NULL}, + {EXIFTAG_OFFSETTIMEDIGITIZED, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "OffsetTimeDigitized", NULL}, + {EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "ComponentsConfiguration", NULL}, + {EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "CompressedBitsPerPixel", NULL}, + {EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ShutterSpeedValue", NULL}, + {EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ApertureValue", NULL}, + {EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL}, + {EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL}, + {EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL}, /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! * However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values, * which are not treated within LibTiff!! */ - {EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL}, - {EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MeteringMode", NULL}, - {EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LightSource", NULL}, - {EXIFTAG_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Flash", NULL}, - {EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLength", NULL}, - {EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SubjectArea", NULL}, - {EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MakerNote", NULL}, - {EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "UserComment", NULL}, - {EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTime", NULL}, - {EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeOriginal", NULL}, - {EXIFTAG_SUBSECTIMEDIGITIZED, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeDigitized", NULL}, - {EXIFTAG_TEMPERATURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Temperature", NULL}, - {EXIFTAG_HUMIDITY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Humidity", NULL}, - {EXIFTAG_PRESSURE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Pressure", NULL}, - {EXIFTAG_WATERDEPTH, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WaterDepth", NULL}, - {EXIFTAG_ACCELERATION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Acceleration", NULL}, - {EXIFTAG_CAMERAELEVATIONANGLE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraElevationAngle", NULL}, - {EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashpixVersion", NULL}, - {EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorSpace", NULL}, - {EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelXDimension", NULL}, - {EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelYDimension", NULL}, - {EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RelatedSoundFile", NULL}, - {EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashEnergy", NULL}, - {EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SpatialFrequencyResponse", NULL}, - {EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneXResolution", NULL}, - {EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneYResolution", NULL}, - {EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneResolutionUnit", NULL}, - {EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectLocation", NULL}, - {EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureIndex", NULL}, - {EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SensingMethod", NULL}, - {EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FileSource", NULL}, - {EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneType", NULL}, - {EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CFAPattern", NULL}, - {EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CustomRendered", NULL}, - {EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureMode", NULL}, - {EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhiteBalance", NULL}, - {EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DigitalZoomRatio", NULL}, - {EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLengthIn35mmFilm", NULL}, - {EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneCaptureType", NULL}, - {EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GainControl", NULL}, - {EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Contrast", NULL}, - {EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Saturation", NULL}, - {EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Sharpness", NULL}, - {EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "DeviceSettingDescription", NULL}, - {EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistanceRange", NULL}, - {EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageUniqueID", NULL}, - {EXIFTAG_CAMERAOWNERNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraOwnerName", NULL}, - {EXIFTAG_BODYSERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BodySerialNumber", NULL}, - {EXIFTAG_LENSSPECIFICATION, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensSpecification", NULL}, - {EXIFTAG_LENSMAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensMake", NULL}, - {EXIFTAG_LENSMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensModel", NULL}, - {EXIFTAG_LENSSERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensSerialNumber", NULL}, - {EXIFTAG_GAMMA, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Gamma", NULL}, - {EXIFTAG_COMPOSITEIMAGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompositeImage", NULL}, - {EXIFTAG_SOURCEIMAGENUMBEROFCOMPOSITEIMAGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SourceImageNumberOfCompositeImage", NULL}, - {EXIFTAG_SOURCEEXPOSURETIMESOFCOMPOSITEIMAGE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, + {EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL}, + {EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "MeteringMode", NULL}, + {EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "LightSource", NULL}, + {EXIFTAG_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "Flash", NULL}, + {EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "FocalLength", NULL}, + {EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, FIELD_CUSTOM, 1, 1, "SubjectArea", NULL}, + {EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "MakerNote", NULL}, + {EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "UserComment", NULL}, + {EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SubSecTime", NULL}, + {EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SubSecTimeOriginal", NULL}, + {EXIFTAG_SUBSECTIMEDIGITIZED, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SubSecTimeDigitized", NULL}, + {EXIFTAG_TEMPERATURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "Temperature", NULL}, + {EXIFTAG_HUMIDITY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "Humidity", NULL}, + {EXIFTAG_PRESSURE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "Pressure", NULL}, + {EXIFTAG_WATERDEPTH, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "WaterDepth", NULL}, + {EXIFTAG_ACCELERATION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "Acceleration", NULL}, + {EXIFTAG_CAMERAELEVATIONANGLE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "CameraElevationAngle", NULL}, + {EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "FlashpixVersion", NULL}, + {EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "ColorSpace", NULL}, + {EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "PixelXDimension", NULL}, + {EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, FIELD_CUSTOM, 1, 0, "PixelYDimension", NULL}, + {EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "RelatedSoundFile", NULL}, + {EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "FlashEnergy", NULL}, + {EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "SpatialFrequencyResponse", NULL}, + {EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "FocalPlaneXResolution", NULL}, + {EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "FocalPlaneYResolution", NULL}, + {EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "FocalPlaneResolutionUnit", NULL}, + {EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, FIELD_CUSTOM, 1, 0, "SubjectLocation", NULL}, + {EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "ExposureIndex", NULL}, + {EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "SensingMethod", NULL}, + {EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, FIELD_CUSTOM, 1, 0, "FileSource", NULL}, + {EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, FIELD_CUSTOM, 1, 0, "SceneType", NULL}, + {EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "CFAPattern", NULL}, + {EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CustomRendered", NULL}, + {EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "ExposureMode", NULL}, + {EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "WhiteBalance", NULL}, + {EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "DigitalZoomRatio", NULL}, + {EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "FocalLengthIn35mmFilm", NULL}, + {EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "SceneCaptureType", NULL}, + {EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "GainControl", NULL}, + {EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "Contrast", NULL}, + {EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "Saturation", NULL}, + {EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "Sharpness", NULL}, + {EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "DeviceSettingDescription", NULL}, + {EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "SubjectDistanceRange", NULL}, + {EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "ImageUniqueID", NULL}, + {EXIFTAG_CAMERAOWNERNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "CameraOwnerName", NULL}, + {EXIFTAG_BODYSERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "BodySerialNumber", NULL}, + {EXIFTAG_LENSSPECIFICATION, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, FIELD_CUSTOM, 1, 0, "LensSpecification", NULL}, + {EXIFTAG_LENSMAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "LensMake", NULL}, + {EXIFTAG_LENSMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "LensModel", NULL}, + {EXIFTAG_LENSSERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "LensSerialNumber", NULL}, + {EXIFTAG_GAMMA, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, FIELD_CUSTOM, 1, 0, "Gamma", NULL}, + {EXIFTAG_COMPOSITEIMAGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "CompositeImage", NULL}, + {EXIFTAG_SOURCEIMAGENUMBEROFCOMPOSITEIMAGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, FIELD_CUSTOM, 1, 0, "SourceImageNumberOfCompositeImage", NULL}, + {EXIFTAG_SOURCEEXPOSURETIMESOFCOMPOSITEIMAGE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "SourceExposureTimesOfCompositeImage", NULL}}; /* * EXIF-GPS tags (Version 2.31, July 2016; nothing changed for version 2.32 May @@ -445,38 +445,38 @@ static const TIFFField gpsFields[] = { * In order to achieve double precision for GPS tags: Standard definitions for GPSTAG is kept to TIFF_SETGET_DOUBLE * and TIFF_SETGET_C0_FLOAT is changed to TIFF_SETGET_C0_DOUBLE. */ - {GPSTAG_VERSIONID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UINT8, FIELD_CUSTOM, 1, 0, "VersionID", NULL}, - {GPSTAG_LATITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LatitudeRef", NULL}, - {GPSTAG_LATITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Latitude", NULL}, - {GPSTAG_LONGITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LongitudeRef", NULL}, - {GPSTAG_LONGITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Longitude", NULL}, - {GPSTAG_ALTITUDEREF, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "AltitudeRef", NULL}, - {GPSTAG_ALTITUDE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Altitude", NULL}, - {GPSTAG_TIMESTAMP, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TimeStamp", NULL}, - {GPSTAG_SATELLITES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Satellites", NULL}, - {GPSTAG_STATUS, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Status", NULL}, - {GPSTAG_MEASUREMODE, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MeasureMode", NULL}, - {GPSTAG_DOP, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DOP", NULL}, - {GPSTAG_SPEEDREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SpeedRef", NULL}, - {GPSTAG_SPEED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Speed", NULL}, - {GPSTAG_TRACKREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TrackRef", NULL}, - {GPSTAG_TRACK, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Track", NULL}, - {GPSTAG_IMGDIRECTIONREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImgDirectionRef", NULL}, - {GPSTAG_IMGDIRECTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImgDirection", NULL}, - {GPSTAG_MAPDATUM, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MapDatum", NULL}, - {GPSTAG_DESTLATITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestLatitudeRef", NULL}, - {GPSTAG_DESTLATITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestLatitude", NULL}, - {GPSTAG_DESTLONGITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestLongitudeRef", NULL}, - {GPSTAG_DESTLONGITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestLongitude", NULL}, - {GPSTAG_DESTBEARINGREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestBearingRef", NULL}, - {GPSTAG_DESTBEARING, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestBearing", NULL}, - {GPSTAG_DESTDISTANCEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestDistanceRef", NULL}, - {GPSTAG_DESTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DestDistance", NULL}, - {GPSTAG_PROCESSINGMETHOD, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProcessingMethod", NULL}, - {GPSTAG_AREAINFORMATION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AreaInformation", NULL}, - {GPSTAG_DATESTAMP, 11, 11, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateStamp", NULL}, - {GPSTAG_DIFFERENTIAL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Differential", NULL}, - {GPSTAG_GPSHPOSITIONINGERROR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "HorizontalPositioningError", NULL}}; + {GPSTAG_VERSIONID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, FIELD_CUSTOM, 1, 0, "VersionID", NULL}, + {GPSTAG_LATITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "LatitudeRef", NULL}, + {GPSTAG_LATITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, FIELD_CUSTOM, 1, 0, "Latitude", NULL}, + {GPSTAG_LONGITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "LongitudeRef", NULL}, + {GPSTAG_LONGITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, FIELD_CUSTOM, 1, 0, "Longitude", NULL}, + {GPSTAG_ALTITUDEREF, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, FIELD_CUSTOM, 1, 0, "AltitudeRef", NULL}, + {GPSTAG_ALTITUDE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "Altitude", NULL}, + {GPSTAG_TIMESTAMP, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, FIELD_CUSTOM, 1, 0, "TimeStamp", NULL}, + {GPSTAG_SATELLITES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Satellites", NULL}, + {GPSTAG_STATUS, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "Status", NULL}, + {GPSTAG_MEASUREMODE, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "MeasureMode", NULL}, + {GPSTAG_DOP, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "DOP", NULL}, + {GPSTAG_SPEEDREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "SpeedRef", NULL}, + {GPSTAG_SPEED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "Speed", NULL}, + {GPSTAG_TRACKREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "TrackRef", NULL}, + {GPSTAG_TRACK, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "Track", NULL}, + {GPSTAG_IMGDIRECTIONREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "ImgDirectionRef", NULL}, + {GPSTAG_IMGDIRECTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "ImgDirection", NULL}, + {GPSTAG_MAPDATUM, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "MapDatum", NULL}, + {GPSTAG_DESTLATITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DestLatitudeRef", NULL}, + {GPSTAG_DESTLATITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, FIELD_CUSTOM, 1, 0, "DestLatitude", NULL}, + {GPSTAG_DESTLONGITUDEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DestLongitudeRef", NULL}, + {GPSTAG_DESTLONGITUDE, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_DOUBLE, FIELD_CUSTOM, 1, 0, "DestLongitude", NULL}, + {GPSTAG_DESTBEARINGREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DestBearingRef", NULL}, + {GPSTAG_DESTBEARING, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "DestBearing", NULL}, + {GPSTAG_DESTDISTANCEREF, 2, 2, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DestDistanceRef", NULL}, + {GPSTAG_DESTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "DestDistance", NULL}, + {GPSTAG_PROCESSINGMETHOD, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "ProcessingMethod", NULL}, + {GPSTAG_AREAINFORMATION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, FIELD_CUSTOM, 1, 1, "AreaInformation", NULL}, + {GPSTAG_DATESTAMP, 11, 11, TIFF_ASCII, 0, TIFF_SETGET_ASCII, FIELD_CUSTOM, 1, 0, "DateStamp", NULL}, + {GPSTAG_DIFFERENTIAL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, FIELD_CUSTOM, 1, 0, "Differential", NULL}, + {GPSTAG_GPSHPOSITIONINGERROR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, FIELD_CUSTOM, 1, 0, "HorizontalPositioningError", NULL}}; /* clang-format on */ /* was off for better readability of tag comments */ static const TIFFFieldArray tiffFieldArray = { @@ -674,18 +674,19 @@ int TIFFFieldSetGetSize(const TIFFField *fip) { /* * TIFFSetField() and TIFFGetField() must provide the parameter accordingly - * to the definition of "set_field_type" of the tag definition in + * to the definition of "set_get_field_type" of the tag definition in * dir_info.c. This function returns the data size for that purpose. * * Furthermore, this data size is also used for the internal storage, * even for TIFF_RATIONAL values for FIELD_CUSTOM, which are stored * internally as 4-byte float, but some of them should be stored internally - * as 8-byte double, depending on the "set_field_type" _FLOAT_ or _DOUBLE_. + * as 8-byte double, depending on the "set_get_field_type" _FLOAT_ or + * _DOUBLE_. */ if (fip == NULL) return 0; - switch (fip->set_field_type) + switch (fip->set_get_field_type) { case TIFF_SETGET_UNDEFINED: case TIFF_SETGET_ASCII: @@ -758,7 +759,7 @@ int TIFFFieldSetGetCountSize(const TIFFField *fip) if (fip == NULL) return 0; - switch (fip->set_field_type) + switch (fip->set_get_field_type) { case TIFF_SETGET_C16_ASCII: case TIFF_SETGET_C16_UINT8: @@ -793,7 +794,7 @@ int TIFFFieldSetGetCountSize(const TIFFField *fip) const TIFFField *TIFFFindField(TIFF *tif, uint32_t tag, TIFFDataType dt) { - TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL}; + TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, NULL, NULL}; TIFFField *pkey = &key; const TIFFField **ret; if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag && @@ -817,7 +818,7 @@ const TIFFField *TIFFFindField(TIFF *tif, uint32_t tag, TIFFDataType dt) static const TIFFField *_TIFFFindFieldByName(TIFF *tif, const char *field_name, TIFFDataType dt) { - TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL}; + TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, NULL, NULL}; TIFFField *pkey = &key; const TIFFField **ret; if (tif->tif_foundfield && @@ -915,59 +916,46 @@ TIFFField *_TIFFCreateAnonField(TIFF *tif, uint32_t tag, { case TIFF_BYTE: case TIFF_UNDEFINED: - fld->set_field_type = TIFF_SETGET_C32_UINT8; - fld->get_field_type = TIFF_SETGET_C32_UINT8; + fld->set_get_field_type = TIFF_SETGET_C32_UINT8; break; case TIFF_ASCII: - fld->set_field_type = TIFF_SETGET_C32_ASCII; - fld->get_field_type = TIFF_SETGET_C32_ASCII; + fld->set_get_field_type = TIFF_SETGET_C32_ASCII; break; case TIFF_SHORT: - fld->set_field_type = TIFF_SETGET_C32_UINT16; - fld->get_field_type = TIFF_SETGET_C32_UINT16; + fld->set_get_field_type = TIFF_SETGET_C32_UINT16; break; case TIFF_LONG: - fld->set_field_type = TIFF_SETGET_C32_UINT32; - fld->get_field_type = TIFF_SETGET_C32_UINT32; + fld->set_get_field_type = TIFF_SETGET_C32_UINT32; break; case TIFF_RATIONAL: case TIFF_SRATIONAL: case TIFF_FLOAT: - fld->set_field_type = TIFF_SETGET_C32_FLOAT; - fld->get_field_type = TIFF_SETGET_C32_FLOAT; + fld->set_get_field_type = TIFF_SETGET_C32_FLOAT; break; case TIFF_SBYTE: - fld->set_field_type = TIFF_SETGET_C32_SINT8; - fld->get_field_type = TIFF_SETGET_C32_SINT8; + fld->set_get_field_type = TIFF_SETGET_C32_SINT8; break; case TIFF_SSHORT: - fld->set_field_type = TIFF_SETGET_C32_SINT16; - fld->get_field_type = TIFF_SETGET_C32_SINT16; + fld->set_get_field_type = TIFF_SETGET_C32_SINT16; break; case TIFF_SLONG: - fld->set_field_type = TIFF_SETGET_C32_SINT32; - fld->get_field_type = TIFF_SETGET_C32_SINT32; + fld->set_get_field_type = TIFF_SETGET_C32_SINT32; break; case TIFF_DOUBLE: - fld->set_field_type = TIFF_SETGET_C32_DOUBLE; - fld->get_field_type = TIFF_SETGET_C32_DOUBLE; + fld->set_get_field_type = TIFF_SETGET_C32_DOUBLE; break; case TIFF_IFD: case TIFF_IFD8: - fld->set_field_type = TIFF_SETGET_C32_IFD8; - fld->get_field_type = TIFF_SETGET_C32_IFD8; + fld->set_get_field_type = TIFF_SETGET_C32_IFD8; break; case TIFF_LONG8: - fld->set_field_type = TIFF_SETGET_C32_UINT64; - fld->get_field_type = TIFF_SETGET_C32_UINT64; + fld->set_get_field_type = TIFF_SETGET_C32_UINT64; break; case TIFF_SLONG8: - fld->set_field_type = TIFF_SETGET_C32_SINT64; - fld->get_field_type = TIFF_SETGET_C32_SINT64; + fld->set_get_field_type = TIFF_SETGET_C32_SINT64; break; default: - fld->set_field_type = TIFF_SETGET_UNDEFINED; - fld->get_field_type = TIFF_SETGET_UNDEFINED; + fld->set_get_field_type = TIFF_SETGET_UNDEFINED; break; } fld->field_bit = FIELD_CUSTOM; @@ -1198,38 +1186,51 @@ int TIFFMergeFieldInfo(TIFF *tif, const TIFFFieldInfo info[], uint32_t n) { tp->field_tag = info[i].field_tag; if (info[i].field_readcount < TIFF_VARIABLE2 || - info[i].field_readcount == 0 || - info[i].field_writecount < TIFF_VARIABLE2 || - info[i].field_writecount == 0) + info[i].field_writecount < TIFF_VARIABLE2) { /* The fields (field_readcount) and (field_writecount) may use the * values TIFF_VARIABLE (-1), TIFF_SPP (-2), TIFF_VARIABLE2 (-3). */ - TIFFErrorExtR(tif, module, - "The value of field_readcount and field_writecount " - "must be greater than or equal to -3 and not zero."); + TIFFErrorExtR( + tif, module, + "The value of field_readcount %d and field_writecount %d " + "must be greater than or equal to -3.", + info[i].field_readcount, info[i].field_writecount); + return -1; + } + if ((info[i].field_readcount == 0 || info[i].field_writecount == 0) && + info[i].field_bit != FIELD_IGNORE) + { + /* The fields (field_readcount) and (field_writecount) may only + be zero for pseudo_tags or ignored tags. */ + TIFFErrorExtR( + tif, module, + "The value of field_readcount %d and field_writecount %d " + "may only be zero for field_bit = 0 (i.e. ignored tags).", + info[i].field_readcount, info[i].field_writecount); return -1; } tp->field_readcount = info[i].field_readcount; tp->field_writecount = info[i].field_writecount; tp->field_type = info[i].field_type; tp->field_anonymous = 0; - tp->set_field_type = + tp->set_get_field_type = _TIFFSetGetType(info[i].field_type, info[i].field_writecount, info[i].field_passcount); - tp->get_field_type = - _TIFFSetGetType(info[i].field_type, info[i].field_readcount, - info[i].field_passcount); tp->field_bit = info[i].field_bit; tp->field_oktochange = info[i].field_oktochange; tp->field_passcount = info[i].field_passcount; + /* Define an empty static string to be passed as field_name where a NULL + * pointer is passed in. Otherwise, this will lead to buffer overflow + * furtheron. */ if (info[i].field_name == NULL) { - TIFFErrorExtR(tif, module, - "Field_name of %d.th allocation tag %d is NULL", i, - info[i].field_tag); - return -1; + static const char *string_static_empty = ""; + tp->field_name = (char *)string_static_empty; + } + else + { + tp->field_name = info[i].field_name; } - tp->field_name = info[i].field_name; tp->field_subfields = NULL; tp++; } diff --git a/3rdparty/libtiff/tif_dirread.c b/3rdparty/libtiff/tif_dirread.c index 3d94ea7d4f..7f0aeb1544 100644 --- a/3rdparty/libtiff/tif_dirread.c +++ b/3rdparty/libtiff/tif_dirread.c @@ -47,6 +47,9 @@ #define TIFFCvtIEEEFloatToNative(tif, n, fp) #define TIFFCvtIEEEDoubleToNative(tif, n, dp) #else +/* If your machine does not support IEEE floating point then you will need to + * add support to tif_machdep.c to convert between the native format and + * IEEE format. */ extern void TIFFCvtIEEEFloatToNative(TIFF *, uint32_t, float *); extern void TIFFCvtIEEEDoubleToNative(TIFF *, uint32_t, double *); #endif @@ -2781,7 +2784,7 @@ TIFFReadDirEntryFloatArray(TIFF *tif, TIFFDirEntry *direntry, float **value) case TIFF_FLOAT: if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong((uint32_t *)origdata, count); - TIFFCvtIEEEDoubleToNative(tif, count, (float *)origdata); + TIFFCvtIEEEFloatToNative(tif, count, (float *)origdata); *value = (float *)origdata; return (TIFFReadDirEntryErrOk); } @@ -4310,7 +4313,6 @@ int TIFFReadDirectory(TIFF *tif) tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS; /* free any old stuff and reinit */ - (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); @@ -4403,10 +4405,13 @@ int TIFFReadDirectory(TIFF *tif) TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); if (fii == FAILED_FII) { - TIFFWarningExtR(tif, module, - "Unknown field with tag %" PRIu16 " (0x%" PRIx16 - ") encountered", - dp->tdir_tag, dp->tdir_tag); + if (tif->tif_warn_about_unknown_tags) + { + TIFFWarningExtR(tif, module, + "Unknown field with tag %" PRIu16 + " (0x%" PRIx16 ") encountered", + dp->tdir_tag, dp->tdir_tag); + } /* the following knowingly leaks the anonymous field structure */ const TIFFField *fld = _TIFFCreateAnonField( @@ -5281,6 +5286,7 @@ int TIFFReadCustomDirectory(TIFF *tif, toff_t diroff, const TIFFField *fip; uint32_t fii; + assert(infoarray != NULL); dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL); if (!dircount) { @@ -5313,7 +5319,6 @@ int TIFFReadCustomDirectory(TIFF *tif, toff_t diroff, } /* Free any old stuff and reinit. */ - (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ TIFFFreeDirectory(tif); /* Even if custom directories do not need the default settings of a standard * IFD, the pointer to the TIFFSetField() and TIFFGetField() (i.e. @@ -5344,18 +5349,25 @@ int TIFFReadCustomDirectory(TIFF *tif, toff_t diroff, TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); if (fii == FAILED_FII) { - TIFFWarningExtR(tif, module, - "Unknown field with tag %" PRIu16 " (0x%" PRIx16 - ") encountered", - dp->tdir_tag, dp->tdir_tag); + if (tif->tif_warn_about_unknown_tags) + { + TIFFWarningExtR(tif, module, + "Unknown field with tag %" PRIu16 " (0x%" PRIx16 + ") encountered", + dp->tdir_tag, dp->tdir_tag); + } const TIFFField *fld = _TIFFCreateAnonField( tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type); if (fld == NULL || !_TIFFMergeFields(tif, fld, 1)) { - TIFFWarningExtR(tif, module, - "Registering anonymous field with tag %" PRIu16 - " (0x%" PRIx16 ") failed", - dp->tdir_tag, dp->tdir_tag); + if (tif->tif_warn_about_unknown_tags) + { + TIFFWarningExtR( + tif, module, + "Registering anonymous field with tag %" PRIu16 + " (0x%" PRIx16 ") failed", + dp->tdir_tag, dp->tdir_tag); + } dp->tdir_ignore = TRUE; } else @@ -6273,19 +6285,19 @@ static int TIFFFetchNormalTag(TIFF *tif, TIFFDirEntry *dp, int recover) } fip = tif->tif_fields[fii]; assert(fip != NULL); /* should not happen */ - assert(fip->set_field_type != + assert(fip->set_get_field_type != TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with this in specialized code */ - assert(fip->set_field_type != + assert(fip->set_get_field_type != TIFF_SETGET_INT); /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */ err = TIFFReadDirEntryErrOk; - switch (fip->set_field_type) + switch (fip->set_get_field_type) { case TIFF_SETGET_UNDEFINED: TIFFErrorExtR( tif, "TIFFFetchNormalTag", - "Defined set_field_type of custom tag %u (%s) is " + "Defined set_get_field_type of custom tag %u (%s) is " "TIFF_SETGET_UNDEFINED and thus tag is not read from file", fip->field_tag, fip->field_name); break; diff --git a/3rdparty/libtiff/tif_dirwrite.c b/3rdparty/libtiff/tif_dirwrite.c index facdeaf7b1..bc5ada0f2b 100644 --- a/3rdparty/libtiff/tif_dirwrite.c +++ b/3rdparty/libtiff/tif_dirwrite.c @@ -35,6 +35,9 @@ #define TIFFCvtNativeToIEEEFloat(tif, n, fp) #define TIFFCvtNativeToIEEEDouble(tif, n, dp) #else +/* If your machine does not support IEEE floating point then you will need to + * add support to tif_machdep.c to convert between the native format and + * IEEE format. */ extern void TIFFCvtNativeToIEEEFloat(TIFF *tif, uint32_t n, float *fp); extern void TIFFCvtNativeToIEEEDouble(TIFF *tif, uint32_t n, double *dp); #endif @@ -534,6 +537,7 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, { _TIFFfreeExt(tif, tif->tif_rawdata); tif->tif_rawdata = NULL; + tif->tif_rawcp = NULL; tif->tif_rawcc = 0; tif->tif_rawdatasize = 0; tif->tif_rawdataoff = 0; @@ -562,6 +566,8 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, tif->tif_dir.td_dirdatasize_write = 0; if (isimage) { + /*-- Step 1: Process named tags for an image with FIELD bits + * associated. --*/ if (TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { if (!TIFFWriteDirectoryTagShortLong(tif, &ndir, dir, @@ -860,6 +866,10 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, if (!TIFFWriteDirectoryTagSubifd(tif, &ndir, dir)) goto bad; } + /*-- Step 2: Process named tags for an image with FIELD bits + added by a codec. + Attention: There is only code for some field_types, + which are actually used by current codecs. --*/ { uint32_t n; for (n = 0; n < tif->tif_nfields; n++) @@ -869,7 +879,7 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, if ((o->field_bit >= FIELD_CODEC) && (TIFFFieldSet(tif, o->field_bit))) { - switch (o->set_field_type) + switch (o->set_get_field_type) { case TIFF_SETGET_ASCII: { @@ -879,7 +889,7 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, assert(o->field_readcount == TIFF_VARIABLE); assert(o->field_passcount == 0); TIFFGetField(tif, o->field_tag, &pb); - pa = (uint32_t)(strlen(pb)); + pa = (uint32_t)(strlen(pb) + 1); if (!TIFFWriteDirectoryTagAscii( tif, &ndir, dir, (uint16_t)o->field_tag, pa, pb)) @@ -938,6 +948,8 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, } } } + /*-- Step 3: Process custom tags without FIELD bit for an image + * or for custom IFDs (e.g. EXIF) with !isimage. --*/ for (m = 0; m < (uint32_t)(tif->tif_dir.td_customValueCount); m++) { uint16_t tag = @@ -1008,7 +1020,8 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, case TIFF_RATIONAL: { /*-- Rational2Double: For Rationals evaluate - * "set_field_type" to determine internal storage size. */ + * "set_get_field_type" to determine internal storage size. + */ int tv_size; tv_size = TIFFFieldSetGetSize( tif->tif_dir.td_customValues[m].info); @@ -1030,11 +1043,11 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, * tv_size==4 should be set as default. */ if (tv_size != 4) { - TIFFErrorExtR(tif, - "TIFFLib: _TIFFWriteDirectorySec()", - "Rational2Double: .set_field_type is " - "not 4 but %d", - tv_size); + TIFFErrorExtR( + tif, "TIFFLib: _TIFFWriteDirectorySec()", + "Rational2Double: .set_get_field_type is " + "not 4 but %d", + tv_size); } } } @@ -1042,7 +1055,8 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, case TIFF_SRATIONAL: { /*-- Rational2Double: For Rationals evaluate - * "set_field_type" to determine internal storage size. */ + * "set_get_field_type" to determine internal storage size. + */ int tv_size; tv_size = TIFFFieldSetGetSize( tif->tif_dir.td_customValues[m].info); @@ -1064,11 +1078,11 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, * tv_size==4 should be set as default. */ if (tv_size != 4) { - TIFFErrorExtR(tif, - "TIFFLib: _TIFFWriteDirectorySec()", - "Rational2Double: .set_field_type is " - "not 4 but %d", - tv_size); + TIFFErrorExtR( + tif, "TIFFLib: _TIFFWriteDirectorySec()", + "Rational2Double: .set_get_field_type is " + "not 4 but %d", + tv_size); } } } @@ -1369,7 +1383,6 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; tif->tif_flags &= ~TIFF_DIRTYSTRIP; - (*tif->tif_cleanup)(tif); /* Reset directory-related state for subsequent directories. */ TIFFCreateDirectory(tif); } @@ -2958,7 +2971,7 @@ static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF *tif, uint32_t *ndir, EvaluateIFDdatasizeWrite(tif, count, 4, ndir); return 1; } - TIFFCvtNativeToIEEEFloat(tif, count, &value); + TIFFCvtNativeToIEEEFloat(tif, count, value); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfFloat(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_FLOAT, count, @@ -2977,7 +2990,7 @@ static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF *tif, uint32_t *ndir, EvaluateIFDdatasizeWrite(tif, count, 8, ndir); return 1; } - TIFFCvtNativeToIEEEDouble(tif, count, &value); + TIFFCvtNativeToIEEEDouble(tif, count, value); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfDouble(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_DOUBLE, count, diff --git a/3rdparty/libtiff/tif_fax3.c b/3rdparty/libtiff/tif_fax3.c index 01a784730b..34e1c7882f 100644 --- a/3rdparty/libtiff/tif_fax3.c +++ b/3rdparty/libtiff/tif_fax3.c @@ -87,6 +87,10 @@ typedef struct int EOLcnt; /* count of EOL codes recognized */ int eofReachedCount; /* number of times decode has been called with EOF already reached */ + int eolReachedCount; /* number of times decode has been called with + EOL already reached */ + int unexpectedReachedCount; /* number of times decode has been called with + "unexpedted" already reached */ TIFFFaxFillFunc fill; /* fill routine */ uint32_t *runs; /* b&w runs for current/previous row */ uint32_t nruns; /* size of the refruns / curruns arrays */ @@ -174,6 +178,8 @@ static int Fax3PreDecode(TIFF *tif, uint16_t s) sp->data = 0; sp->EOLcnt = 0; /* force initial scan for EOL */ sp->eofReachedCount = 0; + sp->eolReachedCount = 0; + sp->unexpectedReachedCount = 0; /* * Decoder assumes lsb-to-msb bit order. Note that we select * this here rather than in Fax3SetupState so that viewers can @@ -209,7 +215,12 @@ static void Fax3Unexpected(const char *module, TIFF *tif, uint32_t line, line, isTiled(tif) ? "tile" : "strip", (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0); } -#define unexpected(table, a0) Fax3Unexpected(module, tif, sp->line, a0) +#define unexpected(table, a0) \ + do \ + { \ + Fax3Unexpected(module, tif, sp->line, a0); \ + ++sp->unexpectedReachedCount; \ + } while (0) static void Fax3Extension(const char *module, TIFF *tif, uint32_t line, uint32_t a0) @@ -233,7 +244,12 @@ static void Fax3BadLength(const char *module, TIFF *tif, uint32_t line, (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0, lastx); } -#define badlength(a0, lastx) Fax3BadLength(module, tif, sp->line, a0, lastx) +#define badlength(a0, lastx) \ + do \ + { \ + Fax3BadLength(module, tif, sp->line, a0, lastx); \ + ++sp->eolReachedCount; \ + } while (0) static void Fax3PrematureEOF(const char *module, TIFF *tif, uint32_t line, uint32_t a0) @@ -251,8 +267,55 @@ static void Fax3PrematureEOF(const char *module, TIFF *tif, uint32_t line, ++sp->eofReachedCount; \ } while (0) +static void Fax3TryG3WithoutEOL(const char *module, TIFF *tif, uint32_t line, + uint32_t a0) +{ + TIFFWarningExtR( + tif, module, + "Try to decode (read) fax Group 3 data without EOL at line %" PRIu32 + " of %s %" PRIu32 " (x %" PRIu32 "). Please check result", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0); +} +#define tryG3WithoutEOL(a0) \ + do \ + { \ + Fax3TryG3WithoutEOL(module, tif, sp->line, a0); \ + } while (0) + #define Nop +static int CheckReachedCounters(TIFF *tif, const char *module, + Fax3CodecState *sp) +{ + if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) + { + TIFFErrorExtR(tif, module, + "End of file (EOF) has already been reached %d times " + "within that %s.", + sp->eofReachedCount, isTiled(tif) ? "tile" : "strip"); + return (-1); + } + if (sp->eolReachedCount >= EOF_REACHED_COUNT_THRESHOLD) + { + TIFFErrorExtR(tif, module, + "Bad line length (EOL) has already been reached %d times " + "within that %s", + sp->eolReachedCount, isTiled(tif) ? "tile" : "strip"); + return (-1); + } + if (sp->unexpectedReachedCount >= EOF_REACHED_COUNT_THRESHOLD) + { + TIFFErrorExtR(tif, module, + "Bad code word (unexpected) has already been reached %d " + "times within that %s", + sp->unexpectedReachedCount, + isTiled(tif) ? "tile" : "strip"); + return (-1); + } + return (0); +} + /** * Decode the requested amount of G3 1D-encoded data. * @param buf destination buffer @@ -269,14 +332,9 @@ static int Fax3Decode1D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } - if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) - { - TIFFErrorExtR( - tif, module, - "End of file has already been reached %d times within that strip", - sp->eofReachedCount); + if (CheckReachedCounters(tif, module, sp)) return (-1); - } +RETRY_WITHOUT_EOL_1D: CACHE_STATE(tif, sp); thisrun = sp->curruns; while (occ > 0) @@ -289,7 +347,7 @@ static int Fax3Decode1D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) printf("-------------------- %" PRIu32 "\n", tif->tif_row); fflush(stdout); #endif - SYNC_EOL(EOF1D); + SYNC_EOL(EOF1D, RETRY_WITHOUT_EOL_1D); EXPAND1D(EOF1Da); (*sp->fill)(buf, thisrun, pa, lastx); buf += sp->b.rowbytes; @@ -327,14 +385,9 @@ static int Fax3Decode2D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } - if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) - { - TIFFErrorExtR( - tif, module, - "End of file has already been reached %d times within that strip", - sp->eofReachedCount); + if (CheckReachedCounters(tif, module, sp)) return (-1); - } +RETRY_WITHOUT_EOL_2D: CACHE_STATE(tif, sp); while (occ > 0) { @@ -345,7 +398,7 @@ static int Fax3Decode2D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) printf("\nBitAcc=%08" PRIX32 ", BitsAvail = %d EOLcnt = %d", BitAcc, BitsAvail, EOLcnt); #endif - SYNC_EOL(EOF2D); + SYNC_EOL(EOF2D, RETRY_WITHOUT_EOL_2D); NeedBits8(1, EOF2D); is1D = GetBits(1); /* 1D/2D-encoding tag bit */ ClrBits(1); @@ -535,6 +588,15 @@ static int Fax3SetupState(TIFF *tif) "Bits/sample must be 1 for Group 3/4 encoding/decoding"); return (0); } + if (td->td_samplesperpixel != 1 && + td->td_planarconfig != PLANARCONFIG_SEPARATE) + { + TIFFErrorExtR( + tif, module, + "Samples/pixel shall be 1 for Group 3/4 encoding/decoding, " + "or PlanarConfiguration must be set to Separate."); + return 0; + } /* * Calculate the scanline/tile widths. */ @@ -1275,24 +1337,23 @@ static void Fax3Cleanup(TIFF *tif) #define FIELD_OPTIONS (FIELD_CODEC + 7) static const TIFFField faxFields[] = { - {TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, - FIELD_PSEUDO, FALSE, FALSE, "FaxMode", NULL}, - {TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_OTHER, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxFillFunc", NULL}, + {TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, FALSE, + FALSE, "FaxMode", NULL}, + {TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_OTHER, FIELD_PSEUDO, + FALSE, FALSE, "FaxFillFunc", NULL}, {TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, - TIFF_SETGET_UINT32, FIELD_BADFAXLINES, TRUE, FALSE, "BadFaxLines", NULL}, + FIELD_BADFAXLINES, TRUE, FALSE, "BadFaxLines", NULL}, {TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, - TIFF_SETGET_UINT16, FIELD_CLEANFAXDATA, TRUE, FALSE, "CleanFaxData", NULL}, + FIELD_CLEANFAXDATA, TRUE, FALSE, "CleanFaxData", NULL}, {TIFFTAG_CONSECUTIVEBADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, - TIFF_SETGET_UINT32, FIELD_BADFAXRUN, TRUE, FALSE, "ConsecutiveBadFaxLines", - NULL}}; + FIELD_BADFAXRUN, TRUE, FALSE, "ConsecutiveBadFaxLines", NULL}}; static const TIFFField fax3Fields[] = { {TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, - TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL}, + FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL}, }; static const TIFFField fax4Fields[] = { {TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, - TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL}, + FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL}, }; static int Fax3VSetField(TIFF *tif, uint32_t tag, va_list ap) @@ -1555,14 +1616,8 @@ static int Fax4Decode(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } - if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) - { - TIFFErrorExtR( - tif, module, - "End of file has already been reached %d times within that strip", - sp->eofReachedCount); + if (CheckReachedCounters(tif, module, sp)) return (-1); - } CACHE_STATE(tif, sp); int start = sp->line; while (occ > 0) @@ -1707,6 +1762,8 @@ static int Fax3DecodeRLE(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } + if (CheckReachedCounters(tif, module, sp)) + return (-1); CACHE_STATE(tif, sp); thisrun = sp->curruns; while (occ > 0) diff --git a/3rdparty/libtiff/tif_fax3.h b/3rdparty/libtiff/tif_fax3.h index e095009bba..c3100ce2c6 100644 --- a/3rdparty/libtiff/tif_fax3.h +++ b/3rdparty/libtiff/tif_fax3.h @@ -289,30 +289,39 @@ static const char *StateNames[] = { * is non-zero then we still need to scan for the final flag * bit that is part of the EOL code. */ -#define SYNC_EOL(eoflab) \ +#define SYNC_EOL(eoflab, retrywithouteol) \ do \ { \ - if (EOLcnt == 0) \ + if (!(sp->b.mode & FAXMODE_NOEOL)) /* skip EOL, if not present */ \ { \ + if (EOLcnt == 0) \ + { \ + for (;;) \ + { \ + NeedBits16(11, eoflab); \ + if (GetBits(11) == 0) \ + break; /* EOL found */ \ + ClrBits(1); \ + } \ + } \ + /* Now move after EOL or detect missing EOL. */ \ for (;;) \ { \ - NeedBits16(11, eoflab); \ - if (GetBits(11) == 0) \ + NeedBits8(8, noEOLFound); \ + if (GetBits(8)) \ break; \ - ClrBits(1); \ + ClrBits(8); \ } \ + while (GetBits(1) == 0) \ + ClrBits(1); \ + ClrBits(1); /* EOL bit */ \ + EOLcnt = 0; /* reset EOL counter/flag */ \ + break; /* existing EOL skipped, leave macro */ \ + noEOLFound: \ + sp->b.mode |= FAXMODE_NOEOL; \ + tryG3WithoutEOL(a0); \ + goto retrywithouteol; \ } \ - for (;;) \ - { \ - NeedBits8(8, eoflab); \ - if (GetBits(8)) \ - break; \ - ClrBits(8); \ - } \ - while (GetBits(1) == 0) \ - ClrBits(1); \ - ClrBits(1); /* EOL bit */ \ - EOLcnt = 0; /* reset EOL counter/flag */ \ } while (0) /* diff --git a/3rdparty/libtiff/tif_getimage.c b/3rdparty/libtiff/tif_getimage.c index 6c7b5031a1..9d4259ef83 100644 --- a/3rdparty/libtiff/tif_getimage.c +++ b/3rdparty/libtiff/tif_getimage.c @@ -600,6 +600,27 @@ int TIFFRGBAImageGet(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, "No \"put\" routine setupl; probably can not handle image format"); return (0); } + /* Verify raster height against image height. + * Width is checked in img->get() function individually. */ + if (0 <= img->row_offset && (uint32_t)img->row_offset < img->height) + { + uint32_t hx = img->height - img->row_offset; + if (h > hx) + { + /* Adapt parameters to read only available lines and put image + * at the bottom of the raster. */ + raster += (size_t)(h - hx) * w; + h = hx; + } + } + else + { + TIFFErrorExtR(img->tif, TIFFFileName(img->tif), + "Error in TIFFRGBAImageGet: row offset %d exceeds " + "image height %d", + img->row_offset, img->height); + return 0; + } return (*img->get)(img, raster, w, h); } @@ -614,12 +635,10 @@ int TIFFReadRGBAImageOriented(TIFF *tif, uint32_t rwidth, uint32_t rheight, TIFFRGBAImage img; int ok; - if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) + if (TIFFRGBAImageBegin(&img, tif, stop, emsg)) { img.req_orientation = (uint16_t)orientation; - /* XXX verify rwidth and rheight against width and height */ - ok = TIFFRGBAImageGet(&img, raster + (rheight - img.height) * rwidth, - rwidth, img.height); + ok = TIFFRGBAImageGet(&img, raster, rwidth, rheight); TIFFRGBAImageEnd(&img); } else @@ -726,6 +745,22 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, uint32_t leftmost_tw; tmsize_t bufsize; + /* If the raster is smaller than the image, + * or if there is a col_offset, adapt the samples to be copied per row. */ + uint32_t wmin; + + if (0 <= img->col_offset && (uint32_t)img->col_offset < img->width) + { + wmin = TIFFmin(w, img->width - img->col_offset); + } + else + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Error in gtTileContig: column offset %d exceeds " + "image width %d", + img->col_offset, img->width); + return 0; + } bufsize = TIFFTileSize(tif); if (bufsize == 0) { @@ -739,7 +774,7 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, flip = setorientation(img); if (flip & FLIP_VERTICALLY) { - if ((tw + w) > INT_MAX) + if (((int64_t)tw + w) > INT_MAX) { TIFFErrorExtR(tif, TIFFFileName(tif), "%s", "unsupported tile size (too wide)"); @@ -750,7 +785,7 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, } else { - if (tw > (INT_MAX + w)) + if (tw > ((int64_t)INT_MAX + w)) { TIFFErrorExtR(tif, TIFFFileName(tif), "%s", "unsupported tile size (too wide)"); @@ -771,7 +806,14 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, */ leftmost_fromskew = img->col_offset % tw; leftmost_tw = tw - leftmost_fromskew; - leftmost_toskew = toskew + leftmost_fromskew; + int64_t skew_i64 = (int64_t)toskew + leftmost_fromskew; + if (skew_i64 > INT_MAX || skew_i64 < INT_MIN) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s %" PRId64, "Invalid skew", + skew_i64); + return (0); + } + leftmost_toskew = (int32_t)skew_i64; for (row = 0; ret != 0 && row < h; row += nrow) { rowstoread = th - (row + img->row_offset) % th; @@ -781,7 +823,8 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, this_toskew = leftmost_toskew; tocol = 0; col = img->col_offset; - while (tocol < w) + /* wmin: only write imagewidth if raster is bigger. */ + while (tocol < wmin) { if (_TIFFReadTileAndAllocBuffer(tif, (void **)&buf, bufsize, col, row + img->row_offset, 0, @@ -793,12 +836,12 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, } pos = ((row + img->row_offset) % th) * TIFFTileRowSize(tif) + ((tmsize_t)fromskew * img->samplesperpixel); - if (tocol + this_tw > w) + if (tocol + this_tw > wmin) { /* * Rightmost tile is clipped on right side. */ - fromskew = tw - (w - tocol); + fromskew = tw - (wmin - tocol); this_tw = tw - fromskew; this_toskew = toskew + fromskew; } @@ -827,7 +870,9 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, for (line = 0; line < h; line++) { uint32_t *left = raster + (line * w); - uint32_t *right = left + w - 1; + /* Use wmin to only flip horizontally data in place and not complete + * raster-row. */ + uint32_t *right = left + wmin - 1; while (left < right) { @@ -874,6 +919,22 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, int32_t leftmost_fromskew; uint32_t leftmost_tw; + /* If the raster is smaller than the image, + * or if there is a col_offset, adapt the samples to be copied per row. */ + uint32_t wmin; + if (0 <= img->col_offset && (uint32_t)img->col_offset < img->width) + { + wmin = TIFFmin(w, img->width - img->col_offset); + } + else + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Error in gtTileSeparate: column offset %d exceeds " + "image width %d", + img->col_offset, img->width); + return 0; + } + tilesize = TIFFTileSize(tif); bufsize = _TIFFMultiplySSize(tif, alpha ? 4 : 3, tilesize, "gtTileSeparate"); @@ -888,7 +949,7 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, flip = setorientation(img); if (flip & FLIP_VERTICALLY) { - if ((tw + w) > INT_MAX) + if (((int64_t)tw + w) > INT_MAX) { TIFFErrorExtR(tif, TIFFFileName(tif), "%s", "unsupported tile size (too wide)"); @@ -899,7 +960,7 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, } else { - if (tw > (INT_MAX + w)) + if (tw > ((int64_t)INT_MAX + w)) { TIFFErrorExtR(tif, TIFFFileName(tif), "%s", "unsupported tile size (too wide)"); @@ -933,7 +994,14 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, */ leftmost_fromskew = img->col_offset % tw; leftmost_tw = tw - leftmost_fromskew; - leftmost_toskew = toskew + leftmost_fromskew; + int64_t skew_i64 = (int64_t)toskew + leftmost_fromskew; + if (skew_i64 > INT_MAX || skew_i64 < INT_MIN) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s %" PRId64, "Invalid skew", + skew_i64); + return (0); + } + leftmost_toskew = (int32_t)skew_i64; for (row = 0; ret != 0 && row < h; row += nrow) { rowstoread = th - (row + img->row_offset) % th; @@ -943,7 +1011,8 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, this_toskew = leftmost_toskew; tocol = 0; col = img->col_offset; - while (tocol < w) + /* wmin: only write imagewidth if raster is bigger. */ + while (tocol < wmin) { if (buf == NULL) { @@ -1000,14 +1069,16 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, break; } + /* For SEPARATE the pos-offset is per sample and should not be + * multiplied by img->samplesperpixel. */ pos = ((row + img->row_offset) % th) * TIFFTileRowSize(tif) + - ((tmsize_t)fromskew * img->samplesperpixel); - if (tocol + this_tw > w) + (tmsize_t)fromskew; + if (tocol + this_tw > wmin) { /* * Rightmost tile is clipped on right side. */ - fromskew = tw - (w - tocol); + fromskew = tw - (wmin - tocol); this_tw = tw - fromskew; this_toskew = toskew + fromskew; } @@ -1036,7 +1107,9 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, for (line = 0; line < h; line++) { uint32_t *left = raster + (line * w); - uint32_t *right = left + w - 1; + /* Use wmin to only flip horizontally data in place and not complete + * raster-row. */ + uint32_t *right = left + wmin - 1; while (left < right) { @@ -1071,10 +1144,28 @@ static int gtStripContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, uint16_t subsamplinghor, subsamplingver; uint32_t imagewidth = img->width; tmsize_t scanline; + /* fromskew, toskew are the increments within the input image or the raster + * from the end of a line to the start of the next line to read or write. */ int32_t fromskew, toskew; int ret = 1, flip; tmsize_t maxstripsize; + /* If the raster is smaller than the image, + * or if there is a col_offset, adapt the samples to be copied per row. */ + uint32_t wmin; + if (0 <= img->col_offset && (uint32_t)img->col_offset < imagewidth) + { + wmin = TIFFmin(w, imagewidth - img->col_offset); + } + else + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Error in gtStripContig: column offset %d exceeds " + "image width %d", + img->col_offset, imagewidth); + return 0; + } + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); if (subsamplingver == 0) @@ -1089,18 +1180,22 @@ static int gtStripContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, flip = setorientation(img); if (flip & FLIP_VERTICALLY) { - if (w > INT_MAX) + if (w > INT_MAX / 2) { TIFFErrorExtR(tif, TIFFFileName(tif), "Width overflow"); return (0); } y = h - 1; - toskew = -(int32_t)(w + w); + /* Skew back to the raster row before the currently written row + * -> one raster width plus copied image pixels. */ + toskew = -(int32_t)(w + wmin); } else { y = 0; - toskew = -(int32_t)(w - w); + /* Skew forward to the end of the raster width of the row currently + * copied. */ + toskew = w - wmin; } TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); @@ -1140,19 +1235,25 @@ static int gtStripContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, pos = ((row + img->row_offset) % rowsperstrip) * scanline + ((tmsize_t)img->col_offset * img->samplesperpixel); tmsize_t roffset = (tmsize_t)y * w; - (*put)(img, raster + roffset, 0, y, w, nrow, fromskew, toskew, + (*put)(img, raster + roffset, 0, y, wmin, nrow, fromskew, toskew, buf + pos); y += ((flip & FLIP_VERTICALLY) ? -(int32_t)nrow : (int32_t)nrow); } if (flip & FLIP_HORIZONTALLY) { + /* Flips the complete raster matrix horizontally. If raster width is + * larger than image width, data are moved horizontally to the right + * side. + * Use wmin to only flip data in place. */ uint32_t line; for (line = 0; line < h; line++) { uint32_t *left = raster + (line * w); - uint32_t *right = left + w - 1; + /* Use wmin to only flip horizontally data in place and not complete + * raster-row. */ + uint32_t *right = left + wmin - 1; while (left < right) { @@ -1194,6 +1295,22 @@ static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, int ret = 1, flip; uint16_t colorchannels; + /* If the raster is smaller than the image, + * or if there is a col_offset, adapt the samples to be copied per row. */ + uint32_t wmin; + if (0 <= img->col_offset && (uint32_t)img->col_offset < imagewidth) + { + wmin = TIFFmin(w, imagewidth - img->col_offset); + } + else + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Error in gtStripSeparate: column offset %d exceeds " + "image width %d", + img->col_offset, imagewidth); + return 0; + } + stripsize = TIFFStripSize(tif); bufsize = _TIFFMultiplySSize(tif, alpha ? 4 : 3, stripsize, "gtStripSeparate"); @@ -1205,18 +1322,22 @@ static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, flip = setorientation(img); if (flip & FLIP_VERTICALLY) { - if (w > INT_MAX) + if (w > INT_MAX / 2) { TIFFErrorExtR(tif, TIFFFileName(tif), "Width overflow"); return (0); } y = h - 1; - toskew = -(int32_t)(w + w); + /* Skew back to the raster row before the currently written row + * -> one raster width plus one image width. */ + toskew = -(int32_t)(w + wmin); } else { y = 0; - toskew = -(int32_t)(w - w); + /* Skew forward to the end of the raster width of the row currently + * written. */ + toskew = w - wmin; } switch (img->photometric) @@ -1312,11 +1433,13 @@ static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, } } + /* For SEPARATE the pos-offset is per sample and should not be + * multiplied by img->samplesperpixel. */ pos = ((row + img->row_offset) % rowsperstrip) * scanline + - ((tmsize_t)img->col_offset * img->samplesperpixel); + (tmsize_t)img->col_offset; tmsize_t roffset = (tmsize_t)y * w; - (*put)(img, raster + roffset, 0, y, w, nrow, fromskew, toskew, p0 + pos, - p1 + pos, p2 + pos, (alpha ? (pa + pos) : NULL)); + (*put)(img, raster + roffset, 0, y, wmin, nrow, fromskew, toskew, + p0 + pos, p1 + pos, p2 + pos, (alpha ? (pa + pos) : NULL)); y += ((flip & FLIP_VERTICALLY) ? -(int32_t)nrow : (int32_t)nrow); } @@ -1327,7 +1450,9 @@ static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, for (line = 0; line < h; line++) { uint32_t *left = raster + (line * w); - uint32_t *right = left + w - 1; + /* Use wmin to only flip horizontally data in place and not complete + * raster-row. */ + uint32_t *right = left + wmin - 1; while (left < right) { @@ -3140,8 +3265,8 @@ static int PickSeparateCase(TIFFRGBAImage *img) case PHOTOMETRIC_SEPARATED: if (img->bitspersample == 8 && img->samplesperpixel == 4) { - img->alpha = - 1; // Not alpha, but seems like the only way to get 4th band + /* Not alpha, but seems like the only way to get 4th band */ + img->alpha = 1; img->put.separate = putCMYKseparate8bittile; } break; @@ -3251,8 +3376,7 @@ int TIFFReadRGBAStripExt(TIFF *tif, uint32_t row, uint32_t *raster, return (0); } - if (TIFFRGBAImageOK(tif, emsg) && - TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) + if (TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) { if (row >= img.height) { @@ -3338,8 +3462,7 @@ int TIFFReadRGBATileExt(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster, * Setup the RGBA reader. */ - if (!TIFFRGBAImageOK(tif, emsg) || - !TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) + if (!TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) { TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg); return (0); diff --git a/3rdparty/libtiff/tif_jpeg.c b/3rdparty/libtiff/tif_jpeg.c index 10aed54635..aba5f99b7c 100644 --- a/3rdparty/libtiff/tif_jpeg.c +++ b/3rdparty/libtiff/tif_jpeg.c @@ -90,6 +90,7 @@ int TIFFJPEGIsFullStripRequired_12(TIFF *tif); /* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 3.0 which * adds a dual-mode 8/12 bit API in the same library. + * (note: libjpeg-turbo 2.2 was actually released as 3.0) */ #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) @@ -205,6 +206,8 @@ typedef struct int samplesperclump; JPEGOtherSettings otherSettings; + + int encode_raw_error; } JPEGState; #define JState(tif) ((JPEGState *)(tif)->tif_data) @@ -220,13 +223,13 @@ static int DecodeRowError(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s); static const TIFFField jpegFields[] = { {TIFFTAG_JPEGTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, - TIFF_SETGET_C32_UINT8, FIELD_JPEGTABLES, FALSE, TRUE, "JPEGTables", NULL}, - {TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL}, - {TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}, - {TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}}; + FIELD_JPEGTABLES, FALSE, TRUE, "JPEGTables", NULL}, + {TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + TRUE, FALSE, "", NULL}, + {TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + FALSE, FALSE, "", NULL}, + {TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + FALSE, FALSE, "", NULL}}; /* * libjpeg interface layer. @@ -1769,7 +1772,8 @@ static int JPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) { unsigned char *out_ptr = ((unsigned char *)buf) + iPair * 3; - JSAMPLE *in_ptr = (JSAMPLE *)(tmpbuf + iPair * 2); + TIFF_JSAMPLE *in_ptr = + (TIFF_JSAMPLE *)(tmpbuf + iPair * 2); out_ptr[0] = (unsigned char)((in_ptr[0] & 0xff0) >> 4); out_ptr[1] = (unsigned char)(((in_ptr[0] & 0xf) << 4) | @@ -2191,9 +2195,12 @@ static int JPEGPreEncode(TIFF *tif, uint16_t s) segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); } - if (segment_width > 65535 || segment_height > 65535) + if (segment_width > (uint32_t)JPEG_MAX_DIMENSION || + segment_height > (uint32_t)JPEG_MAX_DIMENSION) { - TIFFErrorExtR(tif, module, "Strip/tile too large for JPEG"); + TIFFErrorExtR(tif, module, + "Strip/tile too large for JPEG. Maximum dimension is %d", + (int)JPEG_MAX_DIMENSION); return (0); } sp->cinfo.c.image_width = segment_width; @@ -2300,6 +2307,7 @@ static int JPEGPreEncode(TIFF *tif, uint16_t s) return (0); } sp->scancount = 0; + sp->encode_raw_error = FALSE; return (1); } @@ -2396,6 +2404,13 @@ static int JPEGEncodeRaw(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) (void)s; assert(sp != NULL); + + if (sp->encode_raw_error) + { + TIFFErrorExtR(tif, tif->tif_name, "JPEGEncodeRaw() already failed"); + return 0; + } + /* data is expected to be supplied in multiples of a clumpline */ /* a clumpline is equivalent to v_sampling desubsampled scanlines */ /* TODO: the following calculation of bytesperclumpline, should substitute @@ -2467,7 +2482,10 @@ static int JPEGEncodeRaw(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) { int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + { + sp->encode_raw_error = TRUE; return (0); + } sp->scancount = 0; } tif->tif_row += sp->v_sampling; diff --git a/3rdparty/libtiff/tif_lerc.c b/3rdparty/libtiff/tif_lerc.c index d57b1d253d..76d1a7b440 100644 --- a/3rdparty/libtiff/tif_lerc.c +++ b/3rdparty/libtiff/tif_lerc.c @@ -93,7 +93,6 @@ typedef struct #define LERCDecoderState(tif) GetLERCState(tif) #define LERCEncoderState(tif) GetLERCState(tif) -static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); static int LERCFixupTags(TIFF *tif) @@ -222,7 +221,7 @@ static int SetupBuffers(TIFF *tif, LERCState *sp, const char *module) { TIFFErrorExtR(tif, module, "Too large uncompressed strip/tile"); _TIFFfreeExt(tif, sp->uncompressed_buffer); - sp->uncompressed_buffer = 0; + sp->uncompressed_buffer = NULL; sp->uncompressed_alloc = 0; return 0; } @@ -230,12 +229,12 @@ static int SetupBuffers(TIFF *tif, LERCState *sp, const char *module) if (sp->uncompressed_alloc < new_alloc) { _TIFFfreeExt(tif, sp->uncompressed_buffer); - sp->uncompressed_buffer = _TIFFmallocExt(tif, new_alloc); + sp->uncompressed_buffer = (uint8_t *)_TIFFmallocExt(tif, new_alloc); if (!sp->uncompressed_buffer) { TIFFErrorExtR(tif, module, "Cannot allocate buffer"); _TIFFfreeExt(tif, sp->uncompressed_buffer); - sp->uncompressed_buffer = 0; + sp->uncompressed_buffer = NULL; sp->uncompressed_alloc = 0; return 0; } @@ -267,7 +266,7 @@ static int SetupBuffers(TIFF *tif, LERCState *sp, const char *module) TIFFErrorExtR(tif, module, "Cannot allocate buffer"); sp->mask_size = 0; _TIFFfreeExt(tif, sp->uncompressed_buffer); - sp->uncompressed_buffer = 0; + sp->uncompressed_buffer = NULL; sp->uncompressed_alloc = 0; return 0; } @@ -348,7 +347,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s) return 0; } assert(lerc_data_sizet == (unsigned int)lerc_data_sizet); - lerc_data = sp->compressed_buffer; + lerc_data = (uint8_t *)sp->compressed_buffer; lerc_data_size = (unsigned int)lerc_data_sizet; #else z_stream strm; @@ -369,7 +368,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s) strm.avail_in = (uInt)tif->tif_rawcc; strm.next_in = tif->tif_rawcp; strm.avail_out = sp->compressed_size; - strm.next_out = sp->compressed_buffer; + strm.next_out = (Bytef *)sp->compressed_buffer; zlib_ret = inflate(&strm, Z_FINISH); if (zlib_ret != Z_STREAM_END && zlib_ret != Z_OK) { @@ -377,7 +376,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s) inflateEnd(&strm); return 0; } - lerc_data = sp->compressed_buffer; + lerc_data = (uint8_t *)sp->compressed_buffer; lerc_data_size = sp->compressed_size - strm.avail_out; inflateEnd(&strm); #endif @@ -396,7 +395,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s) return 0; } - lerc_data = sp->compressed_buffer; + lerc_data = (uint8_t *)sp->compressed_buffer; lerc_data_size = (unsigned int)zstd_ret; #else TIFFErrorExtR(tif, module, "ZSTD support missing"); @@ -568,7 +567,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s) { _TIFFfreeExt(tif, sp->uncompressed_buffer_multiband); sp->uncompressed_buffer_multiband = - _TIFFmallocExt(tif, num_bytes_needed); + (uint8_t *)_TIFFmallocExt(tif, num_bytes_needed); if (!sp->uncompressed_buffer_multiband) { sp->uncompressed_buffer_multiband_alloc = 0; @@ -752,7 +751,7 @@ static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) assert(sp != NULL); assert(sp->state == LSTATE_INIT_DECODE); - if (sp->uncompressed_buffer == 0) + if (sp->uncompressed_buffer == NULL) { memset(op, 0, (size_t)occ); TIFFErrorExtR(tif, module, "Uncompressed buffer not allocated"); @@ -773,6 +772,8 @@ static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) return 1; } +#ifndef LERC_READ_ONLY + static int LERCSetupEncode(TIFF *tif) { LERCState *sp = LERCEncoderState(tif); @@ -1005,7 +1006,7 @@ static int LERCPostEncode(TIFF *tif) { _TIFFfreeExt(tif, sp->uncompressed_buffer_multiband); sp->uncompressed_buffer_multiband = - _TIFFmallocExt(tif, num_bytes_needed); + (uint8_t *)_TIFFmallocExt(tif, num_bytes_needed); if (!sp->uncompressed_buffer_multiband) { sp->uncompressed_buffer_multiband_alloc = 0; @@ -1126,7 +1127,8 @@ static int LERCPostEncode(TIFF *tif) sp->uncompressed_buffer_multiband, sp->lerc_version, GetLercDataType(tif), 1, sp->segment_width, sp->segment_height, dst_nbands, dst_nbands, sp->mask_buffer, sp->maxzerror, - sp->compressed_buffer, sp->compressed_size, &numBytesWritten); + (unsigned char *)sp->compressed_buffer, sp->compressed_size, + &numBytesWritten); } else #endif @@ -1139,7 +1141,8 @@ static int LERCPostEncode(TIFF *tif) use_mask ? 1 : 0, #endif use_mask ? sp->mask_buffer : NULL, sp->maxzerror, - sp->compressed_buffer, sp->compressed_size, &numBytesWritten); + (unsigned char *)sp->compressed_buffer, sp->compressed_size, + &numBytesWritten); } if (lerc_ret != 0) { @@ -1271,7 +1274,7 @@ static int LERCPostEncode(TIFF *tif) { int ret; uint8_t *tif_rawdata_backup = tif->tif_rawdata; - tif->tif_rawdata = sp->compressed_buffer; + tif->tif_rawdata = (uint8_t *)sp->compressed_buffer; tif->tif_rawcc = numBytesWritten; ret = TIFFFlushData1(tif); tif->tif_rawdata = tif_rawdata_backup; @@ -1282,11 +1285,13 @@ static int LERCPostEncode(TIFF *tif) return 1; } +#endif /* LERC_READ_ONLY */ + static void LERCCleanup(TIFF *tif) { LERCState *sp = GetLERCState(tif); - assert(sp != 0); + assert(sp != NULL); tif->tif_tagmethods.vgetfield = sp->vgetparent; tif->tif_tagmethods.vsetfield = sp->vsetparent; @@ -1311,21 +1316,18 @@ static void LERCCleanup(TIFF *tif) static const TIFFField LERCFields[] = { {TIFFTAG_LERC_PARAMETERS, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG, 0, - TIFF_SETGET_C32_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, FALSE, TRUE, - "LercParameters", NULL}, + TIFF_SETGET_C32_UINT32, FIELD_CUSTOM, FALSE, TRUE, + (char *)"LercParameters", NULL}, {TIFFTAG_LERC_MAXZERROR, 0, 0, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "LercMaximumError", - NULL}, - {TIFFTAG_LERC_VERSION, 0, 0, TIFF_ANY, 0, TIFF_SETGET_UINT32, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "LercVersion", NULL}, + FIELD_PSEUDO, TRUE, FALSE, (char *)"LercMaximumError", NULL}, + {TIFFTAG_LERC_VERSION, 0, 0, TIFF_ANY, 0, TIFF_SETGET_UINT32, FIELD_PSEUDO, + FALSE, FALSE, (char *)"LercVersion", NULL}, {TIFFTAG_LERC_ADD_COMPRESSION, 0, 0, TIFF_ANY, 0, TIFF_SETGET_UINT32, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, - "LercAdditionalCompression", NULL}, - {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, - "ZSTD zstd_compress_level", NULL}, - {TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL}, + FIELD_PSEUDO, FALSE, FALSE, (char *)"LercAdditionalCompression", NULL}, + {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE, + FALSE, (char *)"ZSTD zstd_compress_level", NULL}, + {TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE, + FALSE, (char *)"", NULL}, }; static int LERCVSetFieldBase(TIFF *tif, uint32_t tag, ...) @@ -1517,12 +1519,14 @@ int TIFFInitLERC(TIFF *tif, int scheme) tif->tif_decoderow = LERCDecode; tif->tif_decodestrip = LERCDecode; tif->tif_decodetile = LERCDecode; +#ifndef LERC_READ_ONLY tif->tif_setupencode = LERCSetupEncode; tif->tif_preencode = LERCPreEncode; tif->tif_postencode = LERCPostEncode; tif->tif_encoderow = LERCEncode; tif->tif_encodestrip = LERCEncode; tif->tif_encodetile = LERCEncode; +#endif tif->tif_cleanup = LERCCleanup; /* Default values for codec-specific fields */ diff --git a/3rdparty/libtiff/tif_luv.c b/3rdparty/libtiff/tif_luv.c index d19653550c..ecc3225265 100644 --- a/3rdparty/libtiff/tif_luv.c +++ b/3rdparty/libtiff/tif_luv.c @@ -145,9 +145,11 @@ * quantization errors into noise. */ +#include #include #include #include +#include /* * State block for each open TIFF @@ -770,13 +772,26 @@ static int LogLuvEncodeTile(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) #undef exp2 /* Conflict with C'99 function */ #define exp2(x) exp(M_LN2 *(x)) +#define TIFF_RAND_MAX 32767 + +// From POSIX.1-2001 as an example of an implementation of rand() +static uint32_t _TIFFRand() +{ + static uint32_t nCounter = 0; + if (!nCounter) + nCounter = (uint32_t)(time(NULL) & UINT32_MAX); + ++nCounter; + uint32_t nCounterLocal = + (uint32_t)(((uint64_t)(nCounter)*1103515245U + 12345U) & UINT32_MAX); + nCounter = nCounterLocal; + return (nCounterLocal / 65536U) % (TIFF_RAND_MAX + 1); +}; + static int tiff_itrunc(double x, int m) { if (m == SGILOGENCODE_NODITHER) return (int)x; - /* Silence CoverityScan warning about bad crypto function */ - /* coverity[dont_call] */ - return (int)(x + rand() * (1. / RAND_MAX) - .5); + return (int)(x + _TIFFRand() * (1. / TIFF_RAND_MAX) - .5); } #if !LOGLUV_PUBLIC @@ -1774,10 +1789,10 @@ static int LogLuvVGetField(TIFF *tif, uint32_t tag, va_list ap) } static const TIFFField LogLuvFields[] = { - {TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogDataFmt", NULL}, - {TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogEncode", NULL}}; + {TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + TRUE, FALSE, "SGILogDataFmt", NULL}, + {TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + TRUE, FALSE, "SGILogEncode", NULL}}; int TIFFInitSGILog(TIFF *tif, int scheme) { diff --git a/3rdparty/libtiff/tif_lzma.c b/3rdparty/libtiff/tif_lzma.c index db1c8b6829..9834ae2c2c 100644 --- a/3rdparty/libtiff/tif_lzma.c +++ b/3rdparty/libtiff/tif_lzma.c @@ -450,9 +450,8 @@ static int LZMAVGetField(TIFF *tif, uint32_t tag, va_list ap) } static const TIFFField lzmaFields[] = { - {TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, - "LZMA2 Compression Preset", NULL}, + {TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE, + FALSE, "LZMA2 Compression Preset", NULL}, }; int TIFFInitLZMA(TIFF *tif, int scheme) diff --git a/3rdparty/libtiff/tif_lzw.c b/3rdparty/libtiff/tif_lzw.c index 4baf78e50b..4bf845b393 100644 --- a/3rdparty/libtiff/tif_lzw.c +++ b/3rdparty/libtiff/tif_lzw.c @@ -168,7 +168,6 @@ static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s); #ifdef LZW_COMPAT static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s); #endif -static void cl_hash(LZWCodecState *); /* * LZW Decoder. @@ -733,6 +732,7 @@ after_loop: if (occ > 0) { memset(op, 0, (size_t)occ); + sp->read_error = 1; TIFFErrorExtR(tif, module, "Not enough data at scanline %" PRIu32 " (short %" PRIu64 " bytes)", @@ -1017,6 +1017,10 @@ static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s) } #endif /* LZW_COMPAT */ +#ifndef LZW_READ_ONLY + +static void cl_hash(LZWCodecState *); + /* * LZW Encoding. */ @@ -1373,11 +1377,13 @@ static void cl_hash(LZWCodecState *sp) hp->hash = -1; } +#endif + static void LZWCleanup(TIFF *tif) { (void)TIFFPredictorCleanup(tif); - assert(tif->tif_data != 0); + assert(tif->tif_data != NULL); if (LZWDecoderState(tif)->dec_codetab) _TIFFfreeExt(tif, LZWDecoderState(tif)->dec_codetab); @@ -1416,12 +1422,14 @@ int TIFFInitLZW(TIFF *tif, int scheme) tif->tif_decoderow = LZWDecode; tif->tif_decodestrip = LZWDecode; tif->tif_decodetile = LZWDecode; +#ifndef LZW_READ_ONLY tif->tif_setupencode = LZWSetupEncode; tif->tif_preencode = LZWPreEncode; tif->tif_postencode = LZWPostEncode; tif->tif_encoderow = LZWEncode; tif->tif_encodestrip = LZWEncode; tif->tif_encodetile = LZWEncode; +#endif tif->tif_cleanup = LZWCleanup; /* * Setup predictor setup. diff --git a/3rdparty/libtiff/tif_ojpeg.c b/3rdparty/libtiff/tif_ojpeg.c index f94d2a4e45..5ef7a6af6f 100644 --- a/3rdparty/libtiff/tif_ojpeg.c +++ b/3rdparty/libtiff/tif_ojpeg.c @@ -181,26 +181,25 @@ static const TIFFField ojpegFields[] = { {TIFFTAG_JPEGIFOFFSET, 1, 1, TIFF_LONG8, 0, TIFF_SETGET_UINT64, - TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGINTERCHANGEFORMAT, TRUE, FALSE, - "JpegInterchangeFormat", NULL}, - {TIFFTAG_JPEGIFBYTECOUNT, 1, 1, TIFF_LONG8, 0, TIFF_SETGET_UINT64, - TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH, TRUE, - FALSE, "JpegInterchangeFormatLength", NULL}, - {TIFFTAG_JPEGQTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, - TIFF_SETGET_C32_UINT64, TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGQTABLES, - FALSE, TRUE, "JpegQTables", NULL}, - {TIFFTAG_JPEGDCTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, - TIFF_SETGET_C32_UINT64, TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGDCTABLES, - FALSE, TRUE, "JpegDcTables", NULL}, - {TIFFTAG_JPEGACTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, - TIFF_SETGET_C32_UINT64, TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGACTABLES, - FALSE, TRUE, "JpegAcTables", NULL}, - {TIFFTAG_JPEGPROC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, - TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGPROC, FALSE, FALSE, "JpegProc", + FIELD_OJPEG_JPEGINTERCHANGEFORMAT, TRUE, FALSE, "JpegInterchangeFormat", NULL}, + {TIFFTAG_JPEGIFBYTECOUNT, 1, 1, TIFF_LONG8, 0, TIFF_SETGET_UINT64, + FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH, TRUE, FALSE, + "JpegInterchangeFormatLength", NULL}, + {TIFFTAG_JPEGQTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, + TIFF_SETGET_C32_UINT64, FIELD_OJPEG_JPEGQTABLES, FALSE, TRUE, + "JpegQTables", NULL}, + {TIFFTAG_JPEGDCTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, + TIFF_SETGET_C32_UINT64, FIELD_OJPEG_JPEGDCTABLES, FALSE, TRUE, + "JpegDcTables", NULL}, + {TIFFTAG_JPEGACTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, + TIFF_SETGET_C32_UINT64, FIELD_OJPEG_JPEGACTABLES, FALSE, TRUE, + "JpegAcTables", NULL}, + {TIFFTAG_JPEGPROC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, + FIELD_OJPEG_JPEGPROC, FALSE, FALSE, "JpegProc", NULL}, {TIFFTAG_JPEGRESTARTINTERVAL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, - TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGRESTARTINTERVAL, FALSE, FALSE, - "JpegRestartInterval", NULL}, + FIELD_OJPEG_JPEGRESTARTINTERVAL, FALSE, FALSE, "JpegRestartInterval", + NULL}, }; #ifndef LIBJPEG_ENCAP_EXTERNAL diff --git a/3rdparty/libtiff/tif_open.c b/3rdparty/libtiff/tif_open.c index 59a07bee02..565d13cf69 100644 --- a/3rdparty/libtiff/tif_open.c +++ b/3rdparty/libtiff/tif_open.c @@ -37,7 +37,7 @@ /* * Dummy functions to fill the omitted client procedures. */ -static int _tiffDummyMapProc(thandle_t fd, void **pbase, toff_t *psize) +int _tiffDummyMapProc(thandle_t fd, void **pbase, toff_t *psize) { (void)fd; (void)pbase; @@ -45,7 +45,7 @@ static int _tiffDummyMapProc(thandle_t fd, void **pbase, toff_t *psize) return (0); } -static void _tiffDummyUnmapProc(thandle_t fd, void *base, toff_t size) +void _tiffDummyUnmapProc(thandle_t fd, void *base, toff_t size) { (void)fd; (void)base; @@ -109,6 +109,15 @@ void TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts, opts->max_cumulated_mem_alloc = max_cumulated_mem_alloc; } +/** Whether a warning should be emitted when encountering a unknown tag. + * Default is FALSE since libtiff 4.7.1 + */ +void TIFFOpenOptionsSetWarnAboutUnknownTags(TIFFOpenOptions *opts, + int warn_about_unknown_tags) +{ + opts->warn_about_unknown_tags = warn_about_unknown_tags; +} + void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, TIFFErrorHandlerExtR handler, void *errorhandler_user_data) @@ -386,6 +395,7 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode, tif->tif_warnhandler_user_data = opts->warnhandler_user_data; tif->tif_max_single_mem_alloc = opts->max_single_mem_alloc; tif->tif_max_cumulated_mem_alloc = opts->max_cumulated_mem_alloc; + tif->tif_warn_about_unknown_tags = opts->warn_about_unknown_tags; } if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) diff --git a/3rdparty/libtiff/tif_packbits.c b/3rdparty/libtiff/tif_packbits.c index 1ae50cbd47..d7db9b64ea 100644 --- a/3rdparty/libtiff/tif_packbits.c +++ b/3rdparty/libtiff/tif_packbits.c @@ -31,6 +31,8 @@ */ #include +#ifndef PACKBITS_READ_ONLY + static int PackBitsPreEncode(TIFF *tif, uint16_t s) { (void)s; @@ -78,7 +80,7 @@ static int PackBitsEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) op = tif->tif_rawcp; ep = tif->tif_rawdata + tif->tif_rawdatasize; state = BASE; - lastliteral = 0; + lastliteral = NULL; while (cc > 0) { /* @@ -231,6 +233,8 @@ static int PackBitsEncodeChunk(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) return (1); } +#endif + static int PackBitsDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { static const char module[] = "PackBitsDecode"; @@ -314,11 +318,13 @@ int TIFFInitPackBits(TIFF *tif, int scheme) tif->tif_decoderow = PackBitsDecode; tif->tif_decodestrip = PackBitsDecode; tif->tif_decodetile = PackBitsDecode; +#ifndef PACKBITS_READ_ONLY tif->tif_preencode = PackBitsPreEncode; tif->tif_postencode = PackBitsPostEncode; tif->tif_encoderow = PackBitsEncode; tif->tif_encodestrip = PackBitsEncodeChunk; tif->tif_encodetile = PackBitsEncodeChunk; +#endif return (1); } #endif /* PACKBITS_SUPPORT */ diff --git a/3rdparty/libtiff/tif_pixarlog.c b/3rdparty/libtiff/tif_pixarlog.c index 56cf416a7f..309054804d 100644 --- a/3rdparty/libtiff/tif_pixarlog.c +++ b/3rdparty/libtiff/tif_pixarlog.c @@ -1596,10 +1596,10 @@ static int PixarLogVGetField(TIFF *tif, uint32_t tag, va_list ap) } static const TIFFField pixarlogFields[] = { - {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}, - {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}}; + {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + FALSE, FALSE, "", NULL}, + {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + FALSE, FALSE, "", NULL}}; int TIFFInitPixarLog(TIFF *tif, int scheme) { diff --git a/3rdparty/libtiff/tif_predict.c b/3rdparty/libtiff/tif_predict.c index 386b5fe82a..7a6fc4af8b 100644 --- a/3rdparty/libtiff/tif_predict.c +++ b/3rdparty/libtiff/tif_predict.c @@ -30,6 +30,10 @@ #include "tif_predict.h" #include "tiffiop.h" +#if defined(__x86_64__) || defined(_M_X64) +#include +#endif + #define PredictorState(tif) ((TIFFPredictorState *)(tif)->tif_data) static int horAcc8(TIFF *tif, uint8_t *cp0, tmsize_t cc); @@ -208,16 +212,12 @@ static int PredictorSetupDecode(TIFF *tif) /* * The data should not be swapped outside of the floating * point predictor, the accumulation routine should return - * byres in the native order. + * bytes in the native order. */ if (tif->tif_flags & TIFF_SWAB) { tif->tif_postdecode = _TIFFNoPostDecode; } - /* - * Allocate buffer to keep the decoded bytes before - * rearranging in the right order - */ } return 1; @@ -305,6 +305,15 @@ static int PredictorSetupEncode(TIFF *tif) sp->encodetile = tif->tif_encodetile; tif->tif_encodetile = PredictorEncodeTile; } + /* + * The data should not be swapped outside of the floating + * point predictor, the differentiation routine should return + * bytes in the native order. + */ + if (tif->tif_flags & TIFF_SWAB) + { + tif->tif_postdecode = _TIFFNoPostDecode; + } } return 1; @@ -343,7 +352,7 @@ static int horAcc8(TIFF *tif, uint8_t *cp0, tmsize_t cc) { tmsize_t stride = PredictorState(tif)->stride; - unsigned char *cp = (unsigned char *)cp0; + uint8_t *cp = cp0; if ((cc % stride) != 0) { TIFFErrorExtR(tif, "horAcc8", "%s", "(cc%stride)!=0"); @@ -355,32 +364,48 @@ static int horAcc8(TIFF *tif, uint8_t *cp0, tmsize_t cc) /* * Pipeline the most common cases. */ - if (stride == 3) + if (stride == 1) { - unsigned int cr = cp[0]; - unsigned int cg = cp[1]; - unsigned int cb = cp[2]; + uint32_t acc = cp[0]; + tmsize_t i = stride; + for (; i < cc - 3; i += 4) + { + cp[i + 0] = (uint8_t)((acc += cp[i + 0]) & 0xff); + cp[i + 1] = (uint8_t)((acc += cp[i + 1]) & 0xff); + cp[i + 2] = (uint8_t)((acc += cp[i + 2]) & 0xff); + cp[i + 3] = (uint8_t)((acc += cp[i + 3]) & 0xff); + } + for (; i < cc; i++) + { + cp[i + 0] = (uint8_t)((acc += cp[i + 0]) & 0xff); + } + } + else if (stride == 3) + { + uint32_t cr = cp[0]; + uint32_t cg = cp[1]; + uint32_t cb = cp[2]; tmsize_t i = stride; for (; i < cc; i += stride) { - cp[i + 0] = (unsigned char)((cr += cp[i + 0]) & 0xff); - cp[i + 1] = (unsigned char)((cg += cp[i + 1]) & 0xff); - cp[i + 2] = (unsigned char)((cb += cp[i + 2]) & 0xff); + cp[i + 0] = (uint8_t)((cr += cp[i + 0]) & 0xff); + cp[i + 1] = (uint8_t)((cg += cp[i + 1]) & 0xff); + cp[i + 2] = (uint8_t)((cb += cp[i + 2]) & 0xff); } } else if (stride == 4) { - unsigned int cr = cp[0]; - unsigned int cg = cp[1]; - unsigned int cb = cp[2]; - unsigned int ca = cp[3]; + uint32_t cr = cp[0]; + uint32_t cg = cp[1]; + uint32_t cb = cp[2]; + uint32_t ca = cp[3]; tmsize_t i = stride; for (; i < cc; i += stride) { - cp[i + 0] = (unsigned char)((cr += cp[i + 0]) & 0xff); - cp[i + 1] = (unsigned char)((cg += cp[i + 1]) & 0xff); - cp[i + 2] = (unsigned char)((cb += cp[i + 2]) & 0xff); - cp[i + 3] = (unsigned char)((ca += cp[i + 3]) & 0xff); + cp[i + 0] = (uint8_t)((cr += cp[i + 0]) & 0xff); + cp[i + 1] = (uint8_t)((cg += cp[i + 1]) & 0xff); + cp[i + 2] = (uint8_t)((cb += cp[i + 2]) & 0xff); + cp[i + 3] = (uint8_t)((ca += cp[i + 3]) & 0xff); } } else @@ -389,7 +414,7 @@ static int horAcc8(TIFF *tif, uint8_t *cp0, tmsize_t cc) do { REPEAT4(stride, - cp[stride] = (unsigned char)((cp[stride] + *cp) & 0xff); + cp[stride] = (uint8_t)((cp[stride] + *cp) & 0xff); cp++) cc -= stride; } while (cc > 0); @@ -512,7 +537,7 @@ static int fpAcc(TIFF *tif, uint8_t *cp0, tmsize_t cc) uint32_t bps = tif->tif_dir.td_bitspersample / 8; tmsize_t wc = cc / bps; tmsize_t count = cc; - uint8_t *cp = (uint8_t *)cp0; + uint8_t *cp = cp0; uint8_t *tmp; if (cc % (bps * stride) != 0) @@ -525,17 +550,85 @@ static int fpAcc(TIFF *tif, uint8_t *cp0, tmsize_t cc) if (!tmp) return 0; - while (count > stride) + if (stride == 1) { - REPEAT4(stride, - cp[stride] = (unsigned char)((cp[stride] + cp[0]) & 0xff); - cp++) - count -= stride; + /* Optimization of general case */ +#define OP \ + do \ + { \ + cp[1] = (uint8_t)((cp[1] + cp[0]) & 0xff); \ + ++cp; \ + } while (0) + for (; count > 8; count -= 8) + { + OP; + OP; + OP; + OP; + OP; + OP; + OP; + OP; + } + for (; count > 1; count -= 1) + { + OP; + } +#undef OP + } + else + { + while (count > stride) + { + REPEAT4(stride, cp[stride] = (uint8_t)((cp[stride] + cp[0]) & 0xff); + cp++) + count -= stride; + } } _TIFFmemcpy(tmp, cp0, cc); cp = (uint8_t *)cp0; - for (count = 0; count < wc; count++) + count = 0; + +#if defined(__x86_64__) || defined(_M_X64) + if (bps == 4) + { + /* Optimization of general case */ + for (; count + 15 < wc; count += 16) + { + /* Interlace 4*16 byte values */ + + __m128i xmm0 = + _mm_loadu_si128((const __m128i *)(tmp + count + 3 * wc)); + __m128i xmm1 = + _mm_loadu_si128((const __m128i *)(tmp + count + 2 * wc)); + __m128i xmm2 = + _mm_loadu_si128((const __m128i *)(tmp + count + 1 * wc)); + __m128i xmm3 = + _mm_loadu_si128((const __m128i *)(tmp + count + 0 * wc)); + /* (xmm0_0, xmm1_0, xmm0_1, xmm1_1, xmm0_2, xmm1_2, ...) */ + __m128i tmp0 = _mm_unpacklo_epi8(xmm0, xmm1); + /* (xmm0_8, xmm1_8, xmm0_9, xmm1_9, xmm0_10, xmm1_10, ...) */ + __m128i tmp1 = _mm_unpackhi_epi8(xmm0, xmm1); + /* (xmm2_0, xmm3_0, xmm2_1, xmm3_1, xmm2_2, xmm3_2, ...) */ + __m128i tmp2 = _mm_unpacklo_epi8(xmm2, xmm3); + /* (xmm2_8, xmm3_8, xmm2_9, xmm3_9, xmm2_10, xmm3_10, ...) */ + __m128i tmp3 = _mm_unpackhi_epi8(xmm2, xmm3); + /* (xmm0_0, xmm1_0, xmm2_0, xmm3_0, xmm0_1, xmm1_1, xmm2_1, xmm3_1, + * ...) */ + __m128i tmp2_0 = _mm_unpacklo_epi16(tmp0, tmp2); + __m128i tmp2_1 = _mm_unpackhi_epi16(tmp0, tmp2); + __m128i tmp2_2 = _mm_unpacklo_epi16(tmp1, tmp3); + __m128i tmp2_3 = _mm_unpackhi_epi16(tmp1, tmp3); + _mm_storeu_si128((__m128i *)(cp + 4 * count + 0 * 16), tmp2_0); + _mm_storeu_si128((__m128i *)(cp + 4 * count + 1 * 16), tmp2_1); + _mm_storeu_si128((__m128i *)(cp + 4 * count + 2 * 16), tmp2_2); + _mm_storeu_si128((__m128i *)(cp + 4 * count + 3 * 16), tmp2_3); + } + } +#endif + + for (; count < wc; count++) { uint32_t byte; for (byte = 0; byte < bps; byte++) @@ -857,16 +950,38 @@ static int fpDiff(TIFF *tif, uint8_t *cp0, tmsize_t cc) static int PredictorEncodeRow(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { + static const char module[] = "PredictorEncodeRow"; TIFFPredictorState *sp = PredictorState(tif); + uint8_t *working_copy; + int result_code; assert(sp != NULL); assert(sp->encodepfunc != NULL); assert(sp->encoderow != NULL); - /* XXX horizontal differencing alters user's data XXX */ - if (!(*sp->encodepfunc)(tif, bp, cc)) + /* + * Do predictor manipulation in a working buffer to avoid altering + * the callers buffer, like for PredictorEncodeTile(). + * https://gitlab.com/libtiff/libtiff/-/issues/5 + */ + working_copy = (uint8_t *)_TIFFmallocExt(tif, cc); + if (working_copy == NULL) + { + TIFFErrorExtR(tif, module, + "Out of memory allocating %" PRId64 " byte temp buffer.", + (int64_t)cc); return 0; - return (*sp->encoderow)(tif, bp, cc, s); + } + memcpy(working_copy, bp, cc); + + if (!(*sp->encodepfunc)(tif, working_copy, cc)) + { + _TIFFfreeExt(tif, working_copy); + return 0; + } + result_code = (*sp->encoderow)(tif, working_copy, cc, s); + _TIFFfreeExt(tif, working_copy); + return result_code; } static int PredictorEncodeTile(TIFF *tif, uint8_t *bp0, tmsize_t cc0, @@ -923,7 +1038,7 @@ static int PredictorEncodeTile(TIFF *tif, uint8_t *bp0, tmsize_t cc0, static const TIFFField predictFields[] = { {TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, - TIFF_SETGET_UINT16, FIELD_PREDICTOR, FALSE, FALSE, "Predictor", NULL}, + FIELD_PREDICTOR, FALSE, FALSE, "Predictor", NULL}, }; static int PredictorVSetField(TIFF *tif, uint32_t tag, va_list ap) diff --git a/3rdparty/libtiff/tif_print.c b/3rdparty/libtiff/tif_print.c index 2b7fd1765a..addc03ab07 100644 --- a/3rdparty/libtiff/tif_print.c +++ b/3rdparty/libtiff/tif_print.c @@ -677,7 +677,8 @@ void TIFFPrintDirectory(TIFF *tif, FILE *fd, long flags) else { /*--: Rational2Double: For Rationals evaluate - * "set_field_type" to determine internal storage size. */ + * "set_get_field_type" to determine internal storage size. + */ int tv_size = TIFFFieldSetGetSize(fip); raw_data = _TIFFmallocExt(tif, tv_size * value_count); mem_alloc = 1; diff --git a/3rdparty/libtiff/tif_read.c b/3rdparty/libtiff/tif_read.c index 7efab59c6a..a2bb304623 100644 --- a/3rdparty/libtiff/tif_read.c +++ b/3rdparty/libtiff/tif_read.c @@ -351,15 +351,14 @@ static int TIFFSeek(TIFF *tif, uint32_t row, uint16_t sample) * chunk strip */ whole_strip = 1; } -#else - whole_strip = 1; -#endif if (!whole_strip) { /* 16 is for YCbCr mode where we may need to read 16 */ /* lines at a time to get a decompressed line, and 5000 */ /* is some constant value, for example for JPEG tables */ + + /* coverity[dead_error_line:SUPPRESS] */ if (tif->tif_scanlinesize < TIFF_TMSIZE_T_MAX / 16 && tif->tif_scanlinesize * 16 < TIFF_TMSIZE_T_MAX - 5000) { @@ -370,6 +369,9 @@ static int TIFFSeek(TIFF *tif, uint32_t row, uint16_t sample) read_ahead = tif->tif_scanlinesize; } } +#else + whole_strip = 1; +#endif /* * If we haven't loaded this strip, do so now, possibly @@ -383,18 +385,22 @@ static int TIFFSeek(TIFF *tif, uint32_t row, uint16_t sample) if (!TIFFFillStrip(tif, strip)) return (0); } +#if defined(CHUNKY_STRIP_READ_SUPPORT) else { if (!TIFFFillStripPartial(tif, strip, read_ahead, 1)) return 0; } +#endif } +#if defined(CHUNKY_STRIP_READ_SUPPORT) /* ** If we already have some data loaded, do we need to read some more? */ else if (!whole_strip) { + /* coverity[dead_error_line:SUPPRESS] */ if (((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) < read_ahead && (uint64_t)tif->tif_rawdataoff + tif->tif_rawdataloaded < @@ -404,6 +410,7 @@ static int TIFFSeek(TIFF *tif, uint32_t row, uint16_t sample) return 0; } } +#endif if (row < tif->tif_row) { @@ -466,7 +473,9 @@ int TIFFReadScanline(TIFF *tif, void *buf, uint32_t row, uint16_t sample) } else { - memset(buf, 0, (size_t)tif->tif_scanlinesize); + /* See TIFFReadEncodedStrip comment regarding TIFFTAG_FAXFILLFUNC. */ + if (buf) + memset(buf, 0, (size_t)tif->tif_scanlinesize); } return (e > 0 ? 1 : -1); } @@ -554,7 +563,10 @@ tmsize_t TIFFReadEncodedStrip(TIFF *tif, uint32_t strip, void *buf, stripsize = size; if (!TIFFFillStrip(tif, strip)) { - memset(buf, 0, (size_t)stripsize); + /* The output buf may be NULL, in particular if TIFFTAG_FAXFILLFUNC + is being used. Thus, memset must be conditional on buf not NULL. */ + if (buf) + memset(buf, 0, (size_t)stripsize); return ((tmsize_t)(-1)); } if ((*tif->tif_decodestrip)(tif, buf, stripsize, plane) <= 0) @@ -976,7 +988,9 @@ tmsize_t TIFFReadEncodedTile(TIFF *tif, uint32_t tile, void *buf, tmsize_t size) size = tilesize; if (!TIFFFillTile(tif, tile)) { - memset(buf, 0, (size_t)size); + /* See TIFFReadEncodedStrip comment regarding TIFFTAG_FAXFILLFUNC. */ + if (buf) + memset(buf, 0, (size_t)size); return ((tmsize_t)(-1)); } else if ((*tif->tif_decodetile)(tif, (uint8_t *)buf, size, @@ -1569,7 +1583,9 @@ int TIFFReadFromUserBuffer(TIFF *tif, uint32_t strile, void *inbuf, if (!TIFFStartTile(tif, strile)) { ret = 0; - memset(outbuf, 0, (size_t)outsize); + /* See related TIFFReadEncodedStrip comment. */ + if (outbuf) + memset(outbuf, 0, (size_t)outsize); } else if (!(*tif->tif_decodetile)( tif, (uint8_t *)outbuf, outsize, @@ -1596,7 +1612,9 @@ int TIFFReadFromUserBuffer(TIFF *tif, uint32_t strile, void *inbuf, if (!TIFFStartStrip(tif, strile)) { ret = 0; - memset(outbuf, 0, (size_t)outsize); + /* See related TIFFReadEncodedStrip comment. */ + if (outbuf) + memset(outbuf, 0, (size_t)outsize); } else if (!(*tif->tif_decodestrip)( tif, (uint8_t *)outbuf, outsize, diff --git a/3rdparty/libtiff/tif_stream.cxx b/3rdparty/libtiff/tif_stream.cxx index 92ea273c56..13ad0e2b50 100644 --- a/3rdparty/libtiff/tif_stream.cxx +++ b/3rdparty/libtiff/tif_stream.cxx @@ -87,8 +87,8 @@ extern "C" static uint64_t _tiffisSizeProc(thandle_t fd); static int _tiffosCloseProc(thandle_t fd); static int _tiffisCloseProc(thandle_t fd); - static int _tiffDummyMapProc(thandle_t, void **base, toff_t *size); - static void _tiffDummyUnmapProc(thandle_t, void *base, toff_t size); + static int _tiffDummyMapProcCxx(thandle_t, void **base, toff_t *size); + static void _tiffDummyUnmapProcCxx(thandle_t, void *base, toff_t size); static TIFF *_tiffStreamOpen(const char *name, const char *mode, void *fd); struct tiffis_data @@ -324,14 +324,14 @@ extern "C" return 0; } - static int _tiffDummyMapProc(thandle_t, void **base, toff_t *size) + static int _tiffDummyMapProcCxx(thandle_t, void **base, toff_t *size) { (void)base; (void)size; return (0); } - static void _tiffDummyUnmapProc(thandle_t, void *base, toff_t size) + static void _tiffDummyUnmapProcCxx(thandle_t, void *base, toff_t size) { (void)base; (void)size; @@ -354,7 +354,7 @@ extern "C" tif = TIFFClientOpen( name, mode, reinterpret_cast(data), _tiffosReadProc, _tiffosWriteProc, _tiffosSeekProc, _tiffosCloseProc, - _tiffosSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); + _tiffosSizeProc, _tiffDummyMapProcCxx, _tiffDummyUnmapProcCxx); if (!tif) { delete data; @@ -369,7 +369,7 @@ extern "C" tif = TIFFClientOpen( name, mode, reinterpret_cast(data), _tiffisReadProc, _tiffisWriteProc, _tiffisSeekProc, _tiffisCloseProc, - _tiffisSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); + _tiffisSizeProc, _tiffDummyMapProcCxx, _tiffDummyUnmapProcCxx); if (!tif) { delete data; diff --git a/3rdparty/libtiff/tif_strip.c b/3rdparty/libtiff/tif_strip.c index 4dbcf37e48..c9ba393669 100644 --- a/3rdparty/libtiff/tif_strip.c +++ b/3rdparty/libtiff/tif_strip.c @@ -40,7 +40,8 @@ uint32_t TIFFComputeStrip(TIFF *tif, uint32_t row, uint16_t sample) if (td->td_rowsperstrip == 0) { - TIFFErrorExtR(tif, module, "Cannot compute strip: RowsPerStrip is zero"); + TIFFErrorExtR(tif, module, + "Cannot compute strip: RowsPerStrip is zero"); return 0; } strip = row / td->td_rowsperstrip; diff --git a/3rdparty/libtiff/tif_unix.c b/3rdparty/libtiff/tif_unix.c index e65da872a3..9e6fc75b08 100644 --- a/3rdparty/libtiff/tif_unix.c +++ b/3rdparty/libtiff/tif_unix.c @@ -91,6 +91,8 @@ static tmsize_t _tiffReadProc(thandle_t fd, void *buf, tmsize_t size) } if (count < 0) return (tmsize_t)-1; + /* Silence Coverity Scan warning about unsigned to signed underflow. */ + /* coverity[return_overflow:SUPPRESS] */ return (tmsize_t)bytes_read; } @@ -120,6 +122,8 @@ static tmsize_t _tiffWriteProc(thandle_t fd, void *buf, tmsize_t size) } if (count < 0) return (tmsize_t)-1; + /* Silence Coverity Scan warning about unsigned to signed underflow. */ + /* coverity[return_overflow:SUPPRESS] */ return (tmsize_t)bytes_written; /* return ((tmsize_t) write(fdh.fd, buf, bytes_total)); */ } diff --git a/3rdparty/libtiff/tif_webp.c b/3rdparty/libtiff/tif_webp.c index ccffef0703..c06ce163b7 100644 --- a/3rdparty/libtiff/tif_webp.c +++ b/3rdparty/libtiff/tif_webp.c @@ -836,14 +836,12 @@ static int TWebPVGetField(TIFF *tif, uint32_t tag, va_list ap) } static const TIFFField TWebPFields[] = { - {TIFFTAG_WEBP_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP quality", NULL}, - {TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP lossless/lossy", - NULL}, + {TIFFTAG_WEBP_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE, + FALSE, "WEBP quality", NULL}, + {TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + TRUE, FALSE, "WEBP lossless/lossy", NULL}, {TIFFTAG_WEBP_LOSSLESS_EXACT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP exact lossless", - NULL}, + FIELD_PSEUDO, TRUE, FALSE, "WEBP exact lossless", NULL}, }; int TIFFInitWebP(TIFF *tif, int scheme) diff --git a/3rdparty/libtiff/tif_win32.c b/3rdparty/libtiff/tif_win32.c index d64ba49f0e..525cebec76 100644 --- a/3rdparty/libtiff/tif_win32.c +++ b/3rdparty/libtiff/tif_win32.c @@ -158,14 +158,6 @@ static uint64_t _tiffSizeProc(thandle_t fd) return (0); } -static int _tiffDummyMapProc(thandle_t fd, void **pbase, toff_t *psize) -{ - (void)fd; - (void)pbase; - (void)psize; - return (0); -} - /* * From "Hermann Josef Hill" : * @@ -201,13 +193,6 @@ static int _tiffMapProc(thandle_t fd, void **pbase, toff_t *psize) return (1); } -static void _tiffDummyUnmapProc(thandle_t fd, void *base, toff_t size) -{ - (void)fd; - (void)base; - (void)size; -} - static void _tiffUnmapProc(thandle_t fd, void *base, toff_t size) { (void)fd; diff --git a/3rdparty/libtiff/tif_write.c b/3rdparty/libtiff/tif_write.c index 6631a782fd..3263853cc0 100644 --- a/3rdparty/libtiff/tif_write.c +++ b/3rdparty/libtiff/tif_write.c @@ -573,8 +573,13 @@ int TIFFSetupStrips(TIFF *tif) } if (td->td_planarconfig == PLANARCONFIG_SEPARATE) td->td_stripsperimage /= td->td_samplesperpixel; + + if (td->td_stripoffset_p != NULL) + _TIFFfreeExt(tif, td->td_stripoffset_p); td->td_stripoffset_p = (uint64_t *)_TIFFCheckMalloc( tif, td->td_nstrips, sizeof(uint64_t), "for \"StripOffsets\" array"); + if (td->td_stripbytecount_p != NULL) + _TIFFfreeExt(tif, td->td_stripbytecount_p); td->td_stripbytecount_p = (uint64_t *)_TIFFCheckMalloc( tif, td->td_nstrips, sizeof(uint64_t), "for \"StripByteCounts\" array"); if (td->td_stripoffset_p == NULL || td->td_stripbytecount_p == NULL) diff --git a/3rdparty/libtiff/tif_zip.c b/3rdparty/libtiff/tif_zip.c index 2a2a1d787f..8abf88ae76 100644 --- a/3rdparty/libtiff/tif_zip.c +++ b/3rdparty/libtiff/tif_zip.c @@ -128,6 +128,16 @@ static int ZIPSetupDecode(TIFF *tif) } } +static inline uint64_t TIFF_MIN_UINT64(uint64_t a, uint64_t b) +{ + return a < b ? a : b; +} + +static inline uInt TIFF_CLAMP_UINT64_TO_INT32_MAX(uint64_t v) +{ + return (uInt)TIFF_MIN_UINT64(v, INT32_MAX); +} + /* * Setup state for decoding a strip. */ @@ -149,9 +159,7 @@ static int ZIPPreDecode(TIFF *tif, uint16_t s) we need to simplify this code to reflect a ZLib that is likely updated to deal with 8byte memory sizes, though this code will respond appropriately even before we simplify it */ - sp->stream.avail_in = (uint64_t)tif->tif_rawcc < 0xFFFFFFFFU - ? (uInt)tif->tif_rawcc - : 0xFFFFFFFFU; + sp->stream.avail_in = TIFF_CLAMP_UINT64_TO_INT32_MAX(tif->tif_rawcc); if (inflateReset(&sp->stream) == Z_OK) { sp->read_error = 0; @@ -267,14 +275,10 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) do { int state; - uInt avail_in_before = (uint64_t)tif->tif_rawcc <= 0xFFFFFFFFU - ? (uInt)tif->tif_rawcc - : 0xFFFFFFFFU; - uInt avail_out_before = - (uint64_t)occ < 0xFFFFFFFFU ? (uInt)occ : 0xFFFFFFFFU; + uInt avail_in_before = TIFF_CLAMP_UINT64_TO_INT32_MAX(tif->tif_rawcc); + uInt avail_out_before = TIFF_CLAMP_UINT64_TO_INT32_MAX(occ); sp->stream.avail_in = avail_in_before; sp->stream.avail_out = avail_out_before; - /* coverity[overrun-buffer-arg] */ state = inflate(&sp->stream, Z_PARTIAL_FLUSH); tif->tif_rawcc -= (avail_in_before - sp->stream.avail_in); occ -= (avail_out_before - sp->stream.avail_out); @@ -282,7 +286,7 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) break; if (state == Z_DATA_ERROR) { - memset(sp->stream.next_out, 0, sp->stream.avail_out); + memset(sp->stream.next_out, 0, (size_t)occ); TIFFErrorExtR(tif, module, "Decoding error at scanline %lu, %s", (unsigned long)tif->tif_row, SAFE_MSG(sp)); sp->read_error = 1; @@ -290,7 +294,7 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) } if (state != Z_OK) { - memset(sp->stream.next_out, 0, sp->stream.avail_out); + memset(sp->stream.next_out, 0, (size_t)occ); TIFFErrorExtR(tif, module, "ZLib error: %s", SAFE_MSG(sp)); sp->read_error = 1; return (0); @@ -302,7 +306,7 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) "Not enough data at scanline %lu (short %" PRIu64 " bytes)", (unsigned long)tif->tif_row, (uint64_t)occ); - memset(sp->stream.next_out, 0, sp->stream.avail_out); + memset(sp->stream.next_out, 0, (size_t)occ); sp->read_error = 1; return (0); } @@ -481,10 +485,8 @@ static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) appropriately even before we simplify it */ do { - uInt avail_in_before = - (uint64_t)cc <= 0xFFFFFFFFU ? (uInt)cc : 0xFFFFFFFFU; + uInt avail_in_before = TIFF_CLAMP_UINT64_TO_INT32_MAX(cc); sp->stream.avail_in = avail_in_before; - /* coverity[overrun-buffer-arg] */ if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { TIFFErrorExtR(tif, module, "Encoder error: %s", SAFE_MSG(sp)); @@ -496,9 +498,8 @@ static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) if (!TIFFFlushData1(tif)) return 0; sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = (uint64_t)tif->tif_rawdatasize <= 0xFFFFFFFFU - ? (uInt)tif->tif_rawdatasize - : 0xFFFFFFFFU; + sp->stream.avail_out = + TIFF_CLAMP_UINT64_TO_INT32_MAX(tif->tif_rawdatasize); } cc -= (avail_in_before - sp->stream.avail_in); } while (cc > 0); @@ -672,12 +673,31 @@ static int ZIPVGetField(TIFF *tif, uint32_t tag, va_list ap) } static const TIFFField zipFields[] = { - {TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL}, - {TIFFTAG_DEFLATE_SUBCODEC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL}, + {TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE, + FALSE, "", NULL}, + {TIFFTAG_DEFLATE_SUBCODEC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, + TRUE, FALSE, "", NULL}, }; +static void *TIFF_zalloc(void *opaque, unsigned int items, unsigned int size) +{ + static const char module[] = "TIFF_zalloc"; + TIFF *tif = opaque; + + if (items > ~(size_t)0 / size) + { + TIFFErrorExtR(tif, module, "Overflow"); + return NULL; + } + + return _TIFFmallocExt(tif, items * size); +} + +static void TIFF_zfree(void *opaque, void *ptr) +{ + _TIFFfreeExt((TIFF *)opaque, ptr); +} + int TIFFInitZIP(TIFF *tif, int scheme) { static const char module[] = "TIFFInitZIP"; @@ -706,9 +726,9 @@ int TIFFInitZIP(TIFF *tif, int scheme) if (tif->tif_data == NULL) goto bad; sp = GetZIPState(tif); - sp->stream.zalloc = NULL; - sp->stream.zfree = NULL; - sp->stream.opaque = NULL; + sp->stream.zalloc = TIFF_zalloc; + sp->stream.zfree = TIFF_zfree; + sp->stream.opaque = tif; sp->stream.data_type = Z_BINARY; /* diff --git a/3rdparty/libtiff/tif_zstd.c b/3rdparty/libtiff/tif_zstd.c index fc73ce9cf5..c828dbf743 100644 --- a/3rdparty/libtiff/tif_zstd.c +++ b/3rdparty/libtiff/tif_zstd.c @@ -363,9 +363,8 @@ static int ZSTDVGetField(TIFF *tif, uint32_t tag, va_list ap) } static const TIFFField ZSTDFields[] = { - {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, - TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "ZSTD compression_level", - NULL}, + {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE, + FALSE, "ZSTD compression_level", NULL}, }; int TIFFInitZSTD(TIFF *tif, int scheme) diff --git a/3rdparty/libtiff/tiff.h b/3rdparty/libtiff/tiff.h index d8da33dc38..980e8e8f52 100644 --- a/3rdparty/libtiff/tiff.h +++ b/3rdparty/libtiff/tiff.h @@ -216,6 +216,7 @@ typedef enum #define COMPRESSION_ZSTD 50000 /* ZSTD: WARNING not registered in Adobe-maintained registry */ #define COMPRESSION_WEBP 50001 /* WEBP: WARNING not registered in Adobe-maintained registry */ #define COMPRESSION_JXL 50002 /* JPEGXL: WARNING not registered in Adobe-maintained registry */ +#define COMPRESSION_JXL_DNG_1_7 52546 /* JPEGXL from DNG 1.7 specification */ #define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ #define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ #define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ diff --git a/3rdparty/libtiff/tiffconf.h.cmake.in b/3rdparty/libtiff/tiffconf.h.cmake.in index 306874f5a7..a5789bbb0a 100644 --- a/3rdparty/libtiff/tiffconf.h.cmake.in +++ b/3rdparty/libtiff/tiffconf.h.cmake.in @@ -89,7 +89,7 @@ /* Support NeXT 2-bit RLE algorithm */ #cmakedefine NEXT_SUPPORT 1 -/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation +/* Support Old JPEG compression (read contrib/ojpeg/README first! Compilation fails with unpatched IJG JPEG library) */ #cmakedefine OJPEG_SUPPORT 1 diff --git a/3rdparty/libtiff/tiffio.h b/3rdparty/libtiff/tiffio.h index 225f3c1bfe..f9c206e32a 100644 --- a/3rdparty/libtiff/tiffio.h +++ b/3rdparty/libtiff/tiffio.h @@ -45,12 +45,14 @@ typedef struct tiff TIFF; * to pass tag types and values uses the types defined in * tiff.h directly. * - * NB: ttag_t is unsigned int and not unsigned short because + * NB: ttag_t -> deprecated and replaced by uint32_t + * is unsigned int and not unsigned short because * ANSI C requires that the type before the ellipsis be a * promoted type (i.e. one of int, unsigned int, pointer, * or double) and because we defined pseudo-tags that are * outside the range of legal Aldus-assigned tags. - * NB: tsize_t is signed and not unsigned because some functions + * NB: tsize_t -> deprecated and replaced by tmsize_t + * is signed and not unsigned because some functions * return -1. * NB: toff_t is not off_t for many reasons; TIFFs max out at * 32-bit file offsets, and BigTIFF maxes out at 64-bit @@ -66,10 +68,11 @@ typedef TIFF_SSIZE_T tmsize_t; #define TIFF_TMSIZE_T_MAX (tmsize_t)(SIZE_MAX >> 1) typedef uint64_t toff_t; /* file offset */ +typedef uint32_t tdir_t; /* directory index */ + /* the following are deprecated and should be replaced by their defining counterparts */ typedef uint32_t ttag_t; /* directory tag */ -typedef uint32_t tdir_t; /* directory index */ typedef uint16_t tsample_t; /* sample number */ typedef uint32_t tstrile_t; /* strip or tile number */ typedef tstrile_t tstrip_t; /* strip number */ @@ -151,6 +154,18 @@ typedef struct float d_gammaB; } TIFFDisplay; +/* YCbCr->RGB support for TIFFYCbCrToRGBInit() and TIFFYCbCrToRGB() + * Attention: + * Functions TIFFYCbCrToRGBInit() and TIFFYCbCrToRGB() require a user provided + * large memory buffer, where several tables can be setup. + * The pointers to these tables are stored in the structure TIFFYCbCrToRGB, + * which is located at the beginning of the buffer. Thus, this memory has to be + * allocated as follows: + * TIFFYCbCrToRGB *ycbcr = (TIFFYCbCrToRGB *)_TIFFmalloc( + * TIFFroundup_32(sizeof(TIFFYCbCrToRGB), sizeof(long)) + + * 4 * 256 * sizeof(TIFFRGBValue) + 2 * 256 * sizeof(int) + + * 3 * 256 * sizeof(int32_t)); + */ typedef struct { /* YCbCr->RGB support */ TIFFRGBValue *clamptab; /* range clamping table */ @@ -508,6 +523,9 @@ extern int TIFFReadRGBAImageOriented(TIFF *, uint32_t, uint32_t, uint32_t *, TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts, tmsize_t max_cumulated_mem_alloc); extern void + TIFFOpenOptionsSetWarnAboutUnknownTags(TIFFOpenOptions *opts, + int warn_about_unknown_tags); + extern void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, TIFFErrorHandlerExtR handler, void *errorhandler_user_data); @@ -590,7 +608,7 @@ extern int TIFFReadRGBAImageOriented(TIFF *, uint32_t, uint32_t, uint32_t *, extern uint64_t TIFFGetStrileByteCountWithErr(TIFF *tif, uint32_t strile, int *pbErr); -#ifdef LOGLUV_PUBLIC +#if LOGLUV_PUBLIC #define U_NEU 0.210526316 #define V_NEU 0.473684211 #define UVSCALE 410. @@ -634,7 +652,7 @@ extern int TIFFReadRGBAImageOriented(TIFF *, uint32_t, uint32_t, uint32_t *, ****************************************************************************/ typedef struct { - ttag_t field_tag; /* field's tag */ + uint32_t field_tag; /* field's tag */ short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ short field_writecount; /* write count/TIFF_VARIABLE */ TIFFDataType field_type; /* type of associated data */ diff --git a/3rdparty/libtiff/tiffiop.h b/3rdparty/libtiff/tiffiop.h index c4348206df..80c04c279b 100644 --- a/3rdparty/libtiff/tiffiop.h +++ b/3rdparty/libtiff/tiffiop.h @@ -258,6 +258,7 @@ struct tiff tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */ tmsize_t tif_max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */ tmsize_t tif_cur_cumulated_mem_alloc; /* in bytes */ + int tif_warn_about_unknown_tags; }; struct TIFFOpenOptions @@ -268,6 +269,7 @@ struct TIFFOpenOptions void *warnhandler_user_data; /* may be NULL */ tmsize_t max_single_mem_alloc; /* in bytes. 0 for unlimited */ tmsize_t max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */ + int warn_about_unknown_tags; }; #define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ @@ -398,6 +400,8 @@ typedef size_t TIFFIOSize_t; extern "C" { #endif + extern int _tiffDummyMapProc(thandle_t fd, void **pbase, toff_t *psize); + extern void _tiffDummyUnmapProc(thandle_t fd, void *base, toff_t size); extern int _TIFFgetMode(TIFFOpenOptions *opts, thandle_t clientdata, const char *mode, const char *module); extern int _TIFFNoRowEncode(TIFF *tif, uint8_t *pp, tmsize_t cc, diff --git a/cmake/OpenCVCompilerDefenses.cmake b/cmake/OpenCVCompilerDefenses.cmake index 9fffdb4d72..bc450b150d 100644 --- a/cmake/OpenCVCompilerDefenses.cmake +++ b/cmake/OpenCVCompilerDefenses.cmake @@ -41,7 +41,7 @@ if(MSVC) ocv_add_defense_compiler_flag("/guard:cf") ocv_add_defense_compiler_flag("/w34018 /w34146 /w34244 /w34267 /w34302 /w34308 /w34509 /w34532 /w34533 /w34700 /w34789 /w34995 /w34996") set(OPENCV_LINKER_DEFENSES_FLAGS_COMMON "${OPENCV_LINKER_DEFENSES_FLAGS_COMMON} /guard:cf /dynamicbase" ) - if(NOT X86_64) + if(X86) set(OPENCV_LINKER_DEFENSES_FLAGS_COMMON "${OPENCV_LINKER_DEFENSES_FLAGS_COMMON} /safeseh") endif() elseif(CV_CLANG) diff --git a/cmake/OpenCVFindLAPACK.cmake b/cmake/OpenCVFindLAPACK.cmake index 99132aab0a..4071d501ce 100644 --- a/cmake/OpenCVFindLAPACK.cmake +++ b/cmake/OpenCVFindLAPACK.cmake @@ -200,7 +200,7 @@ if(WITH_LAPACK) CBLAS_H "cblas.h" LAPACKE_H "lapacke.h" INCLUDE_DIR "${OpenBLAS_INCLUDE_DIRS}" - LIBRARIES "${OpenBLAS_LIBRARIES}") + LIBRARIES "${OpenBLAS_LIBRARY};${OpenBLAS_LIBRARIES}") endif() endif() if(NOT LAPACK_LIBRARIES AND UNIX) diff --git a/doc/opencv.bib b/doc/opencv.bib index 64f5fa9715..1910795b16 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -1616,3 +1616,12 @@ volume = {8}, url = {https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=1fbd43f3827fffeb76641a9c5ab5b625eb5a75ba} } +@article{Aggarwal1985, + author = {Aggarwal, A. and Chang, J. and Yap, Chee K.}, + title = {Minimum area circumscribing Polygons}, + year = {1985}, + pages = {112--117}, + journal = {The Visual Computer}, + volume = {7}, + url = {https://doi.org/10.1007/BF01898354} +} diff --git a/doc/pattern_tools/gen_pattern.py b/doc/pattern_tools/gen_pattern.py index f426bb11c5..61d4e6839a 100755 --- a/doc/pattern_tools/gen_pattern.py +++ b/doc/pattern_tools/gen_pattern.py @@ -16,6 +16,7 @@ python gen_pattern.py -o out.svg -r 11 -c 8 -T circles -s 20.0 -R 5.0 -u mm -w 2 -m, --markers - list of cells with markers for the radon checkerboard -p, --aruco_marker_size - aruco markers size for ChAruco pattern (default 10.0) -f, --dict_file - file name of custom aruco dictionary for ChAruco pattern +-do, --dict_offset - index of the first ArUco index used -H, --help - show help """ @@ -27,7 +28,7 @@ from svgfig import * class PatternMaker: - def __init__(self, cols, rows, output, units, square_size, radius_rate, page_width, page_height, markers, aruco_marker_size, dict_file): + def __init__(self, cols, rows, output, units, square_size, radius_rate, page_width, page_height, markers, aruco_marker_size, dict_file, dict_offset): self.cols = cols self.rows = rows self.output = output @@ -39,6 +40,7 @@ class PatternMaker: self.markers = markers self.aruco_marker_size = aruco_marker_size #for charuco boards only self.dict_file = dict_file + self.dict_offset = dict_offset self.g = SVG("g") # the svg group container @@ -188,7 +190,7 @@ class PatternMaker: ch_ar_border = (self.square_size - self.aruco_marker_size)/2 if ch_ar_border < side*0.7: print("Marker border {} is less than 70% of ArUco pin size {}. Please increase --square_size or decrease --marker_size for stable board detection".format(ch_ar_border, int(side))) - marker_id = 0 + marker_id = self.dict_offset for y in range(0, self.rows): for x in range(0, self.cols): @@ -248,6 +250,8 @@ def main(): action="store", dest="aruco_marker_size", type=float) parser.add_argument("-f", "--dict_file", help="file name of custom aruco dictionary for ChAruco pattern", default="DICT_ARUCO_ORIGINAL.json", action="store", dest="dict_file", type=str) + parser.add_argument("-do", "--dict_offset", help="index of the first ArUco index used", default=0, + action="store", dest="dict_offset", type=int) args = parser.parse_args() show_help = args.show_help @@ -263,6 +267,7 @@ def main(): radius_rate = args.radius_rate aruco_marker_size = args.aruco_marker_size dict_file = args.dict_file + dict_offset = args.dict_offset if 'page_width' and 'page_height' in args: page_width = args.page_width @@ -288,7 +293,7 @@ def main(): if p_type == "charuco_board" and aruco_marker_size >= square_size: raise ValueError("ArUco markers size must be smaller than square size") - pm = PatternMaker(columns, rows, output, units, square_size, radius_rate, page_width, page_height, markers, aruco_marker_size, dict_file) + pm = PatternMaker(columns, rows, output, units, square_size, radius_rate, page_width, page_height, markers, aruco_marker_size, dict_file, dict_offset) # dict for easy lookup of pattern type mp = {"circles": pm.make_circles_pattern, "acircles": pm.make_acircles_pattern, "checkerboard": pm.make_checkerboard_pattern, "radon_checkerboard": pm.make_radon_checkerboard_pattern, diff --git a/doc/pattern_tools/test_charuco_board.py b/doc/pattern_tools/test_charuco_board.py index 9eca7b1480..31b90e67a5 100644 --- a/doc/pattern_tools/test_charuco_board.py +++ b/doc/pattern_tools/test_charuco_board.py @@ -44,7 +44,7 @@ class aruco_objdetect_test(NewOpenCVTests): basedir = os.path.abspath(os.path.dirname(__file__)) pm = gen_pattern.PatternMaker(cols, rows, filesvg, "px", square_size, 0, board_width, board_height, "charuco_checkboard", marker_size, - os.path.join(basedir, aruco_type_str[aruco_type_i]+'.json.gz')) + os.path.join(basedir, aruco_type_str[aruco_type_i]+'.json.gz'), 0) pm.make_charuco_board() pm.save() drawing = svg2rlg(filesvg) @@ -101,7 +101,7 @@ class aruco_objdetect_test(NewOpenCVTests): try: basedir = os.path.abspath(os.path.dirname(__file__)) pm = gen_pattern.PatternMaker(cols, rows, filesvg, "px", square_size, 0, board_width, - board_height, "charuco_checkboard", marker_size, os.path.join(basedir, aruco_type_str+'.json.gz')) + board_height, "charuco_checkboard", marker_size, os.path.join(basedir, aruco_type_str+'.json.gz'), 0) pm.make_charuco_board() pm.save() drawing = svg2rlg(filesvg) diff --git a/modules/core/include/opencv2/core/bindings_utils.hpp b/modules/core/include/opencv2/core/bindings_utils.hpp index 9c8f9e0f2b..dd00b59ffd 100644 --- a/modules/core/include/opencv2/core/bindings_utils.hpp +++ b/modules/core/include/opencv2/core/bindings_utils.hpp @@ -335,23 +335,6 @@ namespace fs { //! @} // core_utils } // namespace cv::utils -//! @cond IGNORED - -CV_WRAP static inline -int setLogLevel(int level) -{ - // NB: Binding generators doesn't work with enums properly yet, so we define separate overload here - return cv::utils::logging::setLogLevel((cv::utils::logging::LogLevel)level); -} - -CV_WRAP static inline -int getLogLevel() -{ - return cv::utils::logging::getLogLevel(); -} - -//! @endcond IGNORED - } // namespaces cv / utils #endif // OPENCV_CORE_BINDINGS_UTILS_HPP diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 63fc211862..7603b54a45 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -170,7 +170,10 @@ inline _InputArray::_InputArray(const std::vector& vec) { init(+STD_VECTOR template inline _InputArray::_InputArray(const std::vector<_Tp>& vec) -{ init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_READ, &vec); } +{ + CV_CheckLE(vec.size(), static_cast(std::numeric_limits::max()), "Must not be larger than INT_MAX"); + init(FIXED_TYPE + STD_VECTOR + traits::Type<_Tp>::value + ACCESS_READ, &vec); +} template inline _InputArray::_InputArray(const std::array<_Tp, _Nm>& arr) diff --git a/modules/core/include/opencv2/core/utils/logger.hpp b/modules/core/include/opencv2/core/utils/logger.hpp index e5bf455125..c58b0ccf6a 100644 --- a/modules/core/include/opencv2/core/utils/logger.hpp +++ b/modules/core/include/opencv2/core/utils/logger.hpp @@ -22,9 +22,9 @@ namespace logging { /** Set global logging level @return previous logging level */ -CV_EXPORTS LogLevel setLogLevel(LogLevel logLevel); +CV_EXPORTS_W LogLevel setLogLevel(LogLevel logLevel); /** Get global logging level */ -CV_EXPORTS LogLevel getLogLevel(); +CV_EXPORTS_W LogLevel getLogLevel(); CV_EXPORTS void registerLogTag(cv::utils::logging::LogTag* plogtag); diff --git a/modules/core/src/kmeans.cpp b/modules/core/src/kmeans.cpp index c7a03c814b..5b47d854f7 100644 --- a/modules/core/src/kmeans.cpp +++ b/modules/core/src/kmeans.cpp @@ -131,7 +131,15 @@ static void generateCentersPP(const Mat& data, Mat& _out_centers, KMeansPPDistanceComputer(tdist2, data, dist, ci), (double)divUp((size_t)(dims * N), CV_KMEANS_PARALLEL_GRANULARITY)); double s = 0; - for (int i = 0; i < N; i++) + int i = 0; + #if CV_ENABLE_UNROLLED + for (; i + 7 < N; i += 8) + { + s += tdist2[i + 0] + tdist2[i + 1] + tdist2[i + 2] + tdist2[i + 3] + + tdist2[i + 4] + tdist2[i + 5] + tdist2[i + 6] + tdist2[i + 7]; + } + #endif + for (; i < N; i++) { s += tdist2[i]; } diff --git a/modules/core/src/parallel/parallel.cpp b/modules/core/src/parallel/parallel.cpp index 29b482f5f3..77b42e45e3 100644 --- a/modules/core/src/parallel/parallel.cpp +++ b/modules/core/src/parallel/parallel.cpp @@ -71,7 +71,7 @@ std::shared_ptr createParallelForAPI() std::shared_ptr backend = info.backendFactory->create(); if (!backend) { - CV_LOG_VERBOSE(NULL, 0, "core(parallel): not available: " << info.name); + CV_LOG_DEBUG(NULL, "core(parallel): not available: " << info.name); continue; } CV_LOG_INFO(NULL, "core(parallel): using backend: " << info.name << " (priority=" << info.priority << ")"); @@ -95,9 +95,16 @@ std::shared_ptr createParallelForAPI() else { if (!isKnown) - CV_LOG_INFO(NULL, "core(parallel): unknown backend: " << name); + { + CV_LOG_INFO(NULL, "core(parallel): unknown backend: " << name << ", fallback on builtin code"); + } + else + { + CV_LOG_INFO(NULL, "core(parallel): backend=" << name << " is not available, fallback on builtin code"); + } } g_initializedParallelForAPI = true; + getParallelBackendName() = std::string(); return std::shared_ptr(); } @@ -127,6 +134,10 @@ bool setParallelForBackend(const std::string& backendName, bool propagateNumThre { CV_TRACE_FUNCTION(); + bool saved_initialized = g_initializedParallelForAPI; + std::string saved_backendName = getParallelBackendName(); + std::shared_ptr saved_backend; // don't call getCurrentParallelForAPI() if g_initializedParallelForAPI = false to avoid unnecessary "default" initialization + std::string backendName_u = toUpperCase(backendName); if (g_initializedParallelForAPI) { @@ -138,8 +149,9 @@ bool setParallelForBackend(const std::string& backendName, bool propagateNumThre } else { + saved_backend = getCurrentParallelForAPI(); // ... re-create new - CV_LOG_DEBUG(NULL, "core(parallel): replacing parallel backend..."); + CV_LOG_DEBUG(NULL, "core(parallel): replacing parallel backend (old=" << saved_backendName << " new=" << backendName << ")..."); getParallelBackendName() = backendName_u; getCurrentParallelForAPI() = createParallelForAPI(); } @@ -154,7 +166,19 @@ bool setParallelForBackend(const std::string& backendName, bool propagateNumThre { if (!backendName.empty()) { - CV_LOG_WARNING(NULL, "core(parallel): backend is not available: " << backendName << " (using builtin legacy code)"); + // restore previous backend or build default + getParallelBackendName() = saved_backendName; + if (saved_initialized) + { + CV_LOG_WARNING(NULL, "core(parallel): backend is not available: " << backendName << " (keep previous)"); + getCurrentParallelForAPI() = saved_backend; + } + else + { + CV_LOG_WARNING(NULL, "core(parallel): backend is not available: " << backendName << " (use default)"); + g_initializedParallelForAPI = false; + getCurrentParallelForAPI() = createDefaultParallelForAPI(); + } return false; } else diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 89812139a6..c59a139449 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1376,6 +1376,14 @@ TEST(Core_InputArray, empty) ASSERT_TRUE( _InputArray(data).empty() ); } +TEST(Core_InputArray, convert_from_vector_over2GB) +{ + applyTestTag(CV_TEST_TAG_MEMORY_6GB); + // empty buffer more than 2GB size + std::vector buf(size_t(INT_MAX) + 4096); + EXPECT_ANY_THROW(auto work = _InputArray(buf)); +} + TEST(Core_CopyMask, bug1918) { Mat_ tmpSrc(100,100); diff --git a/modules/dnn/src/layers/cpu_kernels/convolution.cpp b/modules/dnn/src/layers/cpu_kernels/convolution.cpp index ee769f0350..49dcc7fdcc 100644 --- a/modules/dnn/src/layers/cpu_kernels/convolution.cpp +++ b/modules/dnn/src/layers/cpu_kernels/convolution.cpp @@ -1852,6 +1852,7 @@ void convBlockMR1_F32(int np, const float* a, const float* b, float *c, const fl } #if CV_SIMD128 +#if CONV_NR_FP32 > 8 static inline void convBlock4x24(int np, const float* a, const float* b, float* c, int ldc, bool init_c, const int convMR, const int convNR) { v_float32x4 c0 = v_setzero_f32(), c1 = c0, c2 = c0, c3 = c0, c4 = c0, c5 = c0; @@ -1956,6 +1957,7 @@ static inline void convBlock4x24(int np, const float* a, const float* b, float* v_store(c + ldc * 3 + 16, c22); v_store(c + ldc * 3 + 20, c23); } +#endif static inline void convBlock4x8(int np, const float* a, const float* b, float* c, int ldc, bool init_c, const int convMR, const int convNR) { @@ -2084,11 +2086,13 @@ void convBlock_F32(int np, const float* a, const float* b, float* c, int ldc, bo // The possible outLen range is [24, 8~1]. #if CV_SIMD128 CV_Assert(convMR == 4); +#if CONV_NR_FP32 > 8 if (outLen > 8 && convNR == 24) { convBlock4x24(np, a, b, c, ldc, init_c, convMR, convNR); return; } +#endif if (outLen <= 8 && outLen > 4) { diff --git a/modules/dnn/src/layers/cpu_kernels/convolution.hpp b/modules/dnn/src/layers/cpu_kernels/convolution.hpp index 98b33ddc5f..55f6f29bb0 100644 --- a/modules/dnn/src/layers/cpu_kernels/convolution.hpp +++ b/modules/dnn/src/layers/cpu_kernels/convolution.hpp @@ -28,6 +28,9 @@ #elif CV_NEON // 16 registers. #define CONV_MR_FP32 4 #define CONV_NR_FP32 12 +#elif CV_WASM_SIMD +#define CONV_MR_FP32 4 +#define CONV_NR_FP32 8 #else // SIMD 128, AVX or AVX2 #define CONV_MR_FP32 4 #define CONV_NR_FP32 24 diff --git a/modules/dnn/src/layers/cpu_kernels/softmax.cpp b/modules/dnn/src/layers/cpu_kernels/softmax.cpp index 3b670232cc..aa5f683be6 100644 --- a/modules/dnn/src/layers/cpu_kernels/softmax.cpp +++ b/modules/dnn/src/layers/cpu_kernels/softmax.cpp @@ -48,7 +48,16 @@ void softmax(Mat &dst, const Mat &src, int axis, int axisBias, int axisStep){ size_t innerDim = i % innerSize; size_t srcOffset = outerDim * outerStep + innerDim; // copy data from src to buf along axis, since the data may not be continuous - for (size_t _cnDim = 0; _cnDim < axisStep; _cnDim++) + size_t _cnDim = 0; +#if CV_ENABLE_UNROLLED && defined(_M_ARM64) + for (; _cnDim + 3 < axisStep; _cnDim += 4) { + axisBuf[_cnDim + 0] = srcPtr[srcOffset + (_cnDim + 0 + axisBias) * cnStep]; + axisBuf[_cnDim + 1] = srcPtr[srcOffset + (_cnDim + 1 + axisBias) * cnStep]; + axisBuf[_cnDim + 2] = srcPtr[srcOffset + (_cnDim + 2 + axisBias) * cnStep]; + axisBuf[_cnDim + 3] = srcPtr[srcOffset + (_cnDim + 3 + axisBias) * cnStep]; + } +#endif + for (; _cnDim < axisStep; _cnDim++) axisBuf[_cnDim] = srcPtr[srcOffset + (_cnDim + axisBias) * cnStep]; float maxVal = -FLT_MAX; @@ -95,7 +104,16 @@ void softmax(Mat &dst, const Mat &src, int axis, int axisBias, int axisStep){ s = 1.f / s; // copy back the result to src - for (size_t _cnDim = 0; _cnDim < axisStep; _cnDim++) + _cnDim = 0; +#if CV_ENABLE_UNROLLED && defined(_M_ARM64) + for (; _cnDim + 3 < axisStep; _cnDim += 4) { + dstPtr[srcOffset + (_cnDim + 0 + axisBias) * cnStep] = axisBuf[_cnDim + 0] * s; + dstPtr[srcOffset + (_cnDim + 1 + axisBias) * cnStep] = axisBuf[_cnDim + 1] * s; + dstPtr[srcOffset + (_cnDim + 2 + axisBias) * cnStep] = axisBuf[_cnDim + 2] * s; + dstPtr[srcOffset + (_cnDim + 3 + axisBias) * cnStep] = axisBuf[_cnDim + 3] * s; + } +#endif + for (; _cnDim < axisStep; _cnDim++) dstPtr[srcOffset + (_cnDim + axisBias) * cnStep] = axisBuf[_cnDim] * s; } }, nstripes); diff --git a/modules/features/src/fast.cpp b/modules/features/src/fast.cpp index a85965732f..b1267bba77 100644 --- a/modules/features/src/fast.cpp +++ b/modules/features/src/fast.cpp @@ -174,8 +174,20 @@ void FAST_t(InputArray _img, std::vector& keypoints, int threshold, bo if(nonmax_suppression) { short d[25]; - for (int _k = 0; _k < 25; _k++) + int _k = 0; + #if CV_ENABLE_UNROLLED + for (; _k + 4 < 25; _k += 5) + { + d[_k] = (short)(ptr[k] - ptr[k + pixel[_k]]); + d[_k + 1] = (short)(ptr[k] - ptr[k + pixel[_k + 1]]); + d[_k + 2] = (short)(ptr[k] - ptr[k + pixel[_k + 2]]); + d[_k + 3] = (short)(ptr[k] - ptr[k + pixel[_k + 3]]); + d[_k + 4] = (short)(ptr[k] - ptr[k + pixel[_k + 4]]); + } + #else + for ( ; _k < 25; _k++) d[_k] = (short)(ptr[k] - ptr[k + pixel[_k]]); + #endif v_int16x8 a0, b0, a1, b1; a0 = b0 = a1 = b1 = v_load(d + 8); diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index 7d43e7f07b..ff1da13302 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -95,9 +95,9 @@ enum ImwriteFlags { IMWRITE_JPEG_SAMPLING_FACTOR = 7, //!< For JPEG, set sampling factor. See cv::ImwriteJPEGSamplingFactorParams. IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting). IMWRITE_PNG_STRATEGY = 17, //!< For PNG, One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE. - IMWRITE_PNG_BILEVEL = 18, //!< For PNG, Binary level PNG, 0 or 1, default is 0. - IMWRITE_PNG_FILTER = 19, //!< For PNG, One of cv::ImwritePNGFilterFlags, default is IMWRITE_PNG_FILTER_SUB. - IMWRITE_PNG_ZLIBBUFFER_SIZE = 20, //!< For PNG with libpng, sets the size of the internal zlib compression buffer in bytes, from 6 to 1048576(1024 KiB). Default is 8192(8 KiB). For normal use, 131072(128 KiB) or 262144(256 KiB) may be sufficient. If WITH_SPNG=ON, it is not supported. + IMWRITE_PNG_BILEVEL = 18, //!< For PNG, Binary level PNG, 0 or 1, default is 0. For APNG, it is not supported. + IMWRITE_PNG_FILTER = 19, //!< For PNG, One of cv::ImwritePNGFilterFlags, default is IMWRITE_PNG_FILTER_SUB. For APNG, it is not supported. + IMWRITE_PNG_ZLIBBUFFER_SIZE = 20, //!< For PNG with libpng, sets the size of the internal zlib compression buffer in bytes, from 6 to 1048576(1024 KiB). Default is 8192(8 KiB). For normal use, 131072(128 KiB) or 262144(256 KiB) may be sufficient. If WITH_SPNG=ON, it is not supported. For APNG, it is not supported. IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1. IMWRITE_EXR_TYPE = (3 << 4) + 0 /* 48 */, //!< override EXR storage type (FLOAT (FP32) is default) IMWRITE_EXR_COMPRESSION = (3 << 4) + 1 /* 49 */, //!< override EXR compression type (ZIP_COMPRESSION = 3 is default) diff --git a/modules/imgcodecs/src/bitstrm.cpp b/modules/imgcodecs/src/bitstrm.cpp index bb92d8a73b..12d9c1bcae 100644 --- a/modules/imgcodecs/src/bitstrm.cpp +++ b/modules/imgcodecs/src/bitstrm.cpp @@ -59,7 +59,17 @@ void RBaseStream::readBlock() throw RBS_THROW_EOS; } +#ifdef _WIN32 + // See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fseek-fseeki64?view=msvc-170 + // See https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models + // - Windows uses LLP64 data model, sizeof long int = 32. + // - Linux uses LP64 data model, sizeof long int = 64. + // So for Windows, we have to use _fseeki64() instead of fseek(). + _fseeki64( m_file, m_block_pos, SEEK_SET ); +#else fseek( m_file, m_block_pos, SEEK_SET ); +#endif + size_t readed = fread( m_start, 1, m_block_size, m_file ); m_end = m_start + readed; @@ -120,7 +130,7 @@ void RBaseStream::release() } -void RBaseStream::setPos( int pos ) +void RBaseStream::setPos( int64_t pos ) { CV_Assert(isOpened() && pos >= 0); @@ -132,7 +142,7 @@ void RBaseStream::setPos( int pos ) } int offset = pos % m_block_size; - int old_block_pos = m_block_pos; + int64_t old_block_pos = m_block_pos; m_block_pos = pos - offset; m_current = m_start + offset; if (old_block_pos != m_block_pos) @@ -140,16 +150,16 @@ void RBaseStream::setPos( int pos ) } -int RBaseStream::getPos() +int64_t RBaseStream::getPos() { CV_Assert(isOpened()); - int pos = validateToInt((m_current - m_start) + m_block_pos); + int64_t pos = validateToInt64((m_current - m_start) + m_block_pos); CV_Assert(pos >= m_block_pos); // overflow check CV_Assert(pos >= 0); // overflow check return pos; } -void RBaseStream::skip( int bytes ) +void RBaseStream::skip( int64_t bytes ) { CV_Assert(bytes >= 0); uchar* old = m_current; diff --git a/modules/imgcodecs/src/bitstrm.hpp b/modules/imgcodecs/src/bitstrm.hpp index 391ade503d..23476ed2ca 100644 --- a/modules/imgcodecs/src/bitstrm.hpp +++ b/modules/imgcodecs/src/bitstrm.hpp @@ -45,9 +45,9 @@ public: virtual bool open( const Mat& buf ); virtual void close(); bool isOpened(); - void setPos( int pos ); - int getPos(); - void skip( int bytes ); + void setPos( int64_t pos ); + int64_t getPos(); + void skip( int64_t bytes ); protected: @@ -57,7 +57,7 @@ protected: uchar* m_current; FILE* m_file; int m_block_size; - int m_block_pos; + int64_t m_block_pos; bool m_is_opened; virtual void readBlock(); diff --git a/modules/imgcodecs/src/grfmt_bmp.cpp b/modules/imgcodecs/src/grfmt_bmp.cpp index faff17811e..f0802211d9 100644 --- a/modules/imgcodecs/src/grfmt_bmp.cpp +++ b/modules/imgcodecs/src/grfmt_bmp.cpp @@ -237,9 +237,6 @@ bool BmpDecoder::readData( Mat& img ) int nch = color ? 3 : 1; int y, width3 = m_width*nch; - // FIXIT: use safe pointer arithmetic (avoid 'int'), use size_t, intptr_t, etc - CV_Assert(((uint64)m_height * m_width * nch < (CV_BIG_UINT(1) << 30)) && "BMP reader implementation doesn't support large images >= 1Gb"); - if( m_offset < 0 || !m_strm.isOpened()) return false; diff --git a/modules/imgcodecs/src/grfmt_bmp.hpp b/modules/imgcodecs/src/grfmt_bmp.hpp index a9f5fe6040..82e8fa6c78 100644 --- a/modules/imgcodecs/src/grfmt_bmp.hpp +++ b/modules/imgcodecs/src/grfmt_bmp.hpp @@ -87,7 +87,7 @@ protected: PaletteEntry m_palette[256]; Origin m_origin; int m_bpp; - int m_offset; + int64_t m_offset; BmpCompression m_rle_code; uint m_rgba_mask[4]; int m_rgba_bit_offset[4]; diff --git a/modules/imgcodecs/src/grfmt_pam.hpp b/modules/imgcodecs/src/grfmt_pam.hpp index f9b2614b28..3b5c1aa2cd 100644 --- a/modules/imgcodecs/src/grfmt_pam.hpp +++ b/modules/imgcodecs/src/grfmt_pam.hpp @@ -78,8 +78,8 @@ public: protected: RLByteStream m_strm; - int m_maxval, m_channels, m_sampledepth, m_offset, - selected_fmt; + int64_t m_offset; + int m_maxval, m_channels, m_sampledepth, selected_fmt; bool bit_mode; }; diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp index 4ae933e2bb..dbb3c41cf2 100644 --- a/modules/imgcodecs/src/grfmt_png.cpp +++ b/modules/imgcodecs/src/grfmt_png.cpp @@ -434,138 +434,147 @@ bool PngDecoder::readData( Mat& img ) if (!processing_start((void*)&frameRaw, mat_cur)) return false; - while (true) + // See https://github.com/opencv/opencv/issues/27744 + if( setjmp( png_jmpbuf ( m_png_ptr ) ) == 0 ) { - id = read_chunk(chunk); - if (!id) - return false; - - if (id == id_fcTL && m_is_IDAT_loaded) + while (true) { - if (!m_is_fcTL_loaded) + id = read_chunk(chunk); + if (!id) + return false; + + if (id == id_fcTL && m_is_IDAT_loaded) { - m_mat_raw.copyTo(m_animation.still_image); - } - else - { - if (processing_finish()) + if (!m_is_fcTL_loaded) { - if (dop == 2) - memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize); - - if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight()) - return false; - - compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur); - if (!delay_den) - delay_den = 100; - m_animation.durations.push_back(cvRound(1000. * delay_num / delay_den)); - - if (mat_cur.channels() == img.channels()) + m_mat_raw.copyTo(m_animation.still_image); + } + else + { + if (processing_finish()) { - if (mat_cur.depth() == CV_16U && img.depth() == CV_8U) - mat_cur.convertTo(img, CV_8U, 1. / 255); + if (dop == 2) + memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize); + + if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight()) + return false; + + compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur); + if (!delay_den) + delay_den = 100; + m_animation.durations.push_back(cvRound(1000. * delay_num / delay_den)); + + if (mat_cur.channels() == img.channels()) + { + if (mat_cur.depth() == CV_16U && img.depth() == CV_8U) + mat_cur.convertTo(img, CV_8U, 1. / 255); + else + mat_cur.copyTo(img); + } else - mat_cur.copyTo(img); + { + Mat mat_cur_scaled; + if (mat_cur.depth() == CV_16U && img.depth() == CV_8U) + mat_cur.convertTo(mat_cur_scaled, CV_8U, 1. / 255); + else + mat_cur_scaled = mat_cur; + + if (img.channels() == 1) + cvtColor(mat_cur_scaled, img, COLOR_BGRA2GRAY); + else if (img.channels() == 3) + cvtColor(mat_cur_scaled, img, COLOR_BGRA2BGR); + } + + if (dop != 2) + { + memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize); + if (dop == 1) + for (j = 0; j < h0; j++) + memset(frameNext.getRows()[y0 + j] + x0 * img.channels(), 0, w0 * img.channels()); + } } else { - Mat mat_cur_scaled; - if (mat_cur.depth() == CV_16U && img.depth() == CV_8U) - mat_cur.convertTo(mat_cur_scaled, CV_8U, 1. / 255); - else - mat_cur_scaled = mat_cur; - - if (img.channels() == 1) - cvtColor(mat_cur_scaled, img, COLOR_BGRA2GRAY); - else if (img.channels() == 3) - cvtColor(mat_cur_scaled, img, COLOR_BGRA2BGR); + return false; } + } - if (dop != 2) + w0 = png_get_uint_32(&chunk.p[12]); + h0 = png_get_uint_32(&chunk.p[16]); + x0 = png_get_uint_32(&chunk.p[20]); + y0 = png_get_uint_32(&chunk.p[24]); + delay_num = png_get_uint_16(&chunk.p[28]); + delay_den = png_get_uint_16(&chunk.p[30]); + dop = chunk.p[32]; + bop = chunk.p[33]; + + if (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1) + { + return false; + } + + memcpy(&m_chunkIHDR.p[8], &chunk.p[12], 8); + + if (m_is_fcTL_loaded) + return true; + else + { + m_is_fcTL_loaded = true; + ClearPngPtr(); + if (!processing_start((void*)&frameRaw, mat_cur)) + return false; + } + } + else if (id == id_IDAT) + { + m_is_IDAT_loaded = true; + png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size()); + } + else if (id == id_fdAT && m_is_fcTL_loaded) + { + m_is_IDAT_loaded = true; + png_save_uint_32(&chunk.p[4], static_cast(chunk.p.size() - 16)); + memcpy(&chunk.p[8], "IDAT", 4); + png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4); + } + else if (id == id_IEND) + { + if (processing_finish()) + { + compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur); + if (!delay_den) + delay_den = 100; + m_animation.durations.push_back(cvRound(1000.*delay_num/delay_den)); + + if (mat_cur.depth() == CV_16U && img.depth() == CV_8U && mat_cur.channels() == img.channels()) + mat_cur.convertTo(img, CV_8U, 1. / 255); + else { - memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize); - if (dop == 1) - for (j = 0; j < h0; j++) - memset(frameNext.getRows()[y0 + j] + x0 * img.channels(), 0, w0 * img.channels()); + if (mat_cur.depth() == CV_16U && img.depth() == CV_8U) + mat_cur.convertTo(mat_cur, CV_8U, 1. / 255); + if (mat_cur.channels() == img.channels()) + mat_cur.copyTo(img); + else if (img.channels() == 1) + cvtColor(mat_cur, img, COLOR_BGRA2GRAY); + else if (img.channels() == 3) + cvtColor(mat_cur, img, COLOR_BGRA2BGR); } } else - { return false; - } - } - w0 = png_get_uint_32(&chunk.p[12]); - h0 = png_get_uint_32(&chunk.p[16]); - x0 = png_get_uint_32(&chunk.p[20]); - y0 = png_get_uint_32(&chunk.p[24]); - delay_num = png_get_uint_16(&chunk.p[28]); - delay_den = png_get_uint_16(&chunk.p[30]); - dop = chunk.p[32]; - bop = chunk.p[33]; - - if (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1) - { - return false; - } - - memcpy(&m_chunkIHDR.p[8], &chunk.p[12], 8); - - if (m_is_fcTL_loaded) return true; - else - { - m_is_fcTL_loaded = true; - ClearPngPtr(); - if (!processing_start((void*)&frameRaw, mat_cur)) - return false; - } - } - else if (id == id_IDAT) - { - m_is_IDAT_loaded = true; - png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size()); - } - else if (id == id_fdAT && m_is_fcTL_loaded) - { - m_is_IDAT_loaded = true; - png_save_uint_32(&chunk.p[4], static_cast(chunk.p.size() - 16)); - memcpy(&chunk.p[8], "IDAT", 4); - png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4); - } - else if (id == id_IEND) - { - if (processing_finish()) - { - compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur); - if (!delay_den) - delay_den = 100; - m_animation.durations.push_back(cvRound(1000.*delay_num/delay_den)); - - if (mat_cur.depth() == CV_16U && img.depth() == CV_8U && mat_cur.channels() == img.channels()) - mat_cur.convertTo(img, CV_8U, 1. / 255); - else - { - if (mat_cur.depth() == CV_16U && img.depth() == CV_8U) - mat_cur.convertTo(mat_cur, CV_8U, 1. / 255); - if (mat_cur.channels() == img.channels()) - mat_cur.copyTo(img); - else if (img.channels() == 1) - cvtColor(mat_cur, img, COLOR_BGRA2GRAY); - else if (img.channels() == 3) - cvtColor(mat_cur, img, COLOR_BGRA2BGR); - } } else - return false; - - return true; + png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size()); } - else - png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size()); + return false; + } + else + { + // libpng internal error is detected. + return false; } - return false; } volatile bool result = false; @@ -1621,20 +1630,52 @@ bool PngEncoder::writeanimation(const Animation& animation, const std::vector ¶ms) { compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy compression_level = MIN(MAX(value, 0), Z_BEST_COMPRESSION); - if(value != m_compression_level) { - CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, m_compression_level)); + if(value != compression_level) { + CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, compression_level)); } set_compression_level = true; } @@ -556,7 +556,7 @@ bool SPngEncoder::write(const Mat &img, const std::vector ¶ms) compression_strategy = value; break; default: - compression_strategy = IMWRITE_PNG_STRATEGY_RLE: + compression_strategy = IMWRITE_PNG_STRATEGY_RLE; CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_STRATEGY must be one of ImwritePNGFlags. It is fallbacked to IMWRITE_PNG_STRATEGY_RLE", value)); break; } diff --git a/modules/imgcodecs/src/grfmt_sunras.cpp b/modules/imgcodecs/src/grfmt_sunras.cpp index f2878d1760..0dd31b3b1a 100644 --- a/modules/imgcodecs/src/grfmt_sunras.cpp +++ b/modules/imgcodecs/src/grfmt_sunras.cpp @@ -94,7 +94,7 @@ bool SunRasterDecoder::readHeader() m_type = IsColorPalette( m_palette, m_bpp ) ? CV_8UC3 : CV_8UC1; m_offset = m_strm.getPos(); - CV_Assert(m_offset == 32 + m_maplength); + CV_Assert(m_offset == static_cast(32 + m_maplength)); result = true; } } @@ -107,7 +107,7 @@ bool SunRasterDecoder::readHeader() m_offset = m_strm.getPos(); - CV_Assert(m_offset == 32 + m_maplength); + CV_Assert(m_offset == static_cast(32 + m_maplength)); result = true; } } diff --git a/modules/imgcodecs/src/grfmt_sunras.hpp b/modules/imgcodecs/src/grfmt_sunras.hpp index fc6284ad40..6a85e36aab 100644 --- a/modules/imgcodecs/src/grfmt_sunras.hpp +++ b/modules/imgcodecs/src/grfmt_sunras.hpp @@ -84,7 +84,7 @@ protected: RMByteStream m_strm; PaletteEntry m_palette[256]; int m_bpp; - int m_offset; + int64_t m_offset; SunRasType m_encoding; SunRasMapType m_maptype; int m_maplength; diff --git a/modules/imgcodecs/src/grfmt_webp.cpp b/modules/imgcodecs/src/grfmt_webp.cpp index ae11c7ce2c..932f08bec1 100644 --- a/modules/imgcodecs/src/grfmt_webp.cpp +++ b/modules/imgcodecs/src/grfmt_webp.cpp @@ -511,23 +511,26 @@ bool WebPEncoder::writeanimation(const Animation& animation, const std::vector 1) + for(size_t i = 0; i < params.size(); i += 2) { - if (params[0] == IMWRITE_WEBP_QUALITY) + const int value = params[i+1]; + if (params[i] == IMWRITE_WEBP_QUALITY) { - config.lossless = 0; - config.quality = static_cast(params[1]); + config.lossless = 0; // false + config.quality = static_cast(value); if (config.quality < 1.0f) { config.quality = 1.0f; + CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_WEBP_QUALITY must be between 1 to 100(lossy) or more(lossless). It is fallbacked to 1", value)); } - if (config.quality >= 100.0f) + if (config.quality > 100.0f) { - config.lossless = 1; + config.quality = 100.0f; + config.lossless = 1; // true } } - anim_config.minimize_size = 0; } std::unique_ptr anim_encoder( diff --git a/modules/imgcodecs/src/utils.cpp b/modules/imgcodecs/src/utils.cpp index 41fd9f5041..1e14e86610 100644 --- a/modules/imgcodecs/src/utils.cpp +++ b/modules/imgcodecs/src/utils.cpp @@ -51,6 +51,13 @@ int validateToInt(size_t sz) return valueInt; } +int64_t validateToInt64(size_t sz) +{ + int64_t valueInt = static_cast(sz); + CV_Assert((size_t)valueInt == sz); + return valueInt; +} + #define SCALE 14 #define cR (int)(0.299*(1 << SCALE) + 0.5) #define cG (int)(0.587*(1 << SCALE) + 0.5) diff --git a/modules/imgcodecs/src/utils.hpp b/modules/imgcodecs/src/utils.hpp index 95deebde31..b5a00c47b3 100644 --- a/modules/imgcodecs/src/utils.hpp +++ b/modules/imgcodecs/src/utils.hpp @@ -45,6 +45,7 @@ namespace cv { int validateToInt(size_t step); +int64_t validateToInt64(size_t step); template static inline size_t safeCastToSizeT(const _Tp v_origin, const char* msg) diff --git a/modules/imgcodecs/test/test_bmp.cpp b/modules/imgcodecs/test/test_bmp.cpp new file mode 100644 index 0000000000..bd061e6f88 --- /dev/null +++ b/modules/imgcodecs/test/test_bmp.cpp @@ -0,0 +1,61 @@ +// 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 +#include "test_precomp.hpp" +#include "test_common.hpp" + +#include + +namespace opencv_test { namespace { + +// See https://github.com/opencv/opencv/issues/27789 +// See https://github.com/opencv/opencv/issues/23233 +TEST(Imgcodecs_BMP, encode_decode_over1GB_regression27789) +{ + applyTestTag( CV_TEST_TAG_MEMORY_2GB, CV_TEST_TAG_LONG ); + + // Create large Mat over 1GB + // 20000 px * 18000 px * 24 bpp(3ch) = 1,080,000,000 bytes + // 1 GiB = 1,073,741,824 bytes + cv::Mat src(20000, 18000, CV_8UC3, cv::Scalar(0,0,0)); + + // Encode large BMP file. + std::vector buf; + bool ret = false; + ASSERT_NO_THROW(ret = cv::imencode(".bmp", src, buf, {})); + ASSERT_TRUE(ret); + + src.release(); // To reduce usage memory, it is needed. + + // Decode large BMP file. + cv::Mat dst; + ASSERT_NO_THROW(dst = cv::imdecode(buf, cv::IMREAD_COLOR)); + ASSERT_FALSE(dst.empty()); +} + +TEST(Imgcodecs_BMP, write_read_over1GB_regression27789) +{ + // tag CV_TEST_TAG_VERYLONG applied to skip on CI. The test writes ~1GB file. + applyTestTag( CV_TEST_TAG_MEMORY_2GB, CV_TEST_TAG_VERYLONG ); + string bmpFilename = cv::tempfile(".bmp"); // To remove it, test must use EXPECT_* instead of ASSERT_*. + + // Create large Mat over 1GB + // 20000 px * 18000 px * 24 bpp(3ch) = 1,080,000,000 bytes + // 1 GiB = 1,073,741,824 bytes + cv::Mat src(20000, 18000, CV_8UC3, cv::Scalar(0,0,0)); + + // Write large BMP file. + bool ret = false; + EXPECT_NO_THROW(ret = cv::imwrite(bmpFilename, src, {})); + EXPECT_TRUE(ret); + + // Read large BMP file. + cv::Mat dst; + EXPECT_NO_THROW(dst = cv::imread(bmpFilename, cv::IMREAD_COLOR)); + EXPECT_FALSE(dst.empty()); + + remove(bmpFilename.c_str()); +} + + +}} // namespace diff --git a/modules/imgcodecs/test/test_png.cpp b/modules/imgcodecs/test/test_png.cpp index 967b852d76..1c8eae233c 100644 --- a/modules/imgcodecs/test/test_png.cpp +++ b/modules/imgcodecs/test/test_png.cpp @@ -157,6 +157,51 @@ TEST(Imgcodecs_Png, decode_regression27295) EXPECT_TRUE(img.empty()); } +// The program must not crash even when decoding a corrupted APNG image. +// See https://github.com/opencv/opencv/issues/27744 +#if defined(HAVE_PNG) // APNG is supported only with using libpng +TEST(Imgcodecs_Png, decode_regression27744) +{ + // Create APNG stream + Animation anim; + for(size_t i = 0 ; i < 3 ; i++) { + Mat frame(120, 120, CV_8UC3, Scalar(0,0,0)); + putText(frame, cv::format("%d", static_cast(i)), Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2); + anim.frames.push_back(frame); + anim.durations.push_back(30); + } + bool ret = false; + vector buff; + EXPECT_NO_THROW(ret = imencodeanimation(".png", anim, buff)); + ASSERT_TRUE(ret) << "imencodeanimation() returns false"; + + // Find IDAT chunk + const vector IDAT = {'I', 'D', 'A', 'T' }; + std::vector::iterator it = std::search(buff.begin(), buff.end(), IDAT.begin(), IDAT.end()); + ASSERT_FALSE(it == buff.end()) << "IDAT chunk not found"; + + // Determine the range to test + // APNG stream contains as { len0, len1, len2, len3, 'I', 'D', 'A' 'T', ... } + size_t idx = std::distance(buff.begin(), it); // 'I' position + size_t len = (buff[idx-4] << 24) + (buff[idx-3] << 16) + + (buff[idx-2] << 8) + (buff[idx-1]); // IDAT chunk length + idx = idx + 4; // Move to IDAT body + + // Test + for(size_t i = 0; i < len; i++, idx++) { + vector work = buff; + work[idx] = static_cast((static_cast(work[idx]) + 1) & 0xff); + + Mat dst; + EXPECT_NO_THROW(dst = imdecode(work, cv::IMREAD_COLOR)); + if(dst.empty()) { + // libpng detects some error, but the program is not crashed. Test is passed. + break; + } + } +} +#endif + typedef testing::TestWithParam Imgcodecs_Png_PngSuite; // Parameterized test for decoding PNG files from the PNGSuite test set diff --git a/modules/imgcodecs/test/test_read_write.cpp b/modules/imgcodecs/test/test_read_write.cpp index 1e171d9e8d..2508ef2dbd 100644 --- a/modules/imgcodecs/test/test_read_write.cpp +++ b/modules/imgcodecs/test/test_read_write.cpp @@ -619,4 +619,13 @@ TEST(Imgcodecs_Params, imencode_regression_22752) EXPECT_ANY_THROW(cv::imencode("test.jpg", img, buf, params)); // parameters size or missing JPEG codec } +TEST(Imgcodecs, decode_over2GB) +{ + applyTestTag(CV_TEST_TAG_MEMORY_6GB); + // empty buffer more than 2GB size + std::vector buf(size_t(INT_MAX) + 4096); + cv::Mat dst; + EXPECT_THROW(dst = cv::imdecode(buf, cv::IMREAD_COLOR), cv::Exception); +} + }} // namespace diff --git a/modules/imgproc/CMakeLists.txt b/modules/imgproc/CMakeLists.txt index ceca2be80e..d3d16e8f8f 100644 --- a/modules/imgproc/CMakeLists.txt +++ b/modules/imgproc/CMakeLists.txt @@ -8,7 +8,7 @@ ocv_add_dispatched_file(color_rgb SSE2 SSE4_1 AVX2) ocv_add_dispatched_file(color_yuv SSE2 SSE4_1 AVX2) ocv_add_dispatched_file(median_blur SSE2 SSE4_1 AVX2 AVX512_SKX) ocv_add_dispatched_file(morph SSE2 SSE4_1 AVX2) -ocv_add_dispatched_file(smooth SSE2 SSE4_1 AVX2) +ocv_add_dispatched_file(smooth SSE2 SSE4_1 AVX2 AVX512_ICL) ocv_add_dispatched_file(sumpixels SSE2 AVX2 AVX512_SKX) ocv_add_dispatched_file(warp_kernels SSE2 SSE4_1 AVX2 NEON NEON_FP16 RVV LASX) ocv_define_module(imgproc opencv_core WRAP java objc python js) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index ff097162ad..54e29c26fa 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -4079,7 +4079,7 @@ The algorithm based on the paper @cite LowIlie2003 . @param approxCurve Result of the approximation. The type is vector of a 2D point (Point2f or Point) in std::vector or Mat. @param nsides The parameter defines the number of sides of the result polygon. @param epsilon_percentage defines the percentage of the maximum of additional area. -If it equals -1, it is not used. Otherwise algorighm stops if additional area is greater than contourArea(_curve) * percentage. +If it equals -1, it is not used. Otherwise algorithm stops if additional area is greater than contourArea(_curve) * percentage. If additional area exceeds the limit, algorithm returns as many vertices as there were at the moment the limit was exceeded. @param ensure_convex If it is true, algorithm creates a convex hull of input contour. Otherwise input vector should be convex. */ @@ -4157,7 +4157,8 @@ The function finds the four vertices of a rotated rectangle. The four vertices a in clockwise order starting from the point with greatest \f$y\f$. If two points have the same \f$y\f$ coordinate the rightmost is the starting point. This function is useful to draw the rectangle. In C++, instead of using this function, you can directly use RotatedRect::points method. Please -visit the @ref tutorial_bounding_rotated_ellipses "tutorial on Creating Bounding rotated boxes and ellipses for contours" for more information. +visit the @ref tutorial_bounding_rotated_ellipses "tutorial on Creating Bounding rotated boxes and ellipses +for contours" for more information. @param box The input rotated rectangle. It may be the output of @ref minAreaRect. @param points The output array of four vertices of rectangles. @@ -4197,6 +4198,30 @@ of the OutputArray must be CV_32F. */ CV_EXPORTS_W double minEnclosingTriangle( InputArray points, CV_OUT OutputArray triangle ); + +/** +@brief Finds a convex polygon of minimum area enclosing a 2D point set and returns its area. + +This function takes a given set of 2D points and finds the enclosing polygon with k vertices and minimal +area. It takes the set of points and the parameter k as input and returns the area of the minimal +enclosing polygon. + +The Implementation is based on a paper by Aggarwal, Chang and Yap @cite Aggarwal1985. They +provide a \f$\theta(n²log(n)log(k))\f$ algorighm for finding the minimal convex polygon with k +vertices enclosing a 2D convex polygon with n vertices (k < n). Since the #minEnclosingConvexPolygon +function takes a 2D point set as input, an additional preprocessing step of computing the convex hull +of the 2D point set is required. The complexity of the #convexHull function is \f$O(n log(n))\f$ which +is lower than \f$\theta(n²log(n)log(k))\f$. Thus the overall complexity of the function is +\f$O(n²log(n)log(k))\f$. + +@param points Input vector of 2D points, stored in std::vector\<\> or Mat +@param polygon Output vector of 2D points defining the vertices of the enclosing polygon +@param k Number of vertices of the output polygon + */ + +CV_EXPORTS_W double minEnclosingConvexPolygon ( InputArray points, OutputArray polygon, int k ); + + /** @brief Compares two shapes. The function compares two shapes. All three implemented methods use the Hu invariants (see #HuMoments) diff --git a/modules/imgproc/src/min_enclosing_convex_polygon.cpp b/modules/imgproc/src/min_enclosing_convex_polygon.cpp new file mode 100644 index 0000000000..c97ada4abc --- /dev/null +++ b/modules/imgproc/src/min_enclosing_convex_polygon.cpp @@ -0,0 +1,1055 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// + // + // 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. + // + // Author: Sara Kuhnert + // Created: 20.05.2025 + // E-mail: + // + // THE IMPLEMENTATION OF THE MODULES IS BASED ON THE FOLLOWING PAPER: + // + // [1] A. Aggarwal, J. S. Chang, Chee K. Yap: "Minimum area circumscribing Polygons", The Visual + // Computer, 1:112-117, 1985 + // + // The overall complexity of the algorithm is theta(n^2log(n)log(k)) where "n" represents the number + // of vertices in the input convex polygon and "k" the number of vertices in the output polygon. + // + //M*/ + +#include "precomp.hpp" +#include + +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////// Constants definitions //////////////////////////// + +#define EPSILON 1e-6 + +//////////////////////// Class and struct declarations //////////////////////// + +namespace minEnclosingConvexPolygon { + +//! Intersection point of two sides with its position relative to the polygon +/*! + * @param point Intersection point of the two sides + * @param position Is the intersection point a valid solution? + */ +struct IntersectionPoint +{ + cv::Point2f point = {-1.0, -1.0}; + bool position = false; + + IntersectionPoint() = default; + IntersectionPoint(const cv::Point2f& a, const cv::Point2f& b, + const cv::Point2f& c, const cv::Point2f& d); + IntersectionPoint(int i, int j, const std::vector& ngon); +}; + +//! Container for the information about the intersection point of two flush sides +/*! + * @param intersection Instance of IntersectionPoint + * @param extra_area The area that would be added to the kgon compared to the ngon + * @param done Set to true once calculated to avoid redundant calculations + */ +struct FlushIntersect +{ + IntersectionPoint intersection = {}; + double extra_area = std::numeric_limits::max(); + bool done = false; +}; + +//! Container for the information about a balanced side between two points +/*! + * @param pi First intersection point + * @param pj Second intersection point + * @param extra_area The area that would be added to the kgon compared to the ngon + * @param flush Flush is a special case of balanced. If the balanced side is also flush, this indicates which of the sides of the ngon it is flush with. The default for not flush sides is -1. + * @param position Is the balanced side a valid solution? + * @param done Set to true once calculated to avoid redundant calculations + */ +struct BalancedIntersect +{ + cv::Point2f pi = {-1, -1}; + cv::Point2f pj = {-1, -1}; + double extra_area = std::numeric_limits::max(); + int flush = -1; + bool position = false; + bool done = false; +}; + +//! Container for the best segment between two points +/*! + * @param extra_area The area that would be added to the kgon compared to the ngon + * @param side Side of the ngon to which it is flush (if flush is true) or edge of the ngon which it is touching (if flush is false) + * @param flush True if it is flush. If false, it is balanced but not flush + * @param exists Does a valid solution exist? + * @param done Set to true once calculated to avoid redundant calculations + */ +struct Segment +{ + double extra_area = std::numeric_limits::max(); + int side = -1; + bool flush = false; + bool exists = false; + bool done = false; +}; + +//! Combination of selected sides and their corresponding chains, which generates the kgon with the minimum area +/*! + * @param area Extra area that the minimal kgon is bigger than the input ngon + * @param i First side + * @param j Second side + */ +struct Minimum +{ + double area = std::numeric_limits::max(); + int i = -1; + int j = -1; +}; + +//! Container for a side of the minimal kgon +/*! + * @param side Index of the side of the ngon which it is flush with or the vertex which it is touching + * @param flush Is this side flush? + */ +struct Side +{ + int side = -1; + bool flush = false; + + Side() = default; + Side(int i, bool b); +}; + +//! Container for the minimal kgon +/*! + * @param sides Indices of the corresponding sindes of the ngon + * @param vertices Vertices of the kgon + * @param extra_area Extra area that the minimal kgon is bigger than the input ngon + * @param i, @param j The chains which build the minimal kgon are formed between those two sides + */ +struct Kgon +{ + std::vector sides; + std::vector vertices; + double extra_area = std::numeric_limits::max(); + int i = -1; + int j = -1; +}; + +//! Class for all the possible combinations of flush intersections of two sides of the input polygon +/*! + * @param ngon Input polygon + * @param intersections Matrix of all possible flush intersections of two sides of the ngon + * @param area_edges Collection of the points that define the extra area of the kgon + */ +class FlushIntersections +{ +private: + const std::vector& ngon; + std::vector> intersections; + std::vector area_edges; + +public: + FlushIntersections(const std::vector& _ngon); + const FlushIntersect& lineIntersect(int i, int j); +}; + +//! Class for all the possible combinations of balanced intersections with two sides of the input polygon +/*! + * @param ngon Input polygon + * @param balanced_intersections atrix of all possible balanced intersections of two sides of the ngon + * @param area_edges Collection of the points that define the extra area of the kgon + */ +class BalancedIntersections +{ +private: + const std::vector& ngon; + std::vector> balanced_intersections; + std::vector area_edges; + + double extraArea ( int first, int last, const cv::Point2f& extra1, const cv::Point2f& extra2 ); + + BalancedIntersect flush(int i, int j, int e); + +public: + BalancedIntersections(const std::vector& _ngon); + BalancedIntersect balancedIntersect(int i, int j, int e); + void markAsDone(int i, int j); + const std::vector& operator[](size_t i) const; +}; + +//! Class for building the one-sided and h-sided chains and calculation the minimum enclosing polygon based on those chains +/*! + * @param ngon Input polygon + * @param single_sides Matrix of the best one-sided chain for each combination of two sides of the ngon + * @param middle_sides Matrix of the middle side of each h-sided chain for all relevant h and each combination of two sides of the ngon + * @param intersections An instance of FlushIntersections to store already calculated flush intersections + * @param balanced_inters An instance of BalancedIntersections to store already calculated balanced intersections + */ +class Chains +{ +private: + const std::vector& ngon; + std::vector> single_sides; + std::vector>> middle_sides; + FlushIntersections intersections; + BalancedIntersections balanced_inters; + + void findSingleE(int i, int j, int l, int r); + void singleSideImpl(int i, int j1, int j2); + void findMiddleE1(int i, int j, int l, int r); + void middleSideImpl1(int i, int j1, int j2); + void findMiddleE(int h, int i, int j, int l, int r); + void middleSideImpl(int h, int i, int j1, int j2); + +public: + Chains(const std::vector& _ngon, int k); + + std::set relevantChainLengths(int h); + void calcOneSidedChains(); + void calcMiddleChains(int h); + + Minimum minimumArea(int n, int k); + std::vector reconstructHSidedChain(int h, int i, int j); + std::vector findKSides(int k, int i, int j); + std::vector findKVertices(std::vector& sides); + +}; + +} //namespace + + +//////////////////////// Class and struct constructors //////////////////////// + +namespace minEnclosingConvexPolygon { + +//! Constructor for IntersectionPoint. Find the intersection point of two lines given by four points and decide whether it is on the correct side of the polygon +/*! + * @param a First point of the first line + * @param b Second point of the first line + * @param c First point of the second line + * @param d Second point of the second line + */ +IntersectionPoint::IntersectionPoint(const cv::Point2f& a, const cv::Point2f& b, + const cv::Point2f& c, const cv::Point2f& d) +{ + const cv::Point2f ab = b - a, cd = d - c, ac = c - a; + const double det = ab.cross(-cd); + if(std::abs (det) < EPSILON ) + return; + + const double loc = ac.cross(-cd) / det; + if(loc <= 0) + return; + + point = a + loc * ab; + position = true; +} + +//! Constructor for IntersectionPoint. Find the intersection point of two sides of the polygon based on the given side indices. +/*! + * @param i Index of the first side + * @param j Index of the second side + * @param ngon Input polygon with n sides + */ +IntersectionPoint::IntersectionPoint(int i, int j, + const std::vector& ngon) : + IntersectionPoint(ngon[i], + ngon[(i + 1) % ngon.size()], + ngon[j], + ngon[(j + 1) % ngon.size()]) +{} + +//! Constructor for FlushIntersections +/*! + * @param _ngon Input polygon with n sides + */ +FlushIntersections::FlushIntersections(const std::vector& _ngon) : + ngon(_ngon), + intersections(ngon.size(), + std::vector(ngon.size())) +{ + area_edges.reserve(ngon.size()); +} + +//! Constructor for BalancedIntersections +/*! + * @param _ngon Input polygon with n sides + */ +BalancedIntersections::BalancedIntersections(const std::vector& _ngon) : +ngon(_ngon), +balanced_intersections(ngon.size(), + std::vector(ngon.size())) +{ + area_edges.reserve(ngon.size()); +} + +//! Constructor for Side. Assign a side index and weather it is flush or not. +/*! + * @param i Side index + * @param b Is side i flush? + */ +Side::Side(int i, bool b) +{ + side = i; + flush = b; +} + +//! Constructor for Chains +/*! + * @param + */ +Chains::Chains(const std::vector& _ngon, int k) : + ngon(_ngon), + single_sides(std::vector>(ngon.size(), + std::vector(ngon.size()))), + middle_sides(std::vector>>( + k, std::vector>(ngon.size(), + std::vector(ngon.size())))), + intersections(ngon), + balanced_inters(ngon) +{} + +} //namespace + + +////////////////////////// Class and struct functions ////////////////////////// + +namespace minEnclosingConvexPolygon { + +//! Find the intersection point of two sides, decide weather it is a valid point and if so calculate the extra area caused by that intersection. +/*! + * @param i Index of the first side + * @param j Index of the second side + */ +const FlushIntersect& FlushIntersections::lineIntersect(int i, int j) +{ + FlushIntersect& itr = intersections[i][j]; + if(itr.done) + return itr; + + const int n = (int)ngon.size(); + if((i + 1) % n == j) + { + itr.intersection.point = ngon[j]; + itr.intersection.position = true; + itr.extra_area = 0.0; + itr.done = true; + return itr; + } + itr.intersection = IntersectionPoint(i, j, ngon); + if(itr.intersection.position) + { + area_edges.resize(0); + for(int t = (i + 1) % n; t != (j + 1) % n; t = (t + 1) % n) + { + area_edges.push_back(ngon[t]); + } + area_edges.push_back(itr.intersection.point); + itr.extra_area = cv::contourArea(area_edges); + itr.done = true; + } + else + { + itr.extra_area = std::numeric_limits::max(); + itr.intersection.position = false; + itr.done = true; + } + return itr; +} + +//! Calculate the added area that is enclosed by a sequence of consecutive vertices of the polygon and the intersection point of two sides. +/*! + * @param first Index of the first point of the sequence + * @param last Index of the last point of the sequence + * @param extra1 Last point of the sequence + * @param extra2 Intersection point + */ +double BalancedIntersections::extraArea(int first, int last, + const cv::Point2f& extra1, + const cv::Point2f& extra2) +{ + const size_t n = ngon.size(); + area_edges.resize(0); + for(int t = first; t != last; t = (t + 1) % n) + area_edges.push_back(ngon[t]); + + area_edges.push_back(extra1); + area_edges.push_back(extra2); + + return cv::contourArea(area_edges); +} + +//! Determine the intersection points of a flush side e that lies between sides i and j with these two sides. Calculate the extra area and the position of the intersection points relative to the polygon. Update balanced_intersections if the new area is smaller than extraArea. +/*! + * @param i Index of first side + * @param j Index of second side + * @param e Index of a side between i and j + */ +BalancedIntersect BalancedIntersections::flush(int i, int j, int e) +{ + CV_Assert(j != e); + + const int n = (int)ngon.size(); + const int before = (e - 1 + n) % n; + BalancedIntersect bi = balanced_intersections[i][j]; + + const IntersectionPoint left_e(i, e, ngon); + const IntersectionPoint right_e(e, j, ngon); + + if(left_e.position == true && right_e.position == true) + { + double extra_area = extraArea((i + 1) % n, e, ngon[e], left_e.point); + if(extra_area < bi.extra_area) + { + extra_area += extraArea((e + 1) % n, j, ngon[j], right_e.point); + if(extra_area < bi.extra_area) + { + bi.extra_area = extra_area; + bi.pi = left_e.point; + bi.pj = right_e.point; + bi.position = true; + bi.flush = e; + } + } + } + + if(before != i) + { + const IntersectionPoint left_before(i, before, ngon); + const IntersectionPoint right_before(before, j, ngon); + if(left_before.position == true && right_before.position == true) + { + double extra_area = + extraArea((i + 1) % n, before, ngon[before], left_before.point); + + if(extra_area < bi.extra_area) + { + extra_area += extraArea(e, j, ngon[j], right_before.point); + if(extra_area < bi.extra_area) + { + bi.extra_area = extra_area; + bi.pi = left_before.point; + bi.pj = right_before.point; + bi.position = true; + bi.flush = before; + } + } + } + } + return bi; +} + +//! Determine the intersection points of a balanced side e that lies between sides i and j with these two sides. If no valid balanced edge is found, ccheck for flush sides. Calculate the extra area and the position of the intersection points relative to the polygon. Update balanced_intersections if the new area is smaller than extraArea. +/*! + * @param i Index of first side + * @param j Index of second side + * @param e Index of a side between i and j + */ +BalancedIntersect BalancedIntersections::balancedIntersect(int i, int j, int e) +{ + if(balanced_intersections[i][j].done) + return balanced_intersections[i][j]; + + const int n = (int)ngon.size(); + if((i + 2) % n == j) + { + BalancedIntersect& bi = balanced_intersections[i][j]; + bi.pi = ngon[(i + 1) % n]; + bi.pj = ngon[j]; + bi.flush = (i + 1) % n; + bi.position = true; + bi.extra_area = 0.0; + bi.done = true; + return bi; + } + + const cv::Point2f p1 = ngon[i], p2 = ngon[(i + 1) % n], p3 = ngon[e], + p4 = ngon[j], p5 = ngon[(j + 1) % n]; + const cv::Point2f dir12 = p2 - p1, dir45 = p5 - p4; + const double det = dir12.cross(dir45); + if(std::abs (det) < EPSILON ) + { + flush(i, j, e); + return balanced_intersections[i][j]; + } + + BalancedIntersect bi; + cv::Point2f temp = 2 * p3 - p2 - p4; + const double s = temp.cross(dir45) / det; + const double t = temp.cross(dir12) / det; + if(s >= 0 && t >= 0) + { + bi.pi = p2 + dir12 * s; + bi.pj = p4 - dir45 * t; + bi.position = true; + + const cv::Point2f dir_balanced = bi.pj - bi.pi, + dir_left = p3 - ngon[(e - 1 + n) % n], + dir_right = ngon[(e + 1) % n] - p3; + + const double cross_left = dir_balanced.cross(dir_left), + cross_right = dir_balanced.cross(dir_right); + if((cross_left < 0 && cross_right < 0) || (cross_left > 0 && cross_right > 0)) + { + BalancedIntersect reset; + bi = reset; + bi = flush(i, j, e); + } + else if(std::abs (cross_left) < EPSILON ) + { + bi.flush = (e - 1 + n) % n; + bi.extra_area = + extraArea((i + 1) % n, (e - 1 + n) % n, ngon[(e - 1 + n) % n], bi.pi) + + extraArea(e, j, ngon[j], bi.pj); + } + else if(std::abs (cross_right) < EPSILON ) + { + bi.flush = e; + bi.extra_area = extraArea((i + 1) % n, e, ngon[e], bi.pi) + + extraArea((e + 1) % n, j, ngon[j], bi.pj); + } + else + { + bi.extra_area = extraArea((i + 1) % n, e, ngon[e], bi.pi) + + extraArea(e, j, ngon[j], bi.pj); + } + } + else + { + flush(i, j, e); + } + + if(bi.extra_area < balanced_intersections[i][j].extra_area) + { + balanced_intersections[i][j] = bi; + } + return bi; +} + +//! Set function for the done attribute of BalancedIntersections +/*! + * @param i Index of first side + * @param j Index of second side + */ +void BalancedIntersections::markAsDone(int i, int j) +{ + balanced_intersections[i][j].done = true; +} + +//! Operator to get a vector of elements from BalancedIntersections +/*! + * @param i index of a side + */ +const std::vector& BalancedIntersections::operator[]( + size_t i) const +{ + return balanced_intersections[i]; +} + +//! For a combination of two fixed sides of the ngon test all sides between left and right boundary to find the one sided chain with minimal extra area +/*! + * @param i Index of first fixed side + * @param j Index of second fixed side + * @param l Index of left boundary + * @param r Index of right boundary + */ +void Chains::findSingleE(int i, int j, int l, int r) +{ + const size_t n = ngon.size(); + Segment& one = single_sides[i][j]; + if (one.done) + return; + + double min_area = std::numeric_limits::max(); + for (int e = l; e != r + 1 && e != j; e = (e + 1) %n) + { + BalancedIntersect candidate = balanced_inters.balancedIntersect(i, j, e); + if(candidate.extra_area < min_area) + { + min_area = candidate.extra_area; + one.side = e; + one.extra_area = candidate.extra_area; + one.flush = false; + one.exists = true; + } + } + one.done = true; + balanced_inters.markAsDone(i, j); +} + +//! Recursively repeat the search for the one sided chain with minimal extra area to shrink the boundaries of bigger distances +/*! + * @param i Fixed side of the ngon + * @param j1 Lower boundary of search intervall + * @param j2 Upper boundary of search intervall + */ +void Chains::singleSideImpl(int i, int j1, int j2) +{ + const int n = (int)ngon.size(); + if((j1 + 1) %n == j2) + { + return; + } + + int mid = (j1 < j2 ? ((j1 + j2) / 2) : ((j1 + n + j2) / 2)) % n; + int l = single_sides[i][j1].side < 0 ? (j1 + 1) %n : single_sides[i][j1].side; + int r = single_sides[i][j2].side < 0 ? (j2 - 1 + n) %n : single_sides[i][j2].side; + + findSingleE(i, mid, l, r); + singleSideImpl(i, j1, mid); + singleSideImpl(i, mid, j2); + + return; +} + +//! For a combination of two fixed sides of the ngon test all sides between left and right boundary to find the middle side of the h-sided chain with minimal extra area. This is the version for h = 1. +/*! + * @param i Index of first fixed side + * @param j Index of second fixed side + * @param l Index of left boundary + * @param r Index of right boundary + */ +void Chains::findMiddleE1(int i, int j, int l, int r) +{ + const size_t n = ngon.size(); + Segment& one = middle_sides[1][i][j]; + if (one.done) + return; + + double min_area = std::numeric_limits::max(); + for (int e = l; e != r + 1 && e != j; e = (e + 1) %n) + { + const FlushIntersect& before = intersections.lineIntersect(i, e); + if(!before.intersection.position) + continue; + const FlushIntersect& after = intersections.lineIntersect(e, j); + if(!after.intersection.position) + continue; + + double tmp_area = before.extra_area + after.extra_area; + if(tmp_area < min_area) + { + min_area = tmp_area; + one.side = e; + one.extra_area = tmp_area; + one.exists = true; + one.flush = true; + } + } + one.done = true; +} + +//! Recursively repeat the search for the middle side of the h-sided chain with minimal extra area to shrink the boundaries of bigger distances. This is the version for h = 1. +/*! + * @param i Fixed side of the ngon + * @param j1 Lower boundary of search intervall + * @param j2 Upper boundary of search intervall + */ +void Chains::middleSideImpl1(int i, int j1, int j2) +{ + const int n = (int)ngon.size(); + if((j1 + 1) %n == j2) + { + return; + } + + int mid = (j1 < j2 ? ((j1 + j2) / 2) : ((j1 + n + j2) / 2)) % n; + int l = middle_sides[1][i][j1].side < 0 ? (j1 + 1) %n : middle_sides[1][i][j1].side; + int r = middle_sides[1][i][j2].side < 0 ? (j2 - 1 + n) %n : middle_sides[1][i][j2].side; + + findMiddleE1(i, mid, l, r); + middleSideImpl1(i, j1, mid); + middleSideImpl1(i, mid, j2); + + return; +} + +//! For a combination of two fixed sides of the ngon test all sides between left and right boundary to find the middle side of the h-sided chain with minimal extra area. This is the version for h > 1. +/*! + * @param h Length of the h-sided chain + * @param i Index of first fixed side + * @param j Index of second fixed side + * @param l Index of left boundary + * @param r Index of right boundary + */ +void Chains::findMiddleE(int h, int i, int j, int l, int r) +{ + const int n = (int)ngon.size(); + Segment& one = middle_sides[h][i][j]; + if (one.done) + return; + + const int dist = (i <= j ? (j - i) : (j + n - i)); + const int h_floor = (h - 1) / 2; + const int h_ceil = h - 1 - h_floor; + + CV_Assert(dist != 0); + + if(dist - 1 < h) + { + one.done = true; + return; + } + if(dist - 1 == h) + { + one.side = (i + h_floor + 1) % n; + one.extra_area = 0.0; + one.exists = true; + one.flush = true; + one.done = true; + return; + } + + double min_area = std::numeric_limits::max(); + for (int e = l; e != r + 1 && e != j; e = (e + 1) %n) + { + const Segment& before = middle_sides[h_floor][i][e]; + if (before.extra_area == std::numeric_limits::max()) + continue; + const Segment& after = middle_sides[h_ceil][e][j]; + if(after.extra_area == std::numeric_limits::max()) + continue; + + double tmp_area = before.extra_area + after.extra_area; + if(tmp_area < min_area) + { + min_area = tmp_area; + one.side = e; + one.extra_area = tmp_area; + one.exists = true; + one.flush = true; + } + } + one.done = true; +} + +//! Recursively repeat the search for the middle side of the h-sided chain with minimal extra area to shrink the boundaries of bigger distances. This is the version for h > 1. +/*! + * @param h Length of the h-sided chain + * @param i Fixed side of the ngon + * @param j1 Lower boundary of search intervall + * @param j2 Upper boundary of search intervall + */ +void Chains::middleSideImpl(int h, int i, int j1, int j2) +{ + const int n = (int)ngon.size(); + if((j1 + 1) %n == j2) + { + return; + } + + int mid = (j1 < j2 ? ((j1 + j2) / 2) : ((j1 + n + j2) / 2)) % n; + int l = middle_sides[h][i][j1].side < 0 ? (j1 + 1) %n : middle_sides[h][i][j1].side; + int r = middle_sides[h][i][j2].side < 0 ? (j2 - 1 + n) %n : middle_sides[h][i][j2].side; + + findMiddleE(h, i, mid, l, r); + middleSideImpl(h, i, j1, mid); + middleSideImpl(h, i, mid, j2); + + return; +} + +//! Calculate the relevant chain lengths. Starting with a maximum chain length of h, down to a chain length of 1, only chains with half the length of the chain before are needed. +/*! + * @param h Length of the longest chain (h = k - 3) + */ +std::set Chains::relevantChainLengths(int h) +{ + if(h <= 1) + return {h}; + + std::set hs = {h}; + const int h_floor = (h - 1) / 2; + const int h_ceil = h - 1 - h_floor; + std::set h1 = relevantChainLengths(h_floor); + for(const int& hNew : h1) + hs.insert(hNew); + if (h_ceil != h_floor) + { + std::set h2 = relevantChainLengths(h_ceil); + for(const int& hNew : h2) + hs.insert(hNew); + } + return hs; +} + +//! Recursively calculate all the onesided chains for each combination of polygon sides. +/*! + */ +void Chains::calcOneSidedChains() +{ + const int n = (int)ngon.size(); + for(int i = 0; i < n; i++) + { + int j1 = (i + 2) %n, j2 = (i - 2 + n) %n; + + findSingleE(i, j1, (i + 1) %n, (j1 - 1 + n) %n); + findSingleE(i, j2, (i + 1) %n, (j2 - 1 + n) %n); + singleSideImpl(i, j1, j2); + } +} + +//! Recursively calculate the middle sides of the h-sided chains for all combinations of polygon sides. +/*! + * @param h Length of the chains + */ +void Chains::calcMiddleChains(int h) +{ + const int n = (int)ngon.size(); + if (h == 0) + { + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + { + Segment& one = middle_sides[h][i][j]; + const FlushIntersect itrs = intersections.lineIntersect(i, j); + + one.side = -1; + one.extra_area = itrs.extra_area; + one.exists = false; + one.flush = false; + one.done = true; + } + } + return; + } + if (h == 1) + { + for (int i = 0; i < n; i++) + { + int j1 = (i + 2) %n, j2 = (i - 2 + n) %n; + + findMiddleE1(i, j1, (i + 1) %n, (j1 - 1 + n) %n); + findMiddleE1(i, j2, (i + 1) %n, (j2 - 1 + n) %n); + middleSideImpl1(i, j1, j2); + } + return; + } + + for (int i = 0; i < n; i++) + { + int j1 = (i + 2) %n, j2 = (i - 2 + n) %n; + + findMiddleE(h, i, j1, (i + 1) %n, (j1 - 1 + n) %n); + findMiddleE(h, i, j2, (i + 1) %n, (j2 - 1 + n) %n); + middleSideImpl(h, i, j1, j2); + } +} + +//! Find the i and j with the smallest extra area. +/*! + * @param n Number of sides of the input polygon + * @param k Number of sides of the output polygon + */ +Minimum Chains::minimumArea(int n, int k) +{ + Minimum min{}; + for(int i = 0; i < n; i++) + { + for(int j = 0; j < n; j++) + { + if(!single_sides[i][j].exists || !middle_sides[k - 3][j][i].exists) + continue; + + double tmp_area = + single_sides[i][j].extra_area + middle_sides[k - 3][j][i].extra_area; + if(tmp_area < min.area) + { + min.area = tmp_area; + min.i = i; + min.j = j; + } + } + } + return min; +} + +//! Reconstruct the h-sided chain based on the two sides that give the smalles extra area. +/*! + * @param h Length of the k - 3 sided chain. + * @param i First index from minimumArea + * @param j Second index from minimumArea + */ +std::vector Chains::reconstructHSidedChain(int h, int i, int j) +{ + CV_Assert(h != 0); + + if(h == 1) + { + return std::vector{{middle_sides[h][i][j].side, true}}; + } + + std::vector before, after; + const int h_floor = (h - 1) / 2; + const int h_ceil = h - 1 - h_floor; + if(h_floor > 0) + before = reconstructHSidedChain(h_floor, i, middle_sides[h][i][j].side); + if(h_ceil > 0) + after = reconstructHSidedChain(h_ceil, middle_sides[h][i][j].side, j); + + std::vector sides{{middle_sides[h][i][j].side, true}}; + sides.insert(sides.end(), before.begin(), before.end()); + sides.insert(sides.end(), after.begin(), after.end()); + return sides; +} + +//! Get the k sides that build the kgon based on the two sides that give the smalles extra area. +/*! + * @param k Number of sides of the output polygon + * @param i First index from minimumArea + * @param j Second index from minimumArea + */ +std::vector Chains::findKSides(int k, int i, int j) +{ + std::vector sides; + sides.push_back({i, true}); + sides.push_back({j, true}); + + if(single_sides[i][j].flush) + sides.push_back({single_sides[i][j].side, true}); + else + sides.push_back({single_sides[i][j].side, false}); + + std::vector flush_chain = reconstructHSidedChain(k - 3, j, i); + sides.insert(sides.end(), flush_chain.begin(), flush_chain.end()); + std::sort(sides.begin(), sides.end(), + [](const Side& lhs, const Side& rhs) { return lhs.side < rhs.side; }); + + return sides; +} + +//! Calculate the k vertices of the kgon from its k sides. +/*! + * @param sides Sides of the output polygon + */ +std::vector Chains::findKVertices(std::vector& sides) +{ + const int k = (int)sides.size(); + std::vector vertices(k); + + for(int u = 0; u < k; u++) + { + const int next = (u + 1) % k; + if(sides[u].flush && sides[next].flush) + { + vertices[u] = intersections.lineIntersect(sides[u].side, + sides[next].side).intersection.point; + } + else if(sides[u].flush && !sides[next].flush) + { + vertices[u] = balanced_inters[sides[u].side][sides[(u + 2) % k].side].pi; + } + else if(!sides[u].flush && sides[next].flush) + { + vertices[u] = balanced_inters[sides[(u - 1 + k) %k].side][sides[next].side].pj; + } + else + { + CV_Error(cv::Error::StsInternal, "findKVertices logic error!"); + } + } + return vertices; +} + +} //namespace + + +///////////////////////// Helper function definitions ///////////////////////// + +namespace minEnclosingConvexPolygon { + +//! Find the minimum enclosing convex polygon and its area by calculating the one-sided and h-sided chains for all possible combinations of sides and then using the one that gives the smallest extra area. +/*! + * @param ngon The polygon representing the convex hull of the points + * @param k Number of vertices of the output polygon + * @param kgon Minimum area convex k-gon enclosing the given polygon + * @param area Area of kgon + */ +static double findMinAreaPolygon(const std::vector &ngon, + std::vector &minPolygon, int k) +{ + const int n = (int)ngon.size(); + + Chains chains(ngon, k); + chains.calcOneSidedChains(); + std::set hs = chains.relevantChainLengths(k - 3); + for(auto& h : hs) + { + chains.calcMiddleChains(h); + } + + Kgon kgon{}; + + const Minimum min = chains.minimumArea(n, k); + + kgon.i = min.i; + kgon.j = min.j; + kgon.extra_area = min.area; + kgon.sides = chains.findKSides(k, min.i, min.j); + kgon.vertices = chains.findKVertices(kgon.sides); + + minPolygon = kgon.vertices; + return cv::contourArea(minPolygon); +} + +} //namespace + + +//////////////////////////////// Main function //////////////////////////////// + +//! Find the minimum enclosing convex polygon for the given set of points and return its area +/*! + * @param points Set of points + * @param polygon Minimum area convex polygon enclosing the given set of points + * @param k Number of vertices of the output polygon + */ + +double cv::minEnclosingConvexPolygon(cv::InputArray points, cv::OutputArray polygon, int k) +{ + int n = (int)points.getMat().checkVector(2); + + CV_Assert(!points.empty() && n >= k); + CV_CheckGE(n, 3, "ngon must have 3 or more different points enclosing an area"); + CV_CheckGE(k, 3, "k must be 3 or higher"); + + std::vector ngon, kgon; + cv::convexHull(points, ngon, true); + + n = (int)ngon.size(); + + if (n < k) + { + CV_LOG_WARNING(NULL, "convex hull of size " << n << " must have equal or more different points than k = " << k); + polygon.release(); + return 0.; + } + + if (n == k) + { + cv::Mat(ngon).copyTo(polygon); + return cv::contourArea(polygon); + } + + if (cv::contourArea(ngon) < EPSILON) + { + CV_LOG_WARNING(NULL, "Singular input poligon"); + polygon.release(); + return 0.; + } + + double area = minEnclosingConvexPolygon::findMinAreaPolygon(ngon, kgon, k); + cv::Mat(kgon).copyTo(polygon); + + return area; +} diff --git a/modules/imgproc/src/smooth.simd.hpp b/modules/imgproc/src/smooth.simd.hpp index dd9d40e1b3..1ca8021556 100644 --- a/modules/imgproc/src/smooth.simd.hpp +++ b/modules/imgproc/src/smooth.simd.hpp @@ -13,6 +13,7 @@ // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Copyright (C) 2014-2015, Itseez Inc., all rights reserved. +// Copyright (C) 2025, Advanced Micro Devices, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -71,13 +72,13 @@ void GaussianBlurFixedPoint(const Mat& src, Mat& dst, namespace { template -void hlineSmooth1N(const ET* src, int cn, const FT* m, int, FT* dst, int len, int) +void hlineSmooth1N(const ET* src, int cn, const FT* m, int, FT* dst, int len, int, bool) { for (int i = 0; i < len*cn; i++, src++, dst++) *dst = (*m) * (*src); } template <> -void hlineSmooth1N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int) +void hlineSmooth1N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int, bool) { int lencn = len*cn; int i = 0; @@ -91,13 +92,13 @@ void hlineSmooth1N(const uint8_t* src, int cn, const ufi dst[i] = m[0] * src[i]; } template -void hlineSmooth1N1(const ET* src, int cn, const FT*, int, FT* dst, int len, int) +void hlineSmooth1N1(const ET* src, int cn, const FT*, int, FT* dst, int len, int, bool) { for (int i = 0; i < len*cn; i++, src++, dst++) *dst = *src; } template <> -void hlineSmooth1N1(const uint8_t* src, int cn, const ufixedpoint16*, int, ufixedpoint16* dst, int len, int) +void hlineSmooth1N1(const uint8_t* src, int cn, const ufixedpoint16*, int, ufixedpoint16* dst, int len, int, bool) { int lencn = len*cn; int i = 0; @@ -110,7 +111,7 @@ void hlineSmooth1N1(const uint8_t* src, int cn, const uf dst[i] = src[i]; } template -void hlineSmooth3N(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType) +void hlineSmooth3N(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -131,9 +132,17 @@ void hlineSmooth3N(const ET* src, int cn, const FT* m, int, FT* dst, int len, in } src += cn; dst += cn; - for (int i = cn; i < (len - 1)*cn; i++, src++, dst++) - *dst = m[0] * src[-cn] + m[1] * src[0] + m[2] * src[cn]; - + if(processInnerRegion) + { + for (int i = cn; i < (len - 1)*cn; i++, src++, dst++) + *dst = m[0] * src[-cn] + m[1] * src[0] + m[2] * src[cn]; + } + else + { + int offset = (len - 2) * cn; + src += offset; + dst += offset; + } // Point that fall right from border for (int k = 0; k < cn; k++) dst[k] = m[0] * src[k - cn] + m[1] * src[k]; @@ -146,7 +155,7 @@ void hlineSmooth3N(const ET* src, int cn, const FT* m, int, FT* dst, int len, in } } template <> -void hlineSmooth3N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth3N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -168,17 +177,26 @@ void hlineSmooth3N(const uint8_t* src, int cn, const ufi src += cn; dst += cn; int i = cn, lencn = (len - 1)*cn; + if(processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const uint16_t* _m = (const uint16_t*)m; - const int VECSZ = VTraits::vlanes(); - v_uint16 v_mul0 = vx_setall_u16(_m[0]); - v_uint16 v_mul1 = vx_setall_u16(_m[1]); - v_uint16 v_mul2 = vx_setall_u16(_m[2]); - for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) - v_store((uint16_t*)dst, v_add(v_add(v_mul(vx_load_expand(src - cn), v_mul0), v_mul(vx_load_expand(src), v_mul1)), v_mul(vx_load_expand(src + cn), v_mul2))); + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = VTraits::vlanes(); + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + v_uint16 v_mul2 = vx_setall_u16(_m[2]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, v_add(v_add(v_mul(vx_load_expand(src - cn), v_mul0), v_mul(vx_load_expand(src), v_mul1)), v_mul(vx_load_expand(src + cn), v_mul2))); #endif - for (; i < lencn; i++, src++, dst++) - *dst = m[0] * src[-cn] + m[1] * src[0] + m[2] * src[cn]; + for (; i < lencn; i++, src++, dst++) + *dst = m[0] * src[-cn] + m[1] * src[0] + m[2] * src[cn]; + } + else + { + int offset = (len - 2) * cn; + src += offset; + dst += offset; + } // Point that fall right from border for (int k = 0; k < cn; k++) @@ -191,9 +209,8 @@ void hlineSmooth3N(const uint8_t* src, int cn, const ufi } } } - template -void hlineSmooth3N121Impl(const ET* src, int cn, const FT*, int, FT* dst, int len, int borderType) +void hlineSmooth3N121Impl(const ET* src, int cn, const FT*, int, FT* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -218,13 +235,22 @@ void hlineSmooth3N121Impl(const ET* src, int cn, const FT*, int, FT* dst, int le src += cn; dst += cn; int i = cn, lencn = (len - 1)*cn; + if(processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const int VECSZ = VTraits::vlanes(); - for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) - v_store((typename FT::raw_t*)dst, v_shl<(FT::fixedShift-2)>(v_add(vx_load_expand(src - cn), vx_load_expand(src + cn), v_shl<1>((vx_load_expand(src)))))); + const int VECSZ = VTraits::vlanes(); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((typename FT::raw_t*)dst, v_shl<(FT::fixedShift-2)>(v_add(vx_load_expand(src - cn), vx_load_expand(src + cn), v_shl<1>((vx_load_expand(src)))))); #endif - for (; i < lencn; i++, src++, dst++) - *dst = (FT(src[-cn])>>2) + (FT(src[cn])>>2) + (FT(src[0])>>1); + for (; i < lencn; i++, src++, dst++) + *dst = (FT(src[-cn])>>2) + (FT(src[cn])>>2) + (FT(src[0])>>1); + } + else + { + int offset = (len - 2) * cn; + src += offset; + dst += offset; + } // Point that fall right from border for (int k = 0; k < cn; k++) @@ -238,20 +264,20 @@ void hlineSmooth3N121Impl(const ET* src, int cn, const FT*, int, FT* dst, int le } } template -void hlineSmooth3N121(const ET* src, int cn, const FT*, int, FT* dst, int len, int borderType); +void hlineSmooth3N121(const ET* src, int cn, const FT*, int, FT* dst, int len, int borderType, bool processInnerRegion); template <> -void hlineSmooth3N121(const uint8_t* src, int cn, const ufixedpoint16* _m, int _n, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth3N121(const uint8_t* src, int cn, const ufixedpoint16* _m, int _n, ufixedpoint16* dst, int len, int borderType, bool processInnerRegion) { - hlineSmooth3N121Impl(src, cn, _m, _n, dst, len, borderType); + hlineSmooth3N121Impl(src, cn, _m, _n, dst, len, borderType, processInnerRegion); } template <> -void hlineSmooth3N121(const uint16_t* src, int cn, const ufixedpoint32* _m, int _n, ufixedpoint32* dst, int len, int borderType) +void hlineSmooth3N121(const uint16_t* src, int cn, const ufixedpoint32* _m, int _n, ufixedpoint32* dst, int len, int borderType, bool processInnerRegion) { - hlineSmooth3N121Impl(src, cn, _m, _n, dst, len, borderType); + hlineSmooth3N121Impl(src, cn, _m, _n, dst, len, borderType, processInnerRegion); } template -void hlineSmooth3Naba(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType) +void hlineSmooth3Naba(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -275,8 +301,17 @@ void hlineSmooth3Naba(const ET* src, int cn, const FT* m, int, FT* dst, int len, } src += cn; dst += cn; - for (int i = cn; i < (len - 1)*cn; i++, src++, dst++) - *dst = m[1] * src[0] + m[0] * src[-cn] + m[0] * src[cn]; + if(processInnerRegion) + { + for (int i = cn; i < (len - 1)*cn; i++, src++, dst++) + *dst = m[1] * src[0] + m[0] * src[-cn] + m[0] * src[cn]; + } + else + { + int offset = (len - 2) * cn; + src += offset; + dst += offset; + } // Point that fall right from border if (borderType != BORDER_CONSTANT)// If BORDER_CONSTANT out of border values are equal to zero and could be skipped @@ -293,7 +328,7 @@ void hlineSmooth3Naba(const ET* src, int cn, const FT* m, int, FT* dst, int len, } } template <> -void hlineSmooth3Naba(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth3Naba(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -318,16 +353,25 @@ void hlineSmooth3Naba(const uint8_t* src, int cn, const src += cn; dst += cn; int i = cn, lencn = (len - 1)*cn; + if(processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const uint16_t* _m = (const uint16_t*)m; - const int VECSZ = VTraits::vlanes(); - v_uint16 v_mul0 = vx_setall_u16(_m[0]); - v_uint16 v_mul1 = vx_setall_u16(_m[1]); - for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) - v_store((uint16_t*)dst, v_add(v_mul(v_add( vx_load_expand(src - cn), vx_load_expand(src + cn)), v_mul0), v_mul(vx_load_expand(src), v_mul1))); + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = VTraits::vlanes(); + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, v_add(v_mul(v_add( vx_load_expand(src - cn), vx_load_expand(src + cn)), v_mul0), v_mul(vx_load_expand(src), v_mul1))); #endif - for (; i < lencn; i++, src++, dst++) - *((uint16_t*)dst) = saturate_cast(((uint16_t*)m)[1] * (uint32_t)(src[0]) + ((uint16_t*)m)[0] * ((uint32_t)(src[-cn]) + (uint32_t)(src[cn]))); + for (; i < lencn; i++, src++, dst++) + *((uint16_t*)dst) = saturate_cast(((uint16_t*)m)[1] * (uint32_t)(src[0]) + ((uint16_t*)m)[0] * ((uint32_t)(src[-cn]) + (uint32_t)(src[cn]))); + } + else + { + int offset = (len - 2) * cn; + src += offset; + dst += offset; + } // Point that fall right from border if (borderType != BORDER_CONSTANT)// If BORDER_CONSTANT out of border values are equal to zero and could be skipped @@ -344,7 +388,7 @@ void hlineSmooth3Naba(const uint8_t* src, int cn, const } } template -void hlineSmooth5N(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType) +void hlineSmooth5N(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -416,9 +460,17 @@ void hlineSmooth5N(const ET* src, int cn, const FT* m, int, FT* dst, int len, in } src += 2*cn; dst += 2*cn; - for (int i = 2*cn; i < (len - 2)*cn; i++, src++, dst++) - *dst = m[0] * src[-2*cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2*cn]; - + if(processInnerRegion) + { + for (int i = 2*cn; i < (len - 2)*cn; i++, src++, dst++) + *dst = m[0] * src[-2*cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2*cn]; + } + else + { + int offset = (len - 4) * cn; + src += offset; + dst += offset; + } // Points that fall right from border for (int k = 0; k < cn; k++) { @@ -438,7 +490,7 @@ void hlineSmooth5N(const ET* src, int cn, const FT* m, int, FT* dst, int len, in } } template <> -void hlineSmooth5N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth5N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -511,20 +563,28 @@ void hlineSmooth5N(const uint8_t* src, int cn, const ufi src += 2 * cn; dst += 2 * cn; int i = 2*cn, lencn = (len - 2)*cn; + if(processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const uint16_t* _m = (const uint16_t*)m; - const int VECSZ = VTraits::vlanes(); - v_uint16 v_mul0 = vx_setall_u16(_m[0]); - v_uint16 v_mul1 = vx_setall_u16(_m[1]); - v_uint16 v_mul2 = vx_setall_u16(_m[2]); - v_uint16 v_mul3 = vx_setall_u16(_m[3]); - v_uint16 v_mul4 = vx_setall_u16(_m[4]); - for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) - v_store((uint16_t*)dst, v_add(v_add(v_add(v_add(v_mul(vx_load_expand(src - 2 * cn), v_mul0), v_mul(vx_load_expand(src - cn), v_mul1)), v_mul(vx_load_expand(src), v_mul2)), v_mul(vx_load_expand(src + cn), v_mul3)), v_mul(vx_load_expand(src + 2 * cn), v_mul4))); + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = VTraits::vlanes(); + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + v_uint16 v_mul2 = vx_setall_u16(_m[2]); + v_uint16 v_mul3 = vx_setall_u16(_m[3]); + v_uint16 v_mul4 = vx_setall_u16(_m[4]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, v_add(v_add(v_add(v_add(v_mul(vx_load_expand(src - 2 * cn), v_mul0), v_mul(vx_load_expand(src - cn), v_mul1)), v_mul(vx_load_expand(src), v_mul2)), v_mul(vx_load_expand(src + cn), v_mul3)), v_mul(vx_load_expand(src + 2 * cn), v_mul4))); #endif - for (; i < lencn; i++, src++, dst++) - *dst = m[0] * src[-2*cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2*cn]; - + for (; i < lencn; i++, src++, dst++) + *dst = m[0] * src[-2*cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2*cn]; + } + else + { + int offset = (len - 4) * cn; + src += offset; + dst += offset; + } // Points that fall right from border for (int k = 0; k < cn; k++) { @@ -543,8 +603,238 @@ void hlineSmooth5N(const uint8_t* src, int cn, const ufi } } } +#if (CV_SIMD || CV_SIMD_SCALABLE) +v_uint32 vx_setall(unsigned value) { + return vx_setall_u32(value); +} +v_uint16 vx_setall(ushort value) { + return vx_setall_u16(value); +} +#endif +template +void inline smooth3N121Impl(const ET* src, int cn, ET *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride) +{ + int offset = 1; + int vOffset = 2; + int v = idst - 1; + int len = (width - offset) * cn; + int x = offset * cn; + int maxRow = min((ito - vOffset),height-2); +#if (CV_SIMD || CV_SIMD_SCALABLE) + VFT v_8 = vx_setall((WET)8); + const int VECSZ = VTraits::vlanes(); + for (; x <= len - VECSZ; x += (VECSZ)) + { + int idst_ = idst; + int j = v; + const ET* src_0 = src + j * src_stride + x; + const ET* src_1 = src_0 + src_stride; + const ET* src_2 = src_1 + src_stride; + VFT v_src0, v_src1, v_src0_cn, v_src1_cn, v_src0_ncn, v_src1_ncn; + + //row 0 + v_expand(vx_load(src_0 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_0), v_src0, v_src1); + v_expand(vx_load(src_0 + cn), v_src0_cn, v_src1_cn); + VFT b00 = v_add(v_shl<1>(v_src0), v_add(v_src0_ncn, v_src0_cn)); + VFT b01 = v_add(v_shl<1>(v_src1), v_add(v_src1_ncn, v_src1_cn)); + + //row 1 + v_expand(vx_load(src_1 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_1), v_src0, v_src1); + v_expand(vx_load(src_1 + cn), v_src0_cn, v_src1_cn); + VFT b10 = v_add(v_shl<1>(v_src0), v_add(v_src0_ncn, v_src0_cn)); + VFT b11 = v_add(v_shl<1>(v_src1), v_add(v_src1_ncn, v_src1_cn)); + + for (; j < maxRow; j++, idst_++) + { + ET* dstx = dst + (idst_ * dst_stride); + + //row 2 + v_expand(vx_load(src_2 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_2), v_src0, v_src1); + v_expand(vx_load(src_2 + cn), v_src0_cn, v_src1_cn); + src_2 += src_stride; + VFT b20 = v_add(v_shl<1>(v_src0), v_add(v_src0_ncn, v_src0_cn)); + VFT b21 = v_add(v_shl<1>(v_src1), v_add(v_src1_ncn, v_src1_cn)); + + b00 = v_shr<4>(v_add(v_add(v_shl<1>(b10), v_add(b00, b20)), v_8)); + b01 = v_shr<4>(v_add(v_add(v_shl<1>(b11), v_add(b01, b21)), v_8)); + v_store(dstx + x, v_pack(b00, b01)); + + b00 = b10; b01 = b11; + b10 = b20; b11 = b21; + } + } +#endif + for (; x < len; x++) + { + int idst_ = idst; + int j = v; + const ET* src_0 = src + j * src_stride + x; + const ET* src_1 = src_0 + src_stride; + const ET* src_2 = src_1 + src_stride; + + WET b0, b1, b2; + b0 = (src_0[0] << 1) + src_0[-cn] + src_0[cn]; + b1 = (src_1[0] << 1) + src_1[-cn] + src_1[cn]; + + for (; j < maxRow; j++, idst_++) + { + ET* dstx = dst + (idst_ * dst_stride); + b2 = (src_2[0] << 1) + src_2[-cn] + src_2[cn]; + src_2 += src_stride; + dstx[x] = (ET)(((b1 <<1) + b0 + b2 + (1<<3)) >> 4); + + b0 = b1; + b1 = b2; + } + } +} template -void hlineSmooth5N14641(const ET* src, int cn, const FT*, int, FT* dst, int len, int borderType) +void inline smooth3N121(const ET* src, const FT*, const FT*, int cn, ET *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride); + +template <> +void inline smooth3N121(const uint8_t* src, const ufixedpoint16*, const ufixedpoint16*, int cn, uint8_t *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride) +{ + smooth3N121Impl(src, cn, dst, ito, idst, width, height, src_stride, dst_stride); +} +template <> +void inline smooth3N121(const uint16_t* src, const ufixedpoint32*, const ufixedpoint32*, int cn, uint16_t *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride) +{ + smooth3N121Impl(src, cn, dst, ito, idst, width, height, src_stride, dst_stride); +} +template +void inline smooth5N14641Impl(const ET* src, int cn, ET* dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride) +{ + int offset = 2; + int vOffset = 3; + int v = idst - 2; + int len = (width - offset) * cn; + int x = offset * cn; + int maxRow = min((ito - vOffset),height-4); + +#if (CV_SIMD || CV_SIMD_SCALABLE) + VFT v_6 = vx_setall((WET)6); + VFT v_128 = vx_setall((WET)128); + const int VECSZ = VTraits::vlanes(); + for (; x <= len - VECSZ; x += (VECSZ)) + { + int idst_ = idst; + int j = v; + const ET* src_0 = src + j * src_stride + x; + const ET* src_1 = src_0 + src_stride; + const ET* src_2 = src_1 + src_stride; + const ET* src_3 = src_2 + src_stride; + const ET* src_4 = src_3 + src_stride; + VFT v_src0, v_src1, v_src0_cn, v_src1_cn, v_src0_ncn, v_src1_ncn, v_src0_2cn, v_src1_2cn, v_src0_n2cn, v_src1_n2cn; + + //row 0 + v_expand(vx_load(src_0 - 2 * cn), v_src0_n2cn, v_src1_n2cn); + v_expand(vx_load(src_0 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_0), v_src0, v_src1); + v_expand(vx_load(src_0 + cn), v_src0_cn, v_src1_cn); + v_expand(vx_load(src_0 + 2 * cn), v_src0_2cn, v_src1_2cn); + VFT b00 = v_add(v_add(v_add(v_mul(v_src0, v_6), v_shl<2>(v_add(v_src0_ncn, v_src0_cn))), v_src0_n2cn), v_src0_2cn); + VFT b01 = v_add(v_add(v_add(v_mul(v_src1, v_6), v_shl<2>(v_add(v_src1_ncn, v_src1_cn))), v_src1_n2cn), v_src1_2cn); + + //row 1 + v_expand(vx_load(src_1 - 2 * cn), v_src0_n2cn, v_src1_n2cn); + v_expand(vx_load(src_1 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_1), v_src0, v_src1); + v_expand(vx_load(src_1 + cn), v_src0_cn, v_src1_cn); + v_expand(vx_load(src_1 + 2 * cn), v_src0_2cn, v_src1_2cn); + VFT b10 = v_add(v_add(v_add(v_mul(v_src0, v_6), v_shl<2>(v_add(v_src0_ncn, v_src0_cn))), v_src0_n2cn), v_src0_2cn); + VFT b11 = v_add(v_add(v_add(v_mul(v_src1, v_6), v_shl<2>(v_add(v_src1_ncn, v_src1_cn))), v_src1_n2cn), v_src1_2cn); + + //row 2 + v_expand(vx_load(src_2 - 2 * cn), v_src0_n2cn, v_src1_n2cn); + v_expand(vx_load(src_2 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_2), v_src0, v_src1); + v_expand(vx_load(src_2 + cn), v_src0_cn, v_src1_cn); + v_expand(vx_load(src_2 + 2 * cn), v_src0_2cn, v_src1_2cn); + VFT b20 = v_add(v_add(v_add(v_mul(v_src0, v_6), v_shl<2>(v_add(v_src0_ncn, v_src0_cn))), v_src0_n2cn), v_src0_2cn); + VFT b21 = v_add(v_add(v_add(v_mul(v_src1, v_6), v_shl<2>(v_add(v_src1_ncn, v_src1_cn))), v_src1_n2cn), v_src1_2cn); + + //row 3 + v_expand(vx_load(src_3 - 2 * cn), v_src0_n2cn, v_src1_n2cn); + v_expand(vx_load(src_3 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_3), v_src0, v_src1); + v_expand(vx_load(src_3 + cn), v_src0_cn, v_src1_cn); + v_expand(vx_load(src_3 + 2 * cn), v_src0_2cn, v_src1_2cn); + VFT b30 = v_add(v_add(v_add(v_mul(v_src0, v_6), v_shl<2>(v_add(v_src0_ncn, v_src0_cn))), v_src0_n2cn), v_src0_2cn); + VFT b31 = v_add(v_add(v_add(v_mul(v_src1, v_6), v_shl<2>(v_add(v_src1_ncn, v_src1_cn))), v_src1_n2cn), v_src1_2cn); + + for (; j < maxRow; j++, idst_++) + { + ET* dstx = dst + (idst_ * dst_stride); + + //row 4 + v_expand(vx_load(src_4 - 2 * cn), v_src0_n2cn, v_src1_n2cn); + v_expand(vx_load(src_4 - cn), v_src0_ncn, v_src1_ncn); + v_expand(vx_load(src_4), v_src0, v_src1); + v_expand(vx_load(src_4 + cn), v_src0_cn, v_src1_cn); + v_expand(vx_load(src_4 + 2 * cn), v_src0_2cn, v_src1_2cn); + src_4 += src_stride; + VFT b40 = v_add(v_add(v_add(v_mul(v_src0, v_6), v_shl<2>(v_add(v_src0_ncn, v_src0_cn))), v_src0_n2cn), v_src0_2cn); + VFT b41 = v_add(v_add(v_add(v_mul(v_src1, v_6), v_shl<2>(v_add(v_src1_ncn, v_src1_cn))), v_src1_n2cn), v_src1_2cn); + + b00 = v_shr<8>(v_add(v_add(v_add(v_add(v_mul(b20, v_6), v_shl<2>(v_add(b10, b30))), b00), b40),v_128)); + b01= v_shr<8>(v_add(v_add(v_add(v_add(v_mul(b21, v_6), v_shl<2>(v_add(b11, b31))), b01), b41),v_128)); + v_store(dstx + x, v_pack(b00, b01)); + + b00 = b10; b01 = b11; + b10 = b20; b11 = b21; + b20 = b30; b21 = b31; + b30 = b40; b31 = b41; + } + } +#endif + + for (; x < len; x++) + { + int idst_ = idst; + int j = v; + const ET* src_0 = src + j * src_stride + x; + const ET* src_1 = src_0 + src_stride; + const ET* src_2 = src_1 + src_stride; + const ET* src_3 = src_2 + src_stride; + const ET* src_4 = src_3 + src_stride; + WET b0, b1, b2, b3, b4; + b0 = ((src_0[0] * 6) + ((src_0[-cn] + src_0[cn]) << 2) + src_0[-2 * cn] + src_0[2 * cn]); + b1 = ((src_1[0] * 6) + ((src_1[-cn] + src_1[cn]) << 2) + src_1[-2 * cn] + src_1[2 * cn]); + b2 = ((src_2[0] * 6) + ((src_2[-cn] + src_2[cn]) << 2) + src_2[-2 * cn] + src_2[2 * cn]); + b3 = ((src_3[0] * 6) + ((src_3[-cn] + src_3[cn]) << 2) + src_3[-2 * cn] + src_3[2 * cn]); + for (; j < maxRow; j++, idst_++) + { + ET* dstx = dst + (idst_ * dst_stride); + b4 = ((src_4[0] * 6) + ((src_4[-cn] + src_4[cn]) << 2) + src_4[-2 * cn] + src_4[2 * cn]); + src_4 += src_stride; + dstx[x] = (ET)((b2 * 6 + ((b1 + b3) << 2) + b0 + b4 +128 ) >> 8); + + b0 = b1; + b1 = b2; + b2 = b3; + b3 = b4; + } + } +} +template +void inline smooth5N14641(const ET* src, const FT*, const FT*, int cn, ET *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride); + +template <> +void inline smooth5N14641(const uint8_t* src, const ufixedpoint16*, const ufixedpoint16*, int cn, uint8_t *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride) +{ + smooth5N14641Impl(src, cn, dst, ito, idst, width, height, src_stride, dst_stride); +} +template <> +void inline smooth5N14641(const uint16_t* src, const ufixedpoint32*, const ufixedpoint32*, int cn, uint16_t *dst, int ito, int idst, int width, int height, size_t src_stride, size_t dst_stride) +{ + smooth5N14641Impl(src, cn, dst, ito, idst, width, height, src_stride, dst_stride); +} + +template +void hlineSmooth5N14641(const ET* src, int cn, const FT*, int, FT* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -619,8 +909,17 @@ void hlineSmooth5N14641(const ET* src, int cn, const FT*, int, FT* dst, int len, } src += 2 * cn; dst += 2 * cn; - for (int i = 2 * cn; i < (len - 2)*cn; i++, src++, dst++) - *dst = (FT(src[0])>>4)*(uint8_t)6 + (FT(src[-cn])>>2) + (FT(src[cn])>>2) + (FT(src[-2 * cn])>>4) + (FT(src[2 * cn])>>4); + if (processInnerRegion) + { + for (int i = 2 * cn; i < (len - 2)*cn; i++, src++, dst++) + *dst = (FT(src[0])>>4)*(uint8_t)6 + (FT(src[-cn])>>2) + (FT(src[cn])>>2) + (FT(src[-2 * cn])>>4) + (FT(src[2 * cn])>>4); + } + else + { + int offset = (len - 4) * cn; + src += offset; + dst += offset; + } // Points that fall right from border for (int k = 0; k < cn; k++) @@ -641,7 +940,7 @@ void hlineSmooth5N14641(const ET* src, int cn, const FT*, int, FT* dst, int len, } } template <> -void hlineSmooth5N14641(const uint8_t* src, int cn, const ufixedpoint16*, int, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth5N14641(const uint8_t* src, int cn, const ufixedpoint16*, int, ufixedpoint16* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -719,14 +1018,23 @@ void hlineSmooth5N14641(const uint8_t* src, int cn, cons src += 2 * cn; dst += 2 * cn; int i = 2 * cn, lencn = (len - 2)*cn; + if (processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const int VECSZ = VTraits::vlanes(); - v_uint16 v_6 = vx_setall_u16(6); - for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) - v_store((uint16_t*)dst, v_shl<4>(v_add(v_add(v_add(v_mul(vx_load_expand(src), v_6), v_shl<2>(v_add(vx_load_expand(src - cn), vx_load_expand(src + cn)))), vx_load_expand(src - 2 * cn)), vx_load_expand(src + 2 * cn)))); + const int VECSZ = VTraits::vlanes(); + v_uint16 v_6 = vx_setall_u16(6); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, v_shl<4>(v_add(v_add(v_add(v_mul(vx_load_expand(src), v_6), v_shl<2>(v_add(vx_load_expand(src - cn), vx_load_expand(src + cn)))), vx_load_expand(src - 2 * cn)), vx_load_expand(src + 2 * cn)))); #endif - for (; i < lencn; i++, src++, dst++) - *((uint16_t*)dst) = (uint16_t(src[0]) * 6 + ((uint16_t(src[-cn]) + uint16_t(src[cn])) << 2) + uint16_t(src[-2 * cn]) + uint16_t(src[2 * cn])) << 4; + for (; i < lencn; i++, src++, dst++) + *((uint16_t*)dst) = (uint16_t(src[0]) * 6 + ((uint16_t(src[-cn]) + uint16_t(src[cn])) << 2) + uint16_t(src[-2 * cn]) + uint16_t(src[2 * cn])) << 4; + } + else + { + int offset = (len - 4) * cn; + src += offset; + dst += offset; + } // Points that fall right from border for (int k = 0; k < cn; k++) @@ -747,7 +1055,7 @@ void hlineSmooth5N14641(const uint8_t* src, int cn, cons } } template -void hlineSmooth5Nabcba(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType) +void hlineSmooth5Nabcba(const ET* src, int cn, const FT* m, int, FT* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -819,8 +1127,17 @@ void hlineSmooth5Nabcba(const ET* src, int cn, const FT* m, int, FT* dst, int le } src += 2 * cn; dst += 2 * cn; - for (int i = 2 * cn; i < (len - 2)*cn; i++, src++, dst++) - *dst = m[0] * src[-2 * cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2 * cn]; + if(processInnerRegion) + { + for (int i = 2 * cn; i < (len - 2)*cn; i++, src++, dst++) + *dst = m[0] * src[-2 * cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2 * cn]; + } + else + { + int offset = (len - 4) * cn; + src += offset; + dst += offset; + } // Points that fall right from border for (int k = 0; k < cn; k++) @@ -841,7 +1158,7 @@ void hlineSmooth5Nabcba(const ET* src, int cn, const FT* m, int, FT* dst, int le } } template <> -void hlineSmooth5Nabcba(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth5Nabcba(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int borderType, bool processInnerRegion) { if (len == 1) { @@ -917,18 +1234,26 @@ void hlineSmooth5Nabcba(const uint8_t* src, int cn, cons src += 2 * cn; dst += 2 * cn; int i = 2 * cn, lencn = (len - 2)*cn; + if(processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const uint16_t* _m = (const uint16_t*)m; - const int VECSZ = VTraits::vlanes(); - v_uint16 v_mul0 = vx_setall_u16(_m[0]); - v_uint16 v_mul1 = vx_setall_u16(_m[1]); - v_uint16 v_mul2 = vx_setall_u16(_m[2]); - for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) - v_store((uint16_t*)dst, v_add(v_add(v_mul(v_add(vx_load_expand(src - 2 * cn), vx_load_expand(src + 2 * cn)), v_mul0), v_mul(v_add(vx_load_expand(src - cn), vx_load_expand(src + cn)), v_mul1)), v_mul(vx_load_expand(src), v_mul2))); + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = VTraits::vlanes(); + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + v_uint16 v_mul2 = vx_setall_u16(_m[2]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, v_add(v_add(v_mul(v_add(vx_load_expand(src - 2 * cn), vx_load_expand(src + 2 * cn)), v_mul0), v_mul(v_add(vx_load_expand(src - cn), vx_load_expand(src + cn)), v_mul1)), v_mul(vx_load_expand(src), v_mul2))); #endif - for (; i < lencn; i++, src++, dst++) - *((uint16_t*)dst) = saturate_cast(((uint16_t*)m)[0] * ((uint32_t)(src[-2 * cn]) + (uint32_t)(src[2 * cn])) + ((uint16_t*)m)[1] * ((uint32_t)(src[-cn]) + (uint32_t)(src[cn])) + ((uint16_t*)m)[2] * (uint32_t)(src[0])); - + for (; i < lencn; i++, src++, dst++) + *((uint16_t*)dst) = saturate_cast(((uint16_t*)m)[0] * ((uint32_t)(src[-2 * cn]) + (uint32_t)(src[2 * cn])) + ((uint16_t*)m)[1] * ((uint32_t)(src[-cn]) + (uint32_t)(src[cn])) + ((uint16_t*)m)[2] * (uint32_t)(src[0])); + } + else + { + int offset = (len - 4) * cn; + src += offset; + dst += offset; + } // Points that fall right from border if (borderType != BORDER_CONSTANT)// If BORDER_CONSTANT out of border values are equal to zero and could be skipped { @@ -951,7 +1276,7 @@ void hlineSmooth5Nabcba(const uint8_t* src, int cn, cons } } template -void hlineSmooth(const ET* src, int cn, const FT* m, int n, FT* dst, int len, int borderType) +void hlineSmooth(const ET* src, int cn, const FT* m, int n, FT* dst, int len, int borderType, bool) { int pre_shift = n / 2; int post_shift = n - pre_shift; @@ -1005,7 +1330,7 @@ void hlineSmooth(const ET* src, int cn, const FT* m, int n, FT* dst, int len, in } } template <> -void hlineSmooth(const uint8_t* src, int cn, const ufixedpoint16* m, int n, ufixedpoint16* dst, int len, int borderType) +void hlineSmooth(const uint8_t* src, int cn, const ufixedpoint16* m, int n, ufixedpoint16* dst, int len, int borderType, bool) { int pre_shift = n / 2; int post_shift = n - pre_shift; @@ -1070,7 +1395,7 @@ void hlineSmooth(const uint8_t* src, int cn, const ufixe } } template -void hlineSmoothONa_yzy_a(const ET* src, int cn, const FT* m, int n, FT* dst, int len, int borderType) +void hlineSmoothONa_yzy_a(const ET* src, int cn, const FT* m, int n, FT* dst, int len, int borderType, bool) { int pre_shift = n / 2; int post_shift = n - pre_shift; @@ -1124,7 +1449,7 @@ void hlineSmoothONa_yzy_a(const ET* src, int cn, const FT* m, int n, FT* dst, in } } template <> -void hlineSmoothONa_yzy_a(const uint8_t* src, int cn, const ufixedpoint16* m, int n, ufixedpoint16* dst, int len, int borderType) +void hlineSmoothONa_yzy_a(const uint8_t* src, int cn, const ufixedpoint16* m, int n, ufixedpoint16* dst, int len, int borderType, bool) { int pre_shift = n / 2; int post_shift = n - pre_shift; @@ -1189,7 +1514,7 @@ void hlineSmoothONa_yzy_a(const uint8_t* src, int cn, co } } template <> -void hlineSmoothONa_yzy_a(const uint16_t* src, int cn, const ufixedpoint32* m, int n, ufixedpoint32* dst, int len, int borderType) +void hlineSmoothONa_yzy_a(const uint16_t* src, int cn, const ufixedpoint32* m, int n, ufixedpoint32* dst, int len, int borderType, bool) { int pre_shift = n / 2; int post_shift = n - pre_shift; @@ -1265,14 +1590,14 @@ void hlineSmoothONa_yzy_a(const uint16_t* src, int cn, } } template -void vlineSmooth1N(const FT* const * src, const FT* m, int, ET* dst, int len) +void vlineSmooth1N(const FT* const * src, const FT* m, int, ET* dst, int len, int , bool) { const FT* src0 = src[0]; for (int i = 0; i < len; i++) dst[i] = *m * src0[i]; } template <> -void vlineSmooth1N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len) +void vlineSmooth1N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len, int , bool) { const ufixedpoint16* src0 = src[0]; int i = 0; @@ -1286,14 +1611,14 @@ void vlineSmooth1N(const ufixedpoint16* const * src, con dst[i] = m[0] * src0[i]; } template -void vlineSmooth1N1(const FT* const * src, const FT*, int, ET* dst, int len) +void vlineSmooth1N1(const FT* const * src, const FT*, int, ET* dst, int len, int, bool) { const FT* src0 = src[0]; for (int i = 0; i < len; i++) dst[i] = src0[i]; } template <> -void vlineSmooth1N1(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len) +void vlineSmooth1N1(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len, int , bool) { const ufixedpoint16* src0 = src[0]; int i = 0; @@ -1306,164 +1631,42 @@ void vlineSmooth1N1(const ufixedpoint16* const * src, co dst[i] = src0[i]; } template -void vlineSmooth3N(const FT* const * src, const FT* m, int, ET* dst, int len) +void vlineSmooth3N(const FT* const * src, const FT* m, int, ET* dst, int len, int kcn, bool processInnerRegion) { - for (int i = 0; i < len; i++) + int i = 0; + for (; i < kcn; i++) dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; -} -template <> -void vlineSmooth3N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len) -{ - int i = 0; -#if (CV_SIMD || CV_SIMD_SCALABLE) - const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); - v_int32 v_128_4 = vx_setall_s32(128 << 16); - const int VECSZ = VTraits::vlanes(); - if (len >= VECSZ) + if(processInnerRegion) { - ufixedpoint32 val[] = { (m[0] + m[1] + m[2]) * ufixedpoint16((uint8_t)128) }; - v_128_4 = vx_setall_s32(*((int32_t*)val)); + for (; i < len-kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; } - uint32_t val01; - std::memcpy(&val01, m, sizeof(val01)); - v_int16 v_mul01 = v_reinterpret_as_s16(vx_setall_u32(val01)); - v_int16 v_mul2 = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + 2)))); - for (; i <= len - 4*VECSZ; i += 4*VECSZ) - { - v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; - v_int16 v_tmp0, v_tmp1; - - const int16_t* src0 = (const int16_t*)src[0] + i; - const int16_t* src1 = (const int16_t*)src[1] + i; - v_src00 = vx_load(src0); - v_src01 = vx_load(src0 + VECSZ); - v_src02 = vx_load(src0 + 2*VECSZ); - v_src03 = vx_load(src0 + 3*VECSZ); - v_src10 = vx_load(src1); - v_src11 = vx_load(src1 + VECSZ); - v_src12 = vx_load(src1 + 2*VECSZ); - v_src13 = vx_load(src1 + 3*VECSZ); - v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_int32 v_res0 = v_dotprod(v_tmp0, v_mul01); - v_int32 v_res1 = v_dotprod(v_tmp1, v_mul01); - v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_int32 v_res2 = v_dotprod(v_tmp0, v_mul01); - v_int32 v_res3 = v_dotprod(v_tmp1, v_mul01); - v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_int32 v_res4 = v_dotprod(v_tmp0, v_mul01); - v_int32 v_res5 = v_dotprod(v_tmp1, v_mul01); - v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_int32 v_res6 = v_dotprod(v_tmp0, v_mul01); - v_int32 v_res7 = v_dotprod(v_tmp1, v_mul01); - - v_int32 v_resj0, v_resj1; - const int16_t* src2 = (const int16_t*)src[2] + i; - v_src00 = vx_load(src2); - v_src01 = vx_load(src2 + VECSZ); - v_src02 = vx_load(src2 + 2*VECSZ); - v_src03 = vx_load(src2 + 3*VECSZ); - v_mul_expand(v_add_wrap(v_src00, v_128), v_mul2, v_resj0, v_resj1); - v_res0 = v_add(v_res0, v_resj0); - v_res1 = v_add(v_res1, v_resj1); - v_mul_expand(v_add_wrap(v_src01, v_128), v_mul2, v_resj0, v_resj1); - v_res2 = v_add(v_res2, v_resj0); - v_res3 = v_add(v_res3, v_resj1); - v_mul_expand(v_add_wrap(v_src02, v_128), v_mul2, v_resj0, v_resj1); - v_res4 = v_add(v_res4, v_resj0); - v_res5 = v_add(v_res5, v_resj1); - v_mul_expand(v_add_wrap(v_src03, v_128), v_mul2, v_resj0, v_resj1); - v_res6 = v_add(v_res6, v_resj0); - v_res7 = v_add(v_res7, v_resj1); - - v_res0 = v_add(v_res0, v_128_4); - v_res1 = v_add(v_res1, v_128_4); - v_res2 = v_add(v_res2, v_128_4); - v_res3 = v_add(v_res3, v_128_4); - v_res4 = v_add(v_res4, v_128_4); - v_res5 = v_add(v_res5, v_128_4); - v_res6 = v_add(v_res6, v_128_4); - v_res7 = v_add(v_res7, v_128_4); - - v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); - v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); - } -#endif - for (; i < len; i++) + for (i = len-kcn; i < len; i++) dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; -} -template -void vlineSmooth3N121(const FT* const * src, const FT*, int, ET* dst, int len) -{ - for (int i = 0; i < len; i++) - dst[i] = (FT::WT(src[0][i]) >> 2) + (FT::WT(src[2][i]) >> 2) + (FT::WT(src[1][i]) >> 1); + } template <> -void vlineSmooth3N121(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len) +void vlineSmooth3N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len, int kcn, bool processInnerRegion) { int i = 0; -#if (CV_SIMD || CV_SIMD_SCALABLE) - const int VECSZ = VTraits::vlanes(); - for (; i <= len - 2*VECSZ; i += 2*VECSZ) + for (; i < kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; + if(processInnerRegion) { - v_uint32 v_src00, v_src01, v_src02, v_src03, v_src10, v_src11, v_src12, v_src13, v_src20, v_src21, v_src22, v_src23; - v_expand(vx_load((uint16_t*)(src[0]) + i), v_src00, v_src01); - v_expand(vx_load((uint16_t*)(src[0]) + i + VECSZ), v_src02, v_src03); - v_expand(vx_load((uint16_t*)(src[1]) + i), v_src10, v_src11); - v_expand(vx_load((uint16_t*)(src[1]) + i + VECSZ), v_src12, v_src13); - v_expand(vx_load((uint16_t*)(src[2]) + i), v_src20, v_src21); - v_expand(vx_load((uint16_t*)(src[2]) + i + VECSZ), v_src22, v_src23); - v_store(dst + i, v_pack(v_rshr_pack<10>(v_add(v_add(v_src00, v_src20), v_add(v_src10, v_src10)), v_add(v_add(v_src01, v_src21), v_add(v_src11, v_src11))), - v_rshr_pack<10>(v_add(v_add(v_src02, v_src22), v_add(v_src12, v_src12)), v_add(v_add(v_src03, v_src23), v_add(v_src13, v_src13))))); - } -#endif - for (; i < len; i++) - dst[i] = (((uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[2]))[i]) + ((uint32_t)(((uint16_t*)(src[1]))[i]) << 1)) + (1 << 9)) >> 10; -} -template <> -void vlineSmooth3N121(const ufixedpoint32* const * src, const ufixedpoint32*, int, uint16_t* dst, int len) -{ - int i = 0; #if (CV_SIMD || CV_SIMD_SCALABLE) - const int VECSZ = VTraits::vlanes(); - for (; i <= len - 2*VECSZ; i += 2*VECSZ) - { - v_uint64 v_src00, v_src01, v_src02, v_src03, v_src10, v_src11, v_src12, v_src13, v_src20, v_src21, v_src22, v_src23; - v_expand(vx_load((uint32_t*)(src[0]) + i), v_src00, v_src01); - v_expand(vx_load((uint32_t*)(src[0]) + i + VECSZ), v_src02, v_src03); - v_expand(vx_load((uint32_t*)(src[1]) + i), v_src10, v_src11); - v_expand(vx_load((uint32_t*)(src[1]) + i + VECSZ), v_src12, v_src13); - v_expand(vx_load((uint32_t*)(src[2]) + i), v_src20, v_src21); - v_expand(vx_load((uint32_t*)(src[2]) + i + VECSZ), v_src22, v_src23); - v_store(dst + i, v_pack(v_rshr_pack<18>(v_add(v_add(v_src00, v_src20), v_add(v_src10, v_src10)), v_add(v_add(v_src01, v_src21), v_add(v_src11, v_src11))), - v_rshr_pack<18>(v_add(v_add(v_src02, v_src22), v_add(v_src12, v_src12)), v_add(v_add(v_src03, v_src23), v_add(v_src13, v_src13))))); - } -#endif - for (; i < len; i++) - dst[i] = (((uint64_t)((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[2]))[i]) + ((uint64_t(((uint32_t*)(src[1]))[i]) << 1)) + (1 << 17)) >> 18; -} -template -void vlineSmooth5N(const FT* const * src, const FT* m, int, ET* dst, int len) -{ - for (int i = 0; i < len; i++) - dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; -} -template <> -void vlineSmooth5N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len) -{ - int i = 0; -#if (CV_SIMD || CV_SIMD_SCALABLE) - const int VECSZ = VTraits::vlanes(); - if (len >= 4 * VECSZ) - { - ufixedpoint32 val[] = { (m[0] + m[1] + m[2] + m[3] + m[4]) * ufixedpoint16((uint8_t)128) }; - v_int32 v_128_4 = vx_setall_s32(*((int32_t*)val)); const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); - v_int16 v_mul01 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)m))); - v_int16 v_mul23 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)(m + 2)))); - v_int16 v_mul4 = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + 4)))); - for (; i <= len - 4*VECSZ; i += 4*VECSZ) + v_int32 v_128_4 = vx_setall_s32(128 << 16); + const int VECSZ = VTraits::vlanes(); + if (len >= VECSZ) + { + ufixedpoint32 val[] = { (m[0] + m[1] + m[2]) * ufixedpoint16((uint8_t)128) }; + v_128_4 = vx_setall_s32(*((int32_t*)val)); + } + uint32_t val01; + std::memcpy(&val01, m, sizeof(val01)); + v_int16 v_mul01 = v_reinterpret_as_s16(vx_setall_u32(val01)); + v_int16 v_mul2 = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + 2)))); + for (; i <= min(len - 4*VECSZ, len-kcn); i += 4*VECSZ) { v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; v_int16 v_tmp0, v_tmp1; @@ -1491,45 +1694,22 @@ void vlineSmooth5N(const ufixedpoint16* const * src, con v_int32 v_res6 = v_dotprod(v_tmp0, v_mul01); v_int32 v_res7 = v_dotprod(v_tmp1, v_mul01); + v_int32 v_resj0, v_resj1; const int16_t* src2 = (const int16_t*)src[2] + i; - const int16_t* src3 = (const int16_t*)src[3] + i; v_src00 = vx_load(src2); v_src01 = vx_load(src2 + VECSZ); v_src02 = vx_load(src2 + 2*VECSZ); v_src03 = vx_load(src2 + 3*VECSZ); - v_src10 = vx_load(src3); - v_src11 = vx_load(src3 + VECSZ); - v_src12 = vx_load(src3 + 2*VECSZ); - v_src13 = vx_load(src3 + 3*VECSZ); - v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_res0 = v_add(v_res0, v_dotprod(v_tmp0, v_mul23)); - v_res1 = v_add(v_res1, v_dotprod(v_tmp1, v_mul23)); - v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_res2 = v_add(v_res2, v_dotprod(v_tmp0, v_mul23)); - v_res3 = v_add(v_res3, v_dotprod(v_tmp1, v_mul23)); - v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_res4 = v_add(v_res4, v_dotprod(v_tmp0, v_mul23)); - v_res5 = v_add(v_res5, v_dotprod(v_tmp1, v_mul23)); - v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_res6 = v_add(v_res6, v_dotprod(v_tmp0, v_mul23)); - v_res7 = v_add(v_res7, v_dotprod(v_tmp1, v_mul23)); - - v_int32 v_resj0, v_resj1; - const int16_t* src4 = (const int16_t*)src[4] + i; - v_src00 = vx_load(src4); - v_src01 = vx_load(src4 + VECSZ); - v_src02 = vx_load(src4 + 2*VECSZ); - v_src03 = vx_load(src4 + 3*VECSZ); - v_mul_expand(v_add_wrap(v_src00, v_128), v_mul4, v_resj0, v_resj1); + v_mul_expand(v_add_wrap(v_src00, v_128), v_mul2, v_resj0, v_resj1); v_res0 = v_add(v_res0, v_resj0); v_res1 = v_add(v_res1, v_resj1); - v_mul_expand(v_add_wrap(v_src01, v_128), v_mul4, v_resj0, v_resj1); + v_mul_expand(v_add_wrap(v_src01, v_128), v_mul2, v_resj0, v_resj1); v_res2 = v_add(v_res2, v_resj0); v_res3 = v_add(v_res3, v_resj1); - v_mul_expand(v_add_wrap(v_src02, v_128), v_mul4, v_resj0, v_resj1); + v_mul_expand(v_add_wrap(v_src02, v_128), v_mul2, v_resj0, v_resj1); v_res4 = v_add(v_res4, v_resj0); v_res5 = v_add(v_res5, v_resj1); - v_mul_expand(v_add_wrap(v_src03, v_128), v_mul4, v_resj0, v_resj1); + v_mul_expand(v_add_wrap(v_src03, v_128), v_mul2, v_resj0, v_resj1); v_res6 = v_add(v_res6, v_resj0); v_res7 = v_add(v_res7, v_resj1); @@ -1543,92 +1723,345 @@ void vlineSmooth5N(const ufixedpoint16* const * src, con v_res7 = v_add(v_res7, v_128_4); v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); } - } #endif - for (; i < len; i++) + for (; i < len-kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; + } + for (i=len-kcn; i < len; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; +} +template +void vlineSmooth3N121(const FT* const * src, const FT*, int, ET* dst, int len, int kcn, bool processInnerRegion) +{ + int i = 0; + for (; i < kcn; i++) + dst[i] = (FT::WT(src[0][i]) >> 2) + (FT::WT(src[2][i]) >> 2) + (FT::WT(src[1][i]) >> 1); + if(processInnerRegion) + { + for (; i < len-kcn; i++) + dst[i] = (FT::WT(src[0][i]) >> 2) + (FT::WT(src[2][i]) >> 2) + (FT::WT(src[1][i]) >> 1); + } + for (i = len-kcn; i < len; i++) + dst[i] = (FT::WT(src[0][i]) >> 2) + (FT::WT(src[2][i]) >> 2) + (FT::WT(src[1][i]) >> 1); +} +template <> +void vlineSmooth3N121(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len, int kcn, bool processInnerRegion) +{ + int i = 0; + for (; i < kcn; i++) + dst[i] = (((uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[2]))[i]) + ((uint32_t)(((uint16_t*)(src[1]))[i]) << 1)) + (1 << 9)) >> 10; + + if(processInnerRegion) + { +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int VECSZ = VTraits::vlanes(); + for (; i <= min(len - 2*VECSZ, len-kcn); i += 2*VECSZ) + { + v_uint32 v_src00, v_src01, v_src02, v_src03, v_src10, v_src11, v_src12, v_src13, v_src20, v_src21, v_src22, v_src23; + v_expand(vx_load((uint16_t*)(src[0]) + i), v_src00, v_src01); + v_expand(vx_load((uint16_t*)(src[0]) + i + VECSZ), v_src02, v_src03); + v_expand(vx_load((uint16_t*)(src[1]) + i), v_src10, v_src11); + v_expand(vx_load((uint16_t*)(src[1]) + i + VECSZ), v_src12, v_src13); + v_expand(vx_load((uint16_t*)(src[2]) + i), v_src20, v_src21); + v_expand(vx_load((uint16_t*)(src[2]) + i + VECSZ), v_src22, v_src23); + v_store(dst + i, v_pack(v_rshr_pack<10>(v_add(v_add(v_src00, v_src20), v_add(v_src10, v_src10)), v_add(v_add(v_src01, v_src21), v_add(v_src11, v_src11))), + v_rshr_pack<10>(v_add(v_add(v_src02, v_src22), v_add(v_src12, v_src12)), v_add(v_add(v_src03, v_src23), v_add(v_src13, v_src13))))); + } +#endif + for (; i < len-kcn; i++) + dst[i] = (((uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[2]))[i]) + ((uint32_t)(((uint16_t*)(src[1]))[i]) << 1)) + (1 << 9)) >> 10; + } + for (i = len-kcn; i < len; i++) + dst[i] = (((uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[2]))[i]) + ((uint32_t)(((uint16_t*)(src[1]))[i]) << 1)) + (1 << 9)) >> 10; +} +template <> +void vlineSmooth3N121(const ufixedpoint32* const * src, const ufixedpoint32*, int, uint16_t* dst, int len, int kcn, bool processInnerRegion) +{ + int i = 0; + for (; i < kcn; i++) + dst[i] = (((uint64_t)((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[2]))[i]) + ((uint64_t(((uint32_t*)(src[1]))[i]) << 1)) + (1 << 17)) >> 18; + + if(processInnerRegion) + { +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int VECSZ = VTraits::vlanes(); + for (; i <= min(len - 2*VECSZ, len-kcn); i += 2*VECSZ) + { + v_uint64 v_src00, v_src01, v_src02, v_src03, v_src10, v_src11, v_src12, v_src13, v_src20, v_src21, v_src22, v_src23; + v_expand(vx_load((uint32_t*)(src[0]) + i), v_src00, v_src01); + v_expand(vx_load((uint32_t*)(src[0]) + i + VECSZ), v_src02, v_src03); + v_expand(vx_load((uint32_t*)(src[1]) + i), v_src10, v_src11); + v_expand(vx_load((uint32_t*)(src[1]) + i + VECSZ), v_src12, v_src13); + v_expand(vx_load((uint32_t*)(src[2]) + i), v_src20, v_src21); + v_expand(vx_load((uint32_t*)(src[2]) + i + VECSZ), v_src22, v_src23); + v_store(dst + i, v_pack(v_rshr_pack<18>(v_add(v_add(v_src00, v_src20), v_add(v_src10, v_src10)), v_add(v_add(v_src01, v_src21), v_add(v_src11, v_src11))), + v_rshr_pack<18>(v_add(v_add(v_src02, v_src22), v_add(v_src12, v_src12)), v_add(v_add(v_src03, v_src23), v_add(v_src13, v_src13))))); + } +#endif + for (; i < len-kcn; i++) + dst[i] = (((uint64_t)((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[2]))[i]) + ((uint64_t(((uint32_t*)(src[1]))[i]) << 1)) + (1 << 17)) >> 18; + } + for (i = len-kcn; i < len; i++) + dst[i] = (((uint64_t)((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[2]))[i]) + ((uint64_t(((uint32_t*)(src[1]))[i]) << 1)) + (1 << 17)) >> 18; +} +template +void vlineSmooth5N(const FT* const * src, const FT* m, int, ET* dst, int len, int kcn, bool processInnerRegion) +{ + int i = 0; + for (; i < kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; + + if(processInnerRegion) + { + for (; i < len-kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; + } + for (i = len-kcn; i < len; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; + + +} +template <> +void vlineSmooth5N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len, int kcn, bool processInnerRegion) +{ + int i = 0; + for (; i < kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; + + if(processInnerRegion) + { +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int VECSZ = VTraits::vlanes(); + if (len >= 4 * VECSZ) + { + ufixedpoint32 val[] = { (m[0] + m[1] + m[2] + m[3] + m[4]) * ufixedpoint16((uint8_t)128) }; + v_int32 v_128_4 = vx_setall_s32(*((int32_t*)val)); + const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); + v_int16 v_mul01 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)m))); + v_int16 v_mul23 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)(m + 2)))); + v_int16 v_mul4 = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + 4)))); + for (; i <= min(len - 4*VECSZ, len-kcn); i += 4*VECSZ) + { + v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; + v_int16 v_tmp0, v_tmp1; + + const int16_t* src0 = (const int16_t*)src[0] + i; + const int16_t* src1 = (const int16_t*)src[1] + i; + v_src00 = vx_load(src0); + v_src01 = vx_load(src0 + VECSZ); + v_src02 = vx_load(src0 + 2*VECSZ); + v_src03 = vx_load(src0 + 3*VECSZ); + v_src10 = vx_load(src1); + v_src11 = vx_load(src1 + VECSZ); + v_src12 = vx_load(src1 + 2*VECSZ); + v_src13 = vx_load(src1 + 3*VECSZ); + v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); + v_int32 v_res0 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res1 = v_dotprod(v_tmp1, v_mul01); + v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); + v_int32 v_res2 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res3 = v_dotprod(v_tmp1, v_mul01); + v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); + v_int32 v_res4 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res5 = v_dotprod(v_tmp1, v_mul01); + v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); + v_int32 v_res6 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res7 = v_dotprod(v_tmp1, v_mul01); + + const int16_t* src2 = (const int16_t*)src[2] + i; + const int16_t* src3 = (const int16_t*)src[3] + i; + v_src00 = vx_load(src2); + v_src01 = vx_load(src2 + VECSZ); + v_src02 = vx_load(src2 + 2*VECSZ); + v_src03 = vx_load(src2 + 3*VECSZ); + v_src10 = vx_load(src3); + v_src11 = vx_load(src3 + VECSZ); + v_src12 = vx_load(src3 + 2*VECSZ); + v_src13 = vx_load(src3 + 3*VECSZ); + v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); + v_res0 = v_add(v_res0, v_dotprod(v_tmp0, v_mul23)); + v_res1 = v_add(v_res1, v_dotprod(v_tmp1, v_mul23)); + v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); + v_res2 = v_add(v_res2, v_dotprod(v_tmp0, v_mul23)); + v_res3 = v_add(v_res3, v_dotprod(v_tmp1, v_mul23)); + v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); + v_res4 = v_add(v_res4, v_dotprod(v_tmp0, v_mul23)); + v_res5 = v_add(v_res5, v_dotprod(v_tmp1, v_mul23)); + v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); + v_res6 = v_add(v_res6, v_dotprod(v_tmp0, v_mul23)); + v_res7 = v_add(v_res7, v_dotprod(v_tmp1, v_mul23)); + + v_int32 v_resj0, v_resj1; + const int16_t* src4 = (const int16_t*)src[4] + i; + v_src00 = vx_load(src4); + v_src01 = vx_load(src4 + VECSZ); + v_src02 = vx_load(src4 + 2*VECSZ); + v_src03 = vx_load(src4 + 3*VECSZ); + v_mul_expand(v_add_wrap(v_src00, v_128), v_mul4, v_resj0, v_resj1); + v_res0 = v_add(v_res0, v_resj0); + v_res1 = v_add(v_res1, v_resj1); + v_mul_expand(v_add_wrap(v_src01, v_128), v_mul4, v_resj0, v_resj1); + v_res2 = v_add(v_res2, v_resj0); + v_res3 = v_add(v_res3, v_resj1); + v_mul_expand(v_add_wrap(v_src02, v_128), v_mul4, v_resj0, v_resj1); + v_res4 = v_add(v_res4, v_resj0); + v_res5 = v_add(v_res5, v_resj1); + v_mul_expand(v_add_wrap(v_src03, v_128), v_mul4, v_resj0, v_resj1); + v_res6 = v_add(v_res6, v_resj0); + v_res7 = v_add(v_res7, v_resj1); + + v_res0 = v_add(v_res0, v_128_4); + v_res1 = v_add(v_res1, v_128_4); + v_res2 = v_add(v_res2, v_128_4); + v_res3 = v_add(v_res3, v_128_4); + v_res4 = v_add(v_res4, v_128_4); + v_res5 = v_add(v_res5, v_128_4); + v_res6 = v_add(v_res6, v_128_4); + v_res7 = v_add(v_res7, v_128_4); + + v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + } + } +#endif + for (; i < len-kcn; i++) + dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; + } + for ( i = len-kcn; i < len; i++) dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; } template -void vlineSmooth5N14641(const FT* const * src, const FT*, int, ET* dst, int len) -{ - for (int i = 0; i < len; i++) - dst[i] = (FT::WT(src[2][i])*(uint8_t)6 + ((FT::WT(src[1][i]) + FT::WT(src[3][i]))<<2) + FT::WT(src[0][i]) + FT::WT(src[4][i])) >> 4; -} -template <> -void vlineSmooth5N14641(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len) +void vlineSmooth5N14641(const FT* const * src, const FT*, int, ET* dst, int len, int kcn, bool processInnerRegion) { int i = 0; -#if (CV_SIMD || CV_SIMD_SCALABLE) - v_uint32 v_6 = vx_setall_u32(6); - const int VECSZ = VTraits::vlanes(); - for (; i <= len - 2*VECSZ; i += 2*VECSZ) + for (; i < kcn; i++) + dst[i] = (FT::WT(src[2][i])*(uint8_t)6 + ((FT::WT(src[1][i]) + FT::WT(src[3][i]))<<2) + FT::WT(src[0][i]) + FT::WT(src[4][i])) >> 4; + if(processInnerRegion) { - v_uint32 v_src00, v_src10, v_src20, v_src30, v_src40; - v_uint32 v_src01, v_src11, v_src21, v_src31, v_src41; - v_uint32 v_src02, v_src12, v_src22, v_src32, v_src42; - v_uint32 v_src03, v_src13, v_src23, v_src33, v_src43; - v_expand(vx_load((uint16_t*)(src[0]) + i), v_src00, v_src01); - v_expand(vx_load((uint16_t*)(src[0]) + i + VECSZ), v_src02, v_src03); - v_expand(vx_load((uint16_t*)(src[1]) + i), v_src10, v_src11); - v_expand(vx_load((uint16_t*)(src[1]) + i + VECSZ), v_src12, v_src13); - v_expand(vx_load((uint16_t*)(src[2]) + i), v_src20, v_src21); - v_expand(vx_load((uint16_t*)(src[2]) + i + VECSZ), v_src22, v_src23); - v_expand(vx_load((uint16_t*)(src[3]) + i), v_src30, v_src31); - v_expand(vx_load((uint16_t*)(src[3]) + i + VECSZ), v_src32, v_src33); - v_expand(vx_load((uint16_t*)(src[4]) + i), v_src40, v_src41); - v_expand(vx_load((uint16_t*)(src[4]) + i + VECSZ), v_src42, v_src43); - v_store(dst + i, v_pack(v_rshr_pack<12>(v_add(v_add(v_add(v_mul(v_src20, v_6), v_shl<2>(v_add(v_src10, v_src30))), v_src00), v_src40), - v_add(v_add(v_add(v_mul(v_src21, v_6), v_shl<2>(v_add(v_src11, v_src31))), v_src01), v_src41)), - v_rshr_pack<12>(v_add(v_add(v_add(v_mul(v_src22, v_6), v_shl<2>(v_add(v_src12, v_src32))), v_src02), v_src42), - v_add(v_add(v_add(v_mul(v_src23, v_6), v_shl<2>(v_add(v_src13, v_src33))), v_src03), v_src43)))); + for (; i < len-kcn; i++) + dst[i] = (FT::WT(src[2][i])*(uint8_t)6 + ((FT::WT(src[1][i]) + FT::WT(src[3][i]))<<2) + FT::WT(src[0][i]) + FT::WT(src[4][i])) >> 4; } + for (i = len - kcn; i < len; i++) + dst[i] = (FT::WT(src[2][i])*(uint8_t)6 + ((FT::WT(src[1][i]) + FT::WT(src[3][i]))<<2) + FT::WT(src[0][i]) + FT::WT(src[4][i])) >> 4; + +} +template <> +void vlineSmooth5N14641(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len, int kcn, bool processInnerRegion) +{ + int i = 0; + for (; i < kcn; i++) + dst[i] = ((uint32_t)(((uint16_t*)(src[2]))[i]) * 6 + + (((uint32_t)(((uint16_t*)(src[1]))[i]) + (uint32_t)(((uint16_t*)(src[3]))[i])) << 2) + + (uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[4]))[i]) + (1 << 11)) >> 12; + if(processInnerRegion) + { +#if (CV_SIMD || CV_SIMD_SCALABLE) + v_uint32 v_6 = vx_setall_u32(6); + const int VECSZ = VTraits::vlanes(); + for (; i <= min(len - 2*VECSZ, len-kcn); i += 2*VECSZ) + { + v_uint32 v_src00, v_src10, v_src20, v_src30, v_src40; + v_uint32 v_src01, v_src11, v_src21, v_src31, v_src41; + v_uint32 v_src02, v_src12, v_src22, v_src32, v_src42; + v_uint32 v_src03, v_src13, v_src23, v_src33, v_src43; + v_expand(vx_load((uint16_t*)(src[0]) + i), v_src00, v_src01); + v_expand(vx_load((uint16_t*)(src[0]) + i + VECSZ), v_src02, v_src03); + v_expand(vx_load((uint16_t*)(src[1]) + i), v_src10, v_src11); + v_expand(vx_load((uint16_t*)(src[1]) + i + VECSZ), v_src12, v_src13); + v_expand(vx_load((uint16_t*)(src[2]) + i), v_src20, v_src21); + v_expand(vx_load((uint16_t*)(src[2]) + i + VECSZ), v_src22, v_src23); + v_expand(vx_load((uint16_t*)(src[3]) + i), v_src30, v_src31); + v_expand(vx_load((uint16_t*)(src[3]) + i + VECSZ), v_src32, v_src33); + v_expand(vx_load((uint16_t*)(src[4]) + i), v_src40, v_src41); + v_expand(vx_load((uint16_t*)(src[4]) + i + VECSZ), v_src42, v_src43); + v_store(dst + i, v_pack(v_rshr_pack<12>(v_add(v_add(v_add(v_mul(v_src20, v_6), v_shl<2>(v_add(v_src10, v_src30))), v_src00), v_src40), + v_add(v_add(v_add(v_mul(v_src21, v_6), v_shl<2>(v_add(v_src11, v_src31))), v_src01), v_src41)), + v_rshr_pack<12>(v_add(v_add(v_add(v_mul(v_src22, v_6), v_shl<2>(v_add(v_src12, v_src32))), v_src02), v_src42), + v_add(v_add(v_add(v_mul(v_src23, v_6), v_shl<2>(v_add(v_src13, v_src33))), v_src03), v_src43)))); + } #endif - for (; i < len; i++) + for (; i < len-kcn; i++) + dst[i] = ((uint32_t)(((uint16_t*)(src[2]))[i]) * 6 + + (((uint32_t)(((uint16_t*)(src[1]))[i]) + (uint32_t)(((uint16_t*)(src[3]))[i])) << 2) + + (uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[4]))[i]) + (1 << 11)) >> 12; + } + for (i = len-kcn; i < len; i++) dst[i] = ((uint32_t)(((uint16_t*)(src[2]))[i]) * 6 + (((uint32_t)(((uint16_t*)(src[1]))[i]) + (uint32_t)(((uint16_t*)(src[3]))[i])) << 2) + (uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[4]))[i]) + (1 << 11)) >> 12; } template <> -void vlineSmooth5N14641(const ufixedpoint32* const * src, const ufixedpoint32*, int, uint16_t* dst, int len) +void vlineSmooth5N14641(const ufixedpoint32* const * src, const ufixedpoint32*, int, uint16_t* dst, int len, int kcn, bool processInnerRegion) { int i = 0; -#if (CV_SIMD || CV_SIMD_SCALABLE) - const int VECSZ = VTraits::vlanes(); - for (; i <= len - 2*VECSZ; i += 2*VECSZ) + for (; i < kcn; i++) + dst[i] = ((uint64_t)(((uint32_t*)(src[2]))[i]) * 6 + + (((uint64_t)(((uint32_t*)(src[1]))[i]) + (uint64_t)(((uint32_t*)(src[3]))[i])) << 2) + + (uint64_t)(((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[4]))[i]) + (1 << 19)) >> 20; + if(processInnerRegion) { - v_uint64 v_src00, v_src10, v_src20, v_src30, v_src40; - v_uint64 v_src01, v_src11, v_src21, v_src31, v_src41; - v_uint64 v_src02, v_src12, v_src22, v_src32, v_src42; - v_uint64 v_src03, v_src13, v_src23, v_src33, v_src43; - v_expand(vx_load((uint32_t*)(src[0]) + i), v_src00, v_src01); - v_expand(vx_load((uint32_t*)(src[0]) + i + VECSZ), v_src02, v_src03); - v_expand(vx_load((uint32_t*)(src[1]) + i), v_src10, v_src11); - v_expand(vx_load((uint32_t*)(src[1]) + i + VECSZ), v_src12, v_src13); - v_expand(vx_load((uint32_t*)(src[2]) + i), v_src20, v_src21); - v_expand(vx_load((uint32_t*)(src[2]) + i + VECSZ), v_src22, v_src23); - v_expand(vx_load((uint32_t*)(src[3]) + i), v_src30, v_src31); - v_expand(vx_load((uint32_t*)(src[3]) + i + VECSZ), v_src32, v_src33); - v_expand(vx_load((uint32_t*)(src[4]) + i), v_src40, v_src41); - v_expand(vx_load((uint32_t*)(src[4]) + i + VECSZ), v_src42, v_src43); - v_store(dst + i, v_pack(v_rshr_pack<20>(v_add(v_add(v_add(v_add(v_shl<2>(v_src20), v_shl<1>(v_src20)), v_shl<2>(v_add(v_src10, v_src30))), v_src00), v_src40), - v_add(v_add(v_add(v_add(v_shl<2>(v_src21), v_shl<1>(v_src21)), v_shl<2>(v_add(v_src11, v_src31))), v_src01), v_src41)), - v_rshr_pack<20>(v_add(v_add(v_add(v_add(v_shl<2>(v_src22), v_shl<1>(v_src22)), v_shl<2>(v_add(v_src12, v_src32))), v_src02), v_src42), - v_add(v_add(v_add(v_add(v_shl<2>(v_src23), v_shl<1>(v_src23)), v_shl<2>(v_add(v_src13, v_src33))), v_src03), v_src43)))); - } +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int VECSZ = VTraits::vlanes(); + for (; i <= min(len - 2*VECSZ, len-kcn); i += 2*VECSZ) + { + v_uint64 v_src00, v_src10, v_src20, v_src30, v_src40; + v_uint64 v_src01, v_src11, v_src21, v_src31, v_src41; + v_uint64 v_src02, v_src12, v_src22, v_src32, v_src42; + v_uint64 v_src03, v_src13, v_src23, v_src33, v_src43; + v_expand(vx_load((uint32_t*)(src[0]) + i), v_src00, v_src01); + v_expand(vx_load((uint32_t*)(src[0]) + i + VECSZ), v_src02, v_src03); + v_expand(vx_load((uint32_t*)(src[1]) + i), v_src10, v_src11); + v_expand(vx_load((uint32_t*)(src[1]) + i + VECSZ), v_src12, v_src13); + v_expand(vx_load((uint32_t*)(src[2]) + i), v_src20, v_src21); + v_expand(vx_load((uint32_t*)(src[2]) + i + VECSZ), v_src22, v_src23); + v_expand(vx_load((uint32_t*)(src[3]) + i), v_src30, v_src31); + v_expand(vx_load((uint32_t*)(src[3]) + i + VECSZ), v_src32, v_src33); + v_expand(vx_load((uint32_t*)(src[4]) + i), v_src40, v_src41); + v_expand(vx_load((uint32_t*)(src[4]) + i + VECSZ), v_src42, v_src43); + v_store(dst + i, v_pack(v_rshr_pack<20>(v_add(v_add(v_add(v_add(v_shl<2>(v_src20), v_shl<1>(v_src20)), v_shl<2>(v_add(v_src10, v_src30))), v_src00), v_src40), + v_add(v_add(v_add(v_add(v_shl<2>(v_src21), v_shl<1>(v_src21)), v_shl<2>(v_add(v_src11, v_src31))), v_src01), v_src41)), + v_rshr_pack<20>(v_add(v_add(v_add(v_add(v_shl<2>(v_src22), v_shl<1>(v_src22)), v_shl<2>(v_add(v_src12, v_src32))), v_src02), v_src42), + v_add(v_add(v_add(v_add(v_shl<2>(v_src23), v_shl<1>(v_src23)), v_shl<2>(v_add(v_src13, v_src33))), v_src03), v_src43)))); + } #endif - for (; i < len; i++) + for (; i < len-kcn; i++) + dst[i] = ((uint64_t)(((uint32_t*)(src[2]))[i]) * 6 + + (((uint64_t)(((uint32_t*)(src[1]))[i]) + (uint64_t)(((uint32_t*)(src[3]))[i])) << 2) + + (uint64_t)(((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[4]))[i]) + (1 << 19)) >> 20; + } + for (i = len-kcn; i < len; i++) dst[i] = ((uint64_t)(((uint32_t*)(src[2]))[i]) * 6 + (((uint64_t)(((uint32_t*)(src[1]))[i]) + (uint64_t)(((uint32_t*)(src[3]))[i])) << 2) + (uint64_t)(((uint32_t*)(src[0]))[i]) + (uint64_t)(((uint32_t*)(src[4]))[i]) + (1 << 19)) >> 20; } template -void vlineSmooth(const FT* const * src, const FT* m, int n, ET* dst, int len) +void vlineSmooth(const FT* const * src, const FT* m, int n, ET* dst, int len, int kcn, bool processInnerRegion) { - for (int i = 0; i < len; i++) + int i = 0; + for (; i < kcn; i++) + { + typename FT::WT val = m[0] * src[0][i]; + for (int j = 1; j < n; j++) + val = val + m[j] * src[j][i]; + dst[i] = val; + } + if(processInnerRegion) + { + for (; i < len-kcn; i++) + { + typename FT::WT val = m[0] * src[0][i]; + for (int j = 1; j < n; j++) + val = val + m[j] * src[j][i]; + dst[i] = val; + } + } + for (i = len-kcn; i < len; i++) { typename FT::WT val = m[0] * src[0][i]; for (int j = 1; j < n; j++) @@ -1646,117 +2079,138 @@ inline uint32_t read_pair_as_u32(const ufixedpoint16 * mem) } template <> -void vlineSmooth(const ufixedpoint16* const * src, const ufixedpoint16* m, int n, uint8_t* dst, int len) +void vlineSmooth(const ufixedpoint16* const * src, const ufixedpoint16* m, int n, uint8_t* dst, int len, int kcn, bool processInnerRegion) { int i = 0; + for (; i < kcn; i++) + { + ufixedpoint32 val = m[0] * src[0][i]; + for (int j = 1; j < n; j++) + { + val = val + m[j] * src[j][i]; + } + dst[i] = val; + } + if(processInnerRegion) + { #if (CV_SIMD || CV_SIMD_SCALABLE) - const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); - v_int32 v_128_4 = vx_setall_s32(128 << 16); - const int VECSZ = VTraits::vlanes(); - if (len >= VECSZ) - { - ufixedpoint16 msum = m[0] + m[1]; - for (int j = 2; j < n; j++) - msum = msum + m[j]; - ufixedpoint32 val[] = { msum * ufixedpoint16((uint8_t)128) }; - v_128_4 = vx_setall_s32(*((int32_t*)val)); - } - for (; i <= len - 4*VECSZ; i += 4*VECSZ) - { - v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; - v_int16 v_tmp0, v_tmp1; - - v_int16 v_mul = v_reinterpret_as_s16(vx_setall_u32(read_pair_as_u32(m))); - - const int16_t* src0 = (const int16_t*)src[0] + i; - const int16_t* src1 = (const int16_t*)src[1] + i; - v_src00 = vx_load(src0); - v_src01 = vx_load(src0 + VECSZ); - v_src02 = vx_load(src0 + 2*VECSZ); - v_src03 = vx_load(src0 + 3*VECSZ); - v_src10 = vx_load(src1); - v_src11 = vx_load(src1 + VECSZ); - v_src12 = vx_load(src1 + 2*VECSZ); - v_src13 = vx_load(src1 + 3*VECSZ); - v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_int32 v_res0 = v_dotprod(v_tmp0, v_mul); - v_int32 v_res1 = v_dotprod(v_tmp1, v_mul); - v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_int32 v_res2 = v_dotprod(v_tmp0, v_mul); - v_int32 v_res3 = v_dotprod(v_tmp1, v_mul); - v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_int32 v_res4 = v_dotprod(v_tmp0, v_mul); - v_int32 v_res5 = v_dotprod(v_tmp1, v_mul); - v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_int32 v_res6 = v_dotprod(v_tmp0, v_mul); - v_int32 v_res7 = v_dotprod(v_tmp1, v_mul); - - int j = 2; - for (; j < n - 1; j+=2) + const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); + v_int32 v_128_4 = vx_setall_s32(128 << 16); + const int VECSZ = VTraits::vlanes(); + if (len >= VECSZ) { - v_mul = v_reinterpret_as_s16(vx_setall_u32(read_pair_as_u32(m + j))); + ufixedpoint16 msum = m[0] + m[1]; + for (int j = 2; j < n; j++) + msum = msum + m[j]; + ufixedpoint32 val[] = { msum * ufixedpoint16((uint8_t)128) }; + v_128_4 = vx_setall_s32(*((int32_t*)val)); + } + for (; i <= min(len - 4*VECSZ, len-kcn); i += 4*VECSZ) + { + v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; + v_int16 v_tmp0, v_tmp1; - const int16_t* srcj0 = (const int16_t*)src[j] + i; - const int16_t* srcj1 = (const int16_t*)src[j + 1] + i; - v_src00 = vx_load(srcj0); - v_src01 = vx_load(srcj0 + VECSZ); - v_src02 = vx_load(srcj0 + 2*VECSZ); - v_src03 = vx_load(srcj0 + 3*VECSZ); - v_src10 = vx_load(srcj1); - v_src11 = vx_load(srcj1 + VECSZ); - v_src12 = vx_load(srcj1 + 2*VECSZ); - v_src13 = vx_load(srcj1 + 3*VECSZ); + v_int16 v_mul = v_reinterpret_as_s16(vx_setall_u32(read_pair_as_u32(m))); + + const int16_t* src0 = (const int16_t*)src[0] + i; + const int16_t* src1 = (const int16_t*)src[1] + i; + v_src00 = vx_load(src0); + v_src01 = vx_load(src0 + VECSZ); + v_src02 = vx_load(src0 + 2*VECSZ); + v_src03 = vx_load(src0 + 3*VECSZ); + v_src10 = vx_load(src1); + v_src11 = vx_load(src1 + VECSZ); + v_src12 = vx_load(src1 + 2*VECSZ); + v_src13 = vx_load(src1 + 3*VECSZ); v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_res0 = v_add(v_res0, v_dotprod(v_tmp0, v_mul)); - v_res1 = v_add(v_res1, v_dotprod(v_tmp1, v_mul)); + v_int32 v_res0 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res1 = v_dotprod(v_tmp1, v_mul); v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_res2 = v_add(v_res2, v_dotprod(v_tmp0, v_mul)); - v_res3 = v_add(v_res3, v_dotprod(v_tmp1, v_mul)); + v_int32 v_res2 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res3 = v_dotprod(v_tmp1, v_mul); v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_res4 = v_add(v_res4, v_dotprod(v_tmp0, v_mul)); - v_res5 = v_add(v_res5, v_dotprod(v_tmp1, v_mul)); + v_int32 v_res4 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res5 = v_dotprod(v_tmp1, v_mul); v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_res6 = v_add(v_res6, v_dotprod(v_tmp0, v_mul)); - v_res7 = v_add(v_res7, v_dotprod(v_tmp1, v_mul)); - } - if(j < n) - { - v_int32 v_resj0, v_resj1; - v_mul = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + j)))); - const int16_t* srcj = (const int16_t*)src[j] + i; - v_src00 = vx_load(srcj); - v_src01 = vx_load(srcj + VECSZ); - v_src02 = vx_load(srcj + 2*VECSZ); - v_src03 = vx_load(srcj + 3*VECSZ); - v_mul_expand(v_add_wrap(v_src00, v_128), v_mul, v_resj0, v_resj1); - v_res0 = v_add(v_res0, v_resj0); - v_res1 = v_add(v_res1, v_resj1); - v_mul_expand(v_add_wrap(v_src01, v_128), v_mul, v_resj0, v_resj1); - v_res2 = v_add(v_res2, v_resj0); - v_res3 = v_add(v_res3, v_resj1); - v_mul_expand(v_add_wrap(v_src02, v_128), v_mul, v_resj0, v_resj1); - v_res4 = v_add(v_res4, v_resj0); - v_res5 = v_add(v_res5, v_resj1); - v_mul_expand(v_add_wrap(v_src03, v_128), v_mul, v_resj0, v_resj1); - v_res6 = v_add(v_res6, v_resj0); - v_res7 = v_add(v_res7, v_resj1); - } - v_res0 = v_add(v_res0, v_128_4); - v_res1 = v_add(v_res1, v_128_4); - v_res2 = v_add(v_res2, v_128_4); - v_res3 = v_add(v_res3, v_128_4); - v_res4 = v_add(v_res4, v_128_4); - v_res5 = v_add(v_res5, v_128_4); - v_res6 = v_add(v_res6, v_128_4); - v_res7 = v_add(v_res7, v_128_4); + v_int32 v_res6 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res7 = v_dotprod(v_tmp1, v_mul); - v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); - v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); - } + int j = 2; + for (; j < n - 1; j+=2) + { + v_mul = v_reinterpret_as_s16(vx_setall_u32(read_pair_as_u32(m + j))); + + const int16_t* srcj0 = (const int16_t*)src[j] + i; + const int16_t* srcj1 = (const int16_t*)src[j + 1] + i; + v_src00 = vx_load(srcj0); + v_src01 = vx_load(srcj0 + VECSZ); + v_src02 = vx_load(srcj0 + 2*VECSZ); + v_src03 = vx_load(srcj0 + 3*VECSZ); + v_src10 = vx_load(srcj1); + v_src11 = vx_load(srcj1 + VECSZ); + v_src12 = vx_load(srcj1 + 2*VECSZ); + v_src13 = vx_load(srcj1 + 3*VECSZ); + v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); + v_res0 = v_add(v_res0, v_dotprod(v_tmp0, v_mul)); + v_res1 = v_add(v_res1, v_dotprod(v_tmp1, v_mul)); + v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); + v_res2 = v_add(v_res2, v_dotprod(v_tmp0, v_mul)); + v_res3 = v_add(v_res3, v_dotprod(v_tmp1, v_mul)); + v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); + v_res4 = v_add(v_res4, v_dotprod(v_tmp0, v_mul)); + v_res5 = v_add(v_res5, v_dotprod(v_tmp1, v_mul)); + v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); + v_res6 = v_add(v_res6, v_dotprod(v_tmp0, v_mul)); + v_res7 = v_add(v_res7, v_dotprod(v_tmp1, v_mul)); + } + if(j < n) + { + v_int32 v_resj0, v_resj1; + v_mul = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + j)))); + const int16_t* srcj = (const int16_t*)src[j] + i; + v_src00 = vx_load(srcj); + v_src01 = vx_load(srcj + VECSZ); + v_src02 = vx_load(srcj + 2*VECSZ); + v_src03 = vx_load(srcj + 3*VECSZ); + v_mul_expand(v_add_wrap(v_src00, v_128), v_mul, v_resj0, v_resj1); + v_res0 = v_add(v_res0, v_resj0); + v_res1 = v_add(v_res1, v_resj1); + v_mul_expand(v_add_wrap(v_src01, v_128), v_mul, v_resj0, v_resj1); + v_res2 = v_add(v_res2, v_resj0); + v_res3 = v_add(v_res3, v_resj1); + v_mul_expand(v_add_wrap(v_src02, v_128), v_mul, v_resj0, v_resj1); + v_res4 = v_add(v_res4, v_resj0); + v_res5 = v_add(v_res5, v_resj1); + v_mul_expand(v_add_wrap(v_src03, v_128), v_mul, v_resj0, v_resj1); + v_res6 = v_add(v_res6, v_resj0); + v_res7 = v_add(v_res7, v_resj1); + } + v_res0 = v_add(v_res0, v_128_4); + v_res1 = v_add(v_res1, v_128_4); + v_res2 = v_add(v_res2, v_128_4); + v_res3 = v_add(v_res3, v_128_4); + v_res4 = v_add(v_res4, v_128_4); + v_res5 = v_add(v_res5, v_128_4); + v_res6 = v_add(v_res6, v_128_4); + v_res7 = v_add(v_res7, v_128_4); + + v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + } #endif - for (; i < len; i++) + for (; i < len-kcn; i++) + { + ufixedpoint32 val = m[0] * src[0][i]; + for (int j = 1; j < n; j++) + { + val = val + m[j] * src[j][i]; + } + dst[i] = val; + } + } + for (i = len-kcn; i < len; i++) { ufixedpoint32 val = m[0] * src[0][i]; for (int j = 1; j < n; j++) @@ -1767,7 +2221,7 @@ void vlineSmooth(const ufixedpoint16* const * src, const } } template -void vlineSmoothONa_yzy_a(const FT* const * src, const FT* m, int n, ET* dst, int len) +void vlineSmoothONa_yzy_a(const FT* const * src, const FT* m, int n, ET* dst, int len, int , bool ) { int pre_shift = n / 2; for (int i = 0; i < len; i++) @@ -1779,7 +2233,7 @@ void vlineSmoothONa_yzy_a(const FT* const * src, const FT* m, int n, ET* dst, in } } template <> -void vlineSmoothONa_yzy_a(const ufixedpoint16* const * src, const ufixedpoint16* m, int n, uint8_t* dst, int len) +void vlineSmoothONa_yzy_a(const ufixedpoint16* const * src, const ufixedpoint16* m, int n, uint8_t* dst, int len, int , bool) { int i = 0; #if (CV_SIMD || CV_SIMD_SCALABLE) @@ -1867,7 +2321,7 @@ void vlineSmoothONa_yzy_a(const ufixedpoint16* const * s } } template <> -void vlineSmoothONa_yzy_a(const ufixedpoint32* const * src, const ufixedpoint32* m, int n, uint16_t* dst, int len) +void vlineSmoothONa_yzy_a(const ufixedpoint32* const * src, const ufixedpoint32* m, int n, uint16_t* dst, int len, int, bool) { int i = 0; #if (CV_SIMD || CV_SIMD_SCALABLE) @@ -1943,7 +2397,7 @@ public: if (kx[0] == (FT::one()>>2)&&kx[1] == (FT::one()>>1)&&kx[2] == (FT::one()>>2)) hlineSmoothFunc = hlineSmooth3N121; else if ((kx[0] - kx[2]).isZero()) - hlineSmoothFunc = hlineSmooth3Naba; + hlineSmoothFunc = hlineSmooth3Naba; else hlineSmoothFunc = hlineSmooth3N; } @@ -2008,7 +2462,55 @@ public: } else vlineSmoothFunc = vlineSmooth; + if ((width>3) && (height>3) && (kxlen == 3) && (kx[0] == (FT::one()>>2)&&kx[1] == (FT::one()>>1)&&kx[2] == (FT::one()>>2)) && + (ky[0] == (FT::one()>>2)&&ky[1] == (FT::one()>>1)&&ky[2] == (FT::one()>>2))) + { + doCombined3N121 = true; + //smoothFunc = smooth3N121; /* using funptr drops performance */ + } + else if((kxlen == 5) && (width > 5) && (height>5) && + kx[2] == (FT::one() * (uint8_t)3 >> 3) && + kx[1] == (FT::one() >> 2) && kx[3] == (FT::one() >> 2) && + kx[0] == (FT::one() >> 4) && kx[4] == (FT::one() >> 4) && + ky[2] == kx[2] && ky[1] == kx[1] && ky[0] == kx[0]) + { + doCombined5N14641 = true; + //smoothFunc = smooth5N14641; + } + } + + void inline computeInnerRegion(int& idst, int& i, int ito, int& bufline, FT** ptrs) const + { + int idst_start = idst; + if (doCombined3N121||doCombined5N14641) + { + for (; i < ito; i++, idst++) + { + bool processFlag = false; + if(i > height - kylen) + processFlag = true; + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, processFlag); + bufline = (bufline + 1) % kylen; + vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn, ((kxlen>>1))*cn, processFlag); + } + // inner region + if(doCombined3N121) + smooth3N121(src, kx, ky, cn, dst, ito, idst_start, width, height, src_stride, dst_stride); + else + smooth5N14641(src, kx, ky, cn, dst, ito, idst_start, width, height, src_stride, dst_stride); + } + else + { + for (; i < ito; i++, idst++) + { + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); + bufline = (bufline + 1) % kylen; + vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst * dst_stride, width*cn, 0, true); + } + } + } + virtual void operator() (const Range& range) const CV_OVERRIDE { AutoBuffer _buf(width*cn*kylen); @@ -2016,13 +2518,14 @@ public: AutoBuffer _ptrs(kylen*2); FT** ptrs = _ptrs.data(); + if (kylen == 1) { ptrs[0] = buf; for (int i = range.start; i < range.end; i++) { - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[0], width, borderType); - vlineSmoothFunc(ptrs, ky, kylen, dst + i * dst_stride, width*cn); + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[0], width, borderType, true); + vlineSmoothFunc(ptrs, ky, kylen, dst + i * dst_stride, width*cn, cn, true); } } else if (borderType != BORDER_CONSTANT)// If BORDER_CONSTANT out of border values are equal to zero and could be skipped @@ -2038,7 +2541,7 @@ public: for (; i < min(ito, height); i++, bufline++) { ptrs[bufline+kylen] = ptrs[bufline] = buf + bufline * width*cn; - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); } for (; i < ito; i++, bufline++) { @@ -2046,7 +2549,7 @@ public: if (src_idx < ifrom) { ptrs[bufline + kylen] = ptrs[bufline] = buf + bufline * width*cn; - hlineSmoothFunc(src + src_idx * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); + hlineSmoothFunc(src + src_idx * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); } else { @@ -2059,14 +2562,14 @@ public: if (src_idx >= ito) { ptrs[2*kylen + j] = ptrs[kylen + j] = buf + (kylen + j) * width*cn; - hlineSmoothFunc(src + src_idx * src_stride, cn, kx, kxlen, ptrs[kylen + j], width, borderType); + hlineSmoothFunc(src + src_idx * src_stride, cn, kx, kxlen, ptrs[kylen + j], width, borderType, true); } else { ptrs[2*kylen + j] = ptrs[kylen + j] = ptrs[src_idx]; } } - vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn); idst++; + vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn, cn, true); idst++; // border mode dependent part evaluation // i points to last src row to evaluate in convolution @@ -2074,27 +2577,23 @@ public: for (; i < min(kylen, ito); i++, idst++) { ptrs[bufline + kylen] = ptrs[bufline] = buf + bufline * width*cn; - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); bufline = (bufline + 1) % kylen; - vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn); + vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn, cn, true); } // Points inside the border - for (; i < ito; i++, idst++) - { - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); - bufline = (bufline + 1) % kylen; - vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn); - } + computeInnerRegion(idst, i, ito, bufline, ptrs); + // Points that could fall below border for (; i < range.end + post_shift; i++, idst++) { int src_idx = borderInterpolate(i, height, borderType); if ((i - src_idx) > kylen) - hlineSmoothFunc(src + src_idx * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); + hlineSmoothFunc(src + src_idx * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); else ptrs[bufline + kylen] = ptrs[bufline] = ptrs[(bufline + kylen - (i - src_idx)) % kylen]; bufline = (bufline + 1) % kylen; - vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn); + vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn, cn, true); } } else @@ -2110,17 +2609,17 @@ public: for (; i < ito; i++, bufline++) { ptrs[bufline + kylen] = ptrs[bufline] = buf + bufline * width*cn; - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); } if (bufline == 1) - vlineSmooth1N(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn); + vlineSmooth1N(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn, cn, true); else if (bufline == 3) - vlineSmooth3N(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn); + vlineSmooth3N(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn, cn, true); else if (bufline == 5) - vlineSmooth5N(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn); + vlineSmooth5N(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn, cn, true); else - vlineSmooth(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn); + vlineSmooth(ptrs, ky - min(ifrom, 0), bufline, dst + idst*dst_stride, width*cn, cn, true); idst++; // border mode dependent part evaluation @@ -2129,54 +2628,49 @@ public: for (; i < min(kylen, ito); i++, idst++) { ptrs[bufline + kylen] = ptrs[bufline] = buf + bufline * width*cn; - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); + hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType, true); bufline++; if (bufline == 3) - vlineSmooth3N(ptrs, ky + kylen - bufline, i + 1, dst + idst*dst_stride, width*cn); + vlineSmooth3N(ptrs, ky + kylen - bufline, i + 1, dst + idst*dst_stride, width*cn, cn, true); else if (bufline == 5) - vlineSmooth5N(ptrs, ky + kylen - bufline, i + 1, dst + idst*dst_stride, width*cn); + vlineSmooth5N(ptrs, ky + kylen - bufline, i + 1, dst + idst*dst_stride, width*cn, cn, true); else - vlineSmooth(ptrs, ky + kylen - bufline, i + 1, dst + idst*dst_stride, width*cn); + vlineSmooth(ptrs, ky + kylen - bufline, i + 1, dst + idst*dst_stride, width*cn, cn, true); bufline %= kylen; } // Points inside the border if (i - max(0, ifrom) >= kylen) { - for (; i < ito; i++, idst++) - { - hlineSmoothFunc(src + i * src_stride, cn, kx, kxlen, ptrs[bufline], width, borderType); - bufline = (bufline + 1) % kylen; - vlineSmoothFunc(ptrs + bufline, ky, kylen, dst + idst*dst_stride, width*cn); - } + computeInnerRegion(idst, i, ito, bufline, ptrs); // Points that could fall below border // i points to first src row to evaluate in convolution bufline = (bufline + 1) % kylen; for (i = idst - pre_shift; i < range.end - pre_shift; i++, idst++, bufline++) if (height - i == 3) - vlineSmooth3N(ptrs + bufline, ky, height - i, dst + idst*dst_stride, width*cn); + vlineSmooth3N(ptrs + bufline, ky, height - i, dst + idst*dst_stride, width*cn, cn, true); else if (height - i == 5) - vlineSmooth5N(ptrs + bufline, ky, height - i, dst + idst*dst_stride, width*cn); + vlineSmooth5N(ptrs + bufline, ky, height - i, dst + idst*dst_stride, width*cn, cn, true); else - vlineSmooth(ptrs + bufline, ky, height - i, dst + idst*dst_stride, width*cn); + vlineSmooth(ptrs + bufline, ky, height - i, dst + idst*dst_stride, width*cn, cn, true); } else { // i points to first src row to evaluate in convolution for (i = idst - pre_shift; i < min(range.end - pre_shift, 0); i++, idst++) if (height == 3) - vlineSmooth3N(ptrs, ky - i, height, dst + idst*dst_stride, width*cn); + vlineSmooth3N(ptrs, ky - i, height, dst + idst*dst_stride, width*cn, cn, true); else if (height == 5) - vlineSmooth5N(ptrs, ky - i, height, dst + idst*dst_stride, width*cn); + vlineSmooth5N(ptrs, ky - i, height, dst + idst*dst_stride, width*cn, cn, true); else - vlineSmooth(ptrs, ky - i, height, dst + idst*dst_stride, width*cn); + vlineSmooth(ptrs, ky - i, height, dst + idst*dst_stride, width*cn, cn, true); for (; i < range.end - pre_shift; i++, idst++) if (height - i == 3) - vlineSmooth3N(ptrs + i - max(0, ifrom), ky, height - i, dst + idst*dst_stride, width*cn); + vlineSmooth3N(ptrs + i - max(0, ifrom), ky, height - i, dst + idst*dst_stride, width*cn, cn, true); else if (height - i == 5) - vlineSmooth5N(ptrs + i - max(0, ifrom), ky, height - i, dst + idst*dst_stride, width*cn); + vlineSmooth5N(ptrs + i - max(0, ifrom), ky, height - i, dst + idst*dst_stride, width*cn, cn, true); else - vlineSmooth(ptrs + i - max(0, ifrom), ky, height - i, dst + idst*dst_stride, width*cn); + vlineSmooth(ptrs + i - max(0, ifrom), ky, height - i, dst + idst*dst_stride, width*cn, cn, true); } } } @@ -2188,8 +2682,11 @@ private: const FT *kx, *ky; int kxlen, kylen; int borderType; - void(*hlineSmoothFunc)(const ET* src, int cn, const FT* m, int n, FT* dst, int len, int borderType); - void(*vlineSmoothFunc)(const FT* const * src, const FT* m, int n, ET* dst, int len); + bool doCombined3N121 = false; + bool doCombined5N14641 = false; + void(*hlineSmoothFunc)(const ET* src, int cn, const FT* m, int n, FT* dst, int len, int borderType, bool processInnerRegion); + void(*vlineSmoothFunc)(const FT* const * src, const FT* m, int n, ET* dst, int len, int cn, bool processInnerRegion); + void(*smoothFunc)(const ET* src, const FT*, const FT*, int cn, ET *dst, int ito, int idst, int width, size_t src_stride, size_t dst_stride); fixedSmoothInvoker(const fixedSmoothInvoker&); fixedSmoothInvoker& operator=(const fixedSmoothInvoker&); diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp index 7e10757514..654df9167d 100644 --- a/modules/imgproc/test/test_convhull.cpp +++ b/modules/imgproc/test/test_convhull.cpp @@ -1069,5 +1069,106 @@ TEST(minEnclosingCircle, three_points) EXPECT_LE(delta, 1.f); } + +//============================ minEnclosingPolygon tests ============================ + +TEST(minEnclosingPolygon, input_errors) +{ + std::vector kgon; + std::vector ngon {{0.0, 0.0}, {1.0, 1.0}}; + + EXPECT_THROW(minEnclosingConvexPolygon(ngon, kgon, 3), cv::Exception); + + ngon = {{0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {1.0, 1.0}}; + EXPECT_THROW(minEnclosingConvexPolygon(ngon, kgon, 2), cv::Exception); + EXPECT_THROW(minEnclosingConvexPolygon(ngon, kgon, 5), cv::Exception); +} + +TEST(minEnclosingPolygon, input_corner_cases) +{ + double area = -1.0; + std::vector kgon; + std::vector ngon = {{0.0, 0.0}, {0.0, 0.0}, {1.0, 1.0}, {1.0, 1.0}}; + + EXPECT_NO_THROW(area = minEnclosingConvexPolygon(ngon, kgon, 3)) + << "unexpected exception: not enough different points in input ngon (double points)"; + EXPECT_LE(area, 0.); + EXPECT_TRUE(kgon.empty()); + + ngon = {{0.0, 0.0}, {1.0, 1.0}, {2.0, 2.0}, {3.0, 3.0}, {4.0, 4.0}}; + EXPECT_NO_THROW(area = minEnclosingConvexPolygon(ngon, kgon, 3)) + << "unexpected exception: all points on line"; + EXPECT_LE(area, 0.); + EXPECT_TRUE(kgon.empty()); +} + +TEST(minEnclosingPolygon, unit_circle) +{ + const int n = 64; + const int k = 7; + double area = -1.0; + std::vector kgon; + std::vector ngon(n); + + for(int i = 0; i < n; i++) + { + ngon[i] = { cosf(float(i * 2.f * M_PI / n)), sinf(float(i * 2.f * M_PI / n)) }; + } + + EXPECT_NO_THROW(area = minEnclosingConvexPolygon(ngon, kgon, k)); + EXPECT_GT(area, cv::contourArea(ngon)); + EXPECT_EQ((int)kgon.size(), k); +} + +TEST(minEnclosingPolygon, random_points) +{ + const int n = 100; + const int k = 7; + + double area = -1.0; + std::vector kgon; + std::vector ngon(n); + std::vector ngonHull; + + cv::randu(ngon, 1, 101); + cv::convexHull(ngon, ngonHull, true); + + EXPECT_NO_THROW(area = minEnclosingConvexPolygon(ngon, kgon, k)); + EXPECT_GT(area, cv::contourArea(ngonHull)); + EXPECT_EQ(kgon.size(), (size_t)k); +} + +TEST(minEnclosingPolygon, pentagon) +{ + double area; + std::vector kgon; + std::vector expectedKgon; + std::vector ngon; + + ngon = {{1, 0}, {0, 8}, {4, 12}, {8, 8}, {7, 0}}; + EXPECT_NO_THROW({ + area = minEnclosingConvexPolygon(ngon, kgon, 4); + }); + + expectedKgon = {{1, 0}, {-0.5, 12}, {8.5, 12}, {7, 0}}; + EXPECT_EQ(area, cv::contourArea(expectedKgon)); + ASSERT_EQ((int)kgon.size(), 4); + + for (size_t i = 0; i < 4; i++) + { + bool match = false; + for (size_t j = 0; j < 4; j++) + { + if(expectedKgon[i].x == kgon[j].x && expectedKgon[i].y == kgon[j].y) + { + match = true; + break; + } + } + EXPECT_EQ(match, true); + } +} + }} // namespace + /* End of file. */ diff --git a/modules/js/generator/embindgen.py b/modules/js/generator/embindgen.py index d5d600e83f..e81ceb837a 100644 --- a/modules/js/generator/embindgen.py +++ b/modules/js/generator/embindgen.py @@ -320,7 +320,6 @@ class Namespace(object): class JSWrapperGenerator(object): def __init__(self, preprocessor_definitions=None): - self.bindings = [] self.wrapper_funcs = [] @@ -333,6 +332,29 @@ class JSWrapperGenerator(object): ) self.class_idx = 0 + def _is_string_type(self, tp: str) -> bool: + """Check if a type should be treated as string in bindings.""" + string_types = { + "std::string", + "char", + "signed char", + "unsigned char", + } + return tp in string_types + + def _generate_class_properties(self, class_info, class_bindings): + # Generate bindings for properties + for prop in class_info.props: + if prop.tp in type_dict and not self._is_string_type(prop.tp): + _class_property = class_property_enum_template + else: + _class_property = class_property_template + + class_bindings.append(_class_property.substitute( + js_name=prop.name, + cpp_name='::'.join([class_info.cname, prop.name]) + )) + def add_class(self, stype, name, decl): class_info = ClassInfo(name, decl) class_info.decl_idx = self.class_idx @@ -893,11 +915,17 @@ class JSWrapperGenerator(object): - # Generate bindings for properties - for property in class_info.props: - _class_property = class_property_enum_template if property.tp in type_dict else class_property_template - class_bindings.append(_class_property.substitute(js_name=property.name, cpp_name='::'.join( - [class_info.cname, property.name]))) + # Generate bindings for properties(prop) + for prop in class_info.props: + if prop.tp in type_dict and not self._is_string_type(prop.tp): + _class_property = class_property_enum_template + else: + _class_property = class_property_template + + class_bindings.append(_class_property.substitute( + js_name=prop.name, + cpp_name='::'.join([class_info.cname, prop.name]) + )) dv = '' base = Template("""base<$base>""") diff --git a/modules/js/src/core_bindings.cpp b/modules/js/src/core_bindings.cpp index 9f4d4d7e51..e6925a8895 100644 --- a/modules/js/src/core_bindings.cpp +++ b/modules/js/src/core_bindings.cpp @@ -107,6 +107,10 @@ typedef SimpleBlobDetector::Params SimpleBlobDetector_Params; typedef TrackerMIL::Params TrackerMIL_Params; #endif +#ifdef HAVE_OPENCV_XIMGPROC +typedef ximgproc::EdgeDrawing::Params EdgeDrawing_Params; +#endif + // HACK: JS generator ommits namespace for parameter types for some reason. Added typedef to handle std::string correctly typedef std::string string; diff --git a/modules/objdetect/src/aruco/charuco_detector.cpp b/modules/objdetect/src/aruco/charuco_detector.cpp index 97f5711d5c..589d837d12 100644 --- a/modules/objdetect/src/aruco/charuco_detector.cpp +++ b/modules/objdetect/src/aruco/charuco_detector.cpp @@ -32,8 +32,10 @@ struct CharucoDetector::CharucoDetectorImpl { const Mat chIds = charucoIds.getMat(); const vector& boardIds = board.getIds(); - const vector > nearestMarkerIdx = board.getNearestMarkerIdx(); - vector distance(board.getNearestMarkerIdx().size(), Point2f(0.f, std::numeric_limits::max())); + const vector > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once + const vector > nearestMarkerCorners = board.getNearestMarkerCorners(); + + vector distance(nearestMarkerIdx.size(), Point2f(0.f, std::numeric_limits::max())); // distance[i].x: max distance from the i-th charuco corner to charuco corner-forming markers. // The two charuco corner-forming markers of i-th charuco corner are defined in getNearestMarkerIdx()[i] // distance[i].y: min distance from the charuco corner to other markers. @@ -52,7 +54,7 @@ struct CharucoDetector::CharucoDetectorImpl { const int nearestMarkerId1 = boardIds[nearestMarkerIdx[chId][0]]; const int nearestMarkerId2 = boardIds[nearestMarkerIdx[chId][1]]; if (nearestMarkerId1 == idMaker || nearestMarkerId2 == idMaker) { - int nearestCornerId = nearestMarkerId1 == idMaker ? board.getNearestMarkerCorners()[chId][0] : board.getNearestMarkerCorners()[chId][1]; + int nearestCornerId = nearestMarkerId1 == idMaker ? nearestMarkerCorners[chId][0] : nearestMarkerCorners[chId][1]; Point2f nearestCorner = mCorners[j].ptr(0)[nearestCornerId]; // distToNearest: distance from the charuco corner to charuco corner-forming markers float distToNearest = sqrt(normL2Sqr(nearestCorner - charucoCorner)); @@ -84,18 +86,21 @@ struct CharucoDetector::CharucoDetectorImpl { InputArray charucoCorners) { size_t nCharucoCorners = charucoCorners.getMat().total(); - CV_Assert(board.getNearestMarkerIdx().size() == nCharucoCorners); + const vector > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once + const vector > nearestMarkerCorners = board.getNearestMarkerCorners(); + + CV_Assert(nearestMarkerIdx.size() == nCharucoCorners); vector winSizes(nCharucoCorners, Size(-1, -1)); for(size_t i = 0ull; i < nCharucoCorners; i++) { if(charucoCorners.getMat().at((int)i) == Point2f(-1.f, -1.f)) continue; - if(board.getNearestMarkerIdx()[i].empty()) continue; + if(nearestMarkerIdx[i].empty()) continue; double minDist = -1; int counter = 0; // calculate the distance to each of the closest corner of each closest marker - for(size_t j = 0; j < board.getNearestMarkerIdx()[i].size(); j++) { + for(size_t j = 0; j < nearestMarkerIdx[i].size(); j++) { // find marker - int markerId = board.getIds()[board.getNearestMarkerIdx()[i][j]]; + int markerId = board.getIds()[nearestMarkerIdx[i][j]]; int markerIdx = -1; for(size_t k = 0; k < markerIds.getMat().total(); k++) { if(markerIds.getMat().at((int)k) == markerId) { @@ -105,7 +110,7 @@ struct CharucoDetector::CharucoDetectorImpl { } if(markerIdx == -1) continue; Point2f markerCorner = - markerCorners.getMat(markerIdx).at(board.getNearestMarkerCorners()[i][j]); + markerCorners.getMat(markerIdx).at(nearestMarkerCorners[i][j]); Point2f charucoCorner = charucoCorners.getMat().at((int)i); double dist = norm(markerCorner - charucoCorner); if(minDist == -1) minDist = dist; // if first distance, just assign it @@ -212,6 +217,8 @@ struct CharucoDetector::CharucoDetectorImpl { vector transformations(nMarkers); vector validTransform(nMarkers, false); const auto& ids = board.getIds(); + const vector > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once + for(size_t i = 0ull; i < nMarkers; i++) { vector markerObjPoints2D; int markerId = markerIds.getMat().at((int)i); @@ -227,15 +234,16 @@ struct CharucoDetector::CharucoDetectorImpl { double det = determinant(transformations[i]); validTransform[i] = std::abs(det) > 1e-6; } - size_t nCharucoCorners = (size_t)board.getChessboardCorners().size(); + const vector chessboardCorners = board.getChessboardCorners(); + size_t nCharucoCorners = (size_t)chessboardCorners.size(); vector allChessboardImgPoints(nCharucoCorners, Point2f(-1, -1)); // for each charuco corner, calculate its interpolation position based on the closest markers // homographies for(size_t i = 0ull; i < nCharucoCorners; i++) { - Point2f objPoint2D = Point2f(board.getChessboardCorners()[i].x, board.getChessboardCorners()[i].y); + Point2f objPoint2D = Point2f(chessboardCorners[i].x, chessboardCorners[i].y); vector interpolatedPositions; - for(size_t j = 0ull; j < board.getNearestMarkerIdx()[i].size(); j++) { - int markerId = board.getIds()[board.getNearestMarkerIdx()[i][j]]; + for(size_t j = 0ull; j < nearestMarkerIdx[i].size(); j++) { + int markerId = board.getIds()[nearestMarkerIdx[i][j]]; int markerIdx = -1; for(size_t k = 0ull; k < markerIds.getMat().total(); k++) { if(markerIds.getMat().at((int)k) == markerId) { @@ -274,13 +282,14 @@ struct CharucoDetector::CharucoDetectorImpl { CV_Assert(charucoParameters.minMarkers >= 0 && charucoParameters.minMarkers <= 2); vector filteredCharucoCorners; vector filteredCharucoIds; + const vector > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once // for each charuco corner for(unsigned int i = 0; i < allCharucoIds.getMat().total(); i++) { int currentCharucoId = allCharucoIds.getMat().at(i); int totalMarkers = 0; // nomber of closest marker detected // look for closest markers - for(unsigned int m = 0; m < board.getNearestMarkerIdx()[currentCharucoId].size(); m++) { - int markerId = board.getIds()[board.getNearestMarkerIdx()[currentCharucoId][m]]; + for(unsigned int m = 0; m < nearestMarkerIdx[currentCharucoId].size(); m++) { + int markerId = board.getIds()[nearestMarkerIdx[currentCharucoId][m]]; bool found = false; for(unsigned int k = 0; k < allArucoIds.getMat().total(); k++) { if(allArucoIds.getMat().at(k) == markerId) { diff --git a/modules/objdetect/src/qrcode.cpp b/modules/objdetect/src/qrcode.cpp index 0d5d7a7be1..923240292a 100644 --- a/modules/objdetect/src/qrcode.cpp +++ b/modules/objdetect/src/qrcode.cpp @@ -3417,8 +3417,10 @@ int QRDetectMulti::findNumberLocalizationPoints(vector& tmp_localizatio Mat tmp_shrinking = bin_barcode; int tmp_num_points = 0; int num_points = -1; - for (eps_horizontal = 0.1; eps_horizontal < 0.4; eps_horizontal += 0.1) + double eps = 0.0; + for (int epsCoeff = 1; epsCoeff <= 3; epsCoeff++) { + eps = eps_horizontal * static_cast(epsCoeff); tmp_num_points = 0; num_points = -1; if (purpose == SHRINKING) @@ -3443,7 +3445,7 @@ int QRDetectMulti::findNumberLocalizationPoints(vector& tmp_localizatio else break; } - vector list_lines_y = extractVerticalLines(list_lines_x, eps_horizontal); + vector list_lines_y = extractVerticalLines(list_lines_x, eps); if (list_lines_y.size() < 3) { if (k == 0) @@ -3453,7 +3455,7 @@ int QRDetectMulti::findNumberLocalizationPoints(vector& tmp_localizatio list_lines_x = searchHorizontalLines(); if (list_lines_x.empty()) break; - list_lines_y = extractVerticalLines(list_lines_x, eps_horizontal); + list_lines_y = extractVerticalLines(list_lines_x, eps); if (list_lines_y.size() < 3) break; } @@ -3531,7 +3533,7 @@ int QRDetectMulti::findNumberLocalizationPoints(vector& tmp_localizatio vector list_lines_x = searchHorizontalLines(); if (list_lines_x.empty()) return num_points; - vector list_lines_y = extractVerticalLines(list_lines_x, eps_horizontal); + vector list_lines_y = extractVerticalLines(list_lines_x, eps); if (list_lines_y.size() < 3) return num_points; if (num_points < 3) diff --git a/modules/objdetect/test/test_qrcode.cpp b/modules/objdetect/test/test_qrcode.cpp index 3830439765..c49480d38f 100644 --- a/modules/objdetect/test/test_qrcode.cpp +++ b/modules/objdetect/test/test_qrcode.cpp @@ -679,4 +679,40 @@ TEST(Objdetect_QRCode_detect, detect_regression_22892) EXPECT_EQ(corners.size(), 4U); } +// See https://github.com/opencv/opencv/issues/27783 +TEST(Objdetect_QRCode_detect, detect_regression_27783) +{ + const std::string name_current_image = "9_qrcodes.jpg"; + const std::string root = "qrcode/multiple/"; + + std::string image_path = findDataFile(root + name_current_image); + Mat src = imread(image_path); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + + std::vector info; + std::vector corners; + + { + // If default, we can decode 9 QRs. + QRCodeDetector qrcode; + EXPECT_TRUE(qrcode.detectAndDecodeMulti(src, info, corners)); + ASSERT_EQ(info.size(), 9UL); + ASSERT_EQ(corners.size(), 36UL); + } + + { + // If setEpsX is too small, we can decode no QRs. + QRCodeDetector qrcode; + qrcode.setEpsX(0.01); + EXPECT_FALSE(qrcode.detectAndDecodeMulti(src, info, corners)); + } + + { + // If setEpsY is too small, we can decode no QRs. + QRCodeDetector qrcode; + qrcode.setEpsY(0.01); + EXPECT_FALSE(qrcode.detectAndDecodeMulti(src, info, corners)); + } +} + }} // namespace diff --git a/modules/python/bindings/CMakeLists.txt b/modules/python/bindings/CMakeLists.txt index c511b9bc80..d8753b1e2d 100644 --- a/modules/python/bindings/CMakeLists.txt +++ b/modules/python/bindings/CMakeLists.txt @@ -51,7 +51,7 @@ ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/fast_math.hpp" ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda/") ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/") ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl/") -ocv_list_filterout(opencv_hdrs "modules/.+/utils/.*") +ocv_list_filterout(opencv_hdrs "modules/.+/utils/trace.hpp") ocv_list_filterout(opencv_hdrs "modules/.*\\\\.inl\\\\.h*") ocv_list_filterout(opencv_hdrs "modules/.*_inl\\\\.h*") ocv_list_filterout(opencv_hdrs "modules/.*\\\\.details\\\\.h*") diff --git a/modules/python/src2/typing_stubs_generation/__init__.py b/modules/python/src2/typing_stubs_generation/__init__.py index 20ebf5773f..c0ae42ce76 100644 --- a/modules/python/src2/typing_stubs_generation/__init__.py +++ b/modules/python/src2/typing_stubs_generation/__init__.py @@ -12,6 +12,7 @@ from .nodes import ( SequenceTypeNode, AnyTypeNode, AggregatedTypeNode, + PathLikeTypeNode, ) from .types_conversion import ( diff --git a/modules/python/src2/typing_stubs_generation/api_refinement.py b/modules/python/src2/typing_stubs_generation/api_refinement.py index 8fdc4c53f2..cb70883e85 100644 --- a/modules/python/src2/typing_stubs_generation/api_refinement.py +++ b/modules/python/src2/typing_stubs_generation/api_refinement.py @@ -28,6 +28,8 @@ def apply_manual_api_refinement(root: NamespaceNode) -> None: version_constant = root.add_constant("__version__", "") version_constant._value_type = "str" + convert_returned_scalar_to_tuple(root) + """ def redirectError( onError: Callable[[int, str, str, str, int], None] | None @@ -126,6 +128,30 @@ def make_optional_arg(*arg_names: str) -> Callable[[NamespaceNode, SymbolName], return _make_optional_arg +def convert_returned_scalar_to_tuple(root: NamespaceNode) -> None: + """Force `tuple[float, float, float, float]` usage instead of Scalar alias + for return types due to `pyopencv_from` specialization for Scalar type. + """ + + float_4_tuple_node = TupleTypeNode( + "ScalarOutput", + items=(PrimitiveTypeNode.float_(),) * 4 + ) + + def fix_scalar_return_type(fn: FunctionNode.Overload): + if fn.return_type is None: + return + if fn.return_type.type_node.typename == "Scalar": + fn.return_type.type_node = float_4_tuple_node + + for overload in for_each_function_overload(root): + fix_scalar_return_type(overload) + + for ns in root.namespaces.values(): + for overload in for_each_function_overload(ns): + fix_scalar_return_type(overload) + + def refine_cuda_module(root: NamespaceNode) -> None: def fix_cudaoptflow_enums_names() -> None: for class_name in ("NvidiaOpticalFlow_1_0", "NvidiaOpticalFlow_2_0"): diff --git a/modules/python/src2/typing_stubs_generation/ast_utils.py b/modules/python/src2/typing_stubs_generation/ast_utils.py index e8ef52d19a..27f5e470d2 100644 --- a/modules/python/src2/typing_stubs_generation/ast_utils.py +++ b/modules/python/src2/typing_stubs_generation/ast_utils.py @@ -4,7 +4,7 @@ import keyword from .nodes import (ASTNode, NamespaceNode, ClassNode, FunctionNode, EnumerationNode, ClassProperty, OptionalTypeNode, - TupleTypeNode) + TupleTypeNode, PathLikeTypeNode) from .types_conversion import create_type_node @@ -167,12 +167,16 @@ def create_function_node_in_scope(scope: Union[NamespaceNode, ClassNode], func_info) -> FunctionNode: def prepare_overload_arguments_and_return_type(variant): arguments = [] # type: list[FunctionNode.Arg] - # Enumerate is requried, because `argno` in `variant.py_arglist` + # Enumerate is required, because `argno` in `variant.py_arglist` # refers to position of argument in C++ function interface, # but `variant.py_noptargs` refers to position in `py_arglist` for i, (_, argno) in enumerate(variant.py_arglist): arg_info = variant.args[argno] type_node = create_type_node(arg_info.tp) + # Special handling for string representation of the file system path + if arg_info.pathlike and type_node.typename == "str": + type_node = PathLikeTypeNode.string_or_pathlike_() + default_value = None if len(arg_info.defval): default_value = arg_info.defval diff --git a/modules/python/src2/typing_stubs_generation/nodes/__init__.py b/modules/python/src2/typing_stubs_generation/nodes/__init__.py index a2dbc49964..eb7769d415 100644 --- a/modules/python/src2/typing_stubs_generation/nodes/__init__.py +++ b/modules/python/src2/typing_stubs_generation/nodes/__init__.py @@ -8,5 +8,5 @@ from .type_node import ( TypeNode, OptionalTypeNode, UnionTypeNode, NoneTypeNode, TupleTypeNode, ASTNodeTypeNode, AliasTypeNode, SequenceTypeNode, AnyTypeNode, AggregatedTypeNode, NDArrayTypeNode, AliasRefTypeNode, PrimitiveTypeNode, - CallableTypeNode, DictTypeNode, ClassTypeNode + CallableTypeNode, DictTypeNode, ClassTypeNode, PathLikeTypeNode ) diff --git a/modules/python/src2/typing_stubs_generation/nodes/type_node.py b/modules/python/src2/typing_stubs_generation/nodes/type_node.py index a1b7ce5b46..86bd744a1c 100644 --- a/modules/python/src2/typing_stubs_generation/nodes/type_node.py +++ b/modules/python/src2/typing_stubs_generation/nodes/type_node.py @@ -43,7 +43,7 @@ class TypeNode(abc.ABC): Returns: str: short name of the type node. """ - pass + return "" @property def full_typename(self) -> str: @@ -123,12 +123,11 @@ class TypeNode(abc.ABC): def is_resolved(self) -> bool: return True - def relative_typename(self, module_full_export_name: str) -> str: + def relative_typename(self, module: str) -> str: """Type name relative to the provided module. Args: - module_full_export_name (str): Full export name of the module to - get relative name to. + module (str): Full export name of the module to get relative name to. Returns: str: If module name of the type node doesn't match `module`, then @@ -715,11 +714,11 @@ class ContainerTypeNode(AggregatedTypeNode): @abc.abstractproperty def type_format(self) -> str: - pass + return "" @abc.abstractproperty def types_separator(self) -> str: - pass + return "" class SequenceTypeNode(ContainerTypeNode): @@ -895,6 +894,31 @@ class ClassTypeNode(ContainerTypeNode): return ", " +class PathLikeTypeNode(TypeNode): + """Type node representing a PathLike object. + """ + def __init__(self, ctype_name: str) -> None: + super().__init__(ctype_name) + + @property + def typename(self) -> str: + return "os.PathLike[str]" + + @property + def required_usage_imports(self) -> Generator[str, None, None]: + yield "import os" + + @staticmethod + def string_or_pathlike_(ctype_name: str = "string") -> UnionTypeNode: + return UnionTypeNode( + ctype_name, + items=( + PrimitiveTypeNode.str_(ctype_name), + PathLikeTypeNode(ctype_name) + ) + ) + + def _resolve_symbol(root: Optional[ASTNode], full_symbol_name: str) -> Optional[ASTNode]: """Searches for a symbol with the given full export name in the AST starting from the `root`. diff --git a/platforms/js/build_js.py b/platforms/js/build_js.py index e8dd782b21..baa6f084bf 100755 --- a/platforms/js/build_js.py +++ b/platforms/js/build_js.py @@ -172,6 +172,10 @@ class Builder: if flags: cmd += ["-DCMAKE_C_FLAGS='%s'" % flags, "-DCMAKE_CXX_FLAGS='%s'" % flags] + + if self.options.extra_modules: + cmd.append("-DOPENCV_EXTRA_MODULES_PATH='%s'" % self.options.extra_modules) + return cmd def get_build_flags(self): @@ -257,6 +261,8 @@ if __name__ == "__main__": # Write a path to modify file like argument of this flag parser.add_argument('--config', help="Specify configuration file with own list of exported into JS functions") parser.add_argument('--webnn', action="store_true", help="Enable WebNN Backend") + parser.add_argument("--extra_modules", required=False, help="Path extra modules location (OPENCV_EXTRA_MODULES_PATH)") + transformed_args = ["--cmake_option={}".format(arg) if arg[:2] == "-D" else arg for arg in sys.argv[1:]] args = parser.parse_args(transformed_args) diff --git a/samples/python/multiview_calibration.py b/samples/python/multiview_calibration.py index 8849c707f5..abe112ec4d 100755 --- a/samples/python/multiview_calibration.py +++ b/samples/python/multiview_calibration.py @@ -1015,19 +1015,19 @@ if __name__ == '__main__': print("params.board_dict_path:", params.board_dict_path) if params.log_level == "verbose": - cv.setLogLevel(6) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_VERBOSE) elif params.log_level == "debug": - cv.setLogLevel(5) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_DEBUG) elif params.log_level == "info": - cv.setLogLevel(4) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_INFO) elif params.log_level == "warning": - cv.setLogLevel(3) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_WARNING) elif params.log_level == "error": - cv.setLogLevel(2) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_ERROR) elif params.log_level == "fatal": - cv.setLogLevel(1) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_FATAL) elif params.log_level == "silent": - cv.setLogLevel(0) + cv.utils.logging.setLogLevel(cv.utils.logging.LOG_LEVEL_SILENT) if params.visualize: assert os.path.exists(params.path_to_visualize), f'Path to result file does not exist: {params.path_to_visualize}'