Compare commits

...

29 Commits

Author SHA1 Message Date
5b42b3b787 Upgrade ECM version requirement to 1.0.0 after all. 2014-07-01 20:16:27 +02:00
f98e508da4 Upgrade ECM and KF5 version requirements. 2014-07-01 15:32:05 +02:00
a92540f00d Upgrade ECM and KF5 version requirements. 2014-06-01 12:40:39 +02:00
2ec0d5abc6 Fix a compiler warning about signed/unsigned comparisons
The "+ 1" was causing an unsigned value to be cast to a signed value,
which was then compared with an unsigned value, causing the warning.
Making the constant unsigned fixes this.
2014-05-30 16:47:19 +01:00
cca4c545a4 Hide documented internal classes from Doxygen 2014-05-30 16:40:05 +01:00
87b545f9ed Make sure Doxygen does not interpret license headers as dox
The extra *s were confusing it.
2014-05-30 16:38:45 +01:00
1132abbf67 Update metainfo.yaml's short description and platform notes 2014-05-16 17:07:10 +01:00
2a8251c493 Upgrade ECM and KF5 version requirements. 2014-05-04 20:48:28 +02:00
51eca9b6a8 Rewrite the PIC image format handler
It now uses QDataStream to deal with endianness. It also supports
several QImageIOHandler options.

This comes with a more comprehensive test suite than the old code. Note
that the old test suite was incorrect as the old code wrote the floats
in the header out incorrectly (although no-one noticed because no
software seems to care about those values).

All the test PIC files in the test suite appear correct according to the
specification (by inspection with Okteta). Unfortunately, there is a
lack of other freely-available software that reads and writes PIC files
(the main application that uses them is proprietary), and so this is the
best I can do.

REVIEW: 117944
2014-05-04 13:42:30 +01:00
74906dd3bc Add framework information in metainfo.yaml files 2014-04-26 15:29:34 +02:00
c1a7769ecc Rename the yaml file per new policy 2014-04-26 12:21:53 +02:00
1eb5228cce Allow some fuzz in the jp2 unit test
See the comment added to the CMake file.

CCMAIL: jr@jriddell.org
2014-04-25 17:57:40 +01:00
889df138bb Update comment for kde4support -> kdelibs4support rename 2014-04-10 18:27:55 +01:00
101ba47b61 Upgrade ECM version requirement and KF5 version. 2014-03-28 19:17:00 +01:00
2ded57d50e Remove FindOpenEXR.cmake
The file has moved to the extra-cmake-modules repository.

REVIEW: 116713
2014-03-11 15:00:40 +01:00
0f795e6625 Implement fuzzy image matching in readtest
Images are converted to ARGB32 format, then each byte (ie: each pixel
channel) in the read image is allowed to deviate by some specified
amount from the corresponding byte in the expected image, to allow for
rounding errors etc.

By default, no deviation is permitted, but the XCF tests are allowed a
deviation of 1, as the alpha blending can result in rounding errors
(depending on whether hardware acceleration is used, for example).  In
the end, we are not too concerned about a small deviation that is
invisible to the human eye.

REVIEW: 116567
2014-03-05 12:10:45 +00:00
895305050c Extract QImage::Format parsing into its own header
Use the array-of-strings suggested by David Faure so that only one list
has to be maintained instead of three.

REVIEW: 116567
2014-03-05 12:10:31 +00:00
e29a897cb9 Add imagedump: a utility to dump the raw data of a QImage
This is intended as an aid when writing and debugging imageformat
plugins.  It creates a file containing the bytes of QImage::bits(),
which can then be viewed in Okteta.

REVIEW: 116532
2014-03-02 16:09:30 +00:00
6d24f585b1 read autotest: write out data when comparison fails
This helps with debugging, as we can just grab the data rather than
using imageconvertor.

Reviewed-by: David Faure
2014-03-01 14:49:38 +00:00
b4192f9f8b Upgrade ECM version requirement and KF5 version. 2014-03-01 12:51:00 +01:00
6375160828 Remove the WebP format
This will be in Qt 5.3.

REVIEW: 116026
2014-02-25 12:16:34 +00:00
89a3e64c0e Rename webp.xml to kf5-imagesformats-webp.xml on installation
This prevents a clash with kde-runtime 4, and is a better naming scheme
anyway (to prevent accidental clashes with mime packages from other
software).

REVIEW: 115913
2014-02-24 17:04:04 +00:00
6272954cc5 Only perform tests for plugins that are built
This both excludes the autotests and tests subdirs if the user sets
BUILD_TESTING off, and makes sure we do not run tests for formats that
were not built due to dependencies not being found.

REVIEW: 115504
2014-02-23 11:54:40 +00:00
4fbbc75429 WebP: use Q_DECL_OVERRIDE
In doing so, found a method that should not have been overridden, and so
removed it.

REVIEW: 115355
2014-02-20 12:56:17 +00:00
331a813662 WebP: remove unused include
REVIEW: 115355
2014-02-20 12:56:14 +00:00
30cff60296 Make WebP mimetype xml match the one in shared-mime-info-git
This includes the detection magic and an alias for image/webp.  It
should be in shared-mime-info 1.3.

Proposed by Jerome Leclanche <adys.wh@gmail.com>.

REVIEW: 115355
2014-02-20 12:56:10 +00:00
7177296335 Import the WebP image I/O code from kde-runtime
The plugin export mechanism has been patched up (including the addition
of the JSON file), and the FindWebP.cmake file is new.

Writing is currently disabled, as it produces broken images.

Autotests are generated using the cwebp and dwebp utilities distributed
with the libwebp reference library.

REVIEW: 115355
2014-02-20 12:56:00 +00:00
f490ab0761 Fix mimetype declarations in json files
There has to be one mimetype declaration for each format name.

REVIEW: 115686
2014-02-16 10:46:42 +00:00
3eafdc861a Remove the xv image format plugin
It appears to be some internal format of xview, although I cannot find
any mention of such a thing on the internet.  There does not appear to
be any sort of mime type to associate with this file format, either.

Therefore, I think it is reasonable to declare it obsolete.

REVIEW: 115768
2014-02-15 18:47:06 +00:00
55 changed files with 1376 additions and 1177 deletions

View File

@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 2.8.12)
project(KImageFormats)
find_package(ECM 0.0.10 REQUIRED NO_MODULE)
find_package(ECM 1.0.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(KDEInstallDirs)
include(KDEFrameworkCompilerSettings)
@ -16,8 +16,38 @@ include(CheckIncludeFiles)
set(REQUIRED_QT_VERSION 5.2.0)
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
# EPS support depends on the gs utility; non-UNIX systems are unlikely to have
# this available in PATH
set(BUILD_EPS_PLUGIN FALSE)
if (UNIX)
find_package(Qt5PrintSupport 5.2.0 NO_MODULE)
set_package_properties(Qt5PrintSupport PROPERTIES
PURPOSE "Required for the QImage plugin for EPS images"
TYPE OPTIONAL
)
if (Qt5PrintSupport_FOUND)
set(BUILD_EPS_PLUGIN TRUE)
endif()
endif()
find_package(Jasper)
set_package_properties(Jasper PROPERTIES
DESCRIPTION "A library for handling JPEG-2000 images"
PURPOSE "Required for the QImage plugin for JPEG-2000 images"
URL "http://www.ece.uvic.ca/~mdadams/jasper"
TYPE OPTIONAL
)
find_package(OpenEXR)
set_package_properties(OpenEXR PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for the QImage plugin for OpenEXR images"
)
add_subdirectory(src)
add_subdirectory(autotests)
add_subdirectory(tests)
if (BUILD_TESTING)
add_subdirectory(autotests)
add_subdirectory(tests)
endif()
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

View File

@ -1,30 +1,42 @@
#find_package(Qt5Test ${REQUIRED_QT_VERSION} NO_MODULE)
include(ECMMarkAsTest)
include(CMakeParseArguments)
add_definitions(-DPLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}/../src")
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
macro(kimageformats_read_tests)
cmake_parse_arguments(KIF_RT "" "FUZZ" "" ${ARGN})
set(_fuzzarg)
if (KIF_RT_FUZZ)
set(_fuzzarg -f ${KIF_RT_FUZZ})
endif()
if (NOT TARGET readtest)
add_executable(readtest readtest.cpp)
target_link_libraries(readtest Qt5::Gui)
target_compile_definitions(readtest
PRIVATE IMAGEDIR="${CMAKE_CURRENT_SOURCE_DIR}/read")
ecm_mark_as_test(readtest)
foreach(_testname ${ARGN})
endif()
foreach(_testname ${KIF_RT_UNPARSED_ARGUMENTS})
add_test(
NAME kimageformats-read-${_testname}
COMMAND readtest ${_testname}
COMMAND readtest ${_fuzzarg} ${_testname}
)
endforeach(_testname)
endmacro()
macro(kimageformats_write_tests)
if (NOT TARGET writetest)
add_executable(writetest writetest.cpp)
target_link_libraries(writetest Qt5::Gui)
target_compile_definitions(writetest
PRIVATE IMAGEDIR="${CMAKE_CURRENT_SOURCE_DIR}/write")
ecm_mark_as_test(writetest)
endif()
foreach(_testname ${ARGN})
string(REGEX MATCH "-lossless$" _is_lossless "${_testname}")
unset(lossless_arg)
@ -43,17 +55,16 @@ endmacro()
# Loads each <format> image in read/<format>/, and compares the
# result against the data read from the corresponding png file
kimageformats_read_tests(
#eps # EPS read tests depend on the vagaries of GhostScript
# which we cannot even guarantee to find
jp2
pcx
pic
psd
ras
rgb
tga
)
# Allow some fuzziness when reading this formats, to allow for
# rounding errors (eg: in alpha blending).
kimageformats_read_tests(FUZZ 1
xcf
xv
)
# Basic write tests
@ -63,12 +74,42 @@ kimageformats_read_tests(
# You can append -lossless to the format to indicate that
# reading back the image data will result in an identical image.
kimageformats_write_tests(
#eps # EPS writing depends on a choice of tools, and so needs
# a cleverer test
jp2
pcx-lossless
pic-lossless
rgb-lossless
tga # fixme: the alpha images appear not to be written properly
xv
)
# EPS read tests depend on the vagaries of GhostScript
# which we cannot even guarantee to find, so disable them for now
#if (BUILD_EPS_PLUGIN)
# kimageformats_read_tests(eps)
# kimageformats_write_tests(eps)
#endif()
if (JASPER_FOUND)
# FIXME: when we read JPEG2000 files on different architectures
# (specifically x86_64 and i386), we get off-by-one errors. The
# jasper utility does not have the same problem, so it is not a
# problem inherent in the jasper library. For now, we just allow
# a little fuzziness to make sure it does not get any worse (being
# off by one in an image value is not noticable to the human eye,
# so it is not a release-blocking issue).
kimageformats_read_tests(FUZZ 1 jp2)
kimageformats_write_tests(jp2)
endif()
if (OpenEXR_FOUND)
# FIXME: OpenEXR tests
endif()
find_package(Qt5Test ${REQUIRED_QT_VERSION} CONFIG QUIET)
if(NOT Qt5Test_FOUND)
message(STATUS "Qt5Test not found, some autotests will not be built.")
return()
endif()
add_executable(pictest pictest.cpp)
target_link_libraries(pictest Qt5::Gui Qt5::Test)
ecm_mark_as_test(pictest)
add_test(NAME kimageformats-pic COMMAND pictest)

BIN
autotests/long-runs.pic Normal file

Binary file not shown.

Binary file not shown.

BIN
autotests/pic/4x4-alpha.pic Normal file

Binary file not shown.

BIN
autotests/pic/4x4-alpha.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

BIN
autotests/pic/long-runs.pic Normal file

Binary file not shown.

BIN
autotests/pic/long-runs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

277
autotests/pictest.cpp Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright 2014 Alex Merry <alex.merry@kdemail.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <QBuffer>
#include <QFile>
#include <QFileInfo>
#include <QImage>
#include <QImageReader>
#include <QImageWriter>
#include <QTest>
#include <QUuid>
Q_DECLARE_METATYPE(QImage::Format)
class PicTests : public QObject
{
Q_OBJECT
private:
void common_data()
{
QTest::addColumn<QString>("picfile");
QTest::addColumn<QString>("pngfile");
QTest::addColumn<QString>("comment");
// whether the pic file has/should have an alpha channel
QTest::addColumn<bool>("alpha");
// the format to convert the png file to before writing
// or comparing to the read image; this can be used to
// induce loss of data (eg: make the image monochrome)
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 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("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("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;
}
private Q_SLOTS:
void initTestCase()
{
QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR));
}
void testWrite_data()
{
common_data();
// NB: 4x4-simple-color only uses solid red, blue, green and white,
// 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;
}
void testRead_data()
{
common_data();
// TODO: test reading files with unusual channel setups
// (eg: one channel for each component)
}
void testWrite()
{
QFETCH(QString, picfile);
QFETCH(QString, pngfile);
QFETCH(QString, comment);
QFETCH(QImage::Format, pngformat);
QFETCH(bool, compress);
QImageReader pngReader(pngfile, "png");
QImage pngImage;
QVERIFY2(pngReader.read(&pngImage), qPrintable(pngReader.errorString()));
pngImage = pngImage.convertToFormat(pngformat);
QFile expFile(picfile);
QVERIFY2(expFile.open(QIODevice::ReadOnly), qPrintable(expFile.errorString()));
QByteArray expData = expFile.readAll();
QByteArray picData;
QBuffer buffer(&picData);
QImageWriter imgWriter(&buffer, "pic");
imgWriter.setText(QStringLiteral("Description"), comment);
imgWriter.setCompression(compress);
imgWriter.write(pngImage);
if (expData != picData) {
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(')');
QFAIL(qPrintable(msg));
}
}
void testRead()
{
QFETCH(QString, picfile);
QFETCH(QString, pngfile);
QFETCH(bool, alpha);
QFETCH(QImage::Format, pngformat);
QImageReader inputReader(picfile, "pic");
QImageReader expReader(pngfile, "png");
QImage inputImage;
QImage expImage;
QVERIFY2(expReader.read(&expImage), qPrintable(expReader.errorString()));
QVERIFY2(inputReader.read(&inputImage), qPrintable(inputReader.errorString()));
QCOMPARE(inputImage.width(), expImage.width());
QCOMPARE(inputImage.height(), expImage.height());
QCOMPARE(inputImage.hasAlphaChannel(), alpha);
QCOMPARE(inputImage.format(), alpha ? QImage::Format_ARGB32
: QImage::Format_RGB32);
expImage = expImage.convertToFormat(pngformat);
expImage = expImage.convertToFormat(alpha ? QImage::Format_ARGB32
: QImage::Format_RGB32);
if (inputImage != expImage) {
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.byteCount());
QFile pngDumpFile(fileNameBase + QStringLiteral("-actual.data"));
QVERIFY2(pngDumpFile.open(QIODevice::WriteOnly), qPrintable(pngDumpFile.errorString()));
pngDumpFile.write(reinterpret_cast<const char *>(expImage.bits()),
expImage.byteCount());
QString msg = QStringLiteral("Read image (")
+ picDumpFile.fileName()
+ QStringLiteral(") differed from expected image (")
+ pngDumpFile.fileName()
+ QLatin1Char(')');
QFAIL(qPrintable(msg));
}
}
void testPreReadComment_data()
{
testRead_data();
}
void testPreReadComment()
{
QFETCH(QString, picfile);
QFETCH(QString, comment);
QImageReader inputReader(picfile, "pic");
QCOMPARE(inputReader.text(QStringLiteral("Description")), comment);
}
void testPreReadSize_data()
{
testRead_data();
}
void testPreReadSize()
{
QFETCH(QString, picfile);
QFETCH(QString, pngfile);
QImageReader inputReader(picfile, "pic");
QImageReader expReader(pngfile, "png");
QCOMPARE(inputReader.size(), expReader.size());
}
void testPreReadImageFormat_data()
{
testRead_data();
}
void testPreReadImageFormat()
{
QFETCH(QString, picfile);
QFETCH(bool, alpha);
QImageReader inputReader(picfile, "pic");
QCOMPARE(inputReader.imageFormat(),
alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
}
};
QTEST_MAIN(PicTests)
#include "pictest.moc"

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,6 +0,0 @@
P7 332
#XVVERSION:
#IMGINFO:
#END_OF_COMMENTS:
32 32 255
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۻ<EFBFBD><EFBFBD>ݾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>~<7E>{<7B><><EFBFBD>پ<EFBFBD><D9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۏW<DB8F>ܼ~>vjn<6A><6E>q]Z<17><><EFBFBD><EFBFBD>];<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۏW}<7D>ܝ?>>rf'Kʲ~z7v<37><76><EFBFBD>~?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۻ<EFBFBD><DBBB><EFBFBD>߿<EFBFBD><DFBF><EFBFBD><EFBFBD>gk<67><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߿<EFBFBD><DFBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>{[<5B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>~}~<7E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҋ<EFBFBD><D28A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>y<EFBFBD><79><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j<EFBFBD><6A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>oO<><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>oNR<4E><52><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֕<EFBFBD><D695><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>~~<7E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>qq<71><71><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>++<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۓ<EFBFBD><DB93><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -29,6 +29,49 @@
#include <QImageReader>
#include <QTextStream>
#include "../tests/format-enum.h"
static void writeImageData(const char *name, const QString &filename, const QImage &image)
{
QFile file(filename);
if (file.open(QIODevice::WriteOnly)) {
qint64 written = file.write(reinterpret_cast<const char *>(image.bits()), image.byteCount());
if (written == image.byteCount()) {
QTextStream(stdout) << " " << name
<< " written to " << filename << "\n";
} else {
QTextStream(stdout) << " could not write " << name
<< " to " << filename << ":"
<< file.errorString() << "\n";
}
} else {
QTextStream(stdout) << " could not open "
<< filename << ":"
<< file.errorString() << "\n";
}
}
// 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)
{
const int height = im1.height();
const int width = im1.width();
for (int i = 0; i < height; ++i) {
const uchar *line1 = im1.scanLine(i);
const uchar *line2 = im2.scanLine(i);
for (int j = 0; j < width; ++j) {
if (line1[j] > line2[j]) {
if (line1[j] - line2[j] > fuzziness)
return false;
} else {
if (line2[j] - line1[j] > fuzziness)
return false;
}
}
}
return true;
}
int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
@ -41,6 +84,11 @@ 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"),
QStringLiteral("Allow for some deviation in ARGB data."),
QStringLiteral("max"));
parser.addOption(fuzz);
parser.process(app);
@ -53,6 +101,17 @@ int main(int argc, char ** argv)
parser.showHelp(1);
}
uchar fuzziness = 0;
if (parser.isSet(fuzz)) {
bool ok;
uint fuzzarg = parser.value(fuzz).toUInt(&ok);
if (!ok || fuzzarg > 255) {
QTextStream(stderr) << "Error: max fuzz argument must be a number between 0 and 255\n";
parser.showHelp(1);
}
fuzziness = uchar(fuzzarg);
}
QString suffix = args.at(0);
QByteArray format = suffix.toLatin1();
@ -95,14 +154,47 @@ int main(int argc, char ** argv)
++failed;
continue;
}
inputImage = inputImage.convertToFormat(expImage.format());
if (expImage != inputImage) {
if (expImage.width() != inputImage.width()) {
QTextStream(stdout) << "FAIL : " << fi.fileName()
<< ": differs from " << expfilename << "\n";
<< ": 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 "
<< expImage.height() << "\n";
++failed;
} else {
if (inputImage.format() != QImage::Format_ARGB32) {
QTextStream(stdout) << "INFO : " << fi.fileName()
<< ": converting " << fi.fileName()
<< " from " << formatToString(inputImage.format())
<< " to ARGB32\n";
inputImage = inputImage.convertToFormat(QImage::Format_ARGB32);
}
if (expImage.format() != QImage::Format_ARGB32) {
QTextStream(stdout) << "INFO : " << fi.fileName()
<< ": converting " << expfilename
<< " from " << formatToString(expImage.format())
<< " to ARGB32\n";
expImage = expImage.convertToFormat(QImage::Format_ARGB32);
}
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);
++failed;
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,144 +0,0 @@
# Try to find the OpenEXR libraries
#
# This will define:
#
# OpenEXR_FOUND - True if OpenEXR is available
# OpenEXR_LIBRARIES - Link to these to use OpenEXR
# OpenEXR_INCLUDE_DIRS - Include directory for OpenEXR
# OpenEXR_DEFINITIONS - Compiler flags required to link against OpenEXR
# OpenEXR::IlmImf - imported target to link against (instead of using the above variables)
#
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
# Copyright (c) 2013-2014, Alex Merry, <alex.merry@kdemail.net>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if(${CMAKE_VERSION} VERSION_LESS 2.8.12)
message(FATAL_ERROR "CMake 2.8.12 is required by FindOpenEXR.cmake")
endif()
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PC_OpenEXR QUIET OpenEXR)
set(OpenEXR_DEFINITIONS ${PC_OpenEXR_CFLAGS_OTHER})
find_path(OpenEXR_INCLUDE_DIR ImfRgbaFile.h
PATHS
${PC_OpenEXR_INCLUDEDIR}
${PC_OpenEXR_INCLUDE_DIRS}
PATH_SUFFIXES OpenEXR
)
# Required libraries for OpenEXR
find_library(OpenEXR_HALF_LIBRARY NAMES Half
PATHS
${PC_OpenEXR_LIBDIR}
${PC_OpenEXR_LIBRARY_DIRS}
)
find_library(OpenEXR_IEX_LIBRARY NAMES Iex
PATHS
${PC_OpenEXR_LIBDIR}
${PC_OpenEXR_LIBRARY_DIRS}
)
find_library(OpenEXR_IMATH_LIBRARY NAMES Imath
PATHS
${PC_OpenEXR_LIBDIR}
${PC_OpenEXR_LIBRARY_DIRS}
)
find_library(OpenEXR_ILMTHREAD_LIBRARY NAMES IlmThread
PATHS
${PC_OpenEXR_LIBDIR}
${PC_OpenEXR_LIBRARY_DIRS}
)
# This is the actual OpenEXR library
find_library(OpenEXR_ILMIMF_LIBRARY NAMES IlmImf
PATHS
${PC_OpenEXR_LIBDIR}
${PC_OpenEXR_LIBRARY_DIRS}
)
set(_OpenEXR_deps
${OpenEXR_HALF_LIBRARY}
${OpenEXR_IEX_LIBRARY}
${OpenEXR_IMATH_LIBRARY}
${OpenEXR_ILMTHREAD_LIBRARY})
set(OpenEXR_LIBRARIES
${_OpenEXR_deps}
${OpenEXR_ILMIMF_LIBRARY})
if (OpenEXR_INCLUDE_DIR AND EXISTS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h")
file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" openexr_version_str
REGEX "^#define[\t ]+OPENEXR_VERSION_STRING[\t ]+\"[^\"]*\"")
string(REGEX REPLACE "^#define[\t ]+OPENEXR_VERSION_STRING[\t ]+\"([^\"]*).*"
"\\1" OpenEXR_VERSION_STRING "${openexr_version_str}")
unset(openexr_version_str)
endif ()
include(FindPackageHandleStandardArgs)
# find_package_handle_standard_args reports the value of the first variable
# on success, so make sure this is the actual OpenEXR library
find_package_handle_standard_args(OpenEXR
FOUND_VAR OpenEXR_FOUND
REQUIRED_VARS
OpenEXR_ILMIMF_LIBRARY
OpenEXR_HALF_LIBRARY
OpenEXR_IEX_LIBRARY
OpenEXR_IMATH_LIBRARY
OpenEXR_ILMTHREAD_LIBRARY
OpenEXR_INCLUDE_DIR
VERSION_VAR OpenEXR_VERSION_STRING)
set(OpenEXR_INCLUDE_DIRS ${OpenEXR_INCLUDE_DIR})
include(FeatureSummary)
set_package_properties(OpenEXR PROPERTIES
URL http://www.openexr.com/
DESCRIPTION "A library for handling OpenEXR high dynamic-range image files")
mark_as_advanced(
OpenEXR_INCLUDE_DIR
OpenEXR_LIBRARIES
OpenEXR_DEFINITIONS
OpenEXR_ILMIMF_LIBRARY
OpenEXR_ILMTHREAD_LIBRARY
OpenEXR_IMATH_LIBRARY
OpenEXR_IEX_LIBRARY
OpenEXR_HALF_LIBRARY
)
if(OpenEXR_FOUND AND NOT TARGET OpenEXR::IlmImf)
add_library(OpenEXR::IlmImf UNKNOWN IMPORTED)
set_target_properties(OpenEXR::IlmImf PROPERTIES
IMPORTED_LOCATION "${OpenEXR_ILMIMF_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${OpenEXR_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${_OpenEXR_deps}"
)
endif()

View File

@ -1 +0,0 @@
tier: 1

12
metainfo.yaml Normal file
View File

@ -0,0 +1,12 @@
maintainer: alexmerry
description: Plugins to allow QImage to support extra file formats
tier: 1
type: functional
platforms:
- name: Linux
- name: MacOSX
- name: Windows
note: No EPS support on Windows
portingAid: false
deprecated: false
release: true

View File

@ -1,4 +1,4 @@
# NB: the desktop files are installed for the benefit of KImageIO in KDE4Support.
# NB: the desktop files are installed for the benefit of KImageIO in KDELibs4Support.
##################################
@ -10,15 +10,7 @@ install(FILES dds.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
##################################
# EPS support depends on the gs utility; non-UNIX systems are unlikely to have
# this available in PATH
if (UNIX)
find_package(Qt5PrintSupport 5.2.0 NO_MODULE)
set_package_properties(Qt5PrintSupport PROPERTIES
PURPOSE "Required for the QImage plugin for EPS images"
TYPE OPTIONAL
)
if (BUILD_EPS_PLUGIN)
if (Qt5PrintSupport_FOUND)
add_library(kimg_eps MODULE eps.cpp)
target_link_libraries(kimg_eps Qt5::Gui Qt5::PrintSupport)
@ -30,14 +22,6 @@ endif()
##################################
find_package(Jasper)
set_package_properties(Jasper PROPERTIES
DESCRIPTION "A library for handling JPEG-2000 images"
PURPOSE "Required for the QImage plugin for JPEG-2000 images"
URL "http://www.ece.uvic.ca/~mdadams/jasper"
TYPE OPTIONAL
)
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(stdint.h HAVE_STDINT_H)
configure_file(config-jp2.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-jp2.h)
@ -54,12 +38,6 @@ endif()
##################################
find_package(OpenEXR)
set_package_properties(OpenEXR PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for the QImage plugin for OpenEXR images"
)
if(OpenEXR_FOUND)
add_library(kimg_exr MODULE exr.cpp)
target_link_libraries(kimg_exr Qt5::Gui OpenEXR::IlmImf)
@ -79,7 +57,7 @@ install(FILES pcx.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
##################################
add_library(kimg_pic MODULE pic_read.cpp pic_write.cpp pic.cpp)
add_library(kimg_pic MODULE pic.cpp)
target_link_libraries(kimg_pic Qt5::Gui)
install(TARGETS kimg_pic DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
@ -125,11 +103,3 @@ target_link_libraries(kimg_xcf Qt5::Gui)
install(TARGETS kimg_xcf DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES xcf.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
##################################
add_library(kimg_xview MODULE xview.cpp)
target_link_libraries(kimg_xview Qt5::Gui)
install(TARGETS kimg_xview DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES xv.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)

View File

@ -1,4 +1,4 @@
/**
/*
* QImageIO Routines to read/write EPS images.
* copyright (c) 1998 Dirk Schoenberger <dirk.schoenberger@freenet.de>
* Copyright (c) 2013 Alex Merry <alex.merry@kdemail.net>

View File

@ -1,4 +1,4 @@
/**
/*
* QImageIO Routines to read/write EPS images.
* copyright (c) 1998 Dirk Schoenberger <dirk.schoenberger@freenet.de>
*

View File

@ -1,4 +1,4 @@
{
"Keys": [ "eps", "epsi", "epsf" ],
"MimeTypes": [ "image/x-eps" ]
"MimeTypes": [ "image/x-eps", "image/x-eps", "image/x-eps" ]
}

View File

@ -1,5 +1,5 @@
/**
/*
* KImageIO Routines to read (and perhaps in the future, write) images
* in the high dynamic range EXR format.
* Copyright (c) 2003, Brad Hards <bradh@frogmouth.net>

View File

@ -1,4 +1,4 @@
/**
/*
* QImageIO Routines to read (and perhaps in the future, write) images
* in the high definition EXR format.
*

View File

@ -1,4 +1,4 @@
/**
/*
* QImageIO Routines to read/write JPEG2000 images.
* copyright (c) 2002 Michael Ritzert <michael@ritzert.de>
*

View File

@ -1,4 +1,4 @@
/**
/*
* QImageIO Routines to read/write JPEG2000 images.
* copyright (c) 2002 Michael Ritzert <michael@ritzert.de>
*

View File

@ -1,6 +1,8 @@
/**
* PIC_RW - Qt PIC Support
* Copyright (C) 2007 Ruben Lopez <r.lopez@bren.es>
/*
* Softimage PIC support for QImage
* Copyright 1998 Halfdan Ingvarsson
* Copyright 2007 Ruben Lopez <r.lopez@bren.es>
* Copyright 2014 Alex Merry <alex.merry@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,12 +20,340 @@
* ----------------------------------------------------------------------------
*/
#include "pic.h"
#include "pic_rw.h"
/* This code is based on the GIMP-PIC plugin by Halfdan Ingvarsson,
* and relicensed from GPL to LGPL to accommodate the KDE licensing policy
* with his permission.
*/
#include <QVariant>
#include "pic.h"
#include <QDataStream>
#include <QDebug>
#include <QImage>
#include <iostream>
#include <QVariant>
#include <qendian.h>
#include <algorithm>
#include <functional>
/**
* Reads a PIC file header from a data stream.
*
* @param s The data stream to read from.
* @param channels Where the read header will be stored.
* @returns @p s
*
* @relates PicHeader
*/
static QDataStream &operator>> (QDataStream &s, PicHeader &header)
{
s.setFloatingPointPrecision(QDataStream::SinglePrecision);
s >> header.magic;
s >> header.version;
// the comment should be truncated to the first null byte
char comment[81] = {};
s.readRawData(comment, 80);
header.comment = QByteArray(comment);
header.id.resize(4);
s.readRawData(header.id.data(), 4);
s >> header.width;
s >> header.height;
s >> header.ratio;
qint16 fields;
s >> fields;
header.fields = static_cast<PicFields>(fields);
qint16 pad;
s >> pad;
return s;
}
/**
* Writes a PIC file header to a data stream.
*
* @param s The data stream to write to.
* @param channels The header to write.
* @returns @p s
*
* @relates PicHeader
*/
static QDataStream &operator<< (QDataStream &s, const PicHeader &header)
{
s.setFloatingPointPrecision(QDataStream::SinglePrecision);
s << header.magic;
s << header.version;
char comment[80] = {};
strncpy(comment, header.comment.constData(), sizeof(comment));
s.writeRawData(comment, sizeof(comment));
char id[4] = {};
strncpy(id, header.id.constData(), sizeof(id));
s.writeRawData(id, sizeof(id));
s << header.width;
s << header.height;
s << header.ratio;
s << quint16(header.fields);
s << quint16(0);
return s;
}
/**
* Reads a series of channel descriptions from a data stream.
*
* If the stream contains more than 8 channel descriptions, the status of @p s
* will be set to QDataStream::ReadCorruptData (note that more than 4 channels
* - one for each component - does not really make sense anyway).
*
* @param s The data stream to read from.
* @param channels The location to place the read channel descriptions; any
* existing entries will be cleared.
* @returns @p s
*
* @relates PicChannel
*/
static QDataStream &operator>> (QDataStream &s, QList<PicChannel> &channels)
{
const unsigned maxChannels = 8;
unsigned count = 0;
quint8 chained = 1;
channels.clear();
while (chained && count < maxChannels && s.status() == QDataStream::Ok) {
PicChannel channel;
s >> chained;
s >> channel.size;
quint8 encoding;
s >> encoding;
channel.encoding = PicChannelEncoding(encoding);
s >> channel.code;
channels << channel;
++count;
}
if (chained) {
// too many channels!
s.setStatus(QDataStream::ReadCorruptData);
}
return s;
}
/**
* Writes a series of channel descriptions to a data stream.
*
* Note that the corresponding read operation will not read more than 8 channel
* descriptions, although there should be no reason to have more than 4 channels
* anyway.
*
* @param s The data stream to write to.
* @param channels The channel descriptions to write.
* @returns @p s
*
* @relates PicChannel
*/
static QDataStream &operator<< (QDataStream &s, const QList<PicChannel> &channels)
{
Q_ASSERT(channels.size() > 0);
for (int i = 0; i < channels.size() - 1; ++i) {
s << quint8(1); // chained
s << channels[i].size;
s << quint8(channels[i].encoding);
s << channels[i].code;
}
s << quint8(0); // chained
s << channels.last().size;
s << quint8(channels.last().encoding);
s << channels.last().code;
return s;
}
/**
* Decodes data written in mixed run-length encoding format.
*
* This is intended to be used with lambda functions.
*
* Note that this functions expects that, at the current location in @p stream,
* exactly @p length items have been encoded as a unit (and so it will not be
* partway through a run when it has decoded @p length items). If this is not
* the case, it will return @c false.
*
* @param stream The stream to read the data from.
* @param data The location to write the data.
* @param length The number of items to read.
* @param readItem A function that takes a QDataStream reference and reads a
* single item.
* @param updateItem A function that takes an item from @p data and an item
* read by @p readItem and produces the item that should be
* written to @p data.
*
* @returns @c true if @p length items in mixed RLE were successfully read
* into @p data, @c false otherwise.
*/
template<typename Item, typename Func1, typename Func2>
static bool decodeMixedRLEData(QDataStream &stream,
Item *data,
quint16 length,
Func1 readItem,
Func2 updateItem)
{
unsigned offset = 0; // in data
while (offset < length) {
unsigned remaining = length - offset;
quint8 count1;
stream >> count1;
if (count1 >= 128u) {
unsigned length;
if (count1 == 128u) {
// If the value is exactly 128, it means that it is more than
// 127 repetitions
quint16 count2;
stream >> count2;
length = count2;
} else {
// If last bit is 1, then it is 2 to 127 repetitions
length = count1 - 127u;
}
if (length > remaining) {
qDebug() << "Row overrun:" << length << ">" << remaining;
return false;
}
Item item = readItem(stream);
for (unsigned i = offset; i < offset + length; ++i) {
data[i] = updateItem(data[i], item);
}
offset += length;
} else {
// No repetitions
unsigned length = count1 + 1u;
if (length > remaining) {
qDebug() << "Row overrun:" << length << ">" << remaining;
return false;
}
for (unsigned i = offset; i < offset + length; ++i) {
Item item = readItem(stream);
data[i] = updateItem(data[i], item);
}
offset += length;
}
}
if (stream.status() != QDataStream::Ok) {
qDebug() << "DataStream status was" << stream.status();;;;
}
return stream.status() == QDataStream::Ok;
}
static bool readRow(QDataStream &stream, QRgb *row, quint16 width, QList<PicChannel> channels)
{
Q_FOREACH(const PicChannel &channel, channels) {
auto readPixel = [&] (QDataStream &str) -> QRgb {
quint8 red = 0;
if (channel.code & RED) {
str >> red;
}
quint8 green = 0;
if (channel.code & GREEN) {
str >> green;
}
quint8 blue = 0;
if (channel.code & BLUE) {
str >> blue;
}
quint8 alpha = 0;
if (channel.code & ALPHA) {
str >> alpha;
}
return qRgba(red, green, blue, alpha);
};
auto updatePixel = [&] (QRgb oldPixel, QRgb newPixel) -> QRgb {
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) {
if (!decodeMixedRLEData(stream, row, width, readPixel, updatePixel)) {
qDebug() << "decodeMixedRLEData failed";
return false;
}
} else if (channel.encoding == Uncompressed) {
for (quint16 i = 0; i < width; ++i) {
QRgb pixel = readPixel(stream);
row[i] = updatePixel(row[i], pixel);
}
} else {
// unknown encoding
qDebug() << "Unknown encoding";
return false;
}
}
if (stream.status() != QDataStream::Ok) {
qDebug() << "DataStream status was" << stream.status();
}
return stream.status() == QDataStream::Ok;
}
/**
* Encodes data in mixed run-length encoding format.
*
* This is intended to be used with lambda functions.
*
* @param stream The stream to write the data to.
* @param data The data to be written.
* @param length The number of items to write.
* @param itemsEqual A function that takes two items and returns whether
* @p writeItem would write them identically.
* @param writeItem A function that takes a QDataStream reference and an item
* and writes the item to the data stream.
*/
template<typename Item, typename Func1, typename Func2>
static void encodeMixedRLEData(QDataStream &stream, const Item *data, unsigned length, Func1 itemsEqual, Func2 writeItem)
{
unsigned offset = 0;
while (offset < length) {
const Item *chunkStart = data + offset;
unsigned maxChunk = qMin(length - offset, 65535u);
const Item *chunkEnd = chunkStart + 1;
quint16 chunkLength = 1;
while (chunkLength < maxChunk && itemsEqual(*chunkStart, *chunkEnd)) {
++chunkEnd;
++chunkLength;
}
if (chunkLength > 127) {
// Sequence of > 127 identical pixels
stream << quint8(128);
stream << quint16(chunkLength);
writeItem(stream, *chunkStart);
} else if (chunkLength > 1) {
// Sequence of < 128 identical pixels
stream << quint8(chunkLength + 127);
writeItem(stream, *chunkStart);
} else {
// find a string of up to 128 values, each different from the one
// that follows it
if (maxChunk > 128) {
maxChunk = 128;
}
chunkLength = 1;
chunkEnd = chunkStart + 1;
while (chunkLength < maxChunk &&
(chunkLength + 1u == maxChunk ||
!itemsEqual(*chunkEnd, *(chunkEnd+1))))
{
++chunkEnd;
++chunkLength;
}
stream << quint8(chunkLength - 1);
for (unsigned i = 0; i < chunkLength; ++i) {
writeItem(stream, *(chunkStart + i));
}
}
offset += chunkLength;
}
}
bool SoftimagePICHandler::canRead() const
{
@ -36,43 +366,211 @@ bool SoftimagePICHandler::canRead() const
bool SoftimagePICHandler::read(QImage *image)
{
pic_read(device(), image);
if (!readChannels()) {
return false;
}
QImage::Format fmt = QImage::Format_RGB32;
Q_FOREACH(const PicChannel &channel, m_channels) {
if (channel.size != 8) {
// we cannot read images that do not come in bytes
qDebug() << "Channel size was" << channel.size;
m_state = Error;
return false;
}
if (channel.code & ALPHA) {
fmt = QImage::Format_ARGB32;
}
}
QImage img(m_header.width, m_header.height, fmt);
img.fill(qRgb(0,0,0));
for (int y = 0; y < m_header.height; y++) {
QRgb *row = reinterpret_cast<QRgb*>(img.scanLine(y));
if (!readRow(m_dataStream, row, m_header.width, m_channels)) {
qDebug() << "readRow failed";
m_state = Error;
return false;
}
}
*image = img;
m_state = Ready;
return true;
}
bool SoftimagePICHandler::write(const QImage &image)
bool SoftimagePICHandler::write(const QImage &_image)
{
pic_write(device(), &image);
return true;
bool alpha = _image.hasAlphaChannel();
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();
return false;
}
if (image.width() > 65535 || image.height() > 65535) {
qDebug() << "Image too big:" << image.width() << image.height();
// there are only two bytes for each dimension
return false;
}
QDataStream stream(device());
stream << PicHeader(image.width(), image.height(), m_description);
PicChannelEncoding encoding = m_compression ? MixedRLE : Uncompressed;
QList<PicChannel> channels;
channels << PicChannel(encoding, RED | GREEN | BLUE);
if (alpha) {
channels << PicChannel(encoding, ALPHA);
}
stream << channels;
for (int r = 0; r < image.height(); r++) {
const QRgb *row = reinterpret_cast<const QRgb*>(image.scanLine(r));
/* 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);
};
auto writeRgb = [] (QDataStream &str, QRgb pixel) -> void {
str << quint8(qRed(pixel))
<< quint8(qGreen(pixel))
<< quint8(qBlue(pixel));
};
if (m_compression) {
encodeMixedRLEData(stream, row, image.width(), rgbEqual, writeRgb);
} else {
for (int i = 0; i < image.width(); ++i) {
writeRgb(stream, row[i]);
}
}
/* Write the alpha channel */
if (alpha) {
auto alphaEqual = [] (QRgb p1, QRgb p2) -> bool {
return qAlpha(p1) == qAlpha(p2);
};
auto writeAlpha = [] (QDataStream &str, QRgb pixel) -> void {
str << quint8(qAlpha(pixel));
};
if (m_compression) {
encodeMixedRLEData(stream, row, image.width(), alphaEqual, writeAlpha);
} else {
for (int i = 0; i < image.width(); ++i) {
writeAlpha(stream, row[i]);
}
}
}
}
return stream.status() == QDataStream::Ok;
}
bool SoftimagePICHandler::canRead(QIODevice *device)
{
PICHeader hdr;
if (picReadHeader(device, &hdr, true)) {
if (strncmp(hdr.id, "PICT", 4) == 0) {
return true;
}
}
char data[4];
if (device->peek(data, 4) != 4) {
return false;
}
return qFromBigEndian<qint32>(reinterpret_cast<uchar*>(data)) == PIC_MAGIC_NUMBER;
}
bool SoftimagePICHandler::readHeader()
{
if (m_state == Ready) {
m_state = Error;
m_dataStream.setDevice(device());
m_dataStream >> m_header;
if (m_header.isValid() && m_dataStream.status() == QDataStream::Ok) {
m_state = ReadHeader;
}
}
return m_state != Error;
}
bool SoftimagePICHandler::readChannels()
{
readHeader();
if (m_state == ReadHeader) {
m_state = Error;
m_dataStream >> m_channels;
if (m_dataStream.status() == QDataStream::Ok) {
m_state = ReadChannels;
}
}
return m_state != Error;
}
void SoftimagePICHandler::setOption(ImageOption option, const QVariant &value)
{
switch (option) {
case CompressionRatio:
m_compression = value.toBool();
break;
case Description: {
m_description.clear();
QStringList entries = value.toString().split(QStringLiteral("\n\n"));
Q_FOREACH(const QString entry, entries) {
if (entry.startsWith(QStringLiteral("Description: "))) {
m_description = entry.mid(13).simplified().toUtf8();
}
}
break;
}
default:
break;
}
}
QVariant SoftimagePICHandler::option(ImageOption option) const
{
if (option == Size) {
PICHeader hdr;
if (picReadHeader(device(), &hdr, true)) {
return QSize(hdr.width, hdr.height);
const_cast<SoftimagePICHandler*>(this)->readHeader();
switch (option) {
case Size:
if (const_cast<SoftimagePICHandler*>(this)->readHeader()) {
return QSize(m_header.width, m_header.height);
} else {
return QSize(-1, -1);
return QVariant();
}
case CompressionRatio:
return m_compression;
case Description:
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();
case ImageFormat:
if (const_cast<SoftimagePICHandler*>(this)->readChannels()) {
Q_FOREACH (const PicChannel &channel, m_channels) {
if (channel.code & ALPHA) {
return QImage::Format_ARGB32;
}
}
return QImage::Format_RGB32;
}
return QVariant();
default:
return QVariant();
}
}
bool SoftimagePICHandler::supportsOption(ImageOption option) const
{
return (option == Size);
return (option == CompressionRatio ||
option == Description ||
option == ImageFormat ||
option == Size);
}
QImageIOPlugin::Capabilities SoftimagePICPlugin::capabilities(QIODevice *device, const QByteArray &format) const

View File

@ -1,4 +1,4 @@
/**
/*
* PIC_RW - Qt PIC Support
* Copyright (C) 2007 Ruben Lopez <r.lopez@bren.es>
*
@ -23,17 +23,169 @@
#include <QImageIOPlugin>
/**
* The magic number at the start of a SoftImage PIC file.
*/
static const qint32 PIC_MAGIC_NUMBER = 0x5380f634;
/**
* How fields are distributed over the image.
*
* This information is not used by this image format code.
*/
enum PicFields {
NoPicture = 0, /**< No picture */
OddScanlines = 1, /**< Odd scanlines */
EvenScanlines = 2, /**< Even scanlines */
BothScanlines = 3 /**< Every scanline */
};
/**
* How the data for a channel is encoded.
*/
enum PicChannelEncoding {
Uncompressed = 0, /**< Image is uncompressed */
MixedRLE = 2 /**< Run length compression */
};
/**
* What components are encoded in a channel.
*/
enum PicChannelCode {
RED = 0x80, /**< Red channel */
GREEN = 0x40, /**< Green channel */
BLUE = 0x20, /**< Blue channel */
ALPHA = 0x10 /**< Alpha channel */
};
/**
* The header for a SoftImage PIC file.
*
* @private
*/
struct PicHeader {
/**
* Construct a valid header for a SoftImage PIC file.
*
* Note that the comment will be truncated to 80 bytes when written.
*
* @param _width The width of the image in pixels
* @param _height The height of the image in pixels
* @param _comment A comment to add to the image
*/
PicHeader(quint16 _width, quint16 _height, const QByteArray &_comment = QByteArray())
: magic(PIC_MAGIC_NUMBER)
, version(3.71f)
, comment(_comment)
, id("PICT")
, width(_width)
, height(_height)
, ratio(1.0f)
, fields(BothScanlines)
{}
/** Construct an invalid header. */
PicHeader() {}
quint32 magic; /**< Should be PIC_MAGIC_NUMBER */
float version; /**< Version of something (header? file format?) (ignored) */
QByteArray comment; /**< A free comment field (truncated to 80 bytes when
written) */
QByteArray id; /**< The file format ID (should be "PICT") */
quint16 width; /**< The width of the image in pixels */
quint16 height; /**< The height of the image in pixels */
float ratio; /**< The aspect ratio: width/height of each individual pixel
(ignored) */
PicFields fields; /**< The interlace type (ignored) */
/**
* Returns true if the @p magic and @p id fields are set correctly.
*/
bool isValid() const {
return magic == PIC_MAGIC_NUMBER
&& id == "PICT";
}
/**
* The length of the encoded data, in bytes.
*/
static const qint64 encodedLength = 104;
};
/**
* Describes a channel in a SoftImage PIC file.
*
* @private
*/
struct PicChannel {
quint8 size; /**< Bits per component per pixel. */
PicChannelEncoding encoding; /**< How the channel's data is encoded. */
quint8 code; /**< Flag field to describe which components are encoded in
this channel. */
/**
* Constructs a channel description for a SoftImage PIC file.
*
* @param _encoding How the channel's data is or will be encoded.
* @param _code What components are or will be encoded by this
* channel.
* @param _size The number of bits used to encoded a single component
* for a single pixel in this channel (should be 8).
*/
PicChannel(PicChannelEncoding _encoding, quint8 _code, quint8 _size = 8)
: size(_size)
, encoding(_encoding)
, code(_code)
{}
/**
* Constructs a default channel description for a SoftImage PIC file.
*
* This will have size set to 8, encoding set to Uncompressed and the code
* set to 0 (so that the channel does not encode any information).
*
* The result of this should not be written to a file without setting the
* encoding and channel fields correctly.
*/
PicChannel()
: size(8)
{}
};
class SoftimagePICHandler : public QImageIOHandler
{
public:
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &) Q_DECL_OVERRIDE;
virtual QVariant option(ImageOption option) const;
virtual bool supportsOption(ImageOption option) const;
QVariant option(ImageOption option) const Q_DECL_OVERRIDE;
void setOption(ImageOption option, const QVariant &value) Q_DECL_OVERRIDE;
bool supportsOption(ImageOption option) const Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
enum State {
Error,
Ready,
ReadHeader,
ReadChannels
};
SoftimagePICHandler()
: m_state(Ready)
, m_compression(true)
{}
bool readHeader();
bool readChannels();
private:
State m_state;
QDataStream m_dataStream;
PicHeader m_header;
QList<PicChannel> m_channels;
// mostly used for writing:
bool m_compression;
QByteArray m_description;
};
class SoftimagePICPlugin : public QImageIOPlugin

View File

@ -1,293 +0,0 @@
/**
* PIC_RW - Qt PIC Support
* Copyright (C) 2007 Ruben Lopez <r.lopez@bren.es>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* ----------------------------------------------------------------------------
*/
/* This code is based on the GIMP-PIC plugin by Halfdan Ingvarsson,
* and relicensed from GPL to LGPL to accommodate the KDE licensing policy
* with his permission.
* These is the original copyright:
* Copyright (C) 1998 Halfdan Ingvarsson
*/
#include "pic_rw.h"
#include <qendian.h>
#include <iostream>
#include <qimage.h>
#include <algorithm>
/**
* Reads the PIC header and checks that it is OK
* @param dev The QT device to read from
* @param hdr A pointer to the PIC header
* @param peek Keep bytes in the device
* @return true on success
*/
bool picReadHeader(QIODevice *dev, PICHeader *hdr, bool peek)
{
int result = 0;
if (peek) {
result = dev->peek((char *) hdr, HEADER_SIZE);
} else {
result = dev->read((char *) hdr, HEADER_SIZE);
}
hdr->magic = qFromBigEndian(hdr->magic);
hdr->width = qFromBigEndian(hdr->width);
hdr->height = qFromBigEndian(hdr->height);
hdr->fields = qFromBigEndian(hdr->fields);
if (hdr->magic != PIC_MAGIC_NUMBER || strncmp(hdr->id, "PICT", 4)) {
return false;
}
return result == HEADER_SIZE;
}
#define CHANNEL_BYTE(ch, mask) (( ch & mask) ? 1 : 0)
/**
* Gets the channels definition and returns the number of bytes per pixel
* @param channels The channels bitfield
* @return The number of bytes per pixel
*/
static int channels2bpp(char channels)
{
return CHANNEL_BYTE(channels, RED)
+ CHANNEL_BYTE(channels, GREEN)
+ CHANNEL_BYTE(channels, BLUE)
+ CHANNEL_BYTE(channels, ALPHA);
}
/**
* Reads the channels info
* @param dev The QT device to read from
* @param channels A pointer to 8 channels
* @return true on success
*/
static bool readChannels(QIODevice *dev, PICChannel *channels, int &bpp)
{
int c = 0;
memset(channels, 0, sizeof(PICChannel) * 8);
do {
int result = dev->read((char *) & channels[c], CHANNEL_SIZE);
if (result != CHANNEL_SIZE) {
return false;
} else {
bpp += channels2bpp(channels[c].channel);
c++;
}
} while (channels[c - 1].chained);
return true;
}
/**
* Makes a component map based on the channels info
* @param channels The channel information
* @param cmap The component map to be built
*/
inline static void makeComponentMap(unsigned channel, unsigned char *cmap)
{
std::fill(cmap, cmap + 8, 0);
unsigned compos[] = {ALPHA, BLUE, GREEN, RED};
unsigned rgba[] = {3, 2, 1, 0};
unsigned pos = 0;
for (unsigned compo = 0; compo < 4; compo++) {
if (CHANNEL_BYTE(channel, compos[compo])) {
cmap[pos++] = rgba[compo];
}
}
}
/**
* Converts a PIC pixel to 32bits RGBA
* @param src_pixel The source PIC pixel as readed from file
* @param target_pixel The target buffer where to write the pixel info
* @param cmap The component map that maps each component in PIC format to RGBA format
* @param components The number of components in the source pixel
*/
inline static void pic2RGBA(unsigned char *src_pixel, unsigned char *target_pixel, unsigned char *cmap, unsigned components)
{
for (unsigned i = 0; i < components; i++) {
target_pixel[cmap[i]] = src_pixel[i];
}
}
/**
* Counts the number of channels in the PICChannel header
* @param channels The header
* @return The number of used channels
*/
inline static unsigned getNumChannels(PICChannel *channels)
{
unsigned result = 0;
for (unsigned i = 0; i < 8; i++) {
if (channels[i].channel != 0) {
result++;
} else {
return result;
}
}
return result;
}
/**
* Decodes a Run-length encoded chunk
* @param dev The device to read from
* @param row The row pointer to write to
* @param max The maximum length to write
* @param channels The channels header
* @return The number of generated pixels
*/
static int decodeRLE(QIODevice *dev, void *row, unsigned max, unsigned bpp, unsigned channels)
{
unsigned char buf[512];
unsigned *ptr = (unsigned *) row;
unsigned char component_map[8];
unsigned len = 0;
makeComponentMap(channels, component_map);
if (dev->read((char *) buf, 1) != 1) {
return -1;
}
/* If last bit is 1, then it is 2 to 127 repetitions */
if (buf[0] > 128) {
len = buf[0] - 127;
if (len > max) {
return -1;
}
unsigned count = dev->read((char *) buf, bpp);
if (count != bpp) {
return -1;
}
for (unsigned i = 0; i < len; i++) {
pic2RGBA(buf, (unsigned char *)(ptr + i), component_map, bpp);
}
} /* If the value is exactly 10000000, it means that it is more than 127 repetitions */
else if (buf[0] == 128) {
unsigned count = dev->read((char *) buf, bpp + 2);
if (count != bpp + 2) {
return -1;
}
len = (buf[0] << 8) | buf[1];
if (len > max) {
return -1;
}
for (unsigned i = 0; i < len; i++) {
pic2RGBA(buf + 2, (unsigned char *)(ptr + i), component_map, bpp);
}
} /** No repetitions */
else {
len = buf[0] + 1;
if (len > max) {
return -1;
}
unsigned count = dev->read((char *) buf, len * bpp);
if (count != len * bpp) {
return -1;
}
for (unsigned i = 0; i < len; i++) {
pic2RGBA(buf + (i * bpp), (unsigned char *)(ptr + i), component_map, bpp);
}
}
return len;
}
/**
* Reads a row from the file
* @param dev The device to read from
* @param row The row pointer to write to
* @param width The image width
* @param bpp The bytes per pixel
* @param channels The channels header info
*/
static bool readRow(QIODevice *dev, unsigned *row, unsigned width, PICChannel *channels)
{
for (int c = 0; channels[c].channel != 0; c++) {
unsigned remain = width;
unsigned bpp = channels2bpp(channels[c].channel);
if (channels[c].type == (int) RLE) {
unsigned *rowpos = row;
while (remain > 0) {
int readed = decodeRLE(dev, rowpos, remain, bpp, channels[c].channel);
if (readed < 0) {
return false;
}
remain -= readed;
rowpos += readed;
}
} else {
unsigned char component_map[8];
unsigned count = dev->read((char *) row, width * bpp);
if (count != width * bpp) {
return false;
}
makeComponentMap(channels[c].channel, component_map);
for (unsigned i = 0; i < width; i++) {
pic2RGBA(((unsigned char *) row) + (i * bpp), (unsigned char *)(row + i), component_map, bpp);
}
}
}
return true;
}
#define FAIL() { \
std::cout << "ERROR Reading PIC!" << std::endl; \
return; \
}
bool hasAlpha(PICChannel *channels)
{
int channel = 0;
do {
if (CHANNEL_BYTE(channels[channel].channel, ALPHA)) {
return true;
}
channel++;
} while (channels[channel - 1].chained);
return false;
}
/**
* KDE image reading function. Must have this exact name in order to work
*/
void pic_read(QIODevice *dev, QImage *result)
{
PICHeader header;
PICChannel channels[8];
int bpp = 0;
if (!picReadHeader(dev, &header) || !readChannels(dev, channels, bpp)) {
FAIL();
}
QImage img(header.width, header.height, QImage::Format_ARGB32);
for (int r = 0; r < header.height; r++) {
unsigned *row = (unsigned *) img.scanLine(r);
std::fill(row, row + header.width, 0);
if (!readRow(dev, row, header.width, channels)) {
FAIL();
}
}
// img->setAlphaBuffer(hasAlpha(channels));
*result = img;
}

View File

@ -1,108 +0,0 @@
/**
* PIC_RW - Qt PIC Support
* Copyright (C) 2007 Ruben Lopez <r.lopez@bren.es>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* ----------------------------------------------------------------------------
*/
/* This code is based on the GIMP-PIC plugin by Halfdan Ingvarsson,
* and relicensed from GPL to LGPL to accommodate the KDE licensing policy
* with his permission.
* These is the original copyright:
* Copyright (C) 1998 Halfdan Ingvarsson
*/
#ifndef __PIC_RW_H__
#define __PIC_RW_H__
#define PIC_MAGIC_NUMBER 0x5380f634
#include <QtCore/QFile>
#include <QImageIOPlugin>
#include <QColor>
/**
* How fields are distributed over the image
*/
typedef enum {
NONE = 0, /* No picture */
ODD = 1, /* Odd scanlines */
EVEN = 2, /* Even scanlines */
BOTH = 3 /* Every scanline */
} PICFields;
/**
* Type of a channel
*/
typedef enum {
UNCOMPRESSED = 0, /* Image is uncompressed */
RLE = 2 /* Run length compression */
} PICChannelType;
/**
* Channel codes
*/
typedef enum {
RED = 0x80, /* Red channel */
GREEN = 0x40, /* Green channel */
BLUE = 0x20, /* Blue channel */
ALPHA = 0x10 /* Alpha channel */
} PICChannelCode;
/**
* PIC format header
*/
typedef struct {
qint32 magic; /* PIC_MAGIC_NUMBER */
float version; /* Version of format */
char comment[80]; /* Prototype description */
char id[4]; /* "PICT" */
qint16 width; /* Image width, in pixels */
qint16 height; /* Image height, in pixels */
float ratio; /* Pixel aspect ratio */
qint16 fields; /* Picture field type */
qint16 pad; /* Unused */
} PICHeader;
/**
* PIC channel header
*/
typedef struct {
char chained; /* 1 if another packet follows, else 0 */
char size; /* Bits per pixel by channel */
char type; /* RLE or uncompressed */
char channel; /* Channel code (which planes are affected by this channel) */
} PICChannel;
#define HEADER_SIZE sizeof(PICHeader)
#define CHANNEL_SIZE sizeof(PICChannel)
/**
* Reads the PIC header and checks that it is OK
* @param dev The QT device to read from
* @param hdr A pointer to the PIC header
* @param peek Keep bytes in the device
* @return true on success
*/
bool picReadHeader(QIODevice *dev, PICHeader *hdr, bool peek = false);
/// Pic read handler for Qt / KDE
void pic_read(QIODevice *dev, QImage *img);
/// Pic write handler for Qt / KDE
void pic_write(QIODevice *dev, const QImage *img);
#endif//__PIC_RW_H__

View File

@ -1,228 +0,0 @@
/**
* PIC_RW - Qt PIC Support
* Copyright (C) 2007 Ruben Lopez <r.lopez@bren.es>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* ----------------------------------------------------------------------------
*/
/* This code is based on the GIMP-PIC plugin by Halfdan Ingvarsson,
* and relicensed from GPL to LGPL to accommodate the KDE licensing policy
* with his permission.
* These is the original copyright:
* Copyright (C) 1998 Halfdan Ingvarsson
*/
#include "pic_rw.h"
#include <iostream>
#include <qimage.h>
#include <qendian.h>
/**
* Writes the PIC header info.
* @param dev IO Device
* @param msg Header message
* @param width Image width
* @param height Image height
* @param alpha Image has alpha?
* @return True on success
*/
static bool writeHeader(QIODevice *dev, std::string msg, unsigned width, unsigned height, bool alpha)
{
PICHeader h;
PICChannel c;
unsigned count = 0;
memset(&h, 0, sizeof(PICHeader));
h.magic = qToBigEndian<qint32>(PIC_MAGIC_NUMBER);
h.version = 3.71f;
strcpy(h.comment, msg.c_str());
strncpy(h.id, "PICT", 4);
h.width = qToBigEndian<qint16>(width);
h.height = qToBigEndian<qint16>(height);
h.ratio = 1.0f;
h.fields = qToBigEndian<qint16>(BOTH);
count = dev->write((const char *) & h, sizeof(PICHeader));
if (count != sizeof(PICHeader)) {
return false;
}
memset(&c, 0, sizeof(PICChannel));
c.size = 8;
c.type = RLE;
c.channel = RED | GREEN | BLUE;
if (alpha) {
c.chained = 1;
}
count = dev->write((const char *) & c, sizeof(PICChannel));
if (count != sizeof(PICChannel)) {
return false;
}
if (alpha) {
c.channel = ALPHA;
c.chained = 0;
count = dev->write((const char *) & c, sizeof(PICChannel));
if (count != sizeof(PICChannel)) {
return false;
}
}
return true;
}
inline unsigned convertABGRtoRGBA(unsigned pixel)
{
unsigned r = pixel & 0xFF;
unsigned g = (pixel >> 8) & 0xFF;
unsigned b = (pixel >> 16) & 0xFF;
unsigned a = (pixel >> 24) & 0xFF;
return a | (b << 8) | (g << 16) | (r << 24);
}
/**
* Encodes a portion of the image in RLE coding
* @param image The image that we want to encode
* @param output The output buffer
* @param channels The number of channels to write
* @param offset Offset in bytes to copy
* @param max The maximum number of pixels to write
* @param oConsumed The number of pixels consumed from image
* @param oProduced The number of bytes produced in out
* @return True on success
*/
static bool encodeRLE(const unsigned *image, unsigned char *output, bool rgb, unsigned max, unsigned &oConsumed, unsigned &oProduced)
{
const unsigned *in = image;
unsigned char *out = output;
unsigned count = 0;
unsigned channels = 3;
unsigned offset = 1;
unsigned mask = 0x00FFFFFF;
if (!rgb) {
channels = 1;
offset = 0;
mask = 0xFF000000;
}
for (; (*in & mask) == (*image & mask) && count < 65536 && count < max; in++, count++) {
}
if (count > 127) {
/* Sequence of > 127 identical pixels */
*out++ = 128;
*out++ = count >> 8;
*out++ = count & 0xFF;
unsigned pixel = convertABGRtoRGBA(*image);
memcpy(out, ((char *) & pixel) + offset, channels);
out += channels;
oConsumed = count;
oProduced = out - output;
} else if (count > 1) {
/* Sequece of < 128 identical pixels */
*out++ = (count + 127);
unsigned pixel = convertABGRtoRGBA(*image);
memcpy(out, ((char *) & pixel) + offset, channels);
out += channels;
oConsumed = count;
oProduced = out - output;
} else {
in = image + 1;
unsigned previous = *image;
count = 0;
while ((*in & mask) != (previous & mask) && count < 128 && count < max) {
previous = *in;
in++;
count++;
}
// This only happens when it is the end of the row, and it is ok
if (count == 0) {
count = 1;
}
*out++ = (count - 1);
in = image;
for (unsigned c = 0; c < count; ++c) {
unsigned pixel = convertABGRtoRGBA(*in);
memcpy(out, ((char *) & pixel) + offset, channels);
out += channels;
in++;
}
oConsumed = count;
oProduced = out - output;
}
return true;
}
/**
* Writes a row to the file
* @return True on success
*/
static bool writeRow(QIODevice *dev, unsigned *row, unsigned width, bool alpha)
{
unsigned char *buf = new unsigned char[width * 4];
unsigned posIn = 0;
unsigned posOut = 0;
memset(buf, 0, width * 4);
unsigned consumed = 0;
unsigned produced = 0;
/* Write the RGB part of the scanline */
while (posIn < width) {
if (!encodeRLE(row + posIn, buf + posOut, true, width - posIn, consumed, produced)) {
delete[] buf;
return false;
}
posIn += consumed;
posOut += produced;
}
/* Write the alpha channel */
if (alpha) {
posIn = 0;
while (posIn < width) {
if (!encodeRLE(row + posIn, buf + posOut, false, width - posIn, consumed, produced)) {
delete[] buf;
return false;
}
posIn += consumed;
posOut += produced;
}
}
dev->write((const char *) buf, posOut);
delete[] buf;
return true;
}
#define FAIL() { \
std::cout << "ERROR Writing PIC!" << std::endl; \
return; \
}
/// Pic write handler for Qt / KDE
void pic_write(QIODevice *dev, const QImage *img)
{
bool alpha = img->hasAlphaChannel();
if (!writeHeader(dev, "Created with KDE", img->width(), img->height(), alpha)) {
FAIL();
}
for (int r = 0; r < img->height(); r++) {
unsigned *row = (unsigned *) img->scanLine(r);
if (!writeRow(dev, row, img->width(), alpha)) {
FAIL();
}
}
}

View File

@ -1,4 +1,4 @@
{
"Keys": [ "rgb", "rgba", "bw", "sgi" ],
"MimeTypes": [ "image/x-rgb" ]
"MimeTypes": [ "image/x-rgb", "image/x-rgb", "image/x-rgb", "image/x-rgb" ]
}

View File

@ -1,7 +0,0 @@
[Desktop Entry]
Type=Service
X-KDE-ServiceTypes=QImageIOPlugins
X-KDE-ImageFormat=xv
X-KDE-MimeType=
X-KDE-Read=true
X-KDE-Write=true

View File

@ -1,242 +0,0 @@
/**
* QImageIO Routines to read/write XV images.
* copyright (c) 1998 Torben Weis <weis@kde.org>
* copyright (c) 1999 Oliver Eiden <o.eiden@pop.ruhr.de>
*
* This library is distributed under the conditions of the GNU LGPL.
*/
#include "xview.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <QImage>
#define BUFSIZE 1024
static const int b_255_3[] = {0, 85, 170, 255}, // index*255/3
rg_255_7[] = {0, 36, 72, 109, 145, 182, 218, 255}; // index *255/7
XVHandler::XVHandler()
{
}
bool XVHandler::canRead() const
{
if (canRead(device())) {
setFormat("xv");
return true;
}
return false;
}
bool XVHandler::read(QImage *retImage)
{
int x = -1;
int y = -1;
int maxval = -1;
QIODevice *iodev = device();
char str[ BUFSIZE ];
// magic number must be "P7 332"
iodev->readLine(str, BUFSIZE);
if (strncmp(str, "P7 332", 6)) {
return false;
}
// next line #XVVERSION
iodev->readLine(str, BUFSIZE);
if (strncmp(str, "#XVVERSION", 10)) {
return false;
}
// now it gets interesting, #BUILTIN means we are out.
// if IMGINFO comes, we are happy!
iodev->readLine(str, BUFSIZE);
if (strncmp(str, "#IMGINFO:", 9)) {
return false;
}
// after this an #END_OF_COMMENTS signals everything to be ok!
iodev->readLine(str, BUFSIZE);
if (strncmp(str, "#END_OF", 7)) {
return false;
}
// now a last line with width, height, maxval which is
// supposed to be 255
iodev->readLine(str, BUFSIZE);
sscanf(str, "%d %d %d", &x, &y, &maxval);
if (maxval != 255) {
return false;
}
int blocksize = x * y;
if (x < 0 || y < 0 || blocksize < x || blocksize < y) {
return false;
}
// now follows a binary block of x*y bytes.
char *block = (char *) malloc(blocksize);
if (!block) {
return false;
}
if (iodev->read(block, blocksize) != blocksize) {
free(block);
return false;
}
// Create the image
QImage image(x, y, QImage::Format_Indexed8);
int numColors;
numColors = qMin(maxval + 1, 0);
numColors = qMax(0, maxval + 1);
image.setColorCount(numColors);
// how do the color handling? they are absolute 24bpp
// or at least can be calculated as such.
int r, g, b;
for (int j = 0; j < 256; j++) {
r = rg_255_7[((j >> 5) & 0x07)];
g = rg_255_7[((j >> 2) & 0x07)];
b = b_255_3[((j >> 0) & 0x03)];
image.setColor(j, qRgb(r, g, b));
}
for (int py = 0; py < y; py++) {
uchar *data = image.scanLine(py);
memcpy(data, block + py * x, x);
}
*retImage = image;
free(block);
return true;
}
bool XVHandler::write(const QImage &image)
{
QIODevice &f = *(device());
// Removed "f.open(...)" and "f.close()" (tanghus)
int w = image.width(), h = image.height();
char str[ 1024 ];
// magic number must be "P7 332"
f.write("P7 332\n", 7);
// next line #XVVERSION
f.write("#XVVERSION:\n", 12);
// now it gets interesting, #BUILTIN means we are out.
// if IMGINFO comes, we are happy!
f.write("#IMGINFO:\n", 10);
// after this an #END_OF_COMMENTS signals everything to be ok!
f.write("#END_OF_COMMENTS:\n", 18);
// now a last line with width, height, maxval which is supposed to be 255
sprintf(str, "%i %i 255\n", w, h);
f.write(str, strlen(str));
QImage tmpImage(image);
if (image.depth() == 1) {
tmpImage = image.convertToFormat(QImage::Format_Indexed8, Qt::AutoColor);
}
uchar *buffer = new uchar[ w ];
for (int py = 0; py < h; py++) {
const uchar *data = tmpImage.scanLine(py);
for (int px = 0; px < w; px++) {
int r, g, b;
if (tmpImage.depth() == 32) {
const QRgb *data32 = (QRgb *) data;
r = qRed(*data32) >> 5;
g = qGreen(*data32) >> 5;
b = qBlue(*data32) >> 6;
data += sizeof(QRgb);
} else {
QRgb color = tmpImage.color(*data);
r = qRed(color) >> 5;
g = qGreen(color) >> 5;
b = qBlue(color) >> 6;
data++;
}
buffer[ px ] = (r << 5) | (g << 2) | b;
}
f.write((const char *)buffer, w);
}
delete[] buffer;
return true;
}
bool XVHandler::canRead(QIODevice *device)
{
if (!device) {
qWarning("XVHandler::canRead() called with no device");
return false;
}
qint64 oldPos = device->pos();
char head[6];
qint64 readBytes = device->read(head, sizeof(head));
if (readBytes != sizeof(head)) {
if (device->isSequential()) {
while (readBytes > 0) {
device->ungetChar(head[readBytes-- - 1]);
}
} else {
device->seek(oldPos);
}
return false;
}
if (device->isSequential()) {
while (readBytes > 0) {
device->ungetChar(head[readBytes-- - 1]);
}
} else {
device->seek(oldPos);
}
return qstrncmp(head, "P7 332", 6) == 0;
}
QImageIOPlugin::Capabilities XVPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "xv") {
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
}
if (!device->isOpen()) {
return 0;
}
Capabilities cap;
if (device->isReadable() && XVHandler::canRead(device)) {
cap |= CanRead;
}
if (device->isWritable()) {
cap |= CanWrite;
}
return cap;
}
QImageIOHandler *XVPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new XVHandler;
handler->setDevice(device);
handler->setFormat(format);
return handler;
}

View File

@ -1,42 +0,0 @@
/**
* QImageIO Routines to read/write XV images.
* copyright (c) 1998 Torben Weis <weis@kde.org>
* copyright (c) 1999 Oliver Eiden <o.eiden@pop.ruhr.de>
*
* This library is distributed under the conditions of the GNU LGPL.
*
*
* Changelog:
* 23.3.99 Oliver Eiden <o.eiden@pop.ruhr.de>
* changed the mapping from 3-3-2 decoded pixels to 8-8-8 decoded true-color pixels
* now it uses the same mapping as xv, this leads to better visual results
* Patch merged in HEAD by Chris Spiegel <matrix@xirtam.org>
*/
#ifndef KIMG_XVIEW_H
#define KIMG_XVIEW_H
#include <QImageIOPlugin>
class XVHandler : public QImageIOHandler
{
public:
XVHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
static bool canRead(QIODevice *device);
};
class XVPlugin : public QImageIOPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "xview.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
#endif // KIMG_XVIEW_H

View File

@ -1,4 +0,0 @@
{
"Keys": [ "xv" ],
"MimeTypes": [ ]
}

View File

@ -12,4 +12,5 @@ endmacro()
kimageformats_executable_tests(
imageconverter
imagedump
)

73
tests/format-enum.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright 2014 Alex Merry <alex.merry@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <QImage>
// Generated from QImage::Format enum
static const char * qimage_format_enum_names[] = {
"Invalid",
"Mono",
"MonoLSB",
"Indexed8",
"RGB32",
"ARGB32",
"ARGB32_Premultiplied",
"RGB16",
"ARGB8565_Premultiplied",
"RGB666",
"ARGB6666_Premultiplied",
"RGB555",
"ARGB8555_Premultiplied",
"RGB888",
"RGB444",
"ARGB4444_Premultiplied",
"RGBX8888",
"RGBA8888",
"RGBA8888_Premultiplied"
};
// Never claim there are more than QImage::NImageFormats supported formats.
// This is future-proofing against the above list being extended.
static const int qimage_format_enum_names_count =
(sizeof(qimage_format_enum_names) / sizeof(*qimage_format_enum_names) > int(QImage::NImageFormats))
? int(QImage::NImageFormats)
: (sizeof(qimage_format_enum_names) / sizeof(*qimage_format_enum_names));
QImage::Format formatFromString(const QString &str)
{
for (int i = 0; i < qimage_format_enum_names_count; ++i) {
if (str.compare(QLatin1String(qimage_format_enum_names[i]), Qt::CaseInsensitive) == 0) {
return (QImage::Format)(i);
}
}
return QImage::Format_Invalid;
}
QString formatToString(QImage::Format format)
{
int index = int(format);
if (index > 0 && index < qimage_format_enum_names_count) {
return QLatin1String(qimage_format_enum_names[index]);
}
return QLatin1String("<unknown:") +
QString::number(index) +
QLatin1String(">");
}

128
tests/imagedump.cpp Normal file
View File

@ -0,0 +1,128 @@
/*
* Copyright 2013 Alex Merry <alex.merry@kdemail.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDebug>
#include <QImageReader>
#include <QFile>
#include <QMetaObject>
#include <QMetaEnum>
#include <QTextStream>
#include "format-enum.h"
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR));
QCoreApplication::setApplicationName(QStringLiteral("imagedump"));
QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0.0"));
QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("Dumps the content of QImage::bits()"));
parser.addHelpOption();
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"),
QStringLiteral("Image file format"),
QStringLiteral("format"));
parser.addOption(informat);
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"),
QStringLiteral("List supported image file formats"));
parser.addOption(listformats);
QCommandLineOption listqformats(
QStringList() << QStringLiteral("p") << QStringLiteral("list-qimage-formats"),
QStringLiteral("List supported QImage data formats"));
parser.addOption(listqformats);
parser.process(app);
const QStringList files = parser.positionalArguments();
if (parser.isSet(listformats)) {
QTextStream out(stdout);
out << "File formats:\n";
foreach (const QByteArray &fmt, QImageReader::supportedImageFormats()) {
out << " " << fmt << '\n';
}
return 0;
}
if (parser.isSet(listqformats)) {
QTextStream out(stdout);
out << "QImage formats:\n";
// skip QImage::Format_Invalid
for (int i = 1; i < qimage_format_enum_names_count; ++i) {
out << " " << qimage_format_enum_names[i] << '\n';
}
return 0;
}
if (files.count() != 2) {
QTextStream(stderr) << "Must provide exactly two files\n";
parser.showHelp(1);
}
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';
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';
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';
return 4;
}
img = img.convertToFormat(qformat);
}
qint64 written = output.write(reinterpret_cast<const char *>(img.bits()), img.byteCount());
if (written != img.byteCount()) {
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";
return 0;
}