KImageFormats

xcf.cpp
1/*
2 xcf.cpp: A Qt 5 plug-in for reading GIMP XCF image files
3 SPDX-FileCopyrightText: 2001 lignum Computing Inc. <allen@lignumcomputing.com>
4 SPDX-FileCopyrightText: 2004 Melchior FRANZ <mfranz@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-or-later
7*/
8
9#include "util_p.h"
10#include "xcf_p.h"
11
12#include <QColorSpace>
13#include <QDebug>
14#include <QIODevice>
15#include <QImage>
16#include <QImageReader>
17#include <QList>
18#include <QLoggingCategory>
19#include <QPainter>
20#include <QStack>
21#include <QtEndian>
22
23#ifndef XCF_QT5_SUPPORT
24// Float images are not supported by Qt 5 and can be disabled in QT 6 to reduce memory usage.
25// Unfortunately enabling/disabling this define results in slightly different images, so leave the default if possible.
26#define USE_FLOAT_IMAGES // default uncommented
27
28// Let's set a "reasonable" maximum size
29#define MAX_IMAGE_WIDTH 300000
30#define MAX_IMAGE_HEIGHT 300000
31#else
32// While it is possible to have images larger than 32767 pixels, QPainter seems unable to go beyond this threshold using Qt 5.
33#define MAX_IMAGE_WIDTH 32767
34#define MAX_IMAGE_HEIGHT 32767
35#endif
36
37#ifdef USE_FLOAT_IMAGES
38#include <qrgbafloat.h>
39#endif
40
41#include <stdlib.h>
42#include <string.h>
43
44#include "gimp_p.h"
45
46Q_DECLARE_LOGGING_CATEGORY(XCFPLUGIN)
47Q_LOGGING_CATEGORY(XCFPLUGIN, "kf.imageformats.plugins.xcf", QtWarningMsg)
48
49//#define DISABLE_TILE_PROFILE // default commented (comment to use the conversion as intended by Martin)
50#define DISABLE_IMAGE_PROFILE // default uncommented (comment to use the conversion as intended by Martin)
51#define DISABLE_TILE_PROFILE_CONV // default uncommented (comment to use the conversion as intended by Martin)
52#define DISABLE_IMAGE_PROFILE_CONV // default uncommented (comment to use the conversion as intended by Martin)
53
54const float INCHESPERMETER = (100.0f / 2.54f);
55
56namespace
57{
58struct RandomTable {
59 // From glibc
60 static constexpr int rand_r(unsigned int *seed)
61 {
62 unsigned int next = *seed;
63 int result = 0;
64
65 next *= 1103515245;
66 next += 12345;
67 result = (unsigned int)(next / 65536) % 2048;
68
69 next *= 1103515245;
70 next += 12345;
71 result <<= 10;
72 result ^= (unsigned int)(next / 65536) % 1024;
73
74 next *= 1103515245;
75 next += 12345;
76 result <<= 10;
77 result ^= (unsigned int)(next / 65536) % 1024;
78
79 *seed = next;
80
81 return result;
82 }
83
84 constexpr RandomTable()
85 : values{}
86 {
87 unsigned int next = RANDOM_SEED;
88
89 for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
90 values[i] = rand_r(&next);
91 }
92
93 for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
94 int tmp{};
95 int swap = i + rand_r(&next) % (RANDOM_TABLE_SIZE - i);
96 tmp = values[i];
97 values[i] = values[swap];
98 values[swap] = tmp;
99 }
100 }
101
102 int values[RANDOM_TABLE_SIZE]{};
103};
104} // namespace {
105
106/*!
107 * Each layer in an XCF file is stored as a matrix of
108 * 64-pixel by 64-pixel images. The GIMP has a sophisticated
109 * method of handling very large images as well as implementing
110 * parallel processing on a tile-by-tile basis. Here, though,
111 * we just read them in en-masse and store them in a matrix.
112 */
113typedef QList<QList<QImage>> Tiles;
114
115class XCFImageFormat
116{
117 Q_GADGET
118public:
119 //! Properties which can be stored in an XCF file.
120 enum PropType {
121 PROP_END = 0,
122 PROP_COLORMAP = 1,
123 PROP_ACTIVE_LAYER = 2,
124 PROP_ACTIVE_CHANNEL = 3,
125 PROP_SELECTION = 4,
126 PROP_FLOATING_SELECTION = 5,
127 PROP_OPACITY = 6,
128 PROP_MODE = 7,
129 PROP_VISIBLE = 8,
130 PROP_LINKED = 9,
131 PROP_LOCK_ALPHA = 10,
132 PROP_APPLY_MASK = 11,
133 PROP_EDIT_MASK = 12,
134 PROP_SHOW_MASK = 13,
135 PROP_SHOW_MASKED = 14,
136 PROP_OFFSETS = 15,
137 PROP_COLOR = 16,
138 PROP_COMPRESSION = 17,
139 PROP_GUIDES = 18,
140 PROP_RESOLUTION = 19,
141 PROP_TATTOO = 20,
142 PROP_PARASITES = 21,
143 PROP_UNIT = 22,
144 PROP_PATHS = 23,
145 PROP_USER_UNIT = 24,
146 PROP_VECTORS = 25,
147 PROP_TEXT_LAYER_FLAGS = 26,
148 PROP_OLD_SAMPLE_POINTS = 27,
149 PROP_LOCK_CONTENT = 28,
150 PROP_GROUP_ITEM = 29,
151 PROP_ITEM_PATH = 30,
152 PROP_GROUP_ITEM_FLAGS = 31,
153 PROP_LOCK_POSITION = 32,
154 PROP_FLOAT_OPACITY = 33,
155 PROP_COLOR_TAG = 34,
156 PROP_COMPOSITE_MODE = 35,
157 PROP_COMPOSITE_SPACE = 36,
158 PROP_BLEND_SPACE = 37,
159 PROP_FLOAT_COLOR = 38,
160 PROP_SAMPLE_POINTS = 39,
161 MAX_SUPPORTED_PROPTYPE, // should always be at the end so its value is last + 1
162 };
163 Q_ENUM(PropType)
164
165 //! Compression type used in layer tiles.
166 enum XcfCompressionType : qint8 {
167 COMPRESS_INVALID = -1, /* our own */
168 COMPRESS_NONE = 0,
169 COMPRESS_RLE = 1,
170 COMPRESS_ZLIB = 2, /* unused */
171 COMPRESS_FRACTAL = 3, /* unused */
172 };
173 Q_ENUM(XcfCompressionType)
174
175 enum LayerModeType : quint32 {
176 GIMP_LAYER_MODE_NORMAL_LEGACY,
177 GIMP_LAYER_MODE_DISSOLVE,
178 GIMP_LAYER_MODE_BEHIND_LEGACY,
179 GIMP_LAYER_MODE_MULTIPLY_LEGACY,
180 GIMP_LAYER_MODE_SCREEN_LEGACY,
181 GIMP_LAYER_MODE_OVERLAY_LEGACY,
182 GIMP_LAYER_MODE_DIFFERENCE_LEGACY,
183 GIMP_LAYER_MODE_ADDITION_LEGACY,
184 GIMP_LAYER_MODE_SUBTRACT_LEGACY,
185 GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY,
186 GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY,
187 GIMP_LAYER_MODE_HSV_HUE_LEGACY,
188 GIMP_LAYER_MODE_HSV_SATURATION_LEGACY,
189 GIMP_LAYER_MODE_HSL_COLOR_LEGACY,
190 GIMP_LAYER_MODE_HSV_VALUE_LEGACY,
191 GIMP_LAYER_MODE_DIVIDE_LEGACY,
192 GIMP_LAYER_MODE_DODGE_LEGACY,
193 GIMP_LAYER_MODE_BURN_LEGACY,
194 GIMP_LAYER_MODE_HARDLIGHT_LEGACY,
195 GIMP_LAYER_MODE_SOFTLIGHT_LEGACY,
196 GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY,
197 GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY,
198 GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
199 GIMP_LAYER_MODE_OVERLAY,
200 GIMP_LAYER_MODE_LCH_HUE,
201 GIMP_LAYER_MODE_LCH_CHROMA,
202 GIMP_LAYER_MODE_LCH_COLOR,
203 GIMP_LAYER_MODE_LCH_LIGHTNESS,
204 GIMP_LAYER_MODE_NORMAL,
205 GIMP_LAYER_MODE_BEHIND,
206 GIMP_LAYER_MODE_MULTIPLY,
207 GIMP_LAYER_MODE_SCREEN,
208 GIMP_LAYER_MODE_DIFFERENCE,
209 GIMP_LAYER_MODE_ADDITION,
210 GIMP_LAYER_MODE_SUBTRACT,
211 GIMP_LAYER_MODE_DARKEN_ONLY,
212 GIMP_LAYER_MODE_LIGHTEN_ONLY,
213 GIMP_LAYER_MODE_HSV_HUE,
214 GIMP_LAYER_MODE_HSV_SATURATION,
215 GIMP_LAYER_MODE_HSL_COLOR,
216 GIMP_LAYER_MODE_HSV_VALUE,
217 GIMP_LAYER_MODE_DIVIDE,
218 GIMP_LAYER_MODE_DODGE,
219 GIMP_LAYER_MODE_BURN,
220 GIMP_LAYER_MODE_HARDLIGHT,
221 GIMP_LAYER_MODE_SOFTLIGHT,
222 GIMP_LAYER_MODE_GRAIN_EXTRACT,
223 GIMP_LAYER_MODE_GRAIN_MERGE,
224 GIMP_LAYER_MODE_VIVID_LIGHT,
225 GIMP_LAYER_MODE_PIN_LIGHT,
226 GIMP_LAYER_MODE_LINEAR_LIGHT,
227 GIMP_LAYER_MODE_HARD_MIX,
228 GIMP_LAYER_MODE_EXCLUSION,
229 GIMP_LAYER_MODE_LINEAR_BURN,
230 GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
231 GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
232 GIMP_LAYER_MODE_LUMINANCE,
233 GIMP_LAYER_MODE_COLOR_ERASE,
234 GIMP_LAYER_MODE_ERASE,
235 GIMP_LAYER_MODE_MERGE,
236 GIMP_LAYER_MODE_SPLIT,
237 GIMP_LAYER_MODE_PASS_THROUGH,
238 GIMP_LAYER_MODE_COUNT,
239 };
240 Q_ENUM(LayerModeType)
241
242 //! Type of individual layers in an XCF file.
243 enum GimpImageType : qint32 {
244 RGB_GIMAGE,
245 RGBA_GIMAGE,
246 GRAY_GIMAGE,
247 GRAYA_GIMAGE,
248 INDEXED_GIMAGE,
249 INDEXEDA_GIMAGE,
250 };
251 Q_ENUM(GimpImageType)
252
253 //! Type of individual layers in an XCF file.
254 enum GimpColorSpace : qint32 {
255 AutoColorSpace,
256 RgbLinearSpace,
257 RgbPerceptualSpace,
258 LabSpace,
259 };
260 Q_ENUM(GimpColorSpace);
261
262 //! Mode to use when compositing layer
263 enum GimpCompositeMode : qint32 {
264 CompositeAuto,
265 CompositeUnion,
266 CompositeClipBackdrop,
267 CompositeClipLayer,
268 CompositeIntersect,
269 };
270 Q_ENUM(GimpCompositeMode);
271
272 enum GimpPrecision : qint32 {
273 GIMP_PRECISION_U8_LINEAR = 100, /*< desc="8-bit linear integer" >*/
274 GIMP_PRECISION_U8_NON_LINEAR = 150, /*< desc="8-bit non-linear integer" >*/
275 GIMP_PRECISION_U8_PERCEPTUAL = 175, /*< desc="8-bit perceptual integer" >*/
276 GIMP_PRECISION_U16_LINEAR = 200, /*< desc="16-bit linear integer" >*/
277 GIMP_PRECISION_U16_NON_LINEAR = 250, /*< desc="16-bit non-linear integer" >*/
278 GIMP_PRECISION_U16_PERCEPTUAL = 275, /*< desc="16-bit perceptual integer" >*/
279 GIMP_PRECISION_U32_LINEAR = 300, /*< desc="32-bit linear integer" >*/
280 GIMP_PRECISION_U32_NON_LINEAR = 350, /*< desc="32-bit non-linear integer" >*/
281 GIMP_PRECISION_U32_PERCEPTUAL = 375, /*< desc="32-bit perceptual integer" >*/
282 GIMP_PRECISION_HALF_LINEAR = 500, /*< desc="16-bit linear floating point" >*/
283 GIMP_PRECISION_HALF_NON_LINEAR = 550, /*< desc="16-bit non-linear floating point" >*/
284 GIMP_PRECISION_HALF_PERCEPTUAL = 575, /*< desc="16-bit perceptual floating point" >*/
285 GIMP_PRECISION_FLOAT_LINEAR = 600, /*< desc="32-bit linear floating point" >*/
286 GIMP_PRECISION_FLOAT_NON_LINEAR = 650, /*< desc="32-bit non-linear floating point" >*/
287 GIMP_PRECISION_FLOAT_PERCEPTUAL = 675, /*< desc="32-bit perceptual floating point" >*/
288 GIMP_PRECISION_DOUBLE_LINEAR = 700, /*< desc="64-bit linear floating point" >*/
289 GIMP_PRECISION_DOUBLE_NON_LINEAR = 750, /*< desc="64-bit non-linear floating point" >*/
290 GIMP_PRECISION_DOUBLE_PERCEPTUAL = 775, /*< desc="64-bit perceptual floating point" >*/
291 };
292 Q_ENUM(GimpPrecision);
293
294 XCFImageFormat();
295 bool readXCF(QIODevice *device, QImage *image);
296
297 /*!
298 * Each GIMP image is composed of one or more layers. A layer can
299 * be one of any three basic types: RGB, grayscale or indexed. With an
300 * optional alpha channel, there are six possible types altogether.
301 *
302 * Note: there is only ever one instance of this structure. The
303 * layer info is discarded after it is merged into the final QImage.
304 */
305 class Layer
306 {
307 public:
308 quint32 width; //!< Width of the layer
309 quint32 height; //!< Height of the layer
310 GimpImageType type; //!< Type of the layer (GimpImageType)
311 char *name; //!< Name of the layer
312 qint64 hierarchy_offset; //!< File position of Tile hierarchy
313 qint64 mask_offset; //!< File position of mask image
314
315 uint nrows; //!< Number of rows of tiles (y direction)
316 uint ncols; //!< Number of columns of tiles (x direction)
317
318 Tiles image_tiles; //!< The basic image
319 //! For Grayscale and Indexed images, the alpha channel is stored
320 //! separately (in this data structure, anyway).
321 Tiles alpha_tiles;
322 Tiles mask_tiles; //!< The layer mask (optional)
323
324 //! Additional information about a layer mask.
325 struct {
326 quint32 opacity;
327 float opacityFloat = 1.f;
328 quint32 visible;
329 quint32 show_masked;
330 uchar red, green, blue;
331 float redF, greenF, blueF; // Floats should override
332 quint32 tattoo;
333 } mask_channel;
334
335 XcfCompressionType compression = COMPRESS_INVALID; //!< tile compression method (CompressionType)
336
337 bool active; //!< Is this layer the active layer?
338 quint32 opacity = 255; //!< The opacity of the layer
339 float opacityFloat = 1.f; //!< The opacity of the layer, but floating point (both are set)
340 quint32 visible = 1; //!< Is the layer visible?
341 quint32 linked; //!< Is this layer linked (geometrically)
342 quint32 preserve_transparency; //!< Preserve alpha when drawing on layer?
343 quint32 apply_mask = 9; //!< Apply the layer mask? Use 9 as "uninitilized". Spec says "If the property does not appear for a layer which has a layer
344 //!< mask, it defaults to true (1).
345 // Robust readers should force this to false if the layer has no layer mask.
346 quint32 edit_mask; //!< Is the layer mask the being edited?
347 quint32 show_mask; //!< Show the layer mask rather than the image?
348 qint32 x_offset = 0; //!< x offset of the layer relative to the image
349 qint32 y_offset = 0; //!< y offset of the layer relative to the image
350 LayerModeType mode = GIMP_LAYER_MODE_NORMAL_LEGACY; //!< Combining mode of layer (LayerModeEffects)
351 quint32 tattoo; //!< (unique identifier?)
352 GimpColorSpace blendSpace = RgbLinearSpace; //!< What colorspace to use when blending
353 GimpColorSpace compositeSpace = RgbLinearSpace; //!< What colorspace to use when compositing
354 GimpCompositeMode compositeMode = CompositeUnion; //!< How to composite layer (union, clip, etc.)
355
356 //! As each tile is read from the file, it is buffered here.
357#ifdef USE_FLOAT_IMAGES
358 uchar tile[quint64(TILE_WIDTH * TILE_HEIGHT * sizeof(QRgbaFloat32) * 1.5)];
359#else
360 uchar tile[quint64(TILE_WIDTH * TILE_HEIGHT * sizeof(QRgba64) * 1.5)];
361#endif
362
363 //! The data from tile buffer is copied to the Tile by this
364 //! method. Depending on the type of the tile (RGB, Grayscale,
365 //! Indexed) and use (image or mask), the bytes in the buffer are
366 //! copied in different ways.
367 bool (*assignBytes)(Layer &layer, uint i, uint j, const GimpPrecision &precision);
368
369 Layer(void)
370 : name(nullptr)
371 {
372 }
373 ~Layer(void)
374 {
375 delete[] name;
376 }
377
378 Layer(const Layer &) = delete;
379 Layer &operator=(const Layer &) = delete;
380
381 QImage::Format qimageFormat(const GimpPrecision precision, uint num_colors = 0, bool legacyMode = false) const
382 {
383 int bpc = bytesPerChannel(precision);
384#ifdef USE_FLOAT_IMAGES
385 bool float16 = !legacyMode && precision >= GIMP_PRECISION_HALF_LINEAR && precision <= GIMP_PRECISION_HALF_PERCEPTUAL;
386 bool float32 = !legacyMode && precision >= GIMP_PRECISION_FLOAT_LINEAR && precision <= GIMP_PRECISION_FLOAT_PERCEPTUAL;
387#endif
388
389 if (legacyMode) {
390 bpc = std::min(bpc, 1);
391 }
392
393 switch (type) {
394 case RGB_GIMAGE:
395 if (opacity == OPAQUE_OPACITY) {
396#ifdef USE_FLOAT_IMAGES
397 if (float16) {
399 }
400 if (float32) {
401 return QImage::QImage::Format_RGBX32FPx4;
402 }
403#endif
404
405 if (bpc == 1) {
407 } else if (bpc == 2 || bpc == 4) {
409 } else {
410 qCDebug(XCFPLUGIN) << "Layer has invalid bpc" << bpc << precision;
412 }
413 }
414 Q_FALLTHROUGH();
415 case RGBA_GIMAGE:
416#ifdef USE_FLOAT_IMAGES
417 if (float16) {
419 }
420 if (float32) {
421 return QImage::QImage::Format_RGBA32FPx4;
422 }
423#endif
424 if (bpc == 1) {
426 } else if (bpc == 2 || bpc == 4) {
428 } else {
429 qCDebug(XCFPLUGIN) << "Layer has invalid bpc" << bpc;
431 }
432 break;
433
434 case GRAY_GIMAGE:
435 if (opacity == OPAQUE_OPACITY) {
437 } // else, fall through to 32-bit representation
438 Q_FALLTHROUGH();
439 case GRAYA_GIMAGE:
441 break;
442
443 case INDEXED_GIMAGE:
444 // As noted in the table above, there are quite a few combinations
445 // which are possible with indexed images, depending on the
446 // presence of transparency (note: not translucency, which is not
447 // supported by The GIMP for indexed images) and the number of
448 // individual colors.
449
450 // Note: Qt treats a bitmap with a Black and White color palette
451 // as a mask, so only the "on" bits are drawn, regardless of the
452 // order color table entries. Otherwise (i.e., at least one of the
453 // color table entries is not black or white), it obeys the one-
454 // or two-color palette. Have to ask about this...
455
456 if (num_colors == 1 || num_colors == 2) {
458 } else {
460 }
461 break;
462
463 case INDEXEDA_GIMAGE:
464 if (num_colors == 1) {
466 } else {
468 }
469 }
470 qCWarning(XCFPLUGIN) << "Unhandled layer mode" << XCFImageFormat::LayerModeType(type);
472 }
473 };
474
475 /*!
476 * The in-memory representation of the XCF Image. It contains a few
477 * metadata items, but is mostly a container for the layer information.
478 */
479 class XCFImage
480 {
481 public:
482 struct Header {
483 GimpPrecision precision = GIMP_PRECISION_U8_LINEAR; //!< Default precision (GimpPrecision)
484 quint32 width; //!< width of the XCF image
485 quint32 height; //!< height of the XCF image
486 qint32 type; //!< type of the XCF image (GimpImageBaseType)
487 } header;
488
489 XcfCompressionType compression = COMPRESS_RLE; //!< tile compression method (CompressionType)
490 float x_resolution = -1; //!< x resolution in dots per inch
491 float y_resolution = -1; //!< y resolution in dots per inch
492 qint32 tattoo; //!< (unique identifier?)
493 quint32 unit; //!< Units of The GIMP (inch, mm, pica, etc...)
494 qint32 num_colors = 0; //!< number of colors in an indexed image
495 QList<QRgb> palette; //!< indexed image color palette
496
497 int num_layers; //!< number of layers
498 Layer layer; //!< most recently read layer
499
500 bool initialized; //!< Is the QImage initialized?
501 QImage image; //!< final QImage
502
503 QHash<QString,QByteArray> parasites; //!< parasites data
504
505 XCFImage(void)
506 : initialized(false)
507 {
508 }
509
510 QImage::Format qimageFormat() const
511 {
512 return layer.qimageFormat(header.precision, num_colors, true);
513 }
514
515 uint bytesPerChannel() const
516 {
517 return XCFImageFormat::bytesPerChannel(header.precision);
518 }
519 };
520
521private:
522 static qint64 readOffsetPtr(QDataStream &stream)
523 {
524 if (stream.version() >= 11) {
525 qint64 ret;
526 stream >> ret;
527 return ret;
528 } else {
529 quint32 ret;
530 stream >> ret;
531 return ret;
532 }
533 }
534
535 //! In layer DISSOLVE mode, a random number is chosen to compare to a
536 //! pixel's alpha. If the alpha is greater than the random number, the
537 //! pixel is drawn. This table merely contains the random number seeds
538 //! for each ROW of an image. Therefore, the random numbers chosen
539 //! are consistent from run to run.
540 static int random_table[RANDOM_TABLE_SIZE];
541 static bool random_table_initialized;
542
543 static constexpr RandomTable randomTable{};
544
545 //! This table is used as a shared grayscale ramp to be set on grayscale
546 //! images. This is because Qt does not differentiate between indexed and
547 //! grayscale images.
548 static QList<QRgb> grayTable;
549
550 //! This table provides the add_pixel saturation values (i.e. 250 + 250 = 255).
551 // static int add_lut[256][256]; - this is so lame waste of 256k of memory
552 static int add_lut(int, int);
553
554 //! The bottom-most layer is copied into the final QImage by this
555 //! routine.
556 typedef void (*PixelCopyOperation)(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
557
558 //! Higher layers are merged into the final QImage by this routine.
559 typedef bool (*PixelMergeOperation)(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
560
561 static bool modeAffectsSourceAlpha(const quint32 type);
562
563 bool loadImageProperties(QDataStream &xcf_io, XCFImage &image);
564 bool loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes, quint32 &rawType);
565 bool loadLayer(QDataStream &xcf_io, XCFImage &xcf_image);
566 bool loadLayerProperties(QDataStream &xcf_io, Layer &layer);
567 bool composeTiles(XCFImage &xcf_image);
568 void setGrayPalette(QImage &image);
569 void setPalette(XCFImage &xcf_image, QImage &image);
570 void setImageParasites(const XCFImage &xcf_image, QImage &image);
571 static bool assignImageBytes(Layer &layer, uint i, uint j, const GimpPrecision &precision);
572 bool loadHierarchy(QDataStream &xcf_io, Layer &layer, const GimpPrecision precision);
573 bool loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp, const GimpPrecision precision);
574 static bool assignMaskBytes(Layer &layer, uint i, uint j, const GimpPrecision &precision);
575 bool loadMask(QDataStream &xcf_io, Layer &layer, const GimpPrecision precision);
576 bool loadChannelProperties(QDataStream &xcf_io, Layer &layer);
577 bool initializeImage(XCFImage &xcf_image);
578 bool loadTileRLE(QDataStream &xcf_io, uchar *tile, int size, int data_length, qint32 bpp, qint64 *bytesParsed);
579
580 static void copyLayerToImage(XCFImage &xcf_image);
581 static void copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
582 static void copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
583 static void copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
584 static void copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
585 static void copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
586 static void copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
587 static void copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
588
589 static void mergeLayerIntoImage(XCFImage &xcf_image);
590 static bool mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
591 static bool mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
592 static bool mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
593 static bool mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
594 static bool mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
595 static bool mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
596 static bool mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
597 static bool mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n);
598
599 static void initializeRandomTable();
600 static void dissolveRGBPixels(QImage &image, int x, int y);
601 static void dissolveAlphaPixels(QImage &image, int x, int y);
602
603 static uint bytesPerChannel(const GimpPrecision precision)
604 {
605 switch (precision) {
606 case GIMP_PRECISION_U8_LINEAR:
607 case GIMP_PRECISION_U8_NON_LINEAR:
608 case GIMP_PRECISION_U8_PERCEPTUAL:
609 return 1;
610 break;
611 case GIMP_PRECISION_U16_LINEAR:
612 case GIMP_PRECISION_U16_NON_LINEAR:
613 case GIMP_PRECISION_U16_PERCEPTUAL:
614 case GIMP_PRECISION_HALF_LINEAR:
615 case GIMP_PRECISION_HALF_NON_LINEAR:
616 case GIMP_PRECISION_HALF_PERCEPTUAL:
617 return 2;
618 break;
619
620 case GIMP_PRECISION_U32_LINEAR:
621 case GIMP_PRECISION_U32_NON_LINEAR:
622 case GIMP_PRECISION_U32_PERCEPTUAL:
623 case GIMP_PRECISION_FLOAT_LINEAR:
624 case GIMP_PRECISION_FLOAT_NON_LINEAR:
625 case GIMP_PRECISION_FLOAT_PERCEPTUAL:
626 return 4;
627 break;
628 case GIMP_PRECISION_DOUBLE_LINEAR:
629 case GIMP_PRECISION_DOUBLE_NON_LINEAR:
630 case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
631 return 8;
632 break;
633
634 default:
635 qCDebug(XCFPLUGIN) << "Layer has invalid precision" << precision;
636 return 0;
637 }
638 }
639
640public:
641 static bool readXCFHeader(QDataStream &ds, XCFImage::Header *header);
642};
643
644int XCFImageFormat::random_table[RANDOM_TABLE_SIZE];
645bool XCFImageFormat::random_table_initialized;
646
647constexpr RandomTable XCFImageFormat::randomTable;
648
649QList<QRgb> XCFImageFormat::grayTable;
650
651bool XCFImageFormat::modeAffectsSourceAlpha(const quint32 type)
652{
653 switch (type) {
654 case GIMP_LAYER_MODE_NORMAL_LEGACY:
655 case GIMP_LAYER_MODE_DISSOLVE:
656 case GIMP_LAYER_MODE_BEHIND_LEGACY:
657 return true;
658
659 case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
660 case GIMP_LAYER_MODE_SCREEN_LEGACY:
661 case GIMP_LAYER_MODE_OVERLAY_LEGACY:
662 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
663 case GIMP_LAYER_MODE_ADDITION_LEGACY:
664 case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
665 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
666 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
667 case GIMP_LAYER_MODE_HSV_HUE_LEGACY:
668 case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY:
669 case GIMP_LAYER_MODE_HSL_COLOR_LEGACY:
670 case GIMP_LAYER_MODE_HSV_VALUE_LEGACY:
671 case GIMP_LAYER_MODE_DIVIDE_LEGACY:
672 case GIMP_LAYER_MODE_DODGE_LEGACY:
673 case GIMP_LAYER_MODE_BURN_LEGACY:
674 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY:
675 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY:
676 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY:
677 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY:
678 return false;
679
680 case GIMP_LAYER_MODE_COLOR_ERASE_LEGACY:
681 case GIMP_LAYER_MODE_OVERLAY:
682 case GIMP_LAYER_MODE_LCH_HUE:
683 case GIMP_LAYER_MODE_LCH_CHROMA:
684 case GIMP_LAYER_MODE_LCH_COLOR:
685 case GIMP_LAYER_MODE_LCH_LIGHTNESS:
686 return false;
687
688 case GIMP_LAYER_MODE_NORMAL:
689 return true;
690
691 case GIMP_LAYER_MODE_BEHIND:
692 case GIMP_LAYER_MODE_MULTIPLY:
693 case GIMP_LAYER_MODE_SCREEN:
694 case GIMP_LAYER_MODE_DIFFERENCE:
695 case GIMP_LAYER_MODE_ADDITION:
696 case GIMP_LAYER_MODE_SUBTRACT:
697 case GIMP_LAYER_MODE_DARKEN_ONLY:
698 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
699 case GIMP_LAYER_MODE_HSV_HUE:
700 case GIMP_LAYER_MODE_HSV_SATURATION:
701 case GIMP_LAYER_MODE_HSL_COLOR:
702 case GIMP_LAYER_MODE_HSV_VALUE:
703 case GIMP_LAYER_MODE_DIVIDE:
704 case GIMP_LAYER_MODE_DODGE:
705 case GIMP_LAYER_MODE_BURN:
706 case GIMP_LAYER_MODE_HARDLIGHT:
707 case GIMP_LAYER_MODE_SOFTLIGHT:
708 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
709 case GIMP_LAYER_MODE_GRAIN_MERGE:
710 case GIMP_LAYER_MODE_VIVID_LIGHT:
711 case GIMP_LAYER_MODE_PIN_LIGHT:
712 case GIMP_LAYER_MODE_LINEAR_LIGHT:
713 case GIMP_LAYER_MODE_HARD_MIX:
714 case GIMP_LAYER_MODE_EXCLUSION:
715 case GIMP_LAYER_MODE_LINEAR_BURN:
716 case GIMP_LAYER_MODE_LUMA_DARKEN_ONLY:
717 case GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY:
718 case GIMP_LAYER_MODE_LUMINANCE:
719 case GIMP_LAYER_MODE_COLOR_ERASE:
720 case GIMP_LAYER_MODE_ERASE:
721 case GIMP_LAYER_MODE_MERGE:
722 case GIMP_LAYER_MODE_SPLIT:
723 case GIMP_LAYER_MODE_PASS_THROUGH:
724 return false;
725
726 default:
727 qCWarning(XCFPLUGIN) << "Unhandled layer mode" << XCFImageFormat::LayerModeType(type);
728 return false;
729 }
730}
731
732//! Change a QRgb value's alpha only.
733inline QRgb qRgba(const QRgb rgb, int a)
734{
735 return ((a & 0xff) << 24 | (rgb & RGB_MASK));
736}
737
738/*!
739 * The constructor for the XCF image loader.
740 */
741XCFImageFormat::XCFImageFormat()
742{
743 static_assert(sizeof(QRgb) == 4, "the code assumes sizeof(QRgb) == 4, if that's not your case, help us fix it :)");
744}
745
746/*!
747 * This initializes the tables used in the layer dissolving routines.
748 */
749void XCFImageFormat::initializeRandomTable()
750{
751 // From GIMP "paint_funcs.c" v1.2
752 srand(RANDOM_SEED);
753
754 for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
755 random_table[i] = rand();
756 }
757
758 for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
759 int tmp;
760 int swap = i + rand() % (RANDOM_TABLE_SIZE - i);
761 tmp = random_table[i];
762 random_table[i] = random_table[swap];
763 random_table[swap] = tmp;
764 }
765}
766
767inline int XCFImageFormat::add_lut(int a, int b)
768{
769 return qMin(a + b, 255);
770}
771
772bool XCFImageFormat::readXCFHeader(QDataStream &xcf_io, XCFImage::Header *header)
773{
774 QByteArray tag(14, '\0');
775
776 if (xcf_io.readRawData(tag.data(), tag.size()) != tag.size()) {
777 qCDebug(XCFPLUGIN) << "XCF: read failure on header tag";
778 return false;
779 }
780 if (!tag.startsWith("gimp xcf") || !tag.endsWith('\0')) {
781 qCDebug(XCFPLUGIN) << "XCF: read called on non-XCF file";
782 return false;
783 }
784
785 // Remove null terminator
786 tag.chop(1);
787
788 if (tag.right(4) == "file") {
789 xcf_io.setVersion(0);
790 } else {
791 // Version 1 and onwards use the format "gimp xcf v###" instead of "gimp xcf file"
792 bool ok;
793 xcf_io.setVersion(tag.right(3).toInt(&ok));
794 if (!ok) {
795 qCDebug(XCFPLUGIN) << "Failed to parse version" << tag;
796 return false;
797 }
798 }
799 qCDebug(XCFPLUGIN) << "version" << xcf_io.version();
800
801 if (xcf_io.version() > 12) {
802 qCDebug(XCFPLUGIN) << "Unsupported version" << xcf_io.version();
803 return false;
804 }
805
806 xcf_io >> header->width >> header->height >> header->type;
807
808 if (xcf_io.version() >= 4) {
809 int precision;
810 xcf_io >> precision;
811 qCDebug(XCFPLUGIN) << "Precision" << GimpPrecision(precision);
812 if (xcf_io.version() < 7) {
813 switch (precision) {
814 case 0:
815 precision = GIMP_PRECISION_U8_NON_LINEAR;
816 break;
817 case 1:
818 precision = GIMP_PRECISION_U16_NON_LINEAR;
819 break;
820 case 2:
821 precision = GIMP_PRECISION_U32_LINEAR;
822 break;
823 case 3:
824 precision = GIMP_PRECISION_HALF_LINEAR;
825 break;
826 case 4:
827 precision = GIMP_PRECISION_FLOAT_LINEAR;
828 break;
829 default:
830 if (precision < GIMP_PRECISION_U8_LINEAR) {
831 qCWarning(XCFPLUGIN) << "Invalid precision read" << precision;
832 return false;
833 } else {
834 qCDebug(XCFPLUGIN) << "Unexpected precision" << precision << "in version" << xcf_io.version();
835 }
836 }
837 }
838 header->precision = GimpPrecision(precision);
839 }
840 qCDebug(XCFPLUGIN) << "tag:" << tag << " height: " << header->width << " width: " << header->height << " type: " << header->type;
841
842 if ((sizeof(void *) == 4 && qint64(header->width) * header->height > 16384 * 16384)) {
843 qCWarning(XCFPLUGIN) << "On 32-bits programs the maximum image size is limited to" << 16384 << "x" << 16384 << "px";
844 return false;
845 }
846
847 if (header->width > MAX_IMAGE_WIDTH || header->height > MAX_IMAGE_HEIGHT) {
848 qCWarning(XCFPLUGIN) << "The maximum image size is limited to" << MAX_IMAGE_WIDTH << "x" << MAX_IMAGE_HEIGHT << "px";
849 return false;
850 }
851
852 return true;
853}
854
855bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
856{
857 XCFImage xcf_image;
858 QDataStream xcf_io(device);
859
860 if (!readXCFHeader(xcf_io, &xcf_image.header)) {
861 return false;
862 }
863
864 if (!loadImageProperties(xcf_io, xcf_image)) {
865 return false;
866 }
867
868 // The layers appear to be stored in top-to-bottom order. This is
869 // the reverse of how a merged image must be computed. So, the layer
870 // offsets are pushed onto a LIFO stack (thus, we don't have to load
871 // all the data of all layers before beginning to construct the
872 // merged image).
873
874 QStack<qint64> layer_offsets;
875
876 while (true) {
877 const qint64 layer_offset = readOffsetPtr(xcf_io);
878
879 if (layer_offset == 0) {
880 break;
881 }
882
883 if (layer_offset < 0) {
884 qCDebug(XCFPLUGIN) << "XCF: negative layer offset";
885 return false;
886 }
887
888 layer_offsets.push(layer_offset);
889 }
890
891 xcf_image.num_layers = layer_offsets.size();
892
893 if (layer_offsets.size() == 0) {
894 qCDebug(XCFPLUGIN) << "XCF: no layers!";
895 return false;
896 }
897 qCDebug(XCFPLUGIN) << xcf_image.num_layers << "layers";
898
899 // Load each layer and add it to the image
900 while (!layer_offsets.isEmpty()) {
901 qint64 layer_offset = layer_offsets.pop();
902
903 if (!xcf_io.device()->seek(layer_offset)) {
904 return false;
905 }
906
907 if (!loadLayer(xcf_io, xcf_image)) {
908 return false;
909 }
910 }
911
912 if (!xcf_image.initialized) {
913 qCDebug(XCFPLUGIN) << "XCF: no visible layers!";
914 return false;
915 }
916
917 // The image was created: now I can set metadata and ICC color profile inside it.
918 setImageParasites(xcf_image, xcf_image.image);
919
920 *outImage = xcf_image.image;
921 return true;
922}
923
924/*!
925 * An XCF file can contain an arbitrary number of properties associated
926 * with the image (and layer and mask).
927 * \param xcf_io the data stream connected to the XCF image
928 * \param xcf_image XCF image data.
929 * \return true if there were no I/O errors.
930 */
931bool XCFImageFormat::loadImageProperties(QDataStream &xcf_io, XCFImage &xcf_image)
932{
933 while (true) {
934 PropType type;
935 QByteArray bytes;
936 quint32 rawType;
937
938 if (!loadProperty(xcf_io, type, bytes, rawType)) {
939 qCDebug(XCFPLUGIN) << "XCF: error loading global image properties";
940 return false;
941 }
942
943 QDataStream property(bytes);
944
945 switch (type) {
946 case PROP_END:
947 return true;
948
949 case PROP_COMPRESSION:
950 property >> xcf_image.compression;
951 break;
952
953 case PROP_RESOLUTION:
954 property.setFloatingPointPrecision(QDataStream::SinglePrecision);
955 property >> xcf_image.x_resolution >> xcf_image.y_resolution;
956 break;
957
958 case PROP_TATTOO:
959 property >> xcf_image.tattoo;
960 break;
961
962 case PROP_PARASITES:
963 while (!property.atEnd()) {
964 char *tag;
965#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
966 quint32 size;
967#else
968 qint64 size;
969#endif
970
971 property.readBytes(tag, size);
972
973 quint32 flags;
974 QByteArray data;
975 property >> flags >> data;
976
977 // WARNING: you cannot add metadata to QImage here because it can be null.
978 // Adding a metadata to a QImage when it is null, does nothing (metas are lost).
979 if (tag) // store metadata for future use
980 xcf_image.parasites.insert(QString::fromUtf8(tag), data);
981
982 delete[] tag;
983 }
984 break;
985
986 case PROP_UNIT:
987 property >> xcf_image.unit;
988 break;
989
990 case PROP_PATHS: // This property is ignored.
991 break;
992
993 case PROP_USER_UNIT: // This property is ignored.
994 break;
995
996 case PROP_COLORMAP:
997 property >> xcf_image.num_colors;
998 if (xcf_image.num_colors < 0 || xcf_image.num_colors > 65535) {
999 return false;
1000 }
1001
1002 xcf_image.palette = QList<QRgb>();
1003 xcf_image.palette.reserve(xcf_image.num_colors);
1004
1005 for (int i = 0; i < xcf_image.num_colors; i++) {
1006 uchar r;
1007 uchar g;
1008 uchar b;
1009 property >> r >> g >> b;
1010 xcf_image.palette.push_back(qRgb(r, g, b));
1011 }
1012 break;
1013
1014 default:
1015 qCDebug(XCFPLUGIN) << "XCF: unimplemented image property" << type << "(" << rawType << ")"
1016 << ", size " << bytes.size();
1017 break;
1018 }
1019 }
1020}
1021
1022/*!
1023 * Read a single property from the image file. The property type is returned
1024 * in type and the data is returned in bytes.
1025 * \param xcf the image file data stream.
1026 * \param type returns with the property type.
1027 * \param bytes returns with the property data.
1028 * \return true if there were no IO errors. */
1029bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes, quint32 &rawType)
1030{
1031 quint32 size;
1032
1033 xcf_io >> rawType;
1034 if (rawType >= MAX_SUPPORTED_PROPTYPE) {
1035 type = MAX_SUPPORTED_PROPTYPE;
1036 // we don't support the property, but we still need to read from the device, assume it's like all the
1037 // non custom properties that is data_length + data
1038 xcf_io >> size;
1039 xcf_io.skipRawData(size);
1040 // return true because we don't really want to totally fail on an unsupported property since it may not be fatal
1041 return true;
1042 }
1043
1044 type = PropType(rawType);
1045
1046 char *data = nullptr;
1047
1048 // The colormap property size is not the correct number of bytes:
1049 // The GIMP source xcf.c has size = 4 + ncolors, but it should be
1050 // 4 + 3 * ncolors
1051
1052 if (type == PROP_COLORMAP) {
1053 xcf_io >> size;
1054 quint32 ncolors;
1055 xcf_io >> ncolors;
1056
1057 size = 3 * ncolors + 4;
1058
1059 if (size > 65535 || size < 4) {
1060 return false;
1061 }
1062
1063 data = new char[size];
1064
1065 // since we already read "ncolors" from the stream, we put that data back
1066 data[0] = 0;
1067 data[1] = 0;
1068 data[2] = ncolors >> 8;
1069 data[3] = ncolors & 255;
1070
1071 // ... and read the remaining bytes from the stream
1072 xcf_io.readRawData(data + 4, size - 4);
1073 } else if (type == PROP_USER_UNIT) {
1074 // The USER UNIT property size is not correct. I'm not sure why, though.
1075 float factor;
1076 qint32 digits;
1077
1078 xcf_io >> size >> factor >> digits;
1079
1080 for (int i = 0; i < 5; i++) {
1081 char *unit_strings;
1082
1083 xcf_io >> unit_strings;
1084
1085 delete[] unit_strings;
1086
1087 if (xcf_io.device()->atEnd()) {
1088 qCDebug(XCFPLUGIN) << "XCF: read failure on property " << type;
1089 return false;
1090 }
1091 }
1092
1093 size = 0;
1094 } else {
1095 xcf_io >> size;
1096 if (size > 256000 * 4) {
1097 // NOTE: I didn't find any reference to maximum property dimensions in the specs, so I assume it's just a sanity check.
1098 qCDebug(XCFPLUGIN) << "XCF: loadProperty skips" << type << "due to size being too large";
1099 return false;
1100 }
1101 data = new char[size];
1102 const quint32 dataRead = xcf_io.readRawData(data, size);
1103 if (dataRead < size) {
1104 qCDebug(XCFPLUGIN) << "XCF: loadProperty read less data than expected" << size << dataRead;
1105 memset(&data[dataRead], 0, size - dataRead);
1106 }
1107 }
1108
1109 if (size != 0 && data) {
1110 bytes = QByteArray(data, size);
1111 }
1112
1113 delete[] data;
1114
1115 return true;
1116}
1117
1118/*!
1119 * Load a layer from the XCF file. The data stream must be positioned at
1120 * the beginning of the layer data.
1121 * \param xcf_io the image file data stream.
1122 * \param xcf_image contains the layer and the color table
1123 * (if the image is indexed).
1124 * \return true if there were no I/O errors.
1125 */
1126bool XCFImageFormat::loadLayer(QDataStream &xcf_io, XCFImage &xcf_image)
1127{
1128 Layer &layer(xcf_image.layer);
1129 delete[] layer.name;
1130
1131 xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
1132
1133 // Don't want to keep passing this around, dumb XCF format
1134 layer.compression = XcfCompressionType(xcf_image.compression);
1135
1136 if (!loadLayerProperties(xcf_io, layer)) {
1137 return false;
1138 }
1139
1140 qCDebug(XCFPLUGIN) << "layer: \"" << layer.name << "\", size: " << layer.width << " x " << layer.height << ", type: " << layer.type
1141 << ", mode: " << layer.mode << ", opacity: " << layer.opacity << ", visible: " << layer.visible << ", offset: " << layer.x_offset << ", "
1142 << layer.y_offset << ", compression" << layer.compression;
1143
1144 // Skip reading the rest of it if it is not visible. Typically, when
1145 // you export an image from the The GIMP it flattens (or merges) only
1146 // the visible layers into the output image.
1147
1148 if (layer.visible == 0) {
1149 return true;
1150 }
1151
1152 // If there are any more layers, merge them into the final QImage.
1153
1154 layer.hierarchy_offset = readOffsetPtr(xcf_io);
1155 layer.mask_offset = readOffsetPtr(xcf_io);
1156
1157 if (layer.hierarchy_offset < 0) {
1158 qCDebug(XCFPLUGIN) << "XCF: negative layer hierarchy_offset";
1159 return false;
1160 }
1161
1162 if (layer.mask_offset < 0) {
1163 qCDebug(XCFPLUGIN) << "XCF: negative layer mask_offset";
1164 return false;
1165 }
1166
1167 // Allocate the individual tile QImages based on the size and type
1168 // of this layer.
1169
1170 if (!composeTiles(xcf_image)) {
1171 return false;
1172 }
1173 xcf_io.device()->seek(layer.hierarchy_offset);
1174
1175 // As tiles are loaded, they are copied into the layers tiles by
1176 // this routine. (loadMask(), below, uses a slightly different
1177 // version of assignBytes().)
1178
1179 layer.assignBytes = assignImageBytes;
1180
1181 if (!loadHierarchy(xcf_io, layer, xcf_image.header.precision)) {
1182 return false;
1183 }
1184
1185 if (layer.mask_offset != 0) {
1186 // 9 means its not on the file. Spec says "If the property does not appear for a layer which has a layer mask, it defaults to true (1).
1187 if (layer.apply_mask == 9) {
1188 layer.apply_mask = 1;
1189 }
1190
1191 xcf_io.device()->seek(layer.mask_offset);
1192
1193 if (!loadMask(xcf_io, layer, xcf_image.header.precision)) {
1194 return false;
1195 }
1196 } else {
1197 // Spec says "Robust readers should force this to false if the layer has no layer mask."
1198 layer.apply_mask = 0;
1199 }
1200
1201 // Now we should have enough information to initialize the final
1202 // QImage. The first visible layer determines the attributes
1203 // of the QImage.
1204
1205 if (!xcf_image.initialized) {
1206 if (!initializeImage(xcf_image)) {
1207 return false;
1208 }
1209 copyLayerToImage(xcf_image);
1210 xcf_image.initialized = true;
1211 } else {
1212 const QColorSpace colorspaceBefore = xcf_image.image.colorSpace();
1213 mergeLayerIntoImage(xcf_image);
1214 if (xcf_image.image.colorSpace() != colorspaceBefore) {
1215 qCDebug(XCFPLUGIN) << "Converting color space back to" << colorspaceBefore << "after layer composition";
1216 xcf_image.image.convertToColorSpace(colorspaceBefore);
1217 }
1218 }
1219
1220 return true;
1221}
1222
1223/*!
1224 * An XCF file can contain an arbitrary number of properties associated
1225 * with a layer.
1226 * \param xcf_io the data stream connected to the XCF image.
1227 * \param layer layer to collect the properties.
1228 * \return true if there were no I/O errors.
1229 */
1230bool XCFImageFormat::loadLayerProperties(QDataStream &xcf_io, Layer &layer)
1231{
1232 while (true) {
1233 PropType type;
1234 QByteArray bytes;
1235 quint32 rawType;
1236
1237 if (!loadProperty(xcf_io, type, bytes, rawType)) {
1238 qCDebug(XCFPLUGIN) << "XCF: error loading layer properties";
1239 return false;
1240 }
1241
1242 QDataStream property(bytes);
1243
1244 switch (type) {
1245 case PROP_END:
1246 return true;
1247
1248 case PROP_ACTIVE_LAYER:
1249 layer.active = true;
1250 break;
1251
1252 case PROP_OPACITY:
1253 property >> layer.opacity;
1254 layer.opacity = std::min(layer.opacity, 255u);
1255 break;
1256
1257 case PROP_FLOAT_OPACITY:
1258 // For some reason QDataStream isn't able to read the float (tried
1259 // setting the endianness manually)
1260 if (bytes.size() == 4) {
1261 layer.opacityFloat = qFromBigEndian(*reinterpret_cast<float *>(bytes.data()));
1262 } else {
1263 qCDebug(XCFPLUGIN) << "XCF: Invalid data size for float:" << bytes.size();
1264 }
1265 break;
1266
1267 case PROP_VISIBLE:
1268 property >> layer.visible;
1269 break;
1270
1271 case PROP_LINKED:
1272 property >> layer.linked;
1273 break;
1274
1275 case PROP_LOCK_ALPHA:
1276 property >> layer.preserve_transparency;
1277 break;
1278
1279 case PROP_APPLY_MASK:
1280 property >> layer.apply_mask;
1281 break;
1282
1283 case PROP_EDIT_MASK:
1284 property >> layer.edit_mask;
1285 break;
1286
1287 case PROP_SHOW_MASK:
1288 property >> layer.show_mask;
1289 break;
1290
1291 case PROP_OFFSETS:
1292 property >> layer.x_offset >> layer.y_offset;
1293 break;
1294
1295 case PROP_MODE:
1296 property >> layer.mode;
1297 if (layer.mode >= GIMP_LAYER_MODE_COUNT) {
1298 qCDebug(XCFPLUGIN) << "Found layer with unsupported mode" << LayerModeType(layer.mode) << "Defaulting to mode 0";
1299 layer.mode = GIMP_LAYER_MODE_NORMAL_LEGACY;
1300 }
1301 break;
1302
1303 case PROP_TATTOO:
1304 property >> layer.tattoo;
1305 break;
1306
1307 case PROP_COMPOSITE_SPACE:
1308 property >> layer.compositeSpace;
1309 if (layer.compositeSpace < 0) {
1310 layer.compositeSpace = GimpColorSpace(layer.compositeSpace == std::numeric_limits<qint32>::lowest() ? 0 : -layer.compositeSpace);
1311 }
1312 break;
1313
1314 case PROP_COMPOSITE_MODE:
1315 property >> layer.compositeMode;
1316 if (layer.compositeMode < 0) {
1317 layer.compositeMode =
1318 XCFImageFormat::GimpCompositeMode(layer.compositeMode == std::numeric_limits<qint32>::lowest() ? 0 : -layer.compositeMode);
1319 }
1320 break;
1321
1322 case PROP_BLEND_SPACE:
1323 property >> layer.blendSpace;
1324 if (layer.blendSpace < 0) {
1325 layer.blendSpace = GimpColorSpace(layer.blendSpace == std::numeric_limits<qint32>::lowest() ? 0 : -layer.blendSpace);
1326 }
1327 break;
1328
1329 // Just for organization in the UI, doesn't influence rendering
1330 case PROP_COLOR_TAG:
1331 break;
1332
1333 // We don't support editing, so for now just ignore locking
1334 case PROP_LOCK_CONTENT:
1335 case PROP_LOCK_POSITION:
1336 break;
1337
1338 default:
1339 qCDebug(XCFPLUGIN) << "XCF: unimplemented layer property " << type << "(" << rawType << ")"
1340 << ", size " << bytes.size();
1341 break;
1342 }
1343 }
1344}
1345
1346/*!
1347 * Compute the number of tiles in the current layer and allocate
1348 * QImage structures for each of them.
1349 * \param xcf_image contains the current layer.
1350 */
1351bool XCFImageFormat::composeTiles(XCFImage &xcf_image)
1352{
1353 Layer &layer(xcf_image.layer);
1354
1355 layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
1356 layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
1357
1358 qCDebug(XCFPLUGIN) << "IMAGE: height=" << xcf_image.header.height << ", width=" << xcf_image.header.width;
1359 qCDebug(XCFPLUGIN) << "LAYER: height=" << layer.height << ", width=" << layer.width;
1360 qCDebug(XCFPLUGIN) << "LAYER: rows=" << layer.nrows << ", columns=" << layer.ncols;
1361
1362 // NOTE: starting from GIMP 2.10, images can be very large. The 32K limit for width and height is obsolete
1363 // and it was changed to 300000 (the same as Photoshop Big image). This plugin was able to open an RGB
1364 // image of 108000x40000 pixels saved with GIMP 2.10
1365 // SANITY CHECK: Catch corrupted XCF image file where the width or height
1366 // of a tile is reported are bogus. See Bug# 234030.
1367 if ((sizeof(void *) == 4 && qint64(layer.width) * layer.height > 16384 * 16384)) {
1368 qCWarning(XCFPLUGIN) << "On 32-bits programs the maximum layer size is limited to" << 16384 << "x" << 16384 << "px";
1369 return false;
1370 }
1371 if (layer.width > MAX_IMAGE_WIDTH || layer.height > MAX_IMAGE_HEIGHT) {
1372 qCWarning(XCFPLUGIN) << "The maximum layer size is limited to" << MAX_IMAGE_WIDTH << "x" << MAX_IMAGE_HEIGHT << "px";
1373 return false;
1374 }
1375
1376 // NOTE: A layer is a named rectangular area of pixels which has a definite position with respect to the canvas.
1377 // It may extend beyond the canvas or (more commonly) only cover some of it.
1378 // SANITY CHECK: Avoid to load XCF with a layer grater than 10 times the final image
1379 if (qint64(layer.width) * layer.height / 10 > qint64(xcf_image.header.width) * xcf_image.header.height) {
1380 if (qint64(layer.width) * layer.height > 16384 * 16384) { // large layers only
1381 qCWarning(XCFPLUGIN) << "Euristic sanity check: the image may be corrupted!";
1382 return false;
1383 }
1384 }
1385
1386#ifndef XCF_QT5_SUPPORT
1387 // Qt 6 image allocation limit calculation: we have to check the limit here because the image is splitted in
1388 // tiles of 64x64 pixels. The required memory to build the image is at least doubled because tiles are loaded
1389 // and then the final image is created by copying the tiles inside it.
1390 // NOTE: on Windows to open a 10GiB image the plugin uses 28GiB of RAM
1391 qint64 channels = 1 + (layer.type == RGB_GIMAGE ? 2 : 0) + (layer.type == RGBA_GIMAGE ? 3 : 0);
1392 if (qint64(layer.width) * qint64(layer.height) * channels * 2ll / 1024ll / 1024ll > QImageReader::allocationLimit()) {
1393 qCDebug(XCFPLUGIN) << "Rejecting image as it exceeds the current allocation limit of" << QImageReader::allocationLimit() << "megabytes";
1394 return false;
1395 }
1396#endif
1397
1398 layer.image_tiles.resize(layer.nrows);
1399
1400 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
1401 layer.alpha_tiles.resize(layer.nrows);
1402 }
1403
1404 if (layer.mask_offset != 0) {
1405 layer.mask_tiles.resize(layer.nrows);
1406 }
1407
1408 for (uint j = 0; j < layer.nrows; j++) {
1409 layer.image_tiles[j].resize(layer.ncols);
1410
1411 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
1412 layer.alpha_tiles[j].resize(layer.ncols);
1413 }
1414
1415 if (layer.mask_offset != 0) {
1416 layer.mask_tiles[j].resize(layer.ncols);
1417 }
1418 }
1419
1420 const QImage::Format format = layer.qimageFormat(xcf_image.header.precision);
1421
1422 for (uint j = 0; j < layer.nrows; j++) {
1423 for (uint i = 0; i < layer.ncols; i++) {
1424 uint tile_width = (i + 1) * TILE_WIDTH <= layer.width ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
1425
1426 uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
1427
1428 // Try to create the most appropriate QImage (each GIMP layer
1429 // type is treated slightly differently)
1430
1431 switch (layer.type) {
1432 case RGB_GIMAGE:
1433 case RGBA_GIMAGE:
1434 layer.image_tiles[j][i] = QImage(tile_width, tile_height, format);
1435 if (layer.image_tiles[j][i].isNull()) {
1436 return false;
1437 }
1438 layer.image_tiles[j][i].setColorCount(0);
1439 break;
1440
1441 case GRAY_GIMAGE:
1442 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1443 if (layer.image_tiles[j][i].isNull()) {
1444 return false;
1445 }
1446 layer.image_tiles[j][i].setColorCount(256);
1447 setGrayPalette(layer.image_tiles[j][i]);
1448 break;
1449
1450 case GRAYA_GIMAGE:
1451 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1452 layer.image_tiles[j][i].setColorCount(256);
1453 if (layer.image_tiles[j][i].isNull()) {
1454 return false;
1455 }
1456 setGrayPalette(layer.image_tiles[j][i]);
1457
1458 layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1459 if (layer.alpha_tiles[j][i].isNull()) {
1460 return false;
1461 }
1462 layer.alpha_tiles[j][i].setColorCount(256);
1463 setGrayPalette(layer.alpha_tiles[j][i]);
1464 break;
1465
1466 case INDEXED_GIMAGE:
1467 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1468 layer.image_tiles[j][i].setColorCount(xcf_image.num_colors);
1469 if (layer.image_tiles[j][i].isNull()) {
1470 return false;
1471 }
1472 setPalette(xcf_image, layer.image_tiles[j][i]);
1473 break;
1474
1475 case INDEXEDA_GIMAGE:
1476 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1477 if (layer.image_tiles[j][i].isNull()) {
1478 return false;
1479 }
1480 layer.image_tiles[j][i].setColorCount(xcf_image.num_colors);
1481 setPalette(xcf_image, layer.image_tiles[j][i]);
1482
1483 layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1484 if (layer.alpha_tiles[j][i].isNull()) {
1485 return false;
1486 }
1487 layer.alpha_tiles[j][i].setColorCount(256);
1488 setGrayPalette(layer.alpha_tiles[j][i]);
1489 }
1490 if (layer.type != GRAYA_GIMAGE && layer.image_tiles[j][i].format() != format) {
1491 qCWarning(XCFPLUGIN) << "Selected wrong tile format" << layer.image_tiles[j][i].format() << "expected" << format;
1492 return false;
1493 }
1494
1495#ifndef DISABLE_TILE_PROFILE
1496 switch (xcf_image.header.precision) {
1497 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
1498 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
1499 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
1500 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
1501 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
1502 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
1503 layer.image_tiles[j][i].setColorSpace(QColorSpace::SRgbLinear);
1504 break;
1505 case XCFImageFormat::GIMP_PRECISION_HALF_NON_LINEAR:
1506 case XCFImageFormat::GIMP_PRECISION_FLOAT_NON_LINEAR:
1507 case XCFImageFormat::GIMP_PRECISION_DOUBLE_NON_LINEAR:
1508 case XCFImageFormat::GIMP_PRECISION_U8_NON_LINEAR:
1509 case XCFImageFormat::GIMP_PRECISION_U16_NON_LINEAR:
1510 case XCFImageFormat::GIMP_PRECISION_U32_NON_LINEAR:
1511 layer.image_tiles[j][i].setColorSpace(QColorSpace::SRgb);
1512 break;
1513 case XCFImageFormat::GIMP_PRECISION_HALF_PERCEPTUAL:
1514 case XCFImageFormat::GIMP_PRECISION_FLOAT_PERCEPTUAL:
1515 case XCFImageFormat::GIMP_PRECISION_DOUBLE_PERCEPTUAL:
1516 case XCFImageFormat::GIMP_PRECISION_U8_PERCEPTUAL:
1517 case XCFImageFormat::GIMP_PRECISION_U16_PERCEPTUAL:
1518 case XCFImageFormat::GIMP_PRECISION_U32_PERCEPTUAL:
1519 layer.image_tiles[j][i].setColorSpace(QColorSpace::SRgb);
1520 break;
1521 }
1522#endif
1523 if (layer.mask_offset != 0) {
1524 layer.mask_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1525 layer.mask_tiles[j][i].setColorCount(256);
1526 if (layer.mask_tiles[j][i].isNull()) {
1527 return false;
1528 }
1529 setGrayPalette(layer.mask_tiles[j][i]);
1530 }
1531 }
1532 }
1533 return true;
1534}
1535
1536/*!
1537 * Apply a grayscale palette to the QImage. Note that Qt does not distinguish
1538 * between grayscale and indexed images. A grayscale image is just
1539 * an indexed image with a 256-color, grayscale palette.
1540 * \param image image to set to a grayscale palette.
1541 */
1542void XCFImageFormat::setGrayPalette(QImage &image)
1543{
1544 if (grayTable.isEmpty()) {
1545 grayTable.resize(256);
1546
1547 for (int i = 0; i < 256; i++) {
1548 grayTable[i] = qRgb(i, i, i);
1549 }
1550 }
1551
1552 image.setColorTable(grayTable);
1553}
1554
1555/*!
1556 * Copy the indexed palette from the XCF image into the QImage.
1557 * \param xcf_image XCF image containing the palette read from the data stream.
1558 * \param image image to apply the palette to.
1559 */
1560void XCFImageFormat::setPalette(XCFImage &xcf_image, QImage &image)
1561{
1562 Q_ASSERT(xcf_image.num_colors == xcf_image.palette.size());
1563
1564 image.setColorTable(xcf_image.palette);
1565}
1566
1567/*!
1568 * Copy the parasites info to QImage.
1569 * \param xcf_image XCF image containing the parasites read from the data stream.
1570 * \param image image to apply the parasites data.
1571 * \note Some comment taken from https://gitlab.gnome.org/GNOME/gimp/-/blob/master/devel-docs/parasites.txt
1572 */
1573void XCFImageFormat::setImageParasites(const XCFImage &xcf_image, QImage &image)
1574{
1575 auto&& p = xcf_image.parasites;
1576 auto keys = p.keys();
1577 for (auto &&key : std::as_const(keys)) {
1578 auto value = p.value(key);
1579 if (value.isEmpty())
1580 continue;
1581
1582 // "icc-profile" (IMAGE, PERSISTENT | UNDOABLE)
1583 // This contains an ICC profile describing the color space the
1584 // image was produced in. TIFF images stored in PhotoShop do
1585 // oftentimes contain embedded profiles. An experimental color
1586 // manager exists to use this parasite, and it will be used
1587 // for interchange between TIFF and PNG (identical profiles)
1588 if (key == QStringLiteral("icc-profile")) {
1589 auto cs = QColorSpace::fromIccProfile(value);
1590 if (cs.isValid())
1591 image.setColorSpace(cs);
1592 continue;
1593 }
1594
1595 // "gimp-comment" (IMAGE, PERSISTENT)
1596 // Standard GIF-style image comments. This parasite should be
1597 // human-readable text in UTF-8 encoding. A trailing \0 might
1598 // be included and is not part of the comment. Note that image
1599 // comments may also be present in the "gimp-metadata" parasite.
1600 if (key == QStringLiteral("gimp-comment")) {
1601 value.replace('\0', QByteArray());
1602 image.setText(QStringLiteral(META_KEY_COMMENT), QString::fromUtf8(value));
1603 continue;
1604 }
1605
1606 // "gimp-image-metadata"
1607 // Saved by GIMP 2.10.30 but it is not mentioned in the specification.
1608 // It is an XML block with the properties set using GIMP.
1609 if (key == QStringLiteral("gimp-image-metadata")) {
1610 // NOTE: I arbitrary defined the metadata "XML:org.gimp.xml" because it seems
1611 // a GIMP proprietary XML format (no xmlns defined)
1612 value.replace('\0', QByteArray());
1613 image.setText(QStringLiteral(META_KEY_XML_GIMP), QString::fromUtf8(value));
1614 continue;
1615 }
1616
1617#if 0 // Unable to generate it using latest GIMP version
1618 // "gimp-metadata" (IMAGE, PERSISTENT)
1619 // The metadata associated with the image, serialized as one XMP
1620 // packet. This metadata includes the contents of any XMP, EXIF
1621 // and IPTC blocks from the original image, as well as
1622 // user-specified values such as image comment, copyright,
1623 // license, etc.
1624 if (key == QStringLiteral("gimp-metadata")) {
1625 // NOTE: "XML:com.adobe.xmp" is the meta set by Qt reader when an
1626 // XMP packet is found (e.g. when reading a PNG saved by Photoshop).
1627 // I reused the same key because some programs could search for it.
1628 value.replace('\0', QByteArray());
1629 image.setText(QStringLiteral(META_KEY_XMP_ADOBE), QString::fromUtf8(value));
1630 continue;
1631 }
1632#endif
1633 }
1634
1635#ifdef DISABLE_IMAGE_PROFILE
1636 // final colorspace checks
1637 if (!image.colorSpace().isValid()) {
1638 switch (xcf_image.header.precision) {
1639 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
1640 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
1641 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
1642 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
1643 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
1644 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
1646 break;
1647 default:
1649 break;
1650 }
1651 }
1652#endif
1653}
1654
1655/*!
1656 * Copy the bytes from the tile buffer into the image tile QImage, taking into
1657 * account all the myriad different modes.
1658 * \param layer layer containing the tile buffer and the image tile matrix.
1659 * \param i column index of current tile.
1660 * \param j row index of current tile.
1661 */
1662bool XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j, const GimpPrecision &precision)
1663{
1664 QImage &image = layer.image_tiles[j][i];
1665
1666 const uchar *tile = layer.tile;
1667 const int width = image.width();
1668 const int height = image.height();
1669 const int bytesPerLine = image.bytesPerLine();
1670 uchar *bits = image.bits();
1671
1672 // Handle the special cases
1673 if (layer.type == GRAYA_GIMAGE || layer.type == GRAY_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
1674 auto bpc = bytesPerChannel(precision);
1675 for (int y = 0; y < height; y++) {
1676 uchar *dataPtr = bits + y * bytesPerLine;
1677 uchar *alphaPtr = nullptr;
1678 if (layer.alpha_tiles.size() > j && layer.alpha_tiles.at(j).size() > i) {
1679 QImage &alphaTile = layer.alpha_tiles[j][i];
1680 if (alphaTile.width() >= width && alphaTile.height() > y) {
1681 alphaPtr = alphaTile.scanLine(y);
1682 }
1683 }
1684 if (bpc == 4) {
1685#ifdef USE_FLOAT_IMAGES
1686 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
1687 for (int x = 0; x < width; x++) {
1688 auto src = reinterpret_cast<const quint16 *>(tile);
1689 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1690 if (alphaPtr) {
1691 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1692 tile += sizeof(quint16) * 2;
1693 } else {
1694 tile += sizeof(quint16);
1695 }
1696 }
1697 } else {
1698 for (int x = 0; x < width; x++) {
1699 auto src = reinterpret_cast<const float *>(tile);
1700 *dataPtr++ = qFromBigEndian<float>(src[0]) * 255;
1701 if (alphaPtr) {
1702 *alphaPtr++ = qFromBigEndian<float>(src[1]) * 255;
1703 tile += sizeof(float) * 2;
1704 } else {
1705 tile += sizeof(float);
1706 }
1707 }
1708 }
1709#else
1710 for (int x = 0; x < width; x++) {
1711 auto src = (const quint16 *)tile;
1712 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1713 if (alphaPtr) {
1714 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1715 tile += sizeof(quint16) * 2;
1716 } else {
1717 tile += sizeof(quint16);
1718 }
1719 }
1720#endif
1721 } else if (bpc == 2) {
1722#ifdef USE_FLOAT_IMAGES
1723 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
1724 for (int x = 0; x < width; x++) {
1725 auto src = reinterpret_cast<const quint16 *>(tile);
1726 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1727 if (alphaPtr)
1728 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1729 tile += sizeof(QRgb);
1730 }
1731 } else {
1732 for (int x = 0; x < width; x++) {
1733 auto src = reinterpret_cast<const qfloat16 *>(tile);
1734 *dataPtr++ = qFromBigEndian<qfloat16>(src[0]) * 255;
1735 if (alphaPtr)
1736 *alphaPtr++ = qFromBigEndian<qfloat16>(src[1]) * 255;
1737 tile += sizeof(QRgb);
1738 }
1739 }
1740#else
1741 for (int x = 0; x < width; x++) {
1742 auto src = reinterpret_cast<const quint16 *>(tile);
1743 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1744 if (alphaPtr)
1745 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1746 tile += sizeof(QRgb);
1747 }
1748#endif
1749 } else {
1750 for (int x = 0; x < width; x++) {
1751 if (tile[0] < image.colorCount())
1752 *dataPtr++ = tile[0];
1753 if (alphaPtr)
1754 *alphaPtr++ = tile[1];
1755 tile += sizeof(QRgb);
1756 }
1757 }
1758 }
1759 return true;
1760 }
1761
1762 switch (image.format()) {
1764 for (int y = 0; y < height; y++) {
1765 uchar *dataPtr = image.scanLine(y);
1766 for (int x = 0; x < width * 4; x += 4, tile += 4) {
1767 dataPtr[x + 0] = tile[0];
1768 dataPtr[x + 1] = tile[1];
1769 dataPtr[x + 2] = tile[2];
1770 dataPtr[x + 3] = 255;
1771 }
1772 }
1773 break;
1775 for (int y = 0; y < height; y++) {
1776 const size_t bpl = width * 4;
1777 memcpy(image.scanLine(y), tile + y * bpl, bpl);
1778 }
1779 break;
1781 for (int y = 0; y < height; y++) {
1782 quint16 *dataPtr = reinterpret_cast<quint16 *>(image.scanLine(y));
1783 const size_t bpl = width * sizeof(QRgba64);
1784 const quint16 *src = reinterpret_cast<const quint16 *>(tile + y * bpl);
1785 for (int x = 0; x < width * 4; x += 4) {
1786 dataPtr[x + 0] = qFromBigEndian(src[x + 0]);
1787 dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
1788 dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
1789 dataPtr[x + 3] = 65535;
1790 }
1791 }
1792 break;
1793#ifdef USE_FLOAT_IMAGES
1795 for (int y = 0; y < height; y++) {
1796 qfloat16 *dataPtr = reinterpret_cast<qfloat16 *>(image.scanLine(y));
1797 const qfloat16 *src = reinterpret_cast<const qfloat16 *>(tile + y * width * sizeof(QRgbaFloat16));
1798 for (int x = 0; x < width * 4; x += 4) {
1799 dataPtr[x + 0] = qFromBigEndian(src[x + 0]);
1800 dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
1801 dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
1802 dataPtr[x + 3] = qfloat16(1);
1803 }
1804 }
1805 break;
1807 static_assert(sizeof(QRgbaFloat16) == sizeof(QRgba64), "Different sizes for float and int 16 bit pixels");
1808#endif
1810 for (int y = 0; y < height; y++) {
1811 const size_t bpl = width * sizeof(QRgba64);
1812 qFromBigEndian<qint16>(tile + y * bpl, width * 4, image.scanLine(y));
1813 }
1814 break;
1815#ifdef USE_FLOAT_IMAGES
1817 for (int y = 0; y < height; y++) {
1818 const size_t bpl = width * sizeof(QRgbaFloat32);
1819 qFromBigEndian<qint32>(tile + y * bpl, width * 4, image.scanLine(y));
1820 }
1821 break;
1823 for (int y = 0; y < height; y++) {
1824 float *dataPtr = reinterpret_cast<float *>(image.scanLine(y));
1825 const float *src = reinterpret_cast<const float *>(tile + y * width * sizeof(QRgbaFloat32));
1826 for (int x = 0; x < width * 4; x += 4) {
1827 dataPtr[x + 0] = qFromBigEndian(src[x + 0]);
1828 dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
1829 dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
1830 dataPtr[x + 3] = 1.f;
1831 }
1832 }
1833 break;
1834#endif
1836 for (int y = 0; y < height; y++) {
1837 uchar *dataPtr = bits + y * bytesPerLine;
1838 for (int x = 0; x < width; x++) {
1839 *dataPtr++ = tile[0];
1840 tile += sizeof(QRgb);
1841 }
1842 }
1843 break;
1844 default:
1845 qCWarning(XCFPLUGIN) << "Unhandled image format" << image.format() << "and/or layer type" << layer.type;
1846 return false;
1847 }
1848
1849 return true;
1850}
1851
1852/*!
1853 * The GIMP stores images in a "mipmap"-like hierarchy. As far as the QImage
1854 * is concerned, however, only the top level (i.e., the full resolution image)
1855 * is used.
1856 * \param xcf_io the data stream connected to the XCF image.
1857 * \param layer the layer to collect the image.
1858 * \return true if there were no I/O errors.
1859 */
1860bool XCFImageFormat::loadHierarchy(QDataStream &xcf_io, Layer &layer, const GimpPrecision precision)
1861{
1862 qint32 width;
1863 qint32 height;
1864 quint32 bpp;
1865
1866 xcf_io >> width >> height >> bpp;
1867 const qint64 offset = readOffsetPtr(xcf_io);
1868
1869 qCDebug(XCFPLUGIN) << "width" << width << "height" << height << "bpp" << bpp << "offset" << offset;
1870
1871 if (offset < 0) {
1872 qCDebug(XCFPLUGIN) << "XCF: negative hierarchy offset";
1873 return false;
1874 }
1875
1876 const bool isMask = layer.assignBytes == assignMaskBytes;
1877
1878 // make sure bpp is correct and complain if it is not
1879 switch (layer.type) {
1880 case RGB_GIMAGE:
1881 if (bpp != 3 * bytesPerChannel(precision)) {
1882 qCDebug(XCFPLUGIN) << "Found layer of type RGB but with bpp != 3" << bpp;
1883
1884 if (!isMask) {
1885 return false;
1886 }
1887 }
1888 break;
1889 case RGBA_GIMAGE:
1890 if (bpp != 4 * bytesPerChannel(precision)) {
1891 qCDebug(XCFPLUGIN) << "Found layer of type RGBA but with bpp != 4, got" << bpp << "bpp";
1892
1893 if (!isMask) {
1894 return false;
1895 }
1896 }
1897 break;
1898 case GRAY_GIMAGE:
1899 if (bpp != 1 * bytesPerChannel(precision)) {
1900 qCDebug(XCFPLUGIN) << "Found layer of type Gray but with bpp != 1" << bpp;
1901 return false;
1902 }
1903 break;
1904 case GRAYA_GIMAGE:
1905 if (bpp != 2 * bytesPerChannel(precision)) {
1906 qCDebug(XCFPLUGIN) << "Found layer of type Gray+Alpha but with bpp != 2" << bpp;
1907
1908 if (!isMask) {
1909 return false;
1910 }
1911 }
1912 break;
1913 case INDEXED_GIMAGE:
1914 if (bpp != 1 * bytesPerChannel(precision)) {
1915 qCDebug(XCFPLUGIN) << "Found layer of type Indexed but with bpp != 1" << bpp;
1916 return false;
1917 }
1918 break;
1919 case INDEXEDA_GIMAGE:
1920 if (bpp != 2 * bytesPerChannel(precision)) {
1921 qCDebug(XCFPLUGIN) << "Found layer of type Indexed+Alpha but with bpp != 2" << bpp;
1922
1923 if (!isMask) {
1924 return false;
1925 }
1926 }
1927 break;
1928 }
1929
1930 if (bpp > 4 * bytesPerChannel(precision)) {
1931 qCDebug(XCFPLUGIN) << "bpp is" << bpp << "We don't support layers with bpp > 4";
1932 return false;
1933 }
1934
1935 // GIMP stores images in a "mipmap"-like format (multiple levels of
1936 // increasingly lower resolution). Only the top level is used here,
1937 // however.
1938
1939 quint32 junk;
1940 do {
1941 xcf_io >> junk;
1942
1943 if (xcf_io.device()->atEnd()) {
1944 qCDebug(XCFPLUGIN) << "XCF: read failure on layer " << layer.name << " level offsets";
1945 return false;
1946 }
1947 } while (junk != 0);
1948
1949 qint64 saved_pos = xcf_io.device()->pos();
1950
1951 xcf_io.device()->seek(offset);
1952 if (!loadLevel(xcf_io, layer, bpp, precision)) {
1953 return false;
1954 }
1955
1956 xcf_io.device()->seek(saved_pos);
1957 return true;
1958}
1959
1960template<typename SourceFormat>
1961static bool convertFloatTo16Bit(uchar *output, quint64 outputSize, uchar *input)
1962{
1963 SourceFormat *source = (SourceFormat *)(input);
1964 for (quint64 offset = 0; offset < outputSize; offset++) {
1965 (reinterpret_cast<uint16_t *>(output))[offset] = qToBigEndian(quint16(qBound(0., qFromBigEndian<SourceFormat>(source[offset]) * 65535. + 0.5, 65535.)));
1966 }
1967 return true;
1968}
1969
1970/*!
1971 * Load one level of the image hierarchy (but only the top level is ever used).
1972 * \param xcf_io the data stream connected to the XCF image.
1973 * \param layer the layer to collect the image.
1974 * \param bpp the number of bytes in a pixel.
1975 * \return true if there were no I/O errors.
1976 * \sa loadTileRLE().
1977 */
1978bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp, const GimpPrecision precision)
1979{
1980 auto bpc = bytesPerChannel(precision);
1981 if ((bpc == 0) || (bpp % bpc)) {
1982 qCDebug(XCFPLUGIN) << "XCF: the stream seems corrupted";
1983 return false;
1984 }
1985
1986 qint32 width;
1987 qint32 height;
1988
1989 xcf_io >> width >> height;
1990 qint64 offset = readOffsetPtr(xcf_io);
1991
1992 if (offset < 0) {
1993 qCDebug(XCFPLUGIN) << "XCF: negative level offset";
1994 return false;
1995 }
1996
1997 if (offset == 0) {
1998 // offset 0 with rowsxcols != 0 is probably an error since it means we have tiles
1999 // without data but just clear the bits for now instead of returning false
2000 for (uint j = 0; j < layer.nrows; j++) {
2001 for (uint i = 0; i < layer.ncols; i++) {
2002 layer.image_tiles[j][i].fill(Qt::transparent);
2003 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
2004 layer.alpha_tiles[j][i].fill(Qt::transparent);
2005 }
2006 }
2007 }
2008 return true;
2009 }
2010
2011 bool needConvert = true;
2012 switch (precision) {
2013#ifdef USE_FLOAT_IMAGES
2014 case GIMP_PRECISION_HALF_LINEAR:
2015 case GIMP_PRECISION_HALF_NON_LINEAR:
2016 case GIMP_PRECISION_HALF_PERCEPTUAL:
2017 case GIMP_PRECISION_FLOAT_LINEAR:
2018 case GIMP_PRECISION_FLOAT_NON_LINEAR:
2019 case GIMP_PRECISION_FLOAT_PERCEPTUAL:
2020#endif
2021 case GIMP_PRECISION_U8_LINEAR:
2022 case GIMP_PRECISION_U8_NON_LINEAR:
2023 case GIMP_PRECISION_U8_PERCEPTUAL:
2024 case GIMP_PRECISION_U16_LINEAR:
2025 case GIMP_PRECISION_U16_NON_LINEAR:
2026 case GIMP_PRECISION_U16_PERCEPTUAL:
2027 needConvert = false;
2028 break;
2029 default:
2030 break;
2031 }
2032
2033 const uint blockSize = TILE_WIDTH * TILE_HEIGHT * bpp * 1.5;
2034
2035 QList<uchar> buffer;
2036 if (needConvert) {
2037 buffer.resize(blockSize * (bpp == 2 ? 2 : 1));
2038 }
2039 for (uint j = 0; j < layer.nrows; j++) {
2040 for (uint i = 0; i < layer.ncols; i++) {
2041 if (offset == 0) {
2042 qCDebug(XCFPLUGIN) << "XCF: incorrect number of tiles in layer " << layer.name;
2043 return false;
2044 }
2045
2046 qint64 saved_pos = xcf_io.device()->pos();
2047 qint64 offset2 = readOffsetPtr(xcf_io);
2048
2049 if (offset2 < 0) {
2050 qCDebug(XCFPLUGIN) << "XCF: negative level offset";
2051 return false;
2052 }
2053
2054 // Evidently, RLE can occasionally expand a tile instead of compressing it!
2055 if (offset2 == 0) {
2056 offset2 = offset + blockSize;
2057 }
2058
2059 xcf_io.device()->seek(offset);
2060 qint64 bytesParsed = 0;
2061
2062 switch (layer.compression) {
2063 case COMPRESS_NONE: {
2064 if (xcf_io.version() > 11 || size_t(bpp) > sizeof(QRgba64)) {
2065 qCDebug(XCFPLUGIN) << "Component reading not supported yet";
2066 return false;
2067 }
2068 const int data_size = bpp * TILE_WIDTH * TILE_HEIGHT;
2069 if (data_size > int(blockSize)) {
2070 qCDebug(XCFPLUGIN) << "Tile data too big, we can only fit" << sizeof(layer.tile) << "but need" << data_size;
2071 return false;
2072 }
2073 int dataRead = xcf_io.readRawData(reinterpret_cast<char *>(layer.tile), data_size);
2074 if (dataRead < data_size) {
2075 qCDebug(XCFPLUGIN) << "short read, expected" << data_size << "got" << dataRead;
2076 return false;
2077 }
2078 bytesParsed = dataRead;
2079 break;
2080 }
2081 case COMPRESS_RLE: {
2082 int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
2083 const uint data_size = size * bpp;
2084 if (needConvert) {
2085 if (data_size >= unsigned(buffer.size())) {
2086 qCDebug(XCFPLUGIN) << "Tile data too big, we can only fit" << buffer.size() << "but need" << data_size;
2087 return false;
2088 }
2089 } else {
2090 if (data_size > sizeof(layer.tile)) {
2091 qCDebug(XCFPLUGIN) << "Tile data too big, we can only fit" << sizeof(layer.tile) << "but need" << data_size;
2092 return false;
2093 }
2094 if (blockSize > sizeof(layer.tile)) {
2095 qCWarning(XCFPLUGIN) << "Too small tiles" << sizeof(layer.tile) << "this image requires" << blockSize << sizeof(QRgba64) << bpp;
2096 return false;
2097 }
2098 }
2099 if (!loadTileRLE(xcf_io, needConvert ? buffer.data() : layer.tile, size, offset2 - offset, bpp, &bytesParsed)) {
2100 qCDebug(XCFPLUGIN) << "Failed to read RLE";
2101 return false;
2102 }
2103 break;
2104 }
2105 default:
2106 qCDebug(XCFPLUGIN) << "Unhandled compression" << layer.compression;
2107 return false;
2108 }
2109
2110 if (needConvert) {
2111 if (bytesParsed > buffer.size()) {
2112 qCDebug(XCFPLUGIN) << "Invalid number of bytes parsed" << bytesParsed << buffer.size();
2113 return false;
2114 }
2115
2116 switch (precision) {
2117 case GIMP_PRECISION_U32_LINEAR:
2118 case GIMP_PRECISION_U32_NON_LINEAR:
2119 case GIMP_PRECISION_U32_PERCEPTUAL: {
2120 quint32 *source = reinterpret_cast<quint32 *>(buffer.data());
2121 for (quint64 offset = 0, len = buffer.size() / sizeof(quint32); offset < len; ++offset) {
2122 (reinterpret_cast<quint16 *>(layer.tile))[offset] = qToBigEndian<quint16>(qFromBigEndian(source[offset]) / 65537);
2123 }
2124 break;
2125 }
2126#ifndef USE_FLOAT_IMAGES
2127 case GIMP_PRECISION_HALF_LINEAR:
2128 case GIMP_PRECISION_HALF_NON_LINEAR:
2129 case GIMP_PRECISION_HALF_PERCEPTUAL:
2130 convertFloatTo16Bit<qfloat16>(layer.tile, buffer.size() / sizeof(qfloat16), buffer.data());
2131 break;
2132 case GIMP_PRECISION_FLOAT_LINEAR:
2133 case GIMP_PRECISION_FLOAT_NON_LINEAR:
2134 case GIMP_PRECISION_FLOAT_PERCEPTUAL:
2135 convertFloatTo16Bit<float>(layer.tile, buffer.size() / sizeof(float), buffer.data());
2136 break;
2137 case GIMP_PRECISION_DOUBLE_LINEAR:
2138 case GIMP_PRECISION_DOUBLE_NON_LINEAR:
2139 case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
2140 convertFloatTo16Bit<double>(layer.tile, buffer.size() / sizeof(double), buffer.data());
2141 break;
2142#else
2143 case GIMP_PRECISION_DOUBLE_LINEAR:
2144 case GIMP_PRECISION_DOUBLE_NON_LINEAR:
2145 case GIMP_PRECISION_DOUBLE_PERCEPTUAL: {
2146 double *source = reinterpret_cast<double *>(buffer.data());
2147 for (quint64 offset = 0, len = buffer.size() / sizeof(double); offset < len; ++offset) {
2148 (reinterpret_cast<float *>(layer.tile))[offset] = qToBigEndian<float>(float(qFromBigEndian(source[offset])));
2149 }
2150 break;
2151 }
2152#endif
2153 default:
2154 qCWarning(XCFPLUGIN) << "Unsupported precision" << precision;
2155 return false;
2156 }
2157 }
2158
2159 // The bytes in the layer tile are juggled differently depending on
2160 // the target QImage. The caller has set layer.assignBytes to the
2161 // appropriate routine.
2162 if (!layer.assignBytes(layer, i, j, precision)) {
2163 return false;
2164 }
2165
2166 xcf_io.device()->seek(saved_pos);
2167 offset = readOffsetPtr(xcf_io);
2168
2169 if (offset < 0) {
2170 qCDebug(XCFPLUGIN) << "XCF: negative level offset";
2171 return false;
2172 }
2173 }
2174 }
2175
2176 return true;
2177}
2178
2179/*!
2180 * A layer can have a one channel image which is used as a mask.
2181 * \param xcf_io the data stream connected to the XCF image.
2182 * \param layer the layer to collect the mask image.
2183 * \return true if there were no I/O errors.
2184 */
2185bool XCFImageFormat::loadMask(QDataStream &xcf_io, Layer &layer, const GimpPrecision precision)
2186{
2187 qint32 width;
2188 qint32 height;
2189 char *name;
2190
2191 xcf_io >> width >> height >> name;
2192
2193 delete[] name;
2194
2195 if (!loadChannelProperties(xcf_io, layer)) {
2196 return false;
2197 }
2198
2199 const qint64 hierarchy_offset = readOffsetPtr(xcf_io);
2200
2201 if (hierarchy_offset < 0) {
2202 qCDebug(XCFPLUGIN) << "XCF: negative mask hierarchy_offset";
2203 return false;
2204 }
2205
2206 xcf_io.device()->seek(hierarchy_offset);
2207 layer.assignBytes = assignMaskBytes;
2208
2209 if (!loadHierarchy(xcf_io, layer, precision)) {
2210 return false;
2211 }
2212
2213 return true;
2214}
2215
2216/*!
2217 * This is the routine for which all the other code is simply
2218 * infrastructure. Read the image bytes out of the file and
2219 * store them in the tile buffer. This is passed a full 32-bit deep
2220 * buffer, even if bpp is smaller. The caller can figure out what to
2221 * do with the bytes.
2222 *
2223 * The tile is stored in "channels", i.e. the red component of all
2224 * pixels, then the green component of all pixels, then blue then
2225 * alpha, or, for indexed images, the color indices of all pixels then
2226 * the alpha of all pixels.
2227 *
2228 * The data is compressed with "run length encoding". Some simple data
2229 * integrity checks are made.
2230 *
2231 * \param xcf_io the data stream connected to the XCF image.
2232 * \param tile the buffer to expand the RLE into.
2233 * \param image_size number of bytes expected to be in the image tile.
2234 * \param data_length number of bytes expected in the RLE.
2235 * \param bpp number of bytes per pixel.
2236 * \return true if there were no I/O errors and no obvious corruption of
2237 * the RLE data.
2238 */
2239bool XCFImageFormat::loadTileRLE(QDataStream &xcf_io, uchar *tile, int image_size, int data_length, qint32 bpp, qint64 *bytesParsed)
2240{
2241 uchar *data = tile;
2242
2243 uchar *xcfdata;
2244 uchar *xcfodata;
2245 uchar *xcfdatalimit;
2246
2247 int step = sizeof(QRgb);
2248 switch (bpp) {
2249 case 1:
2250 case 2:
2251 case 3:
2252 case 4:
2253 step = sizeof(QRgb);
2254 break;
2255 case 6:
2256 case 8:
2257 step = sizeof(QRgb) * 2;
2258 break;
2259 case 12:
2260 case 16:
2261 step = sizeof(QRgb) * 4;
2262 break;
2263 default:
2264 qCDebug(XCFPLUGIN) << "XCF: unhandled bit depth" << bpp;
2265 return false;
2266 }
2267
2268 if (data_length < 0 || data_length > int(TILE_WIDTH * TILE_HEIGHT * step * 1.5)) {
2269 qCDebug(XCFPLUGIN) << "XCF: invalid tile data length" << data_length;
2270 return false;
2271 }
2272
2273 xcfdata = xcfodata = new uchar[data_length];
2274
2275 const int dataRead = xcf_io.readRawData((char *)xcfdata, data_length);
2276 if (dataRead <= 0) {
2277 delete[] xcfodata;
2278 qCDebug(XCFPLUGIN) << "XCF: read failure on tile" << dataRead;
2279 return false;
2280 }
2281
2282 if (dataRead < data_length) {
2283 memset(&xcfdata[dataRead], 0, data_length - dataRead);
2284 }
2285
2286 if (!xcf_io.device()->isOpen()) {
2287 delete[] xcfodata;
2288 qCDebug(XCFPLUGIN) << "XCF: read failure on tile";
2289 return false;
2290 }
2291
2292 xcfdatalimit = &xcfodata[data_length - 1];
2293
2294 for (int i = 0; i < bpp; ++i) {
2295 data = tile + i;
2296
2297 int size = image_size;
2298
2299 while (size > 0) {
2300 if (xcfdata > xcfdatalimit) {
2301 goto bogus_rle;
2302 }
2303
2304 uchar val = *xcfdata++;
2305 uint length = val;
2306
2307 if (length >= 128) {
2308 length = 255 - (length - 1);
2309 if (length == 128) {
2310 if (xcfdata >= xcfdatalimit) {
2311 goto bogus_rle;
2312 }
2313
2314 length = (*xcfdata << 8) + xcfdata[1];
2315
2316 xcfdata += 2;
2317 }
2318
2319 size -= length;
2320
2321 if (size < 0) {
2322 goto bogus_rle;
2323 }
2324
2325 if (&xcfdata[length - 1] > xcfdatalimit) {
2326 goto bogus_rle;
2327 }
2328
2329 while (length-- > 0) {
2330 *data = *xcfdata++;
2331 data += step;
2332 }
2333 } else {
2334 length += 1;
2335 if (length == 128) {
2336 if (xcfdata >= xcfdatalimit) {
2337 goto bogus_rle;
2338 }
2339
2340 length = (*xcfdata << 8) + xcfdata[1];
2341 xcfdata += 2;
2342 }
2343
2344 size -= length;
2345
2346 if (size < 0) {
2347 goto bogus_rle;
2348 }
2349
2350 if (xcfdata > xcfdatalimit) {
2351 goto bogus_rle;
2352 }
2353
2354 qintptr totalLength = qintptr(data - tile) + length * step;
2355 if (totalLength >= image_size * step * 1.5) {
2356 qCDebug(XCFPLUGIN) << "Ran out of space when trying to unpack image, over:" << totalLength - image_size << totalLength << image_size
2357 << length;
2358 goto bogus_rle;
2359 }
2360
2361 val = *xcfdata++;
2362
2363 while (length-- > 0) {
2364 *data = val;
2365 data += step;
2366 }
2367 }
2368 }
2369 }
2370 *bytesParsed = qintptr(data - tile);
2371
2372 delete[] xcfodata;
2373 return true;
2374
2375bogus_rle:
2376
2377 qCDebug(XCFPLUGIN) << "The run length encoding could not be decoded properly";
2378 delete[] xcfodata;
2379 return false;
2380}
2381
2382/*!
2383 * An XCF file can contain an arbitrary number of properties associated
2384 * with a channel. Note that this routine only reads mask channel properties.
2385 * \param xcf_io the data stream connected to the XCF image.
2386 * \param layer layer containing the mask channel to collect the properties.
2387 * \return true if there were no I/O errors.
2388 */
2389bool XCFImageFormat::loadChannelProperties(QDataStream &xcf_io, Layer &layer)
2390{
2391 while (true) {
2392 PropType type;
2393 QByteArray bytes;
2394 quint32 rawType;
2395
2396 if (!loadProperty(xcf_io, type, bytes, rawType)) {
2397 qCDebug(XCFPLUGIN) << "XCF: error loading channel properties";
2398 return false;
2399 }
2400
2401 QDataStream property(bytes);
2402
2403 switch (type) {
2404 case PROP_END:
2405 return true;
2406
2407 case PROP_OPACITY:
2408 property >> layer.mask_channel.opacity;
2409 layer.mask_channel.opacity = std::min(layer.mask_channel.opacity, 255u);
2410 break;
2411
2412 case PROP_FLOAT_OPACITY:
2413 // For some reason QDataStream isn't able to read the float (tried
2414 // setting the endianness manually)
2415 if (bytes.size() == 4) {
2416 layer.mask_channel.opacityFloat = qFromBigEndian(*reinterpret_cast<float *>(bytes.data()));
2417 } else {
2418 qCDebug(XCFPLUGIN) << "XCF: Invalid data size for float:" << bytes.size();
2419 }
2420 break;
2421
2422 case PROP_VISIBLE:
2423 property >> layer.mask_channel.visible;
2424 break;
2425
2426 case PROP_SHOW_MASKED:
2427 property >> layer.mask_channel.show_masked;
2428 break;
2429
2430 case PROP_COLOR:
2431 property >> layer.mask_channel.red >> layer.mask_channel.green >> layer.mask_channel.blue;
2432 break;
2433
2434 case PROP_FLOAT_COLOR:
2435 property >> layer.mask_channel.redF >> layer.mask_channel.greenF >> layer.mask_channel.blueF;
2436 break;
2437
2438 case PROP_TATTOO:
2439 property >> layer.mask_channel.tattoo;
2440 break;
2441
2442 // Only used in edit mode
2443 case PROP_LINKED:
2444 break;
2445
2446 // Just for organization in the UI, doesn't influence rendering
2447 case PROP_COLOR_TAG:
2448 break;
2449
2450 // We don't support editing, so for now just ignore locking
2451 case PROP_LOCK_CONTENT:
2452 case PROP_LOCK_POSITION:
2453 break;
2454
2455 default:
2456 qCDebug(XCFPLUGIN) << "XCF: unimplemented channel property " << type << "(" << rawType << ")"
2457 << ", size " << bytes.size();
2458 break;
2459 }
2460 }
2461}
2462
2463/*!
2464 * Copy the bytes from the tile buffer into the mask tile QImage.
2465 * \param layer layer containing the tile buffer and the mask tile matrix.
2466 * \param i column index of current tile.
2467 * \param j row index of current tile.
2468 */
2469bool XCFImageFormat::assignMaskBytes(Layer &layer, uint i, uint j, const GimpPrecision &precision)
2470{
2471 QImage &image = layer.mask_tiles[j][i];
2472 if (image.depth() != 8) {
2473 qCWarning(XCFPLUGIN) << "invalid bytes per pixel, we only do 8 bit masks" << image.depth();
2474 return false;
2475 }
2476
2477 uchar *tile = layer.tile;
2478 const int width = image.width();
2479 const int height = image.height();
2480 const int bytesPerLine = image.bytesPerLine();
2481 uchar *bits = image.bits();
2482 auto bpc = bytesPerChannel(precision);
2483
2484 // mask management is a house of cards: the mask is always treated as 8 bit by the plugin
2485 // (I don't want to twist the code) so it needs a conversion here.
2486 // If previously converted the step is the type size, otherwise is the one set in loadTileRLE().
2487 for (int y = 0; y < height; y++) {
2488 uchar *dataPtr = bits + y * bytesPerLine;
2489#ifdef USE_FLOAT_IMAGES
2490 if (bpc == 4) {
2491 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
2492 for (int x = 0; x < width; x++) {
2493 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2494 tile += sizeof(quint16); // was converted to 16 bits in loadLevel()
2495 }
2496 } else {
2497 for (int x = 0; x < width; x++) {
2498 *dataPtr++ = qFromBigEndian<float>(*reinterpret_cast<const float *>(tile)) * 255;
2499 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2500 }
2501 }
2502 } else if (bpc == 2) {
2503 // when not converted, the step of a
2504 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
2505 for (int x = 0; x < width; x++) {
2506 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2507 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2508 }
2509 } else {
2510 for (int x = 0; x < width; x++) {
2511 *dataPtr++ = qFromBigEndian<qfloat16>(*reinterpret_cast<const qfloat16 *>(tile)) * 255;
2512 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2513 }
2514 }
2515 }
2516#else
2517 if (bpc == 2) {
2518 for (int x = 0; x < width; x++) {
2519 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2520 tile += sizeof(QRgb); // yeah! see loadTileRLE() / loadLevel()
2521 }
2522 } else if (bpc == 4) {
2523 for (int x = 0; x < width; x++) {
2524 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2525 tile += sizeof(quint16); // was converted to 16 bits in loadLevel()
2526 }
2527 }
2528#endif
2529 else {
2530 for (int x = 0; x < width; x++) {
2531 *dataPtr++ = tile[0];
2532 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2533 }
2534 }
2535 }
2536
2537 return true;
2538}
2539
2540/*!
2541 * Construct the QImage which will eventually be returned to the QImage
2542 * loader.
2543 *
2544 * There are a couple of situations which require that the QImage is not
2545 * exactly the same as The GIMP's representation. The full table is:
2546 * \verbatim
2547 * Grayscale opaque : 8 bpp indexed
2548 * Grayscale translucent : 32 bpp + alpha
2549 * Indexed opaque : 1 bpp if num_colors <= 2
2550 * : 8 bpp indexed otherwise
2551 * Indexed translucent : 8 bpp indexed + alpha if num_colors < 256
2552 * : 32 bpp + alpha otherwise
2553 * RGB opaque : 32 bpp
2554 * RGBA translucent : 32 bpp + alpha
2555 * \endverbatim
2556 * Whether the image is translucent or not is determined by the bottom layer's
2557 * alpha channel. However, even if the bottom layer lacks an alpha channel,
2558 * it can still have an opacity < 1. In this case, the QImage is promoted
2559 * to 32-bit. (Note this is different from the output from the GIMP image
2560 * exporter, which seems to ignore this attribute.)
2561 *
2562 * Independently, higher layers can be translucent, but the background of
2563 * the image will not show through if the bottom layer is opaque.
2564 *
2565 * For indexed images, translucency is an all or nothing effect.
2566 * \param xcf_image contains image info and bottom-most layer.
2567 */
2568bool XCFImageFormat::initializeImage(XCFImage &xcf_image)
2569{
2570 // (Aliases to make the code look a little better.)
2571 Layer &layer(xcf_image.layer);
2572 QImage &image(xcf_image.image);
2573
2574 switch (layer.type) {
2575 case GRAY_GIMAGE:
2576 if (layer.opacity == OPAQUE_OPACITY) {
2577 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_Indexed8);
2578 image.setColorCount(256);
2579 if (image.isNull()) {
2580 return false;
2581 }
2582 setGrayPalette(image);
2583 image.fill(255);
2584 break;
2585 } // else, fall through to 32-bit representation
2586 Q_FALLTHROUGH();
2587 case GRAYA_GIMAGE:
2588 case RGB_GIMAGE:
2589 case RGBA_GIMAGE:
2590 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, xcf_image.qimageFormat());
2591 if (image.isNull()) {
2592 return false;
2593 }
2594 if (image.hasAlphaChannel()) {
2595 image.fill(Qt::transparent);
2596 } else {
2597 image.fill(Qt::white);
2598 }
2599 break;
2600
2601 case INDEXED_GIMAGE:
2602 // As noted in the table above, there are quite a few combinations
2603 // which are possible with indexed images, depending on the
2604 // presence of transparency (note: not translucency, which is not
2605 // supported by The GIMP for indexed images) and the number of
2606 // individual colors.
2607
2608 // Note: Qt treats a bitmap with a Black and White color palette
2609 // as a mask, so only the "on" bits are drawn, regardless of the
2610 // order color table entries. Otherwise (i.e., at least one of the
2611 // color table entries is not black or white), it obeys the one-
2612 // or two-color palette. Have to ask about this...
2613
2614 if (xcf_image.num_colors <= 2) {
2615 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_MonoLSB);
2616 image.setColorCount(xcf_image.num_colors);
2617 if (image.isNull()) {
2618 return false;
2619 }
2620 image.fill(0);
2621 setPalette(xcf_image, image);
2622 } else if (xcf_image.num_colors <= 256) {
2623 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_Indexed8);
2624 image.setColorCount(xcf_image.num_colors);
2625 if (image.isNull()) {
2626 return false;
2627 }
2628 image.fill(0);
2629 setPalette(xcf_image, image);
2630 }
2631 break;
2632
2633 case INDEXEDA_GIMAGE:
2634 if (xcf_image.num_colors == 1) {
2635 // Plenty(!) of room to add a transparent color
2636 xcf_image.num_colors++;
2637 xcf_image.palette.resize(xcf_image.num_colors);
2638 xcf_image.palette[1] = xcf_image.palette[0];
2639 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
2640
2641 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_MonoLSB);
2642 image.setColorCount(xcf_image.num_colors);
2643 if (image.isNull()) {
2644 return false;
2645 }
2646 image.fill(0);
2647 setPalette(xcf_image, image);
2648 } else if (xcf_image.num_colors < 256) {
2649 // Plenty of room to add a transparent color
2650 xcf_image.num_colors++;
2651 xcf_image.palette.resize(xcf_image.num_colors);
2652 for (int c = xcf_image.num_colors - 1; c >= 1; c--) {
2653 xcf_image.palette[c] = xcf_image.palette[c - 1];
2654 }
2655
2656 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
2657 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_Indexed8);
2658 image.setColorCount(xcf_image.num_colors);
2659 if (image.isNull()) {
2660 return false;
2661 }
2662 image.fill(0);
2663 setPalette(xcf_image, image);
2664 } else {
2665 // No room for a transparent color, so this has to be promoted to
2666 // true color. (There is no equivalent PNG representation output
2667 // from The GIMP as of v1.2.)
2668 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_ARGB32);
2669 if (image.isNull()) {
2670 return false;
2671 }
2672 image.fill(qRgba(255, 255, 255, 0));
2673 }
2674 break;
2675 }
2676 if (image.format() != xcf_image.qimageFormat()) {
2677 qCWarning(XCFPLUGIN) << "Selected wrong format:" << image.format() << "expected" << layer.qimageFormat(xcf_image.header.precision);
2678 return false;
2679 }
2680
2681 // The final profile should be the one in the Parasite
2682 // NOTE: if not set here, the colorSpace is aet in setImageParasites() (if no one defined in the parasites)
2683#ifndef DISABLE_IMAGE_PROFILE
2684 switch (xcf_image.header.precision) {
2685 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
2686 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
2687 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
2688 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
2689 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
2690 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
2692 break;
2693 case XCFImageFormat::GIMP_PRECISION_HALF_NON_LINEAR:
2694 case XCFImageFormat::GIMP_PRECISION_FLOAT_NON_LINEAR:
2695 case XCFImageFormat::GIMP_PRECISION_DOUBLE_NON_LINEAR:
2696 case XCFImageFormat::GIMP_PRECISION_U8_NON_LINEAR:
2697 case XCFImageFormat::GIMP_PRECISION_U16_NON_LINEAR:
2698 case XCFImageFormat::GIMP_PRECISION_U32_NON_LINEAR:
2700 break;
2701 case XCFImageFormat::GIMP_PRECISION_HALF_PERCEPTUAL:
2702 case XCFImageFormat::GIMP_PRECISION_FLOAT_PERCEPTUAL:
2703 case XCFImageFormat::GIMP_PRECISION_DOUBLE_PERCEPTUAL:
2704 case XCFImageFormat::GIMP_PRECISION_U8_PERCEPTUAL:
2705 case XCFImageFormat::GIMP_PRECISION_U16_PERCEPTUAL:
2706 case XCFImageFormat::GIMP_PRECISION_U32_PERCEPTUAL:
2708 break;
2709 }
2710#endif
2711
2712 if (xcf_image.x_resolution > 0 && xcf_image.y_resolution > 0) {
2713 const float dpmx = xcf_image.x_resolution * INCHESPERMETER;
2714 if (dpmx > float(std::numeric_limits<int>::max())) {
2715 return false;
2716 }
2717 const float dpmy = xcf_image.y_resolution * INCHESPERMETER;
2718 if (dpmy > float(std::numeric_limits<int>::max())) {
2719 return false;
2720 }
2721 image.setDotsPerMeterX((int)dpmx);
2722 image.setDotsPerMeterY((int)dpmy);
2723 }
2724 return true;
2725}
2726
2727/*!
2728 * Copy a layer into an image, taking account of the manifold modes. The
2729 * contents of the image are replaced.
2730 * \param xcf_image contains the layer and image to be replaced.
2731 */
2732void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
2733{
2734 Layer &layer(xcf_image.layer);
2735 QImage &image(xcf_image.image);
2736 PixelCopyOperation copy = nullptr;
2737
2738 switch (layer.type) {
2739 case RGB_GIMAGE:
2740 case RGBA_GIMAGE:
2741 copy = copyRGBToRGB;
2742 break;
2743 case GRAY_GIMAGE:
2744 if (layer.opacity == OPAQUE_OPACITY) {
2745 copy = copyGrayToGray;
2746 } else {
2747 copy = copyGrayToRGB;
2748 }
2749 break;
2750 case GRAYA_GIMAGE:
2751 copy = copyGrayAToRGB;
2752 break;
2753 case INDEXED_GIMAGE:
2754 copy = copyIndexedToIndexed;
2755 break;
2756 case INDEXEDA_GIMAGE:
2757 if (xcf_image.image.depth() <= 8) {
2758 copy = copyIndexedAToIndexed;
2759 } else {
2760 copy = copyIndexedAToRGB;
2761 }
2762 }
2763
2764 if (!copy) {
2765 return;
2766 }
2767
2768 // For each tile...
2769
2770 for (uint j = 0; j < layer.nrows; j++) {
2771 qint32 y = qint32(j * TILE_HEIGHT);
2772
2773 for (uint i = 0; i < layer.ncols; i++) {
2774 qint32 x = qint32(i * TILE_WIDTH);
2775
2776 // This seems the best place to apply the dissolve because it
2777 // depends on the global position of each tile's
2778 // pixels. Apparently it's the only mode which can apply to a
2779 // single layer.
2780
2781 if (layer.mode == GIMP_LAYER_MODE_DISSOLVE) {
2782 if (!random_table_initialized) {
2783 initializeRandomTable();
2784 random_table_initialized = true;
2785 }
2786 if (layer.type == RGBA_GIMAGE) {
2787 dissolveRGBPixels(layer.image_tiles[j][i], x, y);
2788 }
2789
2790 else if (layer.type == GRAYA_GIMAGE) {
2791 dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
2792 }
2793 }
2794
2795 // Shortcut for common case
2796 if (copy == copyRGBToRGB && layer.apply_mask != 1) {
2797 QPainter painter(&image);
2798 painter.setOpacity(layer.opacity / 255.0);
2799 painter.setCompositionMode(QPainter::CompositionMode_Source);
2800 if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
2801 y + layer.y_offset < MAX_IMAGE_HEIGHT) {
2802 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
2803 }
2804 continue;
2805 }
2806
2807 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
2808 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
2809 int m = x + k + layer.x_offset;
2810 int n = y + l + layer.y_offset;
2811
2812 if (m < 0 || m >= image.width() || n < 0 || n >= image.height()) {
2813 continue;
2814 }
2815
2816 (*copy)(layer, i, j, k, l, image, m, n);
2817 }
2818 }
2819 }
2820 }
2821}
2822
2823/*!
2824 * Copy an RGB pixel from the layer to the RGB image. Straight-forward.
2825 * The only thing this has to take account of is the opacity of the
2826 * layer. Evidently, the GIMP exporter itself does not actually do this.
2827 * \param layer source layer.
2828 * \param i x tile index.
2829 * \param j y tile index.
2830 * \param k x pixel index of tile i,j.
2831 * \param l y pixel index of tile i,j.
2832 * \param image destination image.
2833 * \param m x pixel of destination image.
2834 * \param n y pixel of destination image.
2835 */
2836void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2837{
2838 if (image.depth() == 32) {
2839 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2840 uchar src_a = layer.opacity;
2841
2842 if (layer.type == RGBA_GIMAGE) {
2843 src_a = INT_MULT(src_a, qAlpha(src));
2844 }
2845
2846 // Apply the mask (if any)
2847
2848 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2849 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2850 }
2851
2852 image.setPixel(m, n, qRgba(src, src_a));
2853 } else if (image.depth() == 64) {
2854 QRgba64 src = layer.image_tiles[j][i].pixelColor(k, l).rgba64();
2855 quint16 src_a = layer.opacity;
2856
2857 if (layer.type == RGBA_GIMAGE) {
2858 src_a = INT_MULT(src_a, qAlpha(src));
2859 }
2860
2861 // Apply the mask (if any)
2862
2863 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2864 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2865 }
2866 src.setAlpha(src_a);
2867
2868 image.setPixel(m, n, src);
2869 }
2870}
2871
2872/*!
2873 * Copy a Gray pixel from the layer to the Gray image. Straight-forward.
2874 * \param layer source layer.
2875 * \param i x tile index.
2876 * \param j y tile index.
2877 * \param k x pixel index of tile i,j.
2878 * \param l y pixel index of tile i,j.
2879 * \param image destination image.
2880 * \param m x pixel of destination image.
2881 * \param n y pixel of destination image.
2882 */
2883void XCFImageFormat::copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2884{
2885 int src = layer.image_tiles[j][i].pixelIndex(k, l);
2886 image.setPixel(m, n, src);
2887}
2888
2889/*!
2890 * Copy a Gray pixel from the layer to an RGB image. Straight-forward.
2891 * The only thing this has to take account of is the opacity of the
2892 * layer. Evidently, the GIMP exporter itself does not actually do this.
2893 * \param layer source layer.
2894 * \param i x tile index.
2895 * \param j y tile index.
2896 * \param k x pixel index of tile i,j.
2897 * \param l y pixel index of tile i,j.
2898 * \param image destination image.
2899 * \param m x pixel of destination image.
2900 * \param n y pixel of destination image.
2901 */
2902void XCFImageFormat::copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2903{
2904 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2905 uchar src_a = layer.opacity;
2906 image.setPixel(m, n, qRgba(src, src_a));
2907}
2908
2909/*!
2910 * Copy a GrayA pixel from the layer to an RGB image. Straight-forward.
2911 * The only thing this has to take account of is the opacity of the
2912 * layer. Evidently, the GIMP exporter itself does not actually do this.
2913 * \param layer source layer.
2914 * \param i x tile index.
2915 * \param j y tile index.
2916 * \param k x pixel index of tile i,j.
2917 * \param l y pixel index of tile i,j.
2918 * \param image destination image.
2919 * \param m x pixel of destination image.
2920 * \param n y pixel of destination image.
2921 */
2922void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2923{
2924 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2925 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2926 src_a = INT_MULT(src_a, layer.opacity);
2927
2928 // Apply the mask (if any)
2929
2930 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2931 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2932 }
2933
2934 image.setPixel(m, n, qRgba(src, src_a));
2935}
2936
2937/*!
2938 * Copy an Indexed pixel from the layer to the Indexed image. Straight-forward.
2939 * \param layer source layer.
2940 * \param i x tile index.
2941 * \param j y tile index.
2942 * \param k x pixel index of tile i,j.
2943 * \param l y pixel index of tile i,j.
2944 * \param image destination image.
2945 * \param m x pixel of destination image.
2946 * \param n y pixel of destination image.
2947 */
2948void XCFImageFormat::copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2949{
2950 int src = layer.image_tiles[j][i].pixelIndex(k, l);
2951 image.setPixel(m, n, src);
2952}
2953
2954/*!
2955 * Copy an IndexedA pixel from the layer to the Indexed image. Straight-forward.
2956 * \param layer source layer.
2957 * \param i x tile index.
2958 * \param j y tile index.
2959 * \param k x pixel index of tile i,j.
2960 * \param l y pixel index of tile i,j.
2961 * \param image destination image.
2962 * \param m x pixel of destination image.
2963 * \param n y pixel of destination image.
2964 */
2965void XCFImageFormat::copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2966{
2967 uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
2968 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2969 src_a = INT_MULT(src_a, layer.opacity);
2970
2971 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2972 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2973 }
2974
2975 if (src_a > 127) {
2976 src++;
2977 } else {
2978 src = 0;
2979 }
2980
2981 image.setPixel(m, n, src);
2982}
2983
2984/*!
2985 * Copy an IndexedA pixel from the layer to an RGB image. Straight-forward.
2986 * The only thing this has to take account of is the opacity of the
2987 * layer. Evidently, the GIMP exporter itself does not actually do this.
2988 * \param layer source layer.
2989 * \param i x tile index.
2990 * \param j y tile index.
2991 * \param k x pixel index of tile i,j.
2992 * \param l y pixel index of tile i,j.
2993 * \param image destination image.
2994 * \param m x pixel of destination image.
2995 * \param n y pixel of destination image.
2996 */
2997void XCFImageFormat::copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2998{
2999 QRgb src = layer.image_tiles[j][i].pixel(k, l);
3000 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
3001 src_a = INT_MULT(src_a, layer.opacity);
3002
3003 // Apply the mask (if any)
3004 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3005 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3006 }
3007
3008 // This is what appears in the GIMP window
3009 if (src_a <= 127) {
3010 src_a = 0;
3011 } else {
3012 src_a = OPAQUE_OPACITY;
3013 }
3014
3015 image.setPixel(m, n, qRgba(src, src_a));
3016}
3017
3018/*!
3019 * Merge a layer into an image, taking account of the manifold modes.
3020 * \param xcf_image contains the layer and image to merge.
3021 */
3022void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
3023{
3024 Layer &layer(xcf_image.layer);
3025 QImage &image(xcf_image.image);
3026
3027 PixelMergeOperation merge = nullptr;
3028
3029 if (!layer.opacity) {
3030 return; // don't bother doing anything
3031 }
3032
3033 if (layer.blendSpace == XCFImageFormat::AutoColorSpace) {
3034 qCDebug(XCFPLUGIN) << "Auto blend space, defaulting to RgbLinearSpace (same as Gimp when writing this)";
3035 layer.blendSpace = XCFImageFormat::RgbLinearSpace;
3036 }
3037
3038 if (layer.blendSpace != XCFImageFormat::RgbLinearSpace) {
3039 qCDebug(XCFPLUGIN) << "Unimplemented blend color space" << layer.blendSpace;
3040 }
3041 qCDebug(XCFPLUGIN) << "Blend color space" << layer.blendSpace;
3042
3043 if (layer.compositeSpace == XCFImageFormat::AutoColorSpace) {
3044 qCDebug(XCFPLUGIN) << "Auto composite space, defaulting to RgbLinearSpace (same as Gimp when writing this)";
3045 layer.compositeSpace = XCFImageFormat::RgbLinearSpace;
3046 }
3047
3048 if (layer.compositeSpace != XCFImageFormat::RgbLinearSpace) {
3049 qCDebug(XCFPLUGIN) << "Unimplemented composite color space" << layer.compositeSpace;
3050 }
3051 if (layer.compositeMode != XCFImageFormat::CompositeUnion) {
3052 qCDebug(XCFPLUGIN) << "Unhandled composite mode" << layer.compositeMode;
3053 }
3054
3055 switch (layer.type) {
3056 case RGB_GIMAGE:
3057 case RGBA_GIMAGE:
3058 merge = mergeRGBToRGB;
3059 break;
3060 case GRAY_GIMAGE:
3061 if (layer.opacity == OPAQUE_OPACITY && xcf_image.image.depth() <= 8) {
3062 merge = mergeGrayToGray;
3063 } else {
3064 merge = mergeGrayToRGB;
3065 }
3066 break;
3067 case GRAYA_GIMAGE:
3068 if (xcf_image.image.depth() <= 8) {
3069 merge = mergeGrayAToGray;
3070 } else {
3071 merge = mergeGrayAToRGB;
3072 }
3073 break;
3074 case INDEXED_GIMAGE:
3075 merge = mergeIndexedToIndexed;
3076 break;
3077 case INDEXEDA_GIMAGE:
3078 if (xcf_image.image.depth() <= 8) {
3079 merge = mergeIndexedAToIndexed;
3080 } else {
3081 merge = mergeIndexedAToRGB;
3082 }
3083 }
3084
3085 if (!merge) {
3086 return;
3087 }
3088
3089 if (merge == mergeRGBToRGB && layer.apply_mask != 1) {
3090 int painterMode = -1;
3091 switch (layer.mode) {
3092 case GIMP_LAYER_MODE_NORMAL:
3093 case GIMP_LAYER_MODE_NORMAL_LEGACY:
3095 break;
3096 case GIMP_LAYER_MODE_MULTIPLY:
3097 case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
3099 break;
3100 case GIMP_LAYER_MODE_SCREEN:
3101 case GIMP_LAYER_MODE_SCREEN_LEGACY:
3103 break;
3104 case GIMP_LAYER_MODE_OVERLAY:
3105 case GIMP_LAYER_MODE_OVERLAY_LEGACY:
3107 break;
3108 case GIMP_LAYER_MODE_DIFFERENCE:
3109 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
3111 break;
3112 case GIMP_LAYER_MODE_DARKEN_ONLY:
3113 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
3115 break;
3116 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3117 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
3119 break;
3120 case GIMP_LAYER_MODE_DODGE:
3121 case GIMP_LAYER_MODE_DODGE_LEGACY:
3123 break;
3124 case GIMP_LAYER_MODE_BURN:
3125 case GIMP_LAYER_MODE_BURN_LEGACY:
3127 break;
3128 case GIMP_LAYER_MODE_HARDLIGHT:
3129 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY:
3131 break;
3132 case GIMP_LAYER_MODE_SOFTLIGHT:
3133 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY:
3135 break;
3136 case GIMP_LAYER_MODE_ADDITION:
3137 case GIMP_LAYER_MODE_ADDITION_LEGACY:
3138 painterMode = QPainter::CompositionMode_Plus;
3139 break;
3140 case GIMP_LAYER_MODE_EXCLUSION:
3142 break;
3143
3144 // Not bothered to find what the QPainter equivalent is, or there is none
3145 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3146 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY:
3147 case GIMP_LAYER_MODE_GRAIN_MERGE:
3148 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY:
3149 case GIMP_LAYER_MODE_COLOR_ERASE:
3150 case GIMP_LAYER_MODE_COLOR_ERASE_LEGACY:
3151 case GIMP_LAYER_MODE_LCH_HUE:
3152 case GIMP_LAYER_MODE_LCH_CHROMA:
3153 case GIMP_LAYER_MODE_LCH_COLOR:
3154 case GIMP_LAYER_MODE_LCH_LIGHTNESS:
3155 case GIMP_LAYER_MODE_BEHIND:
3156 case GIMP_LAYER_MODE_BEHIND_LEGACY:
3157 case GIMP_LAYER_MODE_SUBTRACT:
3158 case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
3159 case GIMP_LAYER_MODE_HSV_HUE:
3160 case GIMP_LAYER_MODE_HSV_SATURATION:
3161 case GIMP_LAYER_MODE_HSL_COLOR:
3162 case GIMP_LAYER_MODE_HSV_VALUE:
3163 case GIMP_LAYER_MODE_DIVIDE:
3164 case GIMP_LAYER_MODE_VIVID_LIGHT:
3165 case GIMP_LAYER_MODE_PIN_LIGHT:
3166 case GIMP_LAYER_MODE_LINEAR_LIGHT:
3167 case GIMP_LAYER_MODE_HARD_MIX:
3168 case GIMP_LAYER_MODE_LINEAR_BURN:
3169 case GIMP_LAYER_MODE_LUMA_DARKEN_ONLY:
3170 case GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY:
3171 case GIMP_LAYER_MODE_LUMINANCE:
3172 case GIMP_LAYER_MODE_ERASE:
3173 case GIMP_LAYER_MODE_MERGE:
3174 case GIMP_LAYER_MODE_SPLIT:
3175 case GIMP_LAYER_MODE_PASS_THROUGH:
3176 case GIMP_LAYER_MODE_HSV_HUE_LEGACY:
3177 case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY:
3178 case GIMP_LAYER_MODE_HSL_COLOR_LEGACY:
3179 case GIMP_LAYER_MODE_HSV_VALUE_LEGACY:
3180 case GIMP_LAYER_MODE_DIVIDE_LEGACY:
3181 qCDebug(XCFPLUGIN) << "No QPainter equivalent to" << layer.mode;
3182 break;
3183
3184 // Special
3185 case GIMP_LAYER_MODE_DISSOLVE:
3186 case GIMP_LAYER_MODE_COUNT:
3187 break;
3188 }
3189
3190 if (painterMode != -1) {
3191 QPainter painter(&image);
3192 painter.setOpacity(layer.opacity / 255.0);
3193 painter.setCompositionMode(QPainter::CompositionMode(painterMode));
3194 qCDebug(XCFPLUGIN) << "Using QPainter for mode" << layer.mode;
3195
3196 for (uint j = 0; j < layer.nrows; j++) {
3197 qint32 y = qint32(j * TILE_HEIGHT);
3198
3199 for (uint i = 0; i < layer.ncols; i++) {
3200 qint32 x = qint32(i * TILE_WIDTH);
3201
3202 QImage &tile = layer.image_tiles[j][i];
3203 if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
3204 y + layer.y_offset < MAX_IMAGE_HEIGHT) {
3205 painter.drawImage(x + layer.x_offset, y + layer.y_offset, tile);
3206 }
3207 }
3208 }
3209
3210 return;
3211 }
3212 }
3213
3214#ifndef DISABLE_IMAGE_PROFILE_CONV // The final profile should be the one in the Parasite
3215 if (layer.compositeSpace == XCFImageFormat::RgbPerceptualSpace && image.colorSpace() != QColorSpace::SRgb) {
3216 qCDebug(XCFPLUGIN) << "Converting to composite color space" << layer.compositeSpace;
3218 }
3219 if (layer.compositeSpace == XCFImageFormat::RgbLinearSpace && image.colorSpace() != QColorSpace::SRgbLinear) {
3220 qCDebug(XCFPLUGIN) << "Converting to composite color space" << layer.compositeSpace;
3222 }
3223#endif
3224
3225 for (uint j = 0; j < layer.nrows; j++) {
3226 qint32 y = qint32(j * TILE_HEIGHT);
3227
3228 for (uint i = 0; i < layer.ncols; i++) {
3229 qint32 x = qint32(i * TILE_WIDTH);
3230
3231 // This seems the best place to apply the dissolve because it
3232 // depends on the global position of each tile's
3233 // pixels. Apparently it's the only mode which can apply to a
3234 // single layer.
3235
3236 if (layer.mode == GIMP_LAYER_MODE_DISSOLVE) {
3237 if (!random_table_initialized) {
3238 initializeRandomTable();
3239 random_table_initialized = true;
3240 }
3241 if (layer.type == RGBA_GIMAGE) {
3242 dissolveRGBPixels(layer.image_tiles[j][i], x, y);
3243 }
3244
3245 else if (layer.type == GRAYA_GIMAGE) {
3246 dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
3247 }
3248 }
3249
3250 // Shortcut for common case
3251 if (merge == mergeRGBToRGB && layer.apply_mask != 1 && layer.mode == GIMP_LAYER_MODE_NORMAL_LEGACY) {
3252 QPainter painter(&image);
3253 painter.setOpacity(layer.opacity / 255.0);
3254 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
3255 if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
3256 y + layer.y_offset < MAX_IMAGE_HEIGHT) {
3257 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
3258 }
3259 continue;
3260 }
3261
3262#ifndef DISABLE_TILE_PROFILE_CONV // not sure about that: left as old plugin
3263 QImage &tile = layer.image_tiles[j][i];
3264 if (layer.compositeSpace == XCFImageFormat::RgbPerceptualSpace && tile.colorSpace() != QColorSpace::SRgb) {
3266 }
3267 if (layer.compositeSpace == XCFImageFormat::RgbLinearSpace && tile.colorSpace() != QColorSpace::SRgbLinear) {
3269 }
3270#endif
3271
3272 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
3273 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
3274 int m = x + k + layer.x_offset;
3275 int n = y + l + layer.y_offset;
3276
3277 if (m < 0 || m >= image.width() || n < 0 || n >= image.height()) {
3278 continue;
3279 }
3280
3281 if (!(*merge)(layer, i, j, k, l, image, m, n)) {
3282 return;
3283 }
3284 }
3285 }
3286 }
3287 }
3288}
3289
3290/*!
3291 * Merge an RGB pixel from the layer to the RGB image. Straight-forward.
3292 * The only thing this has to take account of is the opacity of the
3293 * layer. Evidently, the GIMP exporter itself does not actually do this.
3294 * \param layer source layer.
3295 * \param i x tile index.
3296 * \param j y tile index.
3297 * \param k x pixel index of tile i,j.
3298 * \param l y pixel index of tile i,j.
3299 * \param image destination image.
3300 * \param m x pixel of destination image.
3301 * \param n y pixel of destination image.
3302 */
3303bool XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3304{
3305 QRgb src = layer.image_tiles[j][i].pixel(k, l);
3306 QRgb dst = image.pixel(m, n);
3307
3308 uchar src_r = qRed(src);
3309 uchar src_g = qGreen(src);
3310 uchar src_b = qBlue(src);
3311 uchar src_a = qAlpha(src);
3312
3313 uchar dst_r = qRed(dst);
3314 uchar dst_g = qGreen(dst);
3315 uchar dst_b = qBlue(dst);
3316 uchar dst_a = qAlpha(dst);
3317
3318 if (!src_a) {
3319 return false; // nothing to merge
3320 }
3321
3322 switch (layer.mode) {
3323 case GIMP_LAYER_MODE_NORMAL:
3324 case GIMP_LAYER_MODE_NORMAL_LEGACY:
3325 break;
3326 case GIMP_LAYER_MODE_MULTIPLY:
3327 case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
3328 src_r = INT_MULT(src_r, dst_r);
3329 src_g = INT_MULT(src_g, dst_g);
3330 src_b = INT_MULT(src_b, dst_b);
3331 src_a = qMin(src_a, dst_a);
3332 break;
3333 case GIMP_LAYER_MODE_DIVIDE:
3334 case GIMP_LAYER_MODE_DIVIDE_LEGACY:
3335 src_r = qMin((dst_r * 256) / (1 + src_r), 255);
3336 src_g = qMin((dst_g * 256) / (1 + src_g), 255);
3337 src_b = qMin((dst_b * 256) / (1 + src_b), 255);
3338 src_a = qMin(src_a, dst_a);
3339 break;
3340 case GIMP_LAYER_MODE_SCREEN:
3341 case GIMP_LAYER_MODE_SCREEN_LEGACY:
3342 src_r = 255 - INT_MULT(255 - dst_r, 255 - src_r);
3343 src_g = 255 - INT_MULT(255 - dst_g, 255 - src_g);
3344 src_b = 255 - INT_MULT(255 - dst_b, 255 - src_b);
3345 src_a = qMin(src_a, dst_a);
3346 break;
3347 case GIMP_LAYER_MODE_OVERLAY:
3348 case GIMP_LAYER_MODE_OVERLAY_LEGACY:
3349 src_r = INT_MULT(dst_r, dst_r + INT_MULT(2 * src_r, 255 - dst_r));
3350 src_g = INT_MULT(dst_g, dst_g + INT_MULT(2 * src_g, 255 - dst_g));
3351 src_b = INT_MULT(dst_b, dst_b + INT_MULT(2 * src_b, 255 - dst_b));
3352 src_a = qMin(src_a, dst_a);
3353 break;
3354 case GIMP_LAYER_MODE_DIFFERENCE:
3355 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
3356 src_r = dst_r > src_r ? dst_r - src_r : src_r - dst_r;
3357 src_g = dst_g > src_g ? dst_g - src_g : src_g - dst_g;
3358 src_b = dst_b > src_b ? dst_b - src_b : src_b - dst_b;
3359 src_a = qMin(src_a, dst_a);
3360 break;
3361 case GIMP_LAYER_MODE_ADDITION:
3362 case GIMP_LAYER_MODE_ADDITION_LEGACY:
3363 src_r = add_lut(dst_r, src_r);
3364 src_g = add_lut(dst_g, src_g);
3365 src_b = add_lut(dst_b, src_b);
3366 src_a = qMin(src_a, dst_a);
3367 break;
3368 case GIMP_LAYER_MODE_SUBTRACT:
3369 case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
3370 src_r = dst_r > src_r ? dst_r - src_r : 0;
3371 src_g = dst_g > src_g ? dst_g - src_g : 0;
3372 src_b = dst_b > src_b ? dst_b - src_b : 0;
3373 src_a = qMin(src_a, dst_a);
3374 break;
3375 case GIMP_LAYER_MODE_DARKEN_ONLY:
3376 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
3377 src_r = dst_r < src_r ? dst_r : src_r;
3378 src_g = dst_g < src_g ? dst_g : src_g;
3379 src_b = dst_b < src_b ? dst_b : src_b;
3380 src_a = qMin(src_a, dst_a);
3381 break;
3382 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3383 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
3384 src_r = dst_r < src_r ? src_r : dst_r;
3385 src_g = dst_g < src_g ? src_g : dst_g;
3386 src_b = dst_b < src_b ? src_b : dst_b;
3387 src_a = qMin(src_a, dst_a);
3388 break;
3389 case GIMP_LAYER_MODE_HSV_HUE:
3390 case GIMP_LAYER_MODE_HSV_HUE_LEGACY: {
3391 uchar new_r = dst_r;
3392 uchar new_g = dst_g;
3393 uchar new_b = dst_b;
3394
3395 RGBTOHSV(src_r, src_g, src_b);
3396 RGBTOHSV(new_r, new_g, new_b);
3397
3398 new_r = src_r;
3399
3400 HSVTORGB(new_r, new_g, new_b);
3401
3402 src_r = new_r;
3403 src_g = new_g;
3404 src_b = new_b;
3405 src_a = qMin(src_a, dst_a);
3406 } break;
3407 case GIMP_LAYER_MODE_HSV_SATURATION:
3408 case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY: {
3409 uchar new_r = dst_r;
3410 uchar new_g = dst_g;
3411 uchar new_b = dst_b;
3412
3413 RGBTOHSV(src_r, src_g, src_b);
3414 RGBTOHSV(new_r, new_g, new_b);
3415
3416 new_g = src_g;
3417
3418 HSVTORGB(new_r, new_g, new_b);
3419
3420 src_r = new_r;
3421 src_g = new_g;
3422 src_b = new_b;
3423 src_a = qMin(src_a, dst_a);
3424 } break;
3425 case GIMP_LAYER_MODE_HSV_VALUE:
3426 case GIMP_LAYER_MODE_HSV_VALUE_LEGACY: {
3427 uchar new_r = dst_r;
3428 uchar new_g = dst_g;
3429 uchar new_b = dst_b;
3430
3431 RGBTOHSV(src_r, src_g, src_b);
3432 RGBTOHSV(new_r, new_g, new_b);
3433
3434 new_b = src_b;
3435
3436 HSVTORGB(new_r, new_g, new_b);
3437
3438 src_r = new_r;
3439 src_g = new_g;
3440 src_b = new_b;
3441 src_a = qMin(src_a, dst_a);
3442 } break;
3443 case GIMP_LAYER_MODE_HSL_COLOR:
3444 case GIMP_LAYER_MODE_HSL_COLOR_LEGACY: {
3445 uchar new_r = dst_r;
3446 uchar new_g = dst_g;
3447 uchar new_b = dst_b;
3448
3449 RGBTOHLS(src_r, src_g, src_b);
3450 RGBTOHLS(new_r, new_g, new_b);
3451
3452 new_r = src_r;
3453 new_b = src_b;
3454
3455 HLSTORGB(new_r, new_g, new_b);
3456
3457 src_r = new_r;
3458 src_g = new_g;
3459 src_b = new_b;
3460 src_a = qMin(src_a, dst_a);
3461 } break;
3462 case GIMP_LAYER_MODE_DODGE:
3463 case GIMP_LAYER_MODE_DODGE_LEGACY: {
3464 uint tmp;
3465
3466 tmp = dst_r << 8;
3467 tmp /= 256 - src_r;
3468 src_r = (uchar)qMin(tmp, 255u);
3469
3470 tmp = dst_g << 8;
3471 tmp /= 256 - src_g;
3472 src_g = (uchar)qMin(tmp, 255u);
3473
3474 tmp = dst_b << 8;
3475 tmp /= 256 - src_b;
3476 src_b = (uchar)qMin(tmp, 255u);
3477
3478 src_a = qMin(src_a, dst_a);
3479 } break;
3480 case GIMP_LAYER_MODE_BURN:
3481 case GIMP_LAYER_MODE_BURN_LEGACY: {
3482 uint tmp;
3483
3484 tmp = (255 - dst_r) << 8;
3485 tmp /= src_r + 1;
3486 src_r = (uchar)qMin(tmp, 255u);
3487 src_r = 255 - src_r;
3488
3489 tmp = (255 - dst_g) << 8;
3490 tmp /= src_g + 1;
3491 src_g = (uchar)qMin(tmp, 255u);
3492 src_g = 255 - src_g;
3493
3494 tmp = (255 - dst_b) << 8;
3495 tmp /= src_b + 1;
3496 src_b = (uchar)qMin(tmp, 255u);
3497 src_b = 255 - src_b;
3498
3499 src_a = qMin(src_a, dst_a);
3500 } break;
3501 case GIMP_LAYER_MODE_HARDLIGHT:
3502 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
3503 uint tmp;
3504 if (src_r > 128) {
3505 tmp = ((int)255 - dst_r) * ((int)255 - ((src_r - 128) << 1));
3506 src_r = (uchar)qMin(255 - (tmp >> 8), 255u);
3507 } else {
3508 tmp = (int)dst_r * ((int)src_r << 1);
3509 src_r = (uchar)qMin(tmp >> 8, 255u);
3510 }
3511
3512 if (src_g > 128) {
3513 tmp = ((int)255 - dst_g) * ((int)255 - ((src_g - 128) << 1));
3514 src_g = (uchar)qMin(255 - (tmp >> 8), 255u);
3515 } else {
3516 tmp = (int)dst_g * ((int)src_g << 1);
3517 src_g = (uchar)qMin(tmp >> 8, 255u);
3518 }
3519
3520 if (src_b > 128) {
3521 tmp = ((int)255 - dst_b) * ((int)255 - ((src_b - 128) << 1));
3522 src_b = (uchar)qMin(255 - (tmp >> 8), 255u);
3523 } else {
3524 tmp = (int)dst_b * ((int)src_b << 1);
3525 src_b = (uchar)qMin(tmp >> 8, 255u);
3526 }
3527 src_a = qMin(src_a, dst_a);
3528 } break;
3529 case GIMP_LAYER_MODE_SOFTLIGHT:
3530 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
3531 uint tmpS;
3532 uint tmpM;
3533
3534 tmpM = INT_MULT(dst_r, src_r);
3535 tmpS = 255 - INT_MULT((255 - dst_r), (255 - src_r));
3536 src_r = INT_MULT((255 - dst_r), tmpM) + INT_MULT(dst_r, tmpS);
3537
3538 tmpM = INT_MULT(dst_g, src_g);
3539 tmpS = 255 - INT_MULT((255 - dst_g), (255 - src_g));
3540 src_g = INT_MULT((255 - dst_g), tmpM) + INT_MULT(dst_g, tmpS);
3541
3542 tmpM = INT_MULT(dst_b, src_b);
3543 tmpS = 255 - INT_MULT((255 - dst_b), (255 - src_b));
3544 src_b = INT_MULT((255 - dst_b), tmpM) + INT_MULT(dst_b, tmpS);
3545
3546 src_a = qMin(src_a, dst_a);
3547 } break;
3548 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3549 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
3550 int tmp;
3551
3552 tmp = dst_r - src_r + 128;
3553 tmp = qMin(tmp, 255);
3554 tmp = qMax(tmp, 0);
3555 src_r = (uchar)tmp;
3556
3557 tmp = dst_g - src_g + 128;
3558 tmp = qMin(tmp, 255);
3559 tmp = qMax(tmp, 0);
3560 src_g = (uchar)tmp;
3561
3562 tmp = dst_b - src_b + 128;
3563 tmp = qMin(tmp, 255);
3564 tmp = qMax(tmp, 0);
3565 src_b = (uchar)tmp;
3566
3567 src_a = qMin(src_a, dst_a);
3568 } break;
3569 case GIMP_LAYER_MODE_GRAIN_MERGE:
3570 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
3571 int tmp;
3572
3573 tmp = dst_r + src_r - 128;
3574 tmp = qMin(tmp, 255);
3575 tmp = qMax(tmp, 0);
3576 src_r = (uchar)tmp;
3577
3578 tmp = dst_g + src_g - 128;
3579 tmp = qMin(tmp, 255);
3580 tmp = qMax(tmp, 0);
3581 src_g = (uchar)tmp;
3582
3583 tmp = dst_b + src_b - 128;
3584 tmp = qMin(tmp, 255);
3585 tmp = qMax(tmp, 0);
3586 src_b = (uchar)tmp;
3587
3588 src_a = qMin(src_a, dst_a);
3589 } break;
3590 case GIMP_LAYER_MODE_LINEAR_LIGHT: {
3591 if (src_r <= 128) {
3592 src_r = qBound(0, dst_r + 2 * src_r - 255, 255);
3593 } else {
3594 src_r = qBound(0, dst_r + 2 * (src_r - 128), 255);
3595 }
3596 if (src_g <= 128) {
3597 src_g = qBound(0, dst_g + 2 * src_g - 255, 255);
3598 } else {
3599 src_g = qBound(0, dst_g + 2 * (src_g - 127), 255);
3600 }
3601 if (src_b <= 128) {
3602 src_b = qBound(0, dst_b + 2 * src_b - 255, 255);
3603 } else {
3604 src_b = qBound(0, dst_b + 2 * (src_b - 127), 255);
3605 }
3606 } break;
3607 case GIMP_LAYER_MODE_VIVID_LIGHT: {
3608 // From http://www.simplefilter.de/en/basics/mixmods.html
3609 float A[3];
3610 A[0] = src_r / 255.;
3611 A[1] = src_g / 255.;
3612 A[2] = src_b / 255.;
3613 float B[3];
3614 B[0] = dst_r / 255.;
3615 B[1] = dst_g / 255.;
3616 B[2] = dst_b / 255.;
3617 float C[3]{};
3618 for (int i = 0; i < 3; i++) {
3619 if (A[i] <= 0.5f) {
3620 if (A[i] > 0.f) {
3621 C[i] = 1.f - (1.f - B[i]) / (2.f * A[i]);
3622 }
3623 } else {
3624 if (A[i] < 1.f) {
3625 C[i] = B[i] / (2.f * (1.f - A[i]));
3626 }
3627 }
3628 }
3629 src_r = qBound(0.f, C[0] * 255.f, 255.f);
3630 src_g = qBound(0.f, C[1] * 255.f, 255.f);
3631 src_b = qBound(0.f, C[2] * 255.f, 255.f);
3632 } break;
3633 default:
3634 qCWarning(XCFPLUGIN) << "Unhandled mode" << layer.mode;
3635 return false;
3636 }
3637
3638 src_a = INT_MULT(src_a, layer.opacity);
3639
3640 // Apply the mask (if any)
3641
3642 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3643 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3644 }
3645
3646 uchar new_r;
3647 uchar new_g;
3648 uchar new_b;
3649 uchar new_a;
3650 new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
3651
3652 const float src_ratio = new_a == 0 ? 1.0 : (float)src_a / new_a;
3653 float dst_ratio = 1.0 - src_ratio;
3654
3655 new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
3656 new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
3657 new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
3658
3659 if (!modeAffectsSourceAlpha(layer.mode)) {
3660 new_a = dst_a;
3661 }
3662
3663 image.setPixel(m, n, qRgba(new_r, new_g, new_b, new_a));
3664 return true;
3665}
3666
3667/*!
3668 * Merge a Gray pixel from the layer to the Gray image. Straight-forward.
3669 * \param layer source layer.
3670 * \param i x tile index.
3671 * \param j y tile index.
3672 * \param k x pixel index of tile i,j.
3673 * \param l y pixel index of tile i,j.
3674 * \param image destination image.
3675 * \param m x pixel of destination image.
3676 * \param n y pixel of destination image.
3677 */
3678bool XCFImageFormat::mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3679{
3680 int src = layer.image_tiles[j][i].pixelIndex(k, l);
3681 image.setPixel(m, n, src);
3682 return true;
3683}
3684
3685/*!
3686 * Merge a GrayA pixel from the layer to the Gray image. Straight-forward.
3687 * \param layer source layer.
3688 * \param i x tile index.
3689 * \param j y tile index.
3690 * \param k x pixel index of tile i,j.
3691 * \param l y pixel index of tile i,j.
3692 * \param image destination image.
3693 * \param m x pixel of destination image.
3694 * \param n y pixel of destination image.
3695 */
3696bool XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3697{
3698 int src = qGray(layer.image_tiles[j][i].pixel(k, l));
3699 int dst = image.pixelIndex(m, n);
3700
3701 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
3702
3703 if (!src_a) {
3704 return false; // nothing to merge
3705 }
3706
3707 switch (layer.mode) {
3708 case GIMP_LAYER_MODE_MULTIPLY:
3709 case GIMP_LAYER_MODE_MULTIPLY_LEGACY: {
3710 src = INT_MULT(src, dst);
3711 } break;
3712 case GIMP_LAYER_MODE_DIVIDE:
3713 case GIMP_LAYER_MODE_DIVIDE_LEGACY: {
3714 src = qMin((dst * 256) / (1 + src), 255);
3715 } break;
3716 case GIMP_LAYER_MODE_SCREEN:
3717 case GIMP_LAYER_MODE_SCREEN_LEGACY: {
3718 src = 255 - INT_MULT(255 - dst, 255 - src);
3719 } break;
3720 case GIMP_LAYER_MODE_OVERLAY:
3721 case GIMP_LAYER_MODE_OVERLAY_LEGACY: {
3722 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
3723 } break;
3724 case GIMP_LAYER_MODE_DIFFERENCE:
3725 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY: {
3726 src = dst > src ? dst - src : src - dst;
3727 } break;
3728 case GIMP_LAYER_MODE_ADDITION:
3729 case GIMP_LAYER_MODE_ADDITION_LEGACY: {
3730 src = add_lut(dst, src);
3731 } break;
3732 case GIMP_LAYER_MODE_SUBTRACT:
3733 case GIMP_LAYER_MODE_SUBTRACT_LEGACY: {
3734 src = dst > src ? dst - src : 0;
3735 } break;
3736 case GIMP_LAYER_MODE_DARKEN_ONLY:
3737 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY: {
3738 src = dst < src ? dst : src;
3739 } break;
3740 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3741 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY: {
3742 src = dst < src ? src : dst;
3743 } break;
3744 case GIMP_LAYER_MODE_DODGE:
3745 case GIMP_LAYER_MODE_DODGE_LEGACY: {
3746 uint tmp = dst << 8;
3747 tmp /= 256 - src;
3748 src = (uchar)qMin(tmp, 255u);
3749 } break;
3750 case GIMP_LAYER_MODE_BURN:
3751 case GIMP_LAYER_MODE_BURN_LEGACY: {
3752 uint tmp = (255 - dst) << 8;
3753 tmp /= src + 1;
3754 src = (uchar)qMin(tmp, 255u);
3755 src = 255 - src;
3756 } break;
3757 case GIMP_LAYER_MODE_HARDLIGHT:
3758 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
3759 uint tmp;
3760 if (src > 128) {
3761 tmp = ((int)255 - dst) * ((int)255 - ((src - 128) << 1));
3762 src = (uchar)qMin(255 - (tmp >> 8), 255u);
3763 } else {
3764 tmp = (int)dst * ((int)src << 1);
3765 src = (uchar)qMin(tmp >> 8, 255u);
3766 }
3767 } break;
3768 case GIMP_LAYER_MODE_SOFTLIGHT:
3769 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
3770 uint tmpS;
3771 uint tmpM;
3772
3773 tmpM = INT_MULT(dst, src);
3774 tmpS = 255 - INT_MULT((255 - dst), (255 - src));
3775 src = INT_MULT((255 - dst), tmpM) + INT_MULT(dst, tmpS);
3776
3777 } break;
3778 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3779 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
3780 int tmp;
3781
3782 tmp = dst - src + 128;
3783 tmp = qMin(tmp, 255);
3784 tmp = qMax(tmp, 0);
3785
3786 src = (uchar)tmp;
3787 } break;
3788 case GIMP_LAYER_MODE_GRAIN_MERGE:
3789 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
3790 int tmp;
3791
3792 tmp = dst + src - 128;
3793 tmp = qMin(tmp, 255);
3794 tmp = qMax(tmp, 0);
3795
3796 src = (uchar)tmp;
3797 } break;
3798 default:
3799 qCWarning(XCFPLUGIN) << "Unhandled mode" << layer.mode;
3800 return false;
3801 }
3802
3803 src_a = INT_MULT(src_a, layer.opacity);
3804
3805 // Apply the mask (if any)
3806
3807 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3808 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3809 }
3810
3811 uchar new_a = OPAQUE_OPACITY;
3812
3813 const float src_ratio = new_a == 0 ? 1.0 : (float)src_a / new_a;
3814 float dst_ratio = 1.0 - src_ratio;
3815
3816 uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
3817
3818 image.setPixel(m, n, new_g);
3819 return true;
3820}
3821
3822/*!
3823 * Merge a Gray pixel from the layer to an RGB image. Straight-forward.
3824 * The only thing this has to take account of is the opacity of the
3825 * layer. Evidently, the GIMP exporter itself does not actually do this.
3826 * \param layer source layer.
3827 * \param i x tile index.
3828 * \param j y tile index.
3829 * \param k x pixel index of tile i,j.
3830 * \param l y pixel index of tile i,j.
3831 * \param image destination image.
3832 * \param m x pixel of destination image.
3833 * \param n y pixel of destination image.
3834 */
3835bool XCFImageFormat::mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3836{
3837 QRgb src = layer.image_tiles[j][i].pixel(k, l);
3838 uchar src_a = layer.opacity;
3839 image.setPixel(m, n, qRgba(src, src_a));
3840 return true;
3841}
3842
3843/*!
3844 * Merge a GrayA pixel from the layer to an RGB image. Straight-forward.
3845 * The only thing this has to take account of is the opacity of the
3846 * layer. Evidently, the GIMP exporter itself does not actually do this.
3847 * \param layer source layer.
3848 * \param i x tile index.
3849 * \param j y tile index.
3850 * \param k x pixel index of tile i,j.
3851 * \param l y pixel index of tile i,j.
3852 * \param image destination image.
3853 * \param m x pixel of destination image.
3854 * \param n y pixel of destination image.
3855 */
3856bool XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3857{
3858 int src = qGray(layer.image_tiles[j][i].pixel(k, l));
3859 int dst = qGray(image.pixel(m, n));
3860
3861 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
3862 uchar dst_a = qAlpha(image.pixel(m, n));
3863
3864 if (!src_a) {
3865 return false; // nothing to merge
3866 }
3867
3868 switch (layer.mode) {
3869 case GIMP_LAYER_MODE_NORMAL:
3870 case GIMP_LAYER_MODE_NORMAL_LEGACY:
3871 break;
3872 case GIMP_LAYER_MODE_MULTIPLY:
3873 case GIMP_LAYER_MODE_MULTIPLY_LEGACY: {
3874 src = INT_MULT(src, dst);
3875 src_a = qMin(src_a, dst_a);
3876 } break;
3877 case GIMP_LAYER_MODE_DIVIDE:
3878 case GIMP_LAYER_MODE_DIVIDE_LEGACY: {
3879 src = qMin((dst * 256) / (1 + src), 255);
3880 src_a = qMin(src_a, dst_a);
3881 } break;
3882 case GIMP_LAYER_MODE_SCREEN:
3883 case GIMP_LAYER_MODE_SCREEN_LEGACY: {
3884 src = 255 - INT_MULT(255 - dst, 255 - src);
3885 src_a = qMin(src_a, dst_a);
3886 } break;
3887 case GIMP_LAYER_MODE_OVERLAY:
3888 case GIMP_LAYER_MODE_OVERLAY_LEGACY: {
3889 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
3890 src_a = qMin(src_a, dst_a);
3891 } break;
3892 case GIMP_LAYER_MODE_DIFFERENCE:
3893 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY: {
3894 src = dst > src ? dst - src : src - dst;
3895 src_a = qMin(src_a, dst_a);
3896 } break;
3897 case GIMP_LAYER_MODE_ADDITION:
3898 case GIMP_LAYER_MODE_ADDITION_LEGACY: {
3899 src = add_lut(dst, src);
3900 src_a = qMin(src_a, dst_a);
3901 } break;
3902 case GIMP_LAYER_MODE_SUBTRACT:
3903 case GIMP_LAYER_MODE_SUBTRACT_LEGACY: {
3904 src = dst > src ? dst - src : 0;
3905 src_a = qMin(src_a, dst_a);
3906 } break;
3907 case GIMP_LAYER_MODE_DARKEN_ONLY:
3908 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY: {
3909 src = dst < src ? dst : src;
3910 src_a = qMin(src_a, dst_a);
3911 } break;
3912 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3913 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY: {
3914 src = dst < src ? src : dst;
3915 src_a = qMin(src_a, dst_a);
3916 } break;
3917 case GIMP_LAYER_MODE_DODGE:
3918 case GIMP_LAYER_MODE_DODGE_LEGACY: {
3919 uint tmp = dst << 8;
3920 tmp /= 256 - src;
3921 src = (uchar)qMin(tmp, 255u);
3922 src_a = qMin(src_a, dst_a);
3923 } break;
3924 case GIMP_LAYER_MODE_BURN:
3925 case GIMP_LAYER_MODE_BURN_LEGACY: {
3926 uint tmp = (255 - dst) << 8;
3927 tmp /= src + 1;
3928 src = (uchar)qMin(tmp, 255u);
3929 src = 255 - src;
3930 src_a = qMin(src_a, dst_a);
3931 } break;
3932 case GIMP_LAYER_MODE_HARDLIGHT:
3933 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
3934 uint tmp;
3935 if (src > 128) {
3936 tmp = ((int)255 - dst) * ((int)255 - ((src - 128) << 1));
3937 src = (uchar)qMin(255 - (tmp >> 8), 255u);
3938 } else {
3939 tmp = (int)dst * ((int)src << 1);
3940 src = (uchar)qMin(tmp >> 8, 255u);
3941 }
3942 src_a = qMin(src_a, dst_a);
3943 } break;
3944 case GIMP_LAYER_MODE_SOFTLIGHT:
3945 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
3946 uint tmpS;
3947 uint tmpM;
3948
3949 tmpM = INT_MULT(dst, src);
3950 tmpS = 255 - INT_MULT((255 - dst), (255 - src));
3951 src = INT_MULT((255 - dst), tmpM) + INT_MULT(dst, tmpS);
3952
3953 src_a = qMin(src_a, dst_a);
3954 } break;
3955 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3956 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
3957 int tmp;
3958
3959 tmp = dst - src + 128;
3960 tmp = qMin(tmp, 255);
3961 tmp = qMax(tmp, 0);
3962
3963 src = (uchar)tmp;
3964 src_a = qMin(src_a, dst_a);
3965 } break;
3966 case GIMP_LAYER_MODE_GRAIN_MERGE:
3967 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
3968 int tmp;
3969
3970 tmp = dst + src - 128;
3971 tmp = qMin(tmp, 255);
3972 tmp = qMax(tmp, 0);
3973
3974 src = (uchar)tmp;
3975 src_a = qMin(src_a, dst_a);
3976 } break;
3977 default:
3978 qCWarning(XCFPLUGIN) << "Unhandled mode" << layer.mode;
3979 return false;
3980 }
3981
3982 src_a = INT_MULT(src_a, layer.opacity);
3983
3984 // Apply the mask (if any)
3985 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3986 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3987 }
3988
3989 uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
3990
3991 const float src_ratio = new_a == 0 ? 1.0 : (float)src_a / new_a;
3992 float dst_ratio = 1.0 - src_ratio;
3993
3994 uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
3995
3996 if (!modeAffectsSourceAlpha(layer.mode)) {
3997 new_a = dst_a;
3998 }
3999
4000 image.setPixel(m, n, qRgba(new_g, new_g, new_g, new_a));
4001 return true;
4002}
4003
4004/*!
4005 * Merge an Indexed pixel from the layer to the Indexed image. Straight-forward.
4006 * \param layer source layer.
4007 * \param i x tile index.
4008 * \param j y tile index.
4009 * \param k x pixel index of tile i,j.
4010 * \param l y pixel index of tile i,j.
4011 * \param image destination image.
4012 * \param m x pixel of destination image.
4013 * \param n y pixel of destination image.
4014 */
4015bool XCFImageFormat::mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
4016{
4017 int src = layer.image_tiles[j][i].pixelIndex(k, l);
4018 image.setPixel(m, n, src);
4019 return true;
4020}
4021
4022/*!
4023 * Merge an IndexedA pixel from the layer to the Indexed image. Straight-forward.
4024 * \param layer source layer.
4025 * \param i x tile index.
4026 * \param j y tile index.
4027 * \param k x pixel index of tile i,j.
4028 * \param l y pixel index of tile i,j.
4029 * \param image destination image.
4030 * \param m x pixel of destination image.
4031 * \param n y pixel of destination image.
4032 */
4033bool XCFImageFormat::mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
4034{
4035 uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
4036 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
4037 src_a = INT_MULT(src_a, layer.opacity);
4038
4039 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
4040 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
4041 }
4042
4043 if (src_a > 127) {
4044 src++;
4045 image.setPixel(m, n, src);
4046 }
4047 return true;
4048}
4049
4050/*!
4051 * Merge an IndexedA pixel from the layer to an RGB image. Straight-forward.
4052 * The only thing this has to take account of is the opacity of the
4053 * layer. Evidently, the GIMP exporter itself does not actually do this.
4054 * \param layer source layer.
4055 * \param i x tile index.
4056 * \param j y tile index.
4057 * \param k x pixel index of tile i,j.
4058 * \param l y pixel index of tile i,j.
4059 * \param image destination image.
4060 * \param m x pixel of destination image.
4061 * \param n y pixel of destination image.
4062 */
4063bool XCFImageFormat::mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
4064{
4065 QRgb src = layer.image_tiles[j][i].pixel(k, l);
4066 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
4067 src_a = INT_MULT(src_a, layer.opacity);
4068
4069 // Apply the mask (if any)
4070 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
4071 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
4072 }
4073
4074 // This is what appears in the GIMP window
4075 if (src_a <= 127) {
4076 src_a = 0;
4077 } else {
4078 src_a = OPAQUE_OPACITY;
4079 }
4080
4081 image.setPixel(m, n, qRgba(src, src_a));
4082 return true;
4083}
4084
4085/*!
4086 * Dissolving pixels: pick a random number between 0 and 255. If the pixel's
4087 * alpha is less than that, make it transparent.
4088 * \param image the image tile to dissolve.
4089 * \param x the global x position of the tile.
4090 * \param y the global y position of the tile.
4091 */
4092void XCFImageFormat::dissolveRGBPixels(QImage &image, int x, int y)
4093{
4094 // The apparently spurious rand() calls are to wind the random
4095 // numbers up to the same point for each tile.
4096
4097 for (int l = 0; l < image.height(); l++) {
4098 unsigned int next = randomTable.values[(l + y) % RANDOM_TABLE_SIZE];
4099
4100 for (int k = 0; k < x; k++) {
4101 RandomTable::rand_r(&next);
4102 }
4103
4104 for (int k = 0; k < image.width(); k++) {
4105 int rand_val = RandomTable::rand_r(&next) & 0xff;
4106 QRgb pixel = image.pixel(k, l);
4107
4108 if (rand_val > qAlpha(pixel)) {
4109 image.setPixel(k, l, qRgba(pixel, 0));
4110 }
4111 }
4112 }
4113}
4114
4115/*!
4116 * Dissolving pixels: pick a random number between 0 and 255. If the pixel's
4117 * alpha is less than that, make it transparent. This routine works for
4118 * the GRAYA and INDEXEDA image types where the pixel alpha's are stored
4119 * separately from the pixel themselves.
4120 * \param image the alpha tile to dissolve.
4121 * \param x the global x position of the tile.
4122 * \param y the global y position of the tile.
4123 */
4124void XCFImageFormat::dissolveAlphaPixels(QImage &image, int x, int y)
4125{
4126 // The apparently spurious rand() calls are to wind the random
4127 // numbers up to the same point for each tile.
4128
4129 for (int l = 0; l < image.height(); l++) {
4130 unsigned int next = randomTable.values[(l + y) % RANDOM_TABLE_SIZE];
4131
4132 for (int k = 0; k < x; k++) {
4133 RandomTable::rand_r(&next);
4134 }
4135
4136 for (int k = 0; k < image.width(); k++) {
4137 int rand_val = RandomTable::rand_r(&next) & 0xff;
4138 uchar alpha = image.pixelIndex(k, l);
4139
4140 if (rand_val > alpha) {
4141 image.setPixel(k, l, 0);
4142 }
4143 }
4144 }
4145}
4146
4147///////////////////////////////////////////////////////////////////////////////
4148
4149XCFHandler::XCFHandler()
4150{
4151}
4152
4153bool XCFHandler::canRead() const
4154{
4155 if (canRead(device())) {
4156 setFormat("xcf");
4157 return true;
4158 }
4159 return false;
4160}
4161
4162bool XCFHandler::read(QImage *image)
4163{
4164 XCFImageFormat xcfif;
4165 auto ok = xcfif.readXCF(device(), image);
4166 m_imageSize = image->size();
4167 return ok;
4168}
4169
4170bool XCFHandler::write(const QImage &)
4171{
4172 return false;
4173}
4174
4175bool XCFHandler::supportsOption(ImageOption option) const
4176{
4177 if (option == QImageIOHandler::Size)
4178 return true;
4179 return false;
4180}
4181
4182QVariant XCFHandler::option(ImageOption option) const
4183{
4184 QVariant v;
4185
4186 if (option == QImageIOHandler::Size) {
4187 if (!m_imageSize.isEmpty()) {
4188 return m_imageSize;
4189 }
4190 /*
4191 * The image structure always starts at offset 0 in the XCF file.
4192 * byte[9] "gimp xcf " File type identification
4193 * byte[4] version XCF version
4194 * "file": version 0
4195 * "v001": version 1
4196 * "v002": version 2
4197 * "v003": version 3
4198 * byte 0 Zero marks the end of the version tag.
4199 * uint32 width Width of canvas
4200 * uint32 height Height of canvas
4201 */
4202 else if (auto d = device()) {
4203 // transactions works on both random and sequential devices
4204 d->startTransaction();
4205 auto ba9 = d->read(9); // "gimp xcf "
4206 auto ba5 = d->read(4+1); // version + null terminator
4207 auto ba = d->read(8); // width and height
4208 d->rollbackTransaction();
4209 if (ba9 == QByteArray("gimp xcf ") && ba5.size() == 5) {
4210 QDataStream ds(ba);
4211 quint32 width;
4212 ds >> width;
4213 quint32 height;
4214 ds >> height;
4215 if (ds.status() == QDataStream::Ok)
4216 v = QVariant::fromValue(QSize(width, height));
4217 }
4218 }
4219 }
4220
4221 return v;
4222}
4223
4224bool XCFHandler::canRead(QIODevice *device)
4225{
4226 if (!device) {
4227 qCDebug(XCFPLUGIN) << "XCFHandler::canRead() called with no device";
4228 return false;
4229 }
4230 if (device->isSequential()) {
4231 return false;
4232 }
4233
4234 const qint64 oldPos = device->pos();
4235
4236 QDataStream ds(device);
4237 XCFImageFormat::XCFImage::Header header;
4238 bool failed = !XCFImageFormat::readXCFHeader(ds, &header);
4239 ds.setDevice(nullptr);
4240
4241 device->seek(oldPos);
4242 if (failed) {
4243 return false;
4244 }
4245
4246 switch (header.precision) {
4247 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
4248 case XCFImageFormat::GIMP_PRECISION_HALF_NON_LINEAR:
4249 case XCFImageFormat::GIMP_PRECISION_HALF_PERCEPTUAL:
4250 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
4251 case XCFImageFormat::GIMP_PRECISION_FLOAT_NON_LINEAR:
4252 case XCFImageFormat::GIMP_PRECISION_FLOAT_PERCEPTUAL:
4253 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
4254 case XCFImageFormat::GIMP_PRECISION_U8_NON_LINEAR:
4255 case XCFImageFormat::GIMP_PRECISION_U8_PERCEPTUAL:
4256 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
4257 case XCFImageFormat::GIMP_PRECISION_U16_NON_LINEAR:
4258 case XCFImageFormat::GIMP_PRECISION_U16_PERCEPTUAL:
4259 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
4260 case XCFImageFormat::GIMP_PRECISION_U32_NON_LINEAR:
4261 case XCFImageFormat::GIMP_PRECISION_U32_PERCEPTUAL:
4262 break;
4263 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
4264 case XCFImageFormat::GIMP_PRECISION_DOUBLE_NON_LINEAR:
4265 case XCFImageFormat::GIMP_PRECISION_DOUBLE_PERCEPTUAL:
4266 default:
4267 qCDebug(XCFPLUGIN) << "unsupported precision" << header.precision;
4268 return false;
4269 }
4270
4271 return true;
4272}
4273
4274QImageIOPlugin::Capabilities XCFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
4275{
4276 if (format == "xcf") {
4277 return Capabilities(CanRead);
4278 }
4279 if (!format.isEmpty()) {
4280 return {};
4281 }
4282 if (!device->isOpen()) {
4283 return {};
4284 }
4285
4286 Capabilities cap;
4287 if (device->isReadable() && XCFHandler::canRead(device)) {
4288 cap |= CanRead;
4289 }
4290 return cap;
4291}
4292
4293QImageIOHandler *XCFPlugin::create(QIODevice *device, const QByteArray &format) const
4294{
4295 QImageIOHandler *handler = new XCFHandler;
4296 handler->setDevice(device);
4297 handler->setFormat(format);
4298 return handler;
4299}
4300
4301// Just so I can get enum values printed
4302#include "xcf.moc"
4303
4304#include "moc_xcf_p.cpp"
QFlags< Capability > Capabilities
QStringView merge(QStringView lhs, QStringView rhs)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString name(StandardAction id)
QAction * copy(const QObject *recvr, const char *slot, QObject *parent)
QAction * next(const QObject *recvr, const char *slot, QObject *parent)
char * data()
bool isEmpty() const const
qsizetype size() const const
QColorSpace fromIccProfile(const QByteArray &iccProfile)
bool isValid() const const
QIODevice * device() const const
int readRawData(char *s, int len)
void setVersion(int v)
int skipRawData(int len)
int version() const const
uchar * bits()
qsizetype bytesPerLine() const const
int colorCount() const const
QColorSpace colorSpace() const const
void convertToColorSpace(const QColorSpace &colorSpace)
int depth() const const
void fill(Qt::GlobalColor color)
Format format() const const
bool hasAlphaChannel() const const
int height() const const
bool isNull() const const
QRgb pixel(const QPoint &position) const const
int pixelIndex(const QPoint &position) const const
uchar * scanLine(int i)
void setColorCount(int colorCount)
void setColorSpace(const QColorSpace &colorSpace)
void setColorTable(const QList< QRgb > &colors)
void setDotsPerMeterX(int x)
void setDotsPerMeterY(int y)
void setPixel(const QPoint &position, uint index_or_rgb)
void setText(const QString &key, const QString &text)
QSize size() const const
int width() const const
void setDevice(QIODevice *device)
void setFormat(const QByteArray &format)
typedef Capabilities
int allocationLimit()
virtual bool atEnd() const const
bool isOpen() const const
bool isReadable() const const
virtual bool isSequential() const const
virtual qint64 pos() const const
virtual bool seek(qint64 pos)
pointer data()
bool isEmpty() const const
void resize(qsizetype size)
qsizetype size() const const
CompositionMode_Source
void setAlpha(quint16 alpha)
void push(const T &t)
QString fromUtf8(QByteArrayView str)
transparent
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:53:42 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.