Compare commits
31 Commits
v6.22.0
...
Frameworks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
950a461fd3 | ||
|
|
ae279c55f4 | ||
|
|
836e0a53bb | ||
|
|
5eb09116b0 | ||
|
|
92368ca58f | ||
|
|
a91c7ef72f | ||
|
|
ea2a4aafab | ||
|
|
c254875780 | ||
|
|
f3de2e77c1 | ||
|
|
1ef779f370 | ||
|
|
169a874cba | ||
|
|
ebf77ccdf5 | ||
|
|
359cb039d2 | ||
|
|
f4b91d8a54 | ||
|
|
263b5a88e2 | ||
|
|
8d07f7db1b | ||
|
|
1c2210c100 | ||
|
|
b7b438f903 | ||
|
|
336b8906aa | ||
|
|
2c8a1ad6ff | ||
|
|
e0f1ba640a | ||
|
|
32773e5f0c | ||
|
|
2410e45614 | ||
|
|
99e4223393 | ||
|
|
8224c0099d | ||
|
|
8d7fb2c3fd | ||
|
|
3353809906 | ||
|
|
abf4d32858 | ||
|
|
6b1c52c55c | ||
|
|
e644ab997f | ||
|
|
1fb3363e7b |
@@ -1,11 +1,11 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.27)
|
||||||
|
|
||||||
set(KF_VERSION "6.22.0") # handled by release scripts
|
set(KF_VERSION "6.24.0") # handled by release scripts
|
||||||
set(KF_DEP_VERSION "6.22.0") # handled by release scripts
|
set(KF_DEP_VERSION "6.24.0") # handled by release scripts
|
||||||
project(KImageFormats VERSION ${KF_VERSION})
|
project(KImageFormats VERSION ${KF_VERSION})
|
||||||
|
|
||||||
include(FeatureSummary)
|
include(FeatureSummary)
|
||||||
find_package(ECM 6.22.0 NO_MODULE)
|
find_package(ECM 6.24.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)
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR
|
|||||||
|
|
||||||
ecm_set_disabled_deprecation_versions(
|
ecm_set_disabled_deprecation_versions(
|
||||||
QT 6.11.0
|
QT 6.11.0
|
||||||
KF 6.21.0
|
KF 6.23.0
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|||||||
@@ -357,9 +357,16 @@ The plugin supports the following image data:
|
|||||||
type 4.
|
type 4.
|
||||||
- FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images
|
- FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images
|
||||||
with color map only.
|
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
|
- FOR4 CIMG (Maya Image File Format): It supports 24/48-bit RGB and 32/64-bit
|
||||||
RGBA images.
|
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
|
### The JP2 plugin
|
||||||
|
|
||||||
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
|
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ private Q_SLOTS:
|
|||||||
QCOMPARE(reader.text(QStringLiteral("Author")), QStringLiteral("KDE Community"));
|
QCOMPARE(reader.text(QStringLiteral("Author")), QStringLiteral("KDE Community"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void textRead()
|
void testRead()
|
||||||
{
|
{
|
||||||
QImageReader reader(QFINDTESTDATA("ani/test.ani"));
|
QImageReader reader(QFINDTESTDATA("ani/test.ani"));
|
||||||
QVERIFY(reader.canRead());
|
QVERIFY(reader.canRead());
|
||||||
|
|||||||
@@ -18,6 +18,11 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
|
LDFLAGS=""
|
||||||
|
if [[ $FUZZING_ENGINE == "afl" ]]; then
|
||||||
|
LDFLAGS="-fuse-ld=lld"
|
||||||
|
fi
|
||||||
|
export LDFLAGS
|
||||||
|
|
||||||
# build zstd
|
# build zstd
|
||||||
cd $SRC/zstd
|
cd $SRC/zstd
|
||||||
@@ -185,7 +190,7 @@ echo "$HANDLER_TYPES" | while read class format; do
|
|||||||
/usr/libexec/moc $SRC/kimageformats/src/imageformats/$format.cpp -o $format.moc
|
/usr/libexec/moc $SRC/kimageformats/src/imageformats/$format.cpp -o $format.moc
|
||||||
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
|
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
|
||||||
/usr/libexec/moc $header -o moc_`basename $header .h`.cpp
|
/usr/libexec/moc $header -o moc_`basename $header .h`.cpp
|
||||||
$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
|
$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
|
||||||
|
|
||||||
# -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.
|
# -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.
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ 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/qtbase.git
|
||||||
git clone --depth 1 --branch=dev git://code.qt.io/qt/qttools.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 master https://invent.kde.org/frameworks/karchive.git
|
||||||
git clone --depth 1 -b v3.12.0 https://aomedia.googlesource.com/aom
|
git clone --depth 1 -b v3.13.1 https://aomedia.googlesource.com/aom
|
||||||
git clone --depth 1 -b v1.2.1 https://github.com/AOMediaCodec/libavif.git
|
git clone --depth 1 -b v1.3.0 https://github.com/AOMediaCodec/libavif.git
|
||||||
git clone --depth 1 https://github.com/strukturag/libde265.git
|
git clone --depth 1 https://github.com/strukturag/libde265.git
|
||||||
git clone --depth 1 -b v2.5.3 https://github.com/uclouvain/openjpeg.git
|
git clone --depth 1 -b v2.5.4 https://github.com/uclouvain/openjpeg.git
|
||||||
git clone --depth 1 https://github.com/strukturag/libheif.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 --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/LibRaw/LibRaw
|
||||||
|
|||||||
BIN
autotests/read/avif/profile_gray.avif
Normal file
|
After Width: | Height: | Size: 267 KiB |
11
autotests/read/avif/profile_gray.avif.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "profile_gray.png",
|
||||||
|
"colorSpace" : {
|
||||||
|
"colorModel" : "Gray",
|
||||||
|
"primaries" : "Custom",
|
||||||
|
"transferFunction" : "SRgb",
|
||||||
|
"gamma" : 2.31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/avif/profile_gray.png
Normal file
|
After Width: | Height: | Size: 267 KiB |
BIN
autotests/read/avif/profile_gray_gamma22.avif
Normal file
|
After Width: | Height: | Size: 261 KiB |
11
autotests/read/avif/profile_gray_gamma22.avif.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "profile_gray_gamma22.png",
|
||||||
|
"colorSpace" : {
|
||||||
|
"colorModel" : "Gray",
|
||||||
|
"primaries" : "Custom",
|
||||||
|
"transferFunction" : "Gamma",
|
||||||
|
"gamma" : 2.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/avif/profile_gray_gamma22.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
autotests/read/avif/profile_gray_gamma28.avif
Normal file
|
After Width: | Height: | Size: 263 KiB |
11
autotests/read/avif/profile_gray_gamma28.avif.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "profile_gray_gamma28.png",
|
||||||
|
"colorSpace" : {
|
||||||
|
"colorModel" : "Gray",
|
||||||
|
"primaries" : "Custom",
|
||||||
|
"transferFunction" : "Gamma",
|
||||||
|
"gamma" : 2.8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/avif/profile_gray_gamma28.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
autotests/read/avif/profile_gray_linear.avif
Normal file
|
After Width: | Height: | Size: 216 KiB |
11
autotests/read/avif/profile_gray_linear.avif.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "profile_gray_linear.png",
|
||||||
|
"colorSpace" : {
|
||||||
|
"colorModel" : "Gray",
|
||||||
|
"primaries" : "Custom",
|
||||||
|
"transferFunction" : "Linear",
|
||||||
|
"gamma" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/avif/profile_gray_linear.png
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
autotests/read/avif/profile_gray_prophoto.avif
Normal file
|
After Width: | Height: | Size: 255 KiB |
12
autotests/read/avif/profile_gray_prophoto.avif.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "profile_gray_prophoto.png",
|
||||||
|
"colorSpace" : {
|
||||||
|
"description" : "grayscale D50 with ProPhoto TRC",
|
||||||
|
"colorModel" : "Gray",
|
||||||
|
"primaries" : "Custom",
|
||||||
|
"transferFunction" : "Custom",
|
||||||
|
"gamma" : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/avif/profile_gray_prophoto.png
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
autotests/read/iff/cdi_cl7.iff
Normal file
BIN
autotests/read/iff/cdi_cl7.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
autotests/read/iff/cdi_dyuv_each.iff
Normal file
9
autotests/read/iff/cdi_dyuv_each.iff.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "cdi_dyuv_each.iff",
|
||||||
|
"resolution" : {
|
||||||
|
"dotsPerMeterX" : 3937,
|
||||||
|
"dotsPerMeterY" : 5249
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/iff/cdi_dyuv_each.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
autotests/read/iff/cdi_dyuv_one.iff
Normal file
BIN
autotests/read/iff/cdi_dyuv_one.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
autotests/read/iff/sv5_gray8_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_gray8_rgx.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
autotests/read/iff/sv5_idx8_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_idx8_rgx.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
autotests/read/iff/sv5_rgb16_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_rgb16_rgx.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
autotests/read/iff/sv5_rgb32_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_rgb32_rgx.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
autotests/read/iff/sv5_rgb8_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_rgb8_rgx.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
autotests/read/iff/sv5_rgba16_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_rgba16_rgx.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
autotests/read/iff/sv5_rgba32_rgx.iff
Normal file
37
autotests/read/iff/sv5_rgba32_rgx.iff.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/iff/sv5_rgba32_rgx.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
autotests/read/iff/sv5_rgba8_rgx.iff
Normal file
BIN
autotests/read/iff/sv5_rgba8_rgx.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
autotests/read/jxl/gray_linear_lossy.jxl
Normal file
14
autotests/read/jxl/gray_linear_lossy.jxl.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/jxl/gray_linear_lossy.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ani_p.h"
|
#include "ani_p.h"
|
||||||
|
#include "util_p.h"
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
@@ -101,7 +102,7 @@ bool ANIHandler::read(QImage *outImage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto frameSize = *(reinterpret_cast<const quint32_le *>(frameSizeData.data()));
|
const auto frameSize = *(reinterpret_cast<const quint32_le *>(frameSizeData.data()));
|
||||||
if (!frameSize) {
|
if (!frameSize || frameSize > quint32(kMaxQVectorSize)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +418,9 @@ bool ANIHandler::ensureScanned() const
|
|||||||
// IART and INAM are technically inside LIST->INFO but "INFO" is supposedly optional
|
// IART and INAM are technically inside LIST->INFO but "INFO" is supposedly optional
|
||||||
// so just handle those two attributes wherever we encounter them
|
// so just handle those two attributes wherever we encounter them
|
||||||
} else if (chunkId == "INAM" || chunkId == "IART") {
|
} else if (chunkId == "INAM" || chunkId == "IART") {
|
||||||
|
if (chunkSize > kMaxQVectorSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const QByteArray value = device()->read(chunkSize);
|
const QByteArray value = device()->read(chunkSize);
|
||||||
|
|
||||||
if (static_cast<quint32_le>(value.size()) != chunkSize) {
|
if (static_cast<quint32_le>(value.size()) != chunkSize) {
|
||||||
|
|||||||
@@ -388,6 +388,9 @@ bool QAVIFHandler::decode_one_frame()
|
|||||||
case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */
|
case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */
|
||||||
colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
|
colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
|
||||||
break;
|
break;
|
||||||
|
case 9:
|
||||||
|
colorspace = QColorSpace(QColorSpace::Primaries::Bt2020, q_trc, q_trc_gamma);
|
||||||
|
break;
|
||||||
/* AVIF_COLOR_PRIMARIES_SMPTE432 */
|
/* AVIF_COLOR_PRIMARIES_SMPTE432 */
|
||||||
case 12:
|
case 12:
|
||||||
colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
|
colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
|
||||||
@@ -740,6 +743,15 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
/* AVIF_TRANSFER_CHARACTERISTICS_LINEAR */
|
/* AVIF_TRANSFER_CHARACTERISTICS_LINEAR */
|
||||||
avif->transferCharacteristics = (avifTransferCharacteristics)8;
|
avif->transferCharacteristics = (avifTransferCharacteristics)8;
|
||||||
break;
|
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:
|
case QColorSpace::TransferFunction::SRgb:
|
||||||
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
|
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
|
||||||
avif->transferCharacteristics = (avifTransferCharacteristics)13;
|
avif->transferCharacteristics = (avifTransferCharacteristics)13;
|
||||||
@@ -754,6 +766,42 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
|
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
|
||||||
break;
|
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
|
if (save_depth > 8) { // QImage::Format_Grayscale16
|
||||||
@@ -838,6 +886,10 @@ bool QAVIFHandler::write(const QImage &image)
|
|||||||
/* AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL */
|
/* AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL */
|
||||||
matrix_to_save = (avifMatrixCoefficients)12;
|
matrix_to_save = (avifMatrixCoefficients)12;
|
||||||
break;
|
break;
|
||||||
|
case QColorSpace::Primaries::Bt2020:
|
||||||
|
primaries_to_save = (avifColorPrimaries)9;
|
||||||
|
matrix_to_save = (avifMatrixCoefficients)12;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
|
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
|
||||||
primaries_to_save = (avifColorPrimaries)2;
|
primaries_to_save = (avifColorPrimaries)2;
|
||||||
@@ -1128,7 +1180,7 @@ bool QAVIFHandler::jumpToNextImage()
|
|||||||
if (m_decoder->imageIndex >= 0) {
|
if (m_decoder->imageIndex >= 0) {
|
||||||
if (m_decoder->imageCount < 2) {
|
if (m_decoder->imageCount < 2) {
|
||||||
m_parseState = ParseAvifSuccess;
|
m_parseState = ParseAvifSuccess;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning
|
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) { // start from beginning
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of the KDE project
|
This file is part of the KDE project
|
||||||
SPDX-FileCopyrightText: 2025 Mirco Miranda <mircomir@outlook.com>
|
SPDX-FileCopyrightText: 2025-2026 Mirco Miranda <mircomir@outlook.com>
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
* - https://wiki.amigaos.net/wiki/IFF_FORM_and_Chunk_Registry
|
* - https://wiki.amigaos.net/wiki/IFF_FORM_and_Chunk_Registry
|
||||||
* - https://www.fileformat.info/format/iff/egff.htm
|
* - https://www.fileformat.info/format/iff/egff.htm
|
||||||
* - https://download.autodesk.com/us/maya/2010help/index.html (Developer resources -> File formats -> Maya IFF)
|
* - 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
|
#ifndef KIMG_CHUNKS_P_H
|
||||||
@@ -55,7 +56,17 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
|
|||||||
#define CMAP_CHUNK QByteArray("CMAP")
|
#define CMAP_CHUNK QByteArray("CMAP")
|
||||||
#define CMYK_CHUNK QByteArray("CMYK") // https://wiki.amigaos.net/wiki/ILBM_IFF_Interleaved_Bitmap#ILBM.CMYK
|
#define CMYK_CHUNK QByteArray("CMYK") // https://wiki.amigaos.net/wiki/ILBM_IFF_Interleaved_Bitmap#ILBM.CMYK
|
||||||
#define DPI__CHUNK QByteArray("DPI ")
|
#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 XBMI_CHUNK QByteArray("XBMI")
|
||||||
|
#define YUVS_CHUNK QByteArray("YUVS")
|
||||||
|
|
||||||
// Different palette for scanline
|
// Different palette for scanline
|
||||||
#define BEAM_CHUNK QByteArray("BEAM")
|
#define BEAM_CHUNK QByteArray("BEAM")
|
||||||
@@ -79,14 +90,18 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
|
|||||||
#define FVER_CHUNK QByteArray("FVER")
|
#define FVER_CHUNK QByteArray("FVER")
|
||||||
#define HIST_CHUNK QByteArray("HIST")
|
#define HIST_CHUNK QByteArray("HIST")
|
||||||
#define NAME_CHUNK QByteArray("NAME")
|
#define NAME_CHUNK QByteArray("NAME")
|
||||||
|
#define VDAT_CHUNK QByteArray("VDAT")
|
||||||
#define VERS_CHUNK QByteArray("VERS")
|
#define VERS_CHUNK QByteArray("VERS")
|
||||||
#define XMP0_CHUNK QByteArray("XMP0") // https://aminet.net/package/docs/misc/IFF-metadata
|
#define XMP0_CHUNK QByteArray("XMP0") // https://aminet.net/package/docs/misc/IFF-metadata
|
||||||
|
|
||||||
|
// FORM types
|
||||||
#define ACBM_FORM_TYPE QByteArray("ACBM")
|
#define ACBM_FORM_TYPE QByteArray("ACBM")
|
||||||
#define ILBM_FORM_TYPE QByteArray("ILBM")
|
#define ILBM_FORM_TYPE QByteArray("ILBM")
|
||||||
|
#define IMAG_FORM_TYPE QByteArray("IMAG")
|
||||||
#define PBM__FORM_TYPE QByteArray("PBM ")
|
#define PBM__FORM_TYPE QByteArray("PBM ")
|
||||||
#define RGB8_FORM_TYPE QByteArray("RGB8")
|
#define RGB8_FORM_TYPE QByteArray("RGB8")
|
||||||
#define RGBN_FORM_TYPE QByteArray("RGBN")
|
#define RGBN_FORM_TYPE QByteArray("RGBN")
|
||||||
|
#define RGFX_FORM_TYPE QByteArray("RGFX")
|
||||||
|
|
||||||
#define CIMG_FOR4_TYPE QByteArray("CIMG")
|
#define CIMG_FOR4_TYPE QByteArray("CIMG")
|
||||||
#define TBMP_FOR4_TYPE QByteArray("TBMP")
|
#define TBMP_FOR4_TYPE QByteArray("TBMP")
|
||||||
@@ -424,7 +439,8 @@ public:
|
|||||||
enum Compression {
|
enum Compression {
|
||||||
Uncompressed = 0, /**< Image data are uncompressed. */
|
Uncompressed = 0, /**< Image data are uncompressed. */
|
||||||
Rle = 1, /**< Image data are RLE compressed. */
|
Rle = 1, /**< Image data are RLE compressed. */
|
||||||
RgbN8 = 4 /**< RGB8/RGBN compresson. */
|
Vdat = 2, /**< Image data are VDAT compressed. */
|
||||||
|
RgbN8 = 4 /**< Image data are RGB8/RGBN compressed. */
|
||||||
};
|
};
|
||||||
enum Masking {
|
enum Masking {
|
||||||
None = 0, /**< Designates an opaque rectangular image. */
|
None = 0, /**< Designates an opaque rectangular image. */
|
||||||
@@ -756,10 +772,11 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
* \brief readStride
|
* \brief readStride
|
||||||
* \param d The device.
|
* \param d The device.
|
||||||
* \param header The bitmap header.
|
|
||||||
* \param y The current scanline.
|
* \param y The current scanline.
|
||||||
|
* \param header The bitmap header.
|
||||||
* \param camg The CAMG chunk (optional)
|
* \param camg The CAMG chunk (optional)
|
||||||
* \param cmap The CMAP 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.
|
* \param formType The type of the current form chunk.
|
||||||
* \return The scanline as requested for QImage.
|
* \return The scanline as requested for QImage.
|
||||||
* \warning Call resetStrideRead() once before this one.
|
* \warning Call resetStrideRead() once before this one.
|
||||||
@@ -776,8 +793,6 @@ public:
|
|||||||
* \brief resetStrideRead
|
* \brief resetStrideRead
|
||||||
* Reset the stride read set the position at the beginning of the data and reset all buffers.
|
* Reset the stride read set the position at the beginning of the data and reset all buffers.
|
||||||
* \param d The device.
|
* \param d The device.
|
||||||
* \param header The BMHDChunk chunk (mandatory)
|
|
||||||
* \param camg The CAMG chunk (optional)
|
|
||||||
* \return True on success, otherwise false.
|
* \return True on success, otherwise false.
|
||||||
* \sa strideRead
|
* \sa strideRead
|
||||||
* \note Must be called once before strideRead().
|
* \note Must be called once before strideRead().
|
||||||
@@ -788,6 +803,7 @@ public:
|
|||||||
* \brief safeModeId
|
* \brief safeModeId
|
||||||
* \param header The header.
|
* \param header The header.
|
||||||
* \param camg The CAMG chunk.
|
* \param camg The CAMG chunk.
|
||||||
|
* \param cmap The CMAP chunk.
|
||||||
* \return The most likely ModeId if not explicitly specified.
|
* \return The most likely ModeId if not explicitly specified.
|
||||||
*/
|
*/
|
||||||
static CAMGChunk::ModeIds safeModeId(const BMHDChunk *header, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr);
|
static CAMGChunk::ModeIds safeModeId(const BMHDChunk *header, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr);
|
||||||
@@ -808,6 +824,8 @@ protected:
|
|||||||
|
|
||||||
QByteArray rgbN(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
|
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:
|
private:
|
||||||
mutable QByteArray _readBuffer;
|
mutable QByteArray _readBuffer;
|
||||||
};
|
};
|
||||||
@@ -921,6 +939,13 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool innerReadStructure(QIODevice *d) override;
|
virtual bool innerReadStructure(QIODevice *d) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QImage::Format iffFormat() const;
|
||||||
|
|
||||||
|
QImage::Format cdiFormat() const;
|
||||||
|
|
||||||
|
QImage::Format rgfxFormat() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1357,6 +1382,32 @@ protected:
|
|||||||
virtual bool innerReadStructure(QIODevice *d) override;
|
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
|
* \brief The VERSChunk class
|
||||||
*/
|
*/
|
||||||
@@ -1400,6 +1451,500 @@ protected:
|
|||||||
virtual bool innerReadStructure(QIODevice *d) override;
|
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 model’s 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 ***
|
* *** UNDOCUMENTED CHUNKS ***
|
||||||
|
|||||||
@@ -262,14 +262,26 @@ static void addMetadata(QImage &img, const IFOR_Chunk *form)
|
|||||||
|
|
||||||
// if no explicit resolution was found, apply the aspect ratio to the default one
|
// if no explicit resolution was found, apply the aspect ratio to the default one
|
||||||
if (!resChanged) {
|
if (!resChanged) {
|
||||||
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
if (form->formType() == IMAG_FORM_TYPE) {
|
||||||
if (!headers.isEmpty()) {
|
auto params = IFFChunk::searchT<IPARChunk>(form);
|
||||||
auto xr = headers.first()->xAspectRatio();
|
if (!params.isEmpty()) {
|
||||||
auto yr = headers.first()->yAspectRatio();
|
img.setDotsPerMeterY(img.dotsPerMeterY() * params.first()->aspectRatio());
|
||||||
if (xr > 0 && yr > 0 && xr > yr) {
|
}
|
||||||
img.setDotsPerMeterX(img.dotsPerMeterX() * yr / xr);
|
} else if (form->formType() == RGFX_FORM_TYPE) {
|
||||||
} else if (xr > 0 && yr > 0 && xr < yr) {
|
auto headers = IFFChunk::searchT<RGHDChunk>(form);
|
||||||
img.setDotsPerMeterY(img.dotsPerMeterY() * xr / yr);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,7 +339,6 @@ bool IFFHandler::readStandardImage(QImage *image)
|
|||||||
// show the first one (I don't have a sample with many images)
|
// show the first one (I don't have a sample with many images)
|
||||||
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
||||||
if (headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage(): no supported image found";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +437,6 @@ bool IFFHandler::readMayaImage(QImage *image)
|
|||||||
// show the first one (I don't have a sample with many images)
|
// show the first one (I don't have a sample with many images)
|
||||||
auto headers = IFFChunk::searchT<TBHDChunk>(form);
|
auto headers = IFFChunk::searchT<TBHDChunk>(form);
|
||||||
if (headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readMayaImage(): no supported image found";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,6 +485,132 @@ bool IFFHandler::readMayaImage(QImage *image)
|
|||||||
return true;
|
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)
|
||||||
|
addMetadata(img, form);
|
||||||
|
|
||||||
|
*image = img;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool IFFHandler::read(QImage *image)
|
bool IFFHandler::read(QImage *image)
|
||||||
{
|
{
|
||||||
if (!d->readStructure(device())) {
|
if (!d->readStructure(device())) {
|
||||||
@@ -490,6 +626,14 @@ bool IFFHandler::read(QImage *image)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (readCDIImage(image)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readRGFXImage(image)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::read(): no supported image found";
|
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::read(): no supported image found";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ private:
|
|||||||
|
|
||||||
bool readMayaImage(QImage *image);
|
bool readMayaImage(QImage *image);
|
||||||
|
|
||||||
|
bool readCDIImage(QImage *image);
|
||||||
|
|
||||||
|
bool readRGFXImage(QImage *image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QScopedPointer<IFFHandlerPrivate> d;
|
const QScopedPointer<IFFHandlerPrivate> d;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -253,20 +253,27 @@ public:
|
|||||||
bool jp2ToImage(QImage *img) const
|
bool jp2ToImage(QImage *img) const
|
||||||
{
|
{
|
||||||
Q_ASSERT(img->depth() == 8 * sizeof(T) || img->depth() == 32 * sizeof(T));
|
Q_ASSERT(img->depth() == 8 * sizeof(T) || img->depth() == 32 * sizeof(T));
|
||||||
for (qint32 c = 0, cc = m_jp2_image->numcomps; c < cc; ++c) {
|
if (img->width() < 1 || img->height() < 1) {
|
||||||
auto cs = cc == 1 ? 1 : 4;
|
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);
|
||||||
auto &&jc = m_jp2_image->comps[c];
|
auto &&jc = m_jp2_image->comps[c];
|
||||||
if (jc.data == nullptr)
|
if (jc.data == nullptr) {
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// discriminate between int and float (avoid complicating things by creating classes with template specializations)
|
// discriminate between int and float (avoid complicating things by creating classes with template specializations)
|
||||||
if (std::numeric_limits<T>::is_integer) {
|
if (std::numeric_limits<T>::is_integer) {
|
||||||
auto divisor = 1;
|
auto divisor = 1ull;
|
||||||
if (jc.prec > sizeof(T) * 8) {
|
auto prec = std::min(size_t(jc.prec), sizeof(*jc.data) * 8);
|
||||||
|
if (prec > sizeof(T) * 8 && prec < 64) {
|
||||||
// convert to the wanted precision (e.g. 16-bit -> 8-bit: divisor = 65535 / 255 = 257)
|
// convert to the wanted precision (e.g. 16-bit -> 8-bit: divisor = 65535 / 255 = 257)
|
||||||
divisor = std::max(1, int(((1ll << jc.prec) - 1) / ((1ll << (sizeof(T) * 8)) - 1)));
|
divisor = std::max(1ull, (((1ull << prec) - 1) / ((1ull << (sizeof(T) * 8)) - 1)));
|
||||||
}
|
}
|
||||||
for (qint32 y = 0, h = img->height(); y < h; ++y) {
|
for (qint32 y = 0, h = img->height(); y < h; ++y) {
|
||||||
auto ptr = reinterpret_cast<T *>(img->scanLine(y));
|
auto ptr = reinterpret_cast<T *>(img->scanLine(y));
|
||||||
|
|||||||
@@ -258,14 +258,16 @@ bool QJpegXLHandler::countALLFrames()
|
|||||||
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
|
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
|
||||||
JxlColorEncoding color_encoding;
|
JxlColorEncoding color_encoding;
|
||||||
if (m_basicinfo.uses_original_profile == JXL_FALSE && m_basicinfo.have_animation == JXL_FALSE) {
|
if (m_basicinfo.uses_original_profile == JXL_FALSE && m_basicinfo.have_animation == JXL_FALSE) {
|
||||||
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
|
if (!is_gray) {
|
||||||
if (jxlcms) {
|
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
|
||||||
status = JxlDecoderSetCms(m_decoder, *jxlcms);
|
if (jxlcms) {
|
||||||
if (status != JXL_DEC_SUCCESS) {
|
status = JxlDecoderSetCms(m_decoder, *jxlcms);
|
||||||
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
|
if (status != JXL_DEC_SUCCESS) {
|
||||||
|
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCWarning(LOG_JXLPLUGIN, "No JPEG XL CMS Interface");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
qCWarning(LOG_JXLPLUGIN, "No JPEG XL CMS Interface");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
||||||
@@ -853,7 +855,11 @@ bool QJpegXLHandler::write(const QImage &image)
|
|||||||
|
|
||||||
size_t pixel_count = size_t(image.width()) * image.height();
|
size_t pixel_count = size_t(image.width()) * image.height();
|
||||||
if (MAX_IMAGE_PIXELS && pixel_count > MAX_IMAGE_PIXELS) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1838,17 +1844,20 @@ bool QJpegXLHandler::rewind()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
|
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
|
||||||
if (jxlcms) {
|
|
||||||
status = JxlDecoderSetCms(m_decoder, *jxlcms);
|
if (!is_gray) {
|
||||||
if (status != JXL_DEC_SUCCESS) {
|
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
|
||||||
qCWarning(LOG_JXLPLUGIN, "JxlDecoderSetCms ERROR");
|
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");
|
||||||
}
|
}
|
||||||
} 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;
|
JxlColorEncoding color_encoding;
|
||||||
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
||||||
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
||||||
@@ -1999,6 +2008,11 @@ bool QJpegXLHandler::extractBox(QByteArray &output, size_t container_size)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rawboxsize > 8388608) { // 8MB limit
|
||||||
|
qCWarning(LOG_JXLPLUGIN, "Skipped decoding of big JXL metadata box");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
output.resize(rawboxsize);
|
output.resize(rawboxsize);
|
||||||
status = JxlDecoderSetBoxBuffer(m_decoder, reinterpret_cast<uint8_t *>(output.data()), output.size());
|
status = JxlDecoderSetBoxBuffer(m_decoder, reinterpret_cast<uint8_t *>(output.data()), output.size());
|
||||||
if (status != JXL_DEC_SUCCESS) {
|
if (status != JXL_DEC_SUCCESS) {
|
||||||
@@ -2012,7 +2026,7 @@ bool QJpegXLHandler::extractBox(QByteArray &output, size_t container_size)
|
|||||||
if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
|
if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
|
||||||
size_t bytes_remains = JxlDecoderReleaseBoxBuffer(m_decoder);
|
size_t bytes_remains = JxlDecoderReleaseBoxBuffer(m_decoder);
|
||||||
|
|
||||||
if (output.size() > 4194304) { // approx. 4MB limit for decompressed metadata box
|
if (output.size() > 33554432) { // approx. 32MB (4*8) limit for decompressed metadata box
|
||||||
qCWarning(LOG_JXLPLUGIN, "JXL metadata box is too large");
|
qCWarning(LOG_JXLPLUGIN, "JXL metadata box is too large");
|
||||||
m_parseState = ParseJpegXLError;
|
m_parseState = ParseJpegXLError;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1017,7 +1017,7 @@ inline void rawChannelCopy(uchar *target, qint32 targetChannels, qint32 targetCh
|
|||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
inline bool cmykToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
||||||
{
|
{
|
||||||
auto s = reinterpret_cast<const T*>(source);
|
auto s = reinterpret_cast<const T*>(source);
|
||||||
auto t = reinterpret_cast<T*>(target);
|
auto t = reinterpret_cast<T*>(target);
|
||||||
@@ -1026,7 +1026,7 @@ inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source,
|
|||||||
|
|
||||||
if (sourceChannels < 2) {
|
if (sourceChannels < 2) {
|
||||||
qCDebug(LOG_PSDPLUGIN) << "cmykToRgb: image is not a valid MCH/CMYK!";
|
qCDebug(LOG_PSDPLUGIN) << "cmykToRgb: image is not a valid MCH/CMYK!";
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (qint32 w = 0; w < width; ++w) {
|
for (qint32 w = 0; w < width; ++w) {
|
||||||
@@ -1047,6 +1047,7 @@ inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source,
|
|||||||
*(pt + 3) = std::numeric_limits<T>::max();
|
*(pt + 3) = std::numeric_limits<T>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double finv(double v)
|
inline double finv(double v)
|
||||||
@@ -1066,7 +1067,7 @@ inline double gammaCorrection(double linear)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
inline bool labToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
|
||||||
{
|
{
|
||||||
auto s = reinterpret_cast<const T*>(source);
|
auto s = reinterpret_cast<const T*>(source);
|
||||||
auto t = reinterpret_cast<T*>(target);
|
auto t = reinterpret_cast<T*>(target);
|
||||||
@@ -1075,7 +1076,7 @@ inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, q
|
|||||||
|
|
||||||
if (sourceChannels < 3) {
|
if (sourceChannels < 3) {
|
||||||
qCDebug(LOG_PSDPLUGIN) << "labToRgb: image is not a valid LAB!";
|
qCDebug(LOG_PSDPLUGIN) << "labToRgb: image is not a valid LAB!";
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (qint32 w = 0; w < width; ++w) {
|
for (qint32 w = 0; w < width; ++w) {
|
||||||
@@ -1110,6 +1111,7 @@ inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, q
|
|||||||
*(pt + 3) = std::numeric_limits<T>::max();
|
*(pt + 3) = std::numeric_limits<T>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readChannel(QByteArray &target, QDataStream &stream, quint32 compressedSize, quint16 compression)
|
bool readChannel(QByteArray &target, QDataStream &stream, quint32 compressedSize, quint16 compression)
|
||||||
@@ -1450,10 +1452,13 @@ bool PSDHandler::read(QImage *image)
|
|||||||
// Conversion to RGB
|
// Conversion to RGB
|
||||||
if (header.color_mode == CM_CMYK || header.color_mode == CM_MULTICHANNEL) {
|
if (header.color_mode == CM_CMYK || header.color_mode == CM_MULTICHANNEL) {
|
||||||
if (tmpCmyk.isNull()) {
|
if (tmpCmyk.isNull()) {
|
||||||
if (header.depth == 8)
|
if (header.depth == 8) {
|
||||||
cmykToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
if (!cmykToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||||
else if (header.depth == 16)
|
return false;
|
||||||
cmykToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
} else if (header.depth == 16) {
|
||||||
|
if (!cmykToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (header.depth == 8) {
|
} else if (header.depth == 8) {
|
||||||
rawChannelsCopyToCMYK<quint8>(tmpCmyk.bits(), 4, psdScanline.data(), header.channel_count, header.width);
|
rawChannelsCopyToCMYK<quint8>(tmpCmyk.bits(), 4, psdScanline.data(), header.channel_count, header.width);
|
||||||
if (auto rgbPtr = iccConv.convertedScanLine(tmpCmyk, 0))
|
if (auto rgbPtr = iccConv.convertedScanLine(tmpCmyk, 0))
|
||||||
@@ -1469,10 +1474,13 @@ bool PSDHandler::read(QImage *image)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header.color_mode == CM_LABCOLOR) {
|
if (header.color_mode == CM_LABCOLOR) {
|
||||||
if (header.depth == 8)
|
if (header.depth == 8) {
|
||||||
labToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
if (!labToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||||
else if (header.depth == 16)
|
return false;
|
||||||
labToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
} else if (header.depth == 16) {
|
||||||
|
if (!labToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (header.color_mode == CM_RGB) {
|
if (header.color_mode == CM_RGB) {
|
||||||
if (header.depth == 8)
|
if (header.depth == 8)
|
||||||
|
|||||||
@@ -319,7 +319,10 @@ bool SGIImagePrivate::readImage(QImage &img)
|
|||||||
|
|
||||||
if (_rle) {
|
if (_rle) {
|
||||||
uint l;
|
uint l;
|
||||||
_starttab = new quint32[_numrows];
|
_starttab = new (std::nothrow) quint32[_numrows];
|
||||||
|
if (_starttab == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
|
for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
|
||||||
_stream >> _starttab[l];
|
_stream >> _starttab[l];
|
||||||
_starttab[l] -= 512 + _numrows * 2 * sizeof(quint32);
|
_starttab[l] -= 512 + _numrows * 2 * sizeof(quint32);
|
||||||
@@ -331,7 +334,10 @@ bool SGIImagePrivate::readImage(QImage &img)
|
|||||||
_starttab[l] = 0;
|
_starttab[l] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_lengthtab = new quint32[_numrows];
|
_lengthtab = new (std::nothrow) quint32[_numrows];
|
||||||
|
if (_lengthtab == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
|
for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
|
||||||
_stream >> _lengthtab[l];
|
_stream >> _lengthtab[l];
|
||||||
if (_stream.status() != QDataStream::Ok) {
|
if (_stream.status() != QDataStream::Ok) {
|
||||||
@@ -794,7 +800,10 @@ bool SGIImagePrivate::writeImage(const QImage &image)
|
|||||||
_pixmax = 0;
|
_pixmax = 0;
|
||||||
_colormap = NORMAL;
|
_colormap = NORMAL;
|
||||||
_numrows = _ysize * _zsize;
|
_numrows = _ysize * _zsize;
|
||||||
_starttab = new quint32[_numrows];
|
_starttab = new (std::nothrow) quint32[_numrows];
|
||||||
|
if (_starttab == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
_rlemap.setBaseOffset(512 + _numrows * 2 * sizeof(quint32));
|
_rlemap.setBaseOffset(512 + _numrows * 2 * sizeof(quint32));
|
||||||
|
|
||||||
if (!scanData(image, tfmt, tcs)) {
|
if (!scanData(image, tfmt, tcs)) {
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ static bool LoadTGA(QIODevice *dev, const TgaHeader &tga, QImage &img)
|
|||||||
if (div == 0)
|
if (div == 0)
|
||||||
hasAlpha = false;
|
hasAlpha = false;
|
||||||
for (int x = x_start; x != x_end; x += x_step) {
|
for (int x = x_start; x != x_end; x += x_step) {
|
||||||
const int alpha = hasAlpha ? int((src[3]) << (8 - numAlphaBits)) * 255 / div : 255;
|
const int alpha = hasAlpha ? int(quint8(src[3]) << (8 - numAlphaBits)) * 255 / div : 255;
|
||||||
scanline[x] = qRgba(src[2], src[1], src[0], alpha);
|
scanline[x] = qRgba(src[2], src[1], src[0], alpha);
|
||||||
src += 4;
|
src += 4;
|
||||||
}
|
}
|
||||||
|
|||||||