Compare commits

..

1 Commits

Author SHA1 Message Date
Albert Astals Cid
8658355701 Fix crash on malformed files
oss-fuzz/449485443
2025-10-05 21:25:48 +00:00
116 changed files with 417 additions and 3176 deletions

View File

@@ -7,5 +7,5 @@ Dependencies:
Options:
test-before-installing: True
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
cmake-options: "-DKIMAGEFORMATS_JXR=ON -DKIMAGEFORMATS_HEIF=ON -DKIMAGEFORMATS_HEIF_TEST:STRING=OFF -DKIMAGEFORMATS_HEJ2_TEST:STRING=OFF -DKIMAGEFORMATS_AVCI_TEST:STRING=OFF"
cmake-options: "-DKIMAGEFORMATS_DDS=ON -DKIMAGEFORMATS_JXR=ON -DKIMAGEFORMATS_HEIF=ON"
per-test-timeout: 90

View File

@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.29)
cmake_minimum_required(VERSION 3.16)
set(KF_VERSION "6.25.0") # handled by release scripts
set(KF_DEP_VERSION "6.25.0") # handled by release scripts
set(KF_VERSION "6.20.0") # handled by release scripts
set(KF_DEP_VERSION "6.19.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION})
include(FeatureSummary)
find_package(ECM 6.25.0 NO_MODULE)
find_package(ECM 6.19.0 NO_MODULE)
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)
@@ -21,7 +21,7 @@ include(ECMDeprecationSettings)
include(CheckIncludeFiles)
include(FindPkgConfig)
set(REQUIRED_QT_VERSION 6.9.0)
set(REQUIRED_QT_VERSION 6.7.0)
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(KF6Archive ${KF_DEP_VERSION})
@@ -65,12 +65,6 @@ set_package_properties(libavif PROPERTIES
option(KIMAGEFORMATS_DDS "Enable plugin for DDS format" ON)
option(KIMAGEFORMATS_HEIF "Enable plugin for HEIF format" OFF)
set(KIMAGEFORMATS_HEIF_TEST "ALL" CACHE STRING "Enable HEIF tests: OFF, READ_ONLY, ALL")
set_property(CACHE KIMAGEFORMATS_HEIF_TEST PROPERTY STRINGS "OFF" "READ_ONLY" "ALL")
set(KIMAGEFORMATS_HEJ2_TEST "ALL" CACHE STRING "Enable HEJ2 tests: OFF, READ_ONLY, ALL")
set_property(CACHE KIMAGEFORMATS_HEJ2_TEST PROPERTY STRINGS "OFF" "READ_ONLY" "ALL")
set(KIMAGEFORMATS_AVCI_TEST "ALL" CACHE STRING "Enable AVCI tests: OFF, ALL")
set_property(CACHE KIMAGEFORMATS_AVCI_TEST PROPERTY STRINGS "OFF" "ALL")
if(KIMAGEFORMATS_HEIF)
pkg_check_modules(LibHeif IMPORTED_TARGET libheif>=1.10.0)
endif()
@@ -105,8 +99,8 @@ endif()
add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images")
ecm_set_disabled_deprecation_versions(
QT 6.11.0
KF 6.23.0
QT 6.10.0
KF 6.18.0
)
add_subdirectory(src)

View File

@@ -21,7 +21,6 @@ The following image formats have read-only support:
- Krita (kra)
- OpenRaster (ora)
- Pixar raster (pxr)
- PlayStation graphics (tim)
- Portable FloatMap/HalfMap (pfm, phm)
- Photoshop documents (psd, psb, pdd, psdt)
- Radiance HDR (hdr)
@@ -251,7 +250,6 @@ limit depends on the format encoding).
- RAW: 65,535 x 65,535 pixels
- RGB: 65,535 x 65,535 pixels
- SCT: 300,000 x 300,000 pixels
- TIM: 65,535 x 65,535 pixels
- TGA: 65,535 x 65,535 pixels
- XCF: 300,000 x 300,000 pixels
@@ -292,7 +290,7 @@ in your cmake options.**
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `DDS_DISABLE_STRIDE_ALIGNMENT`: disable the stride alignment based on DDS
- `DDS_DISABLE_STRIDE_ALIGNMENT`: disable the stride aligment based on DDS
pitch: it is known that some writers do not set it correctly.
### The HEIF plugin
@@ -305,15 +303,6 @@ distributions. In particular, it is necessary that the HEIF library has
support for HEVC codec. If HEVC codec is not available the plugin
will compile but will fail the tests.
**If you are interested in compiling the plugin without running the tests,
also use the following string options:**
- `KIMAGEFORMATS_HEIF_TEST` to change the behaviour of HEIF tests. Set to
`"OFF"` (no test at all) or `"READ_ONLY"` (run read tests only).
- `KIMAGEFORMATS_HEJ2_TEST` to change the behaviour of HEJ2 tests. Set to
`"OFF"` (no test at all) or `"READ_ONLY"` (run read tests only)..
- `KIMAGEFORMATS_AVCI_TEST` to change the behaviour of AVCI tests. Set to
`"OFF"` (no test at all).
### The EXR plugin
The following defines can be defined in cmake to modify the behavior of the
@@ -359,16 +348,9 @@ The plugin supports the following image data:
type 4.
- FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images
with color map only.
- FORM IMAG (Compact Disc-Interactive): It supports CLut4, CLut7, CLut8, Rle7
and DYuv formats.
- FORM RGFX: It supports uncompressed images only.
- FOR4 CIMG (Maya Image File Format): It supports 24/48-bit RGB and 32/64-bit
RGBA images.
> [!note]
> The plugin only supports the IFF, ILBM, and LBM file extensions. You'll
> need to rename files with different extensions to open them.
### The JP2 plugin
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
@@ -400,7 +382,7 @@ The following defines can be defined in cmake to modify the behavior of the
plugin:
- `JXR_DENY_FLOAT_IMAGE`: disables the use of float images and consequently
any HDR data will be lost.
- `JXR_DISABLE_DEPTH_CONVERSION`: remove the needs of additional memory by
- `JXR_DISABLE_DEPTH_CONVERSION`: remove the neeeds of additional memory by
disabling the conversion between different color depths (e.g. RGBA64bpp to
RGBA32bpp) at the cost of reduced compatibility.
- `JXR_DISABLE_BGRA_HACK`: Windows displays and opens JXR files correctly out
@@ -432,8 +414,6 @@ PSD support has the following limitations:
- Multichannel images are treated as CMYK if they have 2 or more channels.
- Multichannel images are treated as Grayscale if they have 1 channel.
- Duotone images are treated as grayscale images.
- Grayscale images with alpha channel or at 32 bit depth are converted to
RGBA due to the lack of the appropriate Qt grayscale container.
- Extra channels other than alpha are discarded.
The following defines can be defined in cmake to modify the behavior of the

View File

@@ -86,7 +86,6 @@ kimageformats_read_tests(
ras
rgb
sct
tim
tga
)
@@ -103,52 +102,36 @@ if (KF6Archive_FOUND)
endif()
if (TARGET avif)
if(${libavif_VERSION} VERSION_GREATER_EQUAL "1.2.0")
kimageformats_read_tests(
avif
)
else()
message(WARNING "libavif ${libavif_VERSION} doesn't support decoding new AVIF files!\n"
"AVIF read tests are disabled, consider updating libavif.")
endif()
kimageformats_read_tests(
avif
)
kimageformats_write_tests(
avif-nodatacheck-lossless
)
endif()
if (LibHeif_FOUND)
if (KIMAGEFORMATS_HEIF_TEST STREQUAL "ALL" OR KIMAGEFORMATS_HEIF_TEST STREQUAL "READ_ONLY")
kimageformats_read_tests(
heif
)
endif()
if (KIMAGEFORMATS_HEIF_TEST STREQUAL "ALL")
# because the plug-ins use RGB->YUV conversion which sometimes results in 1 value difference.
kimageformats_write_tests(FUZZ 1
heif-nodatacheck-lossless
)
endif()
kimageformats_read_tests(
heif
)
# because the plug-ins use RGB->YUV conversion which sometimes results in 1 value difference.
kimageformats_write_tests(FUZZ 1
heif-nodatacheck-lossless
)
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.17.0")
if (KIMAGEFORMATS_HEJ2_TEST STREQUAL "ALL" OR KIMAGEFORMATS_HEJ2_TEST STREQUAL "READ_ONLY")
kimageformats_read_tests(FUZZ 1
hej2
)
endif()
if (KIMAGEFORMATS_HEJ2_TEST STREQUAL "ALL")
kimageformats_write_tests(FUZZ 1
hej2-nodatacheck-lossless
)
endif()
kimageformats_read_tests(FUZZ 1
hej2
)
kimageformats_write_tests(FUZZ 1
hej2-nodatacheck-lossless
)
endif()
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.6")
if (KIMAGEFORMATS_AVCI_TEST STREQUAL "ALL")
kimageformats_read_tests(FUZZ 4
avci
)
endif()
kimageformats_read_tests(FUZZ 4
avci
)
endif()
endif()

View File

@@ -48,7 +48,7 @@ private Q_SLOTS:
QCOMPARE(reader.text(QStringLiteral("Author")), QStringLiteral("KDE Community"));
}
void testRead()
void textRead()
{
QImageReader reader(QFINDTESTDATA("ani/test.ani"));
QVERIFY(reader.canRead());

View File

@@ -18,11 +18,6 @@
# limitations under the License.
#
################################################################################
LDFLAGS=""
if [[ $FUZZING_ENGINE == "afl" ]]; then
LDFLAGS="-fuse-ld=lld"
fi
export LDFLAGS
# build zstd
cd $SRC/zstd
@@ -180,7 +175,6 @@ HANDLER_TYPES="ANIHandler ani
RAWHandler raw
RGBHandler rgb
ScitexHandler sct
TIMHandler tim
TGAHandler tga
XCFHandler xcf"
@@ -191,7 +185,7 @@ echo "$HANDLER_TYPES" | while read class format; do
/usr/libexec/moc $SRC/kimageformats/src/imageformats/$format.cpp -o $format.moc
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
/usr/libexec/moc $header -o moc_`basename $header .h`.cpp
$CXX $CXXFLAGS $LDFLAGS -fPIC -DHANDLER=$class -std=c++17 autotests/ossfuzz/kimgio_fuzzer.cc $SRC/kimageformats/src/imageformats/$format.cpp $SRC/kimageformats/src/imageformats/scanlineconverter.cpp $SRC/kimageformats/src/imageformats/microexif.cpp $SRC/kimageformats/src/imageformats/chunks.cpp -o $OUT/$fuzz_target_name -DJXL_STATIC_DEFINE -DJXL_THREADS_STATIC_DEFINE -DJXL_CMS_STATIC_DEFINE -DINITGUID -I $SRC/kimageformats/src/imageformats/ -I $SRC/libavif/include/ -I $SRC/libjxl/build/lib/include/ -I $SRC/libjxl/lib/include/ -I /usr/local/include/OpenEXR/ -I /usr/local/include/KF6/KArchive/ -I /usr/local/include/openjpeg-2.5 -I /usr/local/include/Imath -I $SRC/jxrlib/common/include -I $SRC/jxrlib/jxrgluelib -I $SRC/jxrlib/image/sys -I /usr/include/QtCore/ -I /usr/include/QtGui/ -I . $SRC/libavif/build/libavif.a /usr/local/lib/libheif.a /usr/local/lib/libde265.a /usr/local/lib/libopenh264.a $SRC/aom/build.libavif/libaom.a $SRC/libjxl/build/lib/libjxl_threads.a $SRC/libjxl/build/lib/libjxl.a $SRC/libjxl/build/lib/libjxl_cms.a $SRC/libjxl/build/third_party/highway/libhwy.a $SRC/libjxl/build/third_party/brotli/libbrotlidec.a $SRC/libjxl/build/third_party/brotli/libbrotlienc.a $SRC/libjxl/build/third_party/brotli/libbrotlicommon.a -lQt6Gui -lQt6Core -lQt6BundledLibpng -lQt6BundledHarfbuzz -lm -lQt6BundledPcre2 -ldl -lpthread $LIB_FUZZING_ENGINE /usr/local/lib/libz.a /usr/local/lib/x86_64-linux-gnu/libKF6Archive.a /usr/local/lib/libz.a /usr/local/lib/libraw.a /usr/local/lib/libOpenEXR-3_3.a /usr/local/lib/libIex-3_3.a /usr/local/lib/libImath-3_1.a /usr/local/lib/libIlmThread-3_3.a /usr/local/lib/libOpenEXRCore-3_3.a /usr/local/lib/libOpenEXRUtil-3_3.a /usr/local/lib/libopenjp2.a /usr/local/lib/libzstd.a $SRC/jxrlib/build/libjxrglue.a $SRC/jxrlib/build/libjpegxr.a /usr/local/lib/liblzma.a /usr/local/lib/libbz2.a -lclang_rt.builtins
$CXX $CXXFLAGS -fPIC -DHANDLER=$class -std=c++17 autotests/ossfuzz/kimgio_fuzzer.cc $SRC/kimageformats/src/imageformats/$format.cpp $SRC/kimageformats/src/imageformats/scanlineconverter.cpp $SRC/kimageformats/src/imageformats/microexif.cpp $SRC/kimageformats/src/imageformats/chunks.cpp -o $OUT/$fuzz_target_name -DJXL_STATIC_DEFINE -DJXL_THREADS_STATIC_DEFINE -DJXL_CMS_STATIC_DEFINE -DINITGUID -I $SRC/kimageformats/src/imageformats/ -I $SRC/libavif/include/ -I $SRC/libjxl/build/lib/include/ -I $SRC/libjxl/lib/include/ -I /usr/local/include/OpenEXR/ -I /usr/local/include/KF6/KArchive/ -I /usr/local/include/openjpeg-2.5 -I /usr/local/include/Imath -I $SRC/jxrlib/common/include -I $SRC/jxrlib/jxrgluelib -I $SRC/jxrlib/image/sys -I /usr/include/QtCore/ -I /usr/include/QtGui/ -I . $SRC/libavif/build/libavif.a /usr/local/lib/libheif.a /usr/local/lib/libde265.a /usr/local/lib/libopenh264.a $SRC/aom/build.libavif/libaom.a $SRC/libjxl/build/lib/libjxl_threads.a $SRC/libjxl/build/lib/libjxl.a $SRC/libjxl/build/lib/libjxl_cms.a $SRC/libjxl/build/third_party/highway/libhwy.a $SRC/libjxl/build/third_party/brotli/libbrotlidec.a $SRC/libjxl/build/third_party/brotli/libbrotlienc.a $SRC/libjxl/build/third_party/brotli/libbrotlicommon.a -lQt6Gui -lQt6Core -lQt6BundledLibpng -lQt6BundledHarfbuzz -lm -lQt6BundledPcre2 -ldl -lpthread $LIB_FUZZING_ENGINE /usr/local/lib/libz.a -lKF6Archive /usr/local/lib/libz.a /usr/local/lib/libraw.a /usr/local/lib/libOpenEXR-3_3.a /usr/local/lib/libIex-3_3.a /usr/local/lib/libImath-3_1.a /usr/local/lib/libIlmThread-3_3.a /usr/local/lib/libOpenEXRCore-3_3.a /usr/local/lib/libOpenEXRUtil-3_3.a /usr/local/lib/libopenjp2.a /usr/local/lib/libzstd.a $SRC/jxrlib/build/libjxrglue.a $SRC/jxrlib/build/libjpegxr.a -llzma /usr/local/lib/libbz2.a -lclang_rt.builtins
# -lclang_rt.builtins in the previous line is a temporary workaround to avoid a linker error "undefined reference to __truncsfhf2". Investigate why this is needed here, but not anywhere else, and possibly remove it.

View File

@@ -23,7 +23,7 @@
Usage:
python infra/helper.py build_image kimageformats
python infra/helper.py build_fuzzers --sanitizer undefined|address|memory kimageformats
python infra/helper.py run_fuzzer kimageformats kimgio_[ani|avif|dds|exr|hdr|heif|iff|jp2|jxl|jxr|kra|ora|pcx|pfm|pic|psd|pxr|qoi|ras|raw|rgb|sct|tim|tga|xcf]_fuzzer
python infra/helper.py run_fuzzer kimageformats kimgio_[ani|avif|dds|exr|hdr|heif|iff|jp2|jxl|jxr|kra|ora|pcx|pfm|pic|psd|pxr|qoi|ras|raw|rgb|sct|tga|xcf]_fuzzer
*/
#include <QBuffer>
@@ -52,7 +52,6 @@
#include "raw_p.h"
#include "rgb_p.h"
#include "sct_p.h"
#include "tim_p.h"
#include "tga_p.h"
#include "xcf_p.h"

View File

@@ -33,12 +33,12 @@ git clone --depth 1 -b master https://invent.kde.org/frameworks/extra-cmake-modu
git clone --depth 1 --branch=dev git://code.qt.io/qt/qtbase.git
git clone --depth 1 --branch=dev git://code.qt.io/qt/qttools.git
git clone --depth 1 -b master https://invent.kde.org/frameworks/karchive.git
git clone --depth 1 -b v3.13.1 https://aomedia.googlesource.com/aom
git clone --depth 1 -b v1.3.0 https://github.com/AOMediaCodec/libavif.git
git clone --depth 1 -b v3.12.0 https://aomedia.googlesource.com/aom
git clone --depth 1 -b v1.2.1 https://github.com/AOMediaCodec/libavif.git
git clone --depth 1 https://github.com/strukturag/libde265.git
git clone --depth 1 -b v2.5.4 https://github.com/uclouvain/openjpeg.git
git clone --depth 1 -b v2.5.3 https://github.com/uclouvain/openjpeg.git
git clone --depth 1 https://github.com/strukturag/libheif.git
git clone --depth=1 --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
git clone --depth=1 --branch v0.11.x --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
git clone --depth 1 https://github.com/LibRaw/LibRaw
git clone --depth 1 https://github.com/mircomir/jxrlib.git
git clone --depth 1 -b v2.6.0 https://github.com/cisco/openh264.git

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

View File

@@ -1,11 +0,0 @@
[
{
"fileName" : "profile_gray.png",
"colorSpace" : {
"colorModel" : "Gray",
"primaries" : "Custom",
"transferFunction" : "SRgb",
"gamma" : 2.31
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

View File

@@ -1,11 +0,0 @@
[
{
"fileName" : "profile_gray_gamma22.png",
"colorSpace" : {
"colorModel" : "Gray",
"primaries" : "Custom",
"transferFunction" : "Gamma",
"gamma" : 2.2
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

View File

@@ -1,11 +0,0 @@
[
{
"fileName" : "profile_gray_gamma28.png",
"colorSpace" : {
"colorModel" : "Gray",
"primaries" : "Custom",
"transferFunction" : "Gamma",
"gamma" : 2.8
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

View File

@@ -1,11 +0,0 @@
[
{
"fileName" : "profile_gray_linear.png",
"colorSpace" : {
"colorModel" : "Gray",
"primaries" : "Custom",
"transferFunction" : "Linear",
"gamma" : 1
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

View File

@@ -1,12 +0,0 @@
[
{
"fileName" : "profile_gray_prophoto.png",
"colorSpace" : {
"description" : "grayscale D50 with ProPhoto TRC",
"colorModel" : "Gray",
"primaries" : "Custom",
"transferFunction" : "Custom",
"gamma" : 0
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

View File

@@ -1,9 +0,0 @@
[
{
"fileName" : "cdi_dyuv_each.iff",
"resolution" : {
"dotsPerMeterX" : 3937,
"dotsPerMeterY" : 5249
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,37 +0,0 @@
[
{
"fileName" : "sv5_rgba32_rgx.png",
"colorSpace" : {
"description" : "TIFF ICC Profile",
"primaries" : "SRgb",
"transferFunction" : "SRgb",
"gamma" : 0
},
"metadata" : [
{
"key" : "Author",
"value" : "KDE Project"
},
{
"key" : "Copyright",
"value" : "@2025 KDE Project"
},
{
"key" : "CreationDate",
"value" : "2025-01-14T10:34:51"
},
{
"key" : "Description",
"value" : "TV broadcast test image."
},
{
"key" : "Title",
"value" : "Test Card"
}
],
"resolution" : {
"dotsPerMeterX" : 2835,
"dotsPerMeterY" : 2835
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -1,14 +0,0 @@
[
{
"fileName" : "gray_linear_lossy.png",
"fuzziness" : 1,
"description" : "Minimum fuzziness value to pass the test on all architectures.",
"colorSpace" : {
"description" : "Gra_D65_Rel_SRG",
"primaries" : "Custom",
"transferFunction" : "SRgb",
"gamma" : 0,
"colorModel" : "Gray"
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -2,8 +2,8 @@
{
"fileName" : "32bit_grayscale.png",
"colorSpace" : {
"description" : "RGB emulation of \"Linear Grayscale Profile\"",
"colorModel" : "Rgb",
"description" : "Linear Grayscale Profile",
"colorModel" : "Gray",
"primaries" : "Custom",
"transferFunction" : "Linear",
"gamma" : 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,26 +0,0 @@
[
{
"fileName" : "testcard_graya16.png",
"colorSpace" : {
"description" : "RGB emulation of \"Gray Gamma 2.2\"",
"colorModel" : "Rgb",
"primaries" : "SRgb",
"transferFunction" : "Gamma",
"gamma" : 2.19922
},
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-11-17T07:27:47"
},
{
"key" : "Software" ,
"value" : "Adobe Photoshop 26.11 (Windows)"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 11811
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,26 +0,0 @@
[
{
"fileName" : "testcard_graya32.png",
"colorSpace" : {
"description" : "RGB emulation of \"Profilo scala di grigio lineare\"",
"colorModel" : "Rgb",
"primaries" : "Custom",
"transferFunction" : "Linear",
"gamma" : 1
},
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-11-17T07:29:19"
},
{
"key" : "Software" ,
"value" : "Adobe Photoshop 26.11 (Windows)"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 11811
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,28 +0,0 @@
[
{
"fileName" : "testcard_graya8.png",
"fuzziness" : 1,
"perceptiveFuzziness" : true,
"colorSpace" : {
"description" : "RGB emulation of \"Gray Gamma 2.2\"",
"colorModel" : "Rgb",
"primaries" : "SRgb",
"transferFunction" : "Gamma",
"gamma" : 2.19922
},
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-11-17T07:28:50"
},
{
"key" : "Software" ,
"value" : "Adobe Photoshop 26.11 (Windows)"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 11811
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot16_icc.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot32_icc.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot32fplin_icc.png",
"fuzziness" : 1
}
]

View File

@@ -1,6 +0,0 @@
[
{
"fileName" : "fruktpilot_icc.png",
"fuzziness" : 1
}
]

View File

@@ -258,26 +258,22 @@ int main(int argc, char **argv)
});
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
// checks if the format has read capability
if (!formats.contains(format)) {
QTextStream(stdout) << "FAIL : current configuration is missing necessary decoder(s) for " << suffix << "!\n"
<< "********* "
<< "Finished basic read tests for " << suffix << " images *********\n";
return 1;
if (format == "avci" || format == "heif" || format == "hej2") {
QTextStream(stdout) << "WARNING : " << suffix << " is not supported with current libheif configuration!\n"
<< "********* "
<< "Finished basic read tests for " << suffix << " images *********\n";
return 0;
}
}
const QFileInfoList lstImgDir = imgdir.entryInfoList();
// Launch 3 runs for each test:
// - first run on a random access device with allocation limit set to 256 MiB.
// - second run on a random access device with allocation limit set to 0 MiB.
// - third run on a sequential access device.
for (int run = 0; run < 3; ++run) {
QImageReader::setAllocationLimit(run == 1 ? 0 : 256);
bool seq = run == 2;
// 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 (allocation limit: " << QImageReader::allocationLimit() << " MiB)\n";
QTextStream(stdout) << "* Run on RANDOM ACCESS device\n";
}
for (const QFileInfo &fi : lstImgDir) {
TemplateImage timg(fi);
@@ -342,7 +338,12 @@ int main(int argc, char **argv)
OptionTest optionTest;
if (!optionTest.store(&inputReader)) {
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": error while reading options\n";
++failed;
if (format == "heif") {
// libheif + ffmpeg decoder is unable to load all HEIF files.
++skipped;
} else {
++failed;
}
continue;
}

View File

@@ -138,11 +138,13 @@ bool TemplateImage::checkOptionaInfo(const QImage& image, QString& error) const
return false;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
auto clmName = QString(QMetaEnum::fromType<QColorSpace::ColorModel>().valueToKey(quint64(cs.colorModel())));
if (clmName != clm) {
error = QStringLiteral("ColorSpace ColorModel mismatch (current: %1, expected: %2)!").arg(clmName, clm);
return false;
}
#endif
}
// Test resolution

View File

@@ -56,7 +56,7 @@ public:
/*!
* \brief skipSequentialDeviceTest
* \return True if the sequential test should be skipped.
* \return tre it the sequential test should be skipped.
*/
bool skipSequentialDeviceTest() const;

View File

@@ -319,9 +319,11 @@ QImage formatSourceImage(const QImage::Format &format)
image = QImage(QStringLiteral("%1/rgba16.png").arg(folder));
break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888:
image = QImage(QStringLiteral("%1/cmyk8.tif").arg(folder));
break;
#endif
default:
break;
@@ -380,7 +382,12 @@ int formatTest(const QString &suffix, bool createTemplates)
QBuffer buffer(&ba);
auto writtenImage = QImageReader(&buffer, suffix.toLatin1()).read();
if (writtenImage.isNull()) {
++failed;
if (suffix.toLatin1() == "heif") {
// libheif + ffmpeg decoder is unable to load all HEIF files.
++skipped;
} else {
++failed;
}
QTextStream(stdout) << "FAIL : error while reading the image " << formatName << "\n";
continue;
}
@@ -634,17 +641,23 @@ int main(int argc, char **argv)
auto suffix = args.at(0);
// skip test if configuration is obviously incomplete
// skip test if libheif configuration is obviously incomplete
QByteArray format = suffix.toLatin1();
const QList<QByteArray> read_formats = QImageReader::supportedImageFormats();
if (!read_formats.contains(format)) { // checks if the format has read capability
QTextStream(stdout) << "FAIL : current configuration is missing necessary decoder(s) for " << format << "!\n";
return 1;
}
const QList<QByteArray> write_formats = QImageWriter::supportedImageFormats();
if (!write_formats.contains(format)) { // checks if the format has write capability
QTextStream(stdout) << "FAIL : libraries configuration is missing necessary encoder(s) for " << format << "!\n";
return 1;
if (!read_formats.contains(format)) {
if (format == "heif" || format == "hej2") {
QTextStream(stdout) << "WARNING : libheif configuration is missing necessary decoder(s)!\n";
return 0;
}
}
if (!write_formats.contains(format)) {
if (format == "heif" || format == "hej2") {
QTextStream(stdout) << "WARNING : libheif configuration is missing necessary encoder(s)!\n";
return 0;
}
}
// run test

View File

@@ -137,10 +137,6 @@ kimageformats_add_plugin(kimg_sct SOURCES sct.cpp)
##################################
kimageformats_add_plugin(kimg_tim SOURCES tim.cpp)
##################################
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp microexif.cpp scanlineconverter.cpp)
##################################

View File

@@ -5,7 +5,6 @@
*/
#include "ani_p.h"
#include "util_p.h"
#include <QImage>
#include <QLoggingCategory>
@@ -102,7 +101,7 @@ bool ANIHandler::read(QImage *outImage)
}
const auto frameSize = *(reinterpret_cast<const quint32_le *>(frameSizeData.data()));
if (!frameSize || frameSize > quint32(kMaxQVectorSize)) {
if (!frameSize) {
return false;
}
@@ -418,9 +417,6 @@ bool ANIHandler::ensureScanned() const
// IART and INAM are technically inside LIST->INFO but "INFO" is supposedly optional
// so just handle those two attributes wherever we encounter them
} else if (chunkId == "INAM" || chunkId == "IART") {
if (chunkSize > kMaxQVectorSize) {
return false;
}
const QByteArray value = device()->read(chunkSize);
if (static_cast<quint32_le>(value.size()) != chunkSize) {

View File

@@ -265,15 +265,9 @@ bool QAVIFHandler::decode_one_frame()
}
}
uint32_t resultdepth = m_decoder->image->depth;
if (m_decoder->image->matrixCoefficients == 16 && m_decoder->image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444 && resultdepth == 10) {
// 10-bit YCgCo-Re AVIF must be decoded to 8bit
resultdepth = 8;
}
QImage::Format resultformat;
if (resultdepth > 8) {
if (m_decoder->image->depth > 8) {
if (loadalpha) {
resultformat = QImage::Format_RGBA64;
} else {
@@ -299,7 +293,9 @@ bool QAVIFHandler::decode_one_frame()
colorspace = QColorSpace::fromIccProfile(icc_data);
if (!colorspace.isValid()) {
qCWarning(LOG_AVIFPLUGIN, "AVIF image has Qt-unsupported or invalid ICC profile!");
} else {
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
else {
if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
qCWarning(LOG_AVIFPLUGIN, "CMYK ICC profile is not extected for AVIF, discarding the ICCprofile!");
colorspace = QColorSpace();
@@ -329,6 +325,7 @@ bool QAVIFHandler::decode_one_frame()
}
}
}
#endif
} else {
float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f};
// outPrimaries: rX, rY, gX, gY, bX, bY, wX, wY
@@ -363,12 +360,14 @@ bool QAVIFHandler::decode_one_frame()
case 13:
q_trc = QColorSpace::TransferFunction::SRgb;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16: /* AVIF_TRANSFER_CHARACTERISTICS_PQ */
q_trc = QColorSpace::TransferFunction::St2084;
break;
case 18: /* AVIF_TRANSFER_CHARACTERISTICS_HLG */
q_trc = QColorSpace::TransferFunction::Hlg;
break;
#endif
default:
qCWarning(LOG_AVIFPLUGIN, "CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
m_decoder->image->colorPrimaries,
@@ -378,9 +377,11 @@ bool QAVIFHandler::decode_one_frame()
}
if (q_trc != QColorSpace::TransferFunction::Custom) { // we create new colorspace using Qt
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
if (loadgray) {
colorspace = QColorSpace(whitePoint, q_trc, q_trc_gamma);
} else {
#endif
switch (m_decoder->image->colorPrimaries) {
/* AVIF_COLOR_PRIMARIES_BT709 */
case 0:
@@ -388,9 +389,6 @@ bool QAVIFHandler::decode_one_frame()
case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */
colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
break;
case 9:
colorspace = QColorSpace(QColorSpace::Primaries::Bt2020, q_trc, q_trc_gamma);
break;
/* AVIF_COLOR_PRIMARIES_SMPTE432 */
case 12:
colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
@@ -399,7 +397,9 @@ bool QAVIFHandler::decode_one_frame()
colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
break;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
}
#endif
}
if (!colorspace.isValid()) {
@@ -414,7 +414,7 @@ bool QAVIFHandler::decode_one_frame()
rgb.maxThreads = m_decoder->maxThreads;
#endif
if (resultdepth > 8) {
if (m_decoder->image->depth > 8) {
rgb.depth = 16;
rgb.format = AVIF_RGB_FORMAT_RGBA;
@@ -513,12 +513,21 @@ bool QAVIFHandler::decode_one_frame()
#else
switch (m_decoder->image->imir.axis) {
#endif
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
case 0: // top-to-bottom
result = result.mirrored(false, true);
break;
case 1: // left-to-right
result = result.mirrored(true, false);
break;
#else
case 0: // top-to-bottom
result = result.flipped(Qt::Vertical);
break;
case 1: // left-to-right
result = result.flipped(Qt::Horizontal);
break;
#endif
}
}
@@ -734,65 +743,22 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_LINEAR */
avif->transferCharacteristics = (avifTransferCharacteristics)8;
break;
case QColorSpace::TransferFunction::Gamma:
if (qAbs(tmpgrayimage.colorSpace().gamma() - 2.2f) < 0.1f) {
/* AVIF_TRANSFER_CHARACTERISTICS_BT470M */
avif->transferCharacteristics = (avifTransferCharacteristics)4;
} else if (qAbs(tmpgrayimage.colorSpace().gamma() - 2.8f) < 0.1f) {
/* AVIF_TRANSFER_CHARACTERISTICS_BT470BG */
avif->transferCharacteristics = (avifTransferCharacteristics)5;
}
break;
case QColorSpace::TransferFunction::SRgb:
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
avif->transferCharacteristics = (avifTransferCharacteristics)13;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084:
avif->transferCharacteristics = (avifTransferCharacteristics)16;
break;
case QColorSpace::TransferFunction::Hlg:
avif->transferCharacteristics = (avifTransferCharacteristics)18;
break;
#endif
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
break;
}
if (avif->transferCharacteristics == 2) { // in case TransferFunction was not identified yet
if (tmpgrayimage.colorSpace().colorModel() == QColorSpace::ColorModel::Gray && lossless) {
avif->colorPrimaries = (avifColorPrimaries)2;
avif->matrixCoefficients = (avifMatrixCoefficients)6;
QByteArray iccprofile_gray = tmpgrayimage.colorSpace().iccProfile();
if (iccprofile_gray.size() > 0) {
#if AVIF_VERSION >= 1000000
res = avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile_gray.constData()), iccprofile_gray.size());
if (res != AVIF_RESULT_OK) {
qCWarning(LOG_AVIFPLUGIN, "ERROR in avifImageSetProfileICC: %s", avifResultToString(res));
return false;
}
#else
avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile_gray.constData()), iccprofile_gray.size());
#endif
}
} else { // convert to grayscale with SRgb
tmpgrayimage.convertToColorSpace(QColorSpace(QPointF(0.3127f, 0.329f), QColorSpace::TransferFunction::SRgb), QImage::Format_Grayscale16);
switch (tmpgrayimage.format()) {
case QImage::Format_Grayscale8:
save_depth = 8;
break;
case QImage::Format_Grayscale16:
save_depth = 10;
avif->transferCharacteristics = (avifTransferCharacteristics)13;
break;
default:
qCWarning(LOG_AVIFPLUGIN, "Error saving Gray image");
return false;
break;
}
}
}
}
if (save_depth > 8) { // QImage::Format_Grayscale16
@@ -833,6 +799,7 @@ bool QAVIFHandler::write(const QImage &image)
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpcolorimage;
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
@@ -847,6 +814,9 @@ bool QAVIFHandler::write(const QImage &image)
} else {
tmpcolorimage = image.convertToFormat(tmpformat);
}
#else
QImage tmpcolorimage = image.convertToFormat(tmpformat);
#endif
avifPixelFormat pixel_format = AVIF_PIXEL_FORMAT_YUV420;
if (m_quality >= KIMG_AVIF_QUALITY_HIGH) {
@@ -877,10 +847,6 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL */
matrix_to_save = (avifMatrixCoefficients)12;
break;
case QColorSpace::Primaries::Bt2020:
primaries_to_save = (avifColorPrimaries)9;
matrix_to_save = (avifMatrixCoefficients)12;
break;
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
primaries_to_save = (avifColorPrimaries)2;
@@ -910,12 +876,14 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
transfer_to_save = (avifTransferCharacteristics)13;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084:
transfer_to_save = (avifTransferCharacteristics)16;
break;
case QColorSpace::TransferFunction::Hlg:
transfer_to_save = (avifTransferCharacteristics)18;
break;
#endif
default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
transfer_to_save = (avifTransferCharacteristics)2;
@@ -951,12 +919,14 @@ bool QAVIFHandler::write(const QImage &image)
case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.8f));
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::St2084));
break;
case 18:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::Hlg));
break;
#endif
default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
transfer_to_save = (avifTransferCharacteristics)13;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2025-2026 Mirco Miranda <mircomir@outlook.com>
SPDX-FileCopyrightText: 2025 Mirco Miranda <mircomir@outlook.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
@@ -10,7 +10,6 @@
* - https://wiki.amigaos.net/wiki/IFF_FORM_and_Chunk_Registry
* - https://www.fileformat.info/format/iff/egff.htm
* - https://download.autodesk.com/us/maya/2010help/index.html (Developer resources -> File formats -> Maya IFF)
* - https://aminet.net/package/dev/misc/IFF-RGFX
*/
#ifndef KIMG_CHUNKS_P_H
@@ -37,7 +36,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
#define LIST_CHUNK QByteArray("LIST")
#define PROP_CHUNK QByteArray("PROP")
// Main chunks (Maya)
// Main chuncks (Maya)
#define CAT4_CHUNK QByteArray("CAT4") // 4 byte alignment
#define FOR4_CHUNK QByteArray("FOR4")
#define LIS4_CHUNK QByteArray("LIS4")
@@ -56,17 +55,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
#define CMAP_CHUNK QByteArray("CMAP")
#define CMYK_CHUNK QByteArray("CMYK") // https://wiki.amigaos.net/wiki/ILBM_IFF_Interleaved_Bitmap#ILBM.CMYK
#define DPI__CHUNK QByteArray("DPI ")
#define IDAT_CHUNK QByteArray("IDAT")
#define IHDR_CHUNK QByteArray("IHDR")
#define IPAR_CHUNK QByteArray("IPAR")
#define PLTE_CHUNK QByteArray("PLTE")
#define RBOD_CHUNK QByteArray("RBOD")
#define RCOL_CHUNK QByteArray("RCOL")
#define RFLG_CHUNK QByteArray("RFLG")
#define RGHD_CHUNK QByteArray("RGHD")
#define RSCM_CHUNK QByteArray("RSCM")
#define XBMI_CHUNK QByteArray("XBMI")
#define YUVS_CHUNK QByteArray("YUVS")
// Different palette for scanline
#define BEAM_CHUNK QByteArray("BEAM")
@@ -90,18 +79,14 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
#define FVER_CHUNK QByteArray("FVER")
#define HIST_CHUNK QByteArray("HIST")
#define NAME_CHUNK QByteArray("NAME")
#define VDAT_CHUNK QByteArray("VDAT")
#define VERS_CHUNK QByteArray("VERS")
#define XMP0_CHUNK QByteArray("XMP0") // https://aminet.net/package/docs/misc/IFF-metadata
// FORM types
#define ACBM_FORM_TYPE QByteArray("ACBM")
#define ILBM_FORM_TYPE QByteArray("ILBM")
#define IMAG_FORM_TYPE QByteArray("IMAG")
#define PBM__FORM_TYPE QByteArray("PBM ")
#define RGB8_FORM_TYPE QByteArray("RGB8")
#define RGBN_FORM_TYPE QByteArray("RGBN")
#define RGFX_FORM_TYPE QByteArray("RGFX")
#define CIMG_FOR4_TYPE QByteArray("CIMG")
#define TBMP_FOR4_TYPE QByteArray("TBMP")
@@ -160,7 +145,7 @@ public:
/*!
* \brief bytes
* \return The size (in bytes) of the chunk data.
* \return The size (in bytes) of the chunck data.
*/
quint32 bytes() const;
@@ -365,12 +350,6 @@ protected:
static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr);
/*!
* \brief dataBytes
* \return Maximum usable cache data size.
*/
quint32 dataBytes() const;
private:
char _chunkId[4];
@@ -439,8 +418,7 @@ public:
enum Compression {
Uncompressed = 0, /**< Image data are uncompressed. */
Rle = 1, /**< Image data are RLE compressed. */
Vdat = 2, /**< Image data are VDAT compressed. */
RgbN8 = 4 /**< Image data are RGB8/RGBN compressed. */
RgbN8 = 4 /**< RGB8/RGBN compresson. */
};
enum Masking {
None = 0, /**< Designates an opaque rectangular image. */
@@ -772,11 +750,10 @@ public:
/*!
* \brief readStride
* \param d The device.
* \param y The current scanline.
* \param header The bitmap header.
* \param y The current scanline.
* \param camg The CAMG chunk (optional)
* \param cmap The CMAP chunk (optional)
* \param ipal The per-line palette chunk (optional)
* \param formType The type of the current form chunk.
* \return The scanline as requested for QImage.
* \warning Call resetStrideRead() once before this one.
@@ -793,6 +770,8 @@ public:
* \brief resetStrideRead
* Reset the stride read set the position at the beginning of the data and reset all buffers.
* \param d The device.
* \param header The BMHDChunk chunk (mandatory)
* \param camg The CAMG chunk (optional)
* \return True on success, otherwise false.
* \sa strideRead
* \note Must be called once before strideRead().
@@ -803,7 +782,6 @@ public:
* \brief safeModeId
* \param header The header.
* \param camg The CAMG chunk.
* \param cmap The CMAP chunk.
* \return The most likely ModeId if not explicitly specified.
*/
static CAMGChunk::ModeIds safeModeId(const BMHDChunk *header, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr);
@@ -824,8 +802,6 @@ protected:
QByteArray rgbN(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
virtual bool innerReadStructure(QIODevice *d) override;
private:
mutable QByteArray _readBuffer;
};
@@ -888,7 +864,7 @@ public:
/*!
* \brief transformation
* \return The image transformation.
* \note The Default implementation returns the transformation of EXIF chunk (if any).
* \note The Default implentation returns the trasformation of EXIF chunk (if any).
*/
virtual QImageIOHandler::Transformation transformation() const;
@@ -939,13 +915,6 @@ public:
protected:
virtual bool innerReadStructure(QIODevice *d) override;
private:
QImage::Format iffFormat() const;
QImage::Format cdiFormat() const;
QImage::Format rgfxFormat() const;
};
@@ -1382,32 +1351,6 @@ protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The VDATChunk class
*/
class VDATChunk : public IFFChunk
{
public:
virtual ~VDATChunk() override;
VDATChunk();
VDATChunk(const VDATChunk& other) = default;
VDATChunk& operator =(const VDATChunk& other) = default;
virtual bool isValid() const override;
CHUNKID_DEFINE(VDAT_CHUNK)
const QByteArray &uncompressedData(const BMHDChunk *header) const;
protected:
virtual bool innerReadStructure(QIODevice *d) override;
private:
mutable QByteArray uncompressed;
};
/*!
* \brief The VERSChunk class
*/
@@ -1451,500 +1394,6 @@ protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* *** I-CD IFF CHUNKS ***
*/
/*!
* \brief The IHDRChunk class
* Image Header
*/
class IHDRChunk: public IFFChunk
{
public:
enum Model {
Invalid = 0, /**< Invalid model. */
Rgb888 = 1, /**< red, green, blue - 8 bits per color. */
Rgb555 = 2, /**< Green Book absolute RGB. */
DYuv = 3, /**< Green Book Delta YUV. */
CLut8 = 4, /**< Green Book 8 bit CLUT. */
CLut7 = 5, /**< Green Book 7 bit CLUT. */
CLut4 = 6, /**< Green Book 4 bit CLUT. */
CLut3 = 7, /**< Green Book 3 bit CLUT. */
Rle7 = 8, /**< Green Book runlength coded 7 bit CLUT. */
Rle3 = 9, /**< Green Book runlength coded 3 bit CLUT. */
PaletteOnly = 10 /**< color palette only. */
};
enum DYuvKind {
One = 0,
Each = 1
};
struct Yuv {
Yuv(quint8 y0 = 0, quint8 u0 = 0, quint8 v0 = 0) : y(y0), u(u0), v(v0) {}
quint8 y;
quint8 u;
quint8 v;
};
virtual ~IHDRChunk() override;
IHDRChunk();
IHDRChunk(const IHDRChunk& other) = default;
IHDRChunk& operator =(const IHDRChunk& other) = default;
virtual bool isValid() const override;
/*!
* \brief width
* \return Width of the bitmap in pixels.
*/
qint32 width() const;
/*!
* \brief height
* \return Height of the bitmap in pixels.
*/
qint32 height() const;
/*!
* \brief size
* \return Size in pixels.
*/
QSize size() const;
/*!
* \brief lineSize
* Physical width of image (number of bytes in each scan line, including any data required at
* the end of each scan line for padding [see description of each models IDAT chunk for padding
* rules]) This field is not used when model() = Rle7 or Rle3.
* When model() = Rgb555, this field defines the size of one scan line of the upper
* or lower portion of the pixel data, but not the size of them both together.
*/
qint32 lineSize() const;
/*!
* \brief model
* Image model (coding method)
*/
Model model() const;
/*!
* \brief depth
* Physical size of pixel (number of bits per pixel used in storing image data) When
* model() = Rle7 or Rle3, this value only represents the size of a
* single pixel; the size of a run of pixels is indeterminate.
*/
quint16 depth() const;
/*!
* \brief yuvKind
* if model() = DYuv, indicates whether there is one DYUV start value for all
* scan lines (in yuvStart()), or whether each scan line has its own start value in the
* YUVS chunk which follows.
*/
DYuvKind yuvKind() const;
/*!
* \brief yuvStart
* Start values for DYUV image if model() = DYuv and dYuvKind() = One
*/
Yuv yuvStart() const;
CHUNKID_DEFINE(IHDR_CHUNK)
protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The IHDRChunk class
*/
class IPARChunk: public IFFChunk
{
public:
struct Rgb {
Rgb(quint8 r0 = 0, quint8 g0 = 0, quint8 b0 = 0) : r(r0), g(g0), b(b0) {}
quint8 r;
quint8 g;
quint8 b;
};
virtual ~IPARChunk() override;
IPARChunk();
IPARChunk(const IPARChunk& other) = default;
IPARChunk& operator =(const IPARChunk& other) = default;
virtual bool isValid() const override;
/*!
* \brief xOffset
* X offset of origin in source image [0 < xOffset() < xPage()]
*/
qint32 xOffset() const;
/*!
* \brief yOffset
* \returnX offset of origin in source image [0 < yOffset() < yPage()]
*/
qint32 yOffset() const;
/*!
* \brief aspectRatio
* Aspect ratio of pixels in source image.
*/
double aspectRatio() const;
/*!
* \brief xPage
* X size of source image.
*/
qint32 xPage() const;
/*!
* \brief yPage
* Y size of source image.
*/
qint32 yPage() const;
/*!
* \brief xGrub
* X location of hot spot within image.
*/
qint32 xGrub() const;
/*!
* \brief yGrub
* Y location of hot spot within image.
*/
qint32 yGrub() const;
/*!
* \brief transparency
* Transparent color.
*/
Rgb transparency() const;
/*!
* \brief mask
* Mask color.
*/
Rgb mask() const;
CHUNKID_DEFINE(IPAR_CHUNK)
protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The PLTEChunk class
*/
class PLTEChunk : public CMAPChunk
{
public:
virtual ~PLTEChunk() override;
PLTEChunk();
PLTEChunk(const PLTEChunk& other) = default;
PLTEChunk& operator =(const PLTEChunk& other) = default;
virtual bool isValid() const override;
/*!
* \brief count
* \return The number of color in the palette.
*/
virtual qint32 count() const override;
CHUNKID_DEFINE(PLTE_CHUNK)
protected:
qint32 offset() const;
qint32 total() const;
virtual QList<QRgb> innerPalette() const override;
};
/*!
* \brief The YUVSChunk class
*/
class YUVSChunk : public IFFChunk
{
public:
virtual ~YUVSChunk() override;
YUVSChunk();
YUVSChunk(const YUVSChunk& other) = default;
YUVSChunk& operator =(const YUVSChunk& other) = default;
virtual bool isValid() const override;
qint32 count() const;
IHDRChunk::Yuv yuvStart(qint32 y) const;
CHUNKID_DEFINE(YUVS_CHUNK)
protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The IDATChunk class
*/
class IDATChunk : public IFFChunk
{
public:
virtual ~IDATChunk() override;
IDATChunk();
IDATChunk(const IDATChunk& other) = default;
IDATChunk& operator =(const IDATChunk& other) = default;
virtual bool isValid() const override;
CHUNKID_DEFINE(IDAT_CHUNK)
/*!
* \brief readStride
* \param d The device.
* \param y The current scanline.
* \param header The bitmap header.
* \param params The additional parameters (optional)
* \return The scanline as requested for QImage.
* \warning Call resetStrideRead() once before this one.
*/
QByteArray strideRead(QIODevice *d,
qint32 y,
const IHDRChunk *header,
const IPARChunk *params = nullptr,
const YUVSChunk *yuvs = nullptr) const;
/*!
* \brief resetStrideRead
* Reset the stride read set the position at the beginning of the data and reset all buffers.
* \param d The device.
* \return True on success, otherwise false.
* \sa strideRead
* \note Must be called once before strideRead().
*/
bool resetStrideRead(QIODevice *d) const;
protected:
quint32 strideSize(const IHDRChunk *header) const;
};
/*!
* *** RGFX IFF CHUNKS ***
*/
/*!
* \brief The RGHDChunk class
*/
class RGHDChunk : public IFFChunk
{
public:
enum Compression {
Uncompressed = 0,
Xpk = 1, /**< any XPK-packer */
Zip = 2 /**< libzip (LZ77/ZIP) compression */
};
enum BitmapType {
Planar8 = 0x0000, /**< unaligned planar 8 bit bitmap */
Chunky8 = 0x0001, /**< unaligned chunky 8 bit bitmap */
Rgb24 = 0x0002, /**< 3-byte 24 bit RGB triples */
Rgb32 = 0x0004, /**< 4-byte 32 bit ARGB quadruples */
Rgb15 = 0x0010, /**< 2-byte 15 bit RGB (x+3x5 bit integer) */
Rgb16 = 0x0020, /**< 2-byte 16 bit ARGB (1+3x5 bit integer) */
Rgb48 = 0x0040, /**< 6-byte 48 bit RGB (3x 16 bit integer) */
Rgb64 = 0x0080, /**< 8-byte 64 bit ARGB (4x 16 bit integer) */
Rgb96 = 0x0100, /**< 12-byte 96 bit RGB (3x 32 bit float) */
Rgb128 = 0x0200, /**< 16-byte 128 bit ARGB (4x 32 bit float) */
HasAlpha = (1 << 30), /**< set if A is meaningful */
HasInvAlpha = (1 << 31) /**< set if A is meaningful but inversed (A = 255 - alpha) */
};
Q_DECLARE_FLAGS(BitmapTypes, BitmapType)
virtual ~RGHDChunk() override;
RGHDChunk();
RGHDChunk(const RGHDChunk&) = default;
RGHDChunk& operator=(const RGHDChunk&) = default;
CHUNKID_DEFINE(RGHD_CHUNK)
virtual bool isValid() const override;
QSize size() const;
qint32 leftEdge() const;
qint32 topEdge() const;
qint32 width() const;
qint32 height() const;
qint32 pageWidth() const;
qint32 pageHeight() const;
quint32 depth() const;
quint32 pixelBits() const;
quint32 bytesPerLine() const;
Compression compression() const;
quint32 xAspect() const;
quint32 yAspect() const;
BitmapTypes bitmapType() const;
double aspectRatio() const;
protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The RCOLChunk class
*/
class RCOLChunk : public CMAPChunk
{
public:
virtual ~RCOLChunk() override;
RCOLChunk();
RCOLChunk(const RCOLChunk& other) = default;
RCOLChunk& operator =(const RCOLChunk& other) = default;
virtual bool isValid() const override;
virtual qint32 count() const override;
CHUNKID_DEFINE(RCOL_CHUNK)
protected:
virtual QList<QRgb> innerPalette() const override;
};
/*!
* \brief The RFLGChunk class
*/
class RFLGChunk : public IFFChunk
{
public:
enum class Flag : quint32 {
FromGray = 0x08, /**< created from 8/16 bit gray source so R==G==B */
From8Bit = 0x10, /**< created from 8 bit source, so (R,G,B)&0xFF00 == ... & 0x00FF */
From4Bit = 0x20, /**< created from 4 bit source, so (R,G,B)&0xF0 == ... & 0x0F */
From8BitAlpha = 0x40, /**< 16/32 bit alpha created from 8 bit alpha source */
From16BitAlpha = 0x80 /**< 32 bit alpha created from 16 bit alpha source */
};
Q_DECLARE_FLAGS(Flags, Flag)
virtual ~RFLGChunk() override;
RFLGChunk();
RFLGChunk(const RFLGChunk&) = default;
RFLGChunk& operator=(const RFLGChunk&) = default;
CHUNKID_DEFINE(RFLG_CHUNK)
virtual bool isValid() const override;
Flags flags() const;
protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The RSCMChunk class
*/
class RSCMChunk : public IFFChunk
{
public:
virtual ~RSCMChunk() override;
RSCMChunk();
RSCMChunk(const RSCMChunk&) = default;
RSCMChunk& operator=(const RSCMChunk&) = default;
CHUNKID_DEFINE(RSCM_CHUNK)
virtual bool isValid() const override;
/*!
* \brief viewMode Default screenmode
*
* Since HAM modes only can be identified by their ID (or DIPF) you have to make sure,
* that rcsm_ViewMode is OR'ed with HAM_KEY for these (same for EHB and EXTRAHALFBRITE_KEY).
*
* Specific RTG ViewModes will lose their meaning, as soon as graphics are transferred between
* different systems, which is why the two LocalVM entries are considered obsolete.
*
* Always set the obsolete entries to 0xFFFFFFFF and avoid interpreting them.
* \return default screenmode
*/
quint32 viewMode() const;
/*!
* \brief localVM0
* \obsolete obsolete local RTG
*/
quint32 localVM0() const;
/*!
* \brief localVM1
* \obsolete obsolete local RTG
*/
quint32 localVM1() const;
protected:
virtual bool innerReadStructure(QIODevice *d) override;
};
/*!
* \brief The RBODChunk class
*/
class RBODChunk : public IFFChunk
{
public:
virtual ~RBODChunk() override;
RBODChunk();
RBODChunk(const RBODChunk&) = default;
RBODChunk& operator=(const RBODChunk&) = default;
CHUNKID_DEFINE(RBOD_CHUNK)
virtual bool isValid() const override;
QByteArray strideRead(QIODevice *d,
qint32 y,
const RGHDChunk *header,
const RSCMChunk *rcsm = nullptr,
const RCOLChunk *rcol = nullptr) const;
bool resetStrideRead(QIODevice *d) const;
private:
QByteArray deinterleave(const QByteArray &planes, qint32 y, const RGHDChunk *header, const RSCMChunk *rcsm = nullptr, const RCOLChunk *rcol = nullptr) const;
quint32 strideSize(const RGHDChunk *header) const;
};
/*!
* *** UNDOCUMENTED CHUNKS ***

View File

@@ -20,7 +20,7 @@
#include <cmath>
#ifndef DDS_DISABLE_STRIDE_ALIGNMENT
// Disable the stride alignment based on DDS pitch: it is known that some writers do not set it correctly
// Disable the stride aligment based on DDS pitch: it is known that some writers do not set it correctly
// #define DDS_DISABLE_STRIDE_ALIGNMENT
#endif
@@ -2120,8 +2120,10 @@ bool writeL8(const QImage &outImage, QDataStream &s)
}
ScanLineConverter slc(QImage::Format_Grayscale8);
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if(outImage.colorSpace().isValid())
slc.setTargetColorSpace(QColorSpace(QPointF(0.3127, 0.3291), QColorSpace::TransferFunction::SRgb));
#endif
for (int y = 0, h = outImage.height(); y < h; ++y) {
const quint8 *scanLine = reinterpret_cast<const quint8*>(slc.convertedScanLine(outImage, y));

View File

@@ -179,7 +179,7 @@ bool EPSHandler::read(QImage *image)
const QString gsExec = QStandardPaths::findExecutable(QStringLiteral("gs"));
if (gsExec.isEmpty()) {
qCWarning(EPSPLUGIN) << "Couldn't find gs executable (from GhostScript) in PATH.";
qCWarning(EPSPLUGIN) << "Couldn't find gs exectuable (from GhostScript) in PATH.";
return false;
}

View File

@@ -404,7 +404,6 @@ bool EXRHandler::read(QImage *outImage)
Imf::Array2D<Imf::Rgba> pixels;
pixels.resizeErase(EXR_LINES_PER_BLOCK, width);
std::memset(pixels[0], 0, sizeof(Imf::Rgba) * EXR_LINES_PER_BLOCK * width);
bool isRgba = image.hasAlphaChannel();
for (int y = 0, n = 0; y < height; y += n) {
@@ -609,13 +608,13 @@ bool EXRHandler::write(const QImage &image)
pixels.resizeErase(EXR_LINES_PER_BLOCK, width);
// convert the image and write into the stream
auto convFormat = image.hasAlphaChannel() ? QImage::Format_RGBA32FPx4 : QImage::Format_RGBX32FPx4;
auto convFormat = image.hasAlphaChannel() ? QImage::Format_RGBA16FPx4 : QImage::Format_RGBX16FPx4;
ScanLineConverter slc(convFormat);
slc.setDefaultSourceColorSpace(QColorSpace(QColorSpace::SRgb));
slc.setTargetColorSpace(QColorSpace(QColorSpace::SRgbLinear));
for (int y = 0, n = 0; y < height; y += n) {
for (n = 0; n < std::min(EXR_LINES_PER_BLOCK, height - y); ++n) {
auto scanLine = reinterpret_cast<const float *>(slc.convertedScanLine(image, y + n));
auto scanLine = reinterpret_cast<const qfloat16 *>(slc.convertedScanLine(image, y + n));
if (scanLine == nullptr) {
return false;
}

View File

@@ -125,16 +125,14 @@ public:
Header h;
int cnt = 0;
int len = 0;
QByteArray line(MAXLINE, char());
int len;
QByteArray line(MAXLINE + 1, Qt::Uninitialized);
QByteArray format;
// Parse header
do {
len = device->readLine(line.data(), line.size());
if (len < 0) {
break;
}
len = device->readLine(line.data(), MAXLINE);
if (line.startsWith("FORMAT=")) {
format = line.mid(7, len - 7).trimmed();
}
@@ -175,11 +173,7 @@ public:
return h;
}
len = device->readLine(line.data(), line.size());
if (len < 0) {
qCDebug(HDRPLUGIN) << "Invalid HDR file, error while reading the first line after the header";
return h;
}
len = device->readLine(line.data(), MAXLINE);
line.resize(len);
/*
@@ -328,7 +322,8 @@ static bool LoadHDR(QDataStream &s, const Header& h, QImage &img)
return false;
}
QByteArray lineArray(4 * width, char());
QByteArray lineArray;
lineArray.resize(4 * width);
uchar *image = reinterpret_cast<uchar *>(lineArray.data());
for (int cline = 0; cline < height; cline++) {
@@ -514,7 +509,7 @@ bool HDRHandler::canRead(QIODevice *device)
return true;
}
// allow to load official test cases: https://radsite.lbl.gov/radiance/framed.html
// allow to load offical test cases: https://radsite.lbl.gov/radiance/framed.html
device->startTransaction();
auto h = HDRHandlerPrivate::readHeader(device);
device->rollbackTransaction();

View File

@@ -189,6 +189,7 @@ bool HEIFHandler::write_helper(const QImage &image)
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpimage;
auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
@@ -204,6 +205,9 @@ bool HEIFHandler::write_helper(const QImage &image)
} else {
tmpimage = image.convertToFormat(tmpformat);
}
#else
QImage tmpimage = image.convertToFormat(tmpformat);
#endif
struct heif_context *context = heif_context_alloc();
struct heif_error err;
@@ -864,7 +868,9 @@ bool HEIFHandler::ensureDecoder()
QColorSpace colorspace = QColorSpace::fromIccProfile(ba);
if (!colorspace.isValid()) {
qCWarning(LOG_HEIFPLUGIN) << "HEIC image has Qt-unsupported or invalid ICC profile!";
} else if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
else if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
qCWarning(LOG_HEIFPLUGIN) << "CMYK ICC profile is not expected for HEIF, discarding the ICCprofile!";
colorspace = QColorSpace();
} else if (colorspace.colorModel() == QColorSpace::ColorModel::Gray) {
@@ -891,6 +897,7 @@ bool HEIFHandler::ensureDecoder()
m_current_image.convertTo(bit_depth > 8 ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
}
}
#endif
m_current_image.setColorSpace(colorspace);
}
} else {
@@ -927,12 +934,14 @@ bool HEIFHandler::ensureDecoder()
case 13:
q_trc = QColorSpace::TransferFunction::SRgb;
break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16:
q_trc = QColorSpace::TransferFunction::St2084;
break;
case 18:
q_trc = QColorSpace::TransferFunction::Hlg;
break;
#endif
default:
qCWarning(LOG_HEIFPLUGIN) << "CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet."
<< nclx->color_primaries

View File

@@ -262,26 +262,14 @@ static void addMetadata(QImage &img, const IFOR_Chunk *form)
// if no explicit resolution was found, apply the aspect ratio to the default one
if (!resChanged) {
if (form->formType() == IMAG_FORM_TYPE) {
auto params = IFFChunk::searchT<IPARChunk>(form);
if (!params.isEmpty()) {
img.setDotsPerMeterY(img.dotsPerMeterY() * params.first()->aspectRatio());
}
} else if (form->formType() == RGFX_FORM_TYPE) {
auto headers = IFFChunk::searchT<RGHDChunk>(form);
if (!headers.isEmpty()) {
img.setDotsPerMeterY(img.dotsPerMeterY() * headers.first()->aspectRatio());
}
} else {
auto headers = IFFChunk::searchT<BMHDChunk>(form);
if (!headers.isEmpty()) {
auto xr = headers.first()->xAspectRatio();
auto yr = headers.first()->yAspectRatio();
if (xr > 0 && yr > 0 && xr > yr) {
img.setDotsPerMeterX(img.dotsPerMeterX() * yr / xr);
} else if (xr > 0 && yr > 0 && xr < yr) {
img.setDotsPerMeterY(img.dotsPerMeterY() * xr / yr);
}
auto headers = IFFChunk::searchT<BMHDChunk>(form);
if (!headers.isEmpty()) {
auto xr = headers.first()->xAspectRatio();
auto yr = headers.first()->yAspectRatio();
if (xr > 0 && yr > 0 && xr > yr) {
img.setDotsPerMeterX(img.dotsPerMeterX() * yr / xr);
} else if (xr > 0 && yr > 0 && xr < yr) {
img.setDotsPerMeterY(img.dotsPerMeterY() * xr / yr);
}
}
}
@@ -339,6 +327,7 @@ bool IFFHandler::readStandardImage(QImage *image)
// show the first one (I don't have a sample with many images)
auto headers = IFFChunk::searchT<BMHDChunk>(form);
if (headers.isEmpty()) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage(): no supported image found";
return false;
}
@@ -437,6 +426,7 @@ bool IFFHandler::readMayaImage(QImage *image)
// show the first one (I don't have a sample with many images)
auto headers = IFFChunk::searchT<TBHDChunk>(form);
if (headers.isEmpty()) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readMayaImage(): no supported image found";
return false;
}
@@ -474,133 +464,11 @@ bool IFFHandler::readMayaImage(QImage *image)
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawImage(tp, ti);
}
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
img.mirror(false, true);
#else
img.flip(Qt::Orientation::Vertical);
addMetadata(img, form);
*image = img;
return true;
}
bool IFFHandler::readCDIImage(QImage *image)
{
auto forms = d->searchForms<FORMChunk>();
if (forms.isEmpty()) {
return false;
}
auto cin = qBound(0, currentImageNumber(), int(forms.size() - 1));
auto &&form = forms.at(cin);
// show the first one (I don't have a sample with many images)
auto headers = IFFChunk::searchT<IHDRChunk>(form);
if (headers.isEmpty()) {
return false;
}
// create the image
auto &&header = headers.first();
auto img = imageAlloc(header->size(), form->format());
if (img.isNull()) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while allocating the image";
return false;
}
// set the palette
if (img.format() == QImage::Format_Indexed8) {
auto pltes = IFFChunk::searchT<PLTEChunk>(form);
if (!pltes.isEmpty()) {
img.setColorTable(pltes.first()->palette());
}
}
// decoding the image
auto bodies = IFFChunk::searchT<IDATChunk>(form);
if (bodies.isEmpty()) {
img.fill(0);
} else {
auto &&body = bodies.first();
if (!body->resetStrideRead(device())) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while reading image data";
return false;
}
auto pars = IFFChunk::searchT<IPARChunk>(form);
auto yuvs = IFFChunk::searchT<YUVSChunk>(form);
for (auto y = 0, h = img.height(); y < h; ++y) {
auto line = reinterpret_cast<char*>(img.scanLine(y));
auto ba = body->strideRead(device(), y, header,
pars.isEmpty() ? nullptr : pars.first(),
yuvs.isEmpty() ? nullptr : yuvs.first());
if (ba.isEmpty()) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while reading image scanline";
return false;
}
memcpy(line, ba.constData(), std::min(img.bytesPerLine(), ba.size()));
}
}
// set metadata (including image resolution)
addMetadata(img, form);
*image = img;
return true;
}
bool IFFHandler::readRGFXImage(QImage *image)
{
auto forms = d->searchForms<FORMChunk>();
if (forms.isEmpty()) {
return false;
}
auto cin = qBound(0, currentImageNumber(), int(forms.size() - 1));
auto &&form = forms.at(cin);
// show the first one (I don't have a sample with many images)
auto headers = IFFChunk::searchT<RGHDChunk>(form);
if (headers.isEmpty()) {
return false;
}
// create the image
auto &&header = headers.first();
auto img = imageAlloc(header->size(), form->format());
if (img.isNull()) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readRGFXImage(): error while allocating the image";
return false;
}
// set the palette
if (img.format() == QImage::Format_Indexed8) {
auto pltes = IFFChunk::searchT<RCOLChunk>(form);
if (!pltes.isEmpty()) {
img.setColorTable(pltes.first()->palette());
}
}
// decoding the image
auto bodies = IFFChunk::searchT<RBODChunk>(form);
if (bodies.isEmpty()) {
img.fill(0);
} else {
auto &&body = bodies.first();
if (!body->resetStrideRead(device())) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readRGFXImage(): error while reading image data";
return false;
}
auto rcsms = IFFChunk::searchT<RSCMChunk>(form);
auto rcols = IFFChunk::searchT<RCOLChunk>(form);
for (auto y = 0, h = img.height(); y < h; ++y) {
auto line = reinterpret_cast<char*>(img.scanLine(y));
auto ba = body->strideRead(device(), y, header,
rcsms.isEmpty() ? nullptr : rcsms.first(),
rcols.isEmpty() ? nullptr : rcols.first());
if (ba.isEmpty()) {
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readRGFXImage(): error while reading image scanline";
return false;
}
memcpy(line, ba.constData(), std::min(img.bytesPerLine(), ba.size()));
}
}
// set metadata (including image resolution)
#endif
addMetadata(img, form);
*image = img;
@@ -622,14 +490,6 @@ bool IFFHandler::read(QImage *image)
return true;
}
if (readCDIImage(image)) {
return true;
}
if (readRGFXImage(image)) {
return true;
}
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::read(): no supported image found";
return false;
}

View File

@@ -35,10 +35,6 @@ private:
bool readMayaImage(QImage *image);
bool readCDIImage(QImage *image);
bool readRGFXImage(QImage *image);
private:
const QScopedPointer<IFFHandlerPrivate> d;
};

View File

@@ -73,7 +73,7 @@ static void info_callback(const char *msg, void *client_data)
static OPJ_SIZE_T jp2_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
{
auto dev = (QIODevice*)p_user_data;
if (dev == nullptr || dev->atEnd()) {
if (dev == nullptr) {
return OPJ_SIZE_T(-1);
}
return OPJ_SIZE_T(dev->read((char*)p_buffer, (qint64)p_nb_bytes));
@@ -253,27 +253,20 @@ public:
bool jp2ToImage(QImage *img) const
{
Q_ASSERT(img->depth() == 8 * sizeof(T) || img->depth() == 32 * sizeof(T));
if (img->width() < 1 || img->height() < 1) {
return false;
}
auto maxChannels = qint32(img->bytesPerLine() / sizeof(T) / img->width());
for (qint32 c = 0, cc = std::min(qint32(m_jp2_image->numcomps), maxChannels); c < cc; ++c) {
auto cs = std::min(cc == 1 ? 1 : 4, maxChannels);
for (qint32 c = 0, cc = m_jp2_image->numcomps; c < cc; ++c) {
auto cs = cc == 1 ? 1 : 4;
auto &&jc = m_jp2_image->comps[c];
if (jc.data == nullptr) {
if (jc.data == nullptr)
return false;
}
if (qint32(jc.w) != img->width() || qint32(jc.h) != img->height()) {
if (qint32(jc.w) != img->width() || qint32(jc.h) != img->height())
return false;
}
// discriminate between int and float (avoid complicating things by creating classes with template specializations)
if (std::numeric_limits<T>::is_integer) {
auto divisor = 1ull;
auto prec = std::min(size_t(jc.prec), sizeof(*jc.data) * 8);
if (prec > sizeof(T) * 8 && prec < 64) {
auto divisor = 1;
if (jc.prec > sizeof(T) * 8) {
// convert to the wanted precision (e.g. 16-bit -> 8-bit: divisor = 65535 / 255 = 257)
divisor = std::max(1ull, (((1ull << prec) - 1) / ((1ull << (sizeof(T) * 8)) - 1)));
divisor = std::max(1, int(((1ll << jc.prec) - 1) / ((1ll << (sizeof(T) * 8)) - 1)));
}
for (qint32 y = 0, h = img->height(); y < h; ++y) {
auto ptr = reinterpret_cast<T *>(img->scanLine(y));
@@ -359,15 +352,11 @@ public:
}
// OpenJPEG uses a shadow copy @32-bit/channel so we need to do a check
const int allocationLimit = QImageReader::allocationLimit();
if (allocationLimit > 0) {
auto maxBytes = qint64(allocationLimit) * 1024 * 1024;
auto neededBytes = qint64(width) * height * nchannels * 4;
if (maxBytes > 0 && neededBytes > maxBytes) {
qCCritical(LOG_JP2PLUGIN) << "Allocation limit set to" << (maxBytes / 1024 / 1024) << "MiB but" << (neededBytes / 1024 / 1024)
<< "MiB are needed!";
return false;
}
auto maxBytes = qint64(QImageReader::allocationLimit()) * 1024 * 1024;
auto neededBytes = qint64(width) * height * nchannels * 4;
if (maxBytes > 0 && neededBytes > maxBytes) {
qCCritical(LOG_JP2PLUGIN) << "Allocation limit set to" << (maxBytes / 1024 / 1024) << "MiB but" << (neededBytes / 1024 / 1024) << "MiB are needed!";
return false;
}
return true;
@@ -402,6 +391,7 @@ public:
prec = 0;
}
auto jp2cs = m_jp2_image->color_space;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (jp2cs == OPJ_CLRSPC_UNKNOWN || jp2cs == OPJ_CLRSPC_UNSPECIFIED) {
auto cs = colorSpace();
if (cs.colorModel() == QColorSpace::ColorModel::Cmyk)
@@ -411,6 +401,7 @@ public:
else if (cs.colorModel() == QColorSpace::ColorModel::Gray)
jp2cs = OPJ_CLRSPC_GRAY;
}
#endif
if (jp2cs == OPJ_CLRSPC_UNKNOWN || jp2cs == OPJ_CLRSPC_UNSPECIFIED) {
if (m_jp2_image->numcomps == 1)
jp2cs = OPJ_CLRSPC_GRAY;
@@ -440,8 +431,10 @@ public:
}
} else if (jp2cs == OPJ_CLRSPC_CMYK) {
if (m_jp2_image->numcomps == 4) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (prec == 8 || prec == 16)
fmt = QImage::Format_CMYK8888;
#endif
}
}
}
@@ -586,6 +579,7 @@ public:
prec = 16;
convFormat = QImage::Format_RGBA64;
break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888: // requires OpenJPEG 2.5.3+
if (opjVersion() >= QT_VERSION_CHECK(2, 5, 3)) {
ncomp = 4;
@@ -594,6 +588,7 @@ public:
} else {
Q_FALLTHROUGH();
}
#endif
default:
if (image.depth() > 32) {
qCWarning(LOG_JP2PLUGIN) << "The image is saved losing precision!";

View File

@@ -26,9 +26,13 @@ Q_LOGGING_CATEGORY(LOG_JXLPLUGIN, "kf.imageformats.plugins.jxl", QtDebugMsg)
Q_LOGGING_CATEGORY(LOG_JXLPLUGIN, "kf.imageformats.plugins.jxl", QtWarningMsg)
#endif
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 3)
#ifndef JXL_QT_AUTOTRANSFORM
#define JXL_QT_AUTOTRANSFORM
#endif
#endif
#ifndef JXL_HDR_PRESERVATION_DISABLED
// Define JXL_HDR_PRESERVATION_DISABLED to disable HDR preservation
@@ -180,7 +184,7 @@ bool QJpegXLHandler::ensureDecoder()
int num_worker_threads = QThread::idealThreadCount();
if (!m_runner && num_worker_threads >= 4) {
/* use half of the threads because plug-in is usually used in environment
* where application performs other tasks in the background (pre-load other images) */
* where application performs another tasks in backround (pre-load other images) */
num_worker_threads = num_worker_threads / 2;
num_worker_threads = qBound(2, num_worker_threads, 64);
m_runner = JxlThreadParallelRunnerCreate(nullptr, num_worker_threads);
@@ -258,16 +262,14 @@ bool QJpegXLHandler::countALLFrames()
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
JxlColorEncoding color_encoding;
if (m_basicinfo.uses_original_profile == JXL_FALSE && m_basicinfo.have_animation == JXL_FALSE) {
if (!is_gray) {
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
if (jxlcms) {
status = JxlDecoderSetCms(m_decoder, *jxlcms);
if (status != JXL_DEC_SUCCESS) {
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
}
} else {
qCWarning(LOG_JXLPLUGIN, "No JPEG XL CMS Interface");
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
if (jxlcms) {
status = JxlDecoderSetCms(m_decoder, *jxlcms);
if (status != JXL_DEC_SUCCESS) {
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
}
} else {
qCWarning(LOG_JXLPLUGIN, "No JPEG XL CMS Interface");
}
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
@@ -412,6 +414,7 @@ bool QJpegXLHandler::countALLFrames()
m_framedelays[0] = 0;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
// CMYK detection
if ((m_basicinfo.uses_original_profile == JXL_TRUE) && (m_basicinfo.num_color_channels == 3) && (m_colorspace.isValid())) {
bool alpha_found = false;
@@ -468,6 +471,7 @@ bool QJpegXLHandler::countALLFrames()
qCWarning(LOG_JXLPLUGIN, "JXL has CMYK colorspace but BLACK channel was not found!");
}
}
#endif
#ifndef JXL_DECODE_BOXES_DISABLED
if (!decodeContainer()) {
@@ -494,6 +498,7 @@ bool QJpegXLHandler::decode_one_frame()
}
if (m_isCMYK) { // CMYK decoding
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
uchar *pixels_cmy = nullptr;
uchar *pixels_black = nullptr;
@@ -734,6 +739,11 @@ bool QJpegXLHandler::decode_one_frame()
free(pixels_cmy);
pixels_cmy = nullptr;
}
#else
// CMYK not supported in older Qt
m_parseState = ParseJpegXLError;
return false;
#endif
} else { // RGB or GRAY
m_current_image = imageAlloc(m_basicinfo.xsize, m_basicinfo.ysize, m_input_image_format);
if (m_current_image.isNull()) {
@@ -855,11 +865,7 @@ bool QJpegXLHandler::write(const QImage &image)
size_t pixel_count = size_t(image.width()) * image.height();
if (MAX_IMAGE_PIXELS && pixel_count > MAX_IMAGE_PIXELS) {
qCWarning(LOG_JXLPLUGIN,
"Image (%dx%d) will not be saved because it has more than %d megapixels!",
image.width(),
image.height(),
MAX_IMAGE_PIXELS / 1024 / 1024);
qCWarning(LOG_JXLPLUGIN, "Image (%dx%d) will not be saved because it has more than %d megapixels!", image.width(), image.height(), MAX_IMAGE_PIXELS / 1024 / 1024);
return false;
}
@@ -915,9 +921,11 @@ bool QJpegXLHandler::write(const QImage &image)
}
bool save_cmyk = false;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (image.format() == QImage::Format_CMYK8888 && image.colorSpace().isValid() && image.colorSpace().colorModel() == QColorSpace::ColorModel::Cmyk) {
save_cmyk = true;
}
#endif
JxlEncoderStatus status;
JxlPixelFormat pixel_format;
@@ -928,6 +936,7 @@ bool QJpegXLHandler::write(const QImage &image)
auto xmp_data = image.text(QStringLiteral(META_KEY_XMP_ADOBE)).toUtf8();
if (save_cmyk) { // CMYK is always lossless
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
output_info.uses_original_profile = JXL_TRUE;
output_info.xsize = image.width();
output_info.ysize = image.height();
@@ -1100,6 +1109,13 @@ bool QJpegXLHandler::write(const QImage &image)
JxlEncoderDestroy(encoder);
return false;
}
#else
if (runner) {
JxlThreadParallelRunnerDestroy(runner);
}
JxlEncoderDestroy(encoder);
return false;
#endif
} else { // RGB or GRAY saving
int save_depth = 8; // 8 / 16 / 32
bool save_fp = false;
@@ -1138,7 +1154,9 @@ bool QJpegXLHandler::write(const QImage &image)
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888:
#endif
save_depth = 8;
break;
case QImage::Format_Grayscale16:
@@ -1233,6 +1251,7 @@ bool QJpegXLHandler::write(const QImage &image)
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpimage;
if (image.colorSpace().isValid()) {
if (is_gray && image.colorSpace().colorModel() != QColorSpace::ColorModel::Gray) {
@@ -1285,6 +1304,9 @@ bool QJpegXLHandler::write(const QImage &image)
} else { // no ColorSpace or invalid
tmpimage = image.convertToFormat(tmpformat);
}
#else
QImage tmpimage = image.convertToFormat(tmpformat);
#endif
output_info.xsize = tmpimage.width();
output_info.ysize = tmpimage.height();
@@ -1310,7 +1332,10 @@ bool QJpegXLHandler::write(const QImage &image)
output_info.uses_original_profile = JXL_FALSE;
if (tmpimage.colorSpace().isValid()) {
const QPointF whiteP = image.colorSpace().whitePoint();
QPointF whiteP(0.3127f, 0.329f);
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
whiteP = image.colorSpace().whitePoint();
#endif
switch (tmpimage.colorSpace().primaries()) {
case QColorSpace::Primaries::SRgb:
@@ -1339,6 +1364,9 @@ bool QJpegXLHandler::write(const QImage &image)
break;
case QColorSpace::Primaries::ProPhotoRgb:
color_profile.white_point = JXL_WHITE_POINT_CUSTOM;
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
whiteP = QPointF(0.3457f, 0.3585f);
#endif
color_profile.white_point_xy[0] = whiteP.x();
color_profile.white_point_xy[1] = whiteP.y();
color_profile.primaries = JXL_PRIMARIES_CUSTOM;
@@ -1349,6 +1377,7 @@ bool QJpegXLHandler::write(const QImage &image)
color_profile.primaries_blue_xy[0] = 0.0366;
color_profile.primaries_blue_xy[1] = 0.0001;
break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QColorSpace::Primaries::Bt2020:
color_profile.white_point = JXL_WHITE_POINT_D65;
color_profile.primaries = JXL_PRIMARIES_2100;
@@ -1359,6 +1388,7 @@ bool QJpegXLHandler::write(const QImage &image)
color_profile.primaries_blue_xy[0] = 0.131;
color_profile.primaries_blue_xy[1] = 0.046;
break;
#endif
default:
if (is_gray && !whiteP.isNull()) {
color_profile.white_point = JXL_WHITE_POINT_CUSTOM;
@@ -1844,20 +1874,17 @@ bool QJpegXLHandler::rewind()
return false;
}
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
if (!is_gray) {
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
if (jxlcms) {
status = JxlDecoderSetCms(m_decoder, *jxlcms);
if (status != JXL_DEC_SUCCESS) {
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
}
} else {
qCWarning(LOG_JXLPLUGIN, "No JPEG XL CMS Interface");
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
if (jxlcms) {
status = JxlDecoderSetCms(m_decoder, *jxlcms);
if (status != JXL_DEC_SUCCESS) {
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
}
} else {
qCWarning(LOG_JXLPLUGIN, "No JPEG XL CMS Interface");
}
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
JxlColorEncoding color_encoding;
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
@@ -2008,11 +2035,6 @@ bool QJpegXLHandler::extractBox(QByteArray &output, size_t container_size)
return false;
}
if (rawboxsize > 8388608) { // 8MB limit
qCWarning(LOG_JXLPLUGIN, "Skipped decoding of big JXL metadata box");
return true;
}
output.resize(rawboxsize);
status = JxlDecoderSetBoxBuffer(m_decoder, reinterpret_cast<uint8_t *>(output.data()), output.size());
if (status != JXL_DEC_SUCCESS) {
@@ -2026,7 +2048,7 @@ bool QJpegXLHandler::extractBox(QByteArray &output, size_t container_size)
if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
size_t bytes_remains = JxlDecoderReleaseBoxBuffer(m_decoder);
if (output.size() > 33554432) { // approx. 32MB (4*8) limit for decompressed metadata box
if (output.size() > 4194304) { // approx. 4MB limit for decompressed metadata box
qCWarning(LOG_JXLPLUGIN, "JXL metadata box is too large");
m_parseState = ParseJpegXLError;
return false;

View File

@@ -45,7 +45,7 @@ Q_LOGGING_CATEGORY(LOG_JXRPLUGIN, "kf.imageformats.plugins.jxr", QtWarningMsg)
// #define JXR_DENY_FLOAT_IMAGE
/*!
* Remove the needs of additional memory by disabling the conversion between
* Remove the neeeds of additional memory by disabling the conversion between
* different color depths (e.g. RGBA64bpp to RGBA32bpp).
*
* NOTE: Leaving deptch conversion enabled (default) ensures maximum read compatibility.
@@ -579,7 +579,9 @@ public:
// IMPORTANT: these values must be in exactMatchingFormat()
// clang-format off
auto valid = QSet<QImage::Format>()
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
<< QImage::Format_CMYK8888
#endif
#ifndef JXR_DENY_FLOAT_IMAGE
<< QImage::Format_RGBA16FPx4
<< QImage::Format_RGBX16FPx4
@@ -669,8 +671,10 @@ public:
wmiSCP->bVerbose = FALSE;
if (fmt == QImage::Format_Grayscale8 || fmt == QImage::Format_Grayscale16 || fmt == QImage::Format_Mono)
wmiSCP->cfColorFormat = Y_ONLY;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
else if (fmt == QImage::Format_CMYK8888)
wmiSCP->cfColorFormat = CMYK;
#endif
else
wmiSCP->cfColorFormat = YUV_444;
wmiSCP->bdBitDepth = BD_LONG;
@@ -808,8 +812,10 @@ private:
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_RGBA32FPx4_Premultiplied, GUID_PKPixelFormat128bppPRGBAFloat)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_RGBX32FPx4, GUID_PKPixelFormat128bppRGBFloat)
#endif // JXR_DENY_FLOAT_IMAGE
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_CMYK8888, GUID_PKPixelFormat32bppCMYK)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_CMYK8888, GUID_PKPixelFormat32bppCMYKDIRECT)
#endif
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_Mono, GUID_PKPixelFormatBlackWhite)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_Grayscale8, GUID_PKPixelFormat8bppGray)
<< std::pair<QImage::Format, PKPixelFormatGUID>(QImage::Format_Grayscale16, GUID_PKPixelFormat16bppGray)

View File

@@ -256,7 +256,7 @@ static bool checkHeader(QDataStream &ds)
/*!
* \brief updatePos
* Write the current stream position in \a pos position as uint32.
* Write the current stram position in \a pos position as uint32.
* \return True on success, otherwise false;
*/
static bool updatePos(QDataStream &ds, quint32 pos)
@@ -510,7 +510,7 @@ static QByteArray readBytes(QDataStream &ds, quint32 count, bool asciiz)
* \param pos The position of the IFD.
* \param knownTags List of known and supported tags.
* \param nextIfd The position of next IFD (0 if none).
* \return True on success, otherwise false.
* \return True on succes, otherwise false.
*/
static bool readIfd(QDataStream &ds, MicroExif::Tags &tags, quint32 pos = 0, const KnownTags &knownTags = staticTagTypes, quint32 *nextIfd = nullptr)
{

Some files were not shown because too many files have changed in this diff Show More