Compare commits

...

113 Commits

Author SHA1 Message Date
aeabd92eea GIT_SILENT Upgrade ECM and KF5 version requirements for 5.43.0 release. 2018-02-05 08:11:10 +00:00
64e719f329 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.42.0 release. 2018-01-05 23:41:49 +00:00
eef855b146 Remove obsolete reviewboardrc file 2018-01-05 13:24:38 +01:00
04e2ee01cb Set LIBRARY_OUTPUT_DIRECTORY so the autotests can run without the plugins installed
Do this properly by defining a function (inspired by kcoreaddons_add_plugin)
2018-01-05 11:19:18 +01:00
7f2c44add4 Use brace-initializer instead of nullptr in returning 0-QFlags
Differential Revision: https://phabricator.kde.org/D9182
2017-12-05 19:34:30 +01:00
ca67a8f342 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.41.0 release. 2017-12-02 10:14:43 +00:00
23759d0aef GIT_SILENT Upgrade ECM and KF5 version requirements for 5.40.0 release. 2017-11-04 21:43:30 +00:00
bfc02ddfe3 Add .arcconfig 2017-10-15 20:24:32 +02:00
a65b504a44 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.39.0 release. 2017-10-07 11:15:41 +00:00
78aeee7d36 GIT_SILENT Upgrade to ECM 5.38 and make tests run uninstalled 2017-08-14 15:15:23 +02:00
a2d0e43889 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.37.0 release. 2017-08-06 16:42:02 +00:00
e0bd85cbc3 GIT_SILENT Upgrade Qt5 version requirement to 5.7.0. 2017-08-06 16:02:31 +00:00
f16485a872 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.36.0 release. 2017-06-30 10:34:05 +00:00
e3afec9e75 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.35.0 release. 2017-06-03 09:02:51 +00:00
b040cf0f96 Use Q_FALLTHROUGH 2017-06-02 07:52:48 +02:00
7be2757c36 GIT_SILENT Upgrade ECM and KF5 version requirements for 5.34.0 release. 2017-05-06 08:37:02 +00:00
a8562a8471 Upgrade ECM and KF5 version requirements for 5.33.0 release. 2017-04-01 17:33:21 +00:00
252b639638 Upgrade ECM and KF5 version requirements for 5.32.0 release. 2017-03-03 12:56:29 +00:00
b0c8c40dec Upgrade ECM and KF5 version requirements for 5.31.0 release. 2017-02-04 18:20:08 +00:00
1afb7681b7 Upgrade Qt5 version requirement to 5.6.0. 2017-02-03 23:44:22 +00:00
740fe5df0e Use nullptr everywhere
Differential Revision: https://phabricator.kde.org/D3987
2017-01-16 09:44:17 +01:00
e4aa067bd2 Upgrade ECM and KF5 version requirements for 5.30.0 release. 2017-01-08 15:31:27 +00:00
9f77675d91 Require CMake 3.0, as discussed on kde-frameworks-devel 2017-01-03 13:24:41 +01:00
8a8ef69b7c Add FreeBSD to metainfo.yaml.
REVIEW: 129472
2016-12-06 19:06:09 +01:00
95e14f8f60 Upgrade ECM and KF5 version requirements for 5.29.0 release. 2016-12-03 10:23:58 +00:00
1fca298a20 Upgrade ECM and KF5 version requirements for 5.28.0 release. 2016-11-05 11:02:19 +00:00
09b1ac5a16 imageformats/kra.h - overrides for KraPlugin capabilities() and create() 2016-10-16 11:50:18 -04:00
7f852d241a Upgrade ECM and KF5 version requirements for 5.27.0 release. 2016-10-02 08:00:57 +00:00
5fdcdff6e3 Drop obsolete version check
Frameworks already require Qt 5.5.0.

REVIEW: 128989
2016-09-23 00:51:41 +02:00
60b5866b77 Upgrade ECM and KF5 version requirements for 5.26.0 release. 2016-09-05 22:36:08 +00:00
f42c1b7423 Upgrade ECM and KF5 version requirements for 5.25.0 release. 2016-08-06 08:34:21 +00:00
ede3a4a3f3 Qt 5.5.0 is now required, as discussed on kde-frameworks-devel 2016-07-24 13:20:33 +00:00
1d2aed54fa Upgrade ECM and KF5 version requirements for 5.24.0 release. 2016-07-02 08:48:36 +00:00
b019a2a57e Promote Android support 2016-06-18 00:04:19 +02:00
a4de98aa4f Silence CMake policy CMP0063 warning
...by adding the NO_POLICY_SCOPE flag as recommended by ECM's
documentation.

REVIEW: 128139
2016-06-09 17:57:09 +02:00
172c494cff remove extra ';' 2016-06-09 10:57:48 +02:00
e8da107189 Upgrade ECM and KF5 version requirements for 5.23.0 release. 2016-06-06 09:31:22 +00:00
0ae43f7d35 update metainfo.yaml for new kapidox version 2016-05-22 12:10:06 +02:00
36b67d38bb Upgrade ECM and KF5 version requirements for 5.22.0 release. 2016-05-06 19:37:55 +00:00
c1164e4eda Upgrade Qt version requirement. 2016-04-03 20:33:17 +00:00
8630653eff Upgrade ECM and KF5 version requirements for 5.21.0 release. 2016-04-02 15:30:22 +00:00
d4009490c5 Upgrade ECM and KF5 version requirements for 5.20.0 release. 2016-03-04 22:17:55 +00:00
baf894ba19 Move to tier2
6934d54417 added an optional dependency
on karchive. This also means that it doesn't merely depend on Qt and a
small number of third-party libs anymore and needs to moved to tier 2.

REVIEW: 127015
2016-02-08 21:41:20 +01:00
5168d097b5 Upgrade ECM and KF5 version requirements for 5.19.0 release. 2016-02-06 09:37:42 +00:00
6934d54417 Add kra and ora imageio plugins (read-only)
kra is the native format for Krita and ora the interchange format
for krita, gimp and mypaint (it's also mypaint's native format).
Both formats are simply zip containers with an embedded png.

REVIEW:126675
2016-01-31 15:01:32 +01:00
5d7ef7c38e fix loading of RLE compressed PSD files
decodeRLEData() expects a quint16 as length, but the PSD loader calls it
 with a quint32.
We do need quint32 for PSD, otherwise it would overflow for images
bigger than 256x256 pixels (it's the pixel count there, i.e. width x
 height).

BUG: 354413
FIXED-IN: 5.19.0
REVIEW: 126684
2016-01-10 13:24:35 +01:00
a68bfe27ff Upgrade ECM and KF5 version requirements for 5.18.0 release. 2016-01-01 19:58:09 +00:00
9304510ee3 Upgrade ECM and KF5 version requirements for 5.17.0 release. 2015-12-06 14:06:19 +00:00
cc219211bb Upgrade ECM and KF5 version requirements for 5.16.0 release. 2015-11-08 11:08:43 +00:00
f2adcb81d1 Recognize image/vnd.adobe.photoshop instead of image/x-psd
REVIEW: 125790
2015-11-07 13:27:42 +01:00
814c7a2b30 Partially revert d7f457a to prevent crash on application exit
The change to QLatin1String to QStringLiteral had a very nasty
unintended side effect, causing many (but not all) applications to
crash on exit.

Laurent, please be wary with blanket changes on low level code as
they might break things in unexpected ways.

CCMAIL: montel@kde.org
CCMAIL: tittiatcoke@gmail.com
2015-11-04 23:51:53 +01:00
d7f457a124 Use QStringLiteral 2015-11-02 21:57:43 +01:00
69c4a4b84a Upgrade ECM and KF5 version requirements for 5.15.0 release. 2015-10-03 10:22:35 +00:00
e3473a53cf Upgrade ECM and KF5 version requirements for 5.14.0 release. 2015-09-04 20:13:45 +00:00
4a54da668a eps: fix includes related to Qt Caterogized Logging
Testing Done:
Build on OS X 10.8

Reviewed at https://git.reviewboard.kde.org/r/125025/
2015-09-03 18:15:54 +02:00
e5fce91de6 Remove DDS and JPEG-2000 plugins
They were already disabled when building with Qt >= 5.3 in commit
3d45b270ea because Qt has better plugins
for those image formats. Now that we depend on Qt 5.3 we can remove
them.

REVIEW: 124636
2015-08-06 00:57:14 +02:00
c7a04b0ed6 less verbose categorized logging, move to ecm module later 2015-08-02 13:01:54 +02:00
feddd046d7 Upgrade Qt version requirement to 5.3 2015-08-01 14:41:18 +02:00
5800e2f011 Upgrade ECM and KF5 version requirements for 5.13.0 release. 2015-08-01 12:14:00 +00:00
df707db404 Upgrade ECM and KF5 version requirements for 5.12.0 release. 2015-07-04 20:36:35 +00:00
e1bcc3b033 Upgrade ECM and KF5 version requirements for 5.11.0 release. 2015-06-06 09:28:19 +00:00
8c8db0fcd2 Add verbose message for when ECM is not found. 2015-05-13 20:41:18 -06:00
52c7839741 Initialize variable to silence warning [-Wsometimes-uninitialized]
It's uninitialized if the else {} is hit.
2015-05-02 23:32:24 +01:00
3dadfa564d Upgrade ECM and KF5 version requirements for 5.10.0 release. 2015-05-01 15:17:27 +00:00
0414b32297 Upgrade ECM and KF5 version requirements for 5.9.0 release. 2015-04-04 11:48:54 +00:00
55af097749 Don't warn the user/developer about something he can't fix
image formats are loaded via qimage/qimagereader and friends, the user/developer does not choose which ones will be used so giving him a warning about sequential devices not being supported is not going to help anyone, only spam their shell/logs.

REVIEW: 123156
Acked by David Edmundson
2015-03-29 23:21:17 +02:00
b7910e169e Fix build with Qt 5.5 (missing QDataStream include) 2015-02-27 19:03:29 +01:00
c27ba814fd Upgrade ECM and KF5 version requirements for 5.8.0 release. 2015-02-25 14:20:14 +00:00
873746d04b Build fix for OS/X.
CCMAIL: mk-lists@email.de
2015-02-21 11:41:58 +00:00
47e8043d45 Make PSD image reader endianess-agnostic.
By using the same strategy as the SoftImage PIC handler (and sharing
some code with it), we should avoid reading the image data incorrectly
on big-endian architectures.

REVIEW: 122650
BUG: 337918
2015-02-20 23:03:10 +00:00
ac2b63046f Use Q_DECL_OVERRIDE where possible
REVIEW: 122542
2015-02-13 13:31:27 +01:00
6b72930cb2 Upgrade ECM and KF5 version requirements for 5.7.0 release. 2015-01-23 20:40:27 +00:00
4cdcf3a98c Add missing QDataStream include
Fixes build with Qt 5.5
2015-01-17 03:40:59 +01:00
88518c5862 Update installation variables. 2015-01-10 17:46:30 +00:00
b870e9cd47 Upgrade ECM and KF5 version requirements for 5.6.0 release. 2014-12-31 14:23:36 +00:00
c21fc5982b Upgrade ECM and KF5 version requirements for 5.5.0 release. 2014-12-02 16:47:14 +00:00
8ffd5bb2f7 Upgrade ECM and KF5 version requirements for 5.4.0 release. 2014-10-31 20:17:43 +00:00
5ae66b99d9 Upgrade ECM and KF5 version requirements for 5.3.0 release. 2014-10-03 17:55:41 +00:00
f4bea644eb Upgrade ECM and KF5 version requirements for 5.2.0 release. 2014-09-07 23:25:44 +00:00
415850f3d3 Switch the brief descriptions around
Put the shorter description in metainfo.yaml, and the longer one in
README.md.
2014-08-15 18:41:16 +01:00
af19f49711 Add metadata about the QMake and CMake packages installed by this framework and remove Links from README.md 2014-08-13 10:04:37 +02:00
3d45b270ea Disable the DDS and JPEG-2000 plugins when Qt version is 5.3 or later
QtImageFormats 5.3 comes with DDS and JPEG-2000 plugins that support
more options and are generally better than our plugins. The only
advantage our plugins offer is that the Qt DDS plugin does not work on
sequential devices, while ours does. This is outweighed by other
improvements, though, such as supporting more variants.

REVIEW: 119590
2014-08-04 22:50:37 +01:00
c9ca1f1862 Rename headers to end with _p.h
Frameworks have a convention of naming uninstalled headers in src/ with
a _p at the end of the name, to make it clear they are not part of the
API. None of the headers in KImageFormats are installed, so it is not
really necessary to follow this convention, but we follow it anyway for
the benefit of both humans and tools (like kapidox).
2014-08-03 18:08:49 +01:00
a96a255f71 Upgrade ECM and KF5 version requirements for 5.1.0 release. 2014-08-02 08:19:18 +00:00
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
102 changed files with 2065 additions and 3161 deletions

3
.arcconfig Normal file
View File

@ -0,0 +1,3 @@
{
"phabricator.uri" : "https://phabricator.kde.org/"
}

View File

@ -1,5 +0,0 @@
REVIEWBOARD_URL = "https://git.reviewboard.kde.org"
REPOSITORY = 'git://anongit.kde.org/kimageformats'
BRANCH = 'master'
TARGET_GROUPS = 'kdeframeworks'
TARGET_PEOPLE = 'alexmerry'

View File

@ -1,23 +1,55 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.0)
project(KImageFormats)
find_package(ECM 0.0.10 REQUIRED NO_MODULE)
include(FeatureSummary)
find_package(ECM 5.43.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules")
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
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)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings)
include(FeatureSummary)
include(CheckIncludeFiles)
set(REQUIRED_QT_VERSION 5.2.0)
set(REQUIRED_QT_VERSION 5.7.0)
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
find_package(KF5Archive)
set_package_properties(KF5Archive PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for the QImage plugin for Krita and OpenRaster images"
)
# 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 ${REQUIRED_QT_VERSION} 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(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,6 +1,6 @@
# KImageFormats
Image format plugins for Qt
Plugins to allow QImage to support extra file formats.
## Introduction
@ -13,7 +13,6 @@ image formats.
The following image formats have read-only support:
- DirectDraw Surface (dds)
- Gimp (xcf)
- OpenEXR (exr)
- Photoshop documents (psd)
@ -22,7 +21,6 @@ The following image formats have read-only support:
The following image formats have read and write support:
- Encapsulated PostScript (eps)
- JPEG-2000 (jp2)
- Personal Computer Exchange (pcx)
- SGI images (rgb, rgba, sgi, bw)
- Softimage PIC (pic)
@ -63,9 +61,3 @@ This framework is licensed under the
The CMake code in this framework is licensed under the
[BSD license](http://opensource.org/licenses/BSD-3-Clause).
## Links
- Home page: <https://projects.kde.org/projects/frameworks/kimageformats>
- Mailing list: <https://mail.kde.org/mailman/listinfo/kde-frameworks-devel>
- IRC channel: \#kde-devel on Freenode
- Git repository: <https://projects.kde.org/projects/frameworks/kimageformats/repository>

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)
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})
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)
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)
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)
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,24 @@ 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
)
if (KF5Archive_FOUND)
kimageformats_read_tests(
kra
ora
)
endif()
# 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 +82,30 @@ 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 (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: 663 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

BIN
autotests/read/kra/src.kra Normal file

Binary file not shown.

BIN
autotests/read/kra/src.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
autotests/read/ora/src.ora Normal file

Binary file not shown.

BIN
autotests/read/ora/src.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

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();
@ -70,7 +129,7 @@ int main(int argc, char ** argv)
foreach (QFileInfo fi, imgdir.entryInfoList()) {
int suffixPos = fi.filePath().count() - suffix.count();
QString inputfile = fi.filePath();
QString expfile = fi.filePath().replace(suffixPos, suffix.count(), "png");
QString expfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
QString expfilename = QFileInfo(expfile).fileName();
QImageReader inputReader(inputfile, format.constData());
@ -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 {
QTextStream(stdout) << "PASS : " << fi.fileName() << "\n";
++passed;
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.

Binary file not shown.

Binary file not shown.

View File

@ -75,7 +75,7 @@ int main(int argc, char ** argv)
foreach (QFileInfo fi, imgdir.entryInfoList()) {
int suffixPos = fi.filePath().count() - suffix.count();
QString pngfile = fi.filePath().replace(suffixPos, suffix.count(), "png");
QString pngfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png"));
QString pngfilename = QFileInfo(pngfile).fileName();
QImageReader pngReader(pngfile, "png");

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

18
metainfo.yaml Normal file
View File

@ -0,0 +1,18 @@
maintainer: alexmerry
description: Image format plugins for Qt
tier: 2
type: functional
platforms:
- name: Linux
- name: FreeBSD
- name: MacOSX
- name: Windows
note: No EPS support on Windows
- name: Android
portingAid: false
deprecated: false
release: true
public_lib: true
group: Frameworks
subgroup: Tier 2

View File

@ -1,135 +1,102 @@
# 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.
##################################
add_library(kimg_dds MODULE dds.cpp)
target_link_libraries(kimg_dds Qt5::Gui)
function(kimageformats_add_plugin plugin)
set(options)
set(oneValueArgs JSON)
set(multiValueArgs SOURCES)
cmake_parse_arguments(KIF_ADD_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT KIF_ADD_PLUGIN_SOURCES)
message(FATAL_ERROR "kimageformats_add_plugin called without SOURCES parameter")
endif()
get_filename_component(json "${KIF_ADD_PLUGIN_JSON}" REALPATH)
if(NOT KIF_ADD_PLUGIN_JSON OR NOT EXISTS ${json})
message(FATAL_ERROR "JSON file doesn't exist: ${json}")
endif()
install(TARGETS kimg_dds DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES dds.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
set_property(SOURCE ${KIF_ADD_PLUGIN_SOURCES} APPEND PROPERTY OBJECT_DEPENDS ${json})
add_library(${plugin} MODULE ${KIF_ADD_PLUGIN_SOURCES})
set_property(TARGET ${plugin} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS ${json})
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats")
target_link_libraries(${plugin} Qt5::Gui)
install(TARGETS ${plugin} DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/imageformats)
endfunction()
##################################
# 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
)
install(FILES dds-qt.desktop RENAME dds.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
if (BUILD_EPS_PLUGIN)
if (Qt5PrintSupport_FOUND)
add_library(kimg_eps MODULE eps.cpp)
target_link_libraries(kimg_eps Qt5::Gui Qt5::PrintSupport)
install(TARGETS kimg_eps DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES eps.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_eps JSON "eps.json" SOURCES eps.cpp)
target_link_libraries(kimg_eps Qt5::PrintSupport)
install(FILES eps.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
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
)
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)
if(JASPER_FOUND)
add_library(kimg_jp2 MODULE jp2.cpp)
target_compile_options(kimg_jp2 PRIVATE ${JASPER_DEFINITIONS})
target_include_directories(kimg_jp2 PRIVATE ${JASPER_INCLUDE_DIR})
target_link_libraries(kimg_jp2 Qt5::Gui ${JASPER_LIBRARIES})
install(TARGETS kimg_jp2 DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES jp2.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
endif()
# need this for Qt's version of the plugin
install(FILES jp2.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
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)
kimageformats_add_plugin(kimg_exr JSON "exr.json" SOURCES exr.cpp)
target_link_libraries(kimg_exr OpenEXR::IlmImf)
kde_target_enable_exceptions(kimg_exr PRIVATE)
install(TARGETS kimg_exr DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES exr.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
install(FILES exr.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
endif()
##################################
add_library(kimg_pcx MODULE pcx.cpp)
target_link_libraries(kimg_pcx Qt5::Gui)
install(TARGETS kimg_pcx DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES pcx.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_pcx JSON "pcx.json" SOURCES pcx.cpp)
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_pic MODULE pic_read.cpp pic_write.cpp pic.cpp)
target_link_libraries(kimg_pic Qt5::Gui)
install(TARGETS kimg_pic DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES pic.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_pic JSON "pic.json" SOURCES pic.cpp)
install(FILES pic.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_psd MODULE psd.cpp)
target_link_libraries(kimg_psd Qt5::Gui)
install(TARGETS kimg_psd DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES psd.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_psd JSON "psd.json" SOURCES psd.cpp)
install(FILES psd.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_ras MODULE ras.cpp)
target_link_libraries(kimg_ras Qt5::Gui)
install(TARGETS kimg_ras DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES ras.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_ras JSON "ras.json" SOURCES ras.cpp)
install(FILES ras.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_rgb MODULE rgb.cpp)
target_link_libraries(kimg_rgb Qt5::Gui)
install(TARGETS kimg_rgb DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES rgb.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_rgb JSON "rgb.json" SOURCES rgb.cpp)
install(FILES rgb.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_tga MODULE tga.cpp)
target_link_libraries(kimg_tga Qt5::Gui)
install(TARGETS kimg_tga DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES tga.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_tga JSON "tga.json" SOURCES tga.cpp)
install(FILES tga.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_xcf MODULE xcf.cpp)
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/)
kimageformats_add_plugin(kimg_xcf JSON "xcf.json" SOURCES xcf.cpp)
install(FILES xcf.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
##################################
add_library(kimg_xview MODULE xview.cpp)
target_link_libraries(kimg_xview Qt5::Gui)
if (KF5Archive_FOUND)
install(TARGETS kimg_xview DESTINATION ${QT_PLUGIN_INSTALL_DIR}/imageformats/)
install(FILES xv.desktop DESTINATION ${SERVICES_INSTALL_DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_kra JSON "kra.json" SOURCES kra.cpp)
target_link_libraries(kimg_kra KF5::Archive)
install(FILES kra.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
kimageformats_add_plugin(kimg_ora JSON "ora.json" SOURCES ora.cpp)
target_link_libraries(kimg_ora KF5::Archive)
install(FILES ora.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
endif()

View File

@ -1,2 +0,0 @@
#cmakedefine01 HAVE_STDINT_H
#cmakedefine01 HAVE_SYS_TYPES_H

View File

@ -4,4 +4,4 @@ X-KDE-ServiceTypes=QImageIOPlugins
X-KDE-ImageFormat=dds
X-KDE-MimeType=image/x-dds
X-KDE-Read=true
X-KDE-Write=false
X-KDE-Write=true

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +0,0 @@
/* This file is part of the KDE project
Copyright (C) 2003 Ignacio Castaño <castano@ludicon.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef KIMG_DDS_H
#define KIMG_DDS_H
#include <QImageIOPlugin>
class DDSHandler : public QImageIOHandler
{
public:
DDSHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
static bool canRead(QIODevice *device);
};
class DDSPlugin : public QImageIOPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "dds.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
#endif // KIMG_DDS_H

View File

@ -1,4 +0,0 @@
{
"Keys": [ "dds" ],
"MimeTypes": [ "image/x-dds" ]
}

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>
@ -6,18 +6,18 @@
*
* This library is distributed under the conditions of the GNU LGPL.
*/
#include "eps.h"
#include "eps_p.h"
#include <QDebug>
#include <QImage>
#include <QImageReader>
#include <QLoggingCategory>
#include <QPainter>
#include <QPrinter>
#include <QProcess>
#include <QTemporaryFile>
Q_LOGGING_CATEGORY(EPSPLUGIN, "epsplugin")
// logging category for this framework, default: log stuff >= warning
Q_LOGGING_CATEGORY(EPSPLUGIN, "epsplugin", QtWarningMsg)
//#define EPS_PERFORMANCE_DEBUG 1
#define BBOX_BUFLEN 200
@ -337,10 +337,10 @@ QImageIOPlugin::Capabilities EPSPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

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,4 +1,4 @@
/**
/*
* QImageIO Routines to read/write EPS images.
* copyright (c) 1998 Dirk Schoenberger <dirk.schoenberger@freenet.de>
*
@ -8,15 +8,16 @@
#define KIMG_EPS_H
#include <QImageIOPlugin>
#include <QLoggingCategory>
class EPSHandler : public QImageIOHandler
{
public:
EPSHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -27,9 +28,11 @@ class EPSPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "eps.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
Q_DECLARE_LOGGING_CATEGORY(EPSPLUGIN)
#endif // KIMG_EPS_H

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>
@ -7,7 +7,7 @@
* This library is distributed under the conditions of the GNU LGPL.
*/
#include "exr.h"
#include "exr_p.h"
#include <ImfRgbaFile.h>
#include <ImfStandardAttributes.h>
@ -41,10 +41,10 @@ public:
{
}
virtual bool read(char c[], int n);
virtual Imf::Int64 tellg();
virtual void seekg(Imf::Int64 pos);
virtual void clear();
bool read(char c[], int n) Q_DECL_OVERRIDE;
Imf::Int64 tellg() Q_DECL_OVERRIDE;
void seekg(Imf::Int64 pos) Q_DECL_OVERRIDE;
void clear() Q_DECL_OVERRIDE;
private:
QIODevice *m_dev;
@ -218,10 +218,10 @@ QImageIOPlugin::Capabilities EXRPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -1,4 +1,4 @@
/**
/*
* QImageIO Routines to read (and perhaps in the future, write) images
* in the high definition EXR format.
*
@ -18,8 +18,8 @@ class EXRHandler : public QImageIOHandler
public:
EXRHandler();
virtual bool canRead() const;
virtual bool read(QImage *outImage);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *outImage) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -30,8 +30,8 @@ class EXRPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "exr.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_EXR_H

View File

@ -8,7 +8,7 @@
version 2 of the License, or (at your option) any later version.
*/
#include "hdr.h"
#include "hdr_p.h"
#include <QImage>
#include <QtCore/QDataStream>

View File

@ -1,526 +0,0 @@
/**
* QImageIO Routines to read/write JPEG2000 images.
* copyright (c) 2002 Michael Ritzert <michael@ritzert.de>
*
* This library is distributed under the conditions of the GNU LGPL.
*/
#include "jp2.h"
#include <config-jp2.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#include <QImage>
#include <QVariant>
#include <QTextStream>
// dirty, but avoids a warning because jasper.h includes jas_config.h.
#undef PACKAGE
#undef VERSION
#include <jasper/jasper.h>
// code taken in parts from JasPer's jiv.c
#define DEFAULT_RATE 0.10
#define MAXCMPTS 256
/************************* JasPer QIODevice stream ***********************/
//unfortunately this is declared as static in JasPer libraries
static jas_stream_t *jas_stream_create()
{
jas_stream_t *stream;
if (!(stream = (jas_stream_t *)jas_malloc(sizeof(jas_stream_t)))) {
return 0;
}
stream->openmode_ = 0;
stream->bufmode_ = 0;
stream->flags_ = 0;
stream->bufbase_ = 0;
stream->bufstart_ = 0;
stream->bufsize_ = 0;
stream->ptr_ = 0;
stream->cnt_ = 0;
stream->ops_ = 0;
stream->obj_ = 0;
stream->rwcnt_ = 0;
stream->rwlimit_ = -1;
return stream;
}
//unfortunately this is declared as static in JasPer libraries
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
int bufsize)
{
/* If this function is being called, the buffer should not have been
initialized yet. */
assert(!stream->bufbase_);
if (bufmode != JAS_STREAM_UNBUF) {
/* The full- or line-buffered mode is being employed. */
if (!buf) {
/* The caller has not specified a buffer to employ, so allocate
one. */
if ((stream->bufbase_ = (unsigned char *)jas_malloc(JAS_STREAM_BUFSIZE +
JAS_STREAM_MAXPUTBACK))) {
stream->bufmode_ |= JAS_STREAM_FREEBUF;
stream->bufsize_ = JAS_STREAM_BUFSIZE;
} else {
/* The buffer allocation has failed. Resort to unbuffered
operation. */
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
}
} else {
/* The caller has specified a buffer to employ. */
/* The buffer must be large enough to accommodate maximum
putback. */
assert(bufsize > JAS_STREAM_MAXPUTBACK);
stream->bufbase_ = JAS_CAST(uchar *, buf);
stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
}
} else {
/* The unbuffered mode is being employed. */
/* A buffer should not have been supplied by the caller. */
assert(!buf);
/* Use a trivial one-character buffer. */
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
}
stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
stream->ptr_ = stream->bufstart_;
stream->cnt_ = 0;
stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
}
static int qiodevice_read(jas_stream_obj_t *obj, char *buf, int cnt)
{
QIODevice *io = (QIODevice *) obj;
return io->read(buf, cnt);
}
static int qiodevice_write(jas_stream_obj_t *obj, char *buf, int cnt)
{
QIODevice *io = (QIODevice *) obj;
return io->write(buf, cnt);
}
static long qiodevice_seek(jas_stream_obj_t *obj, long offset, int origin)
{
QIODevice *io = (QIODevice *) obj;
long newpos;
switch (origin) {
case SEEK_SET:
newpos = offset;
break;
case SEEK_END:
newpos = io->size() - offset;
break;
case SEEK_CUR:
newpos = io->pos() + offset;
break;
default:
return -1;
}
if (newpos < 0) {
return -1;
}
if (io->seek(newpos)) {
return newpos;
} else {
return -1;
}
}
static int qiodevice_close(jas_stream_obj_t *)
{
return 0;
}
static jas_stream_ops_t jas_stream_qiodeviceops = {
qiodevice_read,
qiodevice_write,
qiodevice_seek,
qiodevice_close
};
static jas_stream_t *jas_stream_qiodevice(QIODevice *iodevice)
{
jas_stream_t *stream;
if (!iodevice) {
return 0;
}
if (!(stream = jas_stream_create())) {
return 0;
}
/* A stream associated with a memory buffer is always opened
for both reading and writing in binary mode. */
stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
/* Select the operations for a memory stream. */
stream->obj_ = (void *)iodevice;
stream->ops_ = &jas_stream_qiodeviceops;
return stream;
}
/************************ End of JasPer QIODevice stream ****************/
typedef struct {
jas_image_t *image;
int cmptlut[MAXCMPTS];
jas_image_t *altimage;
} gs_t;
static jas_image_t *
read_image(QIODevice *io)
{
jas_stream_t *in = 0;
in = jas_stream_qiodevice(io);
if (!in) {
return 0;
}
jas_image_t *image = jas_image_decode(in, -1, 0);
jas_stream_close(in);
// image may be 0, but that's Ok
return image;
} // read_image
static bool
convert_colorspace(gs_t &gs)
{
jas_cmprof_t *outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB);
if (!outprof) {
return false;
}
gs.altimage = jas_image_chclrspc(gs.image, outprof,
JAS_CMXFORM_INTENT_PER);
if (!gs.altimage) {
return false;
}
return true;
} // convert_colorspace
static bool
render_view(gs_t &gs, QImage *outImage)
{
if (!gs.altimage) {
return false;
}
QImage qti;
if ((gs.cmptlut[0] = jas_image_getcmptbytype(gs.altimage,
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
(gs.cmptlut[1] = jas_image_getcmptbytype(gs.altimage,
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
(gs.cmptlut[2] = jas_image_getcmptbytype(gs.altimage,
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
return false;
} // if
const int *cmptlut = gs.cmptlut;
int v[3];
// check that all components have the same size.
const int width = jas_image_cmptwidth(gs.altimage, cmptlut[0]);
const int height = jas_image_cmptheight(gs.altimage, cmptlut[0]);
for (int i = 1; i < 3; ++i) {
if (jas_image_cmptwidth(gs.altimage, cmptlut[i]) != width ||
jas_image_cmptheight(gs.altimage, cmptlut[i]) != height) {
return false;
}
} // for
jas_matrix_t *cmptmatrix[3];
jas_seqent_t *buf[3];
int prec[3];
for (int k = 0; k < 3; ++k) {
prec[k] = jas_image_cmptprec(gs.altimage, cmptlut[k]);
if (!(cmptmatrix[k] = jas_matrix_create(1, width))) {
return false;
}
}
qti = QImage(jas_image_width(gs.altimage), jas_image_height(gs.altimage),
QImage::Format_RGB32);
if (qti.isNull()) {
return false;
}
uint32_t *data = (uint32_t *)qti.bits();
for (int y = 0; y < height; ++y) {
for (int k = 0; k < 3; ++k) {
if (jas_image_readcmpt(gs.altimage, cmptlut[k], 0, y, width, 1, cmptmatrix[k])) {
return false;
}
buf[k] = jas_matrix_getref(cmptmatrix[k], 0, 0);
}
for (int x = 0; x < width; ++x) {
for (int k = 0; k < 3; ++k) {
v[k] = *buf[k];
// if the precision of the component is too small, increase
// it to use the complete value range.
v[k] <<= 8 - prec[k];
if (v[k] < 0) {
v[k] = 0;
} else if (v[k] > 255) {
v[k] = 255;
}
++buf[k];
} // for k
*data++ = qRgb(v[0], v[1], v[2]);
} // for x
} // for y
for (int k = 0; k < 3; ++k) {
if (cmptmatrix[k]) {
jas_matrix_destroy(cmptmatrix[k]);
}
}
*outImage = qti;
return true;
} // render_view
static jas_image_t *
create_image(const QImage &qi)
{
// prepare the component parameters
jas_image_cmptparm_t *cmptparms = new jas_image_cmptparm_t[ 3 ];
for (int i = 0; i < 3; ++i) {
// x and y offset
cmptparms[i].tlx = 0;
cmptparms[i].tly = 0;
// the resulting image will be hstep*width x vstep*height !
cmptparms[i].hstep = 1;
cmptparms[i].vstep = 1;
cmptparms[i].width = qi.width();
cmptparms[i].height = qi.height();
// we write everything as 24bit truecolor ATM
cmptparms[i].prec = 8;
cmptparms[i].sgnd = false;
}
jas_image_t *ji = jas_image_create(3 /* number components */, cmptparms, JAS_CLRSPC_UNKNOWN);
delete[] cmptparms;
// returning 0 is ok
return ji;
} // create_image
static bool
write_components(jas_image_t *ji, const QImage &qi)
{
const unsigned height = qi.height();
const unsigned width = qi.width();
jas_matrix_t *m = jas_matrix_create(height, width);
if (!m) {
return false;
}
jas_image_setclrspc(ji, JAS_CLRSPC_SRGB);
jas_image_setcmpttype(ji, 0, JAS_IMAGE_CT_RGB_R);
for (uint y = 0; y < height; ++y)
for (uint x = 0; x < width; ++x) {
jas_matrix_set(m, y, x, qRed(qi.pixel(x, y)));
}
jas_image_writecmpt(ji, 0, 0, 0, width, height, m);
jas_image_setcmpttype(ji, 1, JAS_IMAGE_CT_RGB_G);
for (uint y = 0; y < height; ++y)
for (uint x = 0; x < width; ++x) {
jas_matrix_set(m, y, x, qGreen(qi.pixel(x, y)));
}
jas_image_writecmpt(ji, 1, 0, 0, width, height, m);
jas_image_setcmpttype(ji, 2, JAS_IMAGE_CT_RGB_B);
for (uint y = 0; y < height; ++y)
for (uint x = 0; x < width; ++x) {
jas_matrix_set(m, y, x, qBlue(qi.pixel(x, y)));
}
jas_image_writecmpt(ji, 2, 0, 0, width, height, m);
jas_matrix_destroy(m);
return true;
} // write_components
static bool
write_image(const QImage &image, QIODevice *io, int quality)
{
jas_stream_t *stream = 0;
stream = jas_stream_qiodevice(io);
// by here, a jas_stream_t is open
if (!stream) {
return false;
}
jas_image_t *ji = create_image(image);
if (!ji) {
jas_stream_close(stream);
return false;
} // if
if (!write_components(ji, image)) {
jas_stream_close(stream);
jas_image_destroy(ji);
return false;
} // if
// optstr:
// - rate=#B => the resulting file size is about # bytes
// - rate=0.0 .. 1.0 => the resulting file size is about the factor times
// the uncompressed size
// use sprintf for locale-aware string
char rateBuffer[16];
sprintf(rateBuffer, "rate=%.2g\n", (quality < 0) ? DEFAULT_RATE : quality / 100.0);
int i = jp2_encode(ji, stream, rateBuffer);
jas_image_destroy(ji);
jas_stream_close(stream);
if (i != 0) {
return false;
}
return true;
}
JP2Handler::JP2Handler()
{
quality = 75;
jas_init();
}
JP2Handler::~JP2Handler()
{
jas_cleanup();
}
bool JP2Handler::canRead() const
{
if (canRead(device())) {
setFormat("jp2");
return true;
}
return false;
}
bool JP2Handler::canRead(QIODevice *device)
{
if (!device) {
return false;
}
return device->peek(6) == QByteArray("\x00\x00\x00\x0C\x6A\x50", 6);
}
bool JP2Handler::read(QImage *image)
{
if (!canRead()) {
return false;
}
gs_t gs;
if (!(gs.image = read_image(device()))) {
return false;
}
if (!convert_colorspace(gs)) {
return false;
}
render_view(gs, image);
if (gs.image) {
jas_image_destroy(gs.image);
}
if (gs.altimage) {
jas_image_destroy(gs.altimage);
}
return true;
}
bool JP2Handler::write(const QImage &image)
{
return write_image(image, device(), quality);
}
bool JP2Handler::supportsOption(ImageOption option) const
{
return option == Quality;
}
QVariant JP2Handler::option(ImageOption option) const
{
if (option == Quality) {
return quality;
}
return QVariant();
}
void JP2Handler::setOption(ImageOption option, const QVariant &value)
{
if (option == Quality) {
quality = qBound(-1, value.toInt(), 100);
}
}
QImageIOPlugin::Capabilities JP2Plugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "jp2") {
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
}
if (!device->isOpen()) {
return 0;
}
Capabilities cap;
if (device->isReadable() && JP2Handler::canRead(device)) {
cap |= CanRead;
}
if (device->isWritable()) {
cap |= CanWrite;
}
return cap;
}
QImageIOHandler *JP2Plugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new JP2Handler;
handler->setDevice(device);
handler->setFormat(format);
return handler;
}

View File

@ -1,42 +0,0 @@
/**
* QImageIO Routines to read/write JPEG2000 images.
* copyright (c) 2002 Michael Ritzert <michael@ritzert.de>
*
* This library is distributed under the conditions of the GNU LGPL.
*/
#ifndef KIMG_JP2_H
#define KIMG_JP2_H
#include <QImageIOPlugin>
class JP2Handler : public QImageIOHandler
{
public:
JP2Handler();
virtual ~JP2Handler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
virtual bool supportsOption(ImageOption option) const;
virtual QVariant option(ImageOption option) const;
virtual void setOption(ImageOption option, const QVariant &value);
static bool canRead(QIODevice *device);
private:
int quality;
};
class JP2Plugin : public QImageIOPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "jp2.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
#endif // KIMG_JP2_H

View File

@ -1,4 +0,0 @@
{
"Keys": [ "jp2" ],
"MimeTypes": [ "image/jp2" ]
}

88
src/imageformats/kra.cpp Normal file
View File

@ -0,0 +1,88 @@
/* This file is part of the KDE project
Copyright (C) 2013 Boudewijn Rempt <boud@valdyas.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This code is based on Thacher Ulrich PSD loading code released
on public domain. See: http://tulrich.com/geekstuff/
*/
#include "kra.h"
#include <kzip.h>
#include <QImage>
#include <QIODevice>
#include <QFile>
KraHandler::KraHandler()
{
}
bool KraHandler::canRead() const
{
if (canRead(device())) {
setFormat("kra");
return true;
}
return false;
}
bool KraHandler::read(QImage *image)
{
KZip zip(device());
if (!zip.open(QIODevice::ReadOnly)) return false;
const KArchiveEntry *entry = zip.directory()->entry(QLatin1String("mergedimage.png"));
if (!entry || !entry->isFile()) return false;
const KZipFileEntry* fileZipEntry = static_cast<const KZipFileEntry*>(entry);
image->loadFromData(fileZipEntry->data(), "PNG");
return true;
}
bool KraHandler::canRead(QIODevice *device)
{
if (!device) {
qWarning("KraHandler::canRead() called with no device");
return false;
}
char buff[57];
if (device->peek(buff, sizeof(buff)) == sizeof(buff))
return qstrcmp(buff + 0x26, "application/x-krita") == 0;
return false;
}
QImageIOPlugin::Capabilities KraPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "kra" || format == "KRA") {
return Capabilities(CanRead);
}
if (!format.isEmpty()) {
return {};
}
if (!device->isOpen()) {
return {};
}
Capabilities cap;
if (device->isReadable() && KraHandler::canRead(device)) {
cap |= CanRead;
}
return cap;
}
QImageIOHandler *KraPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new KraHandler;
handler->setDevice(device);
handler->setFormat(format);
return handler;
}

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Type=Service
X-KDE-ServiceTypes=QImageIOPlugins
X-KDE-ImageFormat=kra
X-KDE-MimeType=application/x-krita
X-KDE-Read=true
X-KDE-Write=false

38
src/imageformats/kra.h Normal file
View File

@ -0,0 +1,38 @@
/* This file is part of the KDE project
Copyright (c) 2013 Boudewijn Rempt <boud@valdyas.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef KIMG_KRA_H
#define KIMG_KRA_H
#include <QImageIOPlugin>
class KraHandler : public QImageIOHandler
{
public:
KraHandler();
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
class KraPlugin : public QImageIOPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "kra.json")
public:
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif

View File

@ -0,0 +1,5 @@
{
"Keys": [ "kra" ],
"MimeTypes": [ "application/x-krita", "application/x-krita" ]
}

87
src/imageformats/ora.cpp Normal file
View File

@ -0,0 +1,87 @@
/* This file is part of the KDE project
Copyright (C) 2013 Boudewijn Rempt <boud@valdyas.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This code is based on Thacher Ulrich PSD loading code released
on public domain. See: http://tulrich.com/geekstuff/
*/
#include "ora.h"
#include <QImage>
#include <QScopedPointer>
#include <kzip.h>
OraHandler::OraHandler()
{
}
bool OraHandler::canRead() const
{
if (canRead(device())) {
setFormat("ora");
return true;
}
return false;
}
bool OraHandler::read(QImage *image)
{
KZip zip(device());
if (!zip.open(QIODevice::ReadOnly)) return false;
const KArchiveEntry *entry = zip.directory()->entry(QLatin1String("mergedimage.png"));
if (!entry || !entry->isFile()) return false;
const KZipFileEntry* fileZipEntry = static_cast<const KZipFileEntry*>(entry);
image->loadFromData(fileZipEntry->data(), "PNG");
return true;
}
bool OraHandler::canRead(QIODevice *device)
{
if (!device) {
qWarning("OraHandler::canRead() called with no device");
return false;
}
char buff[54];
if (device->peek(buff, sizeof(buff)) == sizeof(buff))
return qstrcmp(buff + 0x26, "image/openraster") == 0;
return false;
}
QImageIOPlugin::Capabilities OraPlugin::capabilities(QIODevice *device, const QByteArray &format) const
{
if (format == "ora" || format == "ORA") {
return Capabilities(CanRead);
}
if (!format.isEmpty()) {
return {};
}
if (!device->isOpen()) {
return {};
}
Capabilities cap;
if (device->isReadable() && OraHandler::canRead(device)) {
cap |= CanRead;
}
return cap;
}
QImageIOHandler *OraPlugin::create(QIODevice *device, const QByteArray &format) const
{
QImageIOHandler *handler = new OraHandler;
handler->setDevice(device);
handler->setFormat(format);
return handler;
}

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Type=Service
X-KDE-ServiceTypes=QImageIOPlugins
X-KDE-ImageFormat=xv
X-KDE-MimeType=
X-KDE-ImageFormat=ora
X-KDE-MimeType=image/openraster
X-KDE-Read=true
X-KDE-Write=true
X-KDE-Write=false

38
src/imageformats/ora.h Normal file
View File

@ -0,0 +1,38 @@
/* This file is part of the KDE project
Copyright (c) 2013 Boudewijn Rempt <boud@valdyas.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef KIMG_ORA_H
#define KIMG_ORA_H
#include <QImageIOPlugin>
class OraHandler : public QImageIOHandler
{
public:
OraHandler();
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
class OraPlugin : public QImageIOPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "ora.json")
public:
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif

View File

@ -0,0 +1,5 @@
{
"Keys": [ "ora" ],
"MimeTypes": [ "image/openraster", "image/openraster" ]
}

View File

@ -7,7 +7,7 @@
version 2 of the License, or (at your option) any later version.
*/
#include "pcx.h"
#include "pcx_p.h"
#include <QColor>
#include <QDataStream>
@ -667,10 +667,10 @@ QImageIOPlugin::Capabilities PCXPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -17,9 +17,9 @@ class PCXHandler : public QImageIOHandler
public:
PCXHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -30,8 +30,8 @@ class PCXPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "pcx.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_PCX_H

View File

@ -1,6 +1,9 @@
/**
* 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 +21,207 @@
* ----------------------------------------------------------------------------
*/
#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_p.h"
#include "rle_p.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;
}
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) {
bool success = decodeRLEData(RLEVariant::PIC, stream, row, width,
readPixel, updatePixel);
if (!success) {
qDebug() << "decodeRLEData 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;
}
bool SoftimagePICHandler::canRead() const
{
@ -36,43 +234,213 @@ 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) {
encodeRLEData(RLEVariant::PIC, 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) {
encodeRLEData(RLEVariant::PIC, 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 false;
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);
} else {
return QSize(-1, -1);
}
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 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();
}
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
@ -81,10 +449,10 @@ QImageIOPlugin::Capabilities SoftimagePICPlugin::capabilities(QIODevice *device,
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -1,49 +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
* ----------------------------------------------------------------------------
*/
#ifndef KIMG_PIC_H
#define KIMG_PIC_H
#include <QImageIOPlugin>
class SoftimagePICHandler : public QImageIOHandler
{
public:
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &);
virtual QVariant option(ImageOption option) const;
virtual bool supportsOption(ImageOption option) const;
static bool canRead(QIODevice *device);
};
class SoftimagePICPlugin : public QImageIOPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "pic.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
};
#endif // KIMG_PIC_H

202
src/imageformats/pic_p.h Normal file
View File

@ -0,0 +1,202 @@
/*
* 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
* ----------------------------------------------------------------------------
*/
#ifndef KIMG_PIC_H
#define KIMG_PIC_H
#include <QImageIOPlugin>
#include <QDataStream>
/**
* 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:
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &) Q_DECL_OVERRIDE;
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
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "pic.json")
public:
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_PIC_H

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,27 +1,41 @@
/* This file is part of the KDE project
Copyright (C) 2003 Ignacio Castaño <castano@ludicon.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This code is based on Thacher Ulrich PSD loading code released
on public domain. See: http://tulrich.com/geekstuff/
*/
/* this code supports:
* reading:
* rle and raw psd files
* writing:
* not supported
/*
* Photoshop File Format support for QImage.
*
* Copyright 2003 Ignacio Castaño <castano@ludicon.com>
* Copyright 2015 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 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
*/
#include "psd.h"
/*
* This code is based on Thacher Ulrich PSD loading code released
* into the public domain. See: http://tulrich.com/geekstuff/
*/
/*
* Documentation on this file format is available at
* http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
*/
#include "psd_p.h"
#include "rle_p.h"
#include <QDataStream>
#include <QDebug>
#include <QImage>
#include <QtCore/QDataStream>
// #include <QDebug>
typedef quint32 uint;
typedef quint16 ushort;
@ -66,20 +80,6 @@ static QDataStream &operator>> (QDataStream &s, PSDHeader &header)
s >> header.color_mode;
return s;
}
static bool seekBy(QDataStream &s, unsigned int bytes)
{
char buf[4096];
while (bytes) {
unsigned int num = qMin(bytes, (unsigned int)sizeof(buf));
unsigned int l = num;
s.readRawData(buf, l);
if (l != num) {
return false;
}
bytes -= num;
}
return true;
}
// Check that the header is a valid PSD.
static bool IsValid(const PSDHeader &header)
@ -108,125 +108,107 @@ static bool IsSupported(const PSDHeader &header)
return true;
}
// Load the PSD image.
static bool LoadPSD(QDataStream &s, const PSDHeader &header, QImage &img)
static void skip_section(QDataStream &s)
{
// Create dst image.
img = QImage(header.width, header.height, QImage::Format_RGB32);
uint tmp;
quint32 section_length;
// Skip mode data.
s >> tmp;
s.device()->seek(s.device()->pos() + tmp);
s >> section_length;
s.skipRawData(section_length);
}
// Skip image resources.
s >> tmp;
s.device()->seek(s.device()->pos() + tmp);
static quint8 readPixel(QDataStream &stream) {
quint8 pixel;
stream >> pixel;
return pixel;
}
static QRgb updateRed(QRgb oldPixel, quint8 redPixel) {
return qRgba(redPixel, qGreen(oldPixel), qBlue(oldPixel), qAlpha(oldPixel));
}
static QRgb updateGreen(QRgb oldPixel, quint8 greenPixel) {
return qRgba(qRed(oldPixel), greenPixel, qBlue(oldPixel), qAlpha(oldPixel));
}
static QRgb updateBlue(QRgb oldPixel, quint8 bluePixel) {
return qRgba(qRed(oldPixel), qGreen(oldPixel), bluePixel, qAlpha(oldPixel));
}
static QRgb updateAlpha(QRgb oldPixel, quint8 alphaPixel) {
return qRgba(qRed(oldPixel), qGreen(oldPixel), qBlue(oldPixel), alphaPixel);
}
typedef QRgb(*channelUpdater)(QRgb,quint8);
// Skip the reserved data.
s >> tmp;
s.device()->seek(s.device()->pos() + tmp);
// Load the PSD image.
static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
{
// Mode data
skip_section(stream);
// Image resources
skip_section(stream);
// Reserved data
skip_section(stream);
// Find out if the data is compressed.
// Known values:
// 0: no compression
// 1: RLE compressed
ushort compression;
s >> compression;
quint16 compression;
stream >> compression;
if (compression > 1) {
// Unknown compression type.
qDebug() << "Unknown compression type";
return false;
}
uint channel_num = header.channel_count;
quint32 channel_num = header.channel_count;
QImage::Format fmt = QImage::Format_RGB32;
// Clear the image.
if (channel_num < 4) {
img.fill(qRgba(0, 0, 0, 0xFF));
} else {
if (channel_num >= 4) {
// Enable alpha.
img = img.convertToFormat(QImage::Format_ARGB32);
fmt = QImage::Format_ARGB32;
// Ignore the other channels.
channel_num = 4;
}
img = QImage(header.width, header.height, fmt);
img.fill(qRgb(0,0,0));
const uint pixel_count = header.height * header.width;
const quint32 pixel_count = header.height * header.width;
static const uint components[4] = {2, 1, 0, 3}; // @@ Is this endian dependant?
QRgb *image_data = reinterpret_cast<QRgb*>(img.bits());
static const channelUpdater updaters[4] = {
updateRed,
updateGreen,
updateBlue,
updateAlpha
};
if (compression) {
// Skip row lengths.
if (!seekBy(s, header.height * header.channel_count * sizeof(ushort))) {
int skip_count = header.height * header.channel_count * sizeof(quint16);
if (stream.skipRawData(skip_count) != skip_count) {
return false;
}
// Read RLE data.
for (uint channel = 0; channel < channel_num; channel++) {
uchar *ptr = img.bits() + components[channel];
uint count = 0;
while (count < pixel_count) {
uchar c;
if (s.atEnd()) {
return false;
}
s >> c;
uint len = c;
if (len < 128) {
// Copy next len+1 bytes literally.
len++;
count += len;
if (count > pixel_count) {
return false;
}
while (len != 0) {
s >> *ptr;
ptr += 4;
len--;
}
} else if (len > 128) {
// Next -len+1 bytes in the dest are replicated from next source byte.
// (Interpret len as a negative 8-bit int.)
len ^= 0xFF;
len += 2;
count += len;
if (s.atEnd() || count > pixel_count) {
return false;
}
uchar val;
s >> val;
while (len != 0) {
*ptr = val;
ptr += 4;
len--;
}
} else if (len == 128) {
// No-op.
}
for (unsigned short channel = 0; channel < channel_num; channel++) {
bool success = decodeRLEData(RLEVariant::PackBits, stream,
image_data, pixel_count,
&readPixel, updaters[channel]);
if (!success) {
qDebug() << "decodeRLEData on channel" << channel << "failed";
return false;
}
}
} else {
// We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
// where each channel consists of an 8-bit value for each pixel in the image.
// Read the data by channel.
for (uint channel = 0; channel < channel_num; channel++) {
uchar *ptr = img.bits() + components[channel];
// Read the data.
uint count = pixel_count;
while (count != 0) {
s >> *ptr;
ptr += 4;
count--;
for (unsigned short channel = 0; channel < channel_num; channel++) {
for (unsigned i = 0; i < pixel_count; ++i) {
image_data[i] = updaters[channel](image_data[i], readPixel(stream));
}
// make sure we didn't try to read past the end of the stream
if (stream.status() != QDataStream::Ok) {
qDebug() << "DataStream status was" << stream.status();
return false;
}
}
}
@ -318,10 +300,10 @@ QImageIOPlugin::Capabilities PSDPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -2,6 +2,6 @@
Type=Service
X-KDE-ServiceTypes=QImageIOPlugins
X-KDE-ImageFormat=psd
X-KDE-MimeType=image/x-psd
X-KDE-MimeType=image/vnd.adobe.photoshop
X-KDE-Read=true
X-KDE-Write=false

View File

@ -1,4 +1,4 @@
{
"Keys": [ "psd" ],
"MimeTypes": [ "image/x-psd" ]
"MimeTypes": [ "image/vnd.adobe.photoshop" ]
}

View File

@ -17,8 +17,8 @@ class PSDHandler : public QImageIOHandler
public:
PSDHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -29,8 +29,8 @@ class PSDPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "psd.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_PSD_H

View File

@ -9,7 +9,7 @@
version 2 of the License, or (at your option) any later version.
*/
#include "ras.h"
#include "ras_p.h"
#include <QImage>
#include <QtCore/QDataStream>
@ -219,7 +219,7 @@ bool RASHandler::canRead(QIODevice *device)
}
if (device->isSequential()) {
qWarning("Reading ras files from sequential devices not supported");
// qWarning("Reading ras files from sequential devices not supported");
return false;
}
@ -282,10 +282,10 @@ QImageIOPlugin::Capabilities RASPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -18,8 +18,8 @@ class RASHandler : public QImageIOHandler
public:
RASHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -30,8 +30,8 @@ class RASPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "ras.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_RAS_H

View File

@ -21,7 +21,7 @@
* saved by this filter.
*/
#include "rgb.h"
#include "rgb_p.h"
#include <QtCore/QMap>
#include <QtCore/QVector>
@ -111,8 +111,8 @@ private:
};
SGIImage::SGIImage(QIODevice *io) :
_starttab(0),
_lengthtab(0)
_starttab(nullptr),
_lengthtab(nullptr)
{
_dev = io;
_stream.setDevice(_dev);
@ -714,10 +714,10 @@ QImageIOPlugin::Capabilities RGBPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

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

@ -17,9 +17,9 @@ class RGBHandler : public QImageIOHandler
public:
RGBHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -30,8 +30,8 @@ class RGBPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "rgb.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_RGB_H

223
src/imageformats/rle_p.h Normal file
View File

@ -0,0 +1,223 @@
/*
* Run-Length Encoding utilities.
* Copyright 2014-2015 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 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
* ----------------------------------------------------------------------------
*/
#ifndef KIMAGEFORMATS_RLE_H
#define KIMAGEFORMATS_RLE_H
#include <QDebug>
#include <QDataStream>
/**
* The RLEVariant to use.
*
* This mostly concerns what to do values >= 128.
*/
enum class RLEVariant {
/**
* PackBits-style RLE
*
* Value 128 is ignored, 129 indicates a repetition
* of size 2, 130 of size 3, up to 255 of size 128.
*/
PackBits,
/**
* PIC-style RLE
*
* Value 128 indicates a 16-bit repetition count
* follows, while 129 indicates a repetition
* of size 128, 130 of size 127, down to 255 of
* size 2.
*/
PIC
};
/**
* Decodes data written in 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 variant The RLE variant to decode.
* @param stream The stream to read the data from.
* @param buf The location to write the decoded data.
* @param length The number of items to read.
* @param readData A function that takes a QDataStream reference and reads a
* single value.
* @param updateItem A function that takes an item from @p buf and the result
* of a readData call, and produces the item that should be
* written to @p buf.
*
* @returns @c true if @p length items in mixed RLE were successfully read
* 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)
{
unsigned offset = 0; // in dest
while (offset < length) {
unsigned remaining = length - offset;
quint8 count1;
stream >> count1;
if (count1 >= 128u) {
unsigned length = 0;
if (variant == RLEVariant::PIC) {
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 {
// 2 to 128 repetitions
length = count1 - 127u;
}
} else if (variant == RLEVariant::PackBits) {
if (count1 == 128u) {
// Ignore value 128
continue;
} else {
// 128 to 2 repetitions
length = 257u - count1;
}
} else {
Q_ASSERT(false);
}
if (length > remaining) {
qDebug() << "Row overrun:" << length << ">" << remaining;
return false;
}
auto datum = readData(stream);
for (unsigned i = offset; i < offset + length; ++i) {
dest[i] = updateItem(dest[i], datum);
}
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) {
auto datum = readData(stream);
dest[i] = updateItem(dest[i], datum);
}
offset += length;
}
}
if (stream.status() != QDataStream::Ok) {
qDebug() << "DataStream status was" << stream.status();
}
return stream.status() == QDataStream::Ok;
}
/**
* Encodes data in run-length encoding format.
*
* This is intended to be used with lambda functions.
*
* @param variant The RLE variant to encode in.
* @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 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;
while (offset < length) {
const Item *chunkStart = data + offset;
unsigned maxChunk = qMin(length - offset, maxEncodableChunk);
const Item *chunkEnd = chunkStart + 1;
quint16 chunkLength = 1;
while (chunkLength < maxChunk && itemsEqual(*chunkStart, *chunkEnd)) {
++chunkEnd;
++chunkLength;
}
if (chunkLength > 128) {
// Sequence of > 128 identical pixels
Q_ASSERT(variant == RLEVariant::PIC);
stream << quint8(128);
stream << quint16(chunkLength);
writeItem(stream, *chunkStart);
} else if (chunkLength > 1) {
// Sequence of <= 128 identical pixels
quint8 encodedLength;
if (variant == RLEVariant::PIC) {
encodedLength = quint8(chunkLength + 127);
} else if (variant == RLEVariant::PackBits) {
encodedLength = quint8(257 - chunkLength);
} else {
Q_ASSERT(false);
encodedLength = 0;
}
stream << encodedLength;
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;
}
}
#endif // KIMAGEFORMATS_RLE_H

View File

@ -18,7 +18,7 @@
* uncompressed true color tga files
*/
#include "tga.h"
#include "tga_p.h"
#include <assert.h>
@ -145,6 +145,9 @@ struct TgaHeaderInfo {
switch (tga.image_type) {
case TGA_TYPE_RLE_INDEXED:
rle = true;
#if QT_VERSION >= QT_VERSION_CHECK(5,8,0)
Q_FALLTHROUGH();
#endif
// no break is intended!
case TGA_TYPE_INDEXED:
pal = true;
@ -152,6 +155,9 @@ struct TgaHeaderInfo {
case TGA_TYPE_RLE_RGB:
rle = true;
#if QT_VERSION >= QT_VERSION_CHECK(5,8,0)
Q_FALLTHROUGH();
#endif
// no break is intended!
case TGA_TYPE_RGB:
rgb = true;
@ -159,6 +165,9 @@ struct TgaHeaderInfo {
case TGA_TYPE_RLE_GREY:
rle = true;
#if QT_VERSION >= QT_VERSION_CHECK(5,8,0)
Q_FALLTHROUGH();
#endif
// no break is intended!
case TGA_TYPE_GREY:
grey = true;
@ -414,10 +423,10 @@ QImageIOPlugin::Capabilities TGAPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead | CanWrite);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -17,9 +17,9 @@ class TGAHandler : public QImageIOHandler
public:
TGAHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -30,8 +30,8 @@ class TGAPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "tga.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_TGA_H

View File

@ -19,7 +19,7 @@
*
*/
#include "xcf.h"
#include "xcf_p.h"
#include <stdlib.h>
#include <QImage>
@ -29,7 +29,7 @@
#include <QtCore/QVector>
// #include <QDebug>
#include "gimp.h"
#include "gimp_p.h"
const float INCHESPERMETER = (100.0f / 2.54f);
@ -107,7 +107,7 @@ private:
//! copied in different ways.
void (*assignBytes)(Layer &layer, uint i, uint j);
Layer(void) : name(0) {}
Layer(void) : name(nullptr) {}
~Layer(void)
{
delete[] name;
@ -416,7 +416,7 @@ bool XCFImageFormat::loadImageProperties(QDataStream &xcf_io, XCFImage &xcf_imag
property.readBytes(tag, size);
quint32 flags;
char *data = 0;
char *data = nullptr;
property >> flags >> data;
if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0) {
@ -474,7 +474,7 @@ bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArra
xcf_io >> foo;
type = PropType(foo); // TODO urks
char *data = 0;
char *data = nullptr;
quint32 size;
// The colormap property size is not the correct number of bytes:
@ -1323,7 +1323,9 @@ bool XCFImageFormat::initializeImage(XCFImage &xcf_image)
image.fill(qRgb(255, 255, 255));
break;
} // else, fall through to 32-bit representation
#if QT_VERSION >= QT_VERSION_CHECK(5,8,0)
Q_FALLTHROUGH();
#endif
case RGBA_GIMAGE:
image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
if (image.isNull()) {
@ -1343,7 +1345,9 @@ bool XCFImageFormat::initializeImage(XCFImage &xcf_image)
image.fill(255);
break;
} // else, fall through to 32-bit representation
#if QT_VERSION >= QT_VERSION_CHECK(5,8,0)
Q_FALLTHROUGH();
#endif
case GRAYA_GIMAGE:
image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
if (image.isNull()) {
@ -1442,7 +1446,7 @@ void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
{
Layer &layer(xcf_image.layer);
QImage &image(xcf_image.image);
PixelCopyOperation copy = 0;
PixelCopyOperation copy = nullptr;
switch (layer.type) {
case RGB_GIMAGE:
@ -1725,7 +1729,7 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
Layer &layer(xcf_image.layer);
QImage &image(xcf_image.image);
PixelMergeOperation merge = 0;
PixelMergeOperation merge = nullptr;
if (!layer.opacity) {
return; // don't bother doing anything
@ -2686,10 +2690,10 @@ QImageIOPlugin::Capabilities XCFPlugin::capabilities(QIODevice *device, const QB
return Capabilities(CanRead);
}
if (!format.isEmpty()) {
return 0;
return {};
}
if (!device->isOpen()) {
return 0;
return {};
}
Capabilities cap;

View File

@ -29,9 +29,9 @@ class XCFHandler : public QImageIOHandler
public:
XCFHandler();
virtual bool canRead() const;
virtual bool read(QImage *image);
virtual bool write(const QImage &image);
bool canRead() const Q_DECL_OVERRIDE;
bool read(QImage *image) Q_DECL_OVERRIDE;
bool write(const QImage &image) Q_DECL_OVERRIDE;
static bool canRead(QIODevice *device);
};
@ -42,8 +42,8 @@ class XCFPlugin : public QImageIOPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "xcf.json")
public:
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
virtual QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
Capabilities capabilities(QIODevice *device, const QByteArray &format) const Q_DECL_OVERRIDE;
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const Q_DECL_OVERRIDE;
};
#endif // KIMG_XCF_H

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(">");
}

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