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
126 changed files with 512 additions and 3990 deletions

View File

@@ -7,5 +7,5 @@ Dependencies:
Options: Options:
test-before-installing: True test-before-installing: True
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows'] require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
cmake-options: "-DKIMAGEFORMATS_WITH_KNOWN_CRASHES_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 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.26.0") # handled by release scripts set(KF_VERSION "6.20.0") # handled by release scripts
set(KF_DEP_VERSION "6.26.0") # handled by release scripts set(KF_DEP_VERSION "6.19.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION}) project(KImageFormats VERSION ${KF_VERSION})
include(FeatureSummary) include(FeatureSummary)
find_package(ECM 6.26.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") 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)
@@ -21,7 +21,7 @@ include(ECMDeprecationSettings)
include(CheckIncludeFiles) include(CheckIncludeFiles)
include(FindPkgConfig) 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(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(KF6Archive ${KF_DEP_VERSION}) 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_DDS "Enable plugin for DDS format" ON)
option(KIMAGEFORMATS_HEIF "Enable plugin for HEIF format" OFF) 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) if(KIMAGEFORMATS_HEIF)
pkg_check_modules(LibHeif IMPORTED_TARGET libheif>=1.10.0) pkg_check_modules(LibHeif IMPORTED_TARGET libheif>=1.10.0)
endif() endif()
@@ -97,17 +91,16 @@ set_package_properties(LibRaw PROPERTIES
PURPOSE "Required for the QImage plugin for RAW images" PURPOSE "Required for the QImage plugin for RAW images"
) )
# JXR plugin disabled by default due to security issues. # JXR plugin disabled by default due to security issues
# You should not enable it unless you know what you are doing. option(KIMAGEFORMATS_JXR "Enable plugin for JPEG XR format" OFF)
option(KIMAGEFORMATS_WITH_KNOWN_CRASHES_JXR "Enable plugin for JPEG XR format" OFF) if(KIMAGEFORMATS_JXR)
if(KIMAGEFORMATS_WITH_KNOWN_CRASHES_JXR)
find_package(LibJXR) find_package(LibJXR)
endif() endif()
add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images") add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images")
ecm_set_disabled_deprecation_versions( ecm_set_disabled_deprecation_versions(
QT 6.11.0 QT 6.10.0
KF 6.23.0 KF 6.18.0
) )
add_subdirectory(src) add_subdirectory(src)

View File

@@ -21,7 +21,6 @@ The following image formats have read-only support:
- Krita (kra) - Krita (kra)
- OpenRaster (ora) - OpenRaster (ora)
- Pixar raster (pxr) - Pixar raster (pxr)
- PlayStation graphics (tim)
- Portable FloatMap/HalfMap (pfm, phm) - Portable FloatMap/HalfMap (pfm, phm)
- Photoshop documents (psd, psb, pdd, psdt) - Photoshop documents (psd, psb, pdd, psdt)
- Radiance HDR (hdr) - Radiance HDR (hdr)
@@ -155,31 +154,8 @@ About the image:
- `Owner`: Name of the owner of the image. - `Owner`: Name of the owner of the image.
- `Software`: Name and version number of the software package(s) used to - `Software`: Name and version number of the software package(s) used to
create the image. create the image.
- `Speed`: Floating-point number indicating the speed of GPS receiver
movement in Km/h (e.g. 30.2).
- `Title`: The title of the image. - `Title`: The title of the image.
About the shot:
- `DigitalZoomRatio`: Floating-point number indicating the digital zoom ratio
when the image was shot.
- `ExposureMode`: Integer number indicating the exposure mode set when the
image was shot as reported in the EXIF specifications.
- `ExposureProgram`: Integer number indicating the class of the program used
by the camera to set exposure when the picture is taken as reported in the
EXIF specifications.
- `ExposureTime`: Floating-point number indicating the exposure time,
given in seconds (s).
- `Flash`: Integer number indicating the status of flash when the image
was shot as reported in the EXIF specifications.
- `FNumber`: Floating-point number indicating the F number.
- `FocalLength`: Floating-point number indicating the actual focal length
of the lens, in millimeters (mm).
- `ISOSpeedRatings`: Integer number indicating the sensitivity of the camera
or input device when the image was shot as reported in the EXIF
specifications.
- `WhiteBalance`: Integer number indicating the white balance mode set when
the image was shot as reported in the EXIF specifications.
About the camera: About the camera:
- `Manufacturer`: The manufacturer of the recording equipment. - `Manufacturer`: The manufacturer of the recording equipment.
- `Model`: The model name or model number of the recording equipment. - `Model`: The model name or model number of the recording equipment.
@@ -274,7 +250,6 @@ limit depends on the format encoding).
- RAW: 65,535 x 65,535 pixels - RAW: 65,535 x 65,535 pixels
- RGB: 65,535 x 65,535 pixels - RGB: 65,535 x 65,535 pixels
- SCT: 300,000 x 300,000 pixels - SCT: 300,000 x 300,000 pixels
- TIM: 65,535 x 65,535 pixels
- TGA: 65,535 x 65,535 pixels - TGA: 65,535 x 65,535 pixels
- XCF: 300,000 x 300,000 pixels - XCF: 300,000 x 300,000 pixels
@@ -315,14 +290,9 @@ in your cmake options.**
The following defines can be defined in cmake to modify the behavior of the The following defines can be defined in cmake to modify the behavior of the
plugin: 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. pitch: it is known that some writers do not set it correctly.
When writing, it is possible to set which pixel format to use by setting the
subtypes. The default is `Automatic` which chooses the most appropriate format
based on the image. For a complete list of subformats, please use the
appropriate [`QImageWriter`](https://doc.qt.io/qt-6/qimagewriter.html) APIs.
### The HEIF plugin ### The HEIF plugin
**This plugin is disabled by default. It can be enabled by settings **This plugin is disabled by default. It can be enabled by settings
@@ -333,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 support for HEVC codec. If HEVC codec is not available the plugin
will compile but will fail the tests. 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 EXR plugin
The following defines can be defined in cmake to modify the behavior of the The following defines can be defined in cmake to modify the behavior of the
@@ -352,10 +313,6 @@ plugin:
attribute named "xmp". Note that Gimp reads the "xmp" attribute and Darktable attribute named "xmp". Note that Gimp reads the "xmp" attribute and Darktable
writes it as well. writes it as well.
The plugin can set the following additional metadata:
- `EXRLayerName`: A string containing the name of the EXR layer used to decode
the image.
### The EPS plugin ### The EPS plugin
The plugin uses `Ghostscript` to convert the raster image. When reading it The plugin uses `Ghostscript` to convert the raster image. When reading it
@@ -391,16 +348,9 @@ 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`
@@ -411,11 +361,6 @@ JP2 plugin has the following limitations due to the lack of support by OpenJPEG:
- Image resolution is not supported. - Image resolution is not supported.
- To write ICC profiles you need OpenJPEG V2.5.4 or higher - To write ICC profiles you need OpenJPEG V2.5.4 or higher
When writing, it is possible to set which format to use by setting the
following subtypes:
- `JP2` (default): Save data using the JP2 container.
- `J2K`: Save only the compressed codestream.
### The JXL plugin ### The JXL plugin
**The current version of the plugin limits the image size to 256 megapixels **The current version of the plugin limits the image size to 256 megapixels
@@ -431,18 +376,13 @@ plugin:
### The JXR plugin ### The JXR plugin
**This plugin is disabled by default. It can be enabled by settings **This plugin is disabled by default. It can be enabled by settings
`KIMAGEFORMATS_WITH_KNOWN_CRASHES_JXR` to `ON` in your cmake options.** `KIMAGEFORMATS_JXR` to `ON` in your cmake options.**
> [!caution]
> The plugin disabled by default due to security issues in [jxrlib](https://github.com/4creators/jxrlib):
> the upstream jxrlib is dead and there is no "hope" they will fix the issues.
> **You should not enable it unless you know what you are doing.**
The following defines can be defined in cmake to modify the behavior of the The following defines can be defined in cmake to modify the behavior of the
plugin: plugin:
- `JXR_DENY_FLOAT_IMAGE`: disables the use of float images and consequently - `JXR_DENY_FLOAT_IMAGE`: disables the use of float images and consequently
any HDR data will be lost. 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 disabling the conversion between different color depths (e.g. RGBA64bpp to
RGBA32bpp) at the cost of reduced compatibility. RGBA32bpp) at the cost of reduced compatibility.
- `JXR_DISABLE_BGRA_HACK`: Windows displays and opens JXR files correctly out - `JXR_DISABLE_BGRA_HACK`: Windows displays and opens JXR files correctly out
@@ -474,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 CMYK if they have 2 or more channels.
- Multichannel images are treated as Grayscale if they have 1 channel. - Multichannel images are treated as Grayscale if they have 1 channel.
- Duotone images are treated as grayscale images. - 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. - Extra channels other than alpha are discarded.
The following defines can be defined in cmake to modify the behavior of the The following defines can be defined in cmake to modify the behavior of the
@@ -485,13 +423,6 @@ plugin:
- `PSD_NATIVE_CMYK_SUPPORT_DISABLED`: disable native support for CMYK images - `PSD_NATIVE_CMYK_SUPPORT_DISABLED`: disable native support for CMYK images
when compiled with Qt 6.8+ when compiled with Qt 6.8+
The plugin can set the following additional metadata:
- `PSDDuotoneOptions`: Byte array in hexadecimal format of color data of the
duotone specification (the format of which is not documented). From the PSD
specification: *"Other applications that read Photoshop files can treat a
duotone image as a gray image, and just preserve the contents of the duotone
information when reading and writing the file."*
### The RAW plugin ### The RAW plugin
Loading RAW images always requires a conversion. To allow the user to Loading RAW images always requires a conversion. To allow the user to

View File

@@ -86,7 +86,6 @@ kimageformats_read_tests(
ras ras
rgb rgb
sct sct
tim
tga tga
) )
@@ -103,52 +102,36 @@ if (KF6Archive_FOUND)
endif() endif()
if (TARGET avif) if (TARGET avif)
if(${libavif_VERSION} VERSION_GREATER_EQUAL "1.2.0") kimageformats_read_tests(
kimageformats_read_tests( avif
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_write_tests( kimageformats_write_tests(
avif-nodatacheck-lossless avif-nodatacheck-lossless
) )
endif() endif()
if (LibHeif_FOUND) if (LibHeif_FOUND)
if (KIMAGEFORMATS_HEIF_TEST STREQUAL "ALL" OR KIMAGEFORMATS_HEIF_TEST STREQUAL "READ_ONLY") kimageformats_read_tests(
kimageformats_read_tests( heif
heif )
) # because the plug-ins use RGB->YUV conversion which sometimes results in 1 value difference.
endif() kimageformats_write_tests(FUZZ 1
if (KIMAGEFORMATS_HEIF_TEST STREQUAL "ALL") heif-nodatacheck-lossless
# because the plug-ins use RGB->YUV conversion which sometimes results in 1 value difference. )
kimageformats_write_tests(FUZZ 1
heif-nodatacheck-lossless
)
endif()
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.17.0") 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
kimageformats_read_tests(FUZZ 1 hej2
hej2 )
) kimageformats_write_tests(FUZZ 1
endif() hej2-nodatacheck-lossless
if (KIMAGEFORMATS_HEJ2_TEST STREQUAL "ALL") )
kimageformats_write_tests(FUZZ 1
hej2-nodatacheck-lossless
)
endif()
endif() endif()
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.6") if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.6")
if (KIMAGEFORMATS_AVCI_TEST STREQUAL "ALL") kimageformats_read_tests(FUZZ 4
kimageformats_read_tests(FUZZ 4 avci
avci )
)
endif()
endif() endif()
endif() endif()

View File

@@ -48,7 +48,7 @@ Depending on the format, you can specify the following additional options.
- `--help`: Displays help on commandline options. - `--help`: Displays help on commandline options.
- `--fuzz <max>`: The fuzziness. Used to add some deviation in ARGB data - `--fuzz <max>`: The fuzziness. Used to add some deviation in ARGB data
(normally used on lossy codec). (nornally used on lossy codec).
- `--perceptive-fuzz`: Used to scale dynamically the fuzziness based on - `--perceptive-fuzz`: Used to scale dynamically the fuzziness based on
the alpha channel value. This is useful on images with pre-multiplied and the alpha channel value. This is useful on images with pre-multiplied and
small alphas. Qt can use different roundings based on optimizations resulting small alphas. Qt can use different roundings based on optimizations resulting

View File

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

View File

@@ -18,11 +18,6 @@
# 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
@@ -180,7 +175,6 @@ HANDLER_TYPES="ANIHandler ani
RAWHandler raw RAWHandler raw
RGBHandler rgb RGBHandler rgb
ScitexHandler sct ScitexHandler sct
TIMHandler tim
TGAHandler tga TGAHandler tga
XCFHandler xcf" 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 /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 $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. # -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: Usage:
python infra/helper.py build_image kimageformats python infra/helper.py build_image kimageformats
python infra/helper.py build_fuzzers --sanitizer undefined|address|memory 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> #include <QBuffer>
@@ -52,7 +52,6 @@
#include "raw_p.h" #include "raw_p.h"
#include "rgb_p.h" #include "rgb_p.h"
#include "sct_p.h" #include "sct_p.h"
#include "tim_p.h"
#include "tga_p.h" #include "tga_p.h"
#include "xcf_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/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.13.1 https://aomedia.googlesource.com/aom git clone --depth 1 -b v3.12.0 https://aomedia.googlesource.com/aom
git clone --depth 1 -b v1.3.0 https://github.com/AOMediaCodec/libavif.git 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 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 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/LibRaw/LibRaw
git clone --depth 1 https://github.com/mircomir/jxrlib.git git clone --depth 1 https://github.com/mircomir/jxrlib.git
git clone --depth 1 -b v2.6.0 https://github.com/cisco/openh264.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

View File

@@ -1,15 +0,0 @@
[
{
"fileName" : "ps2026_testcard_rgb.png",
"colorSpace" : {
"description" : "sRGB build-in (Profilo RGB lineare)",
"primaries" : "SRgb",
"transferFunction" : "Linear",
"gamma" : 1
},
"resolution" : {
"dotsPerMeterX" : 3937,
"dotsPerMeterY" : 3937
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -2,7 +2,7 @@
{ {
"fileName" : "rgb-gimp.png", "fileName" : "rgb-gimp.png",
"colorSpace" : { "colorSpace" : {
"description" : "Embedded RGB (linear)", "description" : "",
"primaries" : "Custom", "primaries" : "Custom",
"transferFunction" : "Linear", "transferFunction" : "Linear",
"gamma" : 1 "gamma" : 1

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

Binary file not shown.

View File

@@ -14,7 +14,7 @@
}, },
{ {
"key" : "Software" , "key" : "Software" ,
"value" : "LIFE Pro 2.20.35" "value" : "LIFE Pro 2.18.10"
}, },
{ {
"key" : "Altitude", "key" : "Altitude",
@@ -32,10 +32,6 @@
"key" : "Description", "key" : "Description",
"value" : "TV broadcast test image." "value" : "TV broadcast test image."
}, },
{
"key" : "HostComputer",
"value" : "Windows 11 Enterprise (25H2)"
},
{ {
"key" : "Latitude", "key" : "Latitude",
"value" : "44.6478" "value" : "44.6478"

View File

@@ -2,8 +2,8 @@
{ {
"fileName" : "32bit_grayscale.png", "fileName" : "32bit_grayscale.png",
"colorSpace" : { "colorSpace" : {
"description" : "RGB emulation of \"Linear Grayscale Profile\"", "description" : "Linear Grayscale Profile",
"colorModel" : "Rgb", "colorModel" : "Gray",
"primaries" : "Custom", "primaries" : "Custom",
"transferFunction" : "Linear", "transferFunction" : "Linear",
"gamma" : 1 "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"; QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
// checks if the format has read capability
if (!formats.contains(format)) { if (!formats.contains(format)) {
QTextStream(stdout) << "FAIL : current configuration is missing necessary decoder(s) for " << suffix << "!\n" 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 1; << "Finished basic read tests for " << suffix << " images *********\n";
return 0;
}
} }
const QFileInfoList lstImgDir = imgdir.entryInfoList(); const QFileInfoList lstImgDir = imgdir.entryInfoList();
// Launch 3 runs for each test: // Launch 2 runs for each test: first run on a random access device, second run on a sequential access device
// - first run on a random access device with allocation limit set to 256 MiB. for (int seq = 0; seq < 2; ++seq) {
// - 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;
if (seq) { if (seq) {
QTextStream(stdout) << "* Run on SEQUENTIAL ACCESS device\n"; QTextStream(stdout) << "* Run on SEQUENTIAL ACCESS device\n";
} else { } 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) { for (const QFileInfo &fi : lstImgDir) {
TemplateImage timg(fi); TemplateImage timg(fi);
@@ -342,7 +338,12 @@ int main(int argc, char **argv)
OptionTest optionTest; OptionTest optionTest;
if (!optionTest.store(&inputReader)) { if (!optionTest.store(&inputReader)) {
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": error while reading options\n"; 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; continue;
} }

View File

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

View File

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

View File

@@ -13,18 +13,14 @@
"key" : "ModificationDate", "key" : "ModificationDate",
"value" : "2025-02-14T15:58:44+01:00" "value" : "2025-02-14T15:58:44+01:00"
}, },
{
"key" : "Software" ,
"value" : "Adobe Photoshop 26.2 (Windows)"
},
{ {
"key" : "Altitude", "key" : "Altitude",
"value" : "34" "value" : "34"
}, },
{
"key" : "Title",
"value" : "A test"
},
{
"key" : "Software",
"value" : "KImageFormats write test"
},
{ {
"key" : "Author", "key" : "Author",
"value" : "KDE Project" "value" : "KDE Project"
@@ -49,10 +45,6 @@
"key" : "LensModel", "key" : "LensModel",
"value" : "A1234" "value" : "A1234"
}, },
{
"key" : "LensSerialNumber",
"value" : "S/N:1234567"
},
{ {
"key" : "Longitude", "key" : "Longitude",
"value" : "10.9254" "value" : "10.9254"
@@ -64,50 +56,6 @@
{ {
"key" : "Model", "key" : "Model",
"value" : "KImageFormats" "value" : "KImageFormats"
},
{
"key" : "SerialNumber",
"value" : "S/N:7654321"
},
{
"key" : "Speed",
"value" : "13.2"
},
{
"key" : "DigitalZoomRatio",
"value" : "3.4"
},
{
"key" : "ExposureMode",
"value" : "2"
},
{
"key" : "ExposureProgram",
"value" : "6"
},
{
"key" : "ExposureTime",
"value" : "0.004"
},
{
"key" : "Flash",
"value" : "16"
},
{
"key" : "FNumber",
"value" : "1.6"
},
{
"key" : "FocalLength",
"value" : "5.96"
},
{
"key" : "ISOSpeedRatings",
"value" : "50"
},
{
"key" : "WhiteBalance",
"value" : "1"
} }
], ],
"resolution" : { "resolution" : {

View File

@@ -41,10 +41,6 @@
"key" : "LensModel", "key" : "LensModel",
"value" : "A1234" "value" : "A1234"
}, },
{
"key" : "LensSerialNumber",
"value" : "S/N:1234567"
},
{ {
"key" : "Longitude", "key" : "Longitude",
"value" : "10.9254" "value" : "10.9254"
@@ -56,50 +52,6 @@
{ {
"key" : "Model", "key" : "Model",
"value" : "KImageFormats" "value" : "KImageFormats"
},
{
"key" : "SerialNumber",
"value" : "S/N:7654321"
},
{
"key" : "Speed",
"value" : "13.2"
},
{
"key" : "DigitalZoomRatio",
"value" : "3.4"
},
{
"key" : "ExposureMode",
"value" : "2"
},
{
"key" : "ExposureProgram",
"value" : "6"
},
{
"key" : "ExposureTime",
"value" : "0.004"
},
{
"key" : "Flash",
"value" : "16"
},
{
"key" : "FNumber",
"value" : "1.6"
},
{
"key" : "FocalLength",
"value" : "5.96"
},
{
"key" : "ISOSpeedRatings",
"value" : "50"
},
{
"key" : "WhiteBalance",
"value" : "1"
} }
], ],
"resolution" : { "resolution" : {

View File

@@ -62,7 +62,7 @@ void setOptionalInfo(QImage &image, const QString &suffix)
// Set metadata // Set metadata
auto meta = obj.value("metadata").toArray(); auto meta = obj.value("metadata").toArray();
for (auto &&jv : meta) { for (auto jv : meta) {
auto obj = jv.toObject(); auto obj = jv.toObject();
auto key = obj.value("key").toString(); auto key = obj.value("key").toString();
auto val = obj.value("value").toString(); auto val = obj.value("value").toString();
@@ -106,7 +106,7 @@ bool checkOptionalInfo(QImage &image, const QString &suffix)
// Test metadata // Test metadata
auto meta = obj.value("metadata").toArray(); auto meta = obj.value("metadata").toArray();
for (auto &&jv : meta) { for (auto jv : meta) {
auto obj = jv.toObject(); auto obj = jv.toObject();
auto key = obj.value("key").toString(); auto key = obj.value("key").toString();
auto val = obj.value("value").toString(); auto val = obj.value("value").toString();
@@ -319,9 +319,11 @@ QImage formatSourceImage(const QImage::Format &format)
image = QImage(QStringLiteral("%1/rgba16.png").arg(folder)); image = QImage(QStringLiteral("%1/rgba16.png").arg(folder));
break; break;
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
case QImage::Format_CMYK8888: case QImage::Format_CMYK8888:
image = QImage(QStringLiteral("%1/cmyk8.tif").arg(folder)); image = QImage(QStringLiteral("%1/cmyk8.tif").arg(folder));
break; break;
#endif
default: default:
break; break;
@@ -380,7 +382,12 @@ int formatTest(const QString &suffix, bool createTemplates)
QBuffer buffer(&ba); QBuffer buffer(&ba);
auto writtenImage = QImageReader(&buffer, suffix.toLatin1()).read(); auto writtenImage = QImageReader(&buffer, suffix.toLatin1()).read();
if (writtenImage.isNull()) { 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"; QTextStream(stdout) << "FAIL : error while reading the image " << formatName << "\n";
continue; continue;
} }
@@ -634,17 +641,23 @@ int main(int argc, char **argv)
auto suffix = args.at(0); auto suffix = args.at(0);
// skip test if configuration is obviously incomplete // skip test if libheif configuration is obviously incomplete
QByteArray format = suffix.toLatin1(); QByteArray format = suffix.toLatin1();
const QList<QByteArray> read_formats = QImageReader::supportedImageFormats(); 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(); 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"; if (!read_formats.contains(format)) {
return 1; 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 // 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) kimageformats_add_plugin(kimg_tga SOURCES tga.cpp microexif.cpp scanlineconverter.cpp)
################################## ##################################

View File

@@ -5,7 +5,6 @@
*/ */
#include "ani_p.h" #include "ani_p.h"
#include "util_p.h"
#include <QImage> #include <QImage>
#include <QLoggingCategory> #include <QLoggingCategory>
@@ -102,7 +101,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 || frameSize > quint32(kMaxQVectorSize)) { if (!frameSize) {
return false; return false;
} }
@@ -418,9 +417,6 @@ 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) {

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; QImage::Format resultformat;
if (resultdepth > 8) { if (m_decoder->image->depth > 8) {
if (loadalpha) { if (loadalpha) {
resultformat = QImage::Format_RGBA64; resultformat = QImage::Format_RGBA64;
} else { } else {
@@ -299,7 +293,9 @@ bool QAVIFHandler::decode_one_frame()
colorspace = QColorSpace::fromIccProfile(icc_data); colorspace = QColorSpace::fromIccProfile(icc_data);
if (!colorspace.isValid()) { if (!colorspace.isValid()) {
qCWarning(LOG_AVIFPLUGIN, "AVIF image has Qt-unsupported or invalid ICC profile!"); 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) { if (colorspace.colorModel() == QColorSpace::ColorModel::Cmyk) {
qCWarning(LOG_AVIFPLUGIN, "CMYK ICC profile is not extected for AVIF, discarding the ICCprofile!"); qCWarning(LOG_AVIFPLUGIN, "CMYK ICC profile is not extected for AVIF, discarding the ICCprofile!");
colorspace = QColorSpace(); colorspace = QColorSpace();
@@ -329,6 +325,7 @@ bool QAVIFHandler::decode_one_frame()
} }
} }
} }
#endif
} else { } else {
float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f}; 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 // outPrimaries: rX, rY, gX, gY, bX, bY, wX, wY
@@ -363,12 +360,14 @@ bool QAVIFHandler::decode_one_frame()
case 13: case 13:
q_trc = QColorSpace::TransferFunction::SRgb; q_trc = QColorSpace::TransferFunction::SRgb;
break; break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16: /* AVIF_TRANSFER_CHARACTERISTICS_PQ */ case 16: /* AVIF_TRANSFER_CHARACTERISTICS_PQ */
q_trc = QColorSpace::TransferFunction::St2084; q_trc = QColorSpace::TransferFunction::St2084;
break; break;
case 18: /* AVIF_TRANSFER_CHARACTERISTICS_HLG */ case 18: /* AVIF_TRANSFER_CHARACTERISTICS_HLG */
q_trc = QColorSpace::TransferFunction::Hlg; q_trc = QColorSpace::TransferFunction::Hlg;
break; break;
#endif
default: default:
qCWarning(LOG_AVIFPLUGIN, "CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.", qCWarning(LOG_AVIFPLUGIN, "CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
m_decoder->image->colorPrimaries, 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 (q_trc != QColorSpace::TransferFunction::Custom) { // we create new colorspace using Qt
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
if (loadgray) { if (loadgray) {
colorspace = QColorSpace(whitePoint, q_trc, q_trc_gamma); colorspace = QColorSpace(whitePoint, q_trc, q_trc_gamma);
} else { } else {
#endif
switch (m_decoder->image->colorPrimaries) { switch (m_decoder->image->colorPrimaries) {
/* AVIF_COLOR_PRIMARIES_BT709 */ /* AVIF_COLOR_PRIMARIES_BT709 */
case 0: case 0:
@@ -388,9 +389,6 @@ 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);
@@ -399,7 +397,9 @@ bool QAVIFHandler::decode_one_frame()
colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma); colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
break; break;
} }
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
} }
#endif
} }
if (!colorspace.isValid()) { if (!colorspace.isValid()) {
@@ -414,7 +414,7 @@ bool QAVIFHandler::decode_one_frame()
rgb.maxThreads = m_decoder->maxThreads; rgb.maxThreads = m_decoder->maxThreads;
#endif #endif
if (resultdepth > 8) { if (m_decoder->image->depth > 8) {
rgb.depth = 16; rgb.depth = 16;
rgb.format = AVIF_RGB_FORMAT_RGBA; rgb.format = AVIF_RGB_FORMAT_RGBA;
@@ -513,12 +513,21 @@ bool QAVIFHandler::decode_one_frame()
#else #else
switch (m_decoder->image->imir.axis) { switch (m_decoder->image->imir.axis) {
#endif #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 case 0: // top-to-bottom
result = result.flipped(Qt::Vertical); result = result.flipped(Qt::Vertical);
break; break;
case 1: // left-to-right case 1: // left-to-right
result = result.flipped(Qt::Horizontal); result = result.flipped(Qt::Horizontal);
break; break;
#endif
} }
} }
@@ -734,65 +743,22 @@ 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;
break; break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084: case QColorSpace::TransferFunction::St2084:
avif->transferCharacteristics = (avifTransferCharacteristics)16; avif->transferCharacteristics = (avifTransferCharacteristics)16;
break; break;
case QColorSpace::TransferFunction::Hlg: case QColorSpace::TransferFunction::Hlg:
avif->transferCharacteristics = (avifTransferCharacteristics)18; avif->transferCharacteristics = (avifTransferCharacteristics)18;
break; break;
#endif
default: default:
/* 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
@@ -833,6 +799,7 @@ bool QAVIFHandler::write(const QImage &image)
} }
} }
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
QImage tmpcolorimage; QImage tmpcolorimage;
auto cs = image.colorSpace(); auto cs = image.colorSpace();
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) { if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
@@ -847,6 +814,9 @@ bool QAVIFHandler::write(const QImage &image)
} else { } else {
tmpcolorimage = image.convertToFormat(tmpformat); tmpcolorimage = image.convertToFormat(tmpformat);
} }
#else
QImage tmpcolorimage = image.convertToFormat(tmpformat);
#endif
avifPixelFormat pixel_format = AVIF_PIXEL_FORMAT_YUV420; avifPixelFormat pixel_format = AVIF_PIXEL_FORMAT_YUV420;
if (m_quality >= KIMG_AVIF_QUALITY_HIGH) { if (m_quality >= KIMG_AVIF_QUALITY_HIGH) {
@@ -877,10 +847,6 @@ 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;
@@ -910,12 +876,14 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_SRGB */ /* AVIF_TRANSFER_CHARACTERISTICS_SRGB */
transfer_to_save = (avifTransferCharacteristics)13; transfer_to_save = (avifTransferCharacteristics)13;
break; break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case QColorSpace::TransferFunction::St2084: case QColorSpace::TransferFunction::St2084:
transfer_to_save = (avifTransferCharacteristics)16; transfer_to_save = (avifTransferCharacteristics)16;
break; break;
case QColorSpace::TransferFunction::Hlg: case QColorSpace::TransferFunction::Hlg:
transfer_to_save = (avifTransferCharacteristics)18; transfer_to_save = (avifTransferCharacteristics)18;
break; break;
#endif
default: default:
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */ /* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
transfer_to_save = (avifTransferCharacteristics)2; transfer_to_save = (avifTransferCharacteristics)2;
@@ -951,12 +919,14 @@ bool QAVIFHandler::write(const QImage &image)
case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.8f)); tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 2.8f));
break; break;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
case 16: case 16:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::St2084)); tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::St2084));
break; break;
case 18: case 18:
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::Hlg)); tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::Hlg));
break; break;
#endif
default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb)); tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
transfer_to_save = (avifTransferCharacteristics)13; 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 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 SPDX-License-Identifier: LGPL-2.0-or-later
*/ */
@@ -10,7 +10,6 @@
* - 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
@@ -37,7 +36,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
#define LIST_CHUNK QByteArray("LIST") #define LIST_CHUNK QByteArray("LIST")
#define PROP_CHUNK QByteArray("PROP") #define PROP_CHUNK QByteArray("PROP")
// Main chunks (Maya) // Main chuncks (Maya)
#define CAT4_CHUNK QByteArray("CAT4") // 4 byte alignment #define CAT4_CHUNK QByteArray("CAT4") // 4 byte alignment
#define FOR4_CHUNK QByteArray("FOR4") #define FOR4_CHUNK QByteArray("FOR4")
#define LIS4_CHUNK QByteArray("LIS4") #define LIS4_CHUNK QByteArray("LIS4")
@@ -56,17 +55,7 @@ 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")
@@ -90,18 +79,14 @@ 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")
@@ -160,7 +145,7 @@ public:
/*! /*!
* \brief bytes * \brief bytes
* \return The size (in bytes) of the chunk data. * \return The size (in bytes) of the chunck data.
*/ */
quint32 bytes() const; quint32 bytes() const;
@@ -365,12 +350,6 @@ protected:
static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr); static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr);
/*!
* \brief dataBytes
* \return Maximum usable cache data size.
*/
quint32 dataBytes() const;
private: private:
char _chunkId[4]; char _chunkId[4];
@@ -439,8 +418,7 @@ 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. */
Vdat = 2, /**< Image data are VDAT compressed. */ RgbN8 = 4 /**< RGB8/RGBN compresson. */
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. */
@@ -772,11 +750,10 @@ public:
/*! /*!
* \brief readStride * \brief readStride
* \param d The device. * \param d The device.
* \param y The current scanline.
* \param header The bitmap header. * \param header The bitmap header.
* \param y The current scanline.
* \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.
@@ -793,6 +770,8 @@ 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().
@@ -803,7 +782,6 @@ 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);
@@ -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; 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;
}; };
@@ -888,7 +864,7 @@ public:
/*! /*!
* \brief transformation * \brief transformation
* \return The image 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; virtual QImageIOHandler::Transformation transformation() const;
@@ -939,13 +915,6 @@ 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;
}; };
@@ -1382,32 +1351,6 @@ 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
*/ */
@@ -1451,500 +1394,6 @@ 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 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 *** * *** UNDOCUMENTED CHUNKS ***

View File

@@ -20,7 +20,7 @@
#include <cmath> #include <cmath>
#ifndef DDS_DISABLE_STRIDE_ALIGNMENT #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 // #define DDS_DISABLE_STRIDE_ALIGNMENT
#endif #endif
@@ -2120,8 +2120,10 @@ bool writeL8(const QImage &outImage, QDataStream &s)
} }
ScanLineConverter slc(QImage::Format_Grayscale8); ScanLineConverter slc(QImage::Format_Grayscale8);
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if(outImage.colorSpace().isValid()) if(outImage.colorSpace().isValid())
slc.setTargetColorSpace(QColorSpace(QPointF(0.3127, 0.3291), QColorSpace::TransferFunction::SRgb)); slc.setTargetColorSpace(QColorSpace(QPointF(0.3127, 0.3291), QColorSpace::TransferFunction::SRgb));
#endif
for (int y = 0, h = outImage.height(); y < h; ++y) { for (int y = 0, h = outImage.height(); y < h; ++y) {
const quint8 *scanLine = reinterpret_cast<const quint8*>(slc.convertedScanLine(outImage, 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")); const QString gsExec = QStandardPaths::findExecutable(QStringLiteral("gs"));
if (gsExec.isEmpty()) { 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; return false;
} }

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