Compare commits

..

24 Commits

Author SHA1 Message Date
96b40da089 GIT_SILENT Upgrade ECM and KF version requirements for 5.83.0 release. 2021-06-05 08:55:28 +00:00
bf3f94da76 avif: Adjust for libavif breaking change 2021-06-04 14:37:10 +02:00
318dacda75 Remove compiler flags already defined in extra-cmake-modules
-DQT_NO_FOREACH

GIT_SILENT
2021-05-23 17:18:51 +02:00
e358bb0feb Bump required CMake version to 3.16
KF6 task: https://phabricator.kde.org/T14467
2021-05-17 13:21:23 +02:00
dca6e87c89 Enable HEIC plugin to save all ICC profiles 2021-05-14 12:30:28 +02:00
62f9af9a35 Color profile loading/saving fixes
Allow saving Qt-unsupported variants of ICC profiles, they could be
correctly handled by apps with wider color management support.
Change way how QColorSpace is created to avoid
rare problems in some apps.
2021-05-13 16:56:46 +02:00
ff53d3d7e9 xcf: Make sure offsets are not negative
It's not a huge problem since QIODevice::seek() is a noop on negative values but it's
just better to bail out as soon as possible when we realize the file is
broken
2021-05-05 17:23:59 +02:00
780f342825 GIT_SILENT Add auto generated files to .gitignore 2021-05-02 12:48:16 +02:00
297ed9a2fe xcf: Fix Stack-buffer-overflow WRITE on broken files
oss-fuzz/33742
2021-05-02 09:50:50 +00:00
55b4077f2c GIT_SILENT Upgrade ECM and KF version requirements for 5.82.0 release. 2021-05-01 09:42:14 +00:00
2429c95336 Support building with OpenEXR 3
Try to find OpenEXR 3 first via the upstream cmake config and fallback to using our FindOpenEXR
2021-04-24 10:17:25 +00:00
224f892b09 GIT_SILENT increase KF_DISABLE_DEPRECATED_BEFORE_AND_AT 2021-04-11 12:05:38 +02:00
64fa129ed6 GIT_SILENT Add auto generated files to .gitignore 2021-04-07 21:06:01 +02:00
3cb4021afc test: imageconverter: add a way to list mimes instead of formats 2021-04-05 09:44:03 +00:00
95a19a15c3 xcf: fix new[]/delete mismatch, as detected by ASAN 2021-04-04 17:30:52 +02:00
1ba23a1e8e Port away from QPrinter::setPaperSize, deprecated in Qt 5.15
The formula was found in Qt's qt_pixelMultiplier (qpagesize.cpp)
as called by the deprecated setPaperSize method (when the unit is
DevicePixel)

NO_CHANGELOG
2021-04-04 15:56:13 +02:00
bc3c04c7ce GIT_SILENT Upgrade Qt5 version requirement to 5.15.0. 2021-04-04 14:44:40 +02:00
2755f74fbb ani: convert +1 to -1 so we don't do a potential integer overflow
oss-fuzz/32601

runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
2021-04-03 22:46:33 +00:00
3b0c767f82 GIT_SILENT Upgrade ECM and KF version requirements for 5.81.0 release. 2021-04-03 09:33:41 +00:00
e80fcd7c30 GIT_SILENT increase KF_DISABLE_DEPRECATED_BEFORE_AND_AT 2021-03-27 11:37:36 +01:00
a73e3d44dd Add .git-blame-ignore-revs
GIT_SILENT
2021-03-09 02:18:09 +02:00
1169859b07 Run clang-format on all cpp/h files
NO_CHANGELOG
2021-03-08 20:15:33 +02:00
04e276dcb3 Add clang-format bits to CMakeLists.txt
GIT_SILENT
2021-03-08 20:14:48 +02:00
e3ab850712 Add a trailing comma to enum
Should help produce better diffs and clang-format won't squash the enum
on one line.

GIT_SILENT
2021-03-08 20:14:42 +02:00
36 changed files with 1126 additions and 1312 deletions

2
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,2 @@
#clang-format
1169859b07f25c865ee0bfc2a7dc97a431651776

4
.gitignore vendored
View File

@ -22,3 +22,7 @@ CMakeLists.txt.user*
.cmake/
/.clang-format
/compile_commands.json
.clangd
.idea
/cmake-build*
.cache

View File

@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.6)
cmake_minimum_required(VERSION 3.16)
project(KImageFormats)
set (CMAKE_CXX_STANDARD 14)
include(FeatureSummary)
find_package(ECM 5.80.0 NO_MODULE)
find_package(ECM 5.83.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)
@ -15,11 +15,12 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings)
include(KDEGitCommitHooks)
include(CheckIncludeFiles)
set(REQUIRED_QT_VERSION 5.14.0)
set(REQUIRED_QT_VERSION 5.15.0)
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(KF5Archive)
@ -42,7 +43,10 @@ if (UNIX)
endif()
endif()
find_package(OpenEXR 3.0 CONFIG QUIET)
if(NOT OpenEXR_FOUND)
find_package(OpenEXR)
endif()
set_package_properties(OpenEXR PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for the QImage plugin for OpenEXR images"
@ -61,11 +65,10 @@ if(KIMAGEFORMATS_HEIF)
endif()
add_feature_info(LibHeif LibHeif_FOUND "required for the QImage plugin for HEIF/HEIC images")
add_definitions(-DQT_NO_FOREACH)
# 050d00 (5.13) triggers a BIC in qimageiohandler.h, in Qt 5.13, so do not enable that until we can require 5.14
# https://codereview.qt-project.org/c/qt/qtbase/+/279215
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050e00)
add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054F00)
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050f00)
add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x055100)
add_subdirectory(src)
if (BUILD_TESTING)
add_subdirectory(autotests)
@ -73,3 +76,5 @@ if (BUILD_TESTING)
endif()
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)

View File

@ -35,61 +35,27 @@ private:
QTest::addColumn<QImage::Format>("pngformat");
QTest::addColumn<bool>("compress");
QTest::newRow("4x4 no alpha RLE")
<< QFINDTESTDATA("pic/4x4-simple-color.pic")
<< QFINDTESTDATA("pic/4x4-simple-color.png")
<< QString()
<< false
<< QImage::Format_RGB32
<< true;
QTest::newRow("4x4 no alpha RLE") << QFINDTESTDATA("pic/4x4-simple-color.pic") << QFINDTESTDATA("pic/4x4-simple-color.png") << QString() << false
<< QImage::Format_RGB32 << true;
QTest::newRow("4x4 no alpha raw")
<< QFINDTESTDATA("pic/4x4-simple-color-uncompressed.pic")
<< QFINDTESTDATA("pic/4x4-simple-color.png")
<< QString()
<< false
<< QImage::Format_RGB32
<< false;
QTest::newRow("4x4 no alpha raw") << QFINDTESTDATA("pic/4x4-simple-color-uncompressed.pic") << QFINDTESTDATA("pic/4x4-simple-color.png") << QString()
<< false << QImage::Format_RGB32 << false;
QTest::newRow("Short comment")
<< QFINDTESTDATA("pic/short-comment.pic")
<< QFINDTESTDATA("pic/4x4-simple-color.png")
<< QStringLiteral("Test comment value")
<< false
<< QImage::Format_RGB32
<< true;
QTest::newRow("Short comment") << QFINDTESTDATA("pic/short-comment.pic") << QFINDTESTDATA("pic/4x4-simple-color.png")
<< QStringLiteral("Test comment value") << false << QImage::Format_RGB32 << true;
QTest::newRow("Long comment")
<< QFINDTESTDATA("pic/long-comment.pic")
<< QFINDTESTDATA("pic/4x4-simple-color.png")
<< QStringLiteral("Test comment value that goes right up to the end of the comment field and has no")
<< false
<< QImage::Format_RGB32
<< true;
QTest::newRow("Long comment") << QFINDTESTDATA("pic/long-comment.pic") << QFINDTESTDATA("pic/4x4-simple-color.png")
<< QStringLiteral("Test comment value that goes right up to the end of the comment field and has no") << false
<< QImage::Format_RGB32 << true;
QTest::newRow("Long run-lengths")
<< QFINDTESTDATA("pic/long-runs.pic")
<< QFINDTESTDATA("pic/long-runs.png")
<< QString()
<< false
<< QImage::Format_RGB32
<< true;
QTest::newRow("Long run-lengths") << QFINDTESTDATA("pic/long-runs.pic") << QFINDTESTDATA("pic/long-runs.png") << QString() << false
<< QImage::Format_RGB32 << true;
QTest::newRow("4x4 with alpha RLE")
<< QFINDTESTDATA("pic/4x4-alpha.pic")
<< QFINDTESTDATA("pic/4x4-alpha.png")
<< QString()
<< true
<< QImage::Format_ARGB32
<< true;
QTest::newRow("4x4 with alpha RLE") << QFINDTESTDATA("pic/4x4-alpha.pic") << QFINDTESTDATA("pic/4x4-alpha.png") << QString() << true
<< QImage::Format_ARGB32 << true;
QTest::newRow("4x4 with alpha raw")
<< QFINDTESTDATA("pic/4x4-alpha-uncompressed.pic")
<< QFINDTESTDATA("pic/4x4-alpha.png")
<< QString()
<< true
<< QImage::Format_ARGB32
<< false;
QTest::newRow("4x4 with alpha raw") << QFINDTESTDATA("pic/4x4-alpha-uncompressed.pic") << QFINDTESTDATA("pic/4x4-alpha.png") << QString() << true
<< QImage::Format_ARGB32 << false;
}
private Q_SLOTS:
@ -106,13 +72,8 @@ private Q_SLOTS:
// so there is no actual data loss in converting to RGB16.
// This just tests that the pic plugin can deal with different
// input formats.
QTest::newRow("altered format")
<< QFINDTESTDATA("pic/4x4-simple-color.pic")
<< QFINDTESTDATA("pic/4x4-simple-color.png")
<< QString()
<< false
<< QImage::Format_RGB16
<< true;
QTest::newRow("altered format") << QFINDTESTDATA("pic/4x4-simple-color.pic") << QFINDTESTDATA("pic/4x4-simple-color.png") << QString() << false
<< QImage::Format_RGB16 << true;
}
void testRead_data()
@ -148,17 +109,12 @@ private Q_SLOTS:
imgWriter.write(pngImage);
if (expData != picData) {
QString fileNameBase = QUuid::createUuid().toString()
.remove(QLatin1Char('{'))
.remove(QLatin1Char('}'));
QString fileNameBase = QUuid::createUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}'));
QFile dumpFile(fileNameBase + QStringLiteral(".pic"));
QVERIFY2(dumpFile.open(QIODevice::WriteOnly), qPrintable(dumpFile.errorString()));
dumpFile.write(picData);
QString msg = QStringLiteral("Written data (")
+ dumpFile.fileName()
+ QStringLiteral(") differed from expected data (")
+ picfile
+ QLatin1Char(')');
QString msg =
QStringLiteral("Written data (") + dumpFile.fileName() + QStringLiteral(") differed from expected data (") + picfile + QLatin1Char(')');
QFAIL(qPrintable(msg));
}
}
@ -182,28 +138,19 @@ private Q_SLOTS:
QCOMPARE(inputImage.width(), expImage.width());
QCOMPARE(inputImage.height(), expImage.height());
QCOMPARE(inputImage.hasAlphaChannel(), alpha);
QCOMPARE(inputImage.format(), alpha ? QImage::Format_ARGB32
: QImage::Format_RGB32);
QCOMPARE(inputImage.format(), alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
expImage = expImage.convertToFormat(pngformat);
expImage = expImage.convertToFormat(alpha ? QImage::Format_ARGB32
: QImage::Format_RGB32);
expImage = expImage.convertToFormat(alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
if (inputImage != expImage) {
QString fileNameBase = QUuid::createUuid().toString()
.remove(QLatin1Char('{'))
.remove(QLatin1Char('}'));
QString fileNameBase = QUuid::createUuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}'));
QFile picDumpFile(fileNameBase + QStringLiteral("-expected.data"));
QVERIFY2(picDumpFile.open(QIODevice::WriteOnly), qPrintable(picDumpFile.errorString()));
picDumpFile.write(reinterpret_cast<const char *>(inputImage.bits()),
inputImage.sizeInBytes());
picDumpFile.write(reinterpret_cast<const char *>(inputImage.bits()), inputImage.sizeInBytes());
QFile pngDumpFile(fileNameBase + QStringLiteral("-actual.data"));
QVERIFY2(pngDumpFile.open(QIODevice::WriteOnly), qPrintable(pngDumpFile.errorString()));
pngDumpFile.write(reinterpret_cast<const char *>(expImage.bits()),
expImage.sizeInBytes());
QString msg = QStringLiteral("Read image (")
+ picDumpFile.fileName()
+ QStringLiteral(") differed from expected image (")
+ pngDumpFile.fileName()
pngDumpFile.write(reinterpret_cast<const char *>(expImage.bits()), expImage.sizeInBytes());
QString msg = QStringLiteral("Read image (") + picDumpFile.fileName() + QStringLiteral(") differed from expected image (") + pngDumpFile.fileName()
+ QLatin1Char(')');
QFAIL(qPrintable(msg));
}
@ -252,8 +199,7 @@ private Q_SLOTS:
QImageReader inputReader(picfile, "pic");
QCOMPARE(inputReader.imageFormat(),
alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
QCOMPARE(inputReader.imageFormat(), alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
}
};

View File

@ -22,17 +22,12 @@ static void writeImageData(const char *name, const QString &filename, const QIma
if (file.open(QIODevice::WriteOnly)) {
qint64 written = file.write(reinterpret_cast<const char *>(image.bits()), image.sizeInBytes());
if (written == image.sizeInBytes()) {
QTextStream(stdout) << " " << name
<< " written to " << filename << "\n";
QTextStream(stdout) << " " << name << " written to " << filename << "\n";
} else {
QTextStream(stdout) << " could not write " << name
<< " to " << filename << ":"
<< file.errorString() << "\n";
QTextStream(stdout) << " could not write " << name << " to " << filename << ":" << file.errorString() << "\n";
}
} else {
QTextStream(stdout) << " could not open "
<< filename << ":"
<< file.errorString() << "\n";
QTextStream(stdout) << " could not open " << filename << ":" << file.errorString() << "\n";
}
}
@ -63,8 +58,7 @@ static bool fuzzyeq(const QImage &im1, const QImage &im2, uchar fuzziness)
// 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)
{
return (im1.depth() == 64) ? fuzzyeq<quint16>(im1, im2, fuzziness)
: fuzzyeq<quint8>(im1, im2, fuzziness);
return (im1.depth() == 64) ? fuzzyeq<quint16>(im1, im2, fuzziness) : fuzzyeq<quint8>(im1, im2, fuzziness);
}
// Returns the original format if we support, or returns
@ -97,8 +91,7 @@ int main(int argc, char ** argv)
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument(QStringLiteral("format"), QStringLiteral("format to test"));
QCommandLineOption fuzz(
QStringList() << QStringLiteral("f") << QStringLiteral("fuzz"),
QCommandLineOption fuzz(QStringList() << QStringLiteral("f") << QStringLiteral("fuzz"),
QStringLiteral("Allow for some deviation in ARGB data."),
QStringLiteral("max"));
parser.addOption(fuzz);
@ -136,13 +129,14 @@ int main(int argc, char ** argv)
int failed = 0;
QTextStream(stdout) << "********* "
<< "Starting basic read tests for "
<< suffix << " images *********\n";
<< "Starting basic read tests for " << suffix << " images *********\n";
const QList<QByteArray> formats = QImageReader::supportedImageFormats();
QStringList formatStrings;
formatStrings.reserve(formats.size());
std::transform(formats.begin(), formats.end(), std::back_inserter(formatStrings), [](const QByteArray &format) { return QString(format); });
std::transform(formats.begin(), formats.end(), std::back_inserter(formatStrings), [](const QByteArray &format) {
return QString(format);
});
QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n";
const QFileInfoList lstImgDir = imgdir.entryInfoList();
@ -159,39 +153,26 @@ int main(int argc, char ** argv)
QImage expImage;
if (!expReader.read(&expImage)) {
QTextStream(stdout) << "ERROR: " << fi.fileName()
<< ": could not load " << expfilename
<< ": " << expReader.errorString()
<< "\n";
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n";
++failed;
continue;
}
if (!inputReader.canRead()) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": failed can read: "
<< inputReader.errorString()
<< "\n";
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed can read: " << inputReader.errorString() << "\n";
++failed;
continue;
}
if (!inputReader.read(&inputImage)) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": failed to load: "
<< inputReader.errorString()
<< "\n";
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed to load: " << inputReader.errorString() << "\n";
++failed;
continue;
}
if (expImage.width() != inputImage.width()) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": width was " << inputImage.width()
<< " but " << expfilename << " width was "
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": width was " << inputImage.width() << " but " << expfilename << " width was "
<< expImage.width() << "\n";
++failed;
} else if (expImage.height() != inputImage.height()) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": height was " << inputImage.height()
<< " but " << expfilename << " height was "
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": height was " << inputImage.height() << " but " << expfilename << " height was "
<< expImage.height() << "\n";
++failed;
} else {
@ -200,42 +181,30 @@ int main(int argc, char ** argv)
QImage::Format cmpFormat = inputFormat == expFormat ? inputFormat : QImage::Format_ARGB32;
if (inputImage.format() != cmpFormat) {
QTextStream(stdout) << "INFO : " << fi.fileName()
<< ": converting " << fi.fileName()
<< " from " << formatToString(inputImage.format())
QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << fi.fileName() << " from " << formatToString(inputImage.format())
<< " to " << formatToString(cmpFormat) << '\n';
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)) {
QTextStream(stdout) << "PASS : " << fi.fileName() << "\n";
++passed;
} else {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": differs from " << expfilename << "\n";
writeImageData("expected data",
fi.fileName() + QLatin1String("-expected.data"),
expImage);
writeImageData("actual data",
fi.fileName() + QLatin1String("-actual.data"),
inputImage);
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": differs from " << expfilename << "\n";
writeImageData("expected data", fi.fileName() + QLatin1String("-expected.data"), expImage);
writeImageData("actual data", fi.fileName() + QLatin1String("-actual.data"), inputImage);
++failed;
}
}
}
QTextStream(stdout) << "Totals: "
<< passed << " passed, "
<< failed << " failed\n";
QTextStream(stdout) << "Totals: " << passed << " passed, " << failed << " failed\n";
QTextStream(stdout) << "********* "
<< "Finished basic read tests for "
<< suffix << " images *********\n";
<< "Finished basic read tests for " << suffix << " images *********\n";
return failed == 0 ? 0 : 1;
}

View File

@ -29,8 +29,7 @@ int main(int argc, char ** argv)
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument(QStringLiteral("format"), QStringLiteral("format to test."));
QCommandLineOption lossless(
QStringList() << QStringLiteral("l") << QStringLiteral("lossless"),
QCommandLineOption lossless(QStringList() << QStringLiteral("l") << QStringLiteral("lossless"),
QStringLiteral("Check that reading back the data gives the same image."));
parser.addOption(lossless);
@ -56,8 +55,7 @@ int main(int argc, char ** argv)
int failed = 0;
QTextStream(stdout) << "********* "
<< "Starting basic write tests for "
<< suffix << " images *********\n";
<< "Starting basic write tests for " << suffix << " images *********\n";
const QFileInfoList lstImgDir = imgdir.entryInfoList();
for (const QFileInfo &fi : lstImgDir) {
int suffixPos = fi.filePath().count() - suffix.count();
@ -67,20 +65,14 @@ int main(int argc, char ** argv)
QImageReader pngReader(pngfile, "png");
QImage pngImage;
if (!pngReader.read(&pngImage)) {
QTextStream(stdout) << "ERROR: " << fi.fileName()
<< ": could not load " << pngfilename
<< ": " << pngReader.errorString()
<< "\n";
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << pngfilename << ": " << pngReader.errorString() << "\n";
++failed;
continue;
}
QFile expFile(fi.filePath());
if (!expFile.open(QIODevice::ReadOnly)) {
QTextStream(stdout) << "ERROR: " << fi.fileName()
<< ": could not open " << fi.fileName()
<< ": " << expFile.errorString()
<< "\n";
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not open " << fi.fileName() << ": " << expFile.errorString() << "\n";
++failed;
continue;
}
@ -91,10 +83,7 @@ int main(int argc, char ** argv)
char buf[1];
qint64 result = expFile.read(buf, 1);
if (result < 0) {
QTextStream(stdout) << "ERROR: " << fi.fileName()
<< ": could not load " << fi.fileName()
<< ": " << expFile.errorString()
<< "\n";
QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << fi.fileName() << ": " << expFile.errorString() << "\n";
++failed;
continue;
}
@ -105,16 +94,14 @@ int main(int argc, char ** argv)
QBuffer buffer(&writtenData);
QImageWriter imgWriter(&buffer, format.constData());
if (!imgWriter.write(pngImage)) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": failed to write image data\n";
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": failed to write image data\n";
++failed;
continue;
}
}
if (expData != writtenData) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": written data differs from " << fi.fileName() << "\n";
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": written data differs from " << fi.fileName() << "\n";
++failed;
continue;
}
@ -124,8 +111,7 @@ int main(int argc, char ** argv)
QBuffer buffer(&writtenData);
QImageReader imgReader(&buffer, format.constData());
if (!imgReader.read(&reReadImage)) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": could not read back the written data\n";
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": could not read back the written data\n";
++failed;
continue;
}
@ -134,8 +120,7 @@ int main(int argc, char ** argv)
if (parser.isSet(lossless)) {
if (pngImage != reReadImage) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": re-reading the data resulted in a different image\n";
QTextStream(stdout) << "FAIL : " << fi.fileName() << ": re-reading the data resulted in a different image\n";
++failed;
continue;
}
@ -145,12 +130,9 @@ int main(int argc, char ** argv)
++passed;
}
QTextStream(stdout) << "Totals: "
<< passed << " passed, "
<< failed << " failed\n";
QTextStream(stdout) << "Totals: " << passed << " passed, " << failed << " failed\n";
QTextStream(stdout) << "********* "
<< "Finished basic write tests for "
<< suffix << " images *********\n";
<< "Finished basic write tests for " << suffix << " images *********\n";
return failed == 0 ? 0 : 1;
}

View File

@ -58,7 +58,11 @@ install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugi
if(OpenEXR_FOUND)
kimageformats_add_plugin(kimg_exr JSON "exr.json" SOURCES exr.cpp)
if(TARGET OpenEXR::OpenEXR)
target_link_libraries(kimg_exr OpenEXR::OpenEXR)
else()
target_link_libraries(kimg_exr OpenEXR::IlmImf)
endif()
kde_target_enable_exceptions(kimg_exr PRIVATE)
install(FILES exr.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)

View File

@ -9,12 +9,11 @@
#include <QDebug>
#include <QImage>
#include <QScopeGuard>
#include <QtEndian>
#include <QVariant>
#include <QtEndian>
namespace
{
struct ChunkHeader {
char magic[4];
quint32_le size;
@ -64,8 +63,7 @@ bool ANIHandler::canRead() const
const QByteArray nextFrame = device()->peek(sizeof(ChunkHeader));
if (nextFrame.size() == sizeof(ChunkHeader)) {
const auto *header = reinterpret_cast<const ChunkHeader *>(nextFrame.data());
if (qstrncmp(header->magic, "icon", sizeof(header->magic)) == 0
&& header->size > 0) {
if (qstrncmp(header->magic, "icon", sizeof(header->magic)) == 0 && header->size > 0) {
setFormat("ani");
return true;
}
@ -377,8 +375,7 @@ bool ANIHandler::ensureScanned() const
mutableThis->m_displayRate = aniHeader->iDispRate;
} else if (chunkId == "rate" || chunkId == "seq ") {
const QByteArray data = device()->read(chunkSize);
if (static_cast<quint32_le>(data.size()) != chunkSize
|| data.size() % sizeof(quint32_le) != 0) {
if (static_cast<quint32_le>(data.size()) != chunkSize || data.size() % sizeof(quint32_le) != 0) {
return false;
}
@ -455,8 +452,7 @@ bool ANIHandler::ensureScanned() const
const QByteArray curHeaderData = device()->read(sizeof(CurHeader));
const QByteArray cursorDirEntryData = device()->read(sizeof(CursorDirEntry));
if (curHeaderData.length() == sizeof(CurHeader)
&& cursorDirEntryData.length() == sizeof(CursorDirEntry)) {
if (curHeaderData.length() == sizeof(CurHeader) && cursorDirEntryData.length() == sizeof(CursorDirEntry)) {
auto *cursorDirEntry = reinterpret_cast<const CursorDirEntry *>(cursorDirEntryData.data());
mutableThis->m_size = QSize(cursorDirEntry->bWidth, cursorDirEntry->bHeight);
}
@ -508,7 +504,7 @@ bool ANIHandler::ensureScanned() const
return false;
}
if (!m_frameOffsets.isEmpty() && m_frameOffsets.count() != m_frameCount + 1) {
if (!m_frameOffsets.isEmpty() && m_frameOffsets.count() - 1 != m_frameCount) {
qWarning("ANIHandler: number of actual frames does not match 'nFrames' in anih");
return false;
}

View File

@ -53,7 +53,6 @@ private:
QString m_name;
QString m_artist;
QSize m_size;
};
class ANIPlugin : public QImageIOPlugin

View File

@ -6,23 +6,22 @@
SPDX-License-Identifier: BSD-2-Clause
*/
#include <QtGlobal>
#include <QThread>
#include <QtGlobal>
#include <QColorSpace>
#include "avif_p.h"
#include <cfloat>
QAVIFHandler::QAVIFHandler() :
m_parseState(ParseAvifNotParsed),
m_quality(52),
m_container_width(0),
m_container_height(0),
m_rawAvifData(AVIF_DATA_EMPTY),
m_decoder(nullptr),
m_must_jump_to_next_image(false)
QAVIFHandler::QAVIFHandler()
: m_parseState(ParseAvifNotParsed)
, m_quality(52)
, m_container_width(0)
, m_container_height(0)
, m_rawAvifData(AVIF_DATA_EMPTY)
, m_decoder(nullptr)
, m_must_jump_to_next_image(false)
{
}
@ -96,7 +95,6 @@ bool QAVIFHandler::ensureDecoder()
return false;
}
m_decoder = avifDecoderCreate();
avifResult decodeResult;
@ -124,7 +122,6 @@ bool QAVIFHandler::ensureDecoder()
decodeResult = avifDecoderNextImage(m_decoder);
if (decodeResult == AVIF_RESULT_OK) {
m_container_width = m_decoder->image->width;
m_container_height = m_decoder->image->height;
@ -193,10 +190,12 @@ bool QAVIFHandler::decode_one_frame()
return false;
}
QColorSpace colorspace;
if (m_decoder->image->icc.data && (m_decoder->image->icc.size > 0)) {
result.setColorSpace(QColorSpace::fromIccProfile(QByteArray::fromRawData((const char *) m_decoder->image->icc.data, (int) m_decoder->image->icc.size)));
if (! result.colorSpace().isValid()) {
qWarning("Invalid QColorSpace created from ICC!");
const QByteArray icc_data((const char *)m_decoder->image->icc.data, (int)m_decoder->image->icc.size);
colorspace = QColorSpace::fromIccProfile(icc_data);
if (!colorspace.isValid()) {
qWarning("AVIF image has Qt-unsupported or invalid ICC profile!");
}
} else {
float prim[8] = {0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f};
@ -208,7 +207,6 @@ bool QAVIFHandler::decode_one_frame()
const QPointF bluePoint(QAVIFHandler::CompatibleChromacity(prim[4], prim[5]));
const QPointF whitePoint(QAVIFHandler::CompatibleChromacity(prim[6], prim[7]));
QColorSpace::TransferFunction q_trc = QColorSpace::TransferFunction::Custom;
float q_trc_gamma = 0.0f;
@ -235,7 +233,8 @@ bool QAVIFHandler::decode_one_frame()
break;
default:
qWarning("CICP colorPrimaries: %d, transferCharacteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
m_decoder->image->colorPrimaries, m_decoder->image->transferCharacteristics);
m_decoder->image->colorPrimaries,
m_decoder->image->transferCharacteristics);
q_trc = QColorSpace::TransferFunction::SRgb;
break;
}
@ -246,23 +245,25 @@ bool QAVIFHandler::decode_one_frame()
case 0:
case 1:
case 2: /* AVIF_COLOR_PRIMARIES_UNSPECIFIED */
result.setColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma));
colorspace = QColorSpace(QColorSpace::Primaries::SRgb, q_trc, q_trc_gamma);
break;
/* AVIF_COLOR_PRIMARIES_SMPTE432 */
case 12:
result.setColorSpace(QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma));
colorspace = QColorSpace(QColorSpace::Primaries::DciP3D65, q_trc, q_trc_gamma);
break;
default:
result.setColorSpace(QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma));
colorspace = QColorSpace(whitePoint, redPoint, greenPoint, bluePoint, q_trc, q_trc_gamma);
break;
}
}
if (! result.colorSpace().isValid()) {
qWarning("Invalid QColorSpace created from NCLX/CICP!");
if (!colorspace.isValid()) {
qWarning("AVIF plugin created invalid QColorSpace from NCLX/CICP!");
}
}
result.setColorSpace(colorspace);
avifRGBImage rgb;
avifRGBImageSetDefaults(&rgb, m_decoder->image);
@ -303,8 +304,8 @@ bool QAVIFHandler::decode_one_frame()
}
if (m_decoder->image->transformFlags & AVIF_TRANSFORM_CLAP) {
if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) &&
(m_decoder->image->clap.horizOffD > 0) && (m_decoder->image->clap.vertOffD > 0)) {
if ((m_decoder->image->clap.widthD > 0) && (m_decoder->image->clap.heightD > 0) && (m_decoder->image->clap.horizOffD > 0)
&& (m_decoder->image->clap.vertOffD > 0)) {
int new_width, new_height, offx, offy;
new_width = (int)((double)(m_decoder->image->clap.widthN) / (m_decoder->image->clap.widthD) + 0.5);
@ -318,17 +319,14 @@ bool QAVIFHandler::decode_one_frame()
}
if (new_width > 0 && new_height > 0) {
offx = ((double)((int32_t) m_decoder->image->clap.horizOffN)) / (m_decoder->image->clap.horizOffD) +
(result.width() - new_width) / 2.0 + 0.5;
offx = ((double)((int32_t)m_decoder->image->clap.horizOffN)) / (m_decoder->image->clap.horizOffD) + (result.width() - new_width) / 2.0 + 0.5;
if (offx < 0) {
offx = 0;
} else if (offx > (result.width() - new_width)) {
offx = result.width() - new_width;
}
offy = ((double)((int32_t) m_decoder->image->clap.vertOffN)) / (m_decoder->image->clap.vertOffD) +
(result.height() - new_height) / 2.0 + 0.5;
offy = ((double)((int32_t)m_decoder->image->clap.vertOffN)) / (m_decoder->image->clap.vertOffD) + (result.height() - new_height) / 2.0 + 0.5;
if (offy < 0) {
offy = 0;
} else if (offy > (result.height() - new_height)) {
@ -363,11 +361,15 @@ bool QAVIFHandler::decode_one_frame()
}
if (m_decoder->image->transformFlags & AVIF_TRANSFORM_IMIR) {
#if AVIF_VERSION > 90100
switch (m_decoder->image->imir.mode) {
#else
switch (m_decoder->image->imir.axis) {
case 0: //vertical
#endif
case 0: // top-to-bottom
result = result.mirrored(false, true);
break;
case 1: //horizontal
case 1: // left-to-right
result = result.mirrored(true, false);
break;
}
@ -496,7 +498,6 @@ bool QAVIFHandler::write(const QImage &image)
/* AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED */
break;
}
}
if (save_depth > 8) { // QImage::Format_Grayscale16
@ -552,6 +553,7 @@ bool QAVIFHandler::write(const QImage &image)
avifColorPrimaries primaries_to_save = (avifColorPrimaries)2;
avifTransferCharacteristics transfer_to_save = (avifTransferCharacteristics)2;
QByteArray iccprofile;
if (tmpcolorimage.colorSpace().isValid()) {
switch (tmpcolorimage.colorSpace().primaries()) {
@ -603,9 +605,7 @@ bool QAVIFHandler::write(const QImage &image)
}
// in case primaries or trc were not identified
if ((primaries_to_save == 2) ||
(transfer_to_save == 2)) {
if ((primaries_to_save == 2) || (transfer_to_save == 2)) {
// upgrade image to higher bit depth
if (save_depth == 8) {
save_depth = 10;
@ -616,8 +616,7 @@ bool QAVIFHandler::write(const QImage &image)
}
}
if ((primaries_to_save == 2) &&
(transfer_to_save != 2)) { //other primaries but known trc
if ((primaries_to_save == 2) && (transfer_to_save != 2)) { // other primaries but known trc
primaries_to_save = (avifColorPrimaries)1; // AVIF_COLOR_PRIMARIES_BT709
matrix_to_save = (avifMatrixCoefficients)1; // AVIF_MATRIX_COEFFICIENTS_BT709
@ -636,8 +635,7 @@ bool QAVIFHandler::write(const QImage &image)
transfer_to_save = (avifTransferCharacteristics)13;
break;
}
} else if ((primaries_to_save != 2) &&
(transfer_to_save == 2)) { //recognized primaries but other trc
} else if ((primaries_to_save != 2) && (transfer_to_save == 2)) { // recognized primaries but other trc
transfer_to_save = (avifTransferCharacteristics)13;
tmpcolorimage.convertToColorSpace(tmpcolorimage.colorSpace().withTransferFunction(QColorSpace::TransferFunction::SRgb));
} else { // unrecognized profile
@ -647,13 +645,23 @@ bool QAVIFHandler::write(const QImage &image)
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, QColorSpace::TransferFunction::SRgb));
}
}
} else { // profile is unsupported by Qt
iccprofile = tmpcolorimage.colorSpace().iccProfile();
if (iccprofile.size() > 0) {
matrix_to_save = (avifMatrixCoefficients)6;
}
}
avif = avifImageCreate(tmpcolorimage.width(), tmpcolorimage.height(), save_depth, pixel_format);
avif->matrixCoefficients = matrix_to_save;
avif->colorPrimaries = primaries_to_save;
avif->transferCharacteristics = transfer_to_save;
if (iccprofile.size() > 0) {
avifImageSetProfileICC(avif, (const uint8_t *)iccprofile.constData(), iccprofile.size());
}
avifRGBImage rgb;
avifRGBImageSetDefaults(&rgb, avif);
rgb.rowBytes = tmpcolorimage.bytesPerLine();
@ -721,7 +729,6 @@ bool QAVIFHandler::write(const QImage &image)
return false;
}
QVariant QAVIFHandler::option(ImageOption option) const
{
if (option == Quality) {
@ -765,9 +772,7 @@ void QAVIFHandler::setOption(ImageOption option, const QVariant &value)
bool QAVIFHandler::supportsOption(ImageOption option) const
{
return option == Quality
|| option == Size
|| option == Animation;
return option == Quality || option == Size || option == Animation;
}
int QAVIFHandler::imageCount() const
@ -817,11 +822,12 @@ bool QAVIFHandler::jumpToNextImage()
return false;
}
if ((m_container_width != m_decoder->image->width) ||
(m_container_height != m_decoder->image->height)) {
if ((m_container_width != m_decoder->image->width) || (m_container_height != m_decoder->image->height)) {
qWarning("Decoded image sequence size (%dx%d) do not match first image size (%dx%d)!",
m_decoder->image->width, m_decoder->image->height,
m_container_width, m_container_height);
m_decoder->image->width,
m_decoder->image->height,
m_container_width,
m_container_height);
m_parseState = ParseAvifError;
return false;
@ -833,7 +839,6 @@ bool QAVIFHandler::jumpToNextImage()
m_parseState = ParseAvifError;
return false;
}
}
bool QAVIFHandler::jumpToImage(int imageNumber)
@ -866,11 +871,12 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
return false;
}
if ((m_container_width != m_decoder->image->width) ||
(m_container_height != m_decoder->image->height)) {
if ((m_container_width != m_decoder->image->width) || (m_container_height != m_decoder->image->height)) {
qWarning("Decoded image sequence size (%dx%d) do not match declared container size (%dx%d)!",
m_decoder->image->width, m_decoder->image->height,
m_container_width, m_container_height);
m_decoder->image->width,
m_decoder->image->height,
m_container_width,
m_container_height);
m_parseState = ParseAvifError;
return false;

View File

@ -9,13 +9,13 @@
#ifndef KIMG_AVIF_P_H
#define KIMG_AVIF_P_H
#include <QImage>
#include <QVariant>
#include <qimageiohandler.h>
#include <QImageIOPlugin>
#include <QByteArray>
#include <QImage>
#include <QImageIOPlugin>
#include <QPointF>
#include <QVariant>
#include <avif/avif.h>
#include <qimageiohandler.h>
class QAVIFHandler : public QImageIOHandler
{
@ -41,17 +41,17 @@ public:
int nextImageDelay() const override;
int loopCount() const override;
private:
static QPointF CompatibleChromacity(qreal chrX, qreal chrY);
bool ensureParsed() const;
bool ensureDecoder();
bool decode_one_frame();
enum ParseAvifState
{
enum ParseAvifState {
ParseAvifError = -1,
ParseAvifNotParsed = 0,
ParseAvifSuccess = 1
ParseAvifSuccess = 1,
};
ParseAvifState m_parseState;

View File

@ -9,13 +9,13 @@
*/
#include "eps_p.h"
#include <QCoreApplication>
#include <QImage>
#include <QImageReader>
#include <QPainter>
#include <QPrinter>
#include <QProcess>
#include <QTemporaryFile>
#include <QCoreApplication>
// logging category for this framework, default: log stuff >= warning
Q_LOGGING_CATEGORY(EPSPLUGIN, "kf.imageformats.plugins.eps", QtWarningMsg)
@ -51,19 +51,13 @@ static bool seekToCodeStart(QIODevice *io, qint64 &ps_offset, qint64 &ps_size)
return false;
}
ps_offset // Offset is in little endian
= qint64(((unsigned char)buf[0])
+ ((unsigned char)buf[1] << 8)
+ ((unsigned char)buf[2] << 16)
+ ((unsigned char)buf[3] << 24));
= qint64(((unsigned char)buf[0]) + ((unsigned char)buf[1] << 8) + ((unsigned char)buf[2] << 16) + ((unsigned char)buf[3] << 24));
if (io->read(buf, 4) != 4) { // Get size of PostScript code in the MS-DOS EPS file.
qCDebug(EPSPLUGIN) << "cannot read size of MS-DOS EPS file";
return false;
}
ps_size // Size is in little endian
= qint64(((unsigned char)buf[0])
+ ((unsigned char)buf[1] << 8)
+ ((unsigned char)buf[2] << 16)
+ ((unsigned char)buf[3] << 24));
= qint64(((unsigned char)buf[0]) + ((unsigned char)buf[1] << 8) + ((unsigned char)buf[2] << 16) + ((unsigned char)buf[3] << 24));
qCDebug(EPSPLUGIN) << "Offset: " << ps_offset << " Size: " << ps_size;
if (!io->seek(ps_offset)) { // Get offset of PostScript code in the MS-DOS EPS file.
qCDebug(EPSPLUGIN) << "cannot seek in MS-DOS EPS file";
@ -101,8 +95,7 @@ static bool bbox(QIODevice *io, int *x1, int *y1, int *x2, int *y2)
// Some EPS files have non-integer values for the bbox
// We don't support that currently, but at least we parse it
float _x1, _y1, _x2, _y2;
if (sscanf(buf, "%*s %f %f %f %f",
&_x1, &_y1, &_x2, &_y2) == 4) {
if (sscanf(buf, "%*s %f %f %f %f", &_x1, &_y1, &_x2, &_y2) == 4) {
qCDebug(EPSPLUGIN) << "BBOX: " << _x1 << " " << _y1 << " " << _x2 << " " << _y2;
*x1 = int(_x1);
*y1 = int(_y1);
@ -177,23 +170,17 @@ bool EPSHandler::read(QImage *image)
// create GS command line
QStringList gsArgs;
gsArgs << QLatin1String("-sOutputFile=") + tmpFile.fileName()
<< QStringLiteral("-q")
<< QStringLiteral("-g%1x%2").arg(wantedWidth).arg(wantedHeight)
<< QStringLiteral("-dSAFER")
<< QStringLiteral("-dPARANOIDSAFER")
<< QStringLiteral("-dNOPAUSE")
<< QStringLiteral("-sDEVICE=ppm")
gsArgs << QLatin1String("-sOutputFile=") + tmpFile.fileName() << QStringLiteral("-q") << QStringLiteral("-g%1x%2").arg(wantedWidth).arg(wantedHeight)
<< QStringLiteral("-dSAFER") << QStringLiteral("-dPARANOIDSAFER") << QStringLiteral("-dNOPAUSE") << QStringLiteral("-sDEVICE=ppm")
<< QStringLiteral("-c")
<< QStringLiteral("0 0 moveto "
<< QStringLiteral(
"0 0 moveto "
"1000 0 lineto "
"1000 1000 lineto "
"0 1000 lineto "
"1 1 254 255 div setrgbcolor fill "
"0 0 0 setrgbcolor")
<< QStringLiteral("-")
<< QStringLiteral("-c")
<< QStringLiteral("showpage quit");
<< QStringLiteral("-") << QStringLiteral("-c") << QStringLiteral("showpage quit");
qCDebug(EPSPLUGIN) << "Running gs with args" << gsArgs;
QProcess converter;
@ -264,7 +251,8 @@ bool EPSHandler::write(const QImage &image)
psOut.setOutputFileName(tmpFile.fileName());
psOut.setOutputFormat(QPrinter::PdfFormat);
psOut.setFullPage(true);
psOut.setPaperSize(image.size(), QPrinter::DevicePixel);
const double multiplier = psOut.resolution() <= 0 ? 1.0 : 72.0 / psOut.resolution();
psOut.setPageSize(QPageSize(image.size() * multiplier, QPageSize::Point));
// painting the pixmap to the "printer" which is a file
p.begin(&psOut);
@ -277,24 +265,16 @@ bool EPSHandler::write(const QImage &image)
// pdftops comes with Poppler and produces much smaller EPS files than GhostScript
QStringList pdftopsArgs;
pdftopsArgs << QStringLiteral("-eps")
<< tmpFile.fileName()
<< QStringLiteral("-");
pdftopsArgs << QStringLiteral("-eps") << tmpFile.fileName() << QStringLiteral("-");
qCDebug(EPSPLUGIN) << "Running pdftops with args" << pdftopsArgs;
converter.start(QStringLiteral("pdftops"), pdftopsArgs);
if (!converter.waitForStarted()) {
// GhostScript produces huge files, and takes a long time doing so
QStringList gsArgs;
gsArgs << QStringLiteral("-q") << QStringLiteral("-P-")
<< QStringLiteral("-dNOPAUSE") << QStringLiteral("-dBATCH")
<< QStringLiteral("-dSAFER")
<< QStringLiteral("-sDEVICE=epswrite")
<< QStringLiteral("-sOutputFile=-")
<< QStringLiteral("-c")
<< QStringLiteral("save") << QStringLiteral("pop")
<< QStringLiteral("-f")
<< tmpFile.fileName();
gsArgs << QStringLiteral("-q") << QStringLiteral("-P-") << QStringLiteral("-dNOPAUSE") << QStringLiteral("-dBATCH") << QStringLiteral("-dSAFER")
<< QStringLiteral("-sDEVICE=epswrite") << QStringLiteral("-sOutputFile=-") << QStringLiteral("-c") << QStringLiteral("save")
<< QStringLiteral("pop") << QStringLiteral("-f") << tmpFile.fileName();
qCDebug(EPSPLUGIN) << "Failed to start pdftops; trying gs with args" << gsArgs;
converter.start(QStringLiteral("gs"), gsArgs);

View File

@ -35,4 +35,3 @@ public:
Q_DECLARE_LOGGING_CATEGORY(EPSPLUGIN)
#endif // KIMG_EPS_P_H

View File

@ -9,35 +9,37 @@
#include "exr_p.h"
#include <ImfRgbaFile.h>
#include <ImfStandardAttributes.h>
#include <IexThrowErrnoExc.h>
#include <ImathBox.h>
#include <ImfInputFile.h>
#include <ImfArray.h>
#include <ImfBoxAttribute.h>
#include <ImfChannelListAttribute.h>
#include <ImfCompressionAttribute.h>
#include <ImfConvert.h>
#include <ImfFloatAttribute.h>
#include <ImfInputFile.h>
#include <ImfInt64.h>
#include <ImfIntAttribute.h>
#include <ImfLineOrderAttribute.h>
#include <ImfRgbaFile.h>
#include <ImfStandardAttributes.h>
#include <ImfStringAttribute.h>
#include <ImfVecAttribute.h>
#include <ImfArray.h>
#include <ImfConvert.h>
#include <ImfVersion.h>
#include <IexThrowErrnoExc.h>
#include <iostream>
#include <QImage>
#include <QDataStream>
#include <QDebug>
#include <QImage>
#include <QImageIOPlugin>
class K_IStream : public Imf::IStream
{
public:
K_IStream(QIODevice *dev, const QByteArray &fileName):
IStream(fileName.data()), m_dev(dev)
K_IStream(QIODevice *dev, const QByteArray &fileName)
: IStream(fileName.data())
, m_dev(dev)
{
}

View File

@ -41,10 +41,9 @@ const uchar OPAQUE_OPACITY = 255; //!< Opaque value for 8-bit alpha component.
typedef enum {
RGB,
GRAY,
INDEXED
INDEXED,
} GimpImageBaseType;
// From GIMP "libgimp/gimpenums.h" v2.4
//! Effect to apply when layers are merged together.
@ -74,7 +73,6 @@ typedef enum {
GRAIN_MERGE_MODE
} LayerModeEffects;
// From GIMP "paint_funcs.c" v1.2
/*!

View File

@ -8,8 +8,8 @@
#include "hdr_p.h"
#include <QImage>
#include <QDataStream>
#include <QImage>
#include <QLoggingCategory>
#include <QRegularExpressionMatch>
@ -21,7 +21,6 @@ Q_LOGGING_CATEGORY(HDRPLUGIN, "kf.imageformats.plugins.hdr", QtWarningMsg)
namespace // Private.
{
#define MAXLINE 1024
#define MINELEN 8 // minimum scanline length for encoding
#define MAXELEN 0x7fff // maximum scanline length for encoding
@ -81,9 +80,7 @@ static void RGBE_To_QRgbLine(uchar *image, QRgb *scanline, int width)
v = 1.0f / float(1 << -e);
}
scanline[j] = qRgb(ClipToByte(float(image[0]) * v),
ClipToByte(float(image[1]) * v),
ClipToByte(float(image[2]) * v));
scanline[j] = qRgb(ClipToByte(float(image[0]) * v), ClipToByte(float(image[1]) * v), ClipToByte(float(image[2]) * v));
image += 4;
}
@ -228,8 +225,7 @@ bool HDRHandler::read(QImage *outImage)
return false;
}
if ( (match.captured(1).at(1) != u'Y') ||
(match.captured(3).at(1) != u'X') ) {
if ((match.captured(1).at(1) != u'Y') || (match.captured(3).at(1) != u'X')) {
qCDebug(HDRPLUGIN) << "Unsupported image orientation in HDR file.";
return false;
}

View File

@ -10,17 +10,19 @@
#include "heif_p.h"
#include "libheif/heif_cxx.h"
#include <QPointF>
#include <QColorSpace>
#include <QDebug>
#include <QPointF>
#include <QSysInfo>
#include <string.h>
namespace // Private.
{
struct HeifQIODeviceWriter : public heif::Context::Writer {
HeifQIODeviceWriter(QIODevice *device) : m_ioDevice(device) {}
HeifQIODeviceWriter(QIODevice *device)
: m_ioDevice(device)
{
}
heif_error write(const void *data, size_t size) override
{
@ -49,9 +51,9 @@ private:
} // namespace
HEIFHandler::HEIFHandler() :
m_parseState(ParseHeicNotParsed),
m_quality(100)
HEIFHandler::HEIFHandler()
: m_parseState(ParseHeicNotParsed)
, m_quality(100)
{
}
@ -126,7 +128,6 @@ bool HEIFHandler::write(const QImage &image)
tmpformat = QImage::Format_RGB888;
chroma = heif_chroma_interleaved_RGB;
}
}
const QImage tmpimage = image.convertToFormat(tmpformat);
@ -136,13 +137,11 @@ bool HEIFHandler::write(const QImage &image)
heif::Image heifImage;
heifImage.create(tmpimage.width(), tmpimage.height(), heif_colorspace_RGB, chroma);
if (tmpimage.colorSpace().isValid()) {
QByteArray iccprofile = tmpimage.colorSpace().iccProfile();
if (iccprofile.size() > 0) {
std::vector<uint8_t> rawProfile(iccprofile.begin(), iccprofile.end());
heifImage.set_raw_color_profile(heif_color_profile_type_prof, rawProfile);
}
}
heifImage.add_plane(heif_channel_interleaved, image.width(), image.height(), save_depth);
int stride = 0;
@ -342,8 +341,7 @@ void HEIFHandler::setOption(ImageOption option, const QVariant &value)
bool HEIFHandler::supportsOption(ImageOption option) const
{
return option == Quality
|| option == Size;
return option == Quality || option == Size;
}
bool HEIFHandler::ensureParsed() const
@ -376,8 +374,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((const void *)(buffer.constData()), buffer.size());
heif::ImageHandle handle = ctx.get_primary_image_handle();
@ -413,7 +410,6 @@ bool HEIFHandler::ensureDecoder()
return false;
}
heif::Image img = handle.decode_image(heif_colorspace_RGB, chroma);
const int imageWidth = img.get_width(heif_channel_interleaved);
@ -598,7 +594,6 @@ bool HEIFHandler::ensureDecoder()
dest_pixel++;
}
}
}
break;
default:
@ -620,7 +615,7 @@ bool HEIFHandler::ensureDecoder()
} else {
m_current_image.setColorSpace(QColorSpace::fromIccProfile(ba));
if (!m_current_image.colorSpace().isValid()) {
qWarning() << "icc profile is invalid";
qWarning() << "HEIC image has Qt-unsupported or invalid ICC profile!";
}
}
} else {
@ -659,7 +654,8 @@ bool HEIFHandler::ensureDecoder()
break;
default:
qWarning("CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
nclx->color_primaries, nclx->transfer_characteristics);
nclx->color_primaries,
nclx->transfer_characteristics);
q_trc = QColorSpace::TransferFunction::SRgb;
break;
}
@ -681,9 +677,8 @@ bool HEIFHandler::ensureDecoder()
heif_nclx_color_profile_free(nclx);
if (!m_current_image.colorSpace().isValid()) {
qWarning() << "invalid color profile created from NCLX";
qWarning() << "HEIC plugin created invalid QColorSpace from NCLX!";
}
}
} else {

View File

@ -28,6 +28,7 @@ public:
QVariant option(ImageOption option) const override;
void setOption(ImageOption option, const QVariant &value) override;
bool supportsOption(ImageOption option) const override;
private:
static bool isSupportedBMFFType(const QByteArray &header);
bool ensureParsed() const;
@ -36,7 +37,7 @@ private:
enum ParseHeicState {
ParseHeicError = -1,
ParseHeicNotParsed = 0,
ParseHeicSuccess = 1
ParseHeicSuccess = 1,
};
ParseHeicState m_parseState;

View File

@ -12,9 +12,9 @@
#include <kzip.h>
#include <QImage>
#include <QIODevice>
#include <QFile>
#include <QIODevice>
#include <QImage>
static constexpr char s_magic[] = "application/x-krita";
static constexpr int s_magic_size = sizeof(s_magic) - 1; // -1 to remove the last \0
@ -35,10 +35,12 @@ bool KraHandler::canRead() const
bool KraHandler::read(QImage *image)
{
KZip zip(device());
if (!zip.open(QIODevice::ReadOnly)) return false;
if (!zip.open(QIODevice::ReadOnly))
return false;
const KArchiveEntry *entry = zip.directory()->entry(QStringLiteral("mergedimage.png"));
if (!entry || !entry->isFile()) return false;
if (!entry || !entry->isFile())
return false;
const KZipFileEntry *fileZipEntry = static_cast<const KZipFileEntry *>(entry);

View File

@ -31,6 +31,4 @@ public:
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
};
#endif

View File

@ -34,10 +34,12 @@ bool OraHandler::canRead() const
bool OraHandler::read(QImage *image)
{
KZip zip(device());
if (!zip.open(QIODevice::ReadOnly)) return false;
if (!zip.open(QIODevice::ReadOnly))
return false;
const KArchiveEntry *entry = zip.directory()->entry(QStringLiteral("mergedimage.png"));
if (!entry || !entry->isFile()) return false;
if (!entry || !entry->isFile())
return false;
const KZipFileEntry *fileZipEntry = static_cast<const KZipFileEntry *>(entry);

View File

@ -21,7 +21,6 @@ public:
static bool canRead(QIODevice *device);
};
class OraPlugin : public QImageIOPlugin
{
Q_OBJECT
@ -31,6 +30,4 @@ public:
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
};
#endif

View File

@ -12,7 +12,6 @@
#include <QDebug>
#include <QImage>
#pragma pack(push, 1)
class RGB
{
@ -29,7 +28,6 @@ public:
c.b = qBlue(color);
return c;
}
};
class Palette
@ -151,12 +149,16 @@ static QDataStream &operator>>(QDataStream &s, PCXHEADER &ph)
ph.Reserved = res;
ph.NPlanes = np;
quint16 bytesperline;
s >> bytesperline; ph.BytesPerLine = bytesperline;
s >> bytesperline;
ph.BytesPerLine = bytesperline;
quint16 paletteinfo;
s >> paletteinfo; ph.PaletteInfo = paletteinfo;
s >> paletteinfo;
ph.PaletteInfo = paletteinfo;
quint16 hscreensize, vscreensize;
s >> hscreensize; ph.HScreenSize = hscreensize;
s >> vscreensize; ph.VScreenSize = vscreensize;
s >> hscreensize;
ph.HScreenSize = hscreensize;
s >> vscreensize;
ph.VScreenSize = vscreensize;
// Skip the rest of the header
quint8 byte;

View File

@ -21,9 +21,9 @@
#include <QDebug>
#include <QImage>
#include <QVariant>
#include <qendian.h>
#include <algorithm>
#include <functional>
#include <qendian.h>
/**
* Reads a PIC file header from a data stream.
@ -181,15 +181,13 @@ static bool readRow(QDataStream &stream, QRgb *row, quint16 width, const QList<P
return qRgba(red, green, blue, alpha);
};
auto updatePixel = [&](QRgb oldPixel, QRgb newPixel) -> QRgb {
return qRgba(
qRed((channel.code & RED) ? newPixel : oldPixel),
return qRgba(qRed((channel.code & RED) ? newPixel : oldPixel),
qGreen((channel.code & GREEN) ? newPixel : oldPixel),
qBlue((channel.code & BLUE) ? newPixel : oldPixel),
qAlpha((channel.code & ALPHA) ? newPixel : oldPixel));
};
if (channel.encoding == MixedRLE) {
bool success = decodeRLEData(RLEVariant::PIC, stream, row, width,
readPixel, updatePixel);
bool success = decodeRLEData(RLEVariant::PIC, stream, row, width, readPixel, updatePixel);
if (!success) {
qDebug() << "decodeRLEData failed";
return false;
@ -265,9 +263,7 @@ bool SoftimagePICHandler::read(QImage *image)
bool SoftimagePICHandler::write(const QImage &_image)
{
bool alpha = _image.hasAlphaChannel();
const QImage image = _image.convertToFormat(
alpha ? QImage::Format_ARGB32
: QImage::Format_RGB32);
const QImage image = _image.convertToFormat(alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
if (image.width() < 0 || image.height() < 0) {
qDebug() << "Image size invalid:" << image.width() << image.height();
@ -296,18 +292,13 @@ bool SoftimagePICHandler::write(const QImage &_image)
/* Write the RGB part of the scanline */
auto rgbEqual = [](QRgb p1, QRgb p2) -> bool {
return qRed(p1) == qRed(p2) &&
qGreen(p1) == qGreen(p2) &&
qBlue(p1) == qBlue(p2);
return qRed(p1) == qRed(p2) && qGreen(p1) == qGreen(p2) && qBlue(p1) == qBlue(p2);
};
auto writeRgb = [](QDataStream &str, QRgb pixel) -> void {
str << quint8(qRed(pixel))
<< quint8(qGreen(pixel))
<< quint8(qBlue(pixel));
str << quint8(qRed(pixel)) << quint8(qGreen(pixel)) << quint8(qBlue(pixel));
};
if (m_compression) {
encodeRLEData(RLEVariant::PIC, stream, row, image.width(),
rgbEqual, writeRgb);
encodeRLEData(RLEVariant::PIC, stream, row, image.width(), rgbEqual, writeRgb);
} else {
for (int i = 0; i < image.width(); ++i) {
writeRgb(stream, row[i]);
@ -323,8 +314,7 @@ bool SoftimagePICHandler::write(const QImage &_image)
str << quint8(qAlpha(pixel));
};
if (m_compression) {
encodeRLEData(RLEVariant::PIC, stream, row, image.width(),
alphaEqual, writeAlpha);
encodeRLEData(RLEVariant::PIC, stream, row, image.width(), alphaEqual, writeAlpha);
} else {
for (int i = 0; i < image.width(); ++i) {
writeAlpha(stream, row[i]);
@ -408,9 +398,7 @@ QVariant SoftimagePICHandler::option(ImageOption option) const
if (const_cast<SoftimagePICHandler *>(this)->readHeader()) {
QString descStr = QString::fromUtf8(m_header.comment);
if (!descStr.isEmpty()) {
return QString(QStringLiteral("Description: ") +
descStr +
QStringLiteral("\n\n"));
return QString(QStringLiteral("Description: ") + descStr + QStringLiteral("\n\n"));
}
}
return QString();
@ -431,10 +419,7 @@ QVariant SoftimagePICHandler::option(ImageOption option) const
bool SoftimagePICHandler::supportsOption(ImageOption option) const
{
return (option == CompressionRatio ||
option == Description ||
option == ImageFormat ||
option == Size);
return (option == CompressionRatio || option == Description || option == ImageFormat || option == Size);
}
QImageIOPlugin::Capabilities SoftimagePICPlugin::capabilities(QIODevice *device, const QByteArray &format) const

View File

@ -8,8 +8,8 @@
#ifndef KIMG_PIC_P_H
#define KIMG_PIC_P_H
#include <QImageIOPlugin>
#include <QDataStream>
#include <QImageIOPlugin>
/**
* The magic number at the start of a SoftImage PIC file.
@ -25,7 +25,7 @@ enum PicFields {
NoPicture = 0, /**< No picture */
OddScanlines = 1, /**< Odd scanlines */
EvenScanlines = 2, /**< Even scanlines */
BothScanlines = 3 /**< Every scanline */
BothScanlines = 3, /**< Every scanline */
};
/**
@ -33,7 +33,7 @@ enum PicFields {
*/
enum PicChannelEncoding {
Uncompressed = 0, /**< Image is uncompressed */
MixedRLE = 2 /**< Run length compression */
MixedRLE = 2, /**< Run length compression */
};
/**
@ -43,7 +43,7 @@ enum PicChannelCode {
RED = 0x80, /**< Red channel */
GREEN = 0x40, /**< Green channel */
BLUE = 0x20, /**< Blue channel */
ALPHA = 0x10 /**< Alpha channel */
ALPHA = 0x10, /**< Alpha channel */
};
/**
@ -70,9 +70,12 @@ struct PicHeader {
, height(_height)
, ratio(1.0f)
, fields(BothScanlines)
{}
{
}
/** Construct an invalid header. */
PicHeader() {}
PicHeader()
{
}
quint32 magic; /**< Should be PIC_MAGIC_NUMBER */
float version; /**< Version of something (header? file format?) (ignored) */
@ -88,9 +91,9 @@ struct PicHeader {
/**
* Returns true if the @p magic and @p id fields are set correctly.
*/
bool isValid() const {
return magic == PIC_MAGIC_NUMBER
&& id == "PICT";
bool isValid() const
{
return magic == PIC_MAGIC_NUMBER && id == "PICT";
}
/**
@ -123,7 +126,8 @@ struct PicChannel {
: size(_size)
, encoding(_encoding)
, code(_code)
{}
{
}
/**
* Constructs a default channel description for a SoftImage PIC file.
*
@ -135,7 +139,8 @@ struct PicChannel {
*/
PicChannel()
: size(8)
{}
{
}
};
class SoftimagePICHandler : public QImageIOHandler
@ -155,13 +160,14 @@ public:
Error,
Ready,
ReadHeader,
ReadChannels
ReadChannels,
};
SoftimagePICHandler()
: m_state(Ready)
, m_compression(true)
{}
{
}
bool readHeader();
bool readChannels();

View File

@ -31,7 +31,6 @@ typedef quint8 uchar;
namespace // Private.
{
enum ColorMode {
CM_BITMAP = 0,
CM_GRAYSCALE = 1,
@ -40,7 +39,7 @@ enum ColorMode {
CM_CMYK = 4,
CM_MULTICHANNEL = 7,
CM_DUOTONE = 8,
CM_LABCOLOR = 9
CM_LABCOLOR = 9,
};
struct PSDHeader {
@ -105,22 +104,27 @@ static void skip_section(QDataStream &s)
}
template<class Trait>
static Trait readPixel(QDataStream &stream) {
static Trait readPixel(QDataStream &stream)
{
Trait pixel;
stream >> pixel;
return pixel;
}
static QRgb updateRed(QRgb oldPixel, quint8 redPixel) {
static QRgb updateRed(QRgb oldPixel, quint8 redPixel)
{
return qRgba(redPixel, qGreen(oldPixel), qBlue(oldPixel), qAlpha(oldPixel));
}
static QRgb updateGreen(QRgb oldPixel, quint8 greenPixel) {
static QRgb updateGreen(QRgb oldPixel, quint8 greenPixel)
{
return qRgba(qRed(oldPixel), greenPixel, qBlue(oldPixel), qAlpha(oldPixel));
}
static QRgb updateBlue(QRgb oldPixel, quint8 bluePixel) {
static QRgb updateBlue(QRgb oldPixel, quint8 bluePixel)
{
return qRgba(qRed(oldPixel), qGreen(oldPixel), bluePixel, qAlpha(oldPixel));
}
static QRgb updateAlpha(QRgb oldPixel, quint8 alphaPixel) {
static QRgb updateAlpha(QRgb oldPixel, quint8 alphaPixel)
{
return qRgba(qRed(oldPixel), qGreen(oldPixel), qBlue(oldPixel), alphaPixel);
}
typedef QRgb (*channelUpdater)(QRgb, quint8);
@ -151,13 +155,11 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
quint32 channel_num = header.channel_count;
QImage::Format fmt = header.depth == 8 ? QImage::Format_RGB32
: QImage::Format_RGBX64;
QImage::Format fmt = header.depth == 8 ? QImage::Format_RGB32 : QImage::Format_RGBX64;
// Clear the image.
if (channel_num >= 4) {
// Enable alpha.
fmt = header.depth == 8 ? QImage::Format_ARGB32
: QImage::Format_RGBA64;
fmt = header.depth == 8 ? QImage::Format_ARGB32 : QImage::Format_RGBA64;
// Ignore the other channels.
channel_num = 4;
@ -185,20 +187,21 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
return false;
}
static const channelUpdater updaters[4] = {
updateRed,
updateGreen,
updateBlue,
updateAlpha
};
static const channelUpdater updaters[4] = {updateRed, updateGreen, updateBlue, updateAlpha};
typedef QRgba64 (*channelUpdater16)(QRgba64, quint16);
static const channelUpdater16 updaters64[4] = {
[](QRgba64 oldPixel, quint16 redPixel) {return qRgba64((oldPixel & ~(0xFFFFull << 0)) | (quint64( redPixel) << 0));},
[](QRgba64 oldPixel, quint16 greenPixel){return qRgba64((oldPixel & ~(0xFFFFull << 16)) | (quint64(greenPixel) << 16));},
[](QRgba64 oldPixel, quint16 bluePixel) {return qRgba64((oldPixel & ~(0xFFFFull << 32)) | (quint64( bluePixel) << 32));},
[](QRgba64 oldPixel, quint16 alphaPixel){return qRgba64((oldPixel & ~(0xFFFFull << 48)) | (quint64(alphaPixel) << 48));}
};
static const channelUpdater16 updaters64[4] = {[](QRgba64 oldPixel, quint16 redPixel) {
return qRgba64((oldPixel & ~(0xFFFFull << 0)) | (quint64(redPixel) << 0));
},
[](QRgba64 oldPixel, quint16 greenPixel) {
return qRgba64((oldPixel & ~(0xFFFFull << 16)) | (quint64(greenPixel) << 16));
},
[](QRgba64 oldPixel, quint16 bluePixel) {
return qRgba64((oldPixel & ~(0xFFFFull << 32)) | (quint64(bluePixel) << 32));
},
[](QRgba64 oldPixel, quint16 alphaPixel) {
return qRgba64((oldPixel & ~(0xFFFFull << 48)) | (quint64(alphaPixel) << 48));
}};
if (compression) {
// Skip row lengths.
@ -210,14 +213,10 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
for (unsigned short channel = 0; channel < channel_num; channel++) {
bool success = false;
if (header.depth == 8) {
success = decodeRLEData(RLEVariant::PackBits, stream,
image_data, channel_size,
&readPixel<quint8>, updaters[channel]);
success = decodeRLEData(RLEVariant::PackBits, stream, image_data, channel_size, &readPixel<quint8>, updaters[channel]);
} else if (header.depth == 16) {
QRgba64 *image_data = reinterpret_cast<QRgba64 *>(img.bits());
success = decodeRLEData(RLEVariant::PackBits16, stream,
image_data, channel_size,
&readPixel<quint8>, updaters64[channel]);
success = decodeRLEData(RLEVariant::PackBits16, stream, image_data, channel_size, &readPixel<quint8>, updaters64[channel]);
}
if (!success) {

View File

@ -32,4 +32,3 @@ public:
};
#endif // KIMG_PSD_P_H

View File

@ -9,9 +9,9 @@
#include "ras_p.h"
#include <QImage>
#include <QDataStream>
#include <QDebug>
#include <QImage>
namespace // Private.
{
@ -28,13 +28,13 @@ enum RASType {
RAS_TYPE_RGB_FORMAT = 0x3,
RAS_TYPE_TIFF_FORMAT = 0x4,
RAS_TYPE_IFF_FORMAT = 0x5,
RAS_TYPE_EXPERIMENTAL = 0xFFFF
RAS_TYPE_EXPERIMENTAL = 0xFFFF,
};
enum RASColorMapType {
RAS_COLOR_MAP_TYPE_NONE = 0x0,
RAS_COLOR_MAP_TYPE_RGB = 0x1,
RAS_COLOR_MAP_TYPE_RAW = 0x2
RAS_COLOR_MAP_TYPE_RAW = 0x2,
};
struct RasHeader {
@ -46,7 +46,9 @@ struct RasHeader {
quint32 Type;
quint32 ColorMapType;
quint32 ColorMapLength;
enum { SIZE = 32 }; // 8 fields of four bytes each
enum {
SIZE = 32,
}; // 8 fields of four bytes each
};
static QDataStream &operator>>(QDataStream &s, RasHeader &head)
@ -79,8 +81,7 @@ static bool IsSupported(const RasHeader &head)
// check for an appropriate depth
// we support 8bit+palette, 24bit and 32bit ONLY!
// TODO: add support for 1bit
if (!((head.Depth == 8 && head.ColorMapType == 1)
|| head.Depth == 24 || head.Depth == 32)) {
if (!((head.Depth == 8 && head.ColorMapType == 1) || head.Depth == 24 || head.Depth == 32)) {
return false;
}
// the Type field adds support for RLE(BGR), RGB and other encodings
@ -168,7 +169,6 @@ static bool LoadRAS(QDataStream &s, const RasHeader &ras, QImage &img)
img.setPixel(x, y, qRgb(red, green, blue));
}
}
}
if (ras.ColorMapType == 0 && ras.Depth == 24 && (ras.Type == 1 || ras.Type == 2)) {
@ -306,7 +306,6 @@ bool RASHandler::read(QImage *outImage)
QImageIOPlugin::Capabilities RASPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "ras") {
return Capabilities(CanRead);
}

View File

@ -24,14 +24,17 @@
#include <QMap>
#include <QVector>
#include <QImage>
#include <QDebug>
#include <QImage>
class RLEData : public QVector<uchar>
{
public:
RLEData() {}
RLEData(const uchar *d, uint l, uint o) : _offset(o)
RLEData()
{
}
RLEData(const uchar *d, uint l, uint o)
: _offset(o)
{
for (uint i = 0; i < l; i++) {
append(d[i]);
@ -51,7 +54,11 @@ private:
class RLEMap : public QMap<RLEData, uint>
{
public:
RLEMap() : _counter(0), _offset(0) {}
RLEMap()
: _counter(0)
, _offset(0)
{
}
uint insert(const uchar *d, uint l);
QVector<const RLEData *> vector();
void setBaseOffset(uint o)
@ -74,7 +81,12 @@ public:
bool writeImage(const QImage &);
private:
enum { NORMAL, DITHERED, SCREEN, COLORMAP }; // colormap
enum {
NORMAL,
DITHERED,
SCREEN,
COLORMAP,
}; // colormap
QIODevice *_dev;
QDataStream _stream;
@ -108,9 +120,9 @@ private:
uchar intensity(uchar);
};
SGIImage::SGIImage(QIODevice *io) :
_starttab(nullptr),
_lengthtab(nullptr)
SGIImage::SGIImage(QIODevice *io)
: _starttab(nullptr)
, _lengthtab(nullptr)
{
_dev = io;
_stream.setDevice(_dev);
@ -746,8 +758,7 @@ bool RGBHandler::canRead(QIODevice *device)
QImageIOPlugin::Capabilities RGBPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "rgb" || format == "rgba" ||
format == "bw" || format == "sgi") {
if (format == "rgb" || format == "rgba" || format == "bw" || format == "sgi") {
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {

View File

@ -33,4 +33,3 @@ public:
};
#endif // KIMG_RGB_P_H

View File

@ -8,8 +8,8 @@
#ifndef KIMAGEFORMATS_RLE_P_H
#define KIMAGEFORMATS_RLE_P_H
#include <QDebug>
#include <QDataStream>
#include <QDebug>
/**
* The RLEVariant to use.
@ -37,7 +37,7 @@ enum class RLEVariant {
* of size 128, 130 of size 127, down to 255 of
* size 2.
*/
PIC
PIC,
};
/**
@ -64,12 +64,7 @@ enum class RLEVariant {
* into @p buf, @c false otherwise.
*/
template<typename Item, typename Func1, typename Func2>
static inline bool decodeRLEData(RLEVariant variant,
QDataStream &stream,
Item *dest,
quint32 length,
Func1 readData,
Func2 updateItem)
static inline bool decodeRLEData(RLEVariant variant, QDataStream &stream, Item *dest, quint32 length, Func1 readData, Func2 updateItem)
{
unsigned offset = 0; // in dest
bool is_msb = true; // only used for 16-bit PackBits, data is big-endian
@ -154,7 +149,6 @@ static inline bool decodeRLEData(RLEVariant variant,
return stream.status() == QDataStream::Ok;
}
/**
* Encodes data in run-length encoding format.
*
@ -170,18 +164,10 @@ static inline bool decodeRLEData(RLEVariant variant,
* and writes the item to the data stream.
*/
template<typename Item, typename Func1, typename Func2>
static inline void encodeRLEData(RLEVariant variant,
QDataStream &stream,
const Item *data,
unsigned length,
Func1 itemsEqual,
Func2 writeItem)
static inline void encodeRLEData(RLEVariant variant, QDataStream &stream, const Item *data, unsigned length, Func1 itemsEqual, Func2 writeItem)
{
unsigned offset = 0;
const unsigned maxEncodableChunk =
(variant == RLEVariant::PIC)
? 65535u
: 128;
const unsigned maxEncodableChunk = (variant == RLEVariant::PIC) ? 65535u : 128;
while (offset < length) {
const Item *chunkStart = data + offset;
unsigned maxChunk = qMin(length - offset, maxEncodableChunk);
@ -220,10 +206,7 @@ static inline void encodeRLEData(RLEVariant variant,
}
chunkLength = 1;
chunkEnd = chunkStart + 1;
while (chunkLength < maxChunk &&
(chunkLength + 1u == maxChunk ||
!itemsEqual(*chunkEnd, *(chunkEnd+1))))
{
while (chunkLength < maxChunk && (chunkLength + 1u == maxChunk || !itemsEqual(*chunkEnd, *(chunkEnd + 1)))) {
++chunkEnd;
++chunkLength;
}

View File

@ -20,9 +20,9 @@
#include <assert.h>
#include <QImage>
#include <QDataStream>
#include <QDebug>
#include <QImage>
typedef quint32 uint;
typedef quint16 ushort;
@ -30,7 +30,6 @@ typedef quint8 uchar;
namespace // Private.
{
// Header format of saved files.
uchar targaMagic[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@ -40,7 +39,7 @@ enum TGAType {
TGA_TYPE_GREY = 3,
TGA_TYPE_RLE_INDEXED = 9,
TGA_TYPE_RLE_RGB = 10,
TGA_TYPE_RLE_GREY = 11
TGA_TYPE_RLE_GREY = 11,
};
#define TGA_INTERLEAVE_MASK 0xc0
@ -69,7 +68,9 @@ struct TgaHeader {
uchar pixel_size;
uchar flags;
enum { SIZE = 18 }; // const static int SIZE = 18;
enum {
SIZE = 18,
}; // const static int SIZE = 18;
};
static QDataStream &operator>>(QDataStream &s, TgaHeader &head)
@ -88,30 +89,23 @@ static QDataStream &operator>> (QDataStream &s, TgaHeader &head)
s >> head.flags;
/*qDebug() << "id_length: " << head.id_length << " - colormap_type: " << head.colormap_type << " - image_type: " << head.image_type;
qDebug() << "colormap_index: " << head.colormap_index << " - colormap_length: " << head.colormap_length << " - colormap_size: " << head.colormap_size;
qDebug() << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize: " << head.pixel_size << " - flags: " << head.flags;*/
qDebug() << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize:
" << head.pixel_size << " - flags: " << head.flags;*/
return s;
}
static bool IsSupported(const TgaHeader &head)
{
if (head.image_type != TGA_TYPE_INDEXED &&
head.image_type != TGA_TYPE_RGB &&
head.image_type != TGA_TYPE_GREY &&
head.image_type != TGA_TYPE_RLE_INDEXED &&
head.image_type != TGA_TYPE_RLE_RGB &&
head.image_type != TGA_TYPE_RLE_GREY) {
if (head.image_type != TGA_TYPE_INDEXED && head.image_type != TGA_TYPE_RGB && head.image_type != TGA_TYPE_GREY && head.image_type != TGA_TYPE_RLE_INDEXED
&& head.image_type != TGA_TYPE_RLE_RGB && head.image_type != TGA_TYPE_RLE_GREY) {
return false;
}
if (head.image_type == TGA_TYPE_INDEXED ||
head.image_type == TGA_TYPE_RLE_INDEXED) {
if (head.image_type == TGA_TYPE_INDEXED || head.image_type == TGA_TYPE_RLE_INDEXED) {
if (head.colormap_length > 256 || head.colormap_size != 24 || head.colormap_type != 1) {
return false;
}
}
if (head.image_type == TGA_TYPE_RGB ||
head.image_type == TGA_TYPE_GREY ||
head.image_type == TGA_TYPE_RLE_RGB ||
head.image_type == TGA_TYPE_RLE_GREY) {
if (head.image_type == TGA_TYPE_RGB || head.image_type == TGA_TYPE_GREY || head.image_type == TGA_TYPE_RLE_RGB || head.image_type == TGA_TYPE_RLE_GREY) {
if (head.colormap_type != 0) {
return false;
}
@ -119,8 +113,7 @@ static bool IsSupported(const TgaHeader &head)
if (head.width == 0 || head.height == 0) {
return false;
}
if (head.pixel_size != 8 && head.pixel_size != 16 &&
head.pixel_size != 24 && head.pixel_size != 32) {
if (head.pixel_size != 8 && head.pixel_size != 16 && head.pixel_size != 24 && head.pixel_size != 32) {
return false;
}
return true;
@ -138,7 +131,11 @@ struct TgaHeaderInfo {
bool rgb;
bool grey;
TgaHeaderInfo(const TgaHeader &tga) : rle(false), pal(false), rgb(false), grey(false)
TgaHeaderInfo(const TgaHeader &tga)
: rle(false)
, pal(false)
, rgb(false)
, grey(false)
{
switch (tga.image_type) {
case TGA_TYPE_RLE_INDEXED:
@ -282,11 +279,11 @@ static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
return false;
}
if ((uint)dataRead < count) {
const size_t toCopy = count - dataRead;
if (&dst[dataRead] + toCopy > imgEnd) {
qWarning() << "Trying to write out of bounds!" << ptrdiff_t(image) << ptrdiff_t(&dst[dataRead]);;
qWarning() << "Trying to write out of bounds!" << ptrdiff_t(image) << ptrdiff_t(&dst[dataRead]);
;
valid = false;
break;
}

View File

@ -8,15 +8,15 @@
#include "xcf_p.h"
#include <stdlib.h>
#include <QImage>
#include <QPainter>
#include <QDebug>
#include <QIODevice>
#include <QImage>
#include <QLoggingCategory>
#include <QPainter>
#include <QStack>
#include <QVector>
#include <QDebug>
#include <QLoggingCategory>
#include <QtEndian>
#include <stdlib.h>
#include <string.h>
@ -27,7 +27,8 @@ Q_LOGGING_CATEGORY(XCFPLUGIN, "kf.imageformats.plugins.xcf", QtWarningMsg)
const float INCHESPERMETER = (100.0f / 2.54f);
namespace {
namespace
{
struct RandomTable {
// From glibc
static constexpr int rand_r(unsigned int *seed)
@ -54,7 +55,8 @@ struct RandomTable {
return result;
}
constexpr RandomTable() : values{}
constexpr RandomTable()
: values{}
{
unsigned int next = RANDOM_SEED;
@ -88,7 +90,6 @@ class XCFImageFormat
{
Q_GADGET
public:
//! Properties which can be stored in an XCF file.
enum PropType {
PROP_END = 0,
@ -131,7 +132,7 @@ public:
PROP_BLEND_SPACE = 37,
PROP_FLOAT_COLOR = 38,
PROP_SAMPLE_POINTS = 39,
MAX_SUPPORTED_PROPTYPE // should always be at the end so its value is last + 1
MAX_SUPPORTED_PROPTYPE, // should always be at the end so its value is last + 1
};
Q_ENUM(PropType);
@ -141,7 +142,7 @@ public:
COMPRESS_NONE = 0,
COMPRESS_RLE = 1,
COMPRESS_ZLIB = 2, /* unused */
COMPRESS_FRACTAL = 3 /* unused */
COMPRESS_FRACTAL = 3, /* unused */
};
Q_ENUM(XcfCompressionType);
@ -208,7 +209,7 @@ public:
GIMP_LAYER_MODE_MERGE,
GIMP_LAYER_MODE_SPLIT,
GIMP_LAYER_MODE_PASS_THROUGH,
GIMP_LAYER_MODE_COUNT
GIMP_LAYER_MODE_COUNT,
};
Q_ENUM(LayerModeType);
@ -219,7 +220,7 @@ public:
GRAY_GIMAGE,
GRAYA_GIMAGE,
INDEXED_GIMAGE,
INDEXEDA_GIMAGE
INDEXEDA_GIMAGE,
};
Q_ENUM(GimpImageType);
@ -227,7 +228,7 @@ public:
enum GimpColorSpace {
RgbLinearSpace,
RgbPerceptualSpace,
LabSpace
LabSpace,
};
//! Mode to use when compositing layer
@ -239,7 +240,6 @@ public:
CompositeIntersect,
};
XCFImageFormat();
bool readXCF(QIODevice *device, QImage *image);
@ -290,7 +290,8 @@ private:
quint32 visible = 1; //!< Is the layer visible?
quint32 linked; //!< Is this layer linked (geometrically)
quint32 preserve_transparency; //!< Preserve alpha when drawing on layer?
quint32 apply_mask = 9; //!< Apply the layer mask? Use 9 as "uninitilized". Spec says "If the property does not appear for a layer which has a layer mask, it defaults to true (1).
quint32 apply_mask = 9; //!< Apply the layer mask? Use 9 as "uninitilized". Spec says "If the property does not appear for a layer which has a layer
//!< mask, it defaults to true (1).
// Robust readers should force this to false if the layer has no layer mask.
quint32 edit_mask; //!< Is the layer mask the being edited?
quint32 show_mask; //!< Show the layer mask rather than the image?
@ -311,7 +312,10 @@ private:
//! copied in different ways.
void (*assignBytes)(Layer &layer, uint i, uint j);
Layer(void) : name(nullptr) {}
Layer(void)
: name(nullptr)
{
}
~Layer(void)
{
delete[] name;
@ -347,10 +351,14 @@ private:
bool initialized; //!< Is the QImage initialized?
QImage image; //!< final QImage
XCFImage(void) : initialized(false) {}
XCFImage(void)
: initialized(false)
{
}
};
static qint64 readOffsetPtr(QDataStream &stream) {
static qint64 readOffsetPtr(QDataStream &stream)
{
if (stream.version() >= 11) {
qint64 ret;
stream >> ret;
@ -383,12 +391,10 @@ private:
//! The bottom-most layer is copied into the final QImage by this
//! routine.
typedef void (*PixelCopyOperation)(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
typedef void (*PixelCopyOperation)(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
//! Higher layers are merged into the final QImage by this routine.
typedef void (*PixelMergeOperation)(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
typedef void (*PixelMergeOperation)(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static bool modeAffectsSourceAlpha(const quint32 type);
@ -406,42 +412,26 @@ private:
bool loadMask(QDataStream &xcf_io, Layer &layer);
bool loadChannelProperties(QDataStream &xcf_io, Layer &layer);
bool initializeImage(XCFImage &xcf_image);
bool loadTileRLE(QDataStream &xcf_io, uchar *tile, int size,
int data_length, qint32 bpp);
bool loadTileRLE(QDataStream &xcf_io, uchar *tile, int size, int data_length, qint32 bpp);
static void copyLayerToImage(XCFImage &xcf_image);
static void copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeLayerIntoImage(XCFImage &xcf_image);
static void mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n);
static void mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
static void initializeRandomTable();
static void dissolveRGBPixels(QImage &image, int x, int y);
@ -536,7 +526,6 @@ bool XCFImageFormat::modeAffectsSourceAlpha(const quint32 type)
}
}
//! Change a QRgb value's alpha only.
inline QRgb qRgba(const QRgb rgb, int a)
{
@ -548,6 +537,7 @@ inline QRgb qRgba(const QRgb rgb, int a)
*/
XCFImageFormat::XCFImageFormat()
{
static_assert(sizeof(QRgb) == 4, "the code assumes sizeof(QRgb) == 4, if that's not your case, help us fix it :)");
}
/*!
@ -571,8 +561,7 @@ void XCFImageFormat::initializeRandomTable()
}
}
inline
int XCFImageFormat::add_lut(int a, int b)
inline int XCFImageFormat::add_lut(int a, int b)
{
return qMin(a + b, 255);
}
@ -638,19 +627,25 @@ bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
QStack<qint64> layer_offsets;
while (true) {
qint64 layer_offset = readOffsetPtr(xcf_io);
const qint64 layer_offset = readOffsetPtr(xcf_io);
if (layer_offset == 0) {
break;
}
if (layer_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer offset";
return false;
}
layer_offsets.push(layer_offset);
}
xcf_image.num_layers = layer_offsets.size();
if (layer_offsets.size() == 0) {
qCDebug(XCFPLUGIN) << "XCF: no layers!"; return false;
qCDebug(XCFPLUGIN) << "XCF: no layers!";
return false;
}
qCDebug(XCFPLUGIN) << xcf_image.num_layers << "layers";
@ -882,11 +877,9 @@ bool XCFImageFormat::loadLayer(QDataStream &xcf_io, XCFImage &xcf_image)
return false;
}
qCDebug(XCFPLUGIN)
<< "layer: \"" << layer.name << "\", size: " << layer.width << " x "
<< layer.height << ", type: " << GimpImageType(layer.type) << ", mode: " << layer.mode
<< ", opacity: " << layer.opacity << ", visible: " << layer.visible
<< ", offset: " << layer.x_offset << ", " << layer.y_offset;
qCDebug(XCFPLUGIN) << "layer: \"" << layer.name << "\", size: " << layer.width << " x " << layer.height << ", type: " << GimpImageType(layer.type)
<< ", mode: " << layer.mode << ", opacity: " << layer.opacity << ", visible: " << layer.visible << ", offset: " << layer.x_offset << ", "
<< layer.y_offset;
// Skip reading the rest of it if it is not visible. Typically, when
// you export an image from the The GIMP it flattens (or merges) only
@ -901,6 +894,16 @@ bool XCFImageFormat::loadLayer(QDataStream &xcf_io, XCFImage &xcf_image)
layer.hierarchy_offset = readOffsetPtr(xcf_io);
layer.mask_offset = readOffsetPtr(xcf_io);
if (layer.hierarchy_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer hierarchy_offset";
return false;
}
if (layer.mask_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative layer mask_offset";
return false;
}
// Allocate the individual tile QImages based on the size and type
// of this layer.
@ -1083,8 +1086,7 @@ bool XCFImageFormat::composeTiles(XCFImage &xcf_image)
// SANITY CHECK: Catch corrupted XCF image file where the width or height
// of a tile is reported are bogus. See Bug# 234030.
if (layer.width > 32767 || layer.height > 32767
|| (sizeof(void *) == 4 && layer.width * layer.height > 16384 * 16384)) {
if (layer.width > 32767 || layer.height > 32767 || (sizeof(void *) == 4 && layer.width * layer.height > 16384 * 16384)) {
return false;
}
@ -1112,12 +1114,9 @@ bool XCFImageFormat::composeTiles(XCFImage &xcf_image)
for (uint j = 0; j < layer.nrows; j++) {
for (uint i = 0; i < layer.ncols; i++) {
uint tile_width = (i + 1) * TILE_WIDTH <= layer.width ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
? TILE_WIDTH : layer.width - i * TILE_WIDTH;
uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
// Try to create the most appropriate QImage (each GIMP layer
// type is treated slightly differently)
@ -1287,7 +1286,6 @@ void XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j)
uchar *dataPtr = bits + y * bytesPerLine;
uchar *alphaPtr = layer.alpha_tiles[j][i].scanLine(y);
for (int x = 0; x < width; x++) {
// The "if" here should not be necessary, but apparently there
// are some cases where the image can contain larger indices
// than there are colors in the palette. (A bug in The GIMP?)
@ -1321,10 +1319,15 @@ bool XCFImageFormat::loadHierarchy(QDataStream &xcf_io, Layer &layer)
quint32 bpp;
xcf_io >> width >> height >> bpp;
qint64 offset = readOffsetPtr(xcf_io);
const qint64 offset = readOffsetPtr(xcf_io);
qCDebug(XCFPLUGIN) << "width" << width << "height" << height << "bpp" << bpp << "offset" << offset;
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative hierarchy offset";
return false;
}
const bool isMask = layer.assignBytes == assignMaskBytes;
// make sure bpp is correct and complain if it is not
@ -1379,6 +1382,11 @@ bool XCFImageFormat::loadHierarchy(QDataStream &xcf_io, Layer &layer)
break;
}
if (bpp > 4) {
qCDebug(XCFPLUGIN) << "bpp is" << bpp << "We don't support layers with bpp > 4";
return false;
}
// GIMP stores images in a "mipmap"-like format (multiple levels of
// increasingly lower resolution). Only the top level is used here,
// however.
@ -1420,6 +1428,11 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
xcf_io >> width >> height;
qint64 offset = readOffsetPtr(xcf_io);
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
if (offset == 0) {
// offset 0 with rowsxcols != 0 is probably an error since it means we have tiles
// without data but just clear the bits for now instead of returning false
@ -1436,7 +1449,6 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
for (uint j = 0; j < layer.nrows; j++) {
for (uint i = 0; i < layer.ncols; i++) {
if (offset == 0) {
qCDebug(XCFPLUGIN) << "XCF: incorrect number of tiles in layer " << layer.name;
return false;
@ -1445,6 +1457,11 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
qint64 saved_pos = xcf_io.device()->pos();
qint64 offset2 = readOffsetPtr(xcf_io);
if (offset2 < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
// Evidently, RLE can occasionally expand a tile instead of compressing it!
if (offset2 == 0) {
offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
@ -1490,6 +1507,11 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
xcf_io.device()->seek(saved_pos);
offset = readOffsetPtr(xcf_io);
if (offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative level offset";
return false;
}
}
}
@ -1510,13 +1532,18 @@ bool XCFImageFormat::loadMask(QDataStream &xcf_io, Layer &layer)
xcf_io >> width >> height >> name;
delete name;
delete[] name;
if (!loadChannelProperties(xcf_io, layer)) {
return false;
}
qint64 hierarchy_offset = readOffsetPtr(xcf_io);
const qint64 hierarchy_offset = readOffsetPtr(xcf_io);
if (hierarchy_offset < 0) {
qCDebug(XCFPLUGIN) << "XCF: negative mask hierarchy_offset";
return false;
}
xcf_io.device()->seek(hierarchy_offset);
layer.assignBytes = assignMaskBytes;
@ -1551,8 +1578,7 @@ bool XCFImageFormat::loadMask(QDataStream &xcf_io, Layer &layer)
* \return true if there were no I/O errors and no obvious corruption of
* the RLE data.
*/
bool XCFImageFormat::loadTileRLE(QDataStream &xcf_io, uchar *tile, int image_size,
int data_length, qint32 bpp)
bool XCFImageFormat::loadTileRLE(QDataStream &xcf_io, uchar *tile, int image_size, int data_length, qint32 bpp)
{
uchar *data;
@ -1587,7 +1613,6 @@ bool XCFImageFormat::loadTileRLE(QDataStream &xcf_io, uchar *tile, int image_siz
xcfdatalimit = &xcfodata[data_length - 1];
for (int i = 0; i < bpp; ++i) {
data = tile + i;
int count = 0;
@ -1719,13 +1744,11 @@ bool XCFImageFormat::loadChannelProperties(QDataStream &xcf_io, Layer &layer)
break;
case PROP_COLOR:
property >> layer.mask_channel.red >> layer.mask_channel.green
>> layer.mask_channel.blue;
property >> layer.mask_channel.red >> layer.mask_channel.green >> layer.mask_channel.blue;
break;
case PROP_FLOAT_COLOR:
property >> layer.mask_channel.redF >> layer.mask_channel.greenF
>> layer.mask_channel.blueF;
property >> layer.mask_channel.redF >> layer.mask_channel.greenF >> layer.mask_channel.blueF;
break;
case PROP_TATTOO:
@ -2018,7 +2041,6 @@ void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
int m = x + k + layer.x_offset;
int n = y + l + layer.y_offset;
@ -2046,8 +2068,7 @@ void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
uchar src_a = layer.opacity;
@ -2058,8 +2079,7 @@ void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -2077,8 +2097,7 @@ void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
int src = layer.image_tiles[j][i].pixelIndex(k, l);
image.setPixel(m, n, src);
@ -2097,8 +2116,7 @@ void XCFImageFormat::copyGrayToGray(const Layer &layer, uint i, uint j, int k, i
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
uchar src_a = layer.opacity;
@ -2118,8 +2136,7 @@ void XCFImageFormat::copyGrayToRGB(const Layer &layer, uint i, uint j, int k, in
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
@ -2127,8 +2144,7 @@ void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, i
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -2146,8 +2162,7 @@ void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, i
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
int src = layer.image_tiles[j][i].pixelIndex(k, l);
image.setPixel(m, n, src);
@ -2164,16 +2179,13 @@ void XCFImageFormat::copyIndexedToIndexed(const Layer &layer, uint i, uint j, in
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
src_a = INT_MULT(src_a, layer.opacity);
if (layer.apply_mask == 1 &&
layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -2199,16 +2211,14 @@ void XCFImageFormat::copyIndexedAToIndexed(const Layer &layer, uint i, uint j, i
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
src_a = INT_MULT(src_a, layer.opacity);
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -2312,7 +2322,6 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
qCDebug(XCFPLUGIN) << "Unhandled composite mode" << compositeMode;
}
switch (layer.type) {
case RGB_GIMAGE:
case RGBA_GIMAGE:
@ -2373,8 +2382,7 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
}
// Shortcut for common case
if (merge == mergeRGBToRGB && layer.apply_mask != 1
&& layer.mode == NORMAL_MODE) {
if (merge == mergeRGBToRGB && layer.apply_mask != 1 && layer.mode == NORMAL_MODE) {
QPainter painter(&image);
painter.setOpacity(layer.opacity / 255.0);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
@ -2384,7 +2392,6 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
int m = x + k + layer.x_offset;
int n = y + l + layer.y_offset;
@ -2412,8 +2419,7 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
QRgb dst = image.pixel(m, n);
@ -2515,8 +2521,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_g = new_g;
src_b = new_b;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY: {
uchar new_r = dst_r;
uchar new_g = dst_g;
@ -2533,8 +2538,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_g = new_g;
src_b = new_b;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_HSV_VALUE_LEGACY: {
uchar new_r = dst_r;
uchar new_g = dst_g;
@ -2551,8 +2555,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_g = new_g;
src_b = new_b;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_HSL_COLOR_LEGACY: {
uchar new_r = dst_r;
uchar new_g = dst_g;
@ -2570,8 +2573,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_g = new_g;
src_b = new_b;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_DODGE_LEGACY: {
uint tmp;
@ -2588,8 +2590,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_b = (uchar)qMin(tmp, 255u);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_BURN_LEGACY: {
uint tmp;
@ -2609,8 +2610,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_b = 255 - src_b;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
uint tmp;
if (src_r > 128) {
@ -2637,29 +2637,24 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_b = (uchar)qMin(tmp >> 8, 255u);
}
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
uint tmpS, tmpM;
tmpM = INT_MULT(dst_r, src_r);
tmpS = 255 - INT_MULT((255 - dst_r), (255 - src_r));
src_r = INT_MULT((255 - dst_r), tmpM)
+ INT_MULT(dst_r, tmpS);
src_r = INT_MULT((255 - dst_r), tmpM) + INT_MULT(dst_r, tmpS);
tmpM = INT_MULT(dst_g, src_g);
tmpS = 255 - INT_MULT((255 - dst_g), (255 - src_g));
src_g = INT_MULT((255 - dst_g), tmpM)
+ INT_MULT(dst_g, tmpS);
src_g = INT_MULT((255 - dst_g), tmpM) + INT_MULT(dst_g, tmpS);
tmpM = INT_MULT(dst_b, src_b);
tmpS = 255 - INT_MULT((255 - dst_b), (255 - src_b));
src_b = INT_MULT((255 - dst_b), tmpM)
+ INT_MULT(dst_b, tmpS);
src_b = INT_MULT((255 - dst_b), tmpM) + INT_MULT(dst_b, tmpS);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
int tmp;
@ -2679,8 +2674,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_b = (uchar)tmp;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
int tmp;
@ -2700,8 +2694,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
src_b = (uchar)tmp;
src_a = qMin(src_a, dst_a);
}
break;
} break;
default:
break;
}
@ -2710,8 +2703,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -2743,8 +2735,7 @@ void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, in
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
int src = layer.image_tiles[j][i].pixelIndex(k, l);
image.setPixel(m, n, src);
@ -2761,8 +2752,7 @@ void XCFImageFormat::mergeGrayToGray(const Layer &layer, uint i, uint j, int k,
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
int src = qGray(layer.image_tiles[j][i].pixel(k, l));
int dst = image.pixelIndex(m, n);
@ -2776,53 +2766,42 @@ void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k,
switch (layer.mode) {
case MULTIPLY_MODE: {
src = INT_MULT(src, dst);
}
break;
} break;
case DIVIDE_MODE: {
src = qMin((dst * 256) / (1 + src), 255);
}
break;
} break;
case SCREEN_MODE: {
src = 255 - INT_MULT(255 - dst, 255 - src);
}
break;
} break;
case OVERLAY_MODE: {
src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
}
break;
} break;
case DIFFERENCE_MODE: {
src = dst > src ? dst - src : src - dst;
}
break;
} break;
case ADDITION_MODE: {
src = add_lut(dst, src);
}
break;
} break;
case SUBTRACT_MODE: {
src = dst > src ? dst - src : 0;
}
break;
} break;
case DARKEN_ONLY_MODE: {
src = dst < src ? dst : src;
}
break;
} break;
case LIGHTEN_ONLY_MODE: {
src = dst < src ? src : dst;
}
break;
} break;
case DODGE_MODE: {
uint tmp = dst << 8;
tmp /= 256 - src;
src = (uchar)qMin(tmp, 255u);
}
break;
} break;
case BURN_MODE: {
uint tmp = (255 - dst) << 8;
tmp /= src + 1;
src = (uchar)qMin(tmp, 255u);
src = 255 - src;
}
break;
} break;
case HARDLIGHT_MODE: {
uint tmp;
if (src > 128) {
@ -2832,18 +2811,15 @@ void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k,
tmp = (int)dst * ((int)src << 1);
src = (uchar)qMin(tmp >> 8, 255u);
}
}
break;
} break;
case SOFTLIGHT_MODE: {
uint tmpS, tmpM;
tmpM = INT_MULT(dst, src);
tmpS = 255 - INT_MULT((255 - dst), (255 - src));
src = INT_MULT((255 - dst), tmpM)
+ INT_MULT(dst, tmpS);
src = INT_MULT((255 - dst), tmpM) + INT_MULT(dst, tmpS);
}
break;
} break;
case GRAIN_EXTRACT_MODE: {
int tmp;
@ -2852,8 +2828,7 @@ void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k,
tmp = qMax(tmp, 0);
src = (uchar)tmp;
}
break;
} break;
case GRAIN_MERGE_MODE: {
int tmp;
@ -2862,16 +2837,14 @@ void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k,
tmp = qMax(tmp, 0);
src = (uchar)tmp;
}
break;
} break;
}
src_a = INT_MULT(src_a, layer.opacity);
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -2898,8 +2871,7 @@ void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k,
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
uchar src_a = layer.opacity;
@ -2919,8 +2891,7 @@ void XCFImageFormat::mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, i
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
int src = qGray(layer.image_tiles[j][i].pixel(k, l));
int dst = qGray(image.pixel(m, n));
@ -2936,63 +2907,52 @@ void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k,
case MULTIPLY_MODE: {
src = INT_MULT(src, dst);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case DIVIDE_MODE: {
src = qMin((dst * 256) / (1 + src), 255);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case SCREEN_MODE: {
src = 255 - INT_MULT(255 - dst, 255 - src);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case OVERLAY_MODE: {
src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
src_a = qMin(src_a, dst_a);
}
break;
} break;
case DIFFERENCE_MODE: {
src = dst > src ? dst - src : src - dst;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case ADDITION_MODE: {
src = add_lut(dst, src);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case SUBTRACT_MODE: {
src = dst > src ? dst - src : 0;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case DARKEN_ONLY_MODE: {
src = dst < src ? dst : src;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case LIGHTEN_ONLY_MODE: {
src = dst < src ? src : dst;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case DODGE_MODE: {
uint tmp = dst << 8;
tmp /= 256 - src;
src = (uchar)qMin(tmp, 255u);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case BURN_MODE: {
uint tmp = (255 - dst) << 8;
tmp /= src + 1;
src = (uchar)qMin(tmp, 255u);
src = 255 - src;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case HARDLIGHT_MODE: {
uint tmp;
if (src > 128) {
@ -3003,19 +2963,16 @@ void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k,
src = (uchar)qMin(tmp >> 8, 255u);
}
src_a = qMin(src_a, dst_a);
}
break;
} break;
case SOFTLIGHT_MODE: {
uint tmpS, tmpM;
tmpM = INT_MULT(dst, src);
tmpS = 255 - INT_MULT((255 - dst), (255 - src));
src = INT_MULT((255 - dst), tmpM)
+ INT_MULT(dst, tmpS);
src = INT_MULT((255 - dst), tmpM) + INT_MULT(dst, tmpS);
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GRAIN_EXTRACT_MODE: {
int tmp;
@ -3025,8 +2982,7 @@ void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k,
src = (uchar)tmp;
src_a = qMin(src_a, dst_a);
}
break;
} break;
case GRAIN_MERGE_MODE: {
int tmp;
@ -3036,15 +2992,13 @@ void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k,
src = (uchar)tmp;
src_a = qMin(src_a, dst_a);
}
break;
} break;
}
src_a = INT_MULT(src_a, layer.opacity);
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -3073,8 +3027,7 @@ void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k,
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
int src = layer.image_tiles[j][i].pixelIndex(k, l);
image.setPixel(m, n, src);
@ -3091,16 +3044,13 @@ void XCFImageFormat::mergeIndexedToIndexed(const Layer &layer, uint i, uint j, i
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
src_a = INT_MULT(src_a, layer.opacity);
if (layer.apply_mask == 1 &&
layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}
@ -3123,16 +3073,14 @@ void XCFImageFormat::mergeIndexedAToIndexed(const Layer &layer, uint i, uint j,
* \param m x pixel of destination image.
* \param n y pixel of destination image.
*/
void XCFImageFormat::mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
QImage &image, int m, int n)
void XCFImageFormat::mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
{
QRgb src = layer.image_tiles[j][i].pixel(k, l);
uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
src_a = INT_MULT(src_a, layer.opacity);
// Apply the mask (if any)
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
layer.mask_tiles[j].size() > (int)i) {
if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
}

View File

@ -7,8 +7,8 @@
#ifndef FORMAT_ENUM_H
#define FORMAT_ENUM_H
#include <QMetaEnum>
#include <QImage>
#include <QMetaEnum>
QImage::Format formatFromString(const QString &str)
{

View File

@ -27,21 +27,20 @@ int main(int argc, char **argv)
parser.addVersionOption();
parser.addPositionalArgument(QStringLiteral("in"), QStringLiteral("input image file"));
parser.addPositionalArgument(QStringLiteral("out"), QStringLiteral("output image file"));
QCommandLineOption informat(
QStringList() << QStringLiteral("i") << QStringLiteral("informat"),
QCommandLineOption informat(QStringList() << QStringLiteral("i") << QStringLiteral("informat"),
QStringLiteral("Image format for input file"),
QStringLiteral("format"));
parser.addOption(informat);
QCommandLineOption outformat(
QStringList() << QStringLiteral("o") << QStringLiteral("outformat"),
QCommandLineOption outformat(QStringList() << QStringLiteral("o") << QStringLiteral("outformat"),
QStringLiteral("Image format for output file"),
QStringLiteral("format"));
parser.addOption(outformat);
QCommandLineOption listformats(
QStringList() << QStringLiteral("l") << QStringLiteral("list"),
QStringLiteral("List supported image formats"));
QCommandLineOption listformats(QStringList() << QStringLiteral("l") << QStringLiteral("list"), QStringLiteral("List supported image formats"));
parser.addOption(listformats);
QCommandLineOption listmimes(QStringList() << QStringLiteral("m") << QStringLiteral("listmime"), QStringLiteral("List supported image mime formats"));
parser.addOption(listmimes);
parser.process(app);
const QStringList files = parser.positionalArguments();
@ -61,6 +60,21 @@ int main(int argc, char **argv)
return 0;
}
if (parser.isSet(listmimes)) {
QTextStream out(stdout);
out << "Input mime formats:\n";
const auto lstReaderSupportedMimes = QImageReader::supportedMimeTypes();
for (const QByteArray &fmt : lstReaderSupportedMimes) {
out << " " << fmt << '\n';
}
out << "Output mime formats:\n";
const auto lstWriterSupportedMimes = QImageWriter::supportedMimeTypes();
for (const QByteArray &fmt : lstWriterSupportedMimes) {
out << " " << fmt << '\n';
}
return 0;
}
if (files.count() != 2) {
QTextStream(stdout) << "Must provide exactly two files\n";
parser.showHelp(1);

View File

@ -10,10 +10,10 @@
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDebug>
#include <QImageReader>
#include <QFile>
#include <QMetaObject>
#include <QImageReader>
#include <QMetaEnum>
#include <QMetaObject>
#include <QTextStream>
#include "format-enum.h"
@ -31,26 +31,21 @@ int main(int argc, char **argv)
parser.addVersionOption();
parser.addPositionalArgument(QStringLiteral("image"), QStringLiteral("image file"));
parser.addPositionalArgument(QStringLiteral("datafile"), QStringLiteral("file QImage data should be written to"));
QCommandLineOption informat(
QStringList() << QStringLiteral("f") << QStringLiteral("file-format"),
QCommandLineOption informat(QStringList() << QStringLiteral("f") << QStringLiteral("file-format"),
QStringLiteral("Image file format"),
QStringLiteral("format"));
parser.addOption(informat);
QCommandLineOption qimgformat(
QStringList() << QStringLiteral("q") << QStringLiteral("qimage-format"),
QCommandLineOption qimgformat(QStringList() << QStringLiteral("q") << QStringLiteral("qimage-format"),
QStringLiteral("QImage data format"),
QStringLiteral("format"));
parser.addOption(qimgformat);
QCommandLineOption listformats(
QStringList() << QStringLiteral("l") << QStringLiteral("list-file-formats"),
QCommandLineOption listformats(QStringList() << QStringLiteral("l") << QStringLiteral("list-file-formats"),
QStringLiteral("List supported image file formats"));
parser.addOption(listformats);
QCommandLineOption listmimetypes(
QStringList() << QStringLiteral("m") << QStringLiteral("list-mime-types"),
QCommandLineOption listmimetypes(QStringList() << QStringLiteral("m") << QStringLiteral("list-mime-types"),
QStringLiteral("List supported image mime types"));
parser.addOption(listmimetypes);
QCommandLineOption listqformats(
QStringList() << QStringLiteral("p") << QStringLiteral("list-qimage-formats"),
QCommandLineOption listqformats(QStringList() << QStringLiteral("p") << QStringLiteral("list-qimage-formats"),
QStringLiteral("List supported QImage data formats"));
parser.addOption(listqformats);
@ -93,35 +88,29 @@ int main(int argc, char **argv)
QImageReader reader(files.at(0), parser.value(informat).toLatin1());
QImage img = reader.read();
if (img.isNull()) {
QTextStream(stderr) << "Could not read image: "
<< reader.errorString() << '\n';
QTextStream(stderr) << "Could not read image: " << reader.errorString() << '\n';
return 2;
}
QFile output(files.at(1));
if (!output.open(QIODevice::WriteOnly)) {
QTextStream(stderr) << "Could not open " << files.at(1)
<< " for writing: "
<< output.errorString() << '\n';
QTextStream(stderr) << "Could not open " << files.at(1) << " for writing: " << output.errorString() << '\n';
return 3;
}
if (parser.isSet(qimgformat)) {
QImage::Format qformat = formatFromString(parser.value(qimgformat));
if (qformat == QImage::Format_Invalid) {
QTextStream(stderr) << "Unknown QImage data format "
<< parser.value(qimgformat) << '\n';
QTextStream(stderr) << "Unknown QImage data format " << parser.value(qimgformat) << '\n';
return 4;
}
img = img.convertToFormat(qformat);
}
qint64 written = output.write(reinterpret_cast<const char *>(img.bits()), img.sizeInBytes());
if (written != img.sizeInBytes()) {
QTextStream(stderr) << "Could not write image data to " << files.at(1)
<< ":" << output.errorString() << "\n";
QTextStream(stderr) << "Could not write image data to " << files.at(1) << ":" << output.errorString() << "\n";
return 5;
}
QTextStream(stdout) << "Created " << files.at(1) << " with data format "
<< formatToString(img.format()) << "\n";
QTextStream(stdout) << "Created " << files.at(1) << " with data format " << formatToString(img.format()) << "\n";
return 0;
}