Compare commits
32 Commits
v5.99.0-rc
...
v5.101.0
Author | SHA1 | Date | |
---|---|---|---|
7af4eea253 | |||
a3049f6740 | |||
3b1e8f7054 | |||
dcab3a06ab | |||
361f9e867e | |||
35883aa604 | |||
50846f224f | |||
9ad82ed608 | |||
c9f32a226f | |||
a0df142408 | |||
8586bb4719 | |||
d734f28727 | |||
afa7399b36 | |||
bfb12093ad | |||
1190e53e9b | |||
350ce1b990 | |||
bcbf45e23a | |||
c71a7984d6 | |||
b1f3a87896 | |||
8af9a0f9d9 | |||
3790a89cd1 | |||
f475a4b24a | |||
d2f38b8b9c | |||
9ab64dbf22 | |||
20f74ce5e6 | |||
54129819d5 | |||
181eb253c6 | |||
c5f7ea7eac | |||
ea14882ff7 | |||
f8bfdce285 | |||
524f083ee4 | |||
c96ad6ba8a |
@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
project(KImageFormats)
|
||||
|
||||
include(FeatureSummary)
|
||||
find_package(ECM 5.99.0 NO_MODULE)
|
||||
find_package(ECM 5.101.0 NO_MODULE)
|
||||
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
|
||||
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
|
||||
|
@ -136,7 +136,9 @@ kimageformats_write_tests(
|
||||
# kimageformats_write_tests(eps)
|
||||
#endif()
|
||||
if (OpenEXR_FOUND)
|
||||
# FIXME: OpenEXR tests
|
||||
kimageformats_read_tests(
|
||||
exr
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LibRaw_FOUND)
|
||||
|
BIN
autotests/read/avif/rotated090.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated090.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated090_left-to-right.avif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
autotests/read/avif/rotated090_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated090_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated090_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated180.avif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
autotests/read/avif/rotated180.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated180_left-to-right.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated180_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated180_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated180_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated270.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated270.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated270_left-to-right.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/rotated270_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/rotated270_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
autotests/read/avif/rotated270_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/unrotated.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/unrotated.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/unrotated_left-to-right.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/unrotated_left-to-right.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/avif/unrotated_top-to-bottom.avif
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
autotests/read/avif/unrotated_top-to-bottom.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/exr/rgb-gimp.exr
Normal file
BIN
autotests/read/exr/rgb-gimp.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
autotests/read/jxl/orientation1.jxl
Normal file
BIN
autotests/read/jxl/orientation1.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation2.jxl
Normal file
BIN
autotests/read/jxl/orientation2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation3.jxl
Normal file
BIN
autotests/read/jxl/orientation3.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation4.jxl
Normal file
BIN
autotests/read/jxl/orientation4.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation5.jxl
Normal file
BIN
autotests/read/jxl/orientation5.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation6.jxl
Normal file
BIN
autotests/read/jxl/orientation6.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation7.jxl
Normal file
BIN
autotests/read/jxl/orientation7.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/jxl/orientation8.jxl
Normal file
BIN
autotests/read/jxl/orientation8.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
autotests/read/pcx/indexed8.pcx
Normal file
BIN
autotests/read/pcx/indexed8.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
autotests/read/psd/mch-16bits.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
autotests/read/psd/mch-16bits.psd
Normal file
BIN
autotests/read/psd/mch-8bits.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
autotests/read/psd/mch-8bits.psd
Normal file
@ -9,6 +9,7 @@
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QImage>
|
||||
#include <QImageReader>
|
||||
@ -18,6 +19,44 @@
|
||||
|
||||
#include "fuzzyeq.cpp"
|
||||
|
||||
/**
|
||||
* @brief The SequentialFile class
|
||||
* Class to make a file a sequential access device. This class is used to check if the plugins could works
|
||||
* on a sequential device such as a socket.
|
||||
*/
|
||||
class SequentialFile : public QFile
|
||||
{
|
||||
public:
|
||||
SequentialFile()
|
||||
: QFile()
|
||||
{
|
||||
}
|
||||
explicit SequentialFile(const QString &name)
|
||||
: QFile(name)
|
||||
{
|
||||
}
|
||||
#ifndef QT_NO_QOBJECT
|
||||
explicit SequentialFile(QObject *parent)
|
||||
: QFile(parent)
|
||||
{
|
||||
}
|
||||
SequentialFile(const QString &name, QObject *parent)
|
||||
: QFile(name, parent)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isSequential() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 size() const override
|
||||
{
|
||||
return bytesAvailable();
|
||||
}
|
||||
};
|
||||
|
||||
static void writeImageData(const char *name, const QString &filename, const QImage &image)
|
||||
{
|
||||
QFile file(filename);
|
||||
@ -56,7 +95,7 @@ int main(int argc, char **argv)
|
||||
QCoreApplication::removeLibraryPath(QStringLiteral(PLUGIN_DIR));
|
||||
QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR));
|
||||
QCoreApplication::setApplicationName(QStringLiteral("readtest"));
|
||||
QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0"));
|
||||
QCoreApplication::setApplicationVersion(QStringLiteral("1.1.0"));
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QStringLiteral("Performs basic image conversion checking."));
|
||||
@ -98,6 +137,7 @@ int main(int argc, char **argv)
|
||||
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
int skipped = 0;
|
||||
|
||||
QTextStream(stdout) << "********* "
|
||||
<< "Starting basic read tests for " << suffix << " images *********\n";
|
||||
@ -111,6 +151,13 @@ int main(int argc, char **argv)
|
||||
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
|
||||
|
||||
const QFileInfoList lstImgDir = imgdir.entryInfoList();
|
||||
// Launch 2 runs for each test: first run on a random access device, second run on a sequential access device
|
||||
for (int seq = 0; seq < 2; ++seq) {
|
||||
if (seq) {
|
||||
QTextStream(stdout) << "* Run on SEQUENTIAL ACCESS device\n";
|
||||
} else {
|
||||
QTextStream(stdout) << "* Run on RANDOM ACCESS device\n";
|
||||
}
|
||||
for (const QFileInfo &fi : lstImgDir) {
|
||||
if (!fi.suffix().compare("png", Qt::CaseInsensitive)) {
|
||||
continue;
|
||||
@ -120,20 +167,31 @@ int main(int argc, char **argv)
|
||||
QString expfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
|
||||
QString expfilename = QFileInfo(expfile).fileName();
|
||||
|
||||
QImageReader inputReader(inputfile, format);
|
||||
std::unique_ptr<QIODevice> inputDevice(seq ? new SequentialFile(inputfile) : new QFile(inputfile));
|
||||
QImageReader inputReader(inputDevice.get(), format);
|
||||
QImageReader expReader(expfile, "png");
|
||||
|
||||
QImage inputImage;
|
||||
QImage expImage;
|
||||
|
||||
// inputImage is auto-rotated to final orientation
|
||||
inputReader.setAutoTransform(true);
|
||||
|
||||
if (!expReader.read(&expImage)) {
|
||||
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n";
|
||||
++failed;
|
||||
continue;
|
||||
}
|
||||
if (!inputReader.canRead()) {
|
||||
// All plugins must pass the test on a random device.
|
||||
// canRead() must also return false if the plugin is unable to run on a sequential device.
|
||||
if (inputDevice->isSequential()) {
|
||||
QTextStream(stdout) << "SKIP : " << fi.fileName() << ": cannot read on a sequential device (don't worry, it's ok)\n";
|
||||
++skipped;
|
||||
} else {
|
||||
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed can read: " << inputReader.errorString() << "\n";
|
||||
++failed;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!inputReader.read(&inputImage)) {
|
||||
@ -160,8 +218,8 @@ int main(int argc, char **argv)
|
||||
inputImage = inputImage.convertToFormat(cmpFormat);
|
||||
}
|
||||
if (expImage.format() != cmpFormat) {
|
||||
QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << expfilename << " from " << formatToString(expImage.format()) << " to "
|
||||
<< formatToString(cmpFormat) << '\n';
|
||||
QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << expfilename << " from " << formatToString(expImage.format())
|
||||
<< " to " << formatToString(cmpFormat) << '\n';
|
||||
expImage = expImage.convertToFormat(cmpFormat);
|
||||
}
|
||||
if (fuzzyeq(inputImage, expImage, fuzziness)) {
|
||||
@ -175,8 +233,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTextStream(stdout) << "Totals: " << passed << " passed, " << failed << " failed\n";
|
||||
QTextStream(stdout) << "Totals: " << passed << " passed, " << skipped << " skipped, " << failed << " failed\n";
|
||||
QTextStream(stdout) << "********* "
|
||||
<< "Finished basic read tests for " << suffix << " images *********\n";
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Find the LibRaw library <https://www.libraw.org>
|
||||
# This module defines
|
||||
# LibRaw_VERSION, the version string of LibRaw
|
||||
# LibRaw_INCLUDE_DIR, where to find libraw.h
|
||||
# LibRaw_INCLUDE_DIR, where to find libraw/libraw.h
|
||||
# LibRaw_LIBRARIES, the libraries needed to use LibRaw (non-thread-safe)
|
||||
# LibRaw_r_LIBRARIES, the libraries needed to use LibRaw (thread-safe)
|
||||
# LibRaw_DEFINITIONS, the definitions needed to use LibRaw (non-thread-safe)
|
||||
@ -23,11 +23,10 @@ IF(PKG_CONFIG_FOUND)
|
||||
SET(LibRaw_r_DEFINITIONS ${PC_LIBRAW_R_CFLAGS_OTHER})
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(LibRaw_INCLUDE_DIR libraw.h
|
||||
FIND_PATH(LibRaw_INCLUDE_DIR libraw/libraw.h
|
||||
HINTS
|
||||
${PC_LIBRAW_INCLUDEDIR}
|
||||
${PC_LibRaw_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES libraw
|
||||
)
|
||||
|
||||
FIND_LIBRARY(LibRaw_LIBRARIES NAMES raw
|
||||
@ -43,7 +42,7 @@ FIND_LIBRARY(LibRaw_r_LIBRARIES NAMES raw_r
|
||||
)
|
||||
|
||||
IF(LibRaw_INCLUDE_DIR)
|
||||
FILE(READ ${LibRaw_INCLUDE_DIR}/libraw_version.h _libraw_version_content)
|
||||
FILE(READ ${LibRaw_INCLUDE_DIR}/libraw/libraw_version.h _libraw_version_content)
|
||||
|
||||
STRING(REGEX MATCH "#define LIBRAW_MAJOR_VERSION[ \t]*([0-9]*)\n" _version_major_match ${_libraw_version_content})
|
||||
SET(_libraw_version_major "${CMAKE_MATCH_1}")
|
||||
@ -58,7 +57,7 @@ IF(LibRaw_INCLUDE_DIR)
|
||||
SET(LibRaw_VERSION "${_libraw_version_major}.${_libraw_version_minor}.${_libraw_version_patch}")
|
||||
ELSE()
|
||||
IF(NOT LibRaw_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Failed to get version information from ${LibRaw_INCLUDE_DIR}/libraw_version.h")
|
||||
MESSAGE(STATUS "Failed to get version information from ${LibRaw_INCLUDE_DIR}/libraw/libraw_version.h")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
@ -20,19 +20,26 @@ endfunction()
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_ani SOURCES ani.cpp)
|
||||
install(FILES ani.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES ani.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
if (TARGET avif)
|
||||
kimageformats_add_plugin(kimg_avif SOURCES "avif.cpp")
|
||||
target_link_libraries(kimg_avif "avif")
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES avif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
install(FILES dds-qt.desktop RENAME dds.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES dds-qt.desktop RENAME dds.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
@ -40,14 +47,18 @@ if (BUILD_EPS_PLUGIN)
|
||||
if (TARGET Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||
kimageformats_add_plugin(kimg_eps SOURCES eps.cpp)
|
||||
target_link_libraries(kimg_eps Qt${QT_MAJOR_VERSION}::PrintSupport)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES eps.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
# need this for Qt's version of the plugin
|
||||
install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
# need this for Qt's version of the plugin
|
||||
install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
@ -65,13 +76,17 @@ if(OpenEXR_FOUND)
|
||||
endif()
|
||||
kde_target_enable_exceptions(kimg_exr PRIVATE)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES exr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_hdr SOURCES hdr.cpp)
|
||||
install(FILES hdr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES hdr.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
@ -79,7 +94,10 @@ if (LibHeif_FOUND)
|
||||
kimageformats_add_plugin(kimg_heif SOURCES heif.cpp)
|
||||
target_link_libraries(kimg_heif PkgConfig::LibHeif)
|
||||
kde_target_enable_exceptions(kimg_heif PRIVATE)
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES heif.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
@ -90,43 +108,60 @@ if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||
if (LibJXL_VERSION VERSION_GREATER_EQUAL "0.7.0")
|
||||
target_compile_definitions(kimg_jxl PRIVATE KIMG_JXL_API_VERSION=70)
|
||||
endif()
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES jxl.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pcx SOURCES pcx.cpp)
|
||||
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pic SOURCES pic.cpp)
|
||||
install(FILES pic.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES pic.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_psd SOURCES psd.cpp)
|
||||
install(FILES psd.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES psd.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_ras SOURCES ras.cpp)
|
||||
install(FILES ras.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES ras.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_rgb SOURCES rgb.cpp)
|
||||
install(FILES rgb.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES rgb.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp)
|
||||
install(FILES tga.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES tga.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_xcf SOURCES xcf.cpp)
|
||||
install(FILES xcf.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES xcf.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
@ -134,7 +169,9 @@ if (LibRaw_FOUND)
|
||||
kimageformats_add_plugin(kimg_raw SOURCES raw.cpp)
|
||||
kde_enable_exceptions()
|
||||
target_link_libraries(kimg_raw LibRaw::LibRaw)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES raw.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
@ -143,10 +180,14 @@ if (KF5Archive_FOUND)
|
||||
|
||||
kimageformats_add_plugin(kimg_kra SOURCES kra.cpp)
|
||||
target_link_libraries(kimg_kra KF5::Archive)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES kra.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
kimageformats_add_plugin(kimg_ora SOURCES ora.cpp)
|
||||
target_link_libraries(kimg_ora KF5::Archive)
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
install(FILES ora.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
@ -521,6 +521,9 @@ bool ANIHandler::canRead(QIODevice *device)
|
||||
qWarning("ANIHandler::canRead() called with no device");
|
||||
return false;
|
||||
}
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QByteArray riffIntro = device->peek(12);
|
||||
|
||||
|
@ -42,6 +42,11 @@ bool QAVIFHandler::canRead() const
|
||||
|
||||
if (m_parseState != ParseAvifError) {
|
||||
setFormat("avif");
|
||||
|
||||
if (m_parseState == ParseAvifFinished) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -58,7 +63,7 @@ bool QAVIFHandler::canRead(QIODevice *device)
|
||||
}
|
||||
|
||||
avifROData input;
|
||||
input.data = (const uint8_t *)header.constData();
|
||||
input.data = reinterpret_cast<const uint8_t *>(header.constData());
|
||||
input.size = header.size();
|
||||
|
||||
if (avifPeekCompatibleFileType(&input)) {
|
||||
@ -69,7 +74,7 @@ bool QAVIFHandler::canRead(QIODevice *device)
|
||||
|
||||
bool QAVIFHandler::ensureParsed() const
|
||||
{
|
||||
if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifMetadata) {
|
||||
if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifMetadata || m_parseState == ParseAvifFinished) {
|
||||
return true;
|
||||
}
|
||||
if (m_parseState == ParseAvifError) {
|
||||
@ -83,7 +88,7 @@ bool QAVIFHandler::ensureParsed() const
|
||||
|
||||
bool QAVIFHandler::ensureOpened() const
|
||||
{
|
||||
if (m_parseState == ParseAvifSuccess) {
|
||||
if (m_parseState == ParseAvifSuccess || m_parseState == ParseAvifFinished) {
|
||||
return true;
|
||||
}
|
||||
if (m_parseState == ParseAvifError) {
|
||||
@ -111,7 +116,7 @@ bool QAVIFHandler::ensureDecoder()
|
||||
|
||||
m_rawData = device()->readAll();
|
||||
|
||||
m_rawAvifData.data = (const uint8_t *)m_rawData.constData();
|
||||
m_rawAvifData.data = reinterpret_cast<const uint8_t *>(m_rawData.constData());
|
||||
m_rawAvifData.size = m_rawData.size();
|
||||
|
||||
if (avifPeekCompatibleFileType(&m_rawAvifData) == AVIF_FALSE) {
|
||||
@ -132,6 +137,10 @@ bool QAVIFHandler::ensureDecoder()
|
||||
m_decoder->strictFlags = AVIF_STRICT_DISABLED;
|
||||
#endif
|
||||
|
||||
#if AVIF_VERSION >= 110000
|
||||
m_decoder->imageDimensionLimit = 65535;
|
||||
#endif
|
||||
|
||||
avifResult decodeResult;
|
||||
|
||||
decodeResult = avifDecoderSetIOMemory(m_decoder, m_rawAvifData.data, m_rawAvifData.size);
|
||||
@ -246,7 +255,7 @@ bool QAVIFHandler::decode_one_frame()
|
||||
|
||||
QColorSpace colorspace;
|
||||
if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) {
|
||||
const QByteArray icc_data((const char *)m_decoder->image->icc.data, (int)m_decoder->image->icc.size);
|
||||
const QByteArray icc_data(reinterpret_cast<const char *>(m_decoder->image->icc.data), m_decoder->image->icc.size);
|
||||
colorspace = QColorSpace::fromIccProfile(icc_data);
|
||||
if (!colorspace.isValid()) {
|
||||
qWarning("AVIF image has Qt-unsupported or invalid ICC profile!");
|
||||
@ -336,7 +345,7 @@ bool QAVIFHandler::decode_one_frame()
|
||||
rgb.format = AVIF_RGB_FORMAT_ARGB;
|
||||
#endif
|
||||
|
||||
#if (AVIF_VERSION >= 80400) && (AVIF_VERSION <= 100100)
|
||||
#if AVIF_VERSION >= 80400
|
||||
if (m_decoder->imageCount > 1) {
|
||||
/* accelerate animated AVIF */
|
||||
rgb.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
|
||||
@ -351,12 +360,7 @@ bool QAVIFHandler::decode_one_frame()
|
||||
rgb.rowBytes = result.bytesPerLine();
|
||||
rgb.pixels = result.bits();
|
||||
|
||||
#if AVIF_VERSION >= 100101
|
||||
// use faster decoding for animations
|
||||
avifResult res = avifImageYUVToRGB(m_decoder->image, &rgb, (m_decoder->imageCount > 1) ? AVIF_CHROMA_UPSAMPLING_NEAREST : AVIF_YUV_TO_RGB_DEFAULT);
|
||||
#else
|
||||
avifResult res = avifImageYUVToRGB(m_decoder->image, &rgb);
|
||||
#endif
|
||||
if (res != AVIF_RESULT_OK) {
|
||||
qWarning("ERROR in avifImageYUVToRGB: %s", avifResultToString(res));
|
||||
return false;
|
||||
@ -459,6 +463,13 @@ bool QAVIFHandler::read(QImage *image)
|
||||
*image = m_current_image;
|
||||
if (imageCount() >= 2) {
|
||||
m_must_jump_to_next_image = true;
|
||||
if (m_decoder->imageIndex >= m_decoder->imageCount - 1) {
|
||||
// all frames in animation have been read
|
||||
m_parseState = ParseAvifFinished;
|
||||
}
|
||||
} else {
|
||||
// the static image has been read
|
||||
m_parseState = ParseAvifFinished;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -756,7 +767,7 @@ bool QAVIFHandler::write(const QImage &image)
|
||||
avif->transferCharacteristics = transfer_to_save;
|
||||
|
||||
if (iccprofile.size() > 0) {
|
||||
avifImageSetProfileICC(avif, (const uint8_t *)iccprofile.constData(), iccprofile.size());
|
||||
avifImageSetProfileICC(avif, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size());
|
||||
}
|
||||
|
||||
avifRGBImage rgb;
|
||||
@ -782,11 +793,7 @@ bool QAVIFHandler::write(const QImage &image)
|
||||
}
|
||||
}
|
||||
|
||||
#if AVIF_VERSION >= 100101
|
||||
res = avifImageRGBToYUV(avif, &rgb, AVIF_RGB_TO_YUV_DEFAULT);
|
||||
#else
|
||||
res = avifImageRGBToYUV(avif, &rgb);
|
||||
#endif
|
||||
if (res != AVIF_RESULT_OK) {
|
||||
qWarning("ERROR in avifImageRGBToYUV: %s", avifResultToString(res));
|
||||
return false;
|
||||
@ -914,6 +921,7 @@ bool QAVIFHandler::jumpToNextImage()
|
||||
|
||||
if (m_decoder->imageIndex >= 0) {
|
||||
if (m_decoder->imageCount < 2) {
|
||||
m_parseState = ParseAvifSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -958,11 +966,13 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
|
||||
|
||||
if (m_decoder->imageCount < 2) { // not an animation
|
||||
if (imageNumber == 0) {
|
||||
return ensureOpened();
|
||||
} else {
|
||||
return false;
|
||||
if (ensureOpened()) {
|
||||
m_parseState = ParseAvifSuccess;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageNumber < 0 || imageNumber >= m_decoder->imageCount) { // wrong index
|
||||
return false;
|
||||
@ -970,6 +980,7 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
|
||||
|
||||
if (imageNumber == m_decoder->imageIndex) { // we are here already
|
||||
m_must_jump_to_next_image = false;
|
||||
m_parseState = ParseAvifSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1028,7 +1039,8 @@ int QAVIFHandler::loopCount() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
// Endless loop to work around https://github.com/AOMediaCodec/libavif/issues/347
|
||||
return -1;
|
||||
}
|
||||
|
||||
QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
|
||||
@ -1045,12 +1057,26 @@ QPointF QAVIFHandler::CompatibleChromacity(qreal chrX, qreal chrY)
|
||||
|
||||
QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
static const bool isAvifDecoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_DECODE) != nullptr);
|
||||
static const bool isAvifEncoderAvailable(avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE) != nullptr);
|
||||
|
||||
if (format == "avif") {
|
||||
return Capabilities(CanRead | CanWrite);
|
||||
Capabilities format_cap;
|
||||
if (isAvifDecoderAvailable) {
|
||||
format_cap |= CanRead;
|
||||
}
|
||||
if (isAvifEncoderAvailable) {
|
||||
format_cap |= CanWrite;
|
||||
}
|
||||
return format_cap;
|
||||
}
|
||||
|
||||
if (format == "avifs") {
|
||||
return Capabilities(CanRead);
|
||||
Capabilities format_cap;
|
||||
if (isAvifDecoderAvailable) {
|
||||
format_cap |= CanRead;
|
||||
}
|
||||
return format_cap;
|
||||
}
|
||||
|
||||
if (!format.isEmpty()) {
|
||||
@ -1061,10 +1087,10 @@ QImageIOPlugin::Capabilities QAVIFPlugin::capabilities(QIODevice *device, const
|
||||
}
|
||||
|
||||
Capabilities cap;
|
||||
if (device->isReadable() && QAVIFHandler::canRead(device)) {
|
||||
if (device->isReadable() && QAVIFHandler::canRead(device) && isAvifDecoderAvailable) {
|
||||
cap |= CanRead;
|
||||
}
|
||||
if (device->isWritable()) {
|
||||
if (device->isWritable() && isAvifEncoderAvailable) {
|
||||
cap |= CanWrite;
|
||||
}
|
||||
return cap;
|
||||
|
@ -55,6 +55,7 @@ private:
|
||||
ParseAvifNotParsed = 0,
|
||||
ParseAvifSuccess = 1,
|
||||
ParseAvifMetadata = 2,
|
||||
ParseAvifFinished = 3,
|
||||
};
|
||||
|
||||
ParseAvifState m_parseState;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <QDebug>
|
||||
#include <QPointF>
|
||||
#include <QSysInfo>
|
||||
#include <limits>
|
||||
#include <string.h>
|
||||
|
||||
namespace // Private.
|
||||
@ -52,6 +53,11 @@ private:
|
||||
|
||||
} // namespace
|
||||
|
||||
size_t HEIFHandler::m_initialized_count = 0;
|
||||
bool HEIFHandler::m_plugins_queried = false;
|
||||
bool HEIFHandler::m_heif_decoder_available = false;
|
||||
bool HEIFHandler::m_heif_encoder_available = false;
|
||||
|
||||
HEIFHandler::HEIFHandler()
|
||||
: m_parseState(ParseHeicNotParsed)
|
||||
, m_quality(100)
|
||||
@ -88,6 +94,21 @@ bool HEIFHandler::write(const QImage &image)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
startHeifLib();
|
||||
#endif
|
||||
|
||||
bool success = write_helper(image);
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
finishHeifLib();
|
||||
#endif
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HEIFHandler::write_helper(const QImage &image)
|
||||
{
|
||||
int save_depth; // 8 or 10bit per channel
|
||||
QImage::Format tmpformat; // format for temporary image
|
||||
const bool save_alpha = image.hasAlphaChannel();
|
||||
@ -356,8 +377,18 @@ bool HEIFHandler::ensureParsed() const
|
||||
|
||||
HEIFHandler *that = const_cast<HEIFHandler *>(this);
|
||||
|
||||
return that->ensureDecoder();
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
startHeifLib();
|
||||
#endif
|
||||
|
||||
bool success = that->ensureDecoder();
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
finishHeifLib();
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HEIFHandler::ensureDecoder()
|
||||
{
|
||||
if (m_parseState != ParseHeicNotParsed) {
|
||||
@ -375,7 +406,7 @@ bool HEIFHandler::ensureDecoder()
|
||||
|
||||
try {
|
||||
heif::Context ctx;
|
||||
ctx.read_from_memory_without_copy((const void *)(buffer.constData()), buffer.size());
|
||||
ctx.read_from_memory_without_copy(static_cast<const void *>(buffer.constData()), buffer.size());
|
||||
|
||||
heif::ImageHandle handle = ctx.get_primary_image_handle();
|
||||
|
||||
@ -607,8 +638,8 @@ bool HEIFHandler::ensureDecoder()
|
||||
heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle.get_raw_image_handle());
|
||||
struct heif_error err;
|
||||
if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
|
||||
int rawProfileSize = (int)heif_image_handle_get_raw_color_profile_size(handle.get_raw_image_handle());
|
||||
if (rawProfileSize > 0) {
|
||||
size_t rawProfileSize = heif_image_handle_get_raw_color_profile_size(handle.get_raw_image_handle());
|
||||
if (rawProfileSize > 0 && rawProfileSize < std::numeric_limits<int>::max()) {
|
||||
QByteArray ba(rawProfileSize, 0);
|
||||
err = heif_image_handle_get_raw_color_profile(handle.get_raw_image_handle(), ba.data());
|
||||
if (err.code) {
|
||||
@ -620,7 +651,7 @@ bool HEIFHandler::ensureDecoder()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "icc profile is empty";
|
||||
qWarning() << "icc profile is empty or above limits";
|
||||
}
|
||||
|
||||
} else if (profileType == heif_color_profile_type_nclx) {
|
||||
@ -696,14 +727,100 @@ bool HEIFHandler::ensureDecoder()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HEIFHandler::isHeifDecoderAvailable()
|
||||
{
|
||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
||||
|
||||
if (!m_plugins_queried) {
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
if (m_initialized_count == 0) {
|
||||
heif_init(nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
|
||||
m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
|
||||
m_plugins_queried = true;
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
if (m_initialized_count == 0) {
|
||||
heif_deinit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return m_heif_decoder_available;
|
||||
}
|
||||
|
||||
bool HEIFHandler::isHeifEncoderAvailable()
|
||||
{
|
||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
||||
|
||||
if (!m_plugins_queried) {
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
if (m_initialized_count == 0) {
|
||||
heif_init(nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
|
||||
m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
|
||||
m_plugins_queried = true;
|
||||
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
if (m_initialized_count == 0) {
|
||||
heif_deinit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return m_heif_encoder_available;
|
||||
}
|
||||
|
||||
void HEIFHandler::startHeifLib()
|
||||
{
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
||||
|
||||
if (m_initialized_count == 0) {
|
||||
heif_init(nullptr);
|
||||
}
|
||||
|
||||
m_initialized_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void HEIFHandler::finishHeifLib()
|
||||
{
|
||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
||||
|
||||
if (m_initialized_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_initialized_count--;
|
||||
if (m_initialized_count == 0) {
|
||||
heif_deinit();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
QMutex &HEIFHandler::getHEIFHandlerMutex()
|
||||
{
|
||||
static QMutex heif_handler_mutex;
|
||||
return heif_handler_mutex;
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
if (format == "heif" || format == "heic") {
|
||||
Capabilities format_cap;
|
||||
if (heif_have_decoder_for_format(heif_compression_HEVC)) {
|
||||
if (HEIFHandler::isHeifDecoderAvailable()) {
|
||||
format_cap |= CanRead;
|
||||
}
|
||||
if (heif_have_encoder_for_format(heif_compression_HEVC)) {
|
||||
if (HEIFHandler::isHeifEncoderAvailable()) {
|
||||
format_cap |= CanWrite;
|
||||
}
|
||||
return format_cap;
|
||||
@ -716,11 +833,11 @@ QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const Q
|
||||
}
|
||||
|
||||
Capabilities cap;
|
||||
if (device->isReadable() && HEIFHandler::canRead(device) && heif_have_decoder_for_format(heif_compression_HEVC)) {
|
||||
if (device->isReadable() && HEIFHandler::canRead(device) && HEIFHandler::isHeifDecoderAvailable()) {
|
||||
cap |= CanRead;
|
||||
}
|
||||
|
||||
if (device->isWritable() && heif_have_encoder_for_format(heif_compression_HEVC)) {
|
||||
if (device->isWritable() && HEIFHandler::isHeifEncoderAvailable()) {
|
||||
cap |= CanWrite;
|
||||
}
|
||||
return cap;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <QByteArray>
|
||||
#include <QImage>
|
||||
#include <QImageIOPlugin>
|
||||
#include <QMutex>
|
||||
|
||||
class HEIFHandler : public QImageIOHandler
|
||||
{
|
||||
@ -29,6 +30,9 @@ public:
|
||||
void setOption(ImageOption option, const QVariant &value) override;
|
||||
bool supportsOption(ImageOption option) const override;
|
||||
|
||||
static bool isHeifDecoderAvailable();
|
||||
static bool isHeifEncoderAvailable();
|
||||
|
||||
private:
|
||||
static bool isSupportedBMFFType(const QByteArray &header);
|
||||
bool ensureParsed() const;
|
||||
@ -43,6 +47,18 @@ private:
|
||||
ParseHeicState m_parseState;
|
||||
int m_quality;
|
||||
QImage m_current_image;
|
||||
|
||||
bool write_helper(const QImage &image);
|
||||
|
||||
static void startHeifLib();
|
||||
static void finishHeifLib();
|
||||
static size_t m_initialized_count;
|
||||
|
||||
static bool m_plugins_queried;
|
||||
static bool m_heif_decoder_available;
|
||||
static bool m_heif_encoder_available;
|
||||
|
||||
static QMutex &getHEIFHandlerMutex();
|
||||
};
|
||||
|
||||
class HEIFPlugin : public QImageIOPlugin
|
||||
|
@ -48,6 +48,11 @@ bool QJpegXLHandler::canRead() const
|
||||
|
||||
if (m_parseState != ParseJpegXLError) {
|
||||
setFormat("jxl");
|
||||
|
||||
if (m_parseState == ParseJpegXLFinished) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -63,7 +68,7 @@ bool QJpegXLHandler::canRead(QIODevice *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
JxlSignature signature = JxlSignatureCheck((const uint8_t *)header.constData(), header.size());
|
||||
JxlSignature signature = JxlSignatureCheck(reinterpret_cast<const uint8_t *>(header.constData()), header.size());
|
||||
if (signature == JXL_SIG_CODESTREAM || signature == JXL_SIG_CONTAINER) {
|
||||
return true;
|
||||
}
|
||||
@ -72,7 +77,7 @@ bool QJpegXLHandler::canRead(QIODevice *device)
|
||||
|
||||
bool QJpegXLHandler::ensureParsed() const
|
||||
{
|
||||
if (m_parseState == ParseJpegXLSuccess || m_parseState == ParseJpegXLBasicInfoParsed) {
|
||||
if (m_parseState == ParseJpegXLSuccess || m_parseState == ParseJpegXLBasicInfoParsed || m_parseState == ParseJpegXLFinished) {
|
||||
return true;
|
||||
}
|
||||
if (m_parseState == ParseJpegXLError) {
|
||||
@ -90,7 +95,7 @@ bool QJpegXLHandler::ensureALLCounted() const
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_parseState == ParseJpegXLSuccess) {
|
||||
if (m_parseState == ParseJpegXLSuccess || m_parseState == ParseJpegXLFinished) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -111,7 +116,7 @@ bool QJpegXLHandler::ensureDecoder()
|
||||
return false;
|
||||
}
|
||||
|
||||
JxlSignature signature = JxlSignatureCheck((const uint8_t *)m_rawData.constData(), m_rawData.size());
|
||||
JxlSignature signature = JxlSignatureCheck(reinterpret_cast<const uint8_t *>(m_rawData.constData()), m_rawData.size());
|
||||
if (signature != JXL_SIG_CODESTREAM && signature != JXL_SIG_CONTAINER) {
|
||||
m_parseState = ParseJpegXLError;
|
||||
return false;
|
||||
@ -139,7 +144,7 @@ bool QJpegXLHandler::ensureDecoder()
|
||||
}
|
||||
}
|
||||
|
||||
if (JxlDecoderSetInput(m_decoder, (const uint8_t *)m_rawData.constData(), m_rawData.size()) != JXL_DEC_SUCCESS) {
|
||||
if (JxlDecoderSetInput(m_decoder, reinterpret_cast<const uint8_t *>(m_rawData.constData()), m_rawData.size()) != JXL_DEC_SUCCESS) {
|
||||
qWarning("ERROR: JxlDecoderSetInput failed");
|
||||
m_parseState = ParseJpegXLError;
|
||||
return false;
|
||||
@ -273,8 +278,12 @@ bool QJpegXLHandler::countALLFrames()
|
||||
size_t icc_size = 0;
|
||||
if (JxlDecoderGetICCProfileSize(m_decoder, &m_input_pixel_format, JXL_COLOR_PROFILE_TARGET_DATA, &icc_size) == JXL_DEC_SUCCESS) {
|
||||
if (icc_size > 0) {
|
||||
QByteArray icc_data((int)icc_size, 0);
|
||||
if (JxlDecoderGetColorAsICCProfile(m_decoder, &m_input_pixel_format, JXL_COLOR_PROFILE_TARGET_DATA, (uint8_t *)icc_data.data(), icc_data.size())
|
||||
QByteArray icc_data(icc_size, 0);
|
||||
if (JxlDecoderGetColorAsICCProfile(m_decoder,
|
||||
&m_input_pixel_format,
|
||||
JXL_COLOR_PROFILE_TARGET_DATA,
|
||||
reinterpret_cast<uint8_t *>(icc_data.data()),
|
||||
icc_data.size())
|
||||
== JXL_DEC_SUCCESS) {
|
||||
m_colorspace = QColorSpace::fromIccProfile(icc_data);
|
||||
|
||||
@ -397,7 +406,15 @@ bool QJpegXLHandler::decode_one_frame()
|
||||
if (!rewind()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// all frames in animation have been read
|
||||
m_parseState = ParseJpegXLFinished;
|
||||
} else {
|
||||
m_parseState = ParseJpegXLSuccess;
|
||||
}
|
||||
} else {
|
||||
// the static image has been read
|
||||
m_parseState = ParseJpegXLFinished;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -609,7 +626,7 @@ bool QJpegXLHandler::write(const QImage &image)
|
||||
}
|
||||
|
||||
if (!convert_color_profile && iccprofile.size() > 0) {
|
||||
status = JxlEncoderSetICCProfile(encoder, (const uint8_t *)iccprofile.constData(), iccprofile.size());
|
||||
status = JxlEncoderSetICCProfile(encoder, reinterpret_cast<const uint8_t *>(iccprofile.constData()), iccprofile.size());
|
||||
if (status != JXL_ENC_SUCCESS) {
|
||||
qWarning("JxlEncoderSetICCProfile failed!");
|
||||
if (runner) {
|
||||
@ -648,7 +665,7 @@ bool QJpegXLHandler::write(const QImage &image)
|
||||
#endif
|
||||
|
||||
if (image.hasAlphaChannel() || ((save_depth == 8) && (xsize % 4 == 0))) {
|
||||
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, (void *)tmpimage.constBits(), buffer_size);
|
||||
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, static_cast<const void *>(tmpimage.constBits()), buffer_size);
|
||||
} else {
|
||||
if (save_depth > 8) { // 16bit depth without alpha channel
|
||||
uint16_t *tmp_buffer = new (std::nothrow) uint16_t[3 * xsize * ysize];
|
||||
@ -679,7 +696,7 @@ bool QJpegXLHandler::write(const QImage &image)
|
||||
src_pixels += 2; // skipalpha
|
||||
}
|
||||
}
|
||||
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, (void *)tmp_buffer, buffer_size);
|
||||
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, static_cast<const void *>(tmp_buffer), buffer_size);
|
||||
delete[] tmp_buffer;
|
||||
} else { // 8bit depth without alpha channel
|
||||
uchar *tmp_buffer8 = new (std::nothrow) uchar[3 * xsize * ysize];
|
||||
@ -698,7 +715,7 @@ bool QJpegXLHandler::write(const QImage &image)
|
||||
memcpy(dest_pixels8, tmpimage.constScanLine(y), rowbytes);
|
||||
dest_pixels8 += rowbytes;
|
||||
}
|
||||
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, (void *)tmp_buffer8, buffer_size);
|
||||
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, static_cast<const void *>(tmp_buffer8), buffer_size);
|
||||
delete[] tmp_buffer8;
|
||||
}
|
||||
}
|
||||
@ -856,6 +873,7 @@ bool QJpegXLHandler::jumpToNextImage()
|
||||
}
|
||||
}
|
||||
|
||||
m_parseState = ParseJpegXLSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -870,12 +888,14 @@ bool QJpegXLHandler::jumpToImage(int imageNumber)
|
||||
}
|
||||
|
||||
if (imageNumber == m_currentimage_index) {
|
||||
m_parseState = ParseJpegXLSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (imageNumber > m_currentimage_index) {
|
||||
JxlDecoderSkipFrames(m_decoder, imageNumber - m_currentimage_index);
|
||||
m_currentimage_index = imageNumber;
|
||||
m_parseState = ParseJpegXLSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -887,6 +907,7 @@ bool QJpegXLHandler::jumpToImage(int imageNumber)
|
||||
JxlDecoderSkipFrames(m_decoder, imageNumber);
|
||||
}
|
||||
m_currentimage_index = imageNumber;
|
||||
m_parseState = ParseJpegXLSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -910,7 +931,7 @@ int QJpegXLHandler::loopCount() const
|
||||
}
|
||||
|
||||
if (m_basicinfo.have_animation) {
|
||||
return 1;
|
||||
return (m_basicinfo.animation.num_loops > 0) ? m_basicinfo.animation.num_loops - 1 : -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -930,7 +951,7 @@ bool QJpegXLHandler::rewind()
|
||||
}
|
||||
}
|
||||
|
||||
if (JxlDecoderSetInput(m_decoder, (const uint8_t *)m_rawData.constData(), m_rawData.size()) != JXL_DEC_SUCCESS) {
|
||||
if (JxlDecoderSetInput(m_decoder, reinterpret_cast<const uint8_t *>(m_rawData.constData()), m_rawData.size()) != JXL_DEC_SUCCESS) {
|
||||
qWarning("ERROR: JxlDecoderSetInput failed");
|
||||
m_parseState = ParseJpegXLError;
|
||||
return false;
|
||||
|
@ -57,6 +57,7 @@ private:
|
||||
ParseJpegXLNotParsed = 0,
|
||||
ParseJpegXLSuccess = 1,
|
||||
ParseJpegXLBasicInfoParsed = 2,
|
||||
ParseJpegXLFinished = 3,
|
||||
};
|
||||
|
||||
ParseJpegXLState m_parseState;
|
||||
|
@ -57,6 +57,9 @@ bool KraHandler::canRead(QIODevice *device)
|
||||
qWarning("KraHandler::canRead() called with no device");
|
||||
return false;
|
||||
}
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buff[57];
|
||||
if (device->peek(buff, sizeof(buff)) == sizeof(buff)) {
|
||||
|
@ -56,6 +56,9 @@ bool OraHandler::canRead(QIODevice *device)
|
||||
qWarning("OraHandler::canRead() called with no device");
|
||||
return false;
|
||||
}
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buff[54];
|
||||
if (device->peek(buff, sizeof(buff)) == sizeof(buff)) {
|
||||
|
@ -174,7 +174,7 @@ static QDataStream &operator>>(QDataStream &s, PCXHEADER &ph)
|
||||
|
||||
// Skip the rest of the header
|
||||
quint8 byte;
|
||||
while (s.device()->pos() < 128) {
|
||||
for (auto i = 0; i < 54; ++i) {
|
||||
s >> byte;
|
||||
}
|
||||
|
||||
@ -684,12 +684,6 @@ bool PCXHandler::canRead(QIODevice *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
// We do not support sequential images
|
||||
// We need to know the current position to properly read the header
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 oldPos = device->pos();
|
||||
|
||||
char head[1];
|
||||
|
@ -172,7 +172,8 @@ struct PSDLayerAndMaskSection {
|
||||
if (globalLayerMaskInfo.size > -1) {
|
||||
currentSize += globalLayerMaskInfo.size + 4;
|
||||
}
|
||||
for (auto && v : additionalLayerInfo.values()) {
|
||||
auto aliv = additionalLayerInfo.values();
|
||||
for (auto &&v : aliv) {
|
||||
currentSize += (12 + v.size);
|
||||
if (v.signature == S_8B64)
|
||||
currentSize += 4;
|
||||
@ -286,12 +287,6 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
|
||||
qint32 sectioSize;
|
||||
s >> sectioSize;
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
auto pos = qint64();
|
||||
if (auto dev = s.device())
|
||||
pos = dev->pos();
|
||||
#endif
|
||||
|
||||
// Reading Image resource block
|
||||
for (auto size = sectioSize; size > 0;) {
|
||||
// Length Description
|
||||
@ -356,14 +351,6 @@ static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok
|
||||
irs.insert(id, irb);
|
||||
}
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
if (auto dev = s.device()) {
|
||||
if ((dev->pos() - pos) != sectioSize) {
|
||||
*ok = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return irs;
|
||||
}
|
||||
|
||||
@ -659,6 +646,9 @@ static bool IsValid(const PSDHeader &header)
|
||||
// Check that the header is supported by this plugin.
|
||||
static bool IsSupported(const PSDHeader &header)
|
||||
{
|
||||
if (!IsValid(header)) {
|
||||
return false;
|
||||
}
|
||||
if (header.version != 1 && header.version != 2) {
|
||||
return false;
|
||||
}
|
||||
@ -673,10 +663,15 @@ static bool IsSupported(const PSDHeader &header)
|
||||
header.color_mode != CM_INDEXED &&
|
||||
header.color_mode != CM_DUOTONE &&
|
||||
header.color_mode != CM_CMYK &&
|
||||
header.color_mode != CM_MULTICHANNEL &&
|
||||
header.color_mode != CM_LABCOLOR &&
|
||||
header.color_mode != CM_BITMAP) {
|
||||
return false;
|
||||
}
|
||||
if (header.color_mode == CM_MULTICHANNEL &&
|
||||
header.channel_count < 4) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -742,7 +737,8 @@ static QImage::Format imageFormat(const PSDHeader &header, bool alpha)
|
||||
else
|
||||
format = header.channel_count < 4 || !alpha ? QImage::Format_RGB888 : QImage::Format_RGBA8888;
|
||||
break;
|
||||
case CM_CMYK: // Photoshop supports CMYK 8-bits and 16-bits only
|
||||
case CM_MULTICHANNEL: // Treat MCH as CMYK (number of channel check is done in IsSupported())
|
||||
case CM_CMYK: // Photoshop supports CMYK/MCH 8-bits and 16-bits only
|
||||
if (header.depth == 16)
|
||||
format = header.channel_count < 5 || !alpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64;
|
||||
else if (header.depth == 8)
|
||||
@ -1091,7 +1087,7 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
||||
}
|
||||
|
||||
// Conversion to RGB
|
||||
if (header.color_mode == CM_CMYK) {
|
||||
if (header.color_mode == CM_CMYK || header.color_mode == CM_MULTICHANNEL) {
|
||||
if (header.depth == 8)
|
||||
cmykToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
|
||||
else
|
||||
@ -1250,35 +1246,27 @@ bool PSDHandler::canRead(QIODevice *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 oldPos = device->pos();
|
||||
device->startTransaction();
|
||||
|
||||
char head[4];
|
||||
qint64 readBytes = device->read(head, sizeof(head));
|
||||
if (readBytes < 0) {
|
||||
qWarning() << "Read failed" << device->errorString();
|
||||
return false;
|
||||
}
|
||||
QDataStream s(device);
|
||||
s.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
if (readBytes != sizeof(head)) {
|
||||
if (device->isSequential()) {
|
||||
while (readBytes > 0) {
|
||||
device->ungetChar(head[readBytes-- - 1]);
|
||||
}
|
||||
} else {
|
||||
device->seek(oldPos);
|
||||
}
|
||||
PSDHeader header;
|
||||
s >> header;
|
||||
|
||||
device->rollbackTransaction();
|
||||
|
||||
if (s.status() != QDataStream::Ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (device->isSequential()) {
|
||||
while (readBytes > 0) {
|
||||
device->ungetChar(head[readBytes-- - 1]);
|
||||
if (header.color_mode == CM_CMYK || header.color_mode == CM_LABCOLOR || header.color_mode == CM_MULTICHANNEL) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
device->seek(oldPos);
|
||||
}
|
||||
|
||||
return qstrncmp(head, "8BPS", 4) == 0;
|
||||
return IsSupported(header);
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities PSDPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
|
@ -19,11 +19,7 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
#include <libraw.h>
|
||||
#else
|
||||
#include <libraw/libraw.h>
|
||||
#endif
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
// This should be used to exclude the local QIODevice wrapper of the LibRaw_abstract_datastream interface.
|
||||
@ -115,12 +111,19 @@ public:
|
||||
}
|
||||
virtual int read(void *ptr, size_t sz, size_t nmemb) override
|
||||
{
|
||||
auto read = m_device->read(reinterpret_cast<char *>(ptr), sz * nmemb);
|
||||
if (read < 1) {
|
||||
qint64 read = 0;
|
||||
if (sz == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (auto o = read % sz) {
|
||||
seek(-(sz - o), SEEK_CUR);
|
||||
auto data = reinterpret_cast<char*>(ptr);
|
||||
for (qint64 r = 0, size = sz * nmemb; read < size; read += r) {
|
||||
if (m_device->atEnd()) {
|
||||
break;
|
||||
}
|
||||
r = m_device->read(data + read, size - read);
|
||||
if (r < 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return read / sz;
|
||||
}
|
||||
@ -673,6 +676,9 @@ bool LoadRAW(QImageIOHandler *handler, QImage &img)
|
||||
if (params.output_color == 4) {
|
||||
img.setColorSpace(QColorSpace(QColorSpace::ProPhotoRgb));
|
||||
}
|
||||
if (params.output_color == 7) {
|
||||
img.setColorSpace(QColorSpace(QColorSpace::DisplayP3));
|
||||
}
|
||||
}
|
||||
|
||||
// *** Set the metadata
|
||||
@ -855,6 +861,14 @@ int RAWHandler::currentImageNumber() const
|
||||
|
||||
bool RAWHandler::canRead(QIODevice *device)
|
||||
{
|
||||
if (!device) {
|
||||
qWarning("RAWHandler::canRead() called with no device");
|
||||
return false;
|
||||
}
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
device->startTransaction();
|
||||
|
||||
std::unique_ptr<LibRaw> rawProcessor(new LibRaw);
|
||||
|
@ -3341,6 +3341,9 @@ bool XCFHandler::canRead(QIODevice *device)
|
||||
qCDebug(XCFPLUGIN) << "XCFHandler::canRead() called with no device";
|
||||
return false;
|
||||
}
|
||||
if (device->isSequential()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 oldPos = device->pos();
|
||||
|
||||
|