Compare commits

...

80 Commits

Author SHA1 Message Date
Xaver Hugl
888bca7387 cmake: add cmake config
That way, other projects can declare to have a runtime dependency on KImageFormats
2025-05-21 17:39:44 +02:00
Mirco Miranda
e3aefd2aa1 JXR: Restore device position after reading options 2025-05-14 02:50:03 +02:00
Mirco Miranda
aa8134ee0d README.md: minor fixes and improvements 2025-05-06 07:33:27 +02:00
Laurent Montel
9f09473aa0 It compiles fine without kf_6_13 deprecated methods 2025-05-04 21:31:49 +02:00
Mirco Miranda
62eb1d28cb Add README about autotests 2025-05-03 11:01:46 +02:00
Nicolas Fella
15bece40ec Update version to 6.15.0 2025-05-02 17:10:02 +02:00
Nicolas Fella
1b3d2afbe3 Update dependency version to 6.14.0 2025-05-02 16:02:43 +02:00
Mirco Miranda
850068c1dc JXR: fix compilation error on 32-bit systems 2025-04-22 08:01:02 +02:00
Mirco Miranda
6bf38ea638 Improved EXIF V3 compatibility (2)
This patch improve the string read/write in case of non ASCII encoding.
- When reading, checks for UTF-8 text even on ASCII data type. If it fails, Latin1 converter is used.
- When writing using V3 specs, a better check is done to identify 7-bit ASCII text.

Related to MR !358
2025-04-21 11:29:13 +00:00
Alessandro Astone
2adca7c0ca jxr: Use qsizetype for image size variables
Fixes type mismatch on 32-bit architectures.

/builddir/build/BUILD/kf6-kimageformats-6.13.0-build/kimageformats-6.13.0/src/imageformats/jxr.cpp: In member function ‘virtual bool JXRHandler::read(QImage*)’:
/builddir/build/BUILD/kf6-kimageformats-6.13.0-build/kimageformats-6.13.0/src/imageformats/jxr.cpp:994:88: error: no matching function for call to ‘min(qint64&, qsizetype)’
  994 |                 std::memcpy(img.scanLine(y), ba.data() + convStrideSize * y, (std::min)(convStrideSize, img.bytesPerLine()));
      |                                                                              ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2025-04-21 10:07:00 +02:00
Daniel Novomeský
dd69fdaea9 lib prefix on Android
Qt's original qtimageformats plug-ins use lib prefix too,
without the lib prefix, the image plug-ins don't work on Android.
2025-04-19 14:16:18 +00:00
Mirco Miranda
ae62ea3dfc Improved EXIF V3 compatibility
EXIF specs V3 added the UTF-8 data type. The MicroExif class now allows serializations to choose whether to support the V2 or V3 format. To maximize compatibility with old readers, even when V3 is set, the ASCII data type is used if possible.

The JXR plugin, based on TIFF V6 container, does not allow to use the V3 format (it does not recognize the UTF-8 data type) and therefore V2 has been forced. For all other plugins using MicroExif, it is now possible to save, e.g., descriptions in Japanese.

Please note that this patch is also a bugfix: when saving, version 3 was set but the strings were always saved as ASCII.
2025-04-18 13:53:12 +00:00
Nicolas Fella
9c47845f15 Update version to 6.14.0 2025-04-10 19:53:58 +02:00
Volker Krause
7c7fa73020 Remove conditions for no longer supported Qt versions 2025-04-08 18:46:13 +02:00
Albert Astals Cid
92e4271e84 GIT_SILENT Upgrade Qt6 version requirement to 6.7.0. 2025-04-07 10:13:41 +02:00
Laurent Montel
6f588c6fd3 Add missing include mocs 2025-04-03 07:34:17 +02:00
Laurent Montel
a182478e2c It compiles fine without qt6.9 deprecated methods 2025-03-23 22:52:05 +00:00
Mirco Miranda
4026f41890 PSD: use linear profile on float images
On float images, if not color profile is present, a linear one should be chosen. Photoshop works on 32-bit images in a linear color space.
2025-03-23 22:31:23 +00:00
Laurent Montel
bef2b9168f It compiles fine without kf6.12 deprecated methods 2025-03-22 06:47:20 +01:00
Daniel Novomeský
473f5d9847 Write tests for hej2 format 2025-03-16 21:31:46 +01:00
Daniel Novomeský
9bee29cc01 heif: enable saving of hej2 format 2025-03-16 18:37:48 +01:00
Nicolas Fella
cdf3be3af1 Update dependency version to 6.13.0 2025-03-14 21:31:42 +01:00
Albert Astals Cid
752b18a42c CI: Enable heif so we make sure it compiles 2025-03-12 16:17:29 +00:00
Daniel Novomeský
97a1ea181c writetest: special handling for HEIF format 2025-03-12 16:41:39 +01:00
Daniel Novomeský
64a43fb04f readtest: special handling for HEIF format 2025-03-12 16:17:59 +01:00
Daniel Novomeský
6821c29819 heif: disable AVCI decoder for libheif before 1.19.6 2025-03-12 13:26:42 +01:00
Daniel Novomeský
e4d95c03fa SKIP tests when libheif configuration is incomplete 2025-03-10 22:01:14 +01:00
Daniel Novomeský
afa8ed1a5d heif: enable reading images with native 16 bit depth 2025-03-10 19:42:34 +01:00
Mirco Miranda
245c835d92 Use of heif_context_add_XMP_metadata instead
heif_context_add_XMP_metadata2
2025-03-09 10:44:18 +01:00
Nicolas Fella
b2663d2651 Update dependency version to 6.13.0 2025-03-07 19:00:23 +01:00
Nicolas Fella
35ab37c628 Update dependency version to 6.12.0 2025-03-07 15:09:18 +01:00
Albert Astals Cid
b28baa4a1e sct: qRound with param bigger than max int is undefined
oss-fuzz/399667098
2025-03-04 06:33:52 +00:00
Albert Astals Cid
5d2540c135 sct: Use height instead of width when calculating dotsPerMeterY 2025-03-04 06:29:58 +00:00
Mirco Miranda
25cc8bc262 MicroExif: search for the TIFF signature 2025-03-03 09:17:56 +01:00
Mirco Miranda
7742537f8c MicroExif: API improvements and minor bugfixes 2025-03-02 13:34:02 +00:00
Mirco Miranda
d3386bbf50 Fix compilation error 2025-03-02 13:49:25 +01:00
Mirco Miranda
e77986c7e0 Added support for resolution and EXIF/XMP metadata to HEIF 2025-03-02 08:03:28 +00:00
Mirco Miranda
c0261f4926 JXR: Added rotation (transformation) support
- Full rotation support on load and save.
- Improve also Windows compatibility by converting RGB32 to BGR32 on saving

Images saved with orientation are displayed correctly by Windows Explorer (which natively supports JXR files):

![_BC374A2E-7970-4B72-87BD-68DD3D8FB7AA_](/uploads/2268aa3066d82a4f97d026a64f2b70c2/_BC374A2E-7970-4B72-87BD-68DD3D8FB7AA_.png){width=597 height=259}
2025-02-25 21:37:17 +00:00
Mirco Miranda
e5cf9caac5 JXR: added support to EXIF metadata
Improved metadata support via EXIF ​​metadata. Since JXR is based on a TIFF container, EXIF ​​data is read directly from the file so it always works (even with versions of libjxr that don't have the metadata reading API).

It also solves the following issues:
- Incorrect date format on saved JXR files (was saved in ISO format instead of `yyyy:MM:dd HH:mm:ss`).
- Incorrect date type setting in EXIF ​​data: the `DateTime` tag should be updated on every save (verified by GIMP and Photoshop). Our `CreationDate` metadata is the equivalent of the EXIF ​​`DateTimeOriginal` tag.

Closes #22
2025-02-23 00:38:27 +00:00
Mirco Miranda
90d4256f3d AVIF: added support to XMP and EXIF metadata
Allow to load/save info about:
- GPS info (latitude, longitude, altitude)
- Various text info (title, description, author, copyright, etc...)
- Image resolution

The compatibility of the modifications has been tested with GIMP.
2025-02-19 11:56:19 +00:00
Mirco Miranda
bb1c6aab9e Added pixel limit detected by experimental tests 2025-02-17 08:54:49 +01:00
Daniel Novomeský
74a734efed jxl: fix build with Qt before 6.8.0 2025-02-15 16:16:10 +01:00
Mirco Miranda
e9fa4b6610 JP2: Disable ICC profile writing when saving an image with OpenJPEG V2.5.3 or lesser and improve the format detection on reading. 2025-02-12 06:45:21 +00:00
Daniel Novomeský
36a6ef7d78 heif: improve handling of grayscale ICC profiles 2025-02-10 16:59:49 +00:00
Daniel Novomeský
9fd6896cec Improve printing details when writetest fails 2025-02-10 16:59:49 +00:00
Daniel Novomeský
9b14e752db Update HEIF writetest templates 2025-02-10 16:59:49 +00:00
Laurent Montel
90a2e3b412 GIT_SILENT: it compiles fine without kf6.11 deprecated methods 2025-02-10 06:46:22 +01:00
Mirco Miranda
b28cf4c352 Added JXL to CMYK formats 2025-02-07 15:55:23 +01:00
Nicolas Fella
b536ec4a5e Update version to 6.12.0 2025-02-07 15:38:22 +01:00
Nicolas Fella
7d7b295ac2 Update dependency version to 6.11.0 2025-02-07 14:47:25 +01:00
Daniel Novomeský
397957a976 jxl: refactor image saving, native CMYK support 2025-02-07 10:38:46 +00:00
Mirco Miranda
18a729f7a1 Harmonized RAW mime types
Modifications based on information found online and the samples [here](https://raw.pixls.us/data).

Created a [MR for shared-mime-info](https://gitlab.freedesktop.org/xdg/shared-mime-info/-/merge_requests/341) with the missing mime types used in this MR.

Closes #19 

NOTE: for the following formats the images are not loaded by LibRAW (so I removed them): ari (ARRI), cap (Casio), lri (Light).
2025-02-07 10:38:26 +00:00
Daniel Novomeský
7a74b50d64 imageconverter: possibility to set image quality 2025-02-04 14:42:44 +01:00
Daniel Novomeský
0a06a07fa4 Print more details when writetest fails 2025-02-04 10:09:12 +00:00
Mirco Miranda
e89408b426 Fix RAW mime type 2025-01-31 08:32:23 +01:00
Daniel Novomeský
8a05711e99 jxl: refactor image loading 2025-01-29 17:02:51 +00:00
Laurent Montel
d6534f0e68 Add xml/yaml linting 2025-01-29 06:57:55 +01:00
Albert Astals Cid
f608441b03 Fix jp2 and hdr plugin json definition
and add a check that the json files are well-formed

i.e. they have the same number of keys than of mimetypes
2025-01-24 14:48:09 +00:00
Mirco Miranda
49060026b7 Read test: added perceptive fuzziness
Added a new parameter to the read tests called `perceptive-fuzz`.
The parameter, when active, modifies the fuzziness value based on the alpha value of the pixel. The more transparent the pixel, the more the fuzziness value increases.

We have found that some image manipulation functions give different results depending on the architecture (we think it is differences in rounding). These differences can become problematic with small alpha values ​​when there are several image conversions from normal alpha to premultiplied alpha (and vice versa).
In particular, the offending plugin is XCF.

The parameter should be set if and only if necessary. CMakeList has not been modified to allow it to be enabled on all format images (you can still try it from the command line). To use it, you need to set it in the JSON file of the image that has problems (after careful analysis).

More info about the issue on #18 

This MR also fixes a bug in `fazzeq()`: it only compared 1/4 of the image.

Below is the same XCF image rendered on AMD64 and PowerPC:

- AMD64:

![image](/uploads/7815ee49fac9b06d08bf1e0e3879f16e/image.png)

- PowerPC:

![image](/uploads/d7432902d638f6caf9589ebb4ad99827/image.png)

The image is visually the same because the differences are with very low alpha and therefore are negligible. The patch proposed with this MR is useful in these cases.
2025-01-24 13:07:32 +00:00
Mirco Miranda
424e7a75de Modified PCX mime type according to IANA db 2025-01-23 08:00:37 +01:00
Mirco Miranda
be534ea06e PSD: Alpha detection improvements
Small fix to improve alpha detection by checking also the Alpha Identifiers.
2025-01-20 22:30:23 +00:00
Laurent Montel
baaf1093a1 GIT_SILENT: it compiles fine without kf6.10 deprecated methods 2025-01-20 09:53:06 +00:00
Mirco Miranda
e83458a5d8 PSD: improved option support
Added support for the following options:
- `ImageTransformation`: uses EXIF data (same behaviour of Photoshop and GIMP)
- `Description`: uses EXIF data
- `ImageFormat` 

Closes #17
2025-01-18 22:32:15 +00:00
Mirco Miranda
873ec1bb5f More metadata read tests
Adds some metadata/read resolution tests without adding new images.
2025-01-16 23:03:37 +00:00
Mirco Miranda
287a447095 Fix use of deprecated methods 2025-01-16 14:02:44 +01:00
Mirco Miranda
ebb9c1ec18 Metadata and image resolution write test
The goal of MR is to control the correct saving of metadata and resolution in plugins that support them.

- Modified the basic write test to verify that resolution and metadata are saved correctly.
- Verifies the correct functioning of MicroExif in plugins that use it to save metadata.
- EXR: fixed wrong vertical resolution (error found with this MR).
- Added EXR, JXR, JXL, PCX metadata test.
2025-01-16 07:14:27 +00:00
Mirco Miranda
ac3591c7ea PSD: added support to EXIF metadata 2025-01-15 23:26:02 +00:00
Mirco Miranda
a89367dde6 JXR: set max XMP size to 4MiB 2025-01-15 20:36:28 +00:00
Albert Astals Cid
65a587afad CI: Add linux-qt6-next build 2025-01-15 19:16:26 +01:00
Mirco Miranda
5f92bcbf26 DDS: Fix warning in qfloat16 and test failure on PowerPC
Fixes the following warning:
```
/home/daniel/kimageformats/src/imageformats/dds.cpp: In function ‘qfloat16 readFloat16(QDataStream&)’:
/home/daniel/kimageformats/src/imageformats/dds.cpp:1037:11: warning: ‘void* memcpy(void*, const void*, size_t)’ copying an object of non-trivial type ‘class qfloat16’ from an array of ‘quint16’ {aka ‘short unsigned int’} [-Wclass-memaccess]
 1037 |     memcpy(&f16, &rawData, sizeof(rawData));
      |     ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/qt6/QtCore/qmetatype.h:14,
                 from /usr/include/qt6/QtCore/qobject.h:18,
                 from /usr/include/qt6/QtCore/qiodevice.h:10,
                 from /usr/include/qt6/QtGui/qimageiohandler.h:9,
                 from /usr/include/qt6/QtGui/QImageIOPlugin:1,
                 from /home/daniel/kimageformats/src/imageformats/dds_p.h:13,
                 from /home/daniel/kimageformats/src/imageformats/dds.cpp:12:
/usr/include/qt6/QtCore/qfloat16.h:46:7: note: ‘class qfloat16’ declared here
   46 | class qfloat16
      |       ^~~~~~~~

```

Should also fixes the following failed tests under PowerPC (32-bits):
```
INFO : rgba16dx10.dds: converting rgba16dx10.dds from RGBA16FPx4 to ARGB32
FAIL : rgba16dx10.dds: differs from rgba16dx10.png
       expected data written to rgba16dx10.dds-expected.data
       actual data written to rgba16dx10.dds-actual.data
```
```
INFO : rgba_f16.dds: converting rgba_f16.dds from RGBA16FPx4 to ARGB32
FAIL : rgba_f16.dds: differs from rgba_f16.png
       expected data written to rgba_f16.dds-expected.data
       actual data written to rgba_f16.dds-actual.data
```
2025-01-15 17:45:57 +00:00
Mirco Miranda
ae00c110f2 JXL: Resolution and metadata support via EXIF
- Added a class to read and write minimal exif metadata.
- JXL plugin uses EXIF metadata to load/save the resolution of the image (like GIMP).
- JXL plugin uses EXIF metadata to set/store text metadata and date/time.
- Enable info display in Dolphin (JXL File -> Properties -> Details on a JXL file, see image below).
- Enabled read test to check also image metadata and resolution.

![_52C044E4-1BA9-4D84-AC0A-B834CDAF72D8_](/uploads/f1649c2b506bf61a5f5488da0d4a4534/_52C044E4-1BA9-4D84-AC0A-B834CDAF72D8_.png){width=401 height=357}
2025-01-15 06:12:07 +00:00
Albert Astals Cid
f39ca9dc9b ani: Read chunk elements one at a time instead all at once
This way if the file is malformed and there's not that many elements we don't
try allocate too much memory to read into

BUGS: 498368
2025-01-14 00:40:26 +01:00
Albert Astals Cid
f296c38daf xcf: Return early if seek fails
BUGS: 498381
2025-01-09 02:33:51 +00:00
Daniel Novomeský
bda8487147 heif: fix -Wstringop-overread warning 2025-01-08 16:45:57 +01:00
Daniel Novomeský
bb10c4bd5c jxl: refactor metadata boxes reading 2025-01-08 12:43:42 +01:00
Mirco Miranda
1982557a55 RAW: Allow preview loading
This patch addresses reports of performance issues on large raw collections. Programs that generate previews must use the plugin correctly.

**Setting quality to 0 may return a different image than in the past** (Nothing changes for all other quality values): the plugin loads the embedded thumbnail and, in case of error, decodes the image with quality 1. When compiled with libRAW 0.21+, the plugin automatically select the largest preview from the ones in the file.
2025-01-08 07:01:57 +00:00
Mirco Miranda
c97ee00f5e Add JPEG 2000 support
JPEG 2000 support using OpenJPEG library.

- Add read/write support to JP2/J2K format for Gray/RGB(A)/CMYK images @8/16-bits
- Read test case images generated by Photoshop

The plugin has the following limitations:
- Resolution is not set (JP2_RES box is marked "For the future" in jp2.h)
- Metadata are not set (as with resolution)

Closes #13
2025-01-05 10:36:21 +00:00
Mirco Miranda
e6a0f8758b JXL: Fix missing checks for BOXES when parsing animation
Fix error when parsing something like:

```
JXL_DEC_BOX
JXL_DEC_BOX
JXL_DEC_BOX
JXL_DEC_BASIC_INFO
JXL_DEC_COLOR_ENCODING
JXL_DEC_BOX
JXL_DEC_BOX
JXL_DEC_FRAME
JXL_DEC_BOX
JXL_DEC_FRAME
```

CCBUG: 496350
2025-01-04 06:46:41 +00:00
Mirco Miranda
5c0c7e4fd7 Try writers with different image sizes
Improve the write test by using images with different sizes. By doing this we protect ourselves from line alignment problems (e.g. with 1-bpp images), image size divisors (e.g. power-of-2 divisors), etc...

Pros:
- The test does not add new images but reuses the ones for the format test.

Cons:
- No test are done for read only plugins.

Closes #15
2025-01-03 23:32:06 +00:00
Nicolas Fella
40c2aae0cd Update version to 6.11.0 2025-01-03 16:41:05 +01:00
220 changed files with 6847 additions and 810 deletions

View File

@ -5,7 +5,18 @@ include:
- project: sysadmin/ci-utilities
file:
- /gitlab-templates/linux-qt6.yml
- /gitlab-templates/linux-qt6-next.yml
- /gitlab-templates/alpine-qt6.yml
- /gitlab-templates/android-qt6.yml
- /gitlab-templates/freebsd-qt6.yml
- /gitlab-templates/windows-qt6.yml
- /gitlab-templates/xml-lint.yml
- /gitlab-templates/yaml-lint.yml
image_json_validate:
stage: validate
image: invent-registry.kde.org/sysadmin/ci-images/suse-qt68:latest
tags:
- Linux
script:
- find src/imageformats/ -name *.json | xargs -I file bash -c "echo file && jq -e '(.Keys | type == \"array\") and (.MimeTypes | type == \"array\") and (.MimeTypes | length) == (.Keys | length)' file"

View File

@ -1,10 +1,11 @@
Dependencies:
- 'on': ['Linux', 'FreeBSD', 'macOS', 'Windows', 'Android']
'require':
- 'on': ['Linux', 'FreeBSD', 'macOS', 'Windows', 'Android']
'require':
'frameworks/extra-cmake-modules': '@same'
'frameworks/karchive' : '@same'
'frameworks/karchive': '@same'
Options:
test-before-installing: True
require-passing-tests-on: [ 'Linux', 'FreeBSD', 'Windows' ]
cmake-options: "-DKIMAGEFORMATS_DDS=ON -DKIMAGEFORMATS_JXR=ON"
test-before-installing: True
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
cmake-options: "-DKIMAGEFORMATS_DDS=ON -DKIMAGEFORMATS_JXR=ON -DKIMAGEFORMATS_HEIF=ON"
per-test-timeout: 90

View File

@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.16)
set(KF_VERSION "6.10.0") # handled by release scripts
set(KF_DEP_VERSION "6.10.0") # handled by release scripts
set(KF_VERSION "6.15.0") # handled by release scripts
set(KF_DEP_VERSION "6.14.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION})
include(FeatureSummary)
find_package(ECM 6.10.0 NO_MODULE)
find_package(ECM 6.14.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
@ -21,7 +21,7 @@ include(ECMDeprecationSettings)
include(CheckIncludeFiles)
include(FindPkgConfig)
set(REQUIRED_QT_VERSION 6.6.0)
set(REQUIRED_QT_VERSION 6.7.0)
find_package(Qt6Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(KF6Archive ${KF_DEP_VERSION})
@ -72,12 +72,19 @@ add_feature_info(LibHeif LibHeif_FOUND "required for the QImage plugin for HEIF/
option(KIMAGEFORMATS_JXL "Enable plugin for JPEG XL format" ON)
if(KIMAGEFORMATS_JXL)
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.7.0)
pkg_check_modules(LibJXLThreads IMPORTED_TARGET libjxl_threads>=0.7.0)
pkg_check_modules(LibJXLCMS IMPORTED_TARGET libjxl_cms>=0.9.0)
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.9.4)
pkg_check_modules(LibJXLThreads IMPORTED_TARGET libjxl_threads>=0.9.4)
pkg_check_modules(LibJXLCMS IMPORTED_TARGET libjxl_cms>=0.9.4)
endif()
add_feature_info(LibJXL LibJXL_FOUND "required for the QImage plugin for JPEG XL images")
option(KIMAGEFORMATS_JP2 "Enable plugin for JPEG 2000 format" ON)
if(KIMAGEFORMATS_JP2)
find_package(OpenJPEG CONFIG)
endif()
add_feature_info(OpenJPEG OpenJPEG_FOUND "required for the QImage plugin for JPEG 2000 images")
find_package(LibRaw 0.20.2)
set_package_properties(LibRaw PROPERTIES
TYPE OPTIONAL
@ -92,8 +99,8 @@ endif()
add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images")
ecm_set_disabled_deprecation_versions(
QT 6.8.0
KF 6.8.0
QT 6.9.0
KF 6.13.0
)
add_subdirectory(src)
@ -102,6 +109,28 @@ if (BUILD_TESTING)
add_subdirectory(tests)
endif()
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6ImageFormats")
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/KF6ImageFormatsConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/KF6ImageFormatsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF6ImageFormatsConfig.cmake"
INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KF6ImageFormatsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KF6ImageFormatsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
include(ECMFeatureSummary)
ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

View File

@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2025 Xaver Hugl <xaver.hugl@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
@PACKAGE_INIT@
# empty, because this is plugins for Qt instead of a library to link against

188
README.md
View File

@ -32,6 +32,7 @@ The following image formats have read and write support:
- DirectDraw Surface (dds)
- Encapsulated PostScript (eps)
- High Efficiency Image File Format (heif)
- JPEG 2000 (jp2, j2k, jpf)
- JPEG XL (jxl)
- JPEG XR (jxr)
- OpenEXR (exr)
@ -52,8 +53,10 @@ willing to sign the Qt Project contributor agreement, it may be better to
submit the plugin directly to the Qt Project.
To be accepted, contributions must:
- Contain the test images needed to verify that the changes work correctly
- Pass the tests successfully
- Contain the test images needed to verify that the changes work correctly.
- Pass the tests successfully.
For more info about tests, see also [Autotests README](autotests/README.md).
## Duplicated Plugins
@ -75,6 +78,12 @@ The DDS plugin is a fork from Qt 5.6 with bug fixes and improvements.
The plugin was forked because Qt Project no longer supports its DDS plugin.
### The JP2 plugin
The JP2 plugin is based on the popular and wide used OpenJPEG library.
The Qt project has a no longer supported JPEG 2000 plugin based on Jasper.
## License
This framework is licensed under the
@ -106,17 +115,96 @@ clamp). This is not a plugin issue.
### Metadata
Metadata support is implemented in all formats that support it. In particular,
in addition to the classic `"Description"`, `"Author"`, `"Copyright"`, etc... where
possible, XMP data is supported via the `"XML:com.adobe.xmp"` key.
Metadata support is available in formats that include it via
`QImage::setText()` and `QImage::text()`. To ensure consistent metadata
functionality, the following keys have been adopted.
Please note that only the most common metadata is supported.
About the image:
- `Altitude`: Floating-point number indicating the GPS altitude in meters
above sea level (e.g. 35.4).
- `Author`: Person who created the image.
- `Comment`: Additional image information in human-readable form, for
example a verbal description of the image.
- `Copyright`: Copyright notice of the person or organization that claims
the copyright to the image.
- `CreationDate`: When the image was created or captured. Date and time in
ISO 8601 format without milliseconds (e.g. 2024-03-23T15:30:43). This value
should be kept unchanged when present.
- `Description`: A string that describes the subject of the image.
- `Direction`: Floating-point number indicating the direction of the image
when it was captured in degrees (e.g. 123.3).
- `DocumentName`: The name of the document from which this image was
scanned.
- `HostComputer`: The computer and/or operating system in use at the time
of image creation.
- `Latitude`: Floating-point number indicating the latitude in degrees
north of the equator (e.g. 27.717).
- `Longitude`: Floating-point number indicating the longitude in degrees
east of Greenwich (e.g. 85.317).
- `ModificationDate`: Last modification date and time in ISO 8601 format
without milliseconds (e.g. 2024-03-23T15:30:43). This value should be
updated every time the image is saved.
- `Owner`: Name of the owner of the image.
- `Software`: Name and version number of the software package(s) used to
create the image.
- `Title`: The title of the image.
About the camera:
- `Manufacturer`: The manufacturer of the recording equipment.
- `Model`: The model name or model number of the recording equipment.
- `SerialNumber`: The serial number of the recording equipment.
About the lens:
- `LensManufacturer`: The manufacturer of the interchangeable lens that was
used.
- `LensModel`: The model name or model number of the lens that was used.
- `LensSerialNumber`: The serial number of the interchangeable lens that was
used.
Complex metadata (requires a parser):
- `XML:org.gimp.xml`: XML metadata generated by GIMP and present only in XCF
files.
- `XML:com.adobe.xmp`: [Extensible Metadata Platform (XMP)](https://developer.adobe.com/xmp/docs/)
is the metadata standard used by Adobe applications and is supported by all
common image formats. **Note that XMP metadata is read and written by
plugins as is.** Since it may contain information present in other metadata
(e.g. `Description`), it is the user's responsibility to ensure consistency
between all metadata and XMP metadata when writing an image.
Supported metadata may vary from one plugin to another. Please note that only
the most common metadata are supported and some plugins may return keys not
listed here.
### EXIF Metadata
[EXIF (Exchangeable Image File Format)](https://en.wikipedia.org/wiki/Exif)
metadata is a standard for embedding information within the image file itself.
Unlike the metadata described above, EXIF metadata is used internally by some
plugins to standardize image handling. For example, the JXL plugin uses them
to **set/get the image resolution and metadata**. They are also needed to
make the image properties appear in the file details of some file managers
(e.g. Dolphin).
When reading, EXIF metadata is converted into simple metadata (e.g.
`Description`) and inserted into the image if and only if it is not already
present.
On writing, the image metadata is converted to EXIF and saved appropriately.
Note that, if not present in the image to be saved, the following metadata
are created automatically:
- `Software`: Created using `applicationName` and `applicationVersion` methods
of [`QCoreApplication`](https://doc.qt.io/qt-6/qcoreapplication.html).
- `CreationDate`: Set to current time and date.
- `ModificationDate`: Set to current time and date.
### ICC profile support
ICC support is fully implemented in all formats that support it. When saving,
some formats convert the image using color profiles according to
specifications. In particular, HDR formats almost always convert to linear
ICC profile support is implemented in all formats that handle them using
[`QColorSpace`](https://doc.qt.io/qt-6/qcolorspace.html). When saving, some
plugins convert the image using color profiles according to format
specifications. In particular, HDR formats almost always convert to linear
RGB.
### Maximum image size
@ -134,6 +222,7 @@ plugin ('n/a' means no limit, i.e. the limit depends on the format encoding).
- EPS: n/a
- HDR: n/a (large image)
- HEIF: n/a
- JP2: 300,000 x 300,000 pixels, in any case no larger than 2 gigapixels
- JXL: 262,144 x 262,144 pixels, in any case no larger than 256 megapixels
- JXR: n/a, in any case no larger than 4 GB
- KRA: same size as Qt's PNG plugin
@ -178,16 +267,18 @@ been used or the maximum size of the image that can be saved has been limited.
PSD plugin loads CMYK, Lab and Multichannel images and converts them to RGB
without using the ICC profile.
JXR, PSD and SCT plugins natively support 4-channel CMYK images when compiled
with Qt 6.8+.
JP2, JXL, JXR, PSD and SCT plugins natively support 4-channel CMYK images when
compiled with Qt 6.8+.
### The DDS plugin
**This plugin can be disabled by setting `KIMAGEFORMATS_DDS` to `OFF`
in your cmake options.**
The following defines can be defined in cmake to modify the behavior of the plugin:
- `DDS_DISABLE_STRIDE_ALIGNMENT`: disable the stride aligment based on DDS pitch: it is known that some writers do not set it correctly.
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `DDS_DISABLE_STRIDE_ALIGNMENT`: disable the stride aligment based on DDS
pitch: it is known that some writers do not set it correctly.
### The HEIF plugin
@ -201,9 +292,13 @@ will compile but will fail the tests.
### The EXR plugin
The following defines can be defined in cmake to modify the behavior of the plugin:
- `EXR_CONVERT_TO_SRGB`: the linear data is converted to sRGB on read to accommodate programs that do not support color profiles.
- `EXR_DISABLE_XMP_ATTRIBUTE`: disables the stores XMP values in a non-standard attribute named "xmp". Note that Gimp reads the "xmp" attribute and Darktable writes it as well.
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `EXR_CONVERT_TO_SRGB`: the linear data is converted to sRGB on read to
accommodate programs that do not support color profiles.
- `EXR_DISABLE_XMP_ATTRIBUTE`: disables the stores XMP values in a non-standard
attribute named "xmp". Note that Gimp reads the "xmp" attribute and Darktable
writes it as well.
### The EPS plugin
@ -215,16 +310,31 @@ create a temporary PDF file which is then converted to EPS. Therefore, if
### The HDR plugin
The following defines can be defined in cmake to modify the behavior of the plugin:
- `HDR_HALF_QUALITY`: on read, a 16-bit float image is returned instead of a 32-bit float one.
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `HDR_HALF_QUALITY`: on read, a 16-bit float image is returned instead of a
32-bit float one.
### The JP2 plugin
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
in your cmake options.**
JP2 plugin has the following limitations due to the lack of support by OpenJPEG:
- Metadata are not supported.
- Image resolution is not supported.
- To write ICC profiles you need OpenJPEG V2.5.4 or higher
### The JXL plugin
**The current version of the plugin limits the image size to 256 megapixels
according to feature level 5 of the JXL stream encoding.**
The following defines can be defined in cmake to modify the behavior of the plugin:
- `JXL_HDR_PRESERVATION_DISABLED`: disable floating point images (both read and write) by converting them to UINT16 images. Any HDR data is lost. Note that FP images are always disabled when compiling with libJXL less than v0.9.
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `JXL_HDR_PRESERVATION_DISABLED`: disable floating point images (both read
and write) by converting them to UINT16 images. Any HDR data is lost. Note
that FP images are always disabled when compiling with libJXL less than v0.9.
- `JXL_DECODE_BOXES_DISABLED`: disable reading of metadata (e.g. XMP).
### The JXR plugin
@ -232,11 +342,21 @@ The following defines can be defined in cmake to modify the behavior of the plug
**This plugin is disabled by default. It can be enabled by settings
`KIMAGEFORMATS_JXR` to `ON` in your cmake options.**
The following defines can be defined in cmake to modify the behavior of the plugin:
- `JXR_DENY_FLOAT_IMAGE`: disables the use of float images and consequently any HDR data will be lost.
- `JXR_DISABLE_DEPTH_CONVERSION`: remove the neeeds of additional memory by disabling the conversion between different color depths (e.g. RGBA64bpp to RGBA32bpp) at the cost of reduced compatibility.
- `JXR_DISABLE_BGRA_HACK`: Windows displays and opens JXR files correctly out of the box. Unfortunately it doesn't seem to open (P)RGBA @32bpp files as it only wants (P)BGRA32bpp files (a format not supported by Qt). Only for this format an hack is activated to guarantee total compatibility of the plugin with Windows.
- `JXR_ENABLE_ADVANCED_METADATA`: enable metadata support (e.g. XMP). Some distributions use an incomplete JXR library that does not allow reading metadata, causing compilation errors.
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `JXR_DENY_FLOAT_IMAGE`: disables the use of float images and consequently
any HDR data will be lost.
- `JXR_DISABLE_DEPTH_CONVERSION`: remove the neeeds of additional memory by
disabling the conversion between different color depths (e.g. RGBA64bpp to
RGBA32bpp) at the cost of reduced compatibility.
- `JXR_DISABLE_BGRA_HACK`: Windows displays and opens JXR files correctly out
of the box. Unfortunately it doesn't seem to open (P)RGBA @32bpp files as
it only wants (P)BGRA32bpp files (a format not supported by Qt). Only for
this format an hack is activated to guarantee total compatibility of the
plugin with Windows.
- `JXR_ENABLE_ADVANCED_METADATA`: enable metadata support (e.g. XMP). Some
distributions use an incomplete JXR library that does not allow reading
metadata, causing compilation errors.
### The KRA plugin
@ -253,15 +373,19 @@ image.
### The PSD plugin
PSD support has the following limitations:
- Only images saved by Photoshop using compatibility mode enabled (Photoshop default) can be decoded.
- Only images saved by Photoshop using compatibility mode enabled (Photoshop
default) can be decoded.
- Multichannel images are treated as CMYK if they have 2 or more channels.
- Multichannel images are treated as Grayscale if they have 1 channel.
- Duotone images are treated as grayscale images.
- Extra channels other than alpha are discarded.
The following defines can be defined in cmake to modify the behavior of the plugin:
- `PSD_FAST_LAB_CONVERSION`: the LAB image is converted to linear sRGB instead of sRGB which significantly increases performance.
- `PSD_NATIVE_CMYK_SUPPORT_DISABLED`: disable native support for CMYK images when compiled with Qt 6.8+
The following defines can be defined in cmake to modify the behavior of the
plugin:
- `PSD_FAST_LAB_CONVERSION`: the LAB image is converted to linear sRGB instead
of sRGB which significantly increases performance.
- `PSD_NATIVE_CMYK_SUPPORT_DISABLED`: disable native support for CMYK images
when compiled with Qt 6.8+
### The RAW plugin
@ -276,7 +400,9 @@ The default setting tries to balance quality and conversion speed.
### The XCF plugin
XCF support has the following limitations:
- XCF format up to [version 12](https://testing.developer.gimp.org/core/standards/xcf/#version-history) (no support for GIMP 3).
- XCF format up to [version 12](https://testing.developer.gimp.org/core/standards/xcf/#version-history)
(no support for GIMP 3).
- The returned image is always 8-bit.
- Cannot read zlib compressed files.
- The rendered image may be slightly different (colors/transparencies) than in GIMP.
- The rendered image may be slightly different (colors/transparencies) than
in GIMP.

View File

@ -19,9 +19,15 @@ macro(kimageformats_read_tests)
endif()
foreach(_testname ${KIF_RT_UNPARSED_ARGUMENTS})
string(REGEX MATCH "-skipoptional" _is_skip_optional "${_testname}")
unset(skip_optional_arg)
if (_is_skip_optional)
set(skip_optional_arg "--skip-optional-tests")
string(REGEX REPLACE "-skipoptional$" "" _testname "${_testname}")
endif()
add_test(
NAME kimageformats-read-${_testname}
COMMAND readtest ${_fuzzarg} ${_testname}
COMMAND readtest ${skip_optional_arg} ${_fuzzarg} ${_testname}
)
endforeach(_testname)
endmacro()
@ -43,6 +49,8 @@ macro(kimageformats_write_tests)
foreach(_testname ${KIF_RT_UNPARSED_ARGUMENTS})
string(REGEX MATCH "-lossless$" _is_lossless "${_testname}")
string(REGEX MATCH "-nodatacheck" _is_no_data_check "${_testname}")
string(REGEX MATCH "-skipoptional" _is_skip_optional "${_testname}")
unset(skip_optional_arg)
unset(lossless_arg)
unset(no_data_check_arg)
if (_is_lossless)
@ -53,9 +61,13 @@ macro(kimageformats_write_tests)
set(no_data_check_arg "--no-data-check")
string(REGEX REPLACE "-nodatacheck$" "" _testname "${_testname}")
endif()
if (_is_skip_optional)
set(skip_optional_arg "--skip-optional-tests")
string(REGEX REPLACE "-skipoptional$" "" _testname "${_testname}")
endif()
add_test(
NAME kimageformats-write-${_testname}
COMMAND writetest ${lossless_arg} ${no_data_check_arg} ${_fuzzarg} ${_testname}
COMMAND writetest ${lossless_arg} ${no_data_check_arg} ${skip_optional_arg} ${_fuzzarg} ${_testname}
)
endforeach(_testname)
endmacro()
@ -110,22 +122,46 @@ if (LibHeif_FOUND)
kimageformats_read_tests(FUZZ 1
hej2
)
kimageformats_write_tests(FUZZ 1
hej2-nodatacheck-lossless
)
endif()
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.0")
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.6")
kimageformats_read_tests(FUZZ 4
avci
)
endif()
endif()
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
if (OpenJPEG_FOUND)
kimageformats_read_tests(
jxl
)
kimageformats_write_tests(
jxl-nodatacheck-lossless
jp2
)
# CMYK writing is incorrect in versions before 2.5.3
if ("${OPENJPEG_MAJOR_VERSION}.${OPENJPEG_MINOR_VERSION}.${OPENJPEG_BUILD_VERSION}" VERSION_GREATER_EQUAL "2.5.3")
kimageformats_write_tests(
jp2-nodatacheck-lossless
)
endif()
endif()
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
if(LibJXL_VERSION VERSION_GREATER_EQUAL "0.11.0")
kimageformats_read_tests(
jxl
)
kimageformats_write_tests(
jxl-nodatacheck-lossless
)
else()
kimageformats_read_tests(
jxl-skipoptional
)
kimageformats_write_tests(
jxl-skipoptional-nodatacheck-lossless
)
endif()
endif()
if (LibJXR_FOUND)
@ -137,9 +173,7 @@ if (LibJXR_FOUND)
)
endif()
# Allow some fuzziness when reading this formats, to allow for
# rounding errors (eg: in alpha blending).
kimageformats_read_tests(FUZZ 1
kimageformats_read_tests(
xcf
)
@ -150,7 +184,7 @@ kimageformats_read_tests(FUZZ 1
# You can append -lossless to the format to indicate that
# reading back the image data will result in an identical image.
kimageformats_write_tests(
pcx-lossless
pcx-nodatacheck
pic-lossless
qoi-lossless
rgb-lossless
@ -169,7 +203,7 @@ if (OpenEXR_FOUND)
)
# Color space conversions from sRGB to linear on saving and
# from linear to sRGB on loading result in some rounding errors.
kimageformats_write_tests(FUZZ 5
kimageformats_write_tests(FUZZ 6
exr-nodatacheck-lossless
)
endif()

253
autotests/README.md Normal file
View File

@ -0,0 +1,253 @@
# Autotests
Automated testing for plugins to allow
[`QImage`](https://doc.qt.io/qt-6/qimage.html) to support
extra file formats.
## Introduction
The testing part is essential for the correct functioning of the plugins.
There are generic read/write tests and specific tests for the plugins that
require them.
## Read tests
The generic reading tests are contained in the `read` folder. Inside the
`read` folder, there are one or more folders for each plugin to be tested.
A plugin can support multiple image file types, and if you need different
parameters for each type, you need to create a folder for each type supported
by the plugin (see e.g. HEIF plugin). If all formats supported by the plugin
do not require different parameters, a single folder approach is simpler (see
e.g. PSD plugin).
The reading tests are mainly based on comparing the image read by the plugin
with a template in a known and working format. For this reason, the template
formats chosen are those distributed by the Qt project: PNG in the first
instance and TIFF for image formats not supported by PNG (e.g. CMYK images).
Some image options such as `QImageIOHandler::Size`,
`QImageIOHandler::ImageFormat` and `QImageIOHandler::ImageTransformation` are
also checked. If supported by the plugin, the resulting image is checked to
see if it is compatible with the option's specification.
Optionally, for each image, you can also create a JSON file to modify the test
behavior and/or verify data other than image pixels, such as metadata.
Finally, two tests are run for each test case:
- On a random access device: this test must not fail.
- On a sequential access device: a plugin may not support sequential operation.
In this case, the test is skipped. However, if an image is returned, the test
must succeed.
### The readtest command
To start a test, run the `readtest` command with the format to test as an
argument. The format is one of those supported by plugins and a folder with
the name of the format must be present inside the `read` folder.
Depending on the format, you can specify the following additional options.
- `--help`: Displays help on commandline options.
- `--fuzz <max>`: The fuzziness. Used to add some deviation in ARGB data
(nornally used on lossy codec).
- `--perceptive-fuzz`: Used to scale dynamically the fuzziness based on
the alpha channel value. This is useful on images with pre-multiplied and
small alphas. Qt can use different roundings based on optimizations resulting
in very different RGB values. Since the alpha is small visually there is no
difference (so it is not considered an error).
- `--skip-optional-tests`: Used to skip the optional test such as metadata
and resolution tests.
Note that some tests may fail if the correct options are not used. The correct
options for each test are defined in [CMakeLists.txt](CMakeLists.txt).
See also [Add a test to CMakeLists.txt](#add-a-test-to-cmakeliststxt).
### Test image nomenclature
Each test consists of the image to test, the verification image(s) (template)
and, optionally, the additional JSON file.
To be a test, the names of these files must be the same (except for
the extension). A test for a JXL image would be, for example, composed like
this:
- `testRGB.jxl`: The image to test.
- `testRGB.jxl.json`: The test behavior modifier (note that it must contain
the double extension).
- `testRGB.png`: How the image should look (template). The template name
can be different if specified in the JSON file.
Although there is no precise rule for the name of a test, it is good to have
a name that is explanatory.
### JSON behavior file
The behavior file was initially introduced to solve compatibility issues
between different versions of Qt supported by the framework. It was later
extended to also check image metadata.
The JSON file consists of an array of JSON objects. The objects in the array
are iterated sequentially and the first object that matches the requirements
is used for testing (successes are ignored).
Supported values for JSON objects:
- `comment`: Type string. A string shown by the test when a condition occurs.
- `description`: Type string. A description of the object. Not used by the
test.
- `disableAutoTransform`: Type boolean. By default, tests are run with
autotransform enabled (i.e. rotation is applied if the plugin supports it).
Set to `true` to disable autotransform.
- `filename`: Type string. Name of the template file to use. E.g.
"testRGB_Qt_6_2.png".
- `fuzziness`: Type integer. Set the fuzziness only if not already set on the
command line. The value set on the command line wins over the one in the JSON
file.
- `maxQtVersion`: Type string. Maximum Qt version this object is compatible
with (if not set means all). E.g. "6.2.99".
- `metadata`: Type Array. An array of key/value objects (string type)
containing the image metadata as returned by `QImage::text`.
- `minQtVersion`: Type string. Minimum Qt version this object is compatible
with (if not set means all). E.g. "6.2.0".
- `perceptiveFuzziness` Type boolean. Set the perceptive fuzziness only if not
already set on the command line. The value set on the command line wins over
the one in the JSON file.
- `resolution`: Type object. An object with the `dotsPerMeterX` and
`dotsPerMeterY` (integer) values of the image.
- `seeAlso`: Type string. More info about the object. Normally used to point
to bug reports. Not used by the test.
- `unsupportedFormat`: Type `boolean`. When true, the test is skipped.
Some examples:
- Example 1: [Runs only on Qt without alpha bug on float formats](read/jxl/testcard_rgba_fp16.jxl.json)
- Example 2: [Rotation disabled](read/jxl/orientation6_notranfs.jxl.json)
- Example 3: [Metadata](read/psd/metadata.psd.json)
- Example 4: [Check Qt version, resolution and metadata](read/psd/mch-16bits.psd.json)
- Example 5: [Fuzziness setting](read/xcf/birthday16.xcf.json)
These are just a few examples. More examples can be found in the test folders.
## Write tests
The generic writing tests are contained in the `write/basic` and
`write/format` folders. Similar to the read tests, they verify the written
(and then reread) image with a template.
The write test is composed of several phases:
- Basic test: Uses the `write/basic` folder and checks the most common images
and, optionally, metadata and resolution via a JSON properties file.
- Format test: Uses the `write/format` folder and checks that all QImage image
formats are written correctly.
- Dimensional test: Uses the `write/format` folder and check images of
different sizes (odd numbers, prime numbers, etc.) to verify internal
alignments.
- Null device test: Verify that there are no crashes if the device is null.
### The writetest command
To start a test, run the `writetest` command with the format to test as an
argument. The format is one of those supported by plugins, a folder with
the name of the format must be present inside the `write/format` folder and
may need a template image in `write/basic`.
Depending on the format, you can specify the following additional options.
- `--help`: Displays help on commandline options.
- `--create-format-templates`: Create template images for all formats
supported by the QImage in `write/format`. Command to simplify the creation of
format test images when adding a new plugin or modifying an old one. This
command is not intended to be used from the CMakeLists file as it must be used
manually and the generated images must be verified one by one.
- `--fuzz <max>`: The fuzziness. Used to add some deviation in ARGB data
(nornally used on lossy codec).
- `--lossless`: Check that reading back the data gives the same image.
- `--no-data-check`: Don't check that write data is exactly the same.
- `--skip-optional-tests`: Skip optional data tests (metadata, resolution,
etc...).
Note that some tests may fail if the correct options are not used. The correct
options for each test are defined in [CMakeLists.txt](CMakeLists.txt).
See also [Add a test to CMakeLists.txt](#add-a-test-to-cmakeliststxt).
### JSON properties file
The properties file must be located in `write/basic` and must have the name
of the file format (e.g. jxl.json). It is a JSON object composed of the
following values:
- `format`: Type string. The format tested.
- `metadata`: Type Array. An array of key/value objects (string type)
containing the image metadata as returned by `QImage::text`.
- `resolution`: Type object. An object with the `dotsPerMeterX` and `
dotsPerMeterY` (integer) values of the image.
[This is an example](write/basic/jxl.json) of property file.
## Custom tests
If the generic read/write tests do not meet the requirements of a plugin,
it is possible to write a custom test.
In general it makes sense to write a dedicated test for a format if and
only if you are testing unique features not present in other plugins.
### The PIC test
The PIC test is generated using Qt Test class. For more information
see [Qt Test](https://doc.qt.io/qt-6/qttest-index.html).
### The ANI test
The ANI test is generated using Qt Test class. For more information
see [Qt Test](https://doc.qt.io/qt-6/qttest-index.html).
## Add a test to CMakeLists.txt
To add a test to CMake use the `kimageformats_read_tests` and
`kimageformats_write_tests` functions. For example, to add the read
tests for the PSD you just write `kimageformats_read_tests(psd)`.
It is also possible to pass command line arguments to the test by
appropriately composing the string passed to the test functions.
For boolean parameters you need to add a string starting with '-'
after the image format. For example, to pass `--skip-optional-tests`
to the PSD plugin write `kimageformats_read_tests(psd-skipoptional)`.
To add a fuzziness of 4, you must first set it as follows:
`kimageformats_read_tests(FUZZ 4 psd-skipoptional)`.
The possible modifiers for `kimageformats_read_tests` are as follows:
- `-skipoptional`: Add the `--skip-optional-tests` command line parameter.
The possible modifiers for `kimageformats_write_tests` are as follows:
- `-lossless`: Add the `--lossless` command line parameter.
- `-nodatacheck`: Add the `--no-data-check` command line parameter.
- `-skipoptional`: Add the `--skip-optional-tests` command line parameter.
To set multiple parameters, you can enter multiple modifiers. For example:
```
kimageformats_write_tests(FUZZ 1
hej2-nodatacheck-lossless
)
```
## OSS-Fuzz
Plugins are also tested with [OSS-Fuzz](https://google.github.io/oss-fuzz/)
project to identify possible security issues. When adding a new plugin it is
also necessary to add it to the test in the [kimageformats
project](https://github.com/google/oss-fuzz/tree/master/projects/kimageformats)
on OSS-Fuzz.
## TODO
List of tests not implemented or only partially implemented.
### Color Profiles Test
Many plugins support color profiles via [`QColorSpace`](https://doc.qt.io/qt-6/qcolorspace.html).
Checking for correct color management is increasingly necessary especially now
that monitors are HDR and other than RGB color spaces have been added to Qt.
Furthermore, lossy plugins often have different color management behaviors
depending on how the image is saved.
### Animations Test
Few plugins support animations. There are currently no plans for
implementation.

View File

@ -4,34 +4,66 @@
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include <QImage>
#include <QRgb>
#include <QRgba64>
inline int iAbs(const int &v)
{
return v < 0 ? -v : v;
}
template<class Trait>
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
static bool fuzzyeq(const QImage &im1, const QImage &im2, int fuzziness, bool perceptiveFuzzer)
{
Q_ASSERT(im1.format() == im2.format());
Q_ASSERT(im1.depth() == 24 || im1.depth() == 32 || im1.depth() == 64);
const bool hasAlpha = im1.hasAlphaChannel();
const int height = im1.height();
const int width = im1.width();
for (int i = 0; i < height; ++i) {
const Trait *line1 = reinterpret_cast<const Trait *>(im1.scanLine(i));
const Trait *line2 = reinterpret_cast<const Trait *>(im2.scanLine(i));
for (int j = 0; j < width; ++j) {
if (line1[j] > line2[j]) {
if (line1[j] - line2[j] > fuzziness) {
return false;
}
} else {
if (line2[j] - line1[j] > fuzziness) {
return false;
}
auto &&px1 = line1[j];
auto &&px2 = line2[j];
auto fuzz = int(fuzziness);
// Calculate the deltas
auto dr = iAbs(int(qRed(px2)) - int(qRed(px1)));
auto dg = iAbs(int(qGreen(px2)) - int(qGreen(px1)));
auto db = iAbs(int(qBlue(px2)) - int(qBlue(px1)));
auto da = iAbs(int(qAlpha(px2)) - int(qAlpha(px1)));
// Always compare alpha even on images without it: some formats (e.g. RGBX64),
// want it set to a certain value (e.g. 65535).
if (da > fuzz)
return false;
// Calculate the perceptive fuzziness.
if (hasAlpha && perceptiveFuzzer) {
auto alpha = std::max(4, int(qAlpha(px1)));
if (sizeof(Trait) == 4)
fuzz = std::min(fuzz * (255 / alpha), 255);
else
fuzz = std::min(fuzz * (65535 / alpha), 255 * 257);
}
// Compare the deltas of R, G, B components.
if (dr > fuzz)
return false;
if (dg > fuzz)
return false;
if (db > fuzz)
return false;
}
}
return true;
}
// allow each byte to be different by up to 1, to allow for rounding errors
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness, bool perceptiveFuzzer = false)
{
return (im1.depth() == 64) ? fuzzyeq<quint16>(im1, im2, fuzziness) : fuzzyeq<quint8>(im1, im2, fuzziness);
return (im1.depth() == 64) ? fuzzyeq<QRgba64>(im1, im2, int(fuzziness) * 257, perceptiveFuzzer) : fuzzyeq<QRgb>(im1, im2, int(fuzziness), perceptiveFuzzer);
}

Binary file not shown.

View File

@ -0,0 +1,59 @@
[
{
"fileName" : "metadata.png",
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-02-19T08:27:22+01:00"
},
{
"key" : "Software" ,
"value" : "GIMP 3.0.0-RC3"
},
{
"key" : "Altitude",
"value" : "34"
},
{
"key" : "Author",
"value" : "KDE Project"
},
{
"key" : "Copyright",
"value" : "@2025 KDE Project"
},
{
"key" : "Description",
"value" : "TV broadcast test image."
},
{
"key" : "Latitude",
"value" : "44.6478"
},
{
"key" : "LensManufacturer",
"value" : "KDE Glasses"
},
{
"key" : "LensModel",
"value" : "A1234"
},
{
"key" : "Longitude",
"value" : "10.9254"
},
{
"key" : "Manufacturer",
"value" : "KFramework"
},
{
"key" : "Model",
"value" : "KImageFormats"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 5905
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,7 @@
[
{
"fileName" : "rgba16dx10.png",
"fuzziness" : 1,
"description" : "Minimum fuzziness value to pass the test on all architectures."
}
]

View File

@ -0,0 +1,7 @@
[
{
"fileName" : "rgba_f16.png",
"fuzziness" : 1,
"description" : "Minimum fuzziness value to pass the test on all architectures."
}
]

View File

@ -0,0 +1,9 @@
[
{
"fileName" : "rgb-gimp.png",
"resolution" : {
"dotsPerMeterX" : 3937,
"dotsPerMeterY" : 3937
}
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

View File

@ -1,5 +1,11 @@
[
{
"fileName" : "orientation_all.png"
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "GEGL"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,59 @@
[
{
"fileName" : "metadata.png",
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-02-26T16:52:06Z"
},
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10 (Linux)"
},
{
"key" : "Altitude",
"value" : "34"
},
{
"key" : "Author",
"value" : "KDE Project"
},
{
"key" : "Copyright",
"value" : "@2025 KDE Project"
},
{
"key" : "Description",
"value" : "TV broadcast test image."
},
{
"key" : "Latitude",
"value" : "44.6478"
},
{
"key" : "LensManufacturer",
"value" : "KDE Glasses"
},
{
"key" : "LensModel",
"value" : "A1234"
},
{
"key" : "Longitude",
"value" : "10.9254"
},
{
"key" : "Manufacturer",
"value" : "KFramework"
},
{
"key" : "Model",
"value" : "KImageFormats"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 5905
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"minQtVersion" : "6.8.0",
"fileName" : "testcard_cmyk.tif"
},
{
"maxQtVersion" : "6.7.99",
"unsupportedFormat" : true,
"comment" : "Qt versions lower than 6.8 do not support CMYK format so this test should be skipped."
}
]

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"minQtVersion" : "6.8.0",
"fileName" : "testcard_cmyk16.tif"
},
{
"maxQtVersion" : "6.7.99",
"unsupportedFormat" : true,
"comment" : "Qt versions lower than 6.8 do not support CMYK format so this test should be skipped."
}
]

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

View File

@ -0,0 +1,19 @@
[
{
"fileName" : "gimp_exif.png",
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-01-05T10:18:16"
},
{
"key" : "Software" ,
"value" : "GIMP 3.0.0-RC2"
}
],
"resolution" : {
"dotsPerMeterX" : 5905,
"dotsPerMeterY" : 6692
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

View File

@ -0,0 +1,59 @@
[
{
"fileName" : "metadata.png",
"metadata" : [
{
"key" : "CreationDate",
"value" : "2025-01-14T10:34:51Z"
},
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
},
{
"key" : "Altitude",
"value" : "34"
},
{
"key" : "Author",
"value" : "KDE Project"
},
{
"key" : "Copyright",
"value" : "@2025 KDE Project"
},
{
"key" : "Description",
"value" : "TV broadcast test image."
},
{
"key" : "Latitude",
"value" : "44.6478"
},
{
"key" : "LensManufacturer",
"value" : "KDE Glasses"
},
{
"key" : "LensModel",
"value" : "A1234"
},
{
"key" : "Longitude",
"value" : "10.9254"
},
{
"key" : "Manufacturer",
"value" : "KFramework"
},
{
"key" : "Model",
"value" : "KImageFormats"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 5906
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.10"
}
]
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,7 +1,11 @@
[
{
"minQtVersion" : "6.8.0",
"fileName" : "testcard_cmyk8.tif"
"fileName" : "testcard_cmyk8.tif",
"resolution" : {
"dotsPerMeterX" : 3780,
"dotsPerMeterY" : 3780
}
},
{
"maxQtVersion" : "6.7.99",

View File

@ -0,0 +1,9 @@
[
{
"fileName" : "ICONDOC.png",
"resolution" : {
"dotsPerMeterX" : 25197,
"dotsPerMeterY" : 13780
}
}
]

View File

@ -1,7 +1,21 @@
[
{
"minQtVersion" : "6.8.0",
"fileName" : "mch-16bits_qt_6_8.tif"
"fileName" : "mch-16bits_qt_6_8.tif",
"resolution" : {
"dotsPerMeterX" : 4685,
"dotsPerMeterY" : 4685
},
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2022-11-11T14:27:52"
},
{
"key" : "Software",
"value" : "Adobe Photoshop 24.0 (Windows)"
}
]
},
{
"minQtVersion" : "6.0.0",

View File

@ -1,7 +1,21 @@
[
{
"minQtVersion" : "6.8.0",
"fileName" : "mch-8bits_qt_6.8.tif"
"fileName" : "mch-8bits_qt_6.8.tif",
"resolution" : {
"dotsPerMeterX" : 4685,
"dotsPerMeterY" : 4685
},
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2022-11-11T14:27:39"
},
{
"key" : "Software",
"value" : "Adobe Photoshop 24.0 (Windows)"
}
]
},
{
"minQtVersion" : "6.0.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

View File

@ -0,0 +1,59 @@
[
{
"fileName" : "metadata.png",
"metadata" : [
{
"key" : "ModificationDate",
"value" : "2025-01-14T13:53:32+01:00"
},
{
"key" : "Software" ,
"value" : "Adobe Photoshop 26.2 (Windows)"
},
{
"key" : "Altitude",
"value" : "34"
},
{
"key" : "Author",
"value" : "KDE Project"
},
{
"key" : "Copyright",
"value" : "@2025 KDE Project"
},
{
"key" : "Description",
"value" : "TV broadcast test image."
},
{
"key" : "Latitude",
"value" : "44.6478"
},
{
"key" : "LensManufacturer",
"value" : "KDE Glasses"
},
{
"key" : "LensModel",
"value" : "A1234"
},
{
"key" : "Longitude",
"value" : "10.9254"
},
{
"key" : "Manufacturer",
"value" : "KFramework"
},
{
"key" : "Model",
"value" : "KImageFormats"
}
],
"resolution" : {
"dotsPerMeterX" : 11811,
"dotsPerMeterY" : 11811
}
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"fileName" : "orientation_all.png",
"metadata" : [
{
"key" : "Software" ,
"value" : "LIFE Pro 2.18.5 (Windows)"
}
]
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,19 @@
[
{
"fileName" : "RAW_KODAK_C330_FORMAT_NONE_YRGB.png",
"metadata" : [
{
"key" : "Manufacturer",
"value" : "Kodak"
},
{
"key" : "Model" ,
"value" : "C330"
}
],
"resolution" : {
"dotsPerMeterX" : 3937,
"dotsPerMeterY" : 3937
}
}
]

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