Compare commits
92 Commits
Author | SHA1 | Date | |
---|---|---|---|
7af4eea253 | |||
a3049f6740 | |||
3b1e8f7054 | |||
dcab3a06ab | |||
361f9e867e | |||
35883aa604 | |||
50846f224f | |||
9ad82ed608 | |||
c9f32a226f | |||
a0df142408 | |||
8586bb4719 | |||
d734f28727 | |||
afa7399b36 | |||
bfb12093ad | |||
1190e53e9b | |||
350ce1b990 | |||
bcbf45e23a | |||
c71a7984d6 | |||
b1f3a87896 | |||
8af9a0f9d9 | |||
3790a89cd1 | |||
f475a4b24a | |||
d2f38b8b9c | |||
9ab64dbf22 | |||
20f74ce5e6 | |||
54129819d5 | |||
181eb253c6 | |||
c5f7ea7eac | |||
ea14882ff7 | |||
f8bfdce285 | |||
524f083ee4 | |||
c96ad6ba8a | |||
49bd131eef | |||
2a25ec7a56 | |||
a8a477ae67 | |||
2f27dff48b | |||
72a1cc23b1 | |||
6f3a326cf8 | |||
d881a7bbb1 | |||
65a20b43fc | |||
84941b7690 | |||
21928300c6 | |||
024d199ed0 | |||
9ac923ad09 | |||
feb6d9b20f | |||
dfbc6e0f8c | |||
43543f96bc | |||
62e477a6f2 | |||
e6955e1f03 | |||
6074c4d6fd | |||
6f44c5c52a | |||
d030c75925 | |||
9b3133ac92 | |||
b0a0bb1294 | |||
3d5090593c | |||
d4966d169b | |||
bf52896347 | |||
c52ffa2227 | |||
e4e386babf | |||
b47a9d7022 | |||
2cbf815d1f | |||
6cd0056f3b | |||
83374f390e | |||
5e59d950bd | |||
de320447f6 | |||
cf375a207f | |||
2aec1d3926 | |||
2a84dd677d | |||
ebcc34519c | |||
cff2604cf9 | |||
f8a251e268 | |||
52134fc2e9 | |||
343954ca98 | |||
44fd6b7bc0 | |||
c8a0806aab | |||
bb475dedd1 | |||
9e28aae868 | |||
5c47a97b79 | |||
84d56d00cf | |||
384f78a13c | |||
72fc32aefc | |||
98f19c60ae | |||
ae6b724824 | |||
3e751dd80d | |||
e69dff73e6 | |||
64cfe52bee | |||
8732fc8487 | |||
d9729b7190 | |||
55d3c568b2 | |||
4afafee6c1 | |||
f04084e175 | |||
9911c9c2ea |
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
autotests/read/raw/RAW_KODAK_C330_FORMAT_NONE_YRGB.raw binary
|
@ -3,6 +3,12 @@
|
|||||||
|
|
||||||
include:
|
include:
|
||||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
||||||
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-static.yml
|
||||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
|
||||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
|
||||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||||
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
|
||||||
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
|
||||||
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-static.yml
|
||||||
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
||||||
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
|
||||||
|
@ -6,3 +6,4 @@ Dependencies:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
test-before-installing: True
|
test-before-installing: True
|
||||||
|
require-passing-tests-on: [ 'Linux', 'FreeBSD', 'Windows' ]
|
||||||
|
@ -3,19 +3,19 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
project(KImageFormats)
|
project(KImageFormats)
|
||||||
|
|
||||||
include(FeatureSummary)
|
include(FeatureSummary)
|
||||||
find_package(ECM 5.91.0 NO_MODULE)
|
find_package(ECM 5.101.0 NO_MODULE)
|
||||||
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
|
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
|
||||||
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
set(CMAKE_MODULE_PATH ${KImageFormats_SOURCE_DIR}/cmake/find-modules ${ECM_MODULE_PATH})
|
||||||
|
|
||||||
include(KDEInstallDirs)
|
include(KDEInstallDirs)
|
||||||
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
|
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
|
||||||
include(KDECMakeSettings)
|
include(KDECMakeSettings)
|
||||||
|
|
||||||
include(KDEGitCommitHooks)
|
include(KDEGitCommitHooks)
|
||||||
|
include(ECMDeprecationSettings)
|
||||||
|
|
||||||
include(CheckIncludeFiles)
|
include(CheckIncludeFiles)
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
|
|
||||||
@ -70,8 +70,18 @@ if(KIMAGEFORMATS_JXL)
|
|||||||
endif()
|
endif()
|
||||||
add_feature_info(LibJXL LibJXL_FOUND "required for the QImage plugin for JPEG XL images")
|
add_feature_info(LibJXL LibJXL_FOUND "required for the QImage plugin for JPEG XL images")
|
||||||
|
|
||||||
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050f02)
|
# note: module FindLibRaw missing from https://invent.kde.org/frameworks/extra-cmake-modules
|
||||||
add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x055900)
|
find_package(LibRaw 0.20.2)
|
||||||
|
set_package_properties(LibRaw PROPERTIES
|
||||||
|
TYPE OPTIONAL
|
||||||
|
PURPOSE "Required for the QImage plugin for RAW images"
|
||||||
|
)
|
||||||
|
|
||||||
|
ecm_set_disabled_deprecation_versions(
|
||||||
|
QT 5.15.2
|
||||||
|
KF 5.95
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
if (BUILD_TESTING)
|
if (BUILD_TESTING)
|
||||||
add_subdirectory(autotests)
|
add_subdirectory(autotests)
|
||||||
|
@ -16,8 +16,9 @@ The following image formats have read-only support:
|
|||||||
- Animated Windows cursors (ani)
|
- Animated Windows cursors (ani)
|
||||||
- Gimp (xcf)
|
- Gimp (xcf)
|
||||||
- OpenEXR (exr)
|
- OpenEXR (exr)
|
||||||
- Photoshop documents (psd)
|
- Photoshop documents (psd, psb, pdd, psdt)
|
||||||
- Sun Raster (ras)
|
- Sun Raster (ras)
|
||||||
|
- Camera RAW images (arw, cr2, cr3, dcs, dng, ...)
|
||||||
|
|
||||||
The following image formats have read and write support:
|
The following image formats have read and write support:
|
||||||
|
|
||||||
|
@ -30,6 +30,12 @@ macro(kimageformats_read_tests)
|
|||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
macro(kimageformats_write_tests)
|
macro(kimageformats_write_tests)
|
||||||
|
cmake_parse_arguments(KIF_RT "" "FUZZ" "" ${ARGN})
|
||||||
|
set(_fuzzarg)
|
||||||
|
if (KIF_RT_FUZZ)
|
||||||
|
set(_fuzzarg -f ${KIF_RT_FUZZ})
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT TARGET writetest)
|
if (NOT TARGET writetest)
|
||||||
add_executable(writetest writetest.cpp)
|
add_executable(writetest writetest.cpp)
|
||||||
target_link_libraries(writetest Qt${QT_MAJOR_VERSION}::Gui)
|
target_link_libraries(writetest Qt${QT_MAJOR_VERSION}::Gui)
|
||||||
@ -37,16 +43,22 @@ macro(kimageformats_write_tests)
|
|||||||
PRIVATE IMAGEDIR="${CMAKE_CURRENT_SOURCE_DIR}/write")
|
PRIVATE IMAGEDIR="${CMAKE_CURRENT_SOURCE_DIR}/write")
|
||||||
ecm_mark_as_test(writetest)
|
ecm_mark_as_test(writetest)
|
||||||
endif()
|
endif()
|
||||||
foreach(_testname ${ARGN})
|
foreach(_testname ${KIF_RT_UNPARSED_ARGUMENTS})
|
||||||
string(REGEX MATCH "-lossless$" _is_lossless "${_testname}")
|
string(REGEX MATCH "-lossless$" _is_lossless "${_testname}")
|
||||||
|
string(REGEX MATCH "-nodatacheck" _is_no_data_check "${_testname}")
|
||||||
unset(lossless_arg)
|
unset(lossless_arg)
|
||||||
|
unset(no_data_check_arg)
|
||||||
if (_is_lossless)
|
if (_is_lossless)
|
||||||
set(lossless_arg "--lossless")
|
set(lossless_arg "--lossless")
|
||||||
string(REGEX REPLACE "-lossless$" "" _testname "${_testname}")
|
string(REGEX REPLACE "-lossless$" "" _testname "${_testname}")
|
||||||
endif()
|
endif()
|
||||||
|
if (_is_no_data_check)
|
||||||
|
set(no_data_check_arg "--no-data-check")
|
||||||
|
string(REGEX REPLACE "-nodatacheck$" "" _testname "${_testname}")
|
||||||
|
endif()
|
||||||
add_test(
|
add_test(
|
||||||
NAME kimageformats-write-${_testname}
|
NAME kimageformats-write-${_testname}
|
||||||
COMMAND writetest ${lossless_arg} ${_testname}
|
COMMAND writetest ${lossless_arg} ${no_data_check_arg} ${_fuzzarg} ${_testname}
|
||||||
)
|
)
|
||||||
endforeach(_testname)
|
endforeach(_testname)
|
||||||
endmacro()
|
endmacro()
|
||||||
@ -74,18 +86,28 @@ if (TARGET avif)
|
|||||||
kimageformats_read_tests(
|
kimageformats_read_tests(
|
||||||
avif
|
avif
|
||||||
)
|
)
|
||||||
|
kimageformats_write_tests(
|
||||||
|
avif-nodatacheck-lossless
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LibHeif_FOUND)
|
if (LibHeif_FOUND)
|
||||||
kimageformats_read_tests(
|
kimageformats_read_tests(
|
||||||
heif
|
heif
|
||||||
)
|
)
|
||||||
|
# because the plug-ins use RGB->YUV conversion which sometimes results in 1 value difference.
|
||||||
|
kimageformats_write_tests(FUZZ 1
|
||||||
|
heif-nodatacheck-lossless
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||||
kimageformats_read_tests(
|
kimageformats_read_tests(
|
||||||
jxl
|
jxl
|
||||||
)
|
)
|
||||||
|
kimageformats_write_tests(
|
||||||
|
jxl-nodatacheck-lossless
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Allow some fuzziness when reading this formats, to allow for
|
# Allow some fuzziness when reading this formats, to allow for
|
||||||
@ -114,7 +136,15 @@ kimageformats_write_tests(
|
|||||||
# kimageformats_write_tests(eps)
|
# kimageformats_write_tests(eps)
|
||||||
#endif()
|
#endif()
|
||||||
if (OpenEXR_FOUND)
|
if (OpenEXR_FOUND)
|
||||||
# FIXME: OpenEXR tests
|
kimageformats_read_tests(
|
||||||
|
exr
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (LibRaw_FOUND)
|
||||||
|
kimageformats_read_tests(
|
||||||
|
raw
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt${QT_MAJOR_VERSION}Test ${REQUIRED_QT_VERSION} CONFIG QUIET)
|
find_package(Qt${QT_MAJOR_VERSION}Test ${REQUIRED_QT_VERSION} CONFIG QUIET)
|
||||||
|
37
autotests/fuzzyeq.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kdemail.net>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<class Trait>
|
||||||
|
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
|
||||||
|
{
|
||||||
|
Q_ASSERT(im1.format() == im2.format());
|
||||||
|
Q_ASSERT(im1.depth() == 24 || im1.depth() == 32 || im1.depth() == 64);
|
||||||
|
|
||||||
|
const int height = im1.height();
|
||||||
|
const int width = im1.width();
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
const Trait *line1 = reinterpret_cast<const Trait *>(im1.scanLine(i));
|
||||||
|
const Trait *line2 = reinterpret_cast<const Trait *>(im2.scanLine(i));
|
||||||
|
for (int j = 0; j < width; ++j) {
|
||||||
|
if (line1[j] > line2[j]) {
|
||||||
|
if (line1[j] - line2[j] > fuzziness) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (line2[j] - line1[j] > fuzziness) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow each byte to be different by up to 1, to allow for rounding errors
|
||||||
|
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
|
||||||
|
{
|
||||||
|
return (im1.depth() == 64) ? fuzzyeq<quint16>(im1, im2, fuzziness) : fuzzyeq<quint8>(im1, im2, fuzziness);
|
||||||
|
}
|
BIN
autotests/read/avif/rotated090.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated090.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated090_left-to-right.avif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
autotests/read/avif/rotated090_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated090_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated090_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated180.avif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
autotests/read/avif/rotated180.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated180_left-to-right.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated180_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated180_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated180_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated270.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated270.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated270_left-to-right.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated270_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated270_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
autotests/read/avif/rotated270_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/unrotated.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/unrotated.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/unrotated_left-to-right.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/unrotated_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/unrotated_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/unrotated_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/exr/rgb-gimp.exr
Normal file
BIN
autotests/read/exr/rgb-gimp.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
autotests/read/jxl/orientation1.jxl
Normal file
BIN
autotests/read/jxl/orientation1.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation2.jxl
Normal file
BIN
autotests/read/jxl/orientation2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation3.jxl
Normal file
BIN
autotests/read/jxl/orientation3.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation4.jxl
Normal file
BIN
autotests/read/jxl/orientation4.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation5.jxl
Normal file
BIN
autotests/read/jxl/orientation5.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation6.jxl
Normal file
BIN
autotests/read/jxl/orientation6.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation7.jxl
Normal file
BIN
autotests/read/jxl/orientation7.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation8.jxl
Normal file
BIN
autotests/read/jxl/orientation8.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/pcx/indexed8.pcx
Normal file
BIN
autotests/read/pcx/indexed8.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
autotests/read/psd/16bit_grayscale.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
autotests/read/psd/16bit_grayscale.psd
Normal file
BIN
autotests/read/psd/16bit_photoshop.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
autotests/read/psd/16bit_photoshop.psb
Normal file
BIN
autotests/read/psd/32bit-rgb.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
autotests/read/psd/32bit-rgb.psd
Normal file
BIN
autotests/read/psd/32bit_grayscale.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
autotests/read/psd/32bit_grayscale.psd
Normal file
BIN
autotests/read/psd/53alphas.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
autotests/read/psd/53alphas.psd
Normal file
BIN
autotests/read/psd/8bit-grayscale.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
autotests/read/psd/8bit-grayscale.psd
Normal file
BIN
autotests/read/psd/8bit-photoshop.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
autotests/read/psd/8bit-photoshop.psb
Normal file
BIN
autotests/read/psd/adobehq-2_5.png
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
autotests/read/psd/adobehq-2_5.psd
Normal file
BIN
autotests/read/psd/birthday.pdd
Normal file
BIN
autotests/read/psd/birthday.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
autotests/read/psd/bitmap.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
autotests/read/psd/bitmap.psd
Normal file
BIN
autotests/read/psd/ccbug182496.png
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
autotests/read/psd/ccbug182496.psd
Normal file
BIN
autotests/read/psd/cmyka-16bits.png
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
autotests/read/psd/cmyka-16bits.psd
Normal file
BIN
autotests/read/psd/cmyka-8bits.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
autotests/read/psd/cmyka-8bits.psd
Normal file
BIN
autotests/read/psd/duotone.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
autotests/read/psd/duotone.psb
Normal file
BIN
autotests/read/psd/indexed.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
autotests/read/psd/indexed.psd
Normal file
BIN
autotests/read/psd/laba_16bit.png
Normal file
After Width: | Height: | Size: 189 KiB |
BIN
autotests/read/psd/laba_16bit.psd
Normal file
BIN
autotests/read/psd/laba_8bit.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
autotests/read/psd/laba_8bit.psd
Normal file
BIN
autotests/read/psd/mch-16bits.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
autotests/read/psd/mch-16bits.psd
Normal file
BIN
autotests/read/psd/mch-8bits.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
autotests/read/psd/mch-8bits.psd
Normal file
BIN
autotests/read/raw/RAW_KODAK_C330_FORMAT_NONE_YRGB.png
Normal file
After Width: | Height: | Size: 5.2 MiB |
901
autotests/read/raw/RAW_KODAK_C330_FORMAT_NONE_YRGB.raw
Normal file
BIN
autotests/read/xcf/fruktpilot_icc.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
autotests/read/xcf/fruktpilot_icc.xcf
Normal file
@ -9,6 +9,7 @@
|
|||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
@ -16,6 +17,46 @@
|
|||||||
|
|
||||||
#include "../tests/format-enum.h"
|
#include "../tests/format-enum.h"
|
||||||
|
|
||||||
|
#include "fuzzyeq.cpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SequentialFile class
|
||||||
|
* Class to make a file a sequential access device. This class is used to check if the plugins could works
|
||||||
|
* on a sequential device such as a socket.
|
||||||
|
*/
|
||||||
|
class SequentialFile : public QFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SequentialFile()
|
||||||
|
: QFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
explicit SequentialFile(const QString &name)
|
||||||
|
: QFile(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#ifndef QT_NO_QOBJECT
|
||||||
|
explicit SequentialFile(QObject *parent)
|
||||||
|
: QFile(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
SequentialFile(const QString &name, QObject *parent)
|
||||||
|
: QFile(name, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool isSequential() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 size() const override
|
||||||
|
{
|
||||||
|
return bytesAvailable();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void writeImageData(const char *name, const QString &filename, const QImage &image)
|
static void writeImageData(const char *name, const QString &filename, const QImage &image)
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
@ -31,38 +72,6 @@ static void writeImageData(const char *name, const QString &filename, const QIma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Trait>
|
|
||||||
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
|
|
||||||
{
|
|
||||||
Q_ASSERT(im1.format() == im2.format());
|
|
||||||
Q_ASSERT(im1.depth() == 24 || im1.depth() == 32 || im1.depth() == 64);
|
|
||||||
|
|
||||||
const int height = im1.height();
|
|
||||||
const int width = im1.width();
|
|
||||||
for (int i = 0; i < height; ++i) {
|
|
||||||
const Trait *line1 = reinterpret_cast<const Trait *>(im1.scanLine(i));
|
|
||||||
const Trait *line2 = reinterpret_cast<const Trait *>(im2.scanLine(i));
|
|
||||||
for (int j = 0; j < width; ++j) {
|
|
||||||
if (line1[j] > line2[j]) {
|
|
||||||
if (line1[j] - line2[j] > fuzziness) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (line2[j] - line1[j] > fuzziness) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow each byte to be different by up to 1, to allow for rounding errors
|
|
||||||
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
|
|
||||||
{
|
|
||||||
return (im1.depth() == 64) ? fuzzyeq<quint16>(im1, im2, fuzziness) : fuzzyeq<quint8>(im1, im2, fuzziness);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the original format if we support, or returns
|
// Returns the original format if we support, or returns
|
||||||
// format which we preferred to use for `fuzzyeq()`.
|
// format which we preferred to use for `fuzzyeq()`.
|
||||||
// We do only support formats with 8-bits/16-bits pre pixel.
|
// We do only support formats with 8-bits/16-bits pre pixel.
|
||||||
@ -86,7 +95,7 @@ int main(int argc, char **argv)
|
|||||||
QCoreApplication::removeLibraryPath(QStringLiteral(PLUGIN_DIR));
|
QCoreApplication::removeLibraryPath(QStringLiteral(PLUGIN_DIR));
|
||||||
QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR));
|
QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR));
|
||||||
QCoreApplication::setApplicationName(QStringLiteral("readtest"));
|
QCoreApplication::setApplicationName(QStringLiteral("readtest"));
|
||||||
QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0"));
|
QCoreApplication::setApplicationVersion(QStringLiteral("1.1.0"));
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QStringLiteral("Performs basic image conversion checking."));
|
parser.setApplicationDescription(QStringLiteral("Performs basic image conversion checking."));
|
||||||
@ -124,11 +133,11 @@ int main(int argc, char **argv)
|
|||||||
QByteArray format = suffix.toLatin1();
|
QByteArray format = suffix.toLatin1();
|
||||||
|
|
||||||
QDir imgdir(QLatin1String(IMAGEDIR "/") + suffix);
|
QDir imgdir(QLatin1String(IMAGEDIR "/") + suffix);
|
||||||
imgdir.setNameFilters(QStringList(QLatin1String("*.") + suffix));
|
|
||||||
imgdir.setFilter(QDir::Files);
|
imgdir.setFilter(QDir::Files);
|
||||||
|
|
||||||
int passed = 0;
|
int passed = 0;
|
||||||
int failed = 0;
|
int failed = 0;
|
||||||
|
int skipped = 0;
|
||||||
|
|
||||||
QTextStream(stdout) << "********* "
|
QTextStream(stdout) << "********* "
|
||||||
<< "Starting basic read tests for " << suffix << " images *********\n";
|
<< "Starting basic read tests for " << suffix << " images *********\n";
|
||||||
@ -142,26 +151,47 @@ int main(int argc, char **argv)
|
|||||||
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
|
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
|
||||||
|
|
||||||
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
||||||
|
// Launch 2 runs for each test: first run on a random access device, second run on a sequential access device
|
||||||
|
for (int seq = 0; seq < 2; ++seq) {
|
||||||
|
if (seq) {
|
||||||
|
QTextStream(stdout) << "* Run on SEQUENTIAL ACCESS device\n";
|
||||||
|
} else {
|
||||||
|
QTextStream(stdout) << "* Run on RANDOM ACCESS device\n";
|
||||||
|
}
|
||||||
for (const QFileInfo &fi : lstImgDir) {
|
for (const QFileInfo &fi : lstImgDir) {
|
||||||
|
if (!fi.suffix().compare("png", Qt::CaseInsensitive)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int suffixPos = fi.filePath().count() - suffix.count();
|
int suffixPos = fi.filePath().count() - suffix.count();
|
||||||
QString inputfile = fi.filePath();
|
QString inputfile = fi.filePath();
|
||||||
QString expfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
|
QString expfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
|
||||||
QString expfilename = QFileInfo(expfile).fileName();
|
QString expfilename = QFileInfo(expfile).fileName();
|
||||||
|
|
||||||
QImageReader inputReader(inputfile, format);
|
std::unique_ptr<QIODevice> inputDevice(seq ? new SequentialFile(inputfile) : new QFile(inputfile));
|
||||||
|
QImageReader inputReader(inputDevice.get(), format);
|
||||||
QImageReader expReader(expfile, "png");
|
QImageReader expReader(expfile, "png");
|
||||||
|
|
||||||
QImage inputImage;
|
QImage inputImage;
|
||||||
QImage expImage;
|
QImage expImage;
|
||||||
|
|
||||||
|
// inputImage is auto-rotated to final orientation
|
||||||
|
inputReader.setAutoTransform(true);
|
||||||
|
|
||||||
if (!expReader.read(&expImage)) {
|
if (!expReader.read(&expImage)) {
|
||||||
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n";
|
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n";
|
||||||
++failed;
|
++failed;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!inputReader.canRead()) {
|
if (!inputReader.canRead()) {
|
||||||
|
// All plugins must pass the test on a random device.
|
||||||
|
// canRead() must also return false if the plugin is unable to run on a sequential device.
|
||||||
|
if (inputDevice->isSequential()) {
|
||||||
|
QTextStream(stdout) << "SKIP : " << fi.fileName() << ": cannot read on a sequential device (don't worry, it's ok)\n";
|
||||||
|
++skipped;
|
||||||
|
} else {
|
||||||
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed can read: " << inputReader.errorString() << "\n";
|
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed can read: " << inputReader.errorString() << "\n";
|
||||||
++failed;
|
++failed;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!inputReader.read(&inputImage)) {
|
if (!inputReader.read(&inputImage)) {
|
||||||
@ -188,8 +218,8 @@ int main(int argc, char **argv)
|
|||||||
inputImage = inputImage.convertToFormat(cmpFormat);
|
inputImage = inputImage.convertToFormat(cmpFormat);
|
||||||
}
|
}
|
||||||
if (expImage.format() != cmpFormat) {
|
if (expImage.format() != cmpFormat) {
|
||||||
QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << expfilename << " from " << formatToString(expImage.format()) << " to "
|
QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << expfilename << " from " << formatToString(expImage.format())
|
||||||
<< formatToString(cmpFormat) << '\n';
|
<< " to " << formatToString(cmpFormat) << '\n';
|
||||||
expImage = expImage.convertToFormat(cmpFormat);
|
expImage = expImage.convertToFormat(cmpFormat);
|
||||||
}
|
}
|
||||||
if (fuzzyeq(inputImage, expImage, fuzziness)) {
|
if (fuzzyeq(inputImage, expImage, fuzziness)) {
|
||||||
@ -203,8 +233,9 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QTextStream(stdout) << "Totals: " << passed << " passed, " << failed << " failed\n";
|
QTextStream(stdout) << "Totals: " << passed << " passed, " << skipped << " skipped, " << failed << " failed\n";
|
||||||
QTextStream(stdout) << "********* "
|
QTextStream(stdout) << "********* "
|
||||||
<< "Finished basic read tests for " << suffix << " images *********\n";
|
<< "Finished basic read tests for " << suffix << " images *********\n";
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include <QImageWriter>
|
#include <QImageWriter>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#include "fuzzyeq.cpp"
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
@ -31,7 +33,13 @@ int main(int argc, char **argv)
|
|||||||
parser.addPositionalArgument(QStringLiteral("format"), QStringLiteral("format to test."));
|
parser.addPositionalArgument(QStringLiteral("format"), QStringLiteral("format to test."));
|
||||||
QCommandLineOption lossless(QStringList() << QStringLiteral("l") << QStringLiteral("lossless"),
|
QCommandLineOption lossless(QStringList() << QStringLiteral("l") << QStringLiteral("lossless"),
|
||||||
QStringLiteral("Check that reading back the data gives the same image."));
|
QStringLiteral("Check that reading back the data gives the same image."));
|
||||||
|
QCommandLineOption ignoreDataCheck({QStringLiteral("no-data-check")}, QStringLiteral("Don't check that write data is exactly the same."));
|
||||||
|
QCommandLineOption fuzz(QStringList() << QStringLiteral("f") << QStringLiteral("fuzz"),
|
||||||
|
QStringLiteral("Allow for some deviation in ARGB data."),
|
||||||
|
QStringLiteral("max"));
|
||||||
parser.addOption(lossless);
|
parser.addOption(lossless);
|
||||||
|
parser.addOption(ignoreDataCheck);
|
||||||
|
parser.addOption(fuzz);
|
||||||
|
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
@ -44,11 +52,26 @@ int main(int argc, char **argv)
|
|||||||
parser.showHelp(1);
|
parser.showHelp(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uchar fuzziness = 0;
|
||||||
|
if (parser.isSet(fuzz)) {
|
||||||
|
bool ok;
|
||||||
|
uint fuzzarg = parser.value(fuzz).toUInt(&ok);
|
||||||
|
if (!ok || fuzzarg > 255) {
|
||||||
|
QTextStream(stderr) << "Error: max fuzz argument must be a number between 0 and 255\n";
|
||||||
|
parser.showHelp(1);
|
||||||
|
}
|
||||||
|
fuzziness = uchar(fuzzarg);
|
||||||
|
}
|
||||||
|
|
||||||
QString suffix = args.at(0);
|
QString suffix = args.at(0);
|
||||||
QByteArray format = suffix.toLatin1();
|
QByteArray format = suffix.toLatin1();
|
||||||
|
|
||||||
QDir imgdir(QStringLiteral(IMAGEDIR));
|
QDir imgdir(QStringLiteral(IMAGEDIR));
|
||||||
|
if (parser.isSet(ignoreDataCheck)) {
|
||||||
|
imgdir.setNameFilters({QLatin1String("*.png")});
|
||||||
|
} else {
|
||||||
imgdir.setNameFilters(QStringList(QLatin1String("*.") + suffix));
|
imgdir.setNameFilters(QStringList(QLatin1String("*.") + suffix));
|
||||||
|
}
|
||||||
imgdir.setFilter(QDir::Files);
|
imgdir.setFilter(QDir::Files);
|
||||||
|
|
||||||
int passed = 0;
|
int passed = 0;
|
||||||
@ -58,8 +81,13 @@ int main(int argc, char **argv)
|
|||||||
<< "Starting basic write tests for " << suffix << " images *********\n";
|
<< "Starting basic write tests for " << suffix << " images *********\n";
|
||||||
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
||||||
for (const QFileInfo &fi : lstImgDir) {
|
for (const QFileInfo &fi : lstImgDir) {
|
||||||
|
QString pngfile;
|
||||||
|
if (parser.isSet(ignoreDataCheck)) {
|
||||||
|
pngfile = fi.filePath();
|
||||||
|
} else {
|
||||||
int suffixPos = fi.filePath().count() - suffix.count();
|
int suffixPos = fi.filePath().count() - suffix.count();
|
||||||
QString pngfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
|
pngfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
|
||||||
|
}
|
||||||
QString pngfilename = QFileInfo(pngfile).fileName();
|
QString pngfilename = QFileInfo(pngfile).fileName();
|
||||||
|
|
||||||
QImageReader pngReader(pngfile, "png");
|
QImageReader pngReader(pngfile, "png");
|
||||||
@ -70,6 +98,21 @@ int main(int argc, char **argv)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray writtenData;
|
||||||
|
{
|
||||||
|
QBuffer buffer(&writtenData);
|
||||||
|
QImageWriter imgWriter(&buffer, format.constData());
|
||||||
|
if (parser.isSet(lossless)) {
|
||||||
|
imgWriter.setQuality(100);
|
||||||
|
}
|
||||||
|
if (!imgWriter.write(pngImage)) {
|
||||||
|
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed to write image data\n";
|
||||||
|
++failed;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parser.isSet(ignoreDataCheck)) {
|
||||||
QFile expFile(fi.filePath());
|
QFile expFile(fi.filePath());
|
||||||
if (!expFile.open(QIODevice::ReadOnly)) {
|
if (!expFile.open(QIODevice::ReadOnly)) {
|
||||||
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not open " << fi.fileName() << ": " << expFile.errorString() << "\n";
|
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not open " << fi.fileName() << ": " << expFile.errorString() << "\n";
|
||||||
@ -89,22 +132,12 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray writtenData;
|
|
||||||
{
|
|
||||||
QBuffer buffer(&writtenData);
|
|
||||||
QImageWriter imgWriter(&buffer, format.constData());
|
|
||||||
if (!imgWriter.write(pngImage)) {
|
|
||||||
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed to write image data\n";
|
|
||||||
++failed;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expData != writtenData) {
|
if (expData != writtenData) {
|
||||||
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": written data differs from " << fi.fileName() << "\n";
|
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": written data differs from " << fi.fileName() << "\n";
|
||||||
++failed;
|
++failed;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QImage reReadImage;
|
QImage reReadImage;
|
||||||
{
|
{
|
||||||
@ -119,8 +152,18 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(lossless)) {
|
if (parser.isSet(lossless)) {
|
||||||
if (pngImage != reReadImage) {
|
if (!fuzzyeq(pngImage, reReadImage, fuzziness)) {
|
||||||
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": re-reading the data resulted in a different image\n";
|
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": re-reading the data resulted in a different image\n";
|
||||||
|
if (pngImage.size() == reReadImage.size()) {
|
||||||
|
for (int i = 0; i < pngImage.width(); ++i) {
|
||||||
|
for (int j = 0; j < pngImage.height(); ++j) {
|
||||||
|
if (pngImage.pixel(i, j) != reReadImage.pixel(i, j)) {
|
||||||
|
QTextStream(stdout) << "Pixel is different " << i << ',' << j << ' ' << pngImage.pixel(i, j) << ' ' << reReadImage.pixel(i, j)
|
||||||
|
<< '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
++failed;
|
++failed;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
86
cmake/find-modules/FindLibRaw.cmake
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# - Find LibRaw
|
||||||
|
# Find the LibRaw library <https://www.libraw.org>
|
||||||
|
# This module defines
|
||||||
|
# LibRaw_VERSION, the version string of LibRaw
|
||||||
|
# LibRaw_INCLUDE_DIR, where to find libraw/libraw.h
|
||||||
|
# LibRaw_LIBRARIES, the libraries needed to use LibRaw (non-thread-safe)
|
||||||
|
# LibRaw_r_LIBRARIES, the libraries needed to use LibRaw (thread-safe)
|
||||||
|
# LibRaw_DEFINITIONS, the definitions needed to use LibRaw (non-thread-safe)
|
||||||
|
# LibRaw_r_DEFINITIONS, the definitions needed to use LibRaw (thread-safe)
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2013 Pino Toscano <pino at kde dot org>
|
||||||
|
# SPDX-FileCopyrightText: 2013 Gilles Caulier <caulier dot gilles at gmail dot com>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
FIND_PACKAGE(PkgConfig)
|
||||||
|
|
||||||
|
IF(PKG_CONFIG_FOUND)
|
||||||
|
PKG_CHECK_MODULES(PC_LIBRAW libraw)
|
||||||
|
SET(LibRaw_DEFINITIONS ${PC_LIBRAW_CFLAGS_OTHER})
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(PC_LIBRAW_R libraw_r)
|
||||||
|
SET(LibRaw_r_DEFINITIONS ${PC_LIBRAW_R_CFLAGS_OTHER})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
FIND_PATH(LibRaw_INCLUDE_DIR libraw/libraw.h
|
||||||
|
HINTS
|
||||||
|
${PC_LIBRAW_INCLUDEDIR}
|
||||||
|
${PC_LibRaw_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(LibRaw_LIBRARIES NAMES raw
|
||||||
|
HINTS
|
||||||
|
${PC_LIBRAW_LIBDIR}
|
||||||
|
${PC_LIBRAW_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(LibRaw_r_LIBRARIES NAMES raw_r
|
||||||
|
HINTS
|
||||||
|
${PC_LIBRAW_R_LIBDIR}
|
||||||
|
${PC_LIBRAW_R_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
IF(LibRaw_INCLUDE_DIR)
|
||||||
|
FILE(READ ${LibRaw_INCLUDE_DIR}/libraw/libraw_version.h _libraw_version_content)
|
||||||
|
|
||||||
|
STRING(REGEX MATCH "#define LIBRAW_MAJOR_VERSION[ \t]*([0-9]*)\n" _version_major_match ${_libraw_version_content})
|
||||||
|
SET(_libraw_version_major "${CMAKE_MATCH_1}")
|
||||||
|
|
||||||
|
STRING(REGEX MATCH "#define LIBRAW_MINOR_VERSION[ \t]*([0-9]*)\n" _version_minor_match ${_libraw_version_content})
|
||||||
|
SET(_libraw_version_minor "${CMAKE_MATCH_1}")
|
||||||
|
|
||||||
|
STRING(REGEX MATCH "#define LIBRAW_PATCH_VERSION[ \t]*([0-9]*)\n" _version_patch_match ${_libraw_version_content})
|
||||||
|
SET(_libraw_version_patch "${CMAKE_MATCH_1}")
|
||||||
|
|
||||||
|
IF(_version_major_match AND _version_minor_match AND _version_patch_match)
|
||||||
|
SET(LibRaw_VERSION "${_libraw_version_major}.${_libraw_version_minor}.${_libraw_version_patch}")
|
||||||
|
ELSE()
|
||||||
|
IF(NOT LibRaw_FIND_QUIETLY)
|
||||||
|
MESSAGE(STATUS "Failed to get version information from ${LibRaw_INCLUDE_DIR}/libraw/libraw_version.h")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibRaw
|
||||||
|
REQUIRED_VARS LibRaw_LIBRARIES LibRaw_INCLUDE_DIR
|
||||||
|
VERSION_VAR LibRaw_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(LibRaw_VERSION
|
||||||
|
LibRaw_INCLUDE_DIR
|
||||||
|
LibRaw_LIBRARIES
|
||||||
|
LibRaw_r_LIBRARIES
|
||||||
|
LibRaw_DEFINITIONS
|
||||||
|
LibRaw_r_DEFINITIONS
|
||||||
|
)
|
||||||
|
|
||||||
|
if(LibRaw_FOUND AND NOT TARGET LibRaw::LibRaw)
|
||||||
|
add_library(LibRaw::LibRaw UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(LibRaw::LibRaw PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${LibRaw_LIBRARIES}"
|
||||||
|
INTERFACE_COMPILE_OPTIONS "${LibRaw_DEFINITIONS}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${LibRaw_INCLUDE_DIR}"
|
||||||
|
)
|
||||||
|
endif()
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
function(kimageformats_add_plugin plugin)
|
function(kimageformats_add_plugin plugin)
|
||||||
set(options)
|
set(options)
|
||||||
|
set(oneValueArgs)
|
||||||
set(multiValueArgs SOURCES)
|
set(multiValueArgs SOURCES)
|
||||||
cmake_parse_arguments(KIF_ADD_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
cmake_parse_arguments(KIF_ADD_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
if(NOT KIF_ADD_PLUGIN_SOURCES)
|
if(NOT KIF_ADD_PLUGIN_SOURCES)
|
||||||
@ -19,19 +20,26 @@ endfunction()
|
|||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_ani SOURCES ani.cpp)
|
kimageformats_add_plugin(kimg_ani SOURCES ani.cpp)
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES ani.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES ani.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
if (TARGET avif)
|
if (TARGET avif)
|
||||||
kimageformats_add_plugin(kimg_avif SOURCES "avif.cpp")
|
kimageformats_add_plugin(kimg_avif SOURCES "avif.cpp")
|
||||||
target_link_libraries(kimg_avif "avif")
|
target_link_libraries(kimg_avif "avif")
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES avif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES avif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES dds-qt.desktop RENAME dds.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES dds-qt.desktop RENAME dds.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
@ -39,14 +47,18 @@ if (BUILD_EPS_PLUGIN)
|
|||||||
if (TARGET Qt${QT_MAJOR_VERSION}::PrintSupport)
|
if (TARGET Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||||
kimageformats_add_plugin(kimg_eps SOURCES eps.cpp)
|
kimageformats_add_plugin(kimg_eps SOURCES eps.cpp)
|
||||||
target_link_libraries(kimg_eps Qt${QT_MAJOR_VERSION}::PrintSupport)
|
target_link_libraries(kimg_eps Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES eps.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES eps.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
# need this for Qt's version of the plugin
|
# need this for Qt's version of the plugin
|
||||||
install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
@ -64,13 +76,17 @@ if(OpenEXR_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
kde_target_enable_exceptions(kimg_exr PRIVATE)
|
kde_target_enable_exceptions(kimg_exr PRIVATE)
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES exr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES exr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_hdr SOURCES hdr.cpp)
|
kimageformats_add_plugin(kimg_hdr SOURCES hdr.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES hdr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES hdr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
@ -78,51 +94,85 @@ if (LibHeif_FOUND)
|
|||||||
kimageformats_add_plugin(kimg_heif SOURCES heif.cpp)
|
kimageformats_add_plugin(kimg_heif SOURCES heif.cpp)
|
||||||
target_link_libraries(kimg_heif PkgConfig::LibHeif)
|
target_link_libraries(kimg_heif PkgConfig::LibHeif)
|
||||||
kde_target_enable_exceptions(kimg_heif PRIVATE)
|
kde_target_enable_exceptions(kimg_heif PRIVATE)
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES heif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES heif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||||
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
|
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
|
||||||
target_link_libraries(kimg_jxl PkgConfig::LibJXL PkgConfig::LibJXLThreads)
|
target_link_libraries(kimg_jxl PkgConfig::LibJXL PkgConfig::LibJXLThreads)
|
||||||
|
if (LibJXL_VERSION VERSION_GREATER_EQUAL "0.7.0")
|
||||||
|
target_compile_definitions(kimg_jxl PRIVATE KIMG_JXL_API_VERSION=70)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES jxl.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES jxl.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_pcx SOURCES pcx.cpp)
|
kimageformats_add_plugin(kimg_pcx SOURCES pcx.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_pic SOURCES pic.cpp)
|
kimageformats_add_plugin(kimg_pic SOURCES pic.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES pic.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES pic.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_psd SOURCES psd.cpp)
|
kimageformats_add_plugin(kimg_psd SOURCES psd.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES psd.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES psd.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_ras SOURCES ras.cpp)
|
kimageformats_add_plugin(kimg_ras SOURCES ras.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES ras.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES ras.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_rgb SOURCES rgb.cpp)
|
kimageformats_add_plugin(kimg_rgb SOURCES rgb.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES rgb.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES rgb.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp)
|
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES tga.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES tga.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_xcf SOURCES xcf.cpp)
|
kimageformats_add_plugin(kimg_xcf SOURCES xcf.cpp)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES xcf.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES xcf.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
##################################
|
||||||
|
|
||||||
|
if (LibRaw_FOUND)
|
||||||
|
kimageformats_add_plugin(kimg_raw SOURCES raw.cpp)
|
||||||
|
kde_enable_exceptions()
|
||||||
|
target_link_libraries(kimg_raw LibRaw::LibRaw)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
|
install(FILES raw.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
@ -130,10 +180,14 @@ if (KF5Archive_FOUND)
|
|||||||
|
|
||||||
kimageformats_add_plugin(kimg_kra SOURCES kra.cpp)
|
kimageformats_add_plugin(kimg_kra SOURCES kra.cpp)
|
||||||
target_link_libraries(kimg_kra KF5::Archive)
|
target_link_libraries(kimg_kra KF5::Archive)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES kra.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES kra.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_ora SOURCES ora.cpp)
|
kimageformats_add_plugin(kimg_ora SOURCES ora.cpp)
|
||||||
target_link_libraries(kimg_ora KF5::Archive)
|
target_link_libraries(kimg_ora KF5::Archive)
|
||||||
|
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||||
install(FILES ora.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
install(FILES ora.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
@ -521,6 +521,9 @@ bool ANIHandler::canRead(QIODevice *device)
|
|||||||
qWarning("ANIHandler::canRead() called with no device");
|
qWarning("ANIHandler::canRead() called with no device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (device->isSequential()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const QByteArray riffIntro = device->peek(12);
|
const QByteArray riffIntro = device->peek(12);
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include <QColorSpace>
|
#include <QColorSpace>
|
||||||
|
|
||||||
#include "avif_p.h"
|
#include "avif_p.h"
|
||||||
|
#include "util_p.h"
|
||||||
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
|
|
||||||
QAVIFHandler::QAVIFHandler()
|
QAVIFHandler::QAVIFHandler()
|
||||||
@ -40,6 +42,11 @@ bool QAVIFHandler::canRead() const
|
|||||||
|
|
||||||
if (m_parseState != ParseAvifError) {
|
if (m_parseState != ParseAvifError) {
|
||||||
setFormat("avif");
|
setFormat("avif");
|
||||||
|
|
||||||
|
if (m_parseState == ParseAvifFinished) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -56,7 +63,7 @@ bool QAVIFHandler::canRead(QIODevice *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
avifROData input;
|
avifROData input;
|
||||||
input.data = (const uint8_t *)header.constData();
|
input.data = reinterpret_cast<const uint8_t *>(header.constData());
|
||||||
input.size = header.size();
|
input.size = header.size();
|
||||||
|
|
||||||
if (avifPeekCompatibleFileType(&input)) {
|
if (avifPeekCompatibleFileType(&input)) {
|
||||||
@ -67,7 +74,7 @@ bool QAVIFHandler::canRead(QIODevice *device)
|
|||||||
|
|
||||||
bool QAVIFHandler::ensureParsed() const
|
bool QAVIFHandler::ensureParsed() const
|
||||||
{
|
{
|
||||||
if (m_parseState == ParseAvifSuccess) {
|
if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifMetadata || m_parseState == ParseAvifFinished) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_parseState == ParseAvifError) {
|
if (m_parseState == ParseAvifError) {
|
||||||
@ -79,6 +86,28 @@ bool QAVIFHandler::ensureParsed() const
|
|||||||
return that->ensureDecoder();
|
return that->ensureDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QAVIFHandler::ensureOpened() const
|
||||||
|
{
|
||||||
|
if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifFinished) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (m_parseState == ParseAvifError) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAVIFHandler *that = const_cast<QAVIFHandler *>(this);
|
||||||
|
if (ensureParsed()) {
|
||||||
|
if (m_parseState == ParseAvifMetadata) {
|
||||||
|
bool success = that->jumpToNextImage();
|
||||||
|
that->m_parseState = success ? ParseAvifSuccess : ParseAvifError;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
that->m_parseState = ParseAvifError;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool QAVIFHandler::ensureDecoder()
|
bool QAVIFHandler::ensureDecoder()
|
||||||
{
|
{
|
||||||
if (m_decoder) {
|
if (m_decoder) {
|
||||||
@ -87,7 +116,7 @@ bool QAVIFHandler::ensureDecoder()
|
|||||||
|
|
||||||
m_rawData = device()->readAll();
|
m_rawData = device()->readAll();
|
||||||
|
|
||||||
m_rawAvifData.data = (const uint8_t *)m_rawData.constData();
|
m_rawAvifData.data = reinterpret_cast<const uint8_t *>(m_rawData.constData());
|
||||||
m_rawAvifData.size = m_rawData.size();
|
m_rawAvifData.size = m_rawData.size();
|
||||||
|
|
||||||
if (avifPeekCompatibleFileType(&m_rawAvifData) == AVIF_FALSE) {
|
if (avifPeekCompatibleFileType(&m_rawAvifData) == AVIF_FALSE) {
|
||||||
@ -97,6 +126,9 @@ bool QAVIFHandler::ensureDecoder()
|
|||||||
|
|
||||||
m_decoder = avifDecoderCreate();
|
m_decoder = avifDecoderCreate();
|
||||||
|
|
||||||
|
m_decoder->ignoreExif = AVIF_TRUE;
|
||||||
|
m_decoder->ignoreXMP = AVIF_TRUE;
|
||||||
|
|
||||||
#if AVIF_VERSION >= 80400
|
#if AVIF_VERSION >= 80400
|
||||||
m_decoder->maxThreads = qBound(1, QThread::idealThreadCount(), 64);
|
m_decoder->maxThreads = qBound(1, QThread::idealThreadCount(), 64);
|
||||||
#endif
|
#endif
|
||||||
@ -105,6 +137,10 @@ bool QAVIFHandler::ensureDecoder()
|
|||||||
m_decoder->strictFlags = AVIF_STRICT_DISABLED;
|
m_decoder->strictFlags = AVIF_STRICT_DISABLED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if AVIF_VERSION >= 110000
|
||||||
|
m_decoder->imageDimensionLimit = 65535;
|
||||||
|
#endif
|
||||||
|
|
||||||
avifResult decodeResult;
|
avifResult decodeResult;
|
||||||
|
|
||||||
decodeResult = avifDecoderSetIOMemory(m_decoder, m_rawAvifData.data, m_rawAvifData.size);
|
decodeResult = avifDecoderSetIOMemory(m_decoder, m_rawAvifData.data, m_rawAvifData.size);
|
||||||
@ -127,13 +163,10 @@ bool QAVIFHandler::ensureDecoder()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodeResult = avifDecoderNextImage(m_decoder);
|
|
||||||
|
|
||||||
if (decodeResult == AVIF_RESULT_OK) {
|
|
||||||
m_container_width = m_decoder->image->width;
|
m_container_width = m_decoder->image->width;
|
||||||
m_container_height = m_decoder->image->height;
|
m_container_height = m_decoder->image->height;
|
||||||
|
|
||||||
if ((m_container_width > 32768) || (m_container_height > 32768)) {
|
if ((m_container_width > 65535) || (m_container_height > 65535)) {
|
||||||
qWarning("AVIF image (%dx%d) is too large!", m_container_width, m_container_height);
|
qWarning("AVIF image (%dx%d) is too large!", m_container_width, m_container_height);
|
||||||
m_parseState = ParseAvifError;
|
m_parseState = ParseAvifError;
|
||||||
return false;
|
return false;
|
||||||
@ -145,21 +178,43 @@ bool QAVIFHandler::ensureDecoder()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_parseState = ParseAvifSuccess;
|
if (m_container_width > ((16384 * 16384) / m_container_height)) {
|
||||||
if (decode_one_frame()) {
|
qWarning("AVIF image (%dx%d) has more than 256 megapixels!", m_container_width, m_container_height);
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
m_parseState = ParseAvifError;
|
m_parseState = ParseAvifError;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
qWarning("ERROR: Failed to decode image: %s", avifResultToString(decodeResult));
|
|
||||||
}
|
|
||||||
|
|
||||||
avifDecoderDestroy(m_decoder);
|
// calculate final dimensions with crop and rotate operations applied
|
||||||
m_decoder = nullptr;
|
int new_width = m_container_width;
|
||||||
m_parseState = ParseAvifError;
|
int new_height = m_container_height;
|
||||||
return false;
|
|
||||||
|
if (m_decoder->image->transformFlags & AVIF_TRANSFORM_CLAP) {
|
||||||
|
if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) && (m_decoder->image->clap.horizOffD > 0)
|
||||||
|
&& (m_decoder->image->clap.vertOffD > 0)) {
|
||||||
|
int crop_width = (int)((double)(m_decoder->image->clap.widthN) / (m_decoder->image->clap.widthD) + 0.5);
|
||||||
|
if (crop_width < new_width && crop_width > 0) {
|
||||||
|
new_width = crop_width;
|
||||||
|
}
|
||||||
|
int crop_height = (int)((double)(m_decoder->image->clap.heightN) / (m_decoder->image->clap.heightD) + 0.5);
|
||||||
|
if (crop_height < new_height && crop_height > 0) {
|
||||||
|
new_height = crop_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IROT) {
|
||||||
|
if (m_decoder->image->irot.angle == 1 || m_decoder->image->irot.angle == 3) {
|
||||||
|
int tmp = new_width;
|
||||||
|
new_width = new_height;
|
||||||
|
new_height = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_estimated_dimensions.setWidth(new_width);
|
||||||
|
m_estimated_dimensions.setHeight(new_height);
|
||||||
|
|
||||||
|
m_parseState = ParseAvifMetadata;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QAVIFHandler::decode_one_frame()
|
bool QAVIFHandler::decode_one_frame()
|
||||||
@ -186,13 +241,13 @@ bool QAVIFHandler::decode_one_frame()
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (loadalpha) {
|
if (loadalpha) {
|
||||||
resultformat = QImage::Format_RGBA8888;
|
resultformat = QImage::Format_ARGB32;
|
||||||
} else {
|
} else {
|
||||||
resultformat = QImage::Format_RGBX8888;
|
resultformat = QImage::Format_RGB32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QImage result(m_decoder->image->width, m_decoder->image->height, resultformat);
|
|
||||||
|
|
||||||
|
QImage result = imageAlloc(m_decoder->image->width, m_decoder->image->height, resultformat);
|
||||||
if (result.isNull()) {
|
if (result.isNull()) {
|
||||||
qWarning("Memory cannot be allocated");
|
qWarning("Memory cannot be allocated");
|
||||||
return false;
|
return false;
|
||||||
@ -200,7 +255,7 @@ bool QAVIFHandler::decode_one_frame()
|
|||||||
|
|
||||||
QColorSpace colorspace;
|
QColorSpace colorspace;
|
||||||
if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) {
|
if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) {
|
||||||
const QByteArray icc_data((const char *)m_decoder->image->icc.data, (int)m_decoder->image->icc.size);
|
const QByteArray icc_data(reinterpret_cast<const char *>(m_decoder->image->icc.data), m_decoder->image->icc.size);
|
||||||
colorspace = QColorSpace::fromIccProfile(icc_data);
|
colorspace = QColorSpace::fromIccProfile(icc_data);
|
||||||
if (!colorspace.isValid()) {
|
if (!colorspace.isValid()) {
|
||||||
qWarning("AVIF image has Qt-unsupported or invalid ICC profile!");
|
qWarning("AVIF image has Qt-unsupported or invalid ICC profile!");
|
||||||
@ -279,14 +334,16 @@ bool QAVIFHandler::decode_one_frame()
|
|||||||
rgb.depth = 16;
|
rgb.depth = 16;
|
||||||
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
||||||
|
|
||||||
if (!loadalpha) {
|
if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) {
|
||||||
if (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
|
|
||||||
resultformat = QImage::Format_Grayscale16;
|
resultformat = QImage::Format_Grayscale16;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
rgb.depth = 8;
|
rgb.depth = 8;
|
||||||
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||||
|
rgb.format = AVIF_RGB_FORMAT_BGRA;
|
||||||
|
#else
|
||||||
|
rgb.format = AVIF_RGB_FORMAT_ARGB;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if AVIF_VERSION >= 80400
|
#if AVIF_VERSION >= 80400
|
||||||
if (m_decoder->imageCount > 1) {
|
if (m_decoder->imageCount > 1) {
|
||||||
@ -295,14 +352,8 @@ bool QAVIFHandler::decode_one_frame()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (loadalpha) {
|
if (!loadalpha && (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) {
|
||||||
resultformat = QImage::Format_ARGB32;
|
|
||||||
} else {
|
|
||||||
if (m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
|
|
||||||
resultformat = QImage::Format_Grayscale8;
|
resultformat = QImage::Format_Grayscale8;
|
||||||
} else {
|
|
||||||
resultformat = QImage::Format_RGB32;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,13 +444,15 @@ bool QAVIFHandler::decode_one_frame()
|
|||||||
m_current_image = result.convertToFormat(resultformat);
|
m_current_image = result.convertToFormat(resultformat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_estimated_dimensions = m_current_image.size();
|
||||||
|
|
||||||
m_must_jump_to_next_image = false;
|
m_must_jump_to_next_image = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QAVIFHandler::read(QImage *image)
|
bool QAVIFHandler::read(QImage *image)
|
||||||
{
|
{
|
||||||
if (!ensureParsed()) {
|
if (!ensureOpened()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,6 +463,13 @@ bool QAVIFHandler::read(QImage *image)
|
|||||||
*image = m_current_image;
|
*image = m_current_image;
|
||||||
if (imageCount() >= 2) {
|
if (imageCount() >= 2) {
|
||||||
m_must_jump_to_next_image = true;
|
m_must_jump_to_next_image = true;
|
||||||
|
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) {
|
||||||
|
// all frames in animation have been read
|
||||||
|
m_parseState = ParseAvifFinished;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the static image has been read
|
||||||
|
m_parseState = ParseAvifFinished;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -417,15 +477,44 @@ bool QAVIFHandler::read(QImage *image)
|
|||||||
bool QAVIFHandler::write(const QImage &image)
|
bool QAVIFHandler::write(const QImage &image)
|
||||||
{
|
{
|
||||||
if (image.format() == QImage::Format_Invalid) {
|
if (image.format() == QImage::Format_Invalid) {
|
||||||
qWarning("No image data to save");
|
qWarning("No image data to save!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((image.width() > 0) && (image.height() > 0)) {
|
||||||
|
if ((image.width() > 65535) || (image.height() > 65535)) {
|
||||||
|
qWarning("Image (%dx%d) is too large to save!", image.width(), image.height());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.width() > ((16384 * 16384) / image.height())) {
|
||||||
|
qWarning("Image (%dx%d) will not be saved because it has more than 256 megapixels!", image.width(), image.height());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((image.width() > 32768) || (image.height() > 32768)) {
|
if ((image.width() > 32768) || (image.height() > 32768)) {
|
||||||
qWarning("Image is too large");
|
qWarning("Image (%dx%d) has a dimension above 32768 pixels, saved AVIF may not work in other software!", image.width(), image.height());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning("Image has zero dimension!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *encoder_name = avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE);
|
||||||
|
if (!encoder_name) {
|
||||||
|
qWarning("Cannot save AVIF images because libavif was built without AV1 encoders!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lossless = false;
|
||||||
|
if (m_quality >= 100) {
|
||||||
|
if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE)) {
|
||||||
|
lossless = true;
|
||||||
|
} else {
|
||||||
|
qWarning("You are using %s encoder. It is recommended to enable libAOM encoder in libavif to use lossless compression.", encoder_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY * (100 - qBound(0, m_quality, 100)) / 100;
|
int maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY * (100 - qBound(0, m_quality, 100)) / 100;
|
||||||
int minQuantizer = 0;
|
int minQuantizer = 0;
|
||||||
int maxQuantizerAlpha = 0;
|
int maxQuantizerAlpha = 0;
|
||||||
@ -618,6 +707,9 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
|
|
||||||
// in case primaries or trc were not identified
|
// in case primaries or trc were not identified
|
||||||
if ((primaries_to_save == 2) || (transfer_to_save == 2)) {
|
if ((primaries_to_save == 2) || (transfer_to_save == 2)) {
|
||||||
|
if (lossless) {
|
||||||
|
iccprofile = tmpcolorimage.colorSpace().iccProfile();
|
||||||
|
} else {
|
||||||
// upgrade image to higher bit depth
|
// upgrade image to higher bit depth
|
||||||
if (save_depth == 8) {
|
if (save_depth == 8) {
|
||||||
save_depth = 10;
|
save_depth = 10;
|
||||||
@ -657,6 +749,7 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
|
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else { // profile is unsupported by Qt
|
} else { // profile is unsupported by Qt
|
||||||
iccprofile = tmpcolorimage.colorSpace().iccProfile();
|
iccprofile = tmpcolorimage.colorSpace().iccProfile();
|
||||||
if (iccprofile.size() > 0) {
|
if (iccprofile.size() > 0) {
|
||||||
@ -664,6 +757,9 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lossless && pixel_format == AVIF_PIXEL_FORMAT_YUV444) {
|
||||||
|
matrix_to_save = (avifMatrixCoefficients)0;
|
||||||
|
}
|
||||||
avif = avifImageCreate(tmpcolorimage.width(), tmpcolorimage.height(), save_depth, pixel_format);
|
avif = avifImageCreate(tmpcolorimage.width(), tmpcolorimage.height(), save_depth, pixel_format);
|
||||||
avif->matrixCoefficients = matrix_to_save;
|
avif->matrixCoefficients = matrix_to_save;
|
||||||
|
|
||||||
@ -671,7 +767,7 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
avif->transferCharacteristics = transfer_to_save;
|
avif->transferCharacteristics = transfer_to_save;
|
||||||
|
|
||||||
if (iccprofile.size() > 0) {
|
if (iccprofile.size() > 0) {
|
||||||
avifImageSetProfileICC(avif, (const uint8_t *)iccprofile.constData(), iccprofile.size());
|
avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
avifRGBImage rgb;
|
avifRGBImage rgb;
|
||||||
@ -682,9 +778,7 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
if (save_depth > 8) { // 10bit depth
|
if (save_depth > 8) { // 10bit depth
|
||||||
rgb.depth = 16;
|
rgb.depth = 16;
|
||||||
|
|
||||||
if (tmpcolorimage.hasAlphaChannel()) {
|
if (!tmpcolorimage.hasAlphaChannel()) {
|
||||||
avif->alphaRange = AVIF_RANGE_FULL;
|
|
||||||
} else {
|
|
||||||
rgb.ignoreAlpha = AVIF_TRUE;
|
rgb.ignoreAlpha = AVIF_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +788,6 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
|
|
||||||
if (tmpcolorimage.hasAlphaChannel()) {
|
if (tmpcolorimage.hasAlphaChannel()) {
|
||||||
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
rgb.format = AVIF_RGB_FORMAT_RGBA;
|
||||||
avif->alphaRange = AVIF_RANGE_FULL;
|
|
||||||
} else {
|
} else {
|
||||||
rgb.format = AVIF_RGB_FORMAT_RGB;
|
rgb.format = AVIF_RGB_FORMAT_RGB;
|
||||||
}
|
}
|
||||||
@ -718,14 +811,14 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
encoder->maxQuantizerAlpha = maxQuantizerAlpha;
|
encoder->maxQuantizerAlpha = maxQuantizerAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->speed = 7;
|
encoder->speed = 6;
|
||||||
|
|
||||||
res = avifEncoderWrite(encoder, avif, &raw);
|
res = avifEncoderWrite(encoder, avif, &raw);
|
||||||
avifEncoderDestroy(encoder);
|
avifEncoderDestroy(encoder);
|
||||||
avifImageDestroy(avif);
|
avifImageDestroy(avif);
|
||||||
|
|
||||||
if (res == AVIF_RESULT_OK) {
|
if (res == AVIF_RESULT_OK) {
|
||||||
qint64 status = device()->write((const char *)raw.data, raw.size);
|
qint64 status = device()->write(reinterpret_cast<const char *>(raw.data), raw.size);
|
||||||
avifRWDataFree(&raw);
|
avifRWDataFree(&raw);
|
||||||
|
|
||||||
if (status > 0) {
|
if (status > 0) {
|
||||||
@ -753,7 +846,7 @@ QVariant QAVIFHandler::option(ImageOption option) const
|
|||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case Size:
|
case Size:
|
||||||
return m_current_image.size();
|
return m_estimated_dimensions;
|
||||||
case Animation:
|
case Animation:
|
||||||
if (imageCount() >= 2) {
|
if (imageCount() >= 2) {
|
||||||
return true;
|
return true;
|
||||||
@ -809,6 +902,14 @@ int QAVIFHandler::currentImageNumber() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_parseState == ParseAvifMetadata) {
|
||||||
|
if (m_decoder->imageCount >= 2) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return m_decoder->imageIndex;
|
return m_decoder->imageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,13 +919,16 @@ bool QAVIFHandler::jumpToNextImage()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_decoder->imageIndex >= 0) {
|
||||||
if (m_decoder->imageCount < 2) {
|
if (m_decoder->imageCount < 2) {
|
||||||
|
m_parseState = ParseAvifSuccess;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning
|
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning
|
||||||
avifDecoderReset(m_decoder);
|
avifDecoderReset(m_decoder);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
avifResult decodeResult = avifDecoderNextImage(m_decoder);
|
avifResult decodeResult = avifDecoderNextImage(m_decoder);
|
||||||
|
|
||||||
@ -846,6 +950,7 @@ bool QAVIFHandler::jumpToNextImage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (decode_one_frame()) {
|
if (decode_one_frame()) {
|
||||||
|
m_parseState = ParseAvifSuccess;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
m_parseState = ParseAvifError;
|
m_parseState = ParseAvifError;
|
||||||
@ -861,17 +966,21 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
|
|||||||
|
|
||||||
if (m_decoder->imageCount < 2) { // not an animation
|
if (m_decoder->imageCount < 2) { // not an animation
|
||||||
if (imageNumber == 0) {
|
if (imageNumber == 0) {
|
||||||
|
if (ensureOpened()) {
|
||||||
|
m_parseState = ParseAvifSuccess;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (imageNumber < 0 || imageNumber >= m_decoder->imageCount) { // wrong index
|
if (imageNumber < 0 || imageNumber >= m_decoder->imageCount) { // wrong index
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageNumber == m_decoder->imageCount) { // we are here already
|
if (imageNumber == m_decoder->imageIndex) { // we are here already
|
||||||
|
m_must_jump_to_next_image = false;
|
||||||
|
m_parseState = ParseAvifSuccess;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,6 +1004,7 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (decode_one_frame()) {
|
if (decode_one_frame()) {
|
||||||
|
m_parseState = ParseAvifSuccess;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
m_parseState = ParseAvifError;
|
m_parseState = ParseAvifError;
|
||||||
@ -904,7 +1014,7 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
|
|||||||
|
|
||||||
int QAVIFHandler::nextImageDelay() const
|
int QAVIFHandler::nextImageDelay() const
|
||||||
{
|
{
|
||||||
if (!ensureParsed()) {
|
if (!ensureOpened()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,7 +1039,8 @@ int QAVIFHandler::loopCount() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
// Endless loop to work around https://github.com/AOMediaCodec/libavif/issues/347
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
|
QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
|
||||||
@ -946,12 +1057,26 @@ QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
|
|||||||
|
|
||||||
QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||||
{
|
{
|
||||||
|
static const bool isAvifDecoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_DECODE) != nullptr);
|
||||||
|
static const bool isAvifEncoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE) != nullptr);
|
||||||
|
|
||||||
if (format == "avif") {
|
if (format == "avif") {
|
||||||
return Capabilities(CanRead | CanWrite);
|
Capabilities format_cap;
|
||||||
|
if (isAvifDecoderAvailable) {
|
||||||
|
format_cap |= CanRead;
|
||||||
|
}
|
||||||
|
if (isAvifEncoderAvailable) {
|
||||||
|
format_cap |= CanWrite;
|
||||||
|
}
|
||||||
|
return format_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == "avifs") {
|
if (format == "avifs") {
|
||||||
return Capabilities(CanRead);
|
Capabilities format_cap;
|
||||||
|
if (isAvifDecoderAvailable) {
|
||||||
|
format_cap |= CanRead;
|
||||||
|
}
|
||||||
|
return format_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!format.isEmpty()) {
|
if (!format.isEmpty()) {
|
||||||
@ -962,10 +1087,10 @@ QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
Capabilities cap;
|
Capabilities cap;
|
||||||
if (device->isReadable() && QAVIFHandler::canRead(device)) {
|
if (device->isReadable() && QAVIFHandler::canRead(device) && isAvifDecoderAvailable) {
|
||||||
cap |= CanRead;
|
cap |= CanRead;
|
||||||
}
|
}
|
||||||
if (device->isWritable()) {
|
if (device->isWritable() && isAvifEncoderAvailable) {
|
||||||
cap |= CanWrite;
|
cap |= CanWrite;
|
||||||
}
|
}
|
||||||
return cap;
|
return cap;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QImageIOPlugin>
|
#include <QImageIOPlugin>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
|
#include <QSize>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <avif/avif.h>
|
#include <avif/avif.h>
|
||||||
#include <qimageiohandler.h>
|
#include <qimageiohandler.h>
|
||||||
@ -45,6 +46,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
static QPointF CompatibleChromacity(qreal chrX, qreal chrY);
|
static QPointF CompatibleChromacity(qreal chrX, qreal chrY);
|
||||||
bool ensureParsed() const;
|
bool ensureParsed() const;
|
||||||
|
bool ensureOpened() const;
|
||||||
bool ensureDecoder();
|
bool ensureDecoder();
|
||||||
bool decode_one_frame();
|
bool decode_one_frame();
|
||||||
|
|
||||||
@ -52,6 +54,8 @@ private:
|
|||||||
ParseAvifError = -1,
|
ParseAvifError = -1,
|
||||||
ParseAvifNotParsed = 0,
|
ParseAvifNotParsed = 0,
|
||||||
ParseAvifSuccess = 1,
|
ParseAvifSuccess = 1,
|
||||||
|
ParseAvifMetadata = 2,
|
||||||
|
ParseAvifFinished = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseAvifState m_parseState;
|
ParseAvifState m_parseState;
|
||||||
@ -59,6 +63,7 @@ private:
|
|||||||
|
|
||||||
uint32_t m_container_width;
|
uint32_t m_container_width;
|
||||||
uint32_t m_container_height;
|
uint32_t m_container_height;
|
||||||
|
QSize m_estimated_dimensions;
|
||||||
|
|
||||||
QByteArray m_rawData;
|
QByteArray m_rawData;
|
||||||
avifROData m_rawAvifData;
|
avifROData m_rawAvifData;
|
||||||
|