Compare commits
1 Commits
v6.18.0
...
work/kbrou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5494d9acf |
@@ -15,7 +15,7 @@ include:
|
||||
|
||||
image_json_validate:
|
||||
stage: validate
|
||||
image: invent-registry.kde.org/sysadmin/ci-images/suse-qt69:latest
|
||||
image: invent-registry.kde.org/sysadmin/ci-images/suse-qt68:latest
|
||||
tags:
|
||||
- Linux
|
||||
script:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(KF_VERSION "6.18.0") # handled by release scripts
|
||||
set(KF_DEP_VERSION "6.18.0") # handled by release scripts
|
||||
set(KF_VERSION "6.17.0") # handled by release scripts
|
||||
set(KF_DEP_VERSION "6.16.0") # handled by release scripts
|
||||
project(KImageFormats VERSION ${KF_VERSION})
|
||||
|
||||
include(FeatureSummary)
|
||||
find_package(ECM 6.18.0 NO_MODULE)
|
||||
find_package(ECM 6.16.0 NO_MODULE)
|
||||
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
|
||||
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
|
||||
@@ -99,8 +99,8 @@ endif()
|
||||
add_feature_info(LibJXR LibJXR_FOUND "required for the QImage plugin for JPEG XR images")
|
||||
|
||||
ecm_set_disabled_deprecation_versions(
|
||||
QT 6.10.0
|
||||
KF 6.17.0
|
||||
QT 6.9.0
|
||||
KF 6.13.0
|
||||
)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
71
README.md
@@ -17,7 +17,7 @@ The following image formats have read-only support:
|
||||
- Animated Windows cursors (ani)
|
||||
- Camera RAW images (arw, cr2, cr3, dcs, dng, ...)
|
||||
- Gimp (xcf)
|
||||
- Interchange Format Files (iff, ilbm, lbm)
|
||||
- Interchange Format Files (IFF)
|
||||
- Krita (kra)
|
||||
- OpenRaster (ora)
|
||||
- Pixar raster (pxr)
|
||||
@@ -56,17 +56,11 @@ submit the plugin directly to the Qt Project.
|
||||
To be accepted, contributions must:
|
||||
- Contain the test images needed to verify that the changes work correctly.
|
||||
- Pass the tests successfully.
|
||||
- Use Qt logging categories for Debug messages.
|
||||
|
||||
For more info about tests, see also [Autotests README](autotests/README.md).
|
||||
|
||||
## Duplicated Plugins
|
||||
|
||||
> [!important]
|
||||
> To ensure you are using the correct plugin, the unwanted one should be
|
||||
renamed or deleted. If several plugins support the same capability, Qt will
|
||||
select one arbitrarily.
|
||||
|
||||
### The TGA plugin
|
||||
|
||||
The TGA plugin supports more formats than Qt's own TGA plugin;
|
||||
@@ -218,35 +212,30 @@ RGB.
|
||||
|
||||
Where possible, plugins support large images. By convention, many of the
|
||||
large image plugins are limited to a maximum of 300,000 x 300,000 pixels.
|
||||
Anyway, all plugins are also limited by the
|
||||
`QImageIOReader::allocationLimit()`.
|
||||
Anyway, all plugins are also limited by the
|
||||
`QImageIOReader::allocationLimit()`. Below are the maximum sizes for each
|
||||
plugin ('n/a' means no limit, i.e. the limit depends on the format encoding).
|
||||
|
||||
> [!note]
|
||||
> You can change the maximum limit of 300000 pixels by setting the constant
|
||||
> `KIF_LARGE_IMAGE_PIXEL_LIMIT` to the desired value in the cmake file.
|
||||
|
||||
Below are the maximum sizes for each plugin ('n/a' means no limit, i.e. the
|
||||
limit depends on the format encoding).
|
||||
- ANI: n/a
|
||||
- AVIF: 32,768 x 32,768 pixels, in any case no larger than 256 megapixels
|
||||
- DDS: n/a
|
||||
- EXR: 300,000 x 300,000 pixels
|
||||
- EPS: same size as Qt's JPG plugin
|
||||
- HDR: 300,000 x 300,000 pixels
|
||||
- EPS: n/a
|
||||
- HDR: n/a (large image)
|
||||
- HEIF: n/a
|
||||
- IFF: 65,535 x 65,535 pixels
|
||||
- JP2: 300,000 x 300,000 pixels, in any case no larger than 2 gigapixels
|
||||
- JXL: 262,144 x 262,144 pixels, in any case no larger than 256 megapixels
|
||||
- JXR: 300,000 x 300,000 pixels, in any case no larger than 4 GB
|
||||
- JXR: n/a, in any case no larger than 4 GB
|
||||
- KRA: same size as Qt's PNG plugin
|
||||
- ORA: same size as Qt's PNG plugin
|
||||
- PCX: 65,535 x 65,535 pixels
|
||||
- PFM: 300,000 x 300,000 pixels
|
||||
- PFM: n/a (large image)
|
||||
- PIC: 65,535 x 65,535 pixels
|
||||
- PSD: 300,000 x 300,000 pixels
|
||||
- PXR: 65,535 x 65,535 pixels
|
||||
- QOI: 300,000 x 300,000 pixels
|
||||
- RAS: 300,000 x 300,000 pixels
|
||||
- RAS: n/a (large image)
|
||||
- RAW: n/a (depends on the RAW format loaded)
|
||||
- RGB: 65,535 x 65,535 pixels
|
||||
- SCT: 300,000 x 300,000 pixels
|
||||
@@ -328,29 +317,6 @@ plugin:
|
||||
- `HDR_HALF_QUALITY`: on read, a 16-bit float image is returned instead of a
|
||||
32-bit float one.
|
||||
|
||||
|
||||
### The IFF plugin
|
||||
|
||||
Interchange File Format is a chunk-based format. Since the original 1985
|
||||
version, various extensions have been created over time.
|
||||
|
||||
The plugin supports the following image data:
|
||||
- FORM ILBM (Interleaved Bitmap): Electronic Arts’ IFF standard for
|
||||
Interchange File Format (EA IFF 1985). ILBM is a format to handle raster
|
||||
images, specifically an InterLeaved bitplane BitMap image with color map.
|
||||
It supports from 1 to 8-bit indexed images with HAM, Halfbride, and normal
|
||||
encoding. It also supports interleaved 24-bit RGB and 32-bit RGBA
|
||||
extension without color map.
|
||||
- FORM ILBM 64: ILBM extension to support 48-bit RGB and 64-bit RGBA encoding.
|
||||
- FORM ACBM (Amiga Contiguous BitMap): It supports uncompressed ACBMs by
|
||||
converting them to ILBMs at runtime.
|
||||
- FORM RGBN / RGB8: It supports 13-bit and 25-bit RGB images with compression
|
||||
type 4.
|
||||
- FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images
|
||||
with color map only.
|
||||
- FOR4 CIMG (Maya Image File Format): It supports 24/48-bit RGB and 32/64-bit
|
||||
RGBA images.
|
||||
|
||||
### The JP2 plugin
|
||||
|
||||
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
|
||||
@@ -433,25 +399,6 @@ selectively change the conversion (see also [raw_p.h](./src/imageformats/raw_p.h
|
||||
|
||||
The default setting tries to balance quality and conversion speed.
|
||||
|
||||
### The TGA plugin
|
||||
|
||||
TGA plugin supports both version 1 and version 2 of TGA files. When writing,
|
||||
it is possible to force which version to use by setting the following subtypes:
|
||||
- `TGAv1`: force TGA v1.0. No metadata.
|
||||
- `TGAv2` (default): force TGA v2.0 (strict). Adds the TGA Extension Area.
|
||||
- `TGAv2E`: force TGA v2.0 (enhanced). Same as TGA v2.0 (strict) but with the
|
||||
addition of the TGA v2.0 Developer Area with info like, for e.g., Exif data,
|
||||
XMP packet and the ICC profile.
|
||||
|
||||
They are all TGA specs compliant. While for versions 1 and 2 (strict) it is
|
||||
possible to decode all the information with the TGA specification alone, for
|
||||
version 2 (enhanced) it is necessary to know how the additional data is
|
||||
encoded.
|
||||
|
||||
The following defines can be defined in cmake to modify the behavior of the
|
||||
plugin:
|
||||
- `TGA_V2E_AS_DEFAULT`: change the default version of the plugin to `TGAv2E`.
|
||||
|
||||
### The XCF plugin
|
||||
|
||||
XCF support has the following limitations:
|
||||
|
||||
@@ -189,7 +189,7 @@ kimageformats_write_tests(
|
||||
pic-lossless
|
||||
qoi-lossless
|
||||
rgb-lossless
|
||||
tga-nodatacheck
|
||||
tga # fixme: the alpha images appear not to be written properly
|
||||
)
|
||||
|
||||
# EPS read tests depend on the vagaries of GhostScript
|
||||
|
||||
@@ -88,33 +88,30 @@ are iterated sequentially and the first object that matches the requirements
|
||||
is used for testing (successes are ignored).
|
||||
|
||||
Supported values for JSON objects:
|
||||
- `comment`: Type `string`. A string shown by the test when a condition occurs.
|
||||
- `description`: Type `string`. A description of the object. Not used by the
|
||||
- `comment`: Type string. A string shown by the test when a condition occurs.
|
||||
- `description`: Type string. A description of the object. Not used by the
|
||||
test.
|
||||
- `disableAutoTransform`: Type `boolean`. By default, tests are run with
|
||||
- `disableAutoTransform`: Type boolean. By default, tests are run with
|
||||
autotransform enabled (i.e. rotation is applied if the plugin supports it).
|
||||
Set to `true` to disable autotransform.
|
||||
- `filename`: Type `string`. Name of the template file to use. E.g.
|
||||
- `filename`: Type string. Name of the template file to use. E.g.
|
||||
"testRGB_Qt_6_2.png".
|
||||
- `fuzziness`: Type `integer`. Set the fuzziness only if not already set on the
|
||||
- `fuzziness`: Type integer. Set the fuzziness only if not already set on the
|
||||
command line. The value set on the command line wins over the one in the JSON
|
||||
file.
|
||||
- `maxQtVersion`: Type `string`. Maximum Qt version this object is compatible
|
||||
- `maxQtVersion`: Type string. Maximum Qt version this object is compatible
|
||||
with (if not set means all). E.g. "6.2.99".
|
||||
- `metadata`: Type `array`. An array of key/value objects (string type)
|
||||
- `metadata`: Type Array. An array of key/value objects (string type)
|
||||
containing the image metadata as returned by `QImage::text`.
|
||||
- `minQtVersion`: Type `string`. Minimum Qt version this object is compatible
|
||||
- `minQtVersion`: Type string. Minimum Qt version this object is compatible
|
||||
with (if not set means all). E.g. "6.2.0".
|
||||
- `perceptiveFuzziness` Type `boolean`. Set the perceptive fuzziness only if not
|
||||
- `perceptiveFuzziness` Type boolean. Set the perceptive fuzziness only if not
|
||||
already set on the command line. The value set on the command line wins over
|
||||
the one in the JSON file.
|
||||
- `resolution`: Type `object`. An object with the `dotsPerMeterX` and
|
||||
- `resolution`: Type object. An object with the `dotsPerMeterX` and
|
||||
`dotsPerMeterY` (integer) values of the image.
|
||||
- `seeAlso`: Type `string`. More info about the object. Normally used to point
|
||||
- `seeAlso`: Type string. More info about the object. Normally used to point
|
||||
to bug reports. Not used by the test.
|
||||
- `skipSequential`: Type `boolean`. Skip the test on sequential access device.
|
||||
Some plugins may have limited functionality on sequential devices (e.g.,
|
||||
not reading metadata).
|
||||
- `unsupportedFormat`: Type `boolean`. When true, the test is skipped.
|
||||
|
||||
Some examples:
|
||||
@@ -172,12 +169,11 @@ See also [Add a test to CMakeLists.txt](#add-a-test-to-cmakeliststxt).
|
||||
The properties file must be located in `write/basic` and must have the name
|
||||
of the file format (e.g. jxl.json). It is a JSON object composed of the
|
||||
following values:
|
||||
- `format`: Type `string`. The format tested.
|
||||
- `metadata`: Type `array`. An array of key/value objects (string type)
|
||||
- `format`: Type string. The format tested.
|
||||
- `metadata`: Type Array. An array of key/value objects (string type)
|
||||
containing the image metadata as returned by `QImage::text`.
|
||||
- `resolution`: Type `object`. An object with the `dotsPerMeterX` and `
|
||||
- `resolution`: Type object. An object with the `dotsPerMeterX` and `
|
||||
dotsPerMeterY` (integer) values of the image.
|
||||
- `subType`: type `string`. The image writer subtype to set when testing.
|
||||
|
||||
[This is an example](write/basic/jxl.json) of property file.
|
||||
|
||||
@@ -234,7 +230,9 @@ kimageformats_write_tests(FUZZ 1
|
||||
|
||||
Plugins are also tested with [OSS-Fuzz](https://google.github.io/oss-fuzz/)
|
||||
project to identify possible security issues. When adding a new plugin it is
|
||||
also necessary to add it to the test in the [ossfuzz](ossfuzz) directory.
|
||||
also necessary to add it to the test in the [kimageformats
|
||||
project](https://github.com/google/oss-fuzz/tree/master/projects/kimageformats)
|
||||
on OSS-Fuzz.
|
||||
|
||||
## TODO
|
||||
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
#!/bin/bash -eu
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# build zstd
|
||||
cd $SRC/zstd
|
||||
cmake -S build/cmake -DBUILD_SHARED_LIBS=OFF
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build zlib
|
||||
cd $SRC/zlib
|
||||
./configure --static
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build bzip2
|
||||
# Inspired from ../bzip2/build
|
||||
cd $SRC
|
||||
tar xzf bzip2-*.tar.gz && rm -f bzip2-*.tar.gz
|
||||
cd bzip2-*
|
||||
SRCL=(blocksort.o huffman.o crctable.o randtable.o compress.o decompress.o bzlib.o)
|
||||
|
||||
for source in ${SRCL[@]}; do
|
||||
name=$(basename $source .o)
|
||||
$CC $CFLAGS -c ${name}.c
|
||||
done
|
||||
rm -f libbz2.a
|
||||
ar cq libbz2.a ${SRCL[@]}
|
||||
cp -f bzlib.h /usr/local/include
|
||||
cp -f libbz2.a /usr/local/lib
|
||||
|
||||
# Build xz
|
||||
export ORIG_CFLAGS="${CFLAGS}"
|
||||
export ORIG_CXXFLAGS="${CXXFLAGS}"
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
cd $SRC/xz
|
||||
./autogen.sh --no-po4a --no-doxygen
|
||||
./configure --enable-static --disable-debug --disable-shared --disable-xz --disable-xzdec --disable-lzmainfo
|
||||
make install -j$(nproc)
|
||||
export CFLAGS="${ORIG_CFLAGS}"
|
||||
export CXXFLAGS="${ORIG_CXXFLAGS}"
|
||||
|
||||
# Build qt
|
||||
cd $SRC/qtbase
|
||||
./configure -no-glib -qt-libpng -qt-pcre -opensource -confirm-license -static -no-opengl -no-icu -platform linux-clang-libc++ -debug -prefix /usr -no-feature-widgets -no-feature-sql -no-feature-network -no-feature-xml -no-feature-dbus -no-feature-printsupport
|
||||
cmake --build . --parallel $(nproc)
|
||||
cmake --install .
|
||||
|
||||
# Build extra-cmake-modules
|
||||
cd $SRC/extra-cmake-modules
|
||||
cmake . -DBUILD_TESTING=OFF
|
||||
make install -j$(nproc)
|
||||
|
||||
cd $SRC/karchive
|
||||
rm -rf poqm
|
||||
cmake . -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DCMAKE_INSTALL_PREFIX=/usr/local
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build JXRlib
|
||||
cd $SRC/jxrlib
|
||||
make -j$(nproc)
|
||||
|
||||
# Build LibRaw
|
||||
cd $SRC/LibRaw
|
||||
TMP_CFLAGS=$CFLAGS
|
||||
TMP_CXXFLAGS=$CXXFLAGS
|
||||
CFLAGS="$CFLAGS -fno-sanitize=function,vptr"
|
||||
CXXFLAGS="$CXXFLAGS -fno-sanitize=function,vptr"
|
||||
autoreconf --install
|
||||
./configure --disable-examples
|
||||
make -j$(nproc)
|
||||
make install -j$(nproc)
|
||||
CFLAGS=$TMP_CFLAGS
|
||||
CXXFLAGS=$TMP_CXXFLAGS
|
||||
|
||||
|
||||
# Build aom
|
||||
cd $SRC/aom
|
||||
mkdir build.libavif
|
||||
cd build.libavif
|
||||
extra_libaom_flags='-DAOM_MAX_ALLOCABLE_MEMORY=536870912 -DDO_RANGE_CHECK_CLAMP=1'
|
||||
cmake -DBUILD_SHARED_LIBS=0 -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 -DCONFIG_PIC=1 -DAOM_TARGET_CPU=generic -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=12288 -DDECODE_WIDTH_LIMIT=12288 -DAOM_EXTRA_C_FLAGS="${extra_libaom_flags}" -DAOM_EXTRA_CXX_FLAGS="${extra_libaom_flags}" ..
|
||||
make -j$(nproc)
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build libavif
|
||||
cd $SRC/libavif
|
||||
ln -s "$SRC/aom" "$SRC/libavif/ext/"
|
||||
mkdir build
|
||||
cd build
|
||||
CFLAGS="$CFLAGS -fPIC" cmake -DBUILD_SHARED_LIBS=OFF -DAVIF_ENABLE_WERROR=OFF -DAVIF_CODEC_AOM=LOCAL -DAVIF_LIBYUV=OFF ..
|
||||
make -j$(nproc)
|
||||
|
||||
# Build libde265
|
||||
cd $SRC/libde265
|
||||
cmake -DBUILD_SHARED_LIBS=OFF -DDISABLE_SSE=ON .
|
||||
make -j$(nproc)
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build openjpeg
|
||||
cd $SRC/openjpeg
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON -DBUILD_CODEC=OFF ..
|
||||
make -j$(nproc)
|
||||
make install -j$(nproc)
|
||||
|
||||
# build openh264
|
||||
cd $SRC/openh264
|
||||
make USE_ASM=No BUILDTYPE=Debug install-static -j$(nproc)
|
||||
|
||||
# Build openexr
|
||||
cd $SRC/openexr
|
||||
mkdir _build
|
||||
cd _build
|
||||
cmake -DBUILD_SHARED_LIBS=OFF ..
|
||||
make -j$(nproc)
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build libheif
|
||||
cd $SRC/libheif
|
||||
#Reduce max width and height to avoid allocating too much memory
|
||||
sed -i "s/static const int MAX_IMAGE_WIDTH = 32768;/static const int MAX_IMAGE_WIDTH = 8192;/g" libheif/security_limits.h
|
||||
sed -i "s/static const int MAX_IMAGE_HEIGHT = 32768;/static const int MAX_IMAGE_HEIGHT = 8192;/g" libheif/security_limits.h
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_PLUGIN_LOADING=OFF -DWITH_DAV1D=OFF -DWITH_EXAMPLES=OFF -DWITH_LIBDE265=ON -DWITH_RAV1E=OFF -DWITH_RAV1E_PLUGIN=OFF -DWITH_SvtEnc=OFF -DWITH_SvtEnc_PLUGIN=OFF -DWITH_X265=OFF -DWITH_OpenJPEG_DECODER=ON -DWITH_OpenH264_DECODER=ON ..
|
||||
make -j$(nproc)
|
||||
make install -j$(nproc)
|
||||
|
||||
# Build libjxl
|
||||
cd $SRC/libjxl
|
||||
mkdir build
|
||||
cd build
|
||||
CXXFLAGS="$CXXFLAGS -DHWY_COMPILE_ONLY_SCALAR" cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DJPEGXL_ENABLE_BENCHMARK=OFF -DJPEGXL_ENABLE_DOXYGEN=OFF -DJPEGXL_ENABLE_EXAMPLES=OFF -DJPEGXL_ENABLE_JNI=OFF -DJPEGXL_ENABLE_JPEGLI=OFF -DJPEGXL_ENABLE_JPEGLI_LIBJPEG=OFF -DJPEGXL_ENABLE_MANPAGES=OFF -DJPEGXL_ENABLE_OPENEXR=OFF -DJPEGXL_ENABLE_PLUGINS=OFF -DJPEGXL_ENABLE_SJPEG=OFF -DJPEGXL_ENABLE_SKCMS=ON -DJPEGXL_ENABLE_TCMALLOC=OFF -DJPEGXL_ENABLE_TOOLS=OFF -DJPEGXL_ENABLE_FUZZERS=OFF ..
|
||||
make -j$(nproc) jxl jxl_cms jxl_threads
|
||||
|
||||
cd $SRC/kimageformats
|
||||
HANDLER_TYPES="ANIHandler ani
|
||||
QAVIFHandler avif
|
||||
QDDSHandler dds
|
||||
EXRHandler exr
|
||||
HDRHandler hdr
|
||||
HEIFHandler heif
|
||||
IFFHandler iff
|
||||
JP2Handler jp2
|
||||
QJpegXLHandler jxl
|
||||
JXRHandler jxr
|
||||
KraHandler kra
|
||||
OraHandler ora
|
||||
PCXHandler pcx
|
||||
PFMHandler pfm
|
||||
SoftimagePICHandler pic
|
||||
PSDHandler psd
|
||||
PXRHandler pxr
|
||||
QOIHandler qoi
|
||||
RASHandler ras
|
||||
RAWHandler raw
|
||||
RGBHandler rgb
|
||||
ScitexHandler sct
|
||||
TGAHandler tga
|
||||
XCFHandler xcf"
|
||||
|
||||
echo "$HANDLER_TYPES" | while read class format; do
|
||||
(
|
||||
fuzz_target_name=kimgio_${format}_fuzzer
|
||||
|
||||
/usr/libexec/moc $SRC/kimageformats/src/imageformats/$format.cpp -o $format.moc
|
||||
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
|
||||
/usr/libexec/moc $header -o moc_`basename $header .h`.cpp
|
||||
$CXX $CXXFLAGS -fPIC -DHANDLER=$class -std=c++17 autotests/ossfuzz/kimgio_fuzzer.cc $SRC/kimageformats/src/imageformats/$format.cpp $SRC/kimageformats/src/imageformats/scanlineconverter.cpp $SRC/kimageformats/src/imageformats/microexif.cpp $SRC/kimageformats/src/imageformats/chunks.cpp -o $OUT/$fuzz_target_name -DJXL_STATIC_DEFINE -DJXL_THREADS_STATIC_DEFINE -DJXL_CMS_STATIC_DEFINE -DINITGUID -I $SRC/kimageformats/src/imageformats/ -I $SRC/libavif/include/ -I $SRC/libjxl/build/lib/include/ -I $SRC/libjxl/lib/include/ -I /usr/local/include/OpenEXR/ -I /usr/local/include/KF6/KArchive/ -I /usr/local/include/openjpeg-2.5 -I /usr/local/include/Imath -I $SRC/jxrlib/common/include -I $SRC/jxrlib/jxrgluelib -I $SRC/jxrlib/image/sys -I /usr/include/QtCore/ -I /usr/include/QtGui/ -I . $SRC/libavif/build/libavif.a /usr/local/lib/libheif.a /usr/local/lib/libde265.a /usr/local/lib/libopenh264.a $SRC/aom/build.libavif/libaom.a $SRC/libjxl/build/lib/libjxl_threads.a $SRC/libjxl/build/lib/libjxl.a $SRC/libjxl/build/lib/libjxl_cms.a $SRC/libjxl/build/third_party/highway/libhwy.a $SRC/libjxl/build/third_party/brotli/libbrotlidec.a $SRC/libjxl/build/third_party/brotli/libbrotlienc.a $SRC/libjxl/build/third_party/brotli/libbrotlicommon.a -lQt6Gui -lQt6Core -lQt6BundledLibpng -lQt6BundledHarfbuzz -lm -lQt6BundledPcre2 -ldl -lpthread $LIB_FUZZING_ENGINE /usr/local/lib/libz.a -lKF6Archive /usr/local/lib/libz.a /usr/local/lib/libraw.a /usr/local/lib/libOpenEXR-3_3.a /usr/local/lib/libIex-3_3.a /usr/local/lib/libImath-3_1.a /usr/local/lib/libIlmThread-3_3.a /usr/local/lib/libOpenEXRCore-3_3.a /usr/local/lib/libOpenEXRUtil-3_3.a /usr/local/lib/libopenjp2.a /usr/local/lib/libzstd.a $SRC/jxrlib/build/libjxrglue.a $SRC/jxrlib/build/libjpegxr.a -llzma /usr/local/lib/libbz2.a -lclang_rt.builtins
|
||||
|
||||
# -lclang_rt.builtins in the previous line is a temporary workaround to avoid a linker error "undefined reference to __truncsfhf2". Investigate why this is needed here, but not anywhere else, and possibly remove it.
|
||||
|
||||
find . -name "*.${format}" | zip -q $OUT/${fuzz_target_name}_seed_corpus.zip -@
|
||||
)
|
||||
done
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
# SPDX-FileCopyrightText: 2018 Google Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/*
|
||||
Usage:
|
||||
python infra/helper.py build_image kimageformats
|
||||
python infra/helper.py build_fuzzers --sanitizer undefined|address|memory kimageformats
|
||||
python infra/helper.py run_fuzzer kimageformats kimgio_[ani|avif|dds|exr|hdr|heif|iff|jp2|jxl|jxr|kra|ora|pcx|pfm|pic|psd|pxr|qoi|ras|raw|rgb|sct|tga|xcf]_fuzzer
|
||||
*/
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QCoreApplication>
|
||||
#include <QImage>
|
||||
|
||||
#include "ani_p.h"
|
||||
#include "avif_p.h"
|
||||
#include "dds_p.h"
|
||||
#include "exr_p.h"
|
||||
#include "hdr_p.h"
|
||||
#include "heif_p.h"
|
||||
#include "iff_p.h"
|
||||
#include "jp2_p.h"
|
||||
#include "jxl_p.h"
|
||||
#include "jxr_p.h"
|
||||
#include "kra.h"
|
||||
#include "ora.h"
|
||||
#include "pcx_p.h"
|
||||
#include "pfm_p.h"
|
||||
#include "pic_p.h"
|
||||
#include "psd_p.h"
|
||||
#include "pxr_p.h"
|
||||
#include "qoi_p.h"
|
||||
#include "ras_p.h"
|
||||
#include "raw_p.h"
|
||||
#include "rgb_p.h"
|
||||
#include "sct_p.h"
|
||||
#include "tga_p.h"
|
||||
#include "xcf_p.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
int argc = 0;
|
||||
QCoreApplication a(argc, nullptr);
|
||||
|
||||
QImageIOHandler* handler = new HANDLER();
|
||||
|
||||
QImage i;
|
||||
QBuffer b;
|
||||
b.setData((const char *)data, size);
|
||||
b.open(QIODevice::ReadOnly);
|
||||
handler->setDevice(&b);
|
||||
handler->canRead();
|
||||
handler->read(&i);
|
||||
|
||||
delete handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash -eu
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2018 Google Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Based on https://github.com/google/oss-fuzz/blob/33aab4a70dc4b5811143d214536584a8c8cb3924/projects/kimageformats/Dockerfile
|
||||
# Copyright 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
apt-get update && \
|
||||
apt-get install -y cmake make autoconf automake autopoint libtool \
|
||||
wget po4a ninja-build pkgconf
|
||||
|
||||
git clone --depth 1 https://github.com/madler/zlib.git
|
||||
git clone --depth 1 -b v1.5.7 https://github.com/facebook/zstd.git
|
||||
wget https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
|
||||
git clone https://github.com/tukaani-project/xz.git
|
||||
git clone --depth 1 --branch=RB-3.3 https://github.com/AcademySoftwareFoundation/openexr.git
|
||||
git clone --depth 1 -b master https://invent.kde.org/frameworks/extra-cmake-modules.git
|
||||
git clone --depth 1 --branch=dev git://code.qt.io/qt/qtbase.git
|
||||
git clone --depth 1 --branch=dev git://code.qt.io/qt/qttools.git
|
||||
git clone --depth 1 -b master https://invent.kde.org/frameworks/karchive.git
|
||||
git clone --depth 1 -b v3.12.0 https://aomedia.googlesource.com/aom
|
||||
git clone --depth 1 -b v1.2.1 https://github.com/AOMediaCodec/libavif.git
|
||||
git clone --depth 1 https://github.com/strukturag/libde265.git
|
||||
git clone --depth 1 -b v2.5.3 https://github.com/uclouvain/openjpeg.git
|
||||
git clone --depth 1 https://github.com/strukturag/libheif.git
|
||||
git clone --depth=1 --branch v0.11.x --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
|
||||
git clone --depth 1 https://github.com/LibRaw/LibRaw
|
||||
git clone --depth 1 https://github.com/mircomir/jxrlib.git
|
||||
git clone --depth 1 -b v2.6.0 https://github.com/cisco/openh264.git
|
||||
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "ps_testcard_rgb_maya.png"
|
||||
}
|
||||
]
|
||||
@@ -1,31 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "metadata.png",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Author",
|
||||
"value" : "KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "Copyright",
|
||||
"value" : "@2025 KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "CreationDate",
|
||||
"value" : "2025-01-14T10:34:51"
|
||||
},
|
||||
{
|
||||
"key" : "Description",
|
||||
"value" : "TV broadcast test image."
|
||||
},
|
||||
{
|
||||
"key" : "Title",
|
||||
"value" : "Test Card"
|
||||
}
|
||||
],
|
||||
"resolution" : {
|
||||
"dotsPerMeterX" : 2835,
|
||||
"dotsPerMeterY" : 2835
|
||||
}
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "ps_testcard_rgb16_maya.png"
|
||||
}
|
||||
]
|
||||
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "ps_testcard_rgba16_maya.png"
|
||||
}
|
||||
]
|
||||
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "ps_testcard_rgb_maya.png"
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 226 KiB |
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation.png"
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 226 KiB |
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation.png"
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 80 KiB |
@@ -1,56 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "extarea.png",
|
||||
"skipSequential" : true,
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Author",
|
||||
"value" : "KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "Comment",
|
||||
"value" : "TV broadcast test image."
|
||||
},
|
||||
{
|
||||
"key" : "Altitude",
|
||||
"value" : "34"
|
||||
},
|
||||
{
|
||||
"key" : "Copyright",
|
||||
"value" : "@2025 KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "Latitude",
|
||||
"value" : "44.6478"
|
||||
},
|
||||
{
|
||||
"key" : "LensManufacturer",
|
||||
"value" : "KDE Glasses"
|
||||
},
|
||||
{
|
||||
"key" : "LensModel",
|
||||
"value" : "A1234"
|
||||
},
|
||||
{
|
||||
"key" : "Longitude",
|
||||
"value" : "10.9254"
|
||||
},
|
||||
{
|
||||
"key" : "Manufacturer",
|
||||
"value" : "KFramework"
|
||||
},
|
||||
{
|
||||
"key" : "Model",
|
||||
"value" : "KImageFormats"
|
||||
},
|
||||
{
|
||||
"key" : "Software",
|
||||
"value" : "LIFE Pro 2.18.30 (Linux)"
|
||||
}
|
||||
],
|
||||
"resolution" : {
|
||||
"dotsPerMeterX" : 11811,
|
||||
"dotsPerMeterY" : 5906
|
||||
}
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,32 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "extarea.png",
|
||||
"skipSequential" : true,
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "Title",
|
||||
"value" : "Test Card"
|
||||
},
|
||||
{
|
||||
"key" : "Author",
|
||||
"value" : "KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "ModificationDate",
|
||||
"value" : "2025-08-21T07:32:45"
|
||||
},
|
||||
{
|
||||
"key" : "Comment",
|
||||
"value" : "TV broadcast test image."
|
||||
},
|
||||
{
|
||||
"key" : "Software",
|
||||
"value" : "LIFE Pro 2.18.31 (Linux)"
|
||||
}
|
||||
],
|
||||
"resolution" : {
|
||||
"dotsPerMeterX" : 3937,
|
||||
"dotsPerMeterY" : 3937
|
||||
}
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 226 KiB |
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation.png"
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 226 KiB |
@@ -1,5 +0,0 @@
|
||||
[
|
||||
{
|
||||
"fileName" : "orientation.png"
|
||||
}
|
||||
]
|
||||
@@ -281,12 +281,6 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (seq && timg.skipSequentialDeviceTest()) {
|
||||
QTextStream(stdout) << "SKIP : " << fi.fileName() << ": marked to be skipped on a sequential device (don't worry, it's ok)\n";
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
|
||||
TemplateImage::TestFlags flags = TemplateImage::None;
|
||||
QString comment;
|
||||
QFileInfo expFileInfo = timg.compareImage(flags, comment);
|
||||
|
||||
@@ -76,15 +76,6 @@ bool TemplateImage::isLicense() const
|
||||
return !m_fi.suffix().compare(QStringLiteral("license"), Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool TemplateImage::skipSequentialDeviceTest() const
|
||||
{
|
||||
auto obj = searchObject(m_fi);
|
||||
if (obj.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return obj.value("skipSequential").toBool();
|
||||
}
|
||||
|
||||
QFileInfo TemplateImage::compareImage(TestFlags &flags, QString& comment) const
|
||||
{
|
||||
auto fi = jsonImage(flags, comment);
|
||||
|
||||
@@ -54,12 +54,6 @@ public:
|
||||
*/
|
||||
bool isLicense() const;
|
||||
|
||||
/*!
|
||||
* \brief skipSequentialDeviceTest
|
||||
* \return tre it the sequential test should be skipped.
|
||||
*/
|
||||
bool skipSequentialDeviceTest() const;
|
||||
|
||||
/*!
|
||||
* \brief compareImage
|
||||
* \param flags Flags for modifying test behavior (e.g. image format not supported by current Qt version).
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"format" : "tga",
|
||||
"subType" : "TGAv2E",
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "CreationDate",
|
||||
"value" : "2025-01-14T13:53:32+01:00"
|
||||
},
|
||||
{
|
||||
"key" : "Direction",
|
||||
"value" : "123.7"
|
||||
},
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "Adobe Photoshop 26.2 (Windows)"
|
||||
},
|
||||
{
|
||||
"key" : "Altitude",
|
||||
"value" : "34"
|
||||
},
|
||||
{
|
||||
"key" : "Author",
|
||||
"value" : "KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "Copyright",
|
||||
"value" : "@2025 KDE Project"
|
||||
},
|
||||
{
|
||||
"key" : "Description",
|
||||
"value" : "テレビ放送テスト映像。(TV broadcast test image.)"
|
||||
},
|
||||
{
|
||||
"key" : "Latitude",
|
||||
"value" : "44.6478"
|
||||
},
|
||||
{
|
||||
"key" : "LensManufacturer",
|
||||
"value" : "KDE Glasses"
|
||||
},
|
||||
{
|
||||
"key" : "LensModel",
|
||||
"value" : "A1234"
|
||||
},
|
||||
{
|
||||
"key" : "Longitude",
|
||||
"value" : "10.9254"
|
||||
},
|
||||
{
|
||||
"key" : "Manufacturer",
|
||||
"value" : "KFramework"
|
||||
},
|
||||
{
|
||||
"key" : "Model",
|
||||
"value" : "KImageFormats"
|
||||
}
|
||||
],
|
||||
"resolution" : {
|
||||
"dotsPerMeterX" : 11811,
|
||||
"dotsPerMeterY" : 11812
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 36 KiB |
@@ -70,15 +70,6 @@ void setOptionalInfo(QImage &image, const QString &suffix)
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray readSubType(const QString &suffix)
|
||||
{
|
||||
auto obj = readOptionalInfo(suffix);
|
||||
if (obj.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
return obj.value("subType").toString().toLatin1();
|
||||
}
|
||||
|
||||
bool checkOptionalInfo(QImage &image, const QString &suffix)
|
||||
{
|
||||
auto obj = readOptionalInfo(suffix);
|
||||
@@ -166,9 +157,6 @@ int basicTest(const QString &suffix, bool lossless, bool ignoreDataCheck, bool s
|
||||
{
|
||||
QBuffer buffer(&writtenData);
|
||||
QImageWriter imgWriter(&buffer, format.constData());
|
||||
auto subType = readSubType(suffix);
|
||||
if (!subType.isEmpty())
|
||||
imgWriter.setSubType(subType);
|
||||
if (lossless) {
|
||||
imgWriter.setQuality(100);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_iff SOURCES iff.cpp chunks.cpp microexif.cpp)
|
||||
kimageformats_add_plugin(kimg_iff SOURCES iff.cpp chunks.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
@@ -101,11 +101,11 @@ endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pcx SOURCES pcx.cpp scanlineconverter.cpp)
|
||||
kimageformats_add_plugin(kimg_pcx SOURCES pcx.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pic SOURCES pic.cpp scanlineconverter.cpp)
|
||||
kimageformats_add_plugin(kimg_pic SOURCES pic.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
@@ -129,7 +129,7 @@ kimageformats_add_plugin(kimg_ras SOURCES ras.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_rgb SOURCES rgb.cpp scanlineconverter.cpp)
|
||||
kimageformats_add_plugin(kimg_rgb SOURCES rgb.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
@@ -137,7 +137,7 @@ kimageformats_add_plugin(kimg_sct SOURCES sct.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp microexif.cpp scanlineconverter.cpp)
|
||||
kimageformats_add_plugin(kimg_tga SOURCES tga.cpp)
|
||||
|
||||
##################################
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QImage>
|
||||
#include <QImageIOHandler>
|
||||
#include <QImageIOPlugin>
|
||||
#include <QPointF>
|
||||
#include <QSize>
|
||||
#include <QVariant>
|
||||
#include <avif/avif.h>
|
||||
#include <qimageiohandler.h>
|
||||
|
||||
class QAVIFHandler : public QImageIOHandler
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
* Format specifications:
|
||||
* - https://wiki.amigaos.net/wiki/IFF_FORM_and_Chunk_Registry
|
||||
* - https://www.fileformat.info/format/iff/egff.htm
|
||||
* - https://download.autodesk.com/us/maya/2010help/index.html (Developer resources -> File formats -> Maya IFF)
|
||||
*/
|
||||
|
||||
#ifndef KIMG_CHUNKS_P_H
|
||||
@@ -19,15 +18,10 @@
|
||||
#include <QDateTime>
|
||||
#include <QImage>
|
||||
#include <QIODevice>
|
||||
#include <QLoggingCategory>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "microexif_p.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
|
||||
|
||||
// Main chunks (Standard)
|
||||
#define CAT__CHUNK QByteArray("CAT ")
|
||||
#define FILL_CHUNK QByteArray(" ")
|
||||
@@ -36,67 +30,29 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
|
||||
#define PROP_CHUNK QByteArray("PROP")
|
||||
|
||||
// Main chuncks (Maya)
|
||||
#define CAT4_CHUNK QByteArray("CAT4") // 4 byte alignment
|
||||
#define FOR4_CHUNK QByteArray("FOR4")
|
||||
#define LIS4_CHUNK QByteArray("LIS4")
|
||||
#define PRO4_CHUNK QByteArray("PRO4")
|
||||
|
||||
#define CAT8_CHUNK QByteArray("CAT8") // 8 byte alignment (never seen)
|
||||
#define FOR8_CHUNK QByteArray("FOR8")
|
||||
#define LIS8_CHUNK QByteArray("LIS8")
|
||||
#define PRO8_CHUNK QByteArray("PRO8")
|
||||
|
||||
// FORM ILBM IFF
|
||||
#define ABIT_CHUNK QByteArray("ABIT")
|
||||
#define BMHD_CHUNK QByteArray("BMHD")
|
||||
#define BODY_CHUNK QByteArray("BODY")
|
||||
#define CAMG_CHUNK QByteArray("CAMG")
|
||||
#define CMAP_CHUNK QByteArray("CMAP")
|
||||
#define CMYK_CHUNK QByteArray("CMYK") // https://wiki.amigaos.net/wiki/ILBM_IFF_Interleaved_Bitmap#ILBM.CMYK
|
||||
#define DPI__CHUNK QByteArray("DPI ")
|
||||
|
||||
// Different palette for scanline
|
||||
#define BEAM_CHUNK QByteArray("BEAM")
|
||||
#define CTBL_CHUNK QByteArray("CTBL") // same as BEAM
|
||||
#define PCHG_CHUNK QByteArray("PCHG") // encoded in a unknown way (to be investigated)
|
||||
#define RAST_CHUNK QByteArray("RAST") // Atari ST(E)
|
||||
#define SHAM_CHUNK QByteArray("SHAM")
|
||||
#define SHAM_CHUNK QByteArray("SHAM") // undocumented
|
||||
|
||||
// FOR4 CIMG IFF (Maya)
|
||||
#define RGBA_CHUNK QByteArray("RGBA")
|
||||
#define TBHD_CHUNK QByteArray("TBHD")
|
||||
|
||||
// FORx IFF (found on some IFF format specs)
|
||||
#define ANNO_CHUNK QByteArray("ANNO")
|
||||
#define AUTH_CHUNK QByteArray("AUTH")
|
||||
#define COPY_CHUNK QByteArray("(c) ")
|
||||
#define DATE_CHUNK QByteArray("DATE")
|
||||
#define EXIF_CHUNK QByteArray("EXIF") // https://aminet.net/package/docs/misc/IFF-metadata
|
||||
#define ICCN_CHUNK QByteArray("ICCN") // https://aminet.net/package/docs/misc/IFF-metadata
|
||||
#define ICCP_CHUNK QByteArray("ICCP") // https://aminet.net/package/docs/misc/IFF-metadata
|
||||
#define FVER_CHUNK QByteArray("FVER")
|
||||
#define HIST_CHUNK QByteArray("HIST")
|
||||
#define NAME_CHUNK QByteArray("NAME")
|
||||
#define VERS_CHUNK QByteArray("VERS")
|
||||
#define XMP0_CHUNK QByteArray("XMP0") // https://aminet.net/package/docs/misc/IFF-metadata
|
||||
|
||||
#define ACBM_FORM_TYPE QByteArray("ACBM")
|
||||
#define ILBM_FORM_TYPE QByteArray("ILBM")
|
||||
#define PBM__FORM_TYPE QByteArray("PBM ")
|
||||
#define RGB8_FORM_TYPE QByteArray("RGB8")
|
||||
#define RGBN_FORM_TYPE QByteArray("RGBN")
|
||||
|
||||
#define CIMG_FOR4_TYPE QByteArray("CIMG")
|
||||
#define TBMP_FOR4_TYPE QByteArray("TBMP")
|
||||
|
||||
#define CHUNKID_DEFINE(a) static QByteArray defaultChunkId() { return a; }
|
||||
|
||||
// The 8-bit RGB format must be one. If you change it here, you have also to use the same
|
||||
// when converting an image with BEAM/CTBL/SHAM chunks otherwise the option(QImageIOHandler::ImageFormat)
|
||||
// could returns a wrong value.
|
||||
// Warning: Changing it requires changing the algorithms. Se, don't touch! :)
|
||||
#define FORMAT_RGB_8BIT QImage::Format_RGB888
|
||||
|
||||
/*!
|
||||
* \brief The IFFChunk class
|
||||
*/
|
||||
@@ -239,18 +195,15 @@ public:
|
||||
template <class T>
|
||||
static QList<const T*> searchT(const IFFChunk *chunk) {
|
||||
QList<const T*> list;
|
||||
if (chunk == nullptr) {
|
||||
if (chunk == nullptr)
|
||||
return list;
|
||||
}
|
||||
auto cid = T::defaultChunkId();
|
||||
if (chunk->chunkId() == cid) {
|
||||
if (chunk->chunkId() == cid)
|
||||
if (auto c = dynamic_cast<const T*>(chunk))
|
||||
list << c;
|
||||
}
|
||||
auto tmp = chunk->chunks();
|
||||
for (auto &&c : tmp) {
|
||||
for (auto &&c : tmp)
|
||||
list << searchT<T>(c.data());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -263,9 +216,8 @@ public:
|
||||
template <class T>
|
||||
static QList<const T*> searchT(const ChunkList& chunks) {
|
||||
QList<const T*> list;
|
||||
for (auto &&chunk : chunks) {
|
||||
for (auto &&chunk : chunks)
|
||||
list << searchT<T>(chunk.data());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -284,14 +236,11 @@ protected:
|
||||
* \brief setAlignBytes
|
||||
* \param bytes
|
||||
*/
|
||||
void setAlignBytes(qint32 bytes);
|
||||
void setAlignBytes(qint32 bytes)
|
||||
{
|
||||
_align = bytes;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief nextChunkPos
|
||||
* Calculates the position of the next chunk. The position is already aligned.
|
||||
* \return The position of the next chunk from the beginning of the stream.
|
||||
*/
|
||||
qint64 nextChunkPos() const;
|
||||
|
||||
/*!
|
||||
* \brief cacheData
|
||||
@@ -331,7 +280,7 @@ protected:
|
||||
return qint32(ui32(c1, c2, c3, c4));
|
||||
}
|
||||
|
||||
static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr);
|
||||
static ChunkList innerFromDevice(QIODevice *d, bool *ok, qint32 alignBytes, qint32 recursionCnt);
|
||||
|
||||
private:
|
||||
char _chunkId[4];
|
||||
@@ -347,45 +296,20 @@ private:
|
||||
ChunkList _chunks;
|
||||
|
||||
qint32 _recursionCnt;
|
||||
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The IPALChunk class
|
||||
* Interface for additional per-line palette.
|
||||
*/
|
||||
class IPALChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~IPALChunk() override {}
|
||||
IPALChunk() : IFFChunk() {}
|
||||
virtual QList<QRgb> palette(qint32 y, qint32 height) const = 0;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The BMHDChunk class
|
||||
* \brief The IffBMHD class
|
||||
* Bitmap Header
|
||||
*/
|
||||
class BMHDChunk: public IFFChunk
|
||||
{
|
||||
public:
|
||||
enum Compression {
|
||||
Uncompressed = 0, /**< Image data are uncompressed. */
|
||||
Rle = 1, /**< Image data are RLE compressed. */
|
||||
RgbN8 = 4 /**< RGB8/RGBN compresson. */
|
||||
};
|
||||
enum Masking {
|
||||
None = 0, /**< Designates an opaque rectangular image. */
|
||||
HasMask = 1, /**< A mask plane is interleaved with the bitplanes in the BODY chunk. */
|
||||
HasTransparentColor = 2, /**< Pixels in the source planes matching transparentColor
|
||||
are to be considered “transparent”. (Actually, transparentColor
|
||||
isn’t a “color number” since it’s matched with numbers formed
|
||||
by the source bitmap rather than the possibly deeper destination
|
||||
bitmap. Note that having a transparent color implies ignoring
|
||||
one of the color registers. */
|
||||
Lasso = 3 /**< The reader may construct a mask by lassoing the image as in MacPaint.
|
||||
To do this, put a 1 pixel border of transparentColor around the image rectangle.
|
||||
Then do a seed fill from this border. Filled pixels are to be transparent. */
|
||||
Uncompressed = 0,
|
||||
Rle = 1
|
||||
};
|
||||
|
||||
virtual ~BMHDChunk() override;
|
||||
@@ -396,88 +320,34 @@ public:
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
/*!
|
||||
* \brief width
|
||||
* \return Width of the bitmap in pixels.
|
||||
*/
|
||||
qint32 width() const;
|
||||
|
||||
/*!
|
||||
* \brief height
|
||||
* \return Height of the bitmap in pixels.
|
||||
*/
|
||||
qint32 height() const;
|
||||
|
||||
/*!
|
||||
* \brief size
|
||||
* \return Size in pixels.
|
||||
*/
|
||||
QSize size() const;
|
||||
|
||||
/*!
|
||||
* \brief left
|
||||
* \return The left position of the image.
|
||||
*/
|
||||
qint32 left() const;
|
||||
|
||||
/*!
|
||||
* \brief top
|
||||
* \return The top position of the image.
|
||||
*/
|
||||
qint32 top() const;
|
||||
|
||||
/*!
|
||||
* \brief bitplanes
|
||||
* \return The number of bit planes.
|
||||
*/
|
||||
quint8 bitplanes() const;
|
||||
|
||||
/*!
|
||||
* \brief masking
|
||||
* \return Kind of masking is to be used for this image.
|
||||
*/
|
||||
Masking masking() const;
|
||||
quint8 masking() const;
|
||||
|
||||
/*!
|
||||
* \brief compression
|
||||
* \return The type of compression used.
|
||||
*/
|
||||
Compression compression() const;
|
||||
|
||||
/*!
|
||||
* \brief transparency
|
||||
* \return Transparent "color number".
|
||||
*/
|
||||
quint8 padding() const;
|
||||
|
||||
qint16 transparency() const;
|
||||
|
||||
/*!
|
||||
* \brief xAspectRatio
|
||||
* \return X pixel aspect.
|
||||
*/
|
||||
quint8 xAspectRatio() const;
|
||||
|
||||
/*!
|
||||
* \brief yAspectRatio
|
||||
* \return Y pixel aspect.
|
||||
*/
|
||||
quint8 yAspectRatio() const;
|
||||
|
||||
/*!
|
||||
* \brief pageWidth
|
||||
* \return Source "page" width in pixels.
|
||||
*/
|
||||
quint16 pageWidth() const;
|
||||
|
||||
/*!
|
||||
* \brief pageHeight
|
||||
* \return Source "page" height in pixels.
|
||||
*/
|
||||
quint16 pageHeight() const;
|
||||
|
||||
/*!
|
||||
* \brief rowLen
|
||||
* \return The row len of a plane.
|
||||
*/
|
||||
quint32 rowLen() const;
|
||||
|
||||
CHUNKID_DEFINE(BMHD_CHUNK)
|
||||
@@ -499,64 +369,14 @@ public:
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
/*!
|
||||
* \brief count
|
||||
* \return The number of color in the palette.
|
||||
*/
|
||||
virtual qint32 count() const;
|
||||
|
||||
/*!
|
||||
* \brief palette
|
||||
* \param halfbride When True, the new palette values are appended using the halfbride method.
|
||||
* \return The color palette.
|
||||
* \note If \a halfbride is true, the returned palette size is count() * 2.
|
||||
*/
|
||||
QList<QRgb> palette(bool halfbride = false) const;
|
||||
QList<QRgb> palette() const;
|
||||
|
||||
CHUNKID_DEFINE(CMAP_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual QList<QRgb> innerPalette() const;
|
||||
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The CMYKChunk class
|
||||
*
|
||||
* This chunk would allow color specification in terms of Cyan,
|
||||
* Magenta, Yellow, and Black as opposed to the current CMAP which uses RGB.
|
||||
* The format would be the same as the CMAP chunk with the exception that this
|
||||
* chunk uses four color components as opposed to three. The number of colors
|
||||
* contained within would be chunk length/4. This chunk would be used in addition
|
||||
* to the CMAP chunk.
|
||||
*/
|
||||
class CMYKChunk : public CMAPChunk
|
||||
{
|
||||
public:
|
||||
virtual ~CMYKChunk() override;
|
||||
CMYKChunk();
|
||||
CMYKChunk(const CMYKChunk& other) = default;
|
||||
CMYKChunk& operator =(const CMYKChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
/*!
|
||||
* \brief count
|
||||
* \return The number of color in the palette.
|
||||
*/
|
||||
virtual qint32 count() const override;
|
||||
|
||||
CHUNKID_DEFINE(CMYK_CHUNK)
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief palette
|
||||
* \return The CMYK color palette converted to RGB one.
|
||||
*/
|
||||
virtual QList<QRgb> innerPalette() const override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The CAMGChunk class
|
||||
*/
|
||||
@@ -631,6 +451,7 @@ protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
class FORMChunk;
|
||||
|
||||
/*!
|
||||
* \brief The BODYChunk class
|
||||
@@ -651,151 +472,42 @@ public:
|
||||
* \brief readStride
|
||||
* \param d The device.
|
||||
* \param header The bitmap header.
|
||||
* \param y The current scanline.
|
||||
* \param camg The CAMG chunk (optional)
|
||||
* \param cmap The CMAP chunk (optional)
|
||||
* \param formType The type of the current form chunk.
|
||||
* \return The scanline as requested for QImage.
|
||||
* \warning Call resetStrideRead() once before this one.
|
||||
*/
|
||||
virtual QByteArray strideRead(QIODevice *d,
|
||||
qint32 y,
|
||||
const BMHDChunk *header,
|
||||
const CAMGChunk *camg = nullptr,
|
||||
const CMAPChunk *cmap = nullptr,
|
||||
const IPALChunk *ipal = nullptr,
|
||||
const QByteArray& formType = ILBM_FORM_TYPE) const;
|
||||
QByteArray strideRead(QIODevice *d, const FORMChunk *form, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr) const;
|
||||
|
||||
/*!
|
||||
* \brief resetStrideRead
|
||||
* Reset the stride read set the position at the beginning of the data and reset all buffers.
|
||||
* \param d The device.
|
||||
* \param d The device
|
||||
* \param header The BMHDChunk chunk (mandatory)
|
||||
* \param camg The CAMG chunk (optional)
|
||||
* \return True on success, otherwise false.
|
||||
* \sa strideRead
|
||||
* \note Must be called once before strideRead().
|
||||
*/
|
||||
virtual bool resetStrideRead(QIODevice *d) const;
|
||||
|
||||
/*!
|
||||
* \brief safeModeId
|
||||
* \param header The header.
|
||||
* \param camg The CAMG chunk.
|
||||
* \return The most likely ModeId if not explicitly specified.
|
||||
*/
|
||||
static CAMGChunk::ModeIds safeModeId(const BMHDChunk *header, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief strideSize
|
||||
* \param formType The type of the current form chunk.
|
||||
* \return The size of data to have to decode an image row.
|
||||
*/
|
||||
quint32 strideSize(const BMHDChunk *header, const QByteArray& formType) const;
|
||||
|
||||
QByteArray deinterleave(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
|
||||
|
||||
QByteArray pbm(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
|
||||
|
||||
QByteArray rgb8(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
|
||||
|
||||
QByteArray rgbN(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
|
||||
bool resetStrideRead(QIODevice *d) const;
|
||||
|
||||
private:
|
||||
static QByteArray deinterleave(const QByteArray &planes, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr);
|
||||
|
||||
mutable QByteArray _readBuffer;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The ABITChunk class
|
||||
*/
|
||||
class ABITChunk : public BODYChunk
|
||||
{
|
||||
public:
|
||||
virtual ~ABITChunk() override;
|
||||
ABITChunk();
|
||||
ABITChunk(const ABITChunk& other) = default;
|
||||
ABITChunk& operator =(const ABITChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
CHUNKID_DEFINE(ABIT_CHUNK)
|
||||
|
||||
virtual QByteArray strideRead(QIODevice *d,
|
||||
qint32 y,
|
||||
const BMHDChunk *header,
|
||||
const CAMGChunk *camg = nullptr,
|
||||
const CMAPChunk *cmap = nullptr,
|
||||
const IPALChunk *ipal = nullptr,
|
||||
const QByteArray& formType = ACBM_FORM_TYPE) const override;
|
||||
|
||||
virtual bool resetStrideRead(QIODevice *d) const override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The IFOR_Chunk class
|
||||
* Interface for FORM chunks.
|
||||
*/
|
||||
class IFOR_Chunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~IFOR_Chunk() override;
|
||||
IFOR_Chunk();
|
||||
|
||||
/*!
|
||||
* \brief isSupported
|
||||
* \return True if the form is supported by the plugin.
|
||||
*/
|
||||
virtual bool isSupported() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief formType
|
||||
* \return The type of image data contained in the form.
|
||||
*/
|
||||
virtual QByteArray formType() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief format
|
||||
* \return The Qt image format the form is converted to.
|
||||
*/
|
||||
virtual QImage::Format format() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief transformation
|
||||
* \return The image transformation.
|
||||
* \note The Default implentation returns the trasformation of EXIF chunk (if any).
|
||||
*/
|
||||
virtual QImageIOHandler::Transformation transformation() const;
|
||||
|
||||
/*!
|
||||
* \brief size
|
||||
* \return The image size in pixels.
|
||||
*/
|
||||
virtual QSize size() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief optionformat
|
||||
* \return The format retuned by the plugin after all conversions.
|
||||
*/
|
||||
QImage::Format optionformat() const;
|
||||
|
||||
/*!
|
||||
* \brief searchIPal
|
||||
* Search the palett per line chunk.
|
||||
* \return The per line palette (BEAM, CTBL, SHAM, etc....).
|
||||
*/
|
||||
const IPALChunk *searchIPal() const;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The FORMChunk class
|
||||
*/
|
||||
class FORMChunk : public IFOR_Chunk
|
||||
class FORMChunk : public IFFChunk
|
||||
{
|
||||
QByteArray _type;
|
||||
|
||||
public:
|
||||
enum class FormType {
|
||||
Unknown,
|
||||
Ilbm,
|
||||
Pbm,
|
||||
};
|
||||
|
||||
virtual ~FORMChunk() override;
|
||||
FORMChunk();
|
||||
FORMChunk(const FORMChunk& other) = default;
|
||||
@@ -803,25 +515,27 @@ public:
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
virtual bool isSupported() const override;
|
||||
bool isSupported() const;
|
||||
|
||||
virtual QByteArray formType() const override;
|
||||
FormType formType() const;
|
||||
|
||||
virtual QImage::Format format() const override;
|
||||
QImage::Format format() const;
|
||||
|
||||
virtual QSize size() const override;
|
||||
QSize size() const;
|
||||
|
||||
CHUNKID_DEFINE(FORM_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
private:
|
||||
FormType _type = FormType::Unknown;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The FOR4Chunk class
|
||||
*/
|
||||
class FOR4Chunk : public IFOR_Chunk
|
||||
class FOR4Chunk : public IFFChunk
|
||||
{
|
||||
QByteArray _type;
|
||||
|
||||
@@ -835,13 +549,13 @@ public:
|
||||
|
||||
virtual qint32 alignBytes() const override;
|
||||
|
||||
virtual bool isSupported() const override;
|
||||
bool isSupported() const;
|
||||
|
||||
virtual QByteArray formType() const override;
|
||||
QByteArray formType() const;
|
||||
|
||||
virtual QImage::Format format() const override;
|
||||
QImage::Format format() const;
|
||||
|
||||
virtual QSize size() const override;
|
||||
QSize size() const;
|
||||
|
||||
CHUNKID_DEFINE(FOR4_CHUNK)
|
||||
|
||||
@@ -849,29 +563,6 @@ protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The CATChunk class
|
||||
*/
|
||||
class CATChunk : public IFFChunk
|
||||
{
|
||||
QByteArray _type;
|
||||
|
||||
public:
|
||||
virtual ~CATChunk() override;
|
||||
CATChunk();
|
||||
CATChunk(const CATChunk& other) = default;
|
||||
CATChunk& operator =(const CATChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QByteArray catType() const;
|
||||
|
||||
CHUNKID_DEFINE(CAT__CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The TBHDChunk class
|
||||
*/
|
||||
@@ -879,11 +570,12 @@ class TBHDChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
enum Flag {
|
||||
Rgb = 0x01, /**< RGB image */
|
||||
Alpha = 0x02, /**< Image contains alpha channel */
|
||||
ZBuffer = 0x04, /**< If the image has a z-buffer, it is described by ZBUF blocks with the same structure as the RGBA blocks, RLE encoded. */
|
||||
Rgb = 0x01,
|
||||
Alpha = 0x02,
|
||||
ZBuffer = 0x04,
|
||||
Black = 0x10,
|
||||
|
||||
RgbA = Rgb | Alpha /**< RGBA image */
|
||||
RgbA = Rgb | Alpha
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
@@ -1030,33 +722,13 @@ private:
|
||||
QByteArray readStride(QIODevice *d, const TBHDChunk *header) const;
|
||||
|
||||
private:
|
||||
QPoint _posPx;
|
||||
QPoint _pos;
|
||||
|
||||
QSize _sizePx;
|
||||
QSize _size;
|
||||
|
||||
mutable QByteArray _readBuffer;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The ANNOChunk class
|
||||
*/
|
||||
class ANNOChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~ANNOChunk() override;
|
||||
ANNOChunk();
|
||||
ANNOChunk(const ANNOChunk& other) = default;
|
||||
ANNOChunk& operator =(const ANNOChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QString value() const;
|
||||
|
||||
CHUNKID_DEFINE(ANNO_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The AUTHChunk class
|
||||
@@ -1079,27 +751,6 @@ protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The COPYChunk class
|
||||
*/
|
||||
class COPYChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~COPYChunk() override;
|
||||
COPYChunk();
|
||||
COPYChunk(const COPYChunk& other) = default;
|
||||
COPYChunk& operator =(const COPYChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QString value() const;
|
||||
|
||||
CHUNKID_DEFINE(COPY_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The DATEChunk class
|
||||
*/
|
||||
@@ -1121,71 +772,6 @@ protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The EXIFChunk class
|
||||
*/
|
||||
class EXIFChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~EXIFChunk() override;
|
||||
EXIFChunk();
|
||||
EXIFChunk(const EXIFChunk& other) = default;
|
||||
EXIFChunk& operator =(const EXIFChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
MicroExif value() const;
|
||||
|
||||
CHUNKID_DEFINE(EXIF_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The NAMEChunk class
|
||||
*/
|
||||
class ICCNChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~ICCNChunk() override;
|
||||
ICCNChunk();
|
||||
ICCNChunk(const ICCNChunk& other) = default;
|
||||
ICCNChunk& operator =(const ICCNChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QString value() const;
|
||||
|
||||
CHUNKID_DEFINE(ICCN_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The ICCPChunk class
|
||||
*/
|
||||
class ICCPChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~ICCPChunk() override;
|
||||
ICCPChunk();
|
||||
ICCPChunk(const ICCPChunk& other) = default;
|
||||
ICCPChunk& operator =(const ICCPChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QColorSpace value() const;
|
||||
|
||||
CHUNKID_DEFINE(ICCP_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The FVERChunk class
|
||||
*
|
||||
@@ -1230,27 +816,6 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The NAMEChunk class
|
||||
*/
|
||||
class NAMEChunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~NAMEChunk() override;
|
||||
NAMEChunk();
|
||||
NAMEChunk(const NAMEChunk& other) = default;
|
||||
NAMEChunk& operator =(const NAMEChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QString value() const;
|
||||
|
||||
CHUNKID_DEFINE(NAME_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The VERSChunk class
|
||||
*/
|
||||
@@ -1272,114 +837,4 @@ protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief The XMP0Chunk class
|
||||
*/
|
||||
class XMP0Chunk : public IFFChunk
|
||||
{
|
||||
public:
|
||||
virtual ~XMP0Chunk() override;
|
||||
XMP0Chunk();
|
||||
XMP0Chunk(const XMP0Chunk& other) = default;
|
||||
XMP0Chunk& operator =(const XMP0Chunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
QString value() const;
|
||||
|
||||
CHUNKID_DEFINE(XMP0_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* *** UNDOCUMENTED CHUNKS ***
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief The BEAMChunk class
|
||||
*/
|
||||
class BEAMChunk : public IPALChunk
|
||||
{
|
||||
public:
|
||||
virtual ~BEAMChunk() override;
|
||||
BEAMChunk();
|
||||
BEAMChunk(const BEAMChunk& other) = default;
|
||||
BEAMChunk& operator =(const BEAMChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
virtual QList<QRgb> palette(qint32 y, qint32 height) const override;
|
||||
|
||||
CHUNKID_DEFINE(BEAM_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The CTBLChunk class
|
||||
*/
|
||||
class CTBLChunk : public BEAMChunk
|
||||
{
|
||||
public:
|
||||
virtual ~CTBLChunk() override;
|
||||
CTBLChunk();
|
||||
CTBLChunk(const CTBLChunk& other) = default;
|
||||
CTBLChunk& operator =(const CTBLChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
CHUNKID_DEFINE(CTBL_CHUNK)
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The SHAMChunk class
|
||||
*/
|
||||
class SHAMChunk : public IPALChunk
|
||||
{
|
||||
public:
|
||||
virtual ~SHAMChunk() override;
|
||||
SHAMChunk();
|
||||
SHAMChunk(const SHAMChunk& other) = default;
|
||||
SHAMChunk& operator =(const SHAMChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
virtual QList<QRgb> palette(qint32 y, qint32 height) const override;
|
||||
|
||||
CHUNKID_DEFINE(SHAM_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The RASTChunk class
|
||||
* \note I found an Atari STE image with the RAST chunk outside
|
||||
* the form chunk (Fish.neo.iff). To support it the IFF parser
|
||||
* should be changed so, this kind of IFFs are shown wrong.
|
||||
*/
|
||||
class RASTChunk : public IPALChunk
|
||||
{
|
||||
public:
|
||||
virtual ~RASTChunk() override;
|
||||
RASTChunk();
|
||||
RASTChunk(const RASTChunk& other) = default;
|
||||
RASTChunk& operator =(const RASTChunk& other) = default;
|
||||
|
||||
virtual bool isValid() const override;
|
||||
|
||||
virtual QList<QRgb> palette(qint32 y, qint32 height) const override;
|
||||
|
||||
CHUNKID_DEFINE(RAST_CHUNK)
|
||||
|
||||
protected:
|
||||
virtual bool innerReadStructure(QIODevice *d) override;
|
||||
};
|
||||
|
||||
|
||||
#endif // KIMG_CHUNKS_P_H
|
||||
|
||||
@@ -1126,11 +1126,7 @@ static QImage readR32F(QDataStream &s, const quint32 width, const quint32 height
|
||||
for (quint32 y = 0; y < height; y++) {
|
||||
float *line = reinterpret_cast<float *>(image.scanLine(y));
|
||||
for (quint32 x = 0; x < width; x++) {
|
||||
const float f = readFloat32(s);
|
||||
if (std::isnan(f)) {
|
||||
return {};
|
||||
}
|
||||
line[x * 4] = f;
|
||||
line[x * 4] = readFloat32(s);
|
||||
line[x * 4 + 1] = 0;
|
||||
line[x * 4 + 2] = 0;
|
||||
line[x * 4 + 3] = 1;
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "exr_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
/* *** EXR_CONVERT_TO_SRGB ***
|
||||
* If defined, the linear data is converted to sRGB on read to accommodate
|
||||
* programs that do not support color profiles.
|
||||
@@ -32,7 +28,7 @@
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef EXR_MAX_IMAGE_WIDTH
|
||||
#define EXR_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#define EXR_MAX_IMAGE_WIDTH 300000
|
||||
#endif
|
||||
#ifndef EXR_MAX_IMAGE_HEIGHT
|
||||
#define EXR_MAX_IMAGE_HEIGHT EXR_MAX_IMAGE_WIDTH
|
||||
@@ -54,6 +50,10 @@
|
||||
#define EXR_LINES_PER_BLOCK 128
|
||||
#endif
|
||||
|
||||
#include "exr_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <IexThrowErrnoExc.h>
|
||||
#include <ImathBox.h>
|
||||
#include <ImfArray.h>
|
||||
|
||||
@@ -23,16 +23,6 @@
|
||||
*/
|
||||
//#define HDR_HALF_QUALITY // default commented -> you should define it in your cmake file
|
||||
|
||||
/* *** HDR_MAX_IMAGE_WIDTH and HDR_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef HDR_MAX_IMAGE_WIDTH
|
||||
#define HDR_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef HDR_MAX_IMAGE_HEIGHT
|
||||
#define HDR_MAX_IMAGE_HEIGHT HDR_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
Q_LOGGING_CATEGORY(HDRPLUGIN, "kf.imageformats.plugins.hdr", QtWarningMsg)
|
||||
@@ -52,10 +42,7 @@ public:
|
||||
Header(const Header&) = default;
|
||||
Header& operator=(const Header&) = default;
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return width() > 0 && height() > 0 && width() <= HDR_MAX_IMAGE_WIDTH && height() <= HDR_MAX_IMAGE_HEIGHT;
|
||||
}
|
||||
bool isValid() const { return width() > 0 && height() > 0; }
|
||||
qint32 width() const { return(m_size.width()); }
|
||||
qint32 height() const { return(m_size.height()); }
|
||||
QString software() const { return(m_software); }
|
||||
|
||||
@@ -11,43 +11,40 @@
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
#include <QPainter>
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
Q_LOGGING_CATEGORY(LOG_IFFPLUGIN, "kf.imageformats.plugins.iff", QtInfoMsg)
|
||||
#else
|
||||
Q_LOGGING_CATEGORY(LOG_IFFPLUGIN, "kf.imageformats.plugins.iff", QtWarningMsg)
|
||||
#endif
|
||||
|
||||
class IFFHandlerPrivate
|
||||
{
|
||||
public:
|
||||
IFFHandlerPrivate()
|
||||
: m_imageNumber(0)
|
||||
, m_imageCount(0)
|
||||
{
|
||||
IFFHandlerPrivate() {}
|
||||
~IFFHandlerPrivate() {}
|
||||
|
||||
}
|
||||
~IFFHandlerPrivate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool readStructure(QIODevice *d)
|
||||
{
|
||||
bool readStructure(QIODevice *d) {
|
||||
if (d == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_chunks.isEmpty()) {
|
||||
if (!_chunks.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto ok = false;
|
||||
auto chunks = IFFChunk::fromDevice(d, &ok);
|
||||
if (ok) {
|
||||
m_chunks = chunks;
|
||||
_chunks = chunks;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static QList<const T*> searchForms(const IFFChunk::ChunkList &chunks, bool supportedOnly = true)
|
||||
{
|
||||
static QList<const T*> searchForms(const IFFChunk::ChunkList &chunks, bool supportedOnly = true) {
|
||||
QList<const T*> list;
|
||||
auto cid = T::defaultChunkId();
|
||||
auto forms = IFFChunk::search(cid, chunks);
|
||||
@@ -60,25 +57,11 @@ public:
|
||||
}
|
||||
|
||||
template <class T>
|
||||
QList<const T*> searchForms(bool supportedOnly = true)
|
||||
{
|
||||
return searchForms<T>(m_chunks, supportedOnly);
|
||||
QList<const T*> searchForms(bool supportedOnly = true) {
|
||||
return searchForms<T>(_chunks, supportedOnly);
|
||||
}
|
||||
|
||||
IFFChunk::ChunkList m_chunks;
|
||||
|
||||
/*!
|
||||
* \brief m_imageNumber
|
||||
* Value set by QImageReader::jumpToImage() or QImageReader::jumpToNextImage().
|
||||
* The number of view selected in a multiview image.
|
||||
*/
|
||||
qint32 m_imageNumber;
|
||||
|
||||
/*!
|
||||
* \brief m_imageCount
|
||||
* The total number of views (cache value)
|
||||
*/
|
||||
mutable qint32 m_imageCount;
|
||||
IFFChunk::ChunkList _chunks;
|
||||
};
|
||||
|
||||
|
||||
@@ -86,13 +69,12 @@ IFFHandler::IFFHandler()
|
||||
: QImageIOHandler()
|
||||
, d(new IFFHandlerPrivate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool IFFHandler::canRead() const
|
||||
{
|
||||
if (canRead(device())) {
|
||||
setFormat("iff");
|
||||
setFormat("iff"); // TODO ilbm based on header?
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -109,17 +91,6 @@ bool IFFHandler::canRead(QIODevice *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
// I avoid parsing obviously incorrect files
|
||||
auto cid = device->peek(4);
|
||||
if (cid != CAT__CHUNK &&
|
||||
cid != FORM_CHUNK &&
|
||||
cid != LIST_CHUNK &&
|
||||
cid != CAT4_CHUNK &&
|
||||
cid != FOR4_CHUNK &&
|
||||
cid != LIS4_CHUNK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ok = false;
|
||||
auto pos = device->pos();
|
||||
auto chunks = IFFChunk::fromDevice(device, &ok);
|
||||
@@ -134,14 +105,13 @@ bool IFFHandler::canRead(QIODevice *device)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void addMetadata(QImage &img, const IFOR_Chunk *form)
|
||||
void addMetadata(QImage& img, const IFFChunk *form)
|
||||
{
|
||||
// standard IFF metadata
|
||||
auto annos = IFFChunk::searchT<ANNOChunk>(form);
|
||||
if (!annos.isEmpty()) {
|
||||
auto anno = annos.first()->value();
|
||||
if (!anno.isEmpty()) {
|
||||
img.setText(QStringLiteral(META_KEY_DESCRIPTION), anno);
|
||||
auto dates = IFFChunk::searchT<DATEChunk>(form);
|
||||
if (!dates.isEmpty()) {
|
||||
auto dt = dates.first()->value();
|
||||
if (dt.isValid()) {
|
||||
img.setText(QStringLiteral(META_KEY_CREATIONDATE), dt.toString(Qt::ISODate));
|
||||
}
|
||||
}
|
||||
auto auths = IFFChunk::searchT<AUTHChunk>(form);
|
||||
@@ -151,29 +121,6 @@ static void addMetadata(QImage &img, const IFOR_Chunk *form)
|
||||
img.setText(QStringLiteral(META_KEY_AUTHOR), auth);
|
||||
}
|
||||
}
|
||||
auto dates = IFFChunk::searchT<DATEChunk>(form);
|
||||
if (!dates.isEmpty()) {
|
||||
auto dt = dates.first()->value();
|
||||
if (dt.isValid()) {
|
||||
img.setText(QStringLiteral(META_KEY_CREATIONDATE), dt.toString(Qt::ISODate));
|
||||
}
|
||||
}
|
||||
auto copys = IFFChunk::searchT<COPYChunk>(form);
|
||||
if (!copys.isEmpty()) {
|
||||
auto cp = copys.first()->value();
|
||||
if (!cp.isEmpty()) {
|
||||
img.setText(QStringLiteral(META_KEY_COPYRIGHT), cp);
|
||||
}
|
||||
}
|
||||
auto names = IFFChunk::searchT<NAMEChunk>(form);
|
||||
if (!names.isEmpty()) {
|
||||
auto name = names.first()->value();
|
||||
if (!name.isEmpty()) {
|
||||
img.setText(QStringLiteral(META_KEY_TITLE), name);
|
||||
}
|
||||
}
|
||||
|
||||
// software info
|
||||
auto vers = IFFChunk::searchT<VERSChunk>(form);
|
||||
if (!vers.isEmpty()) {
|
||||
auto ver = vers.first()->value();
|
||||
@@ -181,98 +128,6 @@ static void addMetadata(QImage &img, const IFOR_Chunk *form)
|
||||
img.setText(QStringLiteral(META_KEY_SOFTWARE), ver);
|
||||
}
|
||||
}
|
||||
|
||||
// SView5 metadata
|
||||
auto resChanged = false;
|
||||
auto exifs = IFFChunk::searchT<EXIFChunk>(form);
|
||||
if (!exifs.isEmpty()) {
|
||||
auto exif = exifs.first()->value();
|
||||
exif.updateImageMetadata(img, false);
|
||||
resChanged = exif.updateImageResolution(img);
|
||||
}
|
||||
|
||||
auto xmp0s = IFFChunk::searchT<XMP0Chunk>(form);
|
||||
if (!xmp0s.isEmpty()) {
|
||||
auto xmp = xmp0s.first()->value();
|
||||
if (!xmp.isEmpty()) {
|
||||
img.setText(QStringLiteral(META_KEY_XMP_ADOBE), xmp);
|
||||
}
|
||||
}
|
||||
|
||||
auto iccps = IFFChunk::searchT<ICCPChunk>(form);
|
||||
if (!iccps.isEmpty()) {
|
||||
auto cs = iccps.first()->value();
|
||||
if (cs.isValid()) {
|
||||
auto iccns = IFFChunk::searchT<ICCNChunk>(form);
|
||||
if (!iccns.isEmpty()) {
|
||||
auto desc = iccns.first()->value();
|
||||
if (!desc.isEmpty())
|
||||
cs.setDescription(desc);
|
||||
}
|
||||
img.setColorSpace(cs);
|
||||
}
|
||||
}
|
||||
|
||||
// resolution -> leave after set of EXIF chunk
|
||||
auto dpis = IFFChunk::searchT<DPIChunk>(form);
|
||||
if (!dpis.isEmpty()) {
|
||||
auto &&dpi = dpis.first();
|
||||
if (dpi->isValid()) {
|
||||
img.setDotsPerMeterX(dpi->dotsPerMeterX());
|
||||
img.setDotsPerMeterY(dpi->dotsPerMeterY());
|
||||
resChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if no explicit resolution was found, apply the aspect ratio to the default one
|
||||
if (!resChanged) {
|
||||
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
||||
if (!headers.isEmpty()) {
|
||||
auto xr = headers.first()->xAspectRatio();
|
||||
auto yr = headers.first()->yAspectRatio();
|
||||
if (xr > 0 && yr > 0 && xr > yr) {
|
||||
img.setDotsPerMeterX(img.dotsPerMeterX() * yr / xr);
|
||||
} else if (xr > 0 && yr > 0 && xr < yr) {
|
||||
img.setDotsPerMeterY(img.dotsPerMeterY() * xr / yr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief convertIPAL
|
||||
* \param img The source image.
|
||||
* \param ipal The per line palette.
|
||||
* \return The new image converted or \a img if no conversion is needed or possible.
|
||||
*/
|
||||
static QImage convertIPAL(const QImage& img, const IPALChunk *ipal)
|
||||
{
|
||||
if (img.format() != QImage::Format_Indexed8) {
|
||||
qDebug(LOG_IFFPLUGIN) << "convertIPAL(): the image is not indexed!";
|
||||
return img;
|
||||
}
|
||||
|
||||
auto tmp = img.convertToFormat(FORMAT_RGB_8BIT);
|
||||
if (tmp.isNull()) {
|
||||
qCritical(LOG_IFFPLUGIN) << "convertIPAL(): error while converting the image!";
|
||||
return img;
|
||||
}
|
||||
|
||||
for (auto y = 0, h = img.height(); y < h; ++y) {
|
||||
auto src = reinterpret_cast<const quint8 *>(img.constScanLine(y));
|
||||
auto dst = tmp.scanLine(y);
|
||||
auto lpal = ipal->palette(y, h);
|
||||
for (auto x = 0, w = img.width(); x < w; ++x) {
|
||||
if (src[x] < lpal.size()) {
|
||||
auto x3 = x * 3;
|
||||
dst[x3] = qRed(lpal.at(src[x]));
|
||||
dst[x3 + 1] = qGreen(lpal.at(src[x]));
|
||||
dst[x3 + 2] = qBlue(lpal.at(src[x]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool IFFHandler::readStandardImage(QImage *image)
|
||||
@@ -281,8 +136,7 @@ bool IFFHandler::readStandardImage(QImage *image)
|
||||
if (forms.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
auto cin = qBound(0, currentImageNumber(), int(forms.size() - 1));
|
||||
auto &&form = forms.at(cin);
|
||||
auto &&form = forms.first();
|
||||
|
||||
// show the first one (I don't have a sample with many images)
|
||||
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
||||
@@ -299,41 +153,38 @@ bool IFFHandler::readStandardImage(QImage *image)
|
||||
return false;
|
||||
}
|
||||
|
||||
// set color table
|
||||
const CAMGChunk *camg = nullptr;
|
||||
auto camgs = IFFChunk::searchT<CAMGChunk>(form);
|
||||
if (!camgs.isEmpty()) {
|
||||
camg = camgs.first();
|
||||
}
|
||||
|
||||
const CMAPChunk *cmap = nullptr;
|
||||
auto cmaps = IFFChunk::searchT<CMAPChunk>(form);
|
||||
if (cmaps.isEmpty()) {
|
||||
auto cmyks = IFFChunk::searchT<CMYKChunk>(form);
|
||||
for (auto &&cmyk : cmyks)
|
||||
cmaps.append(cmyk);
|
||||
}
|
||||
if (!cmaps.isEmpty()) {
|
||||
cmap = cmaps.first();
|
||||
}
|
||||
if (img.format() == QImage::Format_Indexed8) {
|
||||
if (cmap) {
|
||||
auto halfbride = BODYChunk::safeModeId(header, camg, cmap) & CAMGChunk::ModeId::HalfBrite ? true : false;
|
||||
img.setColorTable(cmap->palette(halfbride));
|
||||
// resolution
|
||||
auto dpis = IFFChunk::searchT<DPIChunk>(form);
|
||||
if (!dpis.isEmpty()) {
|
||||
auto &&dpi = dpis.first();
|
||||
if (dpi->isValid()) {
|
||||
img.setDotsPerMeterX(dpi->dotsPerMeterX());
|
||||
img.setDotsPerMeterY(dpi->dotsPerMeterY());
|
||||
}
|
||||
}
|
||||
|
||||
// reading image data
|
||||
auto ipal = form->searchIPal();
|
||||
auto bodies = IFFChunk::searchT<BODYChunk>(form);
|
||||
if (bodies.isEmpty()) {
|
||||
auto abits = IFFChunk::searchT<ABITChunk>(form);
|
||||
for (auto &&abit : abits)
|
||||
bodies.append(abit);
|
||||
// set color table
|
||||
auto cmaps = IFFChunk::searchT<CMAPChunk>(form);
|
||||
if (img.format() == QImage::Format_Indexed8) {
|
||||
if (!cmaps.isEmpty())
|
||||
if (auto &&cmap = cmaps.first())
|
||||
img.setColorTable(cmap->palette());
|
||||
}
|
||||
|
||||
auto bodies = IFFChunk::searchT<BODYChunk>(form);
|
||||
if (bodies.isEmpty()) {
|
||||
img.fill(0);
|
||||
} else {
|
||||
const CAMGChunk *camg = nullptr;
|
||||
auto camgs = IFFChunk::searchT<CAMGChunk>(form);
|
||||
if (!camgs.isEmpty()) {
|
||||
camg = camgs.first();
|
||||
}
|
||||
|
||||
const CMAPChunk *cmap = nullptr;
|
||||
if (!cmaps.isEmpty())
|
||||
cmap = cmaps.first();
|
||||
|
||||
auto &&body = bodies.first();
|
||||
if (!body->resetStrideRead(device())) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage() error while reading image data";
|
||||
@@ -341,7 +192,7 @@ bool IFFHandler::readStandardImage(QImage *image)
|
||||
}
|
||||
for (auto y = 0, h = img.height(); y < h; ++y) {
|
||||
auto line = reinterpret_cast<char*>(img.scanLine(y));
|
||||
auto ba = body->strideRead(device(), y, header, camg, cmap, ipal, form->formType());
|
||||
auto ba = body->strideRead(device(), form, header, camg, cmap);
|
||||
if (ba.isEmpty()) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage() error while reading image scanline";
|
||||
return false;
|
||||
@@ -350,12 +201,6 @@ bool IFFHandler::readStandardImage(QImage *image)
|
||||
}
|
||||
}
|
||||
|
||||
// BEAM / CTBL conversion (if not already done)
|
||||
if (ipal && img.format() == QImage::Format_Indexed8) {
|
||||
img = convertIPAL(img, ipal);
|
||||
}
|
||||
|
||||
// set metadata (including image resolution)
|
||||
addMetadata(img, form);
|
||||
|
||||
*image = img;
|
||||
@@ -368,8 +213,7 @@ bool IFFHandler::readMayaImage(QImage *image)
|
||||
if (forms.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
auto cin = qBound(0, currentImageNumber(), int(forms.size() - 1));
|
||||
auto &&form = forms.at(cin);
|
||||
auto &&form = forms.first();
|
||||
|
||||
// show the first one (I don't have a sample with many images)
|
||||
auto headers = IFFChunk::searchT<TBHDChunk>(form);
|
||||
@@ -450,93 +294,47 @@ bool IFFHandler::supportsOption(ImageOption option) const
|
||||
if (option == QImageIOHandler::ImageFormat) {
|
||||
return true;
|
||||
}
|
||||
if (option == QImageIOHandler::ImageTransformation) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant IFFHandler::option(ImageOption option) const
|
||||
{
|
||||
if (!supportsOption(option)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const IFOR_Chunk *form = nullptr;
|
||||
if (d->readStructure(device())) {
|
||||
auto forms = d->searchForms<FORMChunk>();
|
||||
auto for4s = d->searchForms<FOR4Chunk>();
|
||||
auto cin = currentImageNumber();
|
||||
if (!forms.isEmpty())
|
||||
form = cin < forms.size() ? forms.at(cin) : forms.first();
|
||||
else if (!for4s.isEmpty())
|
||||
form = cin < for4s.size() ? for4s.at(cin) : for4s.first();
|
||||
}
|
||||
if (form == nullptr) {
|
||||
return {};
|
||||
}
|
||||
QVariant v;
|
||||
|
||||
if (option == QImageIOHandler::Size) {
|
||||
return QVariant::fromValue(form->size());
|
||||
if (d->readStructure(device())) {
|
||||
auto forms = d->searchForms<FORMChunk>();
|
||||
if (!forms.isEmpty())
|
||||
if (auto &&form = forms.first())
|
||||
v = QVariant::fromValue(form->size());
|
||||
|
||||
auto for4s = d->searchForms<FOR4Chunk>();
|
||||
if (!for4s.isEmpty())
|
||||
if (auto &&form = for4s.first())
|
||||
v = QVariant::fromValue(form->size());
|
||||
}
|
||||
}
|
||||
|
||||
if (option == QImageIOHandler::ImageFormat) {
|
||||
return QVariant::fromValue(form->optionformat());
|
||||
if (d->readStructure(device())) {
|
||||
auto forms = d->searchForms<FORMChunk>();
|
||||
if (!forms.isEmpty())
|
||||
if (auto &&form = forms.first())
|
||||
v = QVariant::fromValue(form->format());
|
||||
|
||||
auto for4s = d->searchForms<FOR4Chunk>();
|
||||
if (!for4s.isEmpty())
|
||||
if (auto &&form = for4s.first())
|
||||
v = QVariant::fromValue(form->format());
|
||||
}
|
||||
}
|
||||
|
||||
if (option == QImageIOHandler::ImageTransformation) {
|
||||
return QVariant::fromValue(form->transformation());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool IFFHandler::jumpToNextImage()
|
||||
{
|
||||
return jumpToImage(d->m_imageNumber + 1);
|
||||
}
|
||||
|
||||
bool IFFHandler::jumpToImage(int imageNumber)
|
||||
{
|
||||
if (imageNumber < 0 || imageNumber >= imageCount()) {
|
||||
return false;
|
||||
}
|
||||
d->m_imageNumber = imageNumber;
|
||||
return true;
|
||||
}
|
||||
|
||||
int IFFHandler::imageCount() const
|
||||
{
|
||||
// NOTE: image count is cached for performance reason
|
||||
auto &&count = d->m_imageCount;
|
||||
if (count > 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
count = QImageIOHandler::imageCount();
|
||||
if (!d->readStructure(device())) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::imageCount() invalid IFF structure";
|
||||
return count;
|
||||
}
|
||||
|
||||
auto forms = d->searchForms<FORMChunk>();
|
||||
auto for4s = d->searchForms<FOR4Chunk>();
|
||||
if (!forms.isEmpty())
|
||||
count = forms.size();
|
||||
else if (!for4s.isEmpty())
|
||||
count = for4s.size();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int IFFHandler::currentImageNumber() const
|
||||
{
|
||||
return d->m_imageNumber;
|
||||
return v;
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities IFFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
if (format == "iff" || format == "ilbm" || format == "lbm") {
|
||||
if (format == "iff" || format == "ilbm") {
|
||||
return Capabilities(CanRead);
|
||||
}
|
||||
if (!format.isEmpty()) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"Keys": [ "iff", "iff", "lbm", "ilbm" ],
|
||||
"MimeTypes": [ "application/x-iff", "image/x-ilbm", "image/x-ilbm", "image/x-ilbm" ]
|
||||
"Keys": [ "iff", "ilbm" ],
|
||||
"MimeTypes": [ "application/x-iff", "application/x-ilbm" ]
|
||||
}
|
||||
|
||||
@@ -23,11 +23,6 @@ public:
|
||||
bool supportsOption(QImageIOHandler::ImageOption option) const override;
|
||||
QVariant option(QImageIOHandler::ImageOption option) const override;
|
||||
|
||||
bool jumpToNextImage() override;
|
||||
bool jumpToImage(int imageNumber) override;
|
||||
int imageCount() const override;
|
||||
int currentImageNumber() const override;
|
||||
|
||||
static bool canRead(QIODevice *device);
|
||||
|
||||
private:
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef JP2_MAX_IMAGE_WIDTH
|
||||
#define JP2_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#define JP2_MAX_IMAGE_WIDTH 300000
|
||||
#endif
|
||||
#ifndef JP2_MAX_IMAGE_HEIGHT
|
||||
#define JP2_MAX_IMAGE_HEIGHT JP2_MAX_IMAGE_WIDTH
|
||||
|
||||
@@ -74,16 +74,6 @@ Q_LOGGING_CATEGORY(LOG_JXRPLUGIN, "kf.imageformats.plugins.jxr", QtWarningMsg)
|
||||
|
||||
// #define JXR_ENABLE_ADVANCED_METADATA
|
||||
|
||||
/* *** JXR_MAX_IMAGE_WIDTH and JXR_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef JXR_MAX_IMAGE_WIDTH
|
||||
#define JXR_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef JXR_MAX_IMAGE_HEIGHT
|
||||
#define JXR_MAX_IMAGE_HEIGHT JXR_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
|
||||
#ifndef JXR_MAX_METADATA_SIZE
|
||||
/*!
|
||||
* XMP and EXIF maximum size.
|
||||
@@ -396,11 +386,6 @@ public:
|
||||
if (pDecoder) {
|
||||
qint32 w, h;
|
||||
pDecoder->GetSize(pDecoder, &w, &h);
|
||||
if (w > JXR_MAX_IMAGE_WIDTH || h > JXR_MAX_IMAGE_HEIGHT || w < 1 || h < 1) {
|
||||
qCCritical(LOG_JXRPLUGIN) << "JXRHandlerPrivate::imageSize() Maximum image size is limited to" << JXR_MAX_IMAGE_WIDTH << "x"
|
||||
<< JXR_MAX_IMAGE_HEIGHT << "pixels";
|
||||
return {};
|
||||
}
|
||||
return QSize(w, h);
|
||||
}
|
||||
return {};
|
||||
@@ -1068,10 +1053,6 @@ bool JXRHandler::write(const QImage &image)
|
||||
qCWarning(LOG_JXRPLUGIN) << "JXRHandler::write() image too large: the image cannot exceed 4GB.";
|
||||
return false;
|
||||
}
|
||||
if (image.width() > JXR_MAX_IMAGE_WIDTH || image.height() > JXR_MAX_IMAGE_HEIGHT) {
|
||||
qCCritical(LOG_JXRPLUGIN) << "JXRHandler::write() Maximum image size is limited to" << JXR_MAX_IMAGE_WIDTH << "x" << JXR_MAX_IMAGE_HEIGHT << "pixels";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!d->initForWriting()) {
|
||||
return false;
|
||||
|
||||
@@ -1072,7 +1072,7 @@ QByteArray MicroExif::toByteArray(const QDataStream::ByteOrder &byteOrder, const
|
||||
QByteArray ba;
|
||||
{
|
||||
QBuffer buf(&ba);
|
||||
if (!write(&buf, byteOrder, version))
|
||||
if (!write(&buf, byteOrder))
|
||||
return {};
|
||||
}
|
||||
return ba;
|
||||
@@ -1193,13 +1193,12 @@ void MicroExif::updateImageMetadata(QImage &targetImage, bool replaceExisting) c
|
||||
}
|
||||
}
|
||||
|
||||
bool MicroExif::updateImageResolution(QImage &targetImage)
|
||||
void MicroExif::updateImageResolution(QImage &targetImage)
|
||||
{
|
||||
if (horizontalResolution() > 0)
|
||||
targetImage.setDotsPerMeterX(qRound(horizontalResolution() / 25.4 * 1000));
|
||||
if (verticalResolution() > 0)
|
||||
targetImage.setDotsPerMeterY(qRound(verticalResolution() / 25.4 * 1000));
|
||||
return (horizontalResolution() > 0) || (verticalResolution() > 0);
|
||||
}
|
||||
|
||||
MicroExif MicroExif::fromByteArray(const QByteArray &ba, bool searchHeader)
|
||||
|
||||
@@ -339,9 +339,8 @@ public:
|
||||
* \brief updateImageResolution
|
||||
* Helper to set the EXIF resolution to the image. Resolution is set only if valid.
|
||||
* \param targetImage The image to set resolution on.
|
||||
* \return True if either the x-resolution or the y-resolution has been changed, otherwise false.
|
||||
*/
|
||||
bool updateImageResolution(QImage &targetImage);
|
||||
void updateImageResolution(QImage &targetImage);
|
||||
|
||||
/*!
|
||||
* \brief fromByteArray
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#include "pcx_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <QColor>
|
||||
@@ -622,38 +621,30 @@ static bool writeLine(QDataStream &s, QByteArray &buf)
|
||||
return (s.status() == QDataStream::Ok);
|
||||
}
|
||||
|
||||
static bool writeImage1(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
static bool writeImage1(QImage &img, QDataStream &s, PCXHEADER &header)
|
||||
{
|
||||
auto tfmt = image.format();
|
||||
if (tfmt != QImage::Format_Mono)
|
||||
tfmt = QImage::Format_Mono;
|
||||
|
||||
if (image.isNull() || image.colorCount() < 1) {
|
||||
if (img.format() != QImage::Format_Mono) {
|
||||
img.convertTo(QImage::Format_Mono);
|
||||
}
|
||||
if (img.isNull() || img.colorCount() < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScanLineConverter scl(tfmt);
|
||||
if (image.height() > 0) {
|
||||
scl.convertedScanLine(image, 0); // required to calculate bytesPerLine
|
||||
}
|
||||
auto rgb = img.color(0);
|
||||
auto minIsBlack = (qRed(rgb) + qGreen(rgb) + qBlue(rgb)) / 3 < 127;
|
||||
|
||||
header.Bpp = 1;
|
||||
header.NPlanes = 1;
|
||||
header.BytesPerLine = scl.bytesPerLine();
|
||||
if (header.BytesPerLine == 0) {
|
||||
header.BytesPerLine = image.bytesPerLine();
|
||||
}
|
||||
header.BytesPerLine = img.bytesPerLine();
|
||||
if (header.BytesPerLine == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s << header;
|
||||
|
||||
auto rgb = image.color(0);
|
||||
auto minIsBlack = (qRed(rgb) + qGreen(rgb) + qBlue(rgb)) / 3 < 127;
|
||||
QByteArray buf(header.BytesPerLine, 0);
|
||||
|
||||
for (int y = 0; y < header.height(); ++y) {
|
||||
auto p = scl.convertedScanLine(image, y);
|
||||
auto p = img.constScanLine(y);
|
||||
|
||||
// Invert as QImage uses reverse palette for monochrome images?
|
||||
for (int i = 0; i < header.BytesPerLine; ++i) {
|
||||
@@ -667,7 +658,7 @@ static bool writeImage1(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeImage4(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
static bool writeImage4(QImage &img, QDataStream &s, PCXHEADER &header)
|
||||
{
|
||||
header.Bpp = 1;
|
||||
header.NPlanes = 4;
|
||||
@@ -677,7 +668,7 @@ static bool writeImage4(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
header.ColorMap.setColor(i, image.color(i));
|
||||
header.ColorMap.setColor(i, img.color(i));
|
||||
}
|
||||
|
||||
s << header;
|
||||
@@ -689,7 +680,7 @@ static bool writeImage4(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
}
|
||||
|
||||
for (int y = 0; y < header.height(); ++y) {
|
||||
auto p = image.constScanLine(y);
|
||||
auto p = img.constScanLine(y);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
buf[i].fill(0);
|
||||
@@ -712,23 +703,18 @@ static bool writeImage4(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeImage8(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
static bool writeImage8(QImage &img, QDataStream &s, PCXHEADER &header)
|
||||
{
|
||||
auto tfmt = image.format();
|
||||
if (tfmt == QImage::Format_Grayscale16)
|
||||
tfmt = QImage::Format_Grayscale8;
|
||||
|
||||
ScanLineConverter scl(tfmt);
|
||||
if (image.height() > 0) {
|
||||
scl.convertedScanLine(image, 0); // required to calculate bytesPerLine
|
||||
if (img.format() == QImage::Format_Grayscale16) {
|
||||
img.convertTo(QImage::Format_Grayscale8);
|
||||
}
|
||||
if (img.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
header.Bpp = 8;
|
||||
header.NPlanes = 1;
|
||||
header.BytesPerLine = scl.bytesPerLine();
|
||||
if (header.BytesPerLine == 0) {
|
||||
header.BytesPerLine = image.bytesPerLine();
|
||||
}
|
||||
header.BytesPerLine = img.bytesPerLine();
|
||||
if (header.BytesPerLine == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -738,7 +724,7 @@ static bool writeImage8(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
QByteArray buf(header.BytesPerLine, 0);
|
||||
|
||||
for (int y = 0; y < header.height(); ++y) {
|
||||
auto p = scl.convertedScanLine(image, y);
|
||||
auto p = img.constScanLine(y);
|
||||
|
||||
for (int i = 0; i < header.BytesPerLine; ++i) {
|
||||
buf[i] = p[i];
|
||||
@@ -755,18 +741,18 @@ static bool writeImage8(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
|
||||
// Write palette
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
if (tfmt != QImage::Format_Indexed8)
|
||||
if (img.format() != QImage::Format_Indexed8)
|
||||
s << RGB::from(qRgb(i, i, i));
|
||||
else
|
||||
s << RGB::from(image.color(i));
|
||||
s << RGB::from(img.color(i));
|
||||
}
|
||||
|
||||
return (s.status() == QDataStream::Ok);
|
||||
}
|
||||
|
||||
static bool writeImage24(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
static bool writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
|
||||
{
|
||||
auto hasAlpha = image.hasAlphaChannel();
|
||||
auto hasAlpha = img.hasAlphaChannel();
|
||||
header.Bpp = 8;
|
||||
header.NPlanes = hasAlpha ? 4 : 3;
|
||||
header.BytesPerLine = header.width();
|
||||
@@ -774,17 +760,11 @@ static bool writeImage24(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
auto cs = image.colorSpace();
|
||||
auto tcs = QColorSpace();
|
||||
auto tfmt = image.format();
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && tfmt == QImage::Format_CMYK8888) {
|
||||
tcs = QColorSpace(QColorSpace::SRgb);
|
||||
tfmt = QImage::Format_RGB32;
|
||||
if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB32) {
|
||||
img.convertTo(hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
|
||||
}
|
||||
#endif
|
||||
if (tfmt != QImage::Format_ARGB32 && tfmt != QImage::Format_RGB32) {
|
||||
tfmt = hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
|
||||
if (img.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s << header;
|
||||
@@ -794,10 +774,8 @@ static bool writeImage24(const QImage &image, QDataStream &s, PCXHEADER &header)
|
||||
QByteArray b_buf(header.width(), 0);
|
||||
QByteArray a_buf(header.width(), char(0xFF));
|
||||
|
||||
ScanLineConverter scl(tfmt);
|
||||
scl.setTargetColorSpace(tcs);
|
||||
for (int y = 0; y < header.height(); ++y) {
|
||||
auto p = reinterpret_cast<const QRgb *>(scl.convertedScanLine(image, y));
|
||||
auto p = reinterpret_cast<const QRgb *>(img.constScanLine(y));
|
||||
|
||||
for (int x = 0; x < header.width(); ++x) {
|
||||
auto &&rgb = p[x];
|
||||
@@ -899,8 +877,16 @@ bool PCXHandler::write(const QImage &image)
|
||||
QDataStream s(device());
|
||||
s.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
const int w = image.width();
|
||||
const int h = image.height();
|
||||
QImage img = image;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
auto cs = image.colorSpace();
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
||||
img = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb));
|
||||
}
|
||||
#endif
|
||||
|
||||
const int w = img.width();
|
||||
const int h = img.height();
|
||||
|
||||
if (w > 65536 || h > 65536) {
|
||||
return false;
|
||||
@@ -921,14 +907,14 @@ bool PCXHandler::write(const QImage &image)
|
||||
header.PaletteInfo = 1;
|
||||
|
||||
auto ok = false;
|
||||
if (image.depth() == 1) {
|
||||
ok = writeImage1(image, s, header);
|
||||
} else if (image.format() == QImage::Format_Indexed8 && image.colorCount() <= 16) {
|
||||
ok = writeImage4(image, s, header);
|
||||
} else if (image.depth() == 8 || image.format() == QImage::Format_Grayscale16) {
|
||||
ok = writeImage8(image, s, header);
|
||||
} else if (image.depth() >= 16) {
|
||||
ok = writeImage24(image, s, header);
|
||||
if (img.depth() == 1) {
|
||||
ok = writeImage1(img, s, header);
|
||||
} else if (img.format() == QImage::Format_Indexed8 && img.colorCount() <= 16) {
|
||||
ok = writeImage4(img, s, header);
|
||||
} else if (img.depth() == 8 || img.format() == QImage::Format_Grayscale16) {
|
||||
ok = writeImage8(img, s, header);
|
||||
} else if (img.depth() >= 16) {
|
||||
ok = writeImage24(img, s, header);
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
||||
@@ -22,16 +22,6 @@
|
||||
Q_DECLARE_LOGGING_CATEGORY(LOG_PFMPLUGIN)
|
||||
Q_LOGGING_CATEGORY(LOG_PFMPLUGIN, "kf.imageformats.plugins.pfm", QtWarningMsg)
|
||||
|
||||
/* *** PFM_MAX_IMAGE_WIDTH and PFM_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef PFM_MAX_IMAGE_WIDTH
|
||||
#define PFM_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef PFM_MAX_IMAGE_HEIGHT
|
||||
#define PFM_MAX_IMAGE_HEIGHT PFM_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
|
||||
class PFMHeader
|
||||
{
|
||||
private:
|
||||
@@ -90,7 +80,7 @@ public:
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return (m_width > 0 && m_height > 0 && m_width <= PFM_MAX_IMAGE_WIDTH && m_height <= PFM_MAX_IMAGE_HEIGHT);
|
||||
return (m_width > 0 && m_height > 0);
|
||||
}
|
||||
|
||||
bool isBlackAndWhite() const
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include "pic_p.h"
|
||||
#include "rle_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <QColorSpace>
|
||||
@@ -264,20 +263,18 @@ bool SoftimagePICHandler::read(QImage *image)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftimagePICHandler::write(const QImage &image)
|
||||
bool SoftimagePICHandler::write(const QImage &_image)
|
||||
{
|
||||
bool alpha = image.hasAlphaChannel();
|
||||
bool alpha = _image.hasAlphaChannel();
|
||||
QImage image;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
auto cs = image.colorSpace();
|
||||
auto tfmt = image.format();
|
||||
auto tcs = QColorSpace();
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && tfmt == QImage::Format_CMYK8888) {
|
||||
tcs = QColorSpace(QColorSpace::SRgb);
|
||||
tfmt = QImage::Format_RGB32;
|
||||
auto cs = _image.colorSpace();
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && _image.format() == QImage::Format_CMYK8888) {
|
||||
image = _image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), QImage::Format_RGB32);
|
||||
}
|
||||
#endif
|
||||
if (tfmt != QImage::Format_ARGB32 && tfmt != QImage::Format_RGB32) {
|
||||
tfmt = alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
|
||||
if (image.isNull()) {
|
||||
image = _image.convertToFormat(alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
|
||||
}
|
||||
|
||||
if (image.width() < 0 || image.height() < 0) {
|
||||
@@ -302,10 +299,8 @@ bool SoftimagePICHandler::write(const QImage &image)
|
||||
}
|
||||
stream << channels;
|
||||
|
||||
ScanLineConverter scl(tfmt);
|
||||
scl.setTargetColorSpace(tcs);
|
||||
for (int r = 0; r < image.height(); r++) {
|
||||
const QRgb *row = reinterpret_cast<const QRgb *>(scl.convertedScanLine(image, r));
|
||||
const QRgb *row = reinterpret_cast<const QRgb *>(image.constScanLine(r));
|
||||
|
||||
/* Write the RGB part of the scanline */
|
||||
auto rgbEqual = [](QRgb p1, QRgb p2) -> bool {
|
||||
|
||||
@@ -72,16 +72,6 @@ typedef quint8 uchar;
|
||||
*/
|
||||
// #define PSD_FORCE_RGBA
|
||||
|
||||
/* *** PSD_MAX_IMAGE_WIDTH and PSD_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef PSD_MAX_IMAGE_WIDTH
|
||||
#define PSD_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef PSD_MAX_IMAGE_HEIGHT
|
||||
#define PSD_MAX_IMAGE_HEIGHT PSD_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
|
||||
namespace // Private.
|
||||
{
|
||||
|
||||
@@ -688,7 +678,7 @@ static bool IsValid(const PSDHeader &header)
|
||||
qDebug() << "PSD header: invalid number of channels" << header.channel_count;
|
||||
return false;
|
||||
}
|
||||
if (header.width > std::min(300000, PSD_MAX_IMAGE_WIDTH) || header.height > std::min(300000, PSD_MAX_IMAGE_HEIGHT)) {
|
||||
if (header.width > 300000 || header.height > 300000) {
|
||||
qDebug() << "PSD header: invalid image size" << header.width << "x" << header.height;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,16 +15,6 @@
|
||||
#include <QIODevice>
|
||||
#include <QImage>
|
||||
|
||||
/* *** QOI_MAX_IMAGE_WIDTH and QOI_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef QOI_MAX_IMAGE_WIDTH
|
||||
#define QOI_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef QOI_MAX_IMAGE_HEIGHT
|
||||
#define QOI_MAX_IMAGE_HEIGHT QOI_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
|
||||
namespace // Private
|
||||
{
|
||||
|
||||
@@ -102,7 +92,7 @@ static bool IsSupported(const QoiHeader &head)
|
||||
return false;
|
||||
}
|
||||
// Set a reasonable upper limit
|
||||
if (head.Width > QOI_MAX_IMAGE_WIDTH || head.Height > QOI_MAX_IMAGE_HEIGHT) {
|
||||
if (head.Width > 300000 || head.Height > 300000) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -15,16 +15,6 @@
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
|
||||
/* *** RAS_MAX_IMAGE_WIDTH and RAS_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef RAS_MAX_IMAGE_WIDTH
|
||||
#define RAS_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef RAS_MAX_IMAGE_HEIGHT
|
||||
#define RAS_MAX_IMAGE_HEIGHT RAS_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
|
||||
namespace // Private.
|
||||
{
|
||||
// format info from http://www.fileformat.info/format/sunraster/egff.htm
|
||||
@@ -94,10 +84,9 @@ static bool IsSupported(const RasHeader &head)
|
||||
if (head.Depth != 1 && head.Depth != 8 && head.Depth != 24 && head.Depth != 32) {
|
||||
return false;
|
||||
}
|
||||
if (head.Width == 0 || head.Height == 0 || head.Width > RAS_MAX_IMAGE_WIDTH || head.Height > RAS_MAX_IMAGE_HEIGHT) {
|
||||
if (head.Width == 0 || head.Height == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the Type field adds support for RLE(BGR), RGB and other encodings
|
||||
// we support Type 1: Normal(BGR), Type 2: RLE(BGR) and Type 3: Normal(RGB) ONLY!
|
||||
// TODO: add support for Type 4,5: TIFF/IFF
|
||||
@@ -399,7 +388,7 @@ bool RASHandler::read(QImage *outImage)
|
||||
s >> ras;
|
||||
|
||||
if (ras.ColorMapLength > kMaxQVectorSize) {
|
||||
qWarning() << "read() unsupported image color map length in file header" << ras.ColorMapLength;
|
||||
qWarning() << "LoadRAS() unsupported image color map length in file header" << ras.ColorMapLength;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <QColorSpace>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
#include <QSet>
|
||||
#include <QTimeZone>
|
||||
@@ -21,24 +22,12 @@
|
||||
|
||||
#include <libraw/libraw.h>
|
||||
|
||||
#ifndef RAW_DISABLE_BROKEN_STREAM_PROTECTION
|
||||
/* The LibRaw_QIODevice stream interrupt the reading of the RAW file if a
|
||||
* burst of read errors are detected.
|
||||
* By defining RAW_IGNORE_BROKEN_STREAMS removes this protection, leaving
|
||||
* LibRaw in complete control of error handling (which is mostly absent).
|
||||
*/
|
||||
// #define RAW_DISABLE_BROKEN_STREAM_PROTECTION
|
||||
#endif
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
/* This should be used to exclude the local QIODevice wrapper of the
|
||||
* LibRaw_abstract_datastream interface. If the result changes then the problem
|
||||
* is in the local wrapper and must be corrected.
|
||||
* WARNING: using the LibRaw's streams instead of the local wrapper from a Qt
|
||||
* program falls in the LOCALE bug when the RAW file needs the
|
||||
* scanf_one() function (e.g. *.MOS files). See also raw_scanf_one().
|
||||
*/
|
||||
// #define EXCLUDE_LibRaw_QIODevice // Uncomment this code if you think that the problem is LibRaw_QIODevice (default commented)
|
||||
// This should be used to exclude the local QIODevice wrapper of the LibRaw_abstract_datastream interface.
|
||||
// If the result changes then the problem is in the local wrapper and must be corrected.
|
||||
// WARNING: using the LibRaw's streams instead of the local wrapper from a Qt program falls in the LOCALE
|
||||
// bug when the RAW file needs the scanf_one() function (e.g. *.MOS files). See also raw_scanf_one().
|
||||
//#define EXCLUDE_LibRaw_QIODevice // Uncomment this code if you think that the problem is LibRaw_QIODevice (default commented)
|
||||
#endif
|
||||
|
||||
namespace // Private.
|
||||
@@ -106,46 +95,10 @@ inline int raw_scanf_one(const QByteArray &ba, const char *fmt, void *val)
|
||||
*/
|
||||
class LibRaw_QIODevice : public LibRaw_abstract_datastream
|
||||
{
|
||||
inline void incError()
|
||||
{
|
||||
// Normally, when read errors occur, a plugin exits with an error.
|
||||
// Here, given how LibRaw works, we need to be a little more flexible:
|
||||
// for example, a seek might fail when the library tries to figure out
|
||||
// what it's reading. We therefore use a dynamic error counting system
|
||||
// where the error counts heavily, but subsequent successful
|
||||
// operations can mitigate it.
|
||||
// If the stream is obviously corrupt, the plugin exits.
|
||||
m_errorCount += 3;
|
||||
}
|
||||
inline void decError()
|
||||
{
|
||||
m_errorCount = std::max(m_errorCount - 1, 0);
|
||||
}
|
||||
void checkErrors() {
|
||||
// Internally, LibRaw often doesn't check the return values of various
|
||||
// functions. It's not uncommon to find things like:
|
||||
//
|
||||
// fseek(ifp, oAtom, SEEK_SET);
|
||||
// szAtom = get4();
|
||||
//
|
||||
// which can cause the read to go into an infinite loop on corrupted
|
||||
// files. I've set the error count to high to avoid these issues.
|
||||
if (m_errorCount > 10) {
|
||||
#ifndef RAW_DISABLE_BROKEN_STREAM_PROTECTION
|
||||
// LibRaw stream classes can throw exceptions that are handled by
|
||||
// libraw itself (e.g. see implementation of
|
||||
// LibRaw_bigfile_datastream).
|
||||
// Every LibRaw function that works on the stream used in this
|
||||
// plugin is protected by a Try...Catch.
|
||||
IOERROR(); // defined in libraw_datastream.h
|
||||
#endif
|
||||
}
|
||||
}
|
||||
public:
|
||||
explicit LibRaw_QIODevice(QIODevice *device)
|
||||
: m_device(device)
|
||||
, m_errorCount(0)
|
||||
{
|
||||
m_device = device;
|
||||
}
|
||||
virtual ~LibRaw_QIODevice() override
|
||||
{
|
||||
@@ -156,22 +109,19 @@ public:
|
||||
}
|
||||
virtual int read(void *ptr, size_t sz, size_t nmemb) override
|
||||
{
|
||||
checkErrors();
|
||||
|
||||
qint64 read = 0;
|
||||
if (sz == 0) {
|
||||
return 0;
|
||||
}
|
||||
auto data = reinterpret_cast<char*>(ptr);
|
||||
for (qint64 r = 0, size = sz * nmemb; read < size; read += r) {
|
||||
r = m_device->read(data + read, size - read);
|
||||
if (r < 1) {
|
||||
if (read == 0 || r < 0) {
|
||||
incError();
|
||||
}
|
||||
if (m_device->atEnd()) {
|
||||
break;
|
||||
}
|
||||
r = m_device->read(data + read, size - read);
|
||||
if (r < 1) {
|
||||
break;
|
||||
}
|
||||
decError();
|
||||
}
|
||||
return int(read / sz);
|
||||
}
|
||||
@@ -181,21 +131,17 @@ public:
|
||||
}
|
||||
virtual int seek(INT64 o, int whence) override
|
||||
{
|
||||
checkErrors();
|
||||
|
||||
auto pos = o;
|
||||
auto siz = size();
|
||||
auto size = m_device->size();
|
||||
if (whence == SEEK_CUR) {
|
||||
pos = tell() + o;
|
||||
pos = m_device->pos() + o;
|
||||
}
|
||||
if (whence == SEEK_END) {
|
||||
pos = siz + o;
|
||||
pos = size + o;
|
||||
}
|
||||
if (pos < 0 || pos > siz || m_device->isSequential()) {
|
||||
incError();
|
||||
if (pos < 0 || m_device->isSequential()) {
|
||||
return -1;
|
||||
}
|
||||
decError();
|
||||
return m_device->seek(pos) ? 0 : -1;
|
||||
}
|
||||
virtual INT64 tell() override
|
||||
@@ -208,24 +154,17 @@ public:
|
||||
}
|
||||
virtual char *gets(char *s, int sz) override
|
||||
{
|
||||
checkErrors();
|
||||
|
||||
if (m_device->readLine(s, sz) > 0) {
|
||||
decError();
|
||||
return s;
|
||||
}
|
||||
incError();
|
||||
return nullptr;
|
||||
}
|
||||
virtual int scanf_one(const char *fmt, void *val) override
|
||||
{
|
||||
checkErrors();
|
||||
|
||||
QByteArray ba;
|
||||
for (int xcnt = 0; xcnt < 24 && !m_device->atEnd(); ++xcnt) {
|
||||
char c;
|
||||
if (!m_device->getChar(&c)) {
|
||||
incError();
|
||||
return EOF;
|
||||
}
|
||||
if (ba.isEmpty() && (c == ' ' || c == '\t')) {
|
||||
@@ -236,19 +175,14 @@ public:
|
||||
}
|
||||
ba.append(c);
|
||||
}
|
||||
decError();
|
||||
return raw_scanf_one(ba, fmt, val);
|
||||
}
|
||||
virtual int get_char() override
|
||||
{
|
||||
checkErrors();
|
||||
|
||||
unsigned char c;
|
||||
if (!m_device->getChar(reinterpret_cast<char *>(&c))) {
|
||||
incError();
|
||||
return EOF;
|
||||
}
|
||||
decError();
|
||||
return int(c);
|
||||
}
|
||||
#if (LIBRAW_VERSION < LIBRAW_MAKE_VERSION(0, 21, 0)) || defined(LIBRAW_OLD_VIDEO_SUPPORT)
|
||||
@@ -260,8 +194,6 @@ public:
|
||||
|
||||
private:
|
||||
QIODevice *m_device;
|
||||
|
||||
qint32 m_errorCount;
|
||||
};
|
||||
|
||||
bool addTag(const QString &tag, QStringList &lines)
|
||||
@@ -659,8 +591,8 @@ bool LoadTHUMB(QImageIOHandler *handler, QImage &img)
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
auto all = device->readAll();
|
||||
if (rawProcessor->open_buffer(all.data(), all.size()) != LIBRAW_SUCCESS) {
|
||||
auto ba = device->readAll();
|
||||
if (rawProcessor->open_buffer(ba.data(), ba.size()) != LIBRAW_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
#include "rgb_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <cstring>
|
||||
@@ -134,8 +133,8 @@ private:
|
||||
|
||||
bool writeHeader();
|
||||
bool writeRle();
|
||||
bool writeVerbatim(const QImage &, const QImage::Format&, const QColorSpace&);
|
||||
bool scanData(const QImage &, const QImage::Format&, const QColorSpace&);
|
||||
bool writeVerbatim(const QImage &);
|
||||
bool scanData(const QImage &);
|
||||
uint compact(uchar *, uchar *);
|
||||
uchar intensity(uchar);
|
||||
};
|
||||
@@ -458,7 +457,7 @@ uint SGIImagePrivate::compact(uchar *d, uchar *s)
|
||||
return dest - d;
|
||||
}
|
||||
|
||||
bool SGIImagePrivate::scanData(const QImage &img, const QImage::Format &tfmt, const QColorSpace &tcs)
|
||||
bool SGIImagePrivate::scanData(const QImage &img)
|
||||
{
|
||||
quint32 *start = _starttab;
|
||||
QByteArray lineguard(_xsize * 2, 0);
|
||||
@@ -470,8 +469,6 @@ bool SGIImagePrivate::scanData(const QImage &img, const QImage::Format &tfmt, co
|
||||
unsigned y;
|
||||
uint len;
|
||||
|
||||
ScanLineConverter scl(tfmt);
|
||||
scl.setTargetColorSpace(tcs);
|
||||
for (y = 0; y < _ysize; y++) {
|
||||
const int yPos = _ysize - y - 1; // scanline doesn't do any sanity checking
|
||||
if (yPos >= img.height()) {
|
||||
@@ -479,7 +476,7 @@ bool SGIImagePrivate::scanData(const QImage &img, const QImage::Format &tfmt, co
|
||||
return false;
|
||||
}
|
||||
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, yPos));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(yPos));
|
||||
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
buf[x] = intensity(qRed(*c++));
|
||||
@@ -500,7 +497,7 @@ bool SGIImagePrivate::scanData(const QImage &img, const QImage::Format &tfmt, co
|
||||
return false;
|
||||
}
|
||||
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, yPos));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(yPos));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
buf[x] = intensity(qGreen(*c++));
|
||||
}
|
||||
@@ -515,7 +512,7 @@ bool SGIImagePrivate::scanData(const QImage &img, const QImage::Format &tfmt, co
|
||||
return false;
|
||||
}
|
||||
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, yPos));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(yPos));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
buf[x] = intensity(qBlue(*c++));
|
||||
}
|
||||
@@ -535,7 +532,7 @@ bool SGIImagePrivate::scanData(const QImage &img, const QImage::Format &tfmt, co
|
||||
return false;
|
||||
}
|
||||
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, yPos));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(yPos));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
buf[x] = intensity(qAlpha(*c++));
|
||||
}
|
||||
@@ -686,7 +683,7 @@ bool SGIImagePrivate::writeRle()
|
||||
return _stream.status() == QDataStream::Ok;
|
||||
}
|
||||
|
||||
bool SGIImagePrivate::writeVerbatim(const QImage &img, const QImage::Format &tfmt, const QColorSpace &tcs)
|
||||
bool SGIImagePrivate::writeVerbatim(const QImage &img)
|
||||
{
|
||||
_rle = 0;
|
||||
if (!writeHeader()) {
|
||||
@@ -697,15 +694,11 @@ bool SGIImagePrivate::writeVerbatim(const QImage &img, const QImage::Format &tfm
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
|
||||
ScanLineConverter scl(tfmt);
|
||||
scl.setTargetColorSpace(tcs);
|
||||
QByteArray ba(_xsize, char());
|
||||
for (y = 0; y < _ysize; y++) {
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, _ysize - y - 1));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
ba[x] = char(qRed(*c++));
|
||||
_stream << quint8(qRed(*c++));
|
||||
}
|
||||
_stream.writeRawData(ba.data(), ba.size());
|
||||
}
|
||||
|
||||
if (_zsize == 1) {
|
||||
@@ -714,19 +707,17 @@ bool SGIImagePrivate::writeVerbatim(const QImage &img, const QImage::Format &tfm
|
||||
|
||||
if (_zsize != 2) {
|
||||
for (y = 0; y < _ysize; y++) {
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, _ysize - y - 1));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
ba[x] = char(qGreen(*c++));
|
||||
_stream << quint8(qGreen(*c++));
|
||||
}
|
||||
_stream.writeRawData(ba.data(), ba.size());
|
||||
}
|
||||
|
||||
for (y = 0; y < _ysize; y++) {
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, _ysize - y - 1));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
ba[x] = char(qBlue(*c++));
|
||||
_stream << quint8(qBlue(*c++));
|
||||
}
|
||||
_stream.writeRawData(ba.data(), ba.size());
|
||||
}
|
||||
|
||||
if (_zsize == 3) {
|
||||
@@ -735,11 +726,10 @@ bool SGIImagePrivate::writeVerbatim(const QImage &img, const QImage::Format &tfm
|
||||
}
|
||||
|
||||
for (y = 0; y < _ysize; y++) {
|
||||
c = reinterpret_cast<const QRgb *>(scl.convertedScanLine(img, _ysize - y - 1));
|
||||
c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
|
||||
for (x = 0; x < _xsize; x++) {
|
||||
ba[x] = char(qAlpha(*c++));
|
||||
_stream << quint8(qAlpha(*c++));
|
||||
}
|
||||
_stream.writeRawData(ba.data(), ba.size());
|
||||
}
|
||||
|
||||
return _stream.status() == QDataStream::Ok;
|
||||
@@ -748,35 +738,37 @@ bool SGIImagePrivate::writeVerbatim(const QImage &img, const QImage::Format &tfm
|
||||
bool SGIImagePrivate::writeImage(const QImage &image)
|
||||
{
|
||||
// qDebug() << "writing "; // TODO add filename
|
||||
if (image.allGray()) {
|
||||
QImage img = image;
|
||||
if (img.allGray()) {
|
||||
_dim = 2, _zsize = 1;
|
||||
} else {
|
||||
_dim = 3, _zsize = 3;
|
||||
}
|
||||
|
||||
auto hasAlpha = image.hasAlphaChannel();
|
||||
auto hasAlpha = img.hasAlphaChannel();
|
||||
if (hasAlpha) {
|
||||
_dim = 3, _zsize++;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
||||
auto cs = image.colorSpace();
|
||||
auto tcs = QColorSpace();
|
||||
auto tfmt = image.format();
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && tfmt == QImage::Format_CMYK8888) {
|
||||
tcs = QColorSpace(QColorSpace::SRgb);
|
||||
tfmt = QImage::Format_RGB32;
|
||||
} else if (hasAlpha && tfmt != QImage::Format_ARGB32) {
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
||||
img = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), QImage::Format_RGB32);
|
||||
} else if (hasAlpha && img.format() != QImage::Format_ARGB32) {
|
||||
#else
|
||||
if (hasAlpha && tfmt != QImage::Format_ARGB32) {
|
||||
if (hasAlpha && img.format() != QImage::Format_ARGB32) {
|
||||
#endif
|
||||
tfmt = QImage::Format_ARGB32;
|
||||
} else if (!hasAlpha && tfmt != QImage::Format_RGB32) {
|
||||
tfmt = QImage::Format_RGB32;
|
||||
img = img.convertToFormat(QImage::Format_ARGB32);
|
||||
} else if (!hasAlpha && img.format() != QImage::Format_RGB32) {
|
||||
img = img.convertToFormat(QImage::Format_RGB32);
|
||||
}
|
||||
if (img.isNull()) {
|
||||
// qDebug() << "can't convert image to depth 32";
|
||||
return false;
|
||||
}
|
||||
|
||||
const int w = image.width();
|
||||
const int h = image.height();
|
||||
const int w = img.width();
|
||||
const int h = img.height();
|
||||
|
||||
if (w > 65535 || h > 65535) {
|
||||
return false;
|
||||
@@ -793,7 +785,7 @@ bool SGIImagePrivate::writeImage(const QImage &image)
|
||||
_starttab = new quint32[_numrows];
|
||||
_rlemap.setBaseOffset(512 + _numrows * 2 * sizeof(quint32));
|
||||
|
||||
if (!scanData(image, tfmt, tcs)) {
|
||||
if (!scanData(img)) {
|
||||
// qDebug() << "this can't happen";
|
||||
return false;
|
||||
}
|
||||
@@ -807,7 +799,7 @@ bool SGIImagePrivate::writeImage(const QImage &image)
|
||||
}
|
||||
|
||||
if (verbatim_size <= rle_size) {
|
||||
return writeVerbatim(image, tfmt, tcs);
|
||||
return writeVerbatim(img);
|
||||
}
|
||||
return writeRle();
|
||||
}
|
||||
|
||||
@@ -17,17 +17,8 @@
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_LOGGING_CATEGORY(LOG_SCTPLUGIN, "kf.imageformats.plugins.scitex", QtWarningMsg)
|
||||
|
||||
/* *** SCT_MAX_IMAGE_WIDTH and SCT_MAX_IMAGE_HEIGHT ***
|
||||
* The maximum size in pixel allowed by the plugin.
|
||||
*/
|
||||
#ifndef SCT_MAX_IMAGE_WIDTH
|
||||
#define SCT_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef SCT_MAX_IMAGE_HEIGHT
|
||||
#define SCT_MAX_IMAGE_HEIGHT SCT_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
|
||||
Q_LOGGING_CATEGORY(LOG_IFFPLUGIN, "kf.imageformats.plugins.scitex", QtWarningMsg)
|
||||
|
||||
#define CTRLBLOCK_SIZE 256
|
||||
#define PRMSBLOCK_SIZE_CT 256
|
||||
@@ -149,7 +140,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
// Set a reasonable upper limit
|
||||
if (width() > SCT_MAX_IMAGE_WIDTH || height() > SCT_MAX_IMAGE_HEIGHT) {
|
||||
if (width() > 300000 || height() > 300000) {
|
||||
return false;
|
||||
}
|
||||
return m_cb.fileType() == QStringLiteral(FILETYPE_CT) && format() != QImage::Format_Invalid;
|
||||
|
||||
@@ -22,19 +22,14 @@ public:
|
||||
bool write(const QImage &image) override;
|
||||
|
||||
bool supportsOption(QImageIOHandler::ImageOption option) const override;
|
||||
void setOption(ImageOption option, const QVariant &value) override;
|
||||
QVariant option(QImageIOHandler::ImageOption option) const override;
|
||||
|
||||
static bool canRead(QIODevice *device);
|
||||
|
||||
private:
|
||||
bool writeIndexed(const QImage &image);
|
||||
bool writeGrayscale(const QImage &image);
|
||||
bool writeRGB555(const QImage &image);
|
||||
bool writeRGBA(const QImage &image);
|
||||
|
||||
bool writeMetadata(const QImage &image);
|
||||
bool readMetadata(QImage &image);
|
||||
bool writeRGBA(const QImage &image);
|
||||
|
||||
const QScopedPointer<TGAHandlerPrivate> d;
|
||||
};
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
#include <QImage>
|
||||
#include <QImageIOHandler>
|
||||
|
||||
// Default maximum width and height for the large image plugins.
|
||||
#ifndef KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#define KIF_LARGE_IMAGE_PIXEL_LIMIT 300000
|
||||
#endif
|
||||
|
||||
// Image metadata keys to use in plugins (so they are consistent)
|
||||
#define META_KEY_ALTITUDE "Altitude"
|
||||
#define META_KEY_AUTHOR "Author"
|
||||
|
||||
@@ -26,16 +26,12 @@
|
||||
#define USE_FLOAT_IMAGES // default uncommented
|
||||
|
||||
// Let's set a "reasonable" maximum size
|
||||
#ifndef XCF_MAX_IMAGE_WIDTH
|
||||
#define XCF_MAX_IMAGE_WIDTH KIF_LARGE_IMAGE_PIXEL_LIMIT
|
||||
#endif
|
||||
#ifndef XCF_MAX_IMAGE_HEIGHT
|
||||
#define XCF_MAX_IMAGE_HEIGHT XCF_MAX_IMAGE_WIDTH
|
||||
#endif
|
||||
#define MAX_IMAGE_WIDTH 300000
|
||||
#define MAX_IMAGE_HEIGHT 300000
|
||||
#else
|
||||
// While it is possible to have images larger than 32767 pixels, QPainter seems unable to go beyond this threshold using Qt 5.
|
||||
#define XCF_MAX_IMAGE_WIDTH 32767
|
||||
#define XCF_MAX_IMAGE_HEIGHT 32767
|
||||
#define MAX_IMAGE_WIDTH 32767
|
||||
#define MAX_IMAGE_HEIGHT 32767
|
||||
#endif
|
||||
|
||||
#ifdef USE_FLOAT_IMAGES
|
||||
@@ -848,8 +844,8 @@ bool XCFImageFormat::readXCFHeader(QDataStream &xcf_io, XCFImage::Header *header
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->width > XCF_MAX_IMAGE_WIDTH || header->height > XCF_MAX_IMAGE_HEIGHT) {
|
||||
qCWarning(XCFPLUGIN) << "The maximum image size is limited to" << XCF_MAX_IMAGE_WIDTH << "x" << XCF_MAX_IMAGE_HEIGHT << "px";
|
||||
if (header->width > MAX_IMAGE_WIDTH || header->height > MAX_IMAGE_HEIGHT) {
|
||||
qCWarning(XCFPLUGIN) << "The maximum image size is limited to" << MAX_IMAGE_WIDTH << "x" << MAX_IMAGE_HEIGHT << "px";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1368,8 +1364,8 @@ bool XCFImageFormat::composeTiles(XCFImage &xcf_image)
|
||||
qCWarning(XCFPLUGIN) << "On 32-bits programs the maximum layer size is limited to" << 16384 << "x" << 16384 << "px";
|
||||
return false;
|
||||
}
|
||||
if (layer.width > XCF_MAX_IMAGE_WIDTH || layer.height > XCF_MAX_IMAGE_HEIGHT) {
|
||||
qCWarning(XCFPLUGIN) << "The maximum layer size is limited to" << XCF_MAX_IMAGE_WIDTH << "x" << XCF_MAX_IMAGE_HEIGHT << "px";
|
||||
if (layer.width > MAX_IMAGE_WIDTH || layer.height > MAX_IMAGE_HEIGHT) {
|
||||
qCWarning(XCFPLUGIN) << "The maximum layer size is limited to" << MAX_IMAGE_WIDTH << "x" << MAX_IMAGE_HEIGHT << "px";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2797,7 +2793,8 @@ void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
|
||||
QPainter painter(&image);
|
||||
painter.setOpacity(layer.opacity / 255.0);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
if (x + layer.x_offset < XCF_MAX_IMAGE_WIDTH && y + layer.y_offset < XCF_MAX_IMAGE_HEIGHT) {
|
||||
if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
|
||||
y + layer.y_offset < MAX_IMAGE_HEIGHT) {
|
||||
painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
|
||||
}
|
||||
continue;
|
||||
@@ -3199,7 +3196,8 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
|
||||
qint32 x = qint32(i * TILE_WIDTH);
|
||||
|
||||
QImage &tile = layer.image_tiles[j][i];
|
||||
if (x + layer.x_offset < XCF_MAX_IMAGE_WIDTH && y + layer.y_offset < XCF_MAX_IMAGE_HEIGHT) {
|
||||
if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
|
||||
y + layer.y_offset < MAX_IMAGE_HEIGHT) {
|
||||
painter.drawImage(x + layer.x_offset, y + layer.y_offset, tile);
|
||||
}
|
||||
}
|
||||
@@ -3250,7 +3248,8 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
|
||||
QPainter painter(&image);
|
||||
painter.setOpacity(layer.opacity / 255.0);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
if (x + layer.x_offset < XCF_MAX_IMAGE_WIDTH && y + layer.y_offset < XCF_MAX_IMAGE_HEIGHT) {
|
||||
if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
|
||||
y + layer.y_offset < MAX_IMAGE_HEIGHT) {
|
||||
painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
|
||||
}
|
||||
continue;
|
||||
|
||||