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 qint64 size;
966
967 property.readBytes(tag, size);
968
969 quint32 flags;
970 QByteArray data;
971 property >> flags >> data;
972
973 // WARNING: you cannot add metadata to QImage here because it can be null.
974 // Adding a metadata to a QImage when it is null, does nothing (metas are lost).
975 if (tag) // store metadata for future use
976 xcf_image.parasites.insert(QString::fromUtf8(tag), data);
977
978 delete[] tag;
979 }
980 break;
981
982 case PROP_UNIT:
983 property >> xcf_image.unit;
984 break;
985
986 case PROP_PATHS: // This property is ignored.
987 break;
988
989 case PROP_USER_UNIT: // This property is ignored.
990 break;
991
992 case PROP_COLORMAP:
993 property >> xcf_image.num_colors;
994 if (xcf_image.num_colors < 0 || xcf_image.num_colors > 65535) {
995 return false;
996 }
997
998 xcf_image.palette = QList<QRgb>();
999 xcf_image.palette.reserve(xcf_image.num_colors);
1000
1001 for (int i = 0; i < xcf_image.num_colors; i++) {
1002 uchar r;
1003 uchar g;
1004 uchar b;
1005 property >> r >> g >> b;
1006 xcf_image.palette.push_back(qRgb(r, g, b));
1007 }
1008 break;
1009
1010 default:
1011 qCDebug(XCFPLUGIN) << "XCF: unimplemented image property" << type << "(" << rawType << ")"
1012 << ", size " << bytes.size();
1013 break;
1014 }
1015 }
1016}
1017
1018/*!
1019 * Read a single property from the image file. The property type is returned
1020 * in type and the data is returned in bytes.
1021 * \param xcf the image file data stream.
1022 * \param type returns with the property type.
1023 * \param bytes returns with the property data.
1024 * \return true if there were no IO errors. */
1025bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes, quint32 &rawType)
1026{
1027 quint32 size;
1028
1029 xcf_io >> rawType;
1030 if (rawType >= MAX_SUPPORTED_PROPTYPE) {
1031 type = MAX_SUPPORTED_PROPTYPE;
1032 // we don't support the property, but we still need to read from the device, assume it's like all the
1033 // non custom properties that is data_length + data
1034 xcf_io >> size;
1035 xcf_io.skipRawData(size);
1036 // return true because we don't really want to totally fail on an unsupported property since it may not be fatal
1037 return true;
1038 }
1039
1040 type = PropType(rawType);
1041
1042 char *data = nullptr;
1043
1044 // The colormap property size is not the correct number of bytes:
1045 // The GIMP source xcf.c has size = 4 + ncolors, but it should be
1046 // 4 + 3 * ncolors
1047
1048 if (type == PROP_COLORMAP) {
1049 xcf_io >> size;
1050 quint32 ncolors;
1051 xcf_io >> ncolors;
1052
1053 size = 3 * ncolors + 4;
1054
1055 if (size > 65535 || size < 4) {
1056 return false;
1057 }
1058
1059 data = new char[size];
1060
1061 // since we already read "ncolors" from the stream, we put that data back
1062 data[0] = 0;
1063 data[1] = 0;
1064 data[2] = ncolors >> 8;
1065 data[3] = ncolors & 255;
1066
1067 // ... and read the remaining bytes from the stream
1068 xcf_io.readRawData(data + 4, size - 4);
1069 } else if (type == PROP_USER_UNIT) {
1070 // The USER UNIT property size is not correct. I'm not sure why, though.
1071 float factor;
1072 qint32 digits;
1073
1074 xcf_io >> size >> factor >> digits;
1075
1076 for (int i = 0; i < 5; i++) {
1077 char *unit_strings;
1078
1079 xcf_io >> unit_strings;
1080
1081 delete[] unit_strings;
1082
1083 if (xcf_io.device()->atEnd()) {
1084 qCDebug(XCFPLUGIN) << "XCF: read failure on property " << type;
1085 return false;
1086 }
1087 }
1088
1089 size = 0;
1090 } else {
1091 xcf_io >> size;
1092 if (size > 256000 * 4) {
1093 // NOTE: I didn't find any reference to maximum property dimensions in the specs, so I assume it's just a sanity check.
1094 qCDebug(XCFPLUGIN) << "XCF: loadProperty skips" << type << "due to size being too large";
1095 return false;
1096 }
1097 data = new char[size];
1098 const quint32 dataRead = xcf_io.readRawData(data, size);
1099 if (dataRead < size) {
1100 qCDebug(XCFPLUGIN) << "XCF: loadProperty read less data than expected" << size << dataRead;
1101 memset(&data[dataRead], 0, size - dataRead);
1102 }
1103 }
1104
1105 if (size != 0 && data) {
1106 bytes = QByteArray(data, size);
1107 }
1108
1109 delete[] data;
1110
1111 return true;
1112}
1113
1114/*!
1115 * Load a layer from the XCF file. The data stream must be positioned at
1116 * the beginning of the layer data.
1117 * \param xcf_io the image file data stream.
1118 * \param xcf_image contains the layer and the color table
1119 * (if the image is indexed).
1120 * \return true if there were no I/O errors.
1121 */
1122bool XCFImageFormat::loadLayer(QDataStream &xcf_io, XCFImage &xcf_image)
1123{
1124 Layer &layer(xcf_image.layer);
1125 delete[] layer.name;
1126
1127 xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
1128
1129 // Don't want to keep passing this around, dumb XCF format
1130 layer.compression = XcfCompressionType(xcf_image.compression);
1131
1132 if (!loadLayerProperties(xcf_io, layer)) {
1133 return false;
1134 }
1135
1136 qCDebug(XCFPLUGIN) << "layer: \"" << layer.name << "\", size: " << layer.width << " x " << layer.height << ", type: " << layer.type
1137 << ", mode: " << layer.mode << ", opacity: " << layer.opacity << ", visible: " << layer.visible << ", offset: " << layer.x_offset << ", "
1138 << layer.y_offset << ", compression" << layer.compression;
1139
1140 // Skip reading the rest of it if it is not visible. Typically, when
1141 // you export an image from the The GIMP it flattens (or merges) only
1142 // the visible layers into the output image.
1143
1144 if (layer.visible == 0) {
1145 return true;
1146 }
1147
1148 // If there are any more layers, merge them into the final QImage.
1149
1150 layer.hierarchy_offset = readOffsetPtr(xcf_io);
1151 layer.mask_offset = readOffsetPtr(xcf_io);
1152
1153 if (layer.hierarchy_offset < 0) {
1154 qCDebug(XCFPLUGIN) << "XCF: negative layer hierarchy_offset";
1155 return false;
1156 }
1157
1158 if (layer.mask_offset < 0) {
1159 qCDebug(XCFPLUGIN) << "XCF: negative layer mask_offset";
1160 return false;
1161 }
1162
1163 // Allocate the individual tile QImages based on the size and type
1164 // of this layer.
1165
1166 if (!composeTiles(xcf_image)) {
1167 return false;
1168 }
1169 xcf_io.device()->seek(layer.hierarchy_offset);
1170
1171 // As tiles are loaded, they are copied into the layers tiles by
1172 // this routine. (loadMask(), below, uses a slightly different
1173 // version of assignBytes().)
1174
1175 layer.assignBytes = assignImageBytes;
1176
1177 if (!loadHierarchy(xcf_io, layer, xcf_image.header.precision)) {
1178 return false;
1179 }
1180
1181 if (layer.mask_offset != 0) {
1182 // 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).
1183 if (layer.apply_mask == 9) {
1184 layer.apply_mask = 1;
1185 }
1186
1187 xcf_io.device()->seek(layer.mask_offset);
1188
1189 if (!loadMask(xcf_io, layer, xcf_image.header.precision)) {
1190 return false;
1191 }
1192 } else {
1193 // Spec says "Robust readers should force this to false if the layer has no layer mask."
1194 layer.apply_mask = 0;
1195 }
1196
1197 // Now we should have enough information to initialize the final
1198 // QImage. The first visible layer determines the attributes
1199 // of the QImage.
1200
1201 if (!xcf_image.initialized) {
1202 if (!initializeImage(xcf_image)) {
1203 return false;
1204 }
1205 copyLayerToImage(xcf_image);
1206 xcf_image.initialized = true;
1207 } else {
1208 const QColorSpace colorspaceBefore = xcf_image.image.colorSpace();
1209 mergeLayerIntoImage(xcf_image);
1210 if (xcf_image.image.colorSpace() != colorspaceBefore) {
1211 qCDebug(XCFPLUGIN) << "Converting color space back to" << colorspaceBefore << "after layer composition";
1212 xcf_image.image.convertToColorSpace(colorspaceBefore);
1213 }
1214 }
1215
1216 return true;
1217}
1218
1219/*!
1220 * An XCF file can contain an arbitrary number of properties associated
1221 * with a layer.
1222 * \param xcf_io the data stream connected to the XCF image.
1223 * \param layer layer to collect the properties.
1224 * \return true if there were no I/O errors.
1225 */
1226bool XCFImageFormat::loadLayerProperties(QDataStream &xcf_io, Layer &layer)
1227{
1228 while (true) {
1229 PropType type;
1230 QByteArray bytes;
1231 quint32 rawType;
1232
1233 if (!loadProperty(xcf_io, type, bytes, rawType)) {
1234 qCDebug(XCFPLUGIN) << "XCF: error loading layer properties";
1235 return false;
1236 }
1237
1238 QDataStream property(bytes);
1239
1240 switch (type) {
1241 case PROP_END:
1242 return true;
1243
1244 case PROP_ACTIVE_LAYER:
1245 layer.active = true;
1246 break;
1247
1248 case PROP_OPACITY:
1249 property >> layer.opacity;
1250 layer.opacity = std::min(layer.opacity, 255u);
1251 break;
1252
1253 case PROP_FLOAT_OPACITY:
1254 // For some reason QDataStream isn't able to read the float (tried
1255 // setting the endianness manually)
1256 if (bytes.size() == 4) {
1257 layer.opacityFloat = qFromBigEndian(*reinterpret_cast<float *>(bytes.data()));
1258 } else {
1259 qCDebug(XCFPLUGIN) << "XCF: Invalid data size for float:" << bytes.size();
1260 }
1261 break;
1262
1263 case PROP_VISIBLE:
1264 property >> layer.visible;
1265 break;
1266
1267 case PROP_LINKED:
1268 property >> layer.linked;
1269 break;
1270
1271 case PROP_LOCK_ALPHA:
1272 property >> layer.preserve_transparency;
1273 break;
1274
1275 case PROP_APPLY_MASK:
1276 property >> layer.apply_mask;
1277 break;
1278
1279 case PROP_EDIT_MASK:
1280 property >> layer.edit_mask;
1281 break;
1282
1283 case PROP_SHOW_MASK:
1284 property >> layer.show_mask;
1285 break;
1286
1287 case PROP_OFFSETS:
1288 property >> layer.x_offset >> layer.y_offset;
1289 break;
1290
1291 case PROP_MODE:
1292 property >> layer.mode;
1293 if (layer.mode >= GIMP_LAYER_MODE_COUNT) {
1294 qCDebug(XCFPLUGIN) << "Found layer with unsupported mode" << LayerModeType(layer.mode) << "Defaulting to mode 0";
1295 layer.mode = GIMP_LAYER_MODE_NORMAL_LEGACY;
1296 }
1297 break;
1298
1299 case PROP_TATTOO:
1300 property >> layer.tattoo;
1301 break;
1302
1303 case PROP_COMPOSITE_SPACE:
1304 property >> layer.compositeSpace;
1305 if (layer.compositeSpace < 0) {
1306 layer.compositeSpace = GimpColorSpace(layer.compositeSpace == std::numeric_limits<qint32>::lowest() ? 0 : -layer.compositeSpace);
1307 }
1308 break;
1309
1310 case PROP_COMPOSITE_MODE:
1311 property >> layer.compositeMode;
1312 if (layer.compositeMode < 0) {
1313 layer.compositeMode =
1314 XCFImageFormat::GimpCompositeMode(layer.compositeMode == std::numeric_limits<qint32>::lowest() ? 0 : -layer.compositeMode);
1315 }
1316 break;
1317
1318 case PROP_BLEND_SPACE:
1319 property >> layer.blendSpace;
1320 if (layer.blendSpace < 0) {
1321 layer.blendSpace = GimpColorSpace(layer.blendSpace == std::numeric_limits<qint32>::lowest() ? 0 : -layer.blendSpace);
1322 }
1323 break;
1324
1325 // Just for organization in the UI, doesn't influence rendering
1326 case PROP_COLOR_TAG:
1327 break;
1328
1329 // We don't support editing, so for now just ignore locking
1330 case PROP_LOCK_CONTENT:
1331 case PROP_LOCK_POSITION:
1332 break;
1333
1334 default:
1335 qCDebug(XCFPLUGIN) << "XCF: unimplemented layer property " << type << "(" << rawType << ")"
1336 << ", size " << bytes.size();
1337 break;
1338 }
1339 }
1340}
1341
1342/*!
1343 * Compute the number of tiles in the current layer and allocate
1344 * QImage structures for each of them.
1345 * \param xcf_image contains the current layer.
1346 */
1347bool XCFImageFormat::composeTiles(XCFImage &xcf_image)
1348{
1349 Layer &layer(xcf_image.layer);
1350
1351 layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
1352 layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
1353
1354 qCDebug(XCFPLUGIN) << "IMAGE: height=" << xcf_image.header.height << ", width=" << xcf_image.header.width;
1355 qCDebug(XCFPLUGIN) << "LAYER: height=" << layer.height << ", width=" << layer.width;
1356 qCDebug(XCFPLUGIN) << "LAYER: rows=" << layer.nrows << ", columns=" << layer.ncols;
1357
1358 // NOTE: starting from GIMP 2.10, images can be very large. The 32K limit for width and height is obsolete
1359 // and it was changed to 300000 (the same as Photoshop Big image). This plugin was able to open an RGB
1360 // image of 108000x40000 pixels saved with GIMP 2.10
1361 // SANITY CHECK: Catch corrupted XCF image file where the width or height
1362 // of a tile is reported are bogus. See Bug# 234030.
1363 if ((sizeof(void *) == 4 && qint64(layer.width) * layer.height > 16384 * 16384)) {
1364 qCWarning(XCFPLUGIN) << "On 32-bits programs the maximum layer size is limited to" << 16384 << "x" << 16384 << "px";
1365 return false;
1366 }
1367 if (layer.width > MAX_IMAGE_WIDTH || layer.height > MAX_IMAGE_HEIGHT) {
1368 qCWarning(XCFPLUGIN) << "The maximum layer size is limited to" << MAX_IMAGE_WIDTH << "x" << MAX_IMAGE_HEIGHT << "px";
1369 return false;
1370 }
1371
1372 // NOTE: A layer is a named rectangular area of pixels which has a definite position with respect to the canvas.
1373 // It may extend beyond the canvas or (more commonly) only cover some of it.
1374 // SANITY CHECK: Avoid to load XCF with a layer grater than 10 times the final image
1375 if (qint64(layer.width) * layer.height / 10 > qint64(xcf_image.header.width) * xcf_image.header.height) {
1376 if (qint64(layer.width) * layer.height > 16384 * 16384) { // large layers only
1377 qCWarning(XCFPLUGIN) << "Euristic sanity check: the image may be corrupted!";
1378 return false;
1379 }
1380 }
1381
1382#ifndef XCF_QT5_SUPPORT
1383 // Qt 6 image allocation limit calculation: we have to check the limit here because the image is splitted in
1384 // tiles of 64x64 pixels. The required memory to build the image is at least doubled because tiles are loaded
1385 // and then the final image is created by copying the tiles inside it.
1386 // NOTE: on Windows to open a 10GiB image the plugin uses 28GiB of RAM
1387 qint64 channels = 1 + (layer.type == RGB_GIMAGE ? 2 : 0) + (layer.type == RGBA_GIMAGE ? 3 : 0);
1388 if (qint64(layer.width) * qint64(layer.height) * channels * 2ll / 1024ll / 1024ll > QImageReader::allocationLimit()) {
1389 qCDebug(XCFPLUGIN) << "Rejecting image as it exceeds the current allocation limit of" << QImageReader::allocationLimit() << "megabytes";
1390 return false;
1391 }
1392#endif
1393
1394 layer.image_tiles.resize(layer.nrows);
1395
1396 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
1397 layer.alpha_tiles.resize(layer.nrows);
1398 }
1399
1400 if (layer.mask_offset != 0) {
1401 layer.mask_tiles.resize(layer.nrows);
1402 }
1403
1404 for (uint j = 0; j < layer.nrows; j++) {
1405 layer.image_tiles[j].resize(layer.ncols);
1406
1407 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
1408 layer.alpha_tiles[j].resize(layer.ncols);
1409 }
1410
1411 if (layer.mask_offset != 0) {
1412 layer.mask_tiles[j].resize(layer.ncols);
1413 }
1414 }
1415
1416 const QImage::Format format = layer.qimageFormat(xcf_image.header.precision);
1417
1418 for (uint j = 0; j < layer.nrows; j++) {
1419 for (uint i = 0; i < layer.ncols; i++) {
1420 uint tile_width = (i + 1) * TILE_WIDTH <= layer.width ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
1421
1422 uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
1423
1424 // Try to create the most appropriate QImage (each GIMP layer
1425 // type is treated slightly differently)
1426
1427 switch (layer.type) {
1428 case RGB_GIMAGE:
1429 case RGBA_GIMAGE:
1430 layer.image_tiles[j][i] = QImage(tile_width, tile_height, format);
1431 if (layer.image_tiles[j][i].isNull()) {
1432 return false;
1433 }
1434 layer.image_tiles[j][i].setColorCount(0);
1435 break;
1436
1437 case GRAY_GIMAGE:
1438 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1439 if (layer.image_tiles[j][i].isNull()) {
1440 return false;
1441 }
1442 layer.image_tiles[j][i].setColorCount(256);
1443 setGrayPalette(layer.image_tiles[j][i]);
1444 break;
1445
1446 case GRAYA_GIMAGE:
1447 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1448 layer.image_tiles[j][i].setColorCount(256);
1449 if (layer.image_tiles[j][i].isNull()) {
1450 return false;
1451 }
1452 setGrayPalette(layer.image_tiles[j][i]);
1453
1454 layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1455 if (layer.alpha_tiles[j][i].isNull()) {
1456 return false;
1457 }
1458 layer.alpha_tiles[j][i].setColorCount(256);
1459 setGrayPalette(layer.alpha_tiles[j][i]);
1460 break;
1461
1462 case INDEXED_GIMAGE:
1463 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1464 layer.image_tiles[j][i].setColorCount(xcf_image.num_colors);
1465 if (layer.image_tiles[j][i].isNull()) {
1466 return false;
1467 }
1468 setPalette(xcf_image, layer.image_tiles[j][i]);
1469 break;
1470
1471 case INDEXEDA_GIMAGE:
1472 layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1473 if (layer.image_tiles[j][i].isNull()) {
1474 return false;
1475 }
1476 layer.image_tiles[j][i].setColorCount(xcf_image.num_colors);
1477 setPalette(xcf_image, layer.image_tiles[j][i]);
1478
1479 layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1480 if (layer.alpha_tiles[j][i].isNull()) {
1481 return false;
1482 }
1483 layer.alpha_tiles[j][i].setColorCount(256);
1484 setGrayPalette(layer.alpha_tiles[j][i]);
1485 }
1486 if (layer.type != GRAYA_GIMAGE && layer.image_tiles[j][i].format() != format) {
1487 qCWarning(XCFPLUGIN) << "Selected wrong tile format" << layer.image_tiles[j][i].format() << "expected" << format;
1488 return false;
1489 }
1490
1491#ifndef DISABLE_TILE_PROFILE
1492 switch (xcf_image.header.precision) {
1493 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
1494 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
1495 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
1496 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
1497 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
1498 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
1499 layer.image_tiles[j][i].setColorSpace(QColorSpace::SRgbLinear);
1500 break;
1501 case XCFImageFormat::GIMP_PRECISION_HALF_NON_LINEAR:
1502 case XCFImageFormat::GIMP_PRECISION_FLOAT_NON_LINEAR:
1503 case XCFImageFormat::GIMP_PRECISION_DOUBLE_NON_LINEAR:
1504 case XCFImageFormat::GIMP_PRECISION_U8_NON_LINEAR:
1505 case XCFImageFormat::GIMP_PRECISION_U16_NON_LINEAR:
1506 case XCFImageFormat::GIMP_PRECISION_U32_NON_LINEAR:
1507 layer.image_tiles[j][i].setColorSpace(QColorSpace::SRgb);
1508 break;
1509 case XCFImageFormat::GIMP_PRECISION_HALF_PERCEPTUAL:
1510 case XCFImageFormat::GIMP_PRECISION_FLOAT_PERCEPTUAL:
1511 case XCFImageFormat::GIMP_PRECISION_DOUBLE_PERCEPTUAL:
1512 case XCFImageFormat::GIMP_PRECISION_U8_PERCEPTUAL:
1513 case XCFImageFormat::GIMP_PRECISION_U16_PERCEPTUAL:
1514 case XCFImageFormat::GIMP_PRECISION_U32_PERCEPTUAL:
1515 layer.image_tiles[j][i].setColorSpace(QColorSpace::SRgb);
1516 break;
1517 }
1518#endif
1519 if (layer.mask_offset != 0) {
1520 layer.mask_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
1521 layer.mask_tiles[j][i].setColorCount(256);
1522 if (layer.mask_tiles[j][i].isNull()) {
1523 return false;
1524 }
1525 setGrayPalette(layer.mask_tiles[j][i]);
1526 }
1527 }
1528 }
1529 return true;
1530}
1531
1532/*!
1533 * Apply a grayscale palette to the QImage. Note that Qt does not distinguish
1534 * between grayscale and indexed images. A grayscale image is just
1535 * an indexed image with a 256-color, grayscale palette.
1536 * \param image image to set to a grayscale palette.
1537 */
1538void XCFImageFormat::setGrayPalette(QImage &image)
1539{
1540 if (grayTable.isEmpty()) {
1541 grayTable.resize(256);
1542
1543 for (int i = 0; i < 256; i++) {
1544 grayTable[i] = qRgb(i, i, i);
1545 }
1546 }
1547
1548 image.setColorTable(grayTable);
1549}
1550
1551/*!
1552 * Copy the indexed palette from the XCF image into the QImage.
1553 * \param xcf_image XCF image containing the palette read from the data stream.
1554 * \param image image to apply the palette to.
1555 */
1556void XCFImageFormat::setPalette(XCFImage &xcf_image, QImage &image)
1557{
1558 Q_ASSERT(xcf_image.num_colors == xcf_image.palette.size());
1559
1560 image.setColorTable(xcf_image.palette);
1561}
1562
1563/*!
1564 * Copy the parasites info to QImage.
1565 * \param xcf_image XCF image containing the parasites read from the data stream.
1566 * \param image image to apply the parasites data.
1567 * \note Some comment taken from https://gitlab.gnome.org/GNOME/gimp/-/blob/master/devel-docs/parasites.txt
1568 */
1569void XCFImageFormat::setImageParasites(const XCFImage &xcf_image, QImage &image)
1570{
1571 auto&& p = xcf_image.parasites;
1572 auto keys = p.keys();
1573 for (auto &&key : std::as_const(keys)) {
1574 auto value = p.value(key);
1575 if (value.isEmpty())
1576 continue;
1577
1578 // "icc-profile" (IMAGE, PERSISTENT | UNDOABLE)
1579 // This contains an ICC profile describing the color space the
1580 // image was produced in. TIFF images stored in PhotoShop do
1581 // oftentimes contain embedded profiles. An experimental color
1582 // manager exists to use this parasite, and it will be used
1583 // for interchange between TIFF and PNG (identical profiles)
1584 if (key == QStringLiteral("icc-profile")) {
1585 auto cs = QColorSpace::fromIccProfile(value);
1586 if (cs.isValid())
1587 image.setColorSpace(cs);
1588 continue;
1589 }
1590
1591 // "gimp-comment" (IMAGE, PERSISTENT)
1592 // Standard GIF-style image comments. This parasite should be
1593 // human-readable text in UTF-8 encoding. A trailing \0 might
1594 // be included and is not part of the comment. Note that image
1595 // comments may also be present in the "gimp-metadata" parasite.
1596 if (key == QStringLiteral("gimp-comment")) {
1597 value.replace('\0', QByteArray());
1598 image.setText(QStringLiteral(META_KEY_COMMENT), QString::fromUtf8(value));
1599 continue;
1600 }
1601
1602 // "gimp-image-metadata"
1603 // Saved by GIMP 2.10.30 but it is not mentioned in the specification.
1604 // It is an XML block with the properties set using GIMP.
1605 if (key == QStringLiteral("gimp-image-metadata")) {
1606 // NOTE: I arbitrary defined the metadata "XML:org.gimp.xml" because it seems
1607 // a GIMP proprietary XML format (no xmlns defined)
1608 value.replace('\0', QByteArray());
1609 image.setText(QStringLiteral(META_KEY_XML_GIMP), QString::fromUtf8(value));
1610 continue;
1611 }
1612
1613#if 0 // Unable to generate it using latest GIMP version
1614 // "gimp-metadata" (IMAGE, PERSISTENT)
1615 // The metadata associated with the image, serialized as one XMP
1616 // packet. This metadata includes the contents of any XMP, EXIF
1617 // and IPTC blocks from the original image, as well as
1618 // user-specified values such as image comment, copyright,
1619 // license, etc.
1620 if (key == QStringLiteral("gimp-metadata")) {
1621 // NOTE: "XML:com.adobe.xmp" is the meta set by Qt reader when an
1622 // XMP packet is found (e.g. when reading a PNG saved by Photoshop).
1623 // I reused the same key because some programs could search for it.
1624 value.replace('\0', QByteArray());
1625 image.setText(QStringLiteral(META_KEY_XMP_ADOBE), QString::fromUtf8(value));
1626 continue;
1627 }
1628#endif
1629 }
1630
1631#ifdef DISABLE_IMAGE_PROFILE
1632 // final colorspace checks
1633 if (!image.colorSpace().isValid()) {
1634 switch (xcf_image.header.precision) {
1635 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
1636 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
1637 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
1638 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
1639 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
1640 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
1642 break;
1643 default:
1645 break;
1646 }
1647 }
1648#endif
1649}
1650
1651/*!
1652 * Copy the bytes from the tile buffer into the image tile QImage, taking into
1653 * account all the myriad different modes.
1654 * \param layer layer containing the tile buffer and the image tile matrix.
1655 * \param i column index of current tile.
1656 * \param j row index of current tile.
1657 */
1658bool XCFImageFormat::assignImageBytes(Layer &layer, uint i, uint j, const GimpPrecision &precision)
1659{
1660 QImage &image = layer.image_tiles[j][i];
1661
1662 const uchar *tile = layer.tile;
1663 const int width = image.width();
1664 const int height = image.height();
1665 const int bytesPerLine = image.bytesPerLine();
1666 uchar *bits = image.bits();
1667
1668 // Handle the special cases
1669 if (layer.type == GRAYA_GIMAGE || layer.type == GRAY_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
1670 auto bpc = bytesPerChannel(precision);
1671 for (int y = 0; y < height; y++) {
1672 uchar *dataPtr = bits + y * bytesPerLine;
1673 uchar *alphaPtr = nullptr;
1674 if (layer.alpha_tiles.size() > j && layer.alpha_tiles.at(j).size() > i) {
1675 QImage &alphaTile = layer.alpha_tiles[j][i];
1676 if (alphaTile.width() >= width && alphaTile.height() > y) {
1677 alphaPtr = alphaTile.scanLine(y);
1678 }
1679 }
1680 if (bpc == 4) {
1681#ifdef USE_FLOAT_IMAGES
1682 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
1683 for (int x = 0; x < width; x++) {
1684 auto src = reinterpret_cast<const quint16 *>(tile);
1685 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1686 if (alphaPtr) {
1687 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1688 tile += sizeof(quint16) * 2;
1689 } else {
1690 tile += sizeof(quint16);
1691 }
1692 }
1693 } else {
1694 for (int x = 0; x < width; x++) {
1695 auto src = reinterpret_cast<const float *>(tile);
1696 *dataPtr++ = qFromBigEndian<float>(src[0]) * 255;
1697 if (alphaPtr) {
1698 *alphaPtr++ = qFromBigEndian<float>(src[1]) * 255;
1699 tile += sizeof(float) * 2;
1700 } else {
1701 tile += sizeof(float);
1702 }
1703 }
1704 }
1705#else
1706 for (int x = 0; x < width; x++) {
1707 auto src = (const quint16 *)tile;
1708 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1709 if (alphaPtr) {
1710 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1711 tile += sizeof(quint16) * 2;
1712 } else {
1713 tile += sizeof(quint16);
1714 }
1715 }
1716#endif
1717 } else if (bpc == 2) {
1718#ifdef USE_FLOAT_IMAGES
1719 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
1720 for (int x = 0; x < width; x++) {
1721 auto src = reinterpret_cast<const quint16 *>(tile);
1722 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1723 if (alphaPtr)
1724 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1725 tile += sizeof(QRgb);
1726 }
1727 } else {
1728 for (int x = 0; x < width; x++) {
1729 auto src = reinterpret_cast<const qfloat16 *>(tile);
1730 *dataPtr++ = qFromBigEndian<qfloat16>(src[0]) * 255;
1731 if (alphaPtr)
1732 *alphaPtr++ = qFromBigEndian<qfloat16>(src[1]) * 255;
1733 tile += sizeof(QRgb);
1734 }
1735 }
1736#else
1737 for (int x = 0; x < width; x++) {
1738 auto src = reinterpret_cast<const quint16 *>(tile);
1739 *dataPtr++ = qFromBigEndian<quint16>(src[0]) / 257;
1740 if (alphaPtr)
1741 *alphaPtr++ = qFromBigEndian<quint16>(src[1]) / 257;
1742 tile += sizeof(QRgb);
1743 }
1744#endif
1745 } else {
1746 for (int x = 0; x < width; x++) {
1747 if (tile[0] < image.colorCount())
1748 *dataPtr++ = tile[0];
1749 if (alphaPtr)
1750 *alphaPtr++ = tile[1];
1751 tile += sizeof(QRgb);
1752 }
1753 }
1754 }
1755 return true;
1756 }
1757
1758 switch (image.format()) {
1760 for (int y = 0; y < height; y++) {
1761 uchar *dataPtr = image.scanLine(y);
1762 for (int x = 0; x < width * 4; x += 4, tile += 4) {
1763 dataPtr[x + 0] = tile[0];
1764 dataPtr[x + 1] = tile[1];
1765 dataPtr[x + 2] = tile[2];
1766 dataPtr[x + 3] = 255;
1767 }
1768 }
1769 break;
1771 for (int y = 0; y < height; y++) {
1772 const size_t bpl = width * 4;
1773 memcpy(image.scanLine(y), tile + y * bpl, bpl);
1774 }
1775 break;
1777 for (int y = 0; y < height; y++) {
1778 quint16 *dataPtr = reinterpret_cast<quint16 *>(image.scanLine(y));
1779 const size_t bpl = width * sizeof(QRgba64);
1780 const quint16 *src = reinterpret_cast<const quint16 *>(tile + y * bpl);
1781 for (int x = 0; x < width * 4; x += 4) {
1782 dataPtr[x + 0] = qFromBigEndian(src[x + 0]);
1783 dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
1784 dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
1785 dataPtr[x + 3] = 65535;
1786 }
1787 }
1788 break;
1789#ifdef USE_FLOAT_IMAGES
1791 for (int y = 0; y < height; y++) {
1792 qfloat16 *dataPtr = reinterpret_cast<qfloat16 *>(image.scanLine(y));
1793 const qfloat16 *src = reinterpret_cast<const qfloat16 *>(tile + y * width * sizeof(QRgbaFloat16));
1794 for (int x = 0; x < width * 4; x += 4) {
1795 dataPtr[x + 0] = qFromBigEndian(src[x + 0]);
1796 dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
1797 dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
1798 dataPtr[x + 3] = qfloat16(1);
1799 }
1800 }
1801 break;
1803 static_assert(sizeof(QRgbaFloat16) == sizeof(QRgba64), "Different sizes for float and int 16 bit pixels");
1804#endif
1806 for (int y = 0; y < height; y++) {
1807 const size_t bpl = width * sizeof(QRgba64);
1808 qFromBigEndian<qint16>(tile + y * bpl, width * 4, image.scanLine(y));
1809 }
1810 break;
1811#ifdef USE_FLOAT_IMAGES
1813 for (int y = 0; y < height; y++) {
1814 const size_t bpl = width * sizeof(QRgbaFloat32);
1815 qFromBigEndian<qint32>(tile + y * bpl, width * 4, image.scanLine(y));
1816 }
1817 break;
1819 for (int y = 0; y < height; y++) {
1820 float *dataPtr = reinterpret_cast<float *>(image.scanLine(y));
1821 const float *src = reinterpret_cast<const float *>(tile + y * width * sizeof(QRgbaFloat32));
1822 for (int x = 0; x < width * 4; x += 4) {
1823 dataPtr[x + 0] = qFromBigEndian(src[x + 0]);
1824 dataPtr[x + 1] = qFromBigEndian(src[x + 1]);
1825 dataPtr[x + 2] = qFromBigEndian(src[x + 2]);
1826 dataPtr[x + 3] = 1.f;
1827 }
1828 }
1829 break;
1830#endif
1832 for (int y = 0; y < height; y++) {
1833 uchar *dataPtr = bits + y * bytesPerLine;
1834 for (int x = 0; x < width; x++) {
1835 *dataPtr++ = tile[0];
1836 tile += sizeof(QRgb);
1837 }
1838 }
1839 break;
1840 default:
1841 qCWarning(XCFPLUGIN) << "Unhandled image format" << image.format() << "and/or layer type" << layer.type;
1842 return false;
1843 }
1844
1845 return true;
1846}
1847
1848/*!
1849 * The GIMP stores images in a "mipmap"-like hierarchy. As far as the QImage
1850 * is concerned, however, only the top level (i.e., the full resolution image)
1851 * is used.
1852 * \param xcf_io the data stream connected to the XCF image.
1853 * \param layer the layer to collect the image.
1854 * \return true if there were no I/O errors.
1855 */
1856bool XCFImageFormat::loadHierarchy(QDataStream &xcf_io, Layer &layer, const GimpPrecision precision)
1857{
1858 qint32 width;
1859 qint32 height;
1860 quint32 bpp;
1861
1862 xcf_io >> width >> height >> bpp;
1863 const qint64 offset = readOffsetPtr(xcf_io);
1864
1865 qCDebug(XCFPLUGIN) << "width" << width << "height" << height << "bpp" << bpp << "offset" << offset;
1866
1867 if (offset < 0) {
1868 qCDebug(XCFPLUGIN) << "XCF: negative hierarchy offset";
1869 return false;
1870 }
1871
1872 const bool isMask = layer.assignBytes == assignMaskBytes;
1873
1874 // make sure bpp is correct and complain if it is not
1875 switch (layer.type) {
1876 case RGB_GIMAGE:
1877 if (bpp != 3 * bytesPerChannel(precision)) {
1878 qCDebug(XCFPLUGIN) << "Found layer of type RGB but with bpp != 3" << bpp;
1879
1880 if (!isMask) {
1881 return false;
1882 }
1883 }
1884 break;
1885 case RGBA_GIMAGE:
1886 if (bpp != 4 * bytesPerChannel(precision)) {
1887 qCDebug(XCFPLUGIN) << "Found layer of type RGBA but with bpp != 4, got" << bpp << "bpp";
1888
1889 if (!isMask) {
1890 return false;
1891 }
1892 }
1893 break;
1894 case GRAY_GIMAGE:
1895 if (bpp != 1 * bytesPerChannel(precision)) {
1896 qCDebug(XCFPLUGIN) << "Found layer of type Gray but with bpp != 1" << bpp;
1897 return false;
1898 }
1899 break;
1900 case GRAYA_GIMAGE:
1901 if (bpp != 2 * bytesPerChannel(precision)) {
1902 qCDebug(XCFPLUGIN) << "Found layer of type Gray+Alpha but with bpp != 2" << bpp;
1903
1904 if (!isMask) {
1905 return false;
1906 }
1907 }
1908 break;
1909 case INDEXED_GIMAGE:
1910 if (bpp != 1 * bytesPerChannel(precision)) {
1911 qCDebug(XCFPLUGIN) << "Found layer of type Indexed but with bpp != 1" << bpp;
1912 return false;
1913 }
1914 break;
1915 case INDEXEDA_GIMAGE:
1916 if (bpp != 2 * bytesPerChannel(precision)) {
1917 qCDebug(XCFPLUGIN) << "Found layer of type Indexed+Alpha but with bpp != 2" << bpp;
1918
1919 if (!isMask) {
1920 return false;
1921 }
1922 }
1923 break;
1924 }
1925
1926 if (bpp > 4 * bytesPerChannel(precision)) {
1927 qCDebug(XCFPLUGIN) << "bpp is" << bpp << "We don't support layers with bpp > 4";
1928 return false;
1929 }
1930
1931 // GIMP stores images in a "mipmap"-like format (multiple levels of
1932 // increasingly lower resolution). Only the top level is used here,
1933 // however.
1934
1935 quint32 junk;
1936 do {
1937 xcf_io >> junk;
1938
1939 if (xcf_io.device()->atEnd()) {
1940 qCDebug(XCFPLUGIN) << "XCF: read failure on layer " << layer.name << " level offsets";
1941 return false;
1942 }
1943 } while (junk != 0);
1944
1945 qint64 saved_pos = xcf_io.device()->pos();
1946
1947 xcf_io.device()->seek(offset);
1948 if (!loadLevel(xcf_io, layer, bpp, precision)) {
1949 return false;
1950 }
1951
1952 xcf_io.device()->seek(saved_pos);
1953 return true;
1954}
1955
1956template<typename SourceFormat>
1957static bool convertFloatTo16Bit(uchar *output, quint64 outputSize, uchar *input)
1958{
1959 SourceFormat *source = (SourceFormat *)(input);
1960 for (quint64 offset = 0; offset < outputSize; offset++) {
1961 (reinterpret_cast<uint16_t *>(output))[offset] = qToBigEndian(quint16(qBound(0., qFromBigEndian<SourceFormat>(source[offset]) * 65535. + 0.5, 65535.)));
1962 }
1963 return true;
1964}
1965
1966/*!
1967 * Load one level of the image hierarchy (but only the top level is ever used).
1968 * \param xcf_io the data stream connected to the XCF image.
1969 * \param layer the layer to collect the image.
1970 * \param bpp the number of bytes in a pixel.
1971 * \return true if there were no I/O errors.
1972 * \sa loadTileRLE().
1973 */
1974bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp, const GimpPrecision precision)
1975{
1976 auto bpc = bytesPerChannel(precision);
1977 if ((bpc == 0) || (bpp % bpc)) {
1978 qCDebug(XCFPLUGIN) << "XCF: the stream seems corrupted";
1979 return false;
1980 }
1981
1982 qint32 width;
1983 qint32 height;
1984
1985 xcf_io >> width >> height;
1986 qint64 offset = readOffsetPtr(xcf_io);
1987
1988 if (offset < 0) {
1989 qCDebug(XCFPLUGIN) << "XCF: negative level offset";
1990 return false;
1991 }
1992
1993 if (offset == 0) {
1994 // offset 0 with rowsxcols != 0 is probably an error since it means we have tiles
1995 // without data but just clear the bits for now instead of returning false
1996 for (uint j = 0; j < layer.nrows; j++) {
1997 for (uint i = 0; i < layer.ncols; i++) {
1998 layer.image_tiles[j][i].fill(Qt::transparent);
1999 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
2000 layer.alpha_tiles[j][i].fill(Qt::transparent);
2001 }
2002 }
2003 }
2004 return true;
2005 }
2006
2007 bool needConvert = true;
2008 switch (precision) {
2009#ifdef USE_FLOAT_IMAGES
2010 case GIMP_PRECISION_HALF_LINEAR:
2011 case GIMP_PRECISION_HALF_NON_LINEAR:
2012 case GIMP_PRECISION_HALF_PERCEPTUAL:
2013 case GIMP_PRECISION_FLOAT_LINEAR:
2014 case GIMP_PRECISION_FLOAT_NON_LINEAR:
2015 case GIMP_PRECISION_FLOAT_PERCEPTUAL:
2016#endif
2017 case GIMP_PRECISION_U8_LINEAR:
2018 case GIMP_PRECISION_U8_NON_LINEAR:
2019 case GIMP_PRECISION_U8_PERCEPTUAL:
2020 case GIMP_PRECISION_U16_LINEAR:
2021 case GIMP_PRECISION_U16_NON_LINEAR:
2022 case GIMP_PRECISION_U16_PERCEPTUAL:
2023 needConvert = false;
2024 break;
2025 default:
2026 break;
2027 }
2028
2029 const uint blockSize = TILE_WIDTH * TILE_HEIGHT * bpp * 1.5;
2030
2031 QList<uchar> buffer;
2032 if (needConvert) {
2033 buffer.resize(blockSize * (bpp == 2 ? 2 : 1));
2034 }
2035 for (uint j = 0; j < layer.nrows; j++) {
2036 for (uint i = 0; i < layer.ncols; i++) {
2037 if (offset == 0) {
2038 qCDebug(XCFPLUGIN) << "XCF: incorrect number of tiles in layer " << layer.name;
2039 return false;
2040 }
2041
2042 qint64 saved_pos = xcf_io.device()->pos();
2043 qint64 offset2 = readOffsetPtr(xcf_io);
2044
2045 if (offset2 < 0) {
2046 qCDebug(XCFPLUGIN) << "XCF: negative level offset";
2047 return false;
2048 }
2049
2050 // Evidently, RLE can occasionally expand a tile instead of compressing it!
2051 if (offset2 == 0) {
2052 offset2 = offset + blockSize;
2053 }
2054
2055 xcf_io.device()->seek(offset);
2056 qint64 bytesParsed = 0;
2057
2058 switch (layer.compression) {
2059 case COMPRESS_NONE: {
2060 if (xcf_io.version() > 11 || size_t(bpp) > sizeof(QRgba64)) {
2061 qCDebug(XCFPLUGIN) << "Component reading not supported yet";
2062 return false;
2063 }
2064 const int data_size = bpp * TILE_WIDTH * TILE_HEIGHT;
2065 if (data_size > int(blockSize)) {
2066 qCDebug(XCFPLUGIN) << "Tile data too big, we can only fit" << sizeof(layer.tile) << "but need" << data_size;
2067 return false;
2068 }
2069 int dataRead = xcf_io.readRawData(reinterpret_cast<char *>(layer.tile), data_size);
2070 if (dataRead < data_size) {
2071 qCDebug(XCFPLUGIN) << "short read, expected" << data_size << "got" << dataRead;
2072 return false;
2073 }
2074 bytesParsed = dataRead;
2075 break;
2076 }
2077 case COMPRESS_RLE: {
2078 int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
2079 const uint data_size = size * bpp;
2080 if (needConvert) {
2081 if (data_size >= unsigned(buffer.size())) {
2082 qCDebug(XCFPLUGIN) << "Tile data too big, we can only fit" << buffer.size() << "but need" << data_size;
2083 return false;
2084 }
2085 } else {
2086 if (data_size > sizeof(layer.tile)) {
2087 qCDebug(XCFPLUGIN) << "Tile data too big, we can only fit" << sizeof(layer.tile) << "but need" << data_size;
2088 return false;
2089 }
2090 if (blockSize > sizeof(layer.tile)) {
2091 qCWarning(XCFPLUGIN) << "Too small tiles" << sizeof(layer.tile) << "this image requires" << blockSize << sizeof(QRgba64) << bpp;
2092 return false;
2093 }
2094 }
2095 if (!loadTileRLE(xcf_io, needConvert ? buffer.data() : layer.tile, size, offset2 - offset, bpp, &bytesParsed)) {
2096 qCDebug(XCFPLUGIN) << "Failed to read RLE";
2097 return false;
2098 }
2099 break;
2100 }
2101 default:
2102 qCDebug(XCFPLUGIN) << "Unhandled compression" << layer.compression;
2103 return false;
2104 }
2105
2106 if (needConvert) {
2107 if (bytesParsed > buffer.size()) {
2108 qCDebug(XCFPLUGIN) << "Invalid number of bytes parsed" << bytesParsed << buffer.size();
2109 return false;
2110 }
2111
2112 switch (precision) {
2113 case GIMP_PRECISION_U32_LINEAR:
2114 case GIMP_PRECISION_U32_NON_LINEAR:
2115 case GIMP_PRECISION_U32_PERCEPTUAL: {
2116 quint32 *source = reinterpret_cast<quint32 *>(buffer.data());
2117 for (quint64 offset = 0, len = buffer.size() / sizeof(quint32); offset < len; ++offset) {
2118 (reinterpret_cast<quint16 *>(layer.tile))[offset] = qToBigEndian<quint16>(qFromBigEndian(source[offset]) / 65537);
2119 }
2120 break;
2121 }
2122#ifndef USE_FLOAT_IMAGES
2123 case GIMP_PRECISION_HALF_LINEAR:
2124 case GIMP_PRECISION_HALF_NON_LINEAR:
2125 case GIMP_PRECISION_HALF_PERCEPTUAL:
2126 convertFloatTo16Bit<qfloat16>(layer.tile, buffer.size() / sizeof(qfloat16), buffer.data());
2127 break;
2128 case GIMP_PRECISION_FLOAT_LINEAR:
2129 case GIMP_PRECISION_FLOAT_NON_LINEAR:
2130 case GIMP_PRECISION_FLOAT_PERCEPTUAL:
2131 convertFloatTo16Bit<float>(layer.tile, buffer.size() / sizeof(float), buffer.data());
2132 break;
2133 case GIMP_PRECISION_DOUBLE_LINEAR:
2134 case GIMP_PRECISION_DOUBLE_NON_LINEAR:
2135 case GIMP_PRECISION_DOUBLE_PERCEPTUAL:
2136 convertFloatTo16Bit<double>(layer.tile, buffer.size() / sizeof(double), buffer.data());
2137 break;
2138#else
2139 case GIMP_PRECISION_DOUBLE_LINEAR:
2140 case GIMP_PRECISION_DOUBLE_NON_LINEAR:
2141 case GIMP_PRECISION_DOUBLE_PERCEPTUAL: {
2142 double *source = reinterpret_cast<double *>(buffer.data());
2143 for (quint64 offset = 0, len = buffer.size() / sizeof(double); offset < len; ++offset) {
2144 (reinterpret_cast<float *>(layer.tile))[offset] = qToBigEndian<float>(float(qFromBigEndian(source[offset])));
2145 }
2146 break;
2147 }
2148#endif
2149 default:
2150 qCWarning(XCFPLUGIN) << "Unsupported precision" << precision;
2151 return false;
2152 }
2153 }
2154
2155 // The bytes in the layer tile are juggled differently depending on
2156 // the target QImage. The caller has set layer.assignBytes to the
2157 // appropriate routine.
2158 if (!layer.assignBytes(layer, i, j, precision)) {
2159 return false;
2160 }
2161
2162 xcf_io.device()->seek(saved_pos);
2163 offset = readOffsetPtr(xcf_io);
2164
2165 if (offset < 0) {
2166 qCDebug(XCFPLUGIN) << "XCF: negative level offset";
2167 return false;
2168 }
2169 }
2170 }
2171
2172 return true;
2173}
2174
2175/*!
2176 * A layer can have a one channel image which is used as a mask.
2177 * \param xcf_io the data stream connected to the XCF image.
2178 * \param layer the layer to collect the mask image.
2179 * \return true if there were no I/O errors.
2180 */
2181bool XCFImageFormat::loadMask(QDataStream &xcf_io, Layer &layer, const GimpPrecision precision)
2182{
2183 qint32 width;
2184 qint32 height;
2185 char *name;
2186
2187 xcf_io >> width >> height >> name;
2188
2189 delete[] name;
2190
2191 if (!loadChannelProperties(xcf_io, layer)) {
2192 return false;
2193 }
2194
2195 const qint64 hierarchy_offset = readOffsetPtr(xcf_io);
2196
2197 if (hierarchy_offset < 0) {
2198 qCDebug(XCFPLUGIN) << "XCF: negative mask hierarchy_offset";
2199 return false;
2200 }
2201
2202 xcf_io.device()->seek(hierarchy_offset);
2203 layer.assignBytes = assignMaskBytes;
2204
2205 if (!loadHierarchy(xcf_io, layer, precision)) {
2206 return false;
2207 }
2208
2209 return true;
2210}
2211
2212/*!
2213 * This is the routine for which all the other code is simply
2214 * infrastructure. Read the image bytes out of the file and
2215 * store them in the tile buffer. This is passed a full 32-bit deep
2216 * buffer, even if bpp is smaller. The caller can figure out what to
2217 * do with the bytes.
2218 *
2219 * The tile is stored in "channels", i.e. the red component of all
2220 * pixels, then the green component of all pixels, then blue then
2221 * alpha, or, for indexed images, the color indices of all pixels then
2222 * the alpha of all pixels.
2223 *
2224 * The data is compressed with "run length encoding". Some simple data
2225 * integrity checks are made.
2226 *
2227 * \param xcf_io the data stream connected to the XCF image.
2228 * \param tile the buffer to expand the RLE into.
2229 * \param image_size number of bytes expected to be in the image tile.
2230 * \param data_length number of bytes expected in the RLE.
2231 * \param bpp number of bytes per pixel.
2232 * \return true if there were no I/O errors and no obvious corruption of
2233 * the RLE data.
2234 */
2235bool XCFImageFormat::loadTileRLE(QDataStream &xcf_io, uchar *tile, int image_size, int data_length, qint32 bpp, qint64 *bytesParsed)
2236{
2237 uchar *data = tile;
2238
2239 uchar *xcfdata;
2240 uchar *xcfodata;
2241 uchar *xcfdatalimit;
2242
2243 int step = sizeof(QRgb);
2244 switch (bpp) {
2245 case 1:
2246 case 2:
2247 case 3:
2248 case 4:
2249 step = sizeof(QRgb);
2250 break;
2251 case 6:
2252 case 8:
2253 step = sizeof(QRgb) * 2;
2254 break;
2255 case 12:
2256 case 16:
2257 step = sizeof(QRgb) * 4;
2258 break;
2259 default:
2260 qCDebug(XCFPLUGIN) << "XCF: unhandled bit depth" << bpp;
2261 return false;
2262 }
2263
2264 if (data_length < 0 || data_length > int(TILE_WIDTH * TILE_HEIGHT * step * 1.5)) {
2265 qCDebug(XCFPLUGIN) << "XCF: invalid tile data length" << data_length;
2266 return false;
2267 }
2268
2269 xcfdata = xcfodata = new uchar[data_length];
2270
2271 const int dataRead = xcf_io.readRawData((char *)xcfdata, data_length);
2272 if (dataRead <= 0) {
2273 delete[] xcfodata;
2274 qCDebug(XCFPLUGIN) << "XCF: read failure on tile" << dataRead;
2275 return false;
2276 }
2277
2278 if (dataRead < data_length) {
2279 memset(&xcfdata[dataRead], 0, data_length - dataRead);
2280 }
2281
2282 if (!xcf_io.device()->isOpen()) {
2283 delete[] xcfodata;
2284 qCDebug(XCFPLUGIN) << "XCF: read failure on tile";
2285 return false;
2286 }
2287
2288 xcfdatalimit = &xcfodata[data_length - 1];
2289
2290 for (int i = 0; i < bpp; ++i) {
2291 data = tile + i;
2292
2293 int size = image_size;
2294
2295 while (size > 0) {
2296 if (xcfdata > xcfdatalimit) {
2297 goto bogus_rle;
2298 }
2299
2300 uchar val = *xcfdata++;
2301 uint length = val;
2302
2303 if (length >= 128) {
2304 length = 255 - (length - 1);
2305 if (length == 128) {
2306 if (xcfdata >= xcfdatalimit) {
2307 goto bogus_rle;
2308 }
2309
2310 length = (*xcfdata << 8) + xcfdata[1];
2311
2312 xcfdata += 2;
2313 }
2314
2315 size -= length;
2316
2317 if (size < 0) {
2318 goto bogus_rle;
2319 }
2320
2321 if (&xcfdata[length - 1] > xcfdatalimit) {
2322 goto bogus_rle;
2323 }
2324
2325 while (length-- > 0) {
2326 *data = *xcfdata++;
2327 data += step;
2328 }
2329 } else {
2330 length += 1;
2331 if (length == 128) {
2332 if (xcfdata >= xcfdatalimit) {
2333 goto bogus_rle;
2334 }
2335
2336 length = (*xcfdata << 8) + xcfdata[1];
2337 xcfdata += 2;
2338 }
2339
2340 size -= length;
2341
2342 if (size < 0) {
2343 goto bogus_rle;
2344 }
2345
2346 if (xcfdata > xcfdatalimit) {
2347 goto bogus_rle;
2348 }
2349
2350 qintptr totalLength = qintptr(data - tile) + length * step;
2351 if (totalLength >= image_size * step * 1.5) {
2352 qCDebug(XCFPLUGIN) << "Ran out of space when trying to unpack image, over:" << totalLength - image_size << totalLength << image_size
2353 << length;
2354 goto bogus_rle;
2355 }
2356
2357 val = *xcfdata++;
2358
2359 while (length-- > 0) {
2360 *data = val;
2361 data += step;
2362 }
2363 }
2364 }
2365 }
2366 *bytesParsed = qintptr(data - tile);
2367
2368 delete[] xcfodata;
2369 return true;
2370
2371bogus_rle:
2372
2373 qCDebug(XCFPLUGIN) << "The run length encoding could not be decoded properly";
2374 delete[] xcfodata;
2375 return false;
2376}
2377
2378/*!
2379 * An XCF file can contain an arbitrary number of properties associated
2380 * with a channel. Note that this routine only reads mask channel properties.
2381 * \param xcf_io the data stream connected to the XCF image.
2382 * \param layer layer containing the mask channel to collect the properties.
2383 * \return true if there were no I/O errors.
2384 */
2385bool XCFImageFormat::loadChannelProperties(QDataStream &xcf_io, Layer &layer)
2386{
2387 while (true) {
2388 PropType type;
2389 QByteArray bytes;
2390 quint32 rawType;
2391
2392 if (!loadProperty(xcf_io, type, bytes, rawType)) {
2393 qCDebug(XCFPLUGIN) << "XCF: error loading channel properties";
2394 return false;
2395 }
2396
2397 QDataStream property(bytes);
2398
2399 switch (type) {
2400 case PROP_END:
2401 return true;
2402
2403 case PROP_OPACITY:
2404 property >> layer.mask_channel.opacity;
2405 layer.mask_channel.opacity = std::min(layer.mask_channel.opacity, 255u);
2406 break;
2407
2408 case PROP_FLOAT_OPACITY:
2409 // For some reason QDataStream isn't able to read the float (tried
2410 // setting the endianness manually)
2411 if (bytes.size() == 4) {
2412 layer.mask_channel.opacityFloat = qFromBigEndian(*reinterpret_cast<float *>(bytes.data()));
2413 } else {
2414 qCDebug(XCFPLUGIN) << "XCF: Invalid data size for float:" << bytes.size();
2415 }
2416 break;
2417
2418 case PROP_VISIBLE:
2419 property >> layer.mask_channel.visible;
2420 break;
2421
2422 case PROP_SHOW_MASKED:
2423 property >> layer.mask_channel.show_masked;
2424 break;
2425
2426 case PROP_COLOR:
2427 property >> layer.mask_channel.red >> layer.mask_channel.green >> layer.mask_channel.blue;
2428 break;
2429
2430 case PROP_FLOAT_COLOR:
2431 property >> layer.mask_channel.redF >> layer.mask_channel.greenF >> layer.mask_channel.blueF;
2432 break;
2433
2434 case PROP_TATTOO:
2435 property >> layer.mask_channel.tattoo;
2436 break;
2437
2438 // Only used in edit mode
2439 case PROP_LINKED:
2440 break;
2441
2442 // Just for organization in the UI, doesn't influence rendering
2443 case PROP_COLOR_TAG:
2444 break;
2445
2446 // We don't support editing, so for now just ignore locking
2447 case PROP_LOCK_CONTENT:
2448 case PROP_LOCK_POSITION:
2449 break;
2450
2451 default:
2452 qCDebug(XCFPLUGIN) << "XCF: unimplemented channel property " << type << "(" << rawType << ")"
2453 << ", size " << bytes.size();
2454 break;
2455 }
2456 }
2457}
2458
2459/*!
2460 * Copy the bytes from the tile buffer into the mask tile QImage.
2461 * \param layer layer containing the tile buffer and the mask tile matrix.
2462 * \param i column index of current tile.
2463 * \param j row index of current tile.
2464 */
2465bool XCFImageFormat::assignMaskBytes(Layer &layer, uint i, uint j, const GimpPrecision &precision)
2466{
2467 QImage &image = layer.mask_tiles[j][i];
2468 if (image.depth() != 8) {
2469 qCWarning(XCFPLUGIN) << "invalid bytes per pixel, we only do 8 bit masks" << image.depth();
2470 return false;
2471 }
2472
2473 uchar *tile = layer.tile;
2474 const int width = image.width();
2475 const int height = image.height();
2476 const int bytesPerLine = image.bytesPerLine();
2477 uchar *bits = image.bits();
2478 auto bpc = bytesPerChannel(precision);
2479
2480 // mask management is a house of cards: the mask is always treated as 8 bit by the plugin
2481 // (I don't want to twist the code) so it needs a conversion here.
2482 // If previously converted the step is the type size, otherwise is the one set in loadTileRLE().
2483 for (int y = 0; y < height; y++) {
2484 uchar *dataPtr = bits + y * bytesPerLine;
2485#ifdef USE_FLOAT_IMAGES
2486 if (bpc == 4) {
2487 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
2488 for (int x = 0; x < width; x++) {
2489 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2490 tile += sizeof(quint16); // was converted to 16 bits in loadLevel()
2491 }
2492 } else {
2493 for (int x = 0; x < width; x++) {
2494 *dataPtr++ = qFromBigEndian<float>(*reinterpret_cast<const float *>(tile)) * 255;
2495 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2496 }
2497 }
2498 } else if (bpc == 2) {
2499 // when not converted, the step of a
2500 if (precision < GimpPrecision::GIMP_PRECISION_HALF_LINEAR) {
2501 for (int x = 0; x < width; x++) {
2502 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2503 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2504 }
2505 } else {
2506 for (int x = 0; x < width; x++) {
2507 *dataPtr++ = qFromBigEndian<qfloat16>(*reinterpret_cast<const qfloat16 *>(tile)) * 255;
2508 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2509 }
2510 }
2511 }
2512#else
2513 if (bpc == 2) {
2514 for (int x = 0; x < width; x++) {
2515 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2516 tile += sizeof(QRgb); // yeah! see loadTileRLE() / loadLevel()
2517 }
2518 } else if (bpc == 4) {
2519 for (int x = 0; x < width; x++) {
2520 *dataPtr++ = qFromBigEndian<quint16>(*reinterpret_cast<const quint16 *>(tile)) / 257;
2521 tile += sizeof(quint16); // was converted to 16 bits in loadLevel()
2522 }
2523 }
2524#endif
2525 else {
2526 for (int x = 0; x < width; x++) {
2527 *dataPtr++ = tile[0];
2528 tile += sizeof(QRgb); // yeah! see loadTileRLE()
2529 }
2530 }
2531 }
2532
2533 return true;
2534}
2535
2536/*!
2537 * Construct the QImage which will eventually be returned to the QImage
2538 * loader.
2539 *
2540 * There are a couple of situations which require that the QImage is not
2541 * exactly the same as The GIMP's representation. The full table is:
2542 * \verbatim
2543 * Grayscale opaque : 8 bpp indexed
2544 * Grayscale translucent : 32 bpp + alpha
2545 * Indexed opaque : 1 bpp if num_colors <= 2
2546 * : 8 bpp indexed otherwise
2547 * Indexed translucent : 8 bpp indexed + alpha if num_colors < 256
2548 * : 32 bpp + alpha otherwise
2549 * RGB opaque : 32 bpp
2550 * RGBA translucent : 32 bpp + alpha
2551 * \endverbatim
2552 * Whether the image is translucent or not is determined by the bottom layer's
2553 * alpha channel. However, even if the bottom layer lacks an alpha channel,
2554 * it can still have an opacity < 1. In this case, the QImage is promoted
2555 * to 32-bit. (Note this is different from the output from the GIMP image
2556 * exporter, which seems to ignore this attribute.)
2557 *
2558 * Independently, higher layers can be translucent, but the background of
2559 * the image will not show through if the bottom layer is opaque.
2560 *
2561 * For indexed images, translucency is an all or nothing effect.
2562 * \param xcf_image contains image info and bottom-most layer.
2563 */
2564bool XCFImageFormat::initializeImage(XCFImage &xcf_image)
2565{
2566 // (Aliases to make the code look a little better.)
2567 Layer &layer(xcf_image.layer);
2568 QImage &image(xcf_image.image);
2569
2570 switch (layer.type) {
2571 case GRAY_GIMAGE:
2572 if (layer.opacity == OPAQUE_OPACITY) {
2573 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_Indexed8);
2574 image.setColorCount(256);
2575 if (image.isNull()) {
2576 return false;
2577 }
2578 setGrayPalette(image);
2579 image.fill(255);
2580 break;
2581 } // else, fall through to 32-bit representation
2582 Q_FALLTHROUGH();
2583 case GRAYA_GIMAGE:
2584 case RGB_GIMAGE:
2585 case RGBA_GIMAGE:
2586 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, xcf_image.qimageFormat());
2587 if (image.isNull()) {
2588 return false;
2589 }
2590 if (image.hasAlphaChannel()) {
2591 image.fill(Qt::transparent);
2592 } else {
2593 image.fill(Qt::white);
2594 }
2595 break;
2596
2597 case INDEXED_GIMAGE:
2598 // As noted in the table above, there are quite a few combinations
2599 // which are possible with indexed images, depending on the
2600 // presence of transparency (note: not translucency, which is not
2601 // supported by The GIMP for indexed images) and the number of
2602 // individual colors.
2603
2604 // Note: Qt treats a bitmap with a Black and White color palette
2605 // as a mask, so only the "on" bits are drawn, regardless of the
2606 // order color table entries. Otherwise (i.e., at least one of the
2607 // color table entries is not black or white), it obeys the one-
2608 // or two-color palette. Have to ask about this...
2609
2610 if (xcf_image.num_colors <= 2) {
2611 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_MonoLSB);
2612 image.setColorCount(xcf_image.num_colors);
2613 if (image.isNull()) {
2614 return false;
2615 }
2616 image.fill(0);
2617 setPalette(xcf_image, image);
2618 } else if (xcf_image.num_colors <= 256) {
2619 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_Indexed8);
2620 image.setColorCount(xcf_image.num_colors);
2621 if (image.isNull()) {
2622 return false;
2623 }
2624 image.fill(0);
2625 setPalette(xcf_image, image);
2626 }
2627 break;
2628
2629 case INDEXEDA_GIMAGE:
2630 if (xcf_image.num_colors == 1) {
2631 // Plenty(!) of room to add a transparent color
2632 xcf_image.num_colors++;
2633 xcf_image.palette.resize(xcf_image.num_colors);
2634 xcf_image.palette[1] = xcf_image.palette[0];
2635 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
2636
2637 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_MonoLSB);
2638 image.setColorCount(xcf_image.num_colors);
2639 if (image.isNull()) {
2640 return false;
2641 }
2642 image.fill(0);
2643 setPalette(xcf_image, image);
2644 } else if (xcf_image.num_colors < 256) {
2645 // Plenty of room to add a transparent color
2646 xcf_image.num_colors++;
2647 xcf_image.palette.resize(xcf_image.num_colors);
2648 for (int c = xcf_image.num_colors - 1; c >= 1; c--) {
2649 xcf_image.palette[c] = xcf_image.palette[c - 1];
2650 }
2651
2652 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
2653 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_Indexed8);
2654 image.setColorCount(xcf_image.num_colors);
2655 if (image.isNull()) {
2656 return false;
2657 }
2658 image.fill(0);
2659 setPalette(xcf_image, image);
2660 } else {
2661 // No room for a transparent color, so this has to be promoted to
2662 // true color. (There is no equivalent PNG representation output
2663 // from The GIMP as of v1.2.)
2664 image = imageAlloc(xcf_image.header.width, xcf_image.header.height, QImage::Format_ARGB32);
2665 if (image.isNull()) {
2666 return false;
2667 }
2668 image.fill(qRgba(255, 255, 255, 0));
2669 }
2670 break;
2671 }
2672 if (image.format() != xcf_image.qimageFormat()) {
2673 qCWarning(XCFPLUGIN) << "Selected wrong format:" << image.format() << "expected" << layer.qimageFormat(xcf_image.header.precision);
2674 return false;
2675 }
2676
2677 // The final profile should be the one in the Parasite
2678 // NOTE: if not set here, the colorSpace is aet in setImageParasites() (if no one defined in the parasites)
2679#ifndef DISABLE_IMAGE_PROFILE
2680 switch (xcf_image.header.precision) {
2681 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
2682 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
2683 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
2684 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
2685 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
2686 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
2688 break;
2689 case XCFImageFormat::GIMP_PRECISION_HALF_NON_LINEAR:
2690 case XCFImageFormat::GIMP_PRECISION_FLOAT_NON_LINEAR:
2691 case XCFImageFormat::GIMP_PRECISION_DOUBLE_NON_LINEAR:
2692 case XCFImageFormat::GIMP_PRECISION_U8_NON_LINEAR:
2693 case XCFImageFormat::GIMP_PRECISION_U16_NON_LINEAR:
2694 case XCFImageFormat::GIMP_PRECISION_U32_NON_LINEAR:
2696 break;
2697 case XCFImageFormat::GIMP_PRECISION_HALF_PERCEPTUAL:
2698 case XCFImageFormat::GIMP_PRECISION_FLOAT_PERCEPTUAL:
2699 case XCFImageFormat::GIMP_PRECISION_DOUBLE_PERCEPTUAL:
2700 case XCFImageFormat::GIMP_PRECISION_U8_PERCEPTUAL:
2701 case XCFImageFormat::GIMP_PRECISION_U16_PERCEPTUAL:
2702 case XCFImageFormat::GIMP_PRECISION_U32_PERCEPTUAL:
2704 break;
2705 }
2706#endif
2707
2708 if (xcf_image.x_resolution > 0 && xcf_image.y_resolution > 0) {
2709 const float dpmx = xcf_image.x_resolution * INCHESPERMETER;
2710 if (dpmx > float(std::numeric_limits<int>::max())) {
2711 return false;
2712 }
2713 const float dpmy = xcf_image.y_resolution * INCHESPERMETER;
2714 if (dpmy > float(std::numeric_limits<int>::max())) {
2715 return false;
2716 }
2717 image.setDotsPerMeterX((int)dpmx);
2718 image.setDotsPerMeterY((int)dpmy);
2719 }
2720 return true;
2721}
2722
2723/*!
2724 * Copy a layer into an image, taking account of the manifold modes. The
2725 * contents of the image are replaced.
2726 * \param xcf_image contains the layer and image to be replaced.
2727 */
2728void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
2729{
2730 Layer &layer(xcf_image.layer);
2731 QImage &image(xcf_image.image);
2732 PixelCopyOperation copy = nullptr;
2733
2734 switch (layer.type) {
2735 case RGB_GIMAGE:
2736 case RGBA_GIMAGE:
2737 copy = copyRGBToRGB;
2738 break;
2739 case GRAY_GIMAGE:
2740 if (layer.opacity == OPAQUE_OPACITY) {
2741 copy = copyGrayToGray;
2742 } else {
2743 copy = copyGrayToRGB;
2744 }
2745 break;
2746 case GRAYA_GIMAGE:
2747 copy = copyGrayAToRGB;
2748 break;
2749 case INDEXED_GIMAGE:
2750 copy = copyIndexedToIndexed;
2751 break;
2752 case INDEXEDA_GIMAGE:
2753 if (xcf_image.image.depth() <= 8) {
2754 copy = copyIndexedAToIndexed;
2755 } else {
2756 copy = copyIndexedAToRGB;
2757 }
2758 }
2759
2760 if (!copy) {
2761 return;
2762 }
2763
2764 // For each tile...
2765
2766 for (uint j = 0; j < layer.nrows; j++) {
2767 qint32 y = qint32(j * TILE_HEIGHT);
2768
2769 for (uint i = 0; i < layer.ncols; i++) {
2770 qint32 x = qint32(i * TILE_WIDTH);
2771
2772 // This seems the best place to apply the dissolve because it
2773 // depends on the global position of each tile's
2774 // pixels. Apparently it's the only mode which can apply to a
2775 // single layer.
2776
2777 if (layer.mode == GIMP_LAYER_MODE_DISSOLVE) {
2778 if (!random_table_initialized) {
2779 initializeRandomTable();
2780 random_table_initialized = true;
2781 }
2782 if (layer.type == RGBA_GIMAGE) {
2783 dissolveRGBPixels(layer.image_tiles[j][i], x, y);
2784 }
2785
2786 else if (layer.type == GRAYA_GIMAGE) {
2787 dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
2788 }
2789 }
2790
2791 // Shortcut for common case
2792 if (copy == copyRGBToRGB && layer.apply_mask != 1) {
2793 QPainter painter(&image);
2794 painter.setOpacity(layer.opacity / 255.0);
2795 painter.setCompositionMode(QPainter::CompositionMode_Source);
2796 if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
2797 y + layer.y_offset < MAX_IMAGE_HEIGHT) {
2798 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
2799 }
2800 continue;
2801 }
2802
2803 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
2804 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
2805 int m = x + k + layer.x_offset;
2806 int n = y + l + layer.y_offset;
2807
2808 if (m < 0 || m >= image.width() || n < 0 || n >= image.height()) {
2809 continue;
2810 }
2811
2812 (*copy)(layer, i, j, k, l, image, m, n);
2813 }
2814 }
2815 }
2816 }
2817}
2818
2819/*!
2820 * Copy an RGB pixel from the layer to the RGB image. Straight-forward.
2821 * The only thing this has to take account of is the opacity of the
2822 * layer. Evidently, the GIMP exporter itself does not actually do this.
2823 * \param layer source layer.
2824 * \param i x tile index.
2825 * \param j y tile index.
2826 * \param k x pixel index of tile i,j.
2827 * \param l y pixel index of tile i,j.
2828 * \param image destination image.
2829 * \param m x pixel of destination image.
2830 * \param n y pixel of destination image.
2831 */
2832void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2833{
2834 if (image.depth() == 32) {
2835 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2836 uchar src_a = layer.opacity;
2837
2838 if (layer.type == RGBA_GIMAGE) {
2839 src_a = INT_MULT(src_a, qAlpha(src));
2840 }
2841
2842 // Apply the mask (if any)
2843
2844 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2845 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2846 }
2847
2848 image.setPixel(m, n, qRgba(src, src_a));
2849 } else if (image.depth() == 64) {
2850 QRgba64 src = layer.image_tiles[j][i].pixelColor(k, l).rgba64();
2851 quint16 src_a = layer.opacity;
2852
2853 if (layer.type == RGBA_GIMAGE) {
2854 src_a = INT_MULT(src_a, qAlpha(src));
2855 }
2856
2857 // Apply the mask (if any)
2858
2859 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2860 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2861 }
2862 src.setAlpha(src_a);
2863
2864 image.setPixel(m, n, src);
2865 }
2866}
2867
2868/*!
2869 * Copy a Gray pixel from the layer to the Gray image. Straight-forward.
2870 * \param layer source layer.
2871 * \param i x tile index.
2872 * \param j y tile index.
2873 * \param k x pixel index of tile i,j.
2874 * \param l y pixel index of tile i,j.
2875 * \param image destination image.
2876 * \param m x pixel of destination image.
2877 * \param n y pixel of destination image.
2878 */
2879void XCFImageFormat::copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2880{
2881 int src = layer.image_tiles[j][i].pixelIndex(k, l);
2882 image.setPixel(m, n, src);
2883}
2884
2885/*!
2886 * Copy a Gray pixel from the layer to an RGB image. Straight-forward.
2887 * The only thing this has to take account of is the opacity of the
2888 * layer. Evidently, the GIMP exporter itself does not actually do this.
2889 * \param layer source layer.
2890 * \param i x tile index.
2891 * \param j y tile index.
2892 * \param k x pixel index of tile i,j.
2893 * \param l y pixel index of tile i,j.
2894 * \param image destination image.
2895 * \param m x pixel of destination image.
2896 * \param n y pixel of destination image.
2897 */
2898void XCFImageFormat::copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2899{
2900 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2901 uchar src_a = layer.opacity;
2902 image.setPixel(m, n, qRgba(src, src_a));
2903}
2904
2905/*!
2906 * Copy a GrayA pixel from the layer to an RGB image. Straight-forward.
2907 * The only thing this has to take account of is the opacity of the
2908 * layer. Evidently, the GIMP exporter itself does not actually do this.
2909 * \param layer source layer.
2910 * \param i x tile index.
2911 * \param j y tile index.
2912 * \param k x pixel index of tile i,j.
2913 * \param l y pixel index of tile i,j.
2914 * \param image destination image.
2915 * \param m x pixel of destination image.
2916 * \param n y pixel of destination image.
2917 */
2918void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2919{
2920 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2921 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2922 src_a = INT_MULT(src_a, layer.opacity);
2923
2924 // Apply the mask (if any)
2925
2926 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2927 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2928 }
2929
2930 image.setPixel(m, n, qRgba(src, src_a));
2931}
2932
2933/*!
2934 * Copy an Indexed pixel from the layer to the Indexed image. Straight-forward.
2935 * \param layer source layer.
2936 * \param i x tile index.
2937 * \param j y tile index.
2938 * \param k x pixel index of tile i,j.
2939 * \param l y pixel index of tile i,j.
2940 * \param image destination image.
2941 * \param m x pixel of destination image.
2942 * \param n y pixel of destination image.
2943 */
2944void XCFImageFormat::copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2945{
2946 int src = layer.image_tiles[j][i].pixelIndex(k, l);
2947 image.setPixel(m, n, src);
2948}
2949
2950/*!
2951 * Copy an IndexedA pixel from the layer to the Indexed image. Straight-forward.
2952 * \param layer source layer.
2953 * \param i x tile index.
2954 * \param j y tile index.
2955 * \param k x pixel index of tile i,j.
2956 * \param l y pixel index of tile i,j.
2957 * \param image destination image.
2958 * \param m x pixel of destination image.
2959 * \param n y pixel of destination image.
2960 */
2961void XCFImageFormat::copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2962{
2963 uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
2964 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2965 src_a = INT_MULT(src_a, layer.opacity);
2966
2967 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
2968 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2969 }
2970
2971 if (src_a > 127) {
2972 src++;
2973 } else {
2974 src = 0;
2975 }
2976
2977 image.setPixel(m, n, src);
2978}
2979
2980/*!
2981 * Copy an IndexedA pixel from the layer to an RGB image. Straight-forward.
2982 * The only thing this has to take account of is the opacity of the
2983 * layer. Evidently, the GIMP exporter itself does not actually do this.
2984 * \param layer source layer.
2985 * \param i x tile index.
2986 * \param j y tile index.
2987 * \param k x pixel index of tile i,j.
2988 * \param l y pixel index of tile i,j.
2989 * \param image destination image.
2990 * \param m x pixel of destination image.
2991 * \param n y pixel of destination image.
2992 */
2993void XCFImageFormat::copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
2994{
2995 QRgb src = layer.image_tiles[j][i].pixel(k, l);
2996 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2997 src_a = INT_MULT(src_a, layer.opacity);
2998
2999 // Apply the mask (if any)
3000 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3001 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3002 }
3003
3004 // This is what appears in the GIMP window
3005 if (src_a <= 127) {
3006 src_a = 0;
3007 } else {
3008 src_a = OPAQUE_OPACITY;
3009 }
3010
3011 image.setPixel(m, n, qRgba(src, src_a));
3012}
3013
3014/*!
3015 * Merge a layer into an image, taking account of the manifold modes.
3016 * \param xcf_image contains the layer and image to merge.
3017 */
3018void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
3019{
3020 Layer &layer(xcf_image.layer);
3021 QImage &image(xcf_image.image);
3022
3023 PixelMergeOperation merge = nullptr;
3024
3025 if (!layer.opacity) {
3026 return; // don't bother doing anything
3027 }
3028
3029 if (layer.blendSpace == XCFImageFormat::AutoColorSpace) {
3030 qCDebug(XCFPLUGIN) << "Auto blend space, defaulting to RgbLinearSpace (same as Gimp when writing this)";
3031 layer.blendSpace = XCFImageFormat::RgbLinearSpace;
3032 }
3033
3034 if (layer.blendSpace != XCFImageFormat::RgbLinearSpace) {
3035 qCDebug(XCFPLUGIN) << "Unimplemented blend color space" << layer.blendSpace;
3036 }
3037 qCDebug(XCFPLUGIN) << "Blend color space" << layer.blendSpace;
3038
3039 if (layer.compositeSpace == XCFImageFormat::AutoColorSpace) {
3040 qCDebug(XCFPLUGIN) << "Auto composite space, defaulting to RgbLinearSpace (same as Gimp when writing this)";
3041 layer.compositeSpace = XCFImageFormat::RgbLinearSpace;
3042 }
3043
3044 if (layer.compositeSpace != XCFImageFormat::RgbLinearSpace) {
3045 qCDebug(XCFPLUGIN) << "Unimplemented composite color space" << layer.compositeSpace;
3046 }
3047 if (layer.compositeMode != XCFImageFormat::CompositeUnion) {
3048 qCDebug(XCFPLUGIN) << "Unhandled composite mode" << layer.compositeMode;
3049 }
3050
3051 switch (layer.type) {
3052 case RGB_GIMAGE:
3053 case RGBA_GIMAGE:
3054 merge = mergeRGBToRGB;
3055 break;
3056 case GRAY_GIMAGE:
3057 if (layer.opacity == OPAQUE_OPACITY && xcf_image.image.depth() <= 8) {
3058 merge = mergeGrayToGray;
3059 } else {
3060 merge = mergeGrayToRGB;
3061 }
3062 break;
3063 case GRAYA_GIMAGE:
3064 if (xcf_image.image.depth() <= 8) {
3065 merge = mergeGrayAToGray;
3066 } else {
3067 merge = mergeGrayAToRGB;
3068 }
3069 break;
3070 case INDEXED_GIMAGE:
3071 merge = mergeIndexedToIndexed;
3072 break;
3073 case INDEXEDA_GIMAGE:
3074 if (xcf_image.image.depth() <= 8) {
3075 merge = mergeIndexedAToIndexed;
3076 } else {
3077 merge = mergeIndexedAToRGB;
3078 }
3079 }
3080
3081 if (!merge) {
3082 return;
3083 }
3084
3085 if (merge == mergeRGBToRGB && layer.apply_mask != 1) {
3086 int painterMode = -1;
3087 switch (layer.mode) {
3088 case GIMP_LAYER_MODE_NORMAL:
3089 case GIMP_LAYER_MODE_NORMAL_LEGACY:
3091 break;
3092 case GIMP_LAYER_MODE_MULTIPLY:
3093 case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
3095 break;
3096 case GIMP_LAYER_MODE_SCREEN:
3097 case GIMP_LAYER_MODE_SCREEN_LEGACY:
3099 break;
3100 case GIMP_LAYER_MODE_OVERLAY:
3101 case GIMP_LAYER_MODE_OVERLAY_LEGACY:
3103 break;
3104 case GIMP_LAYER_MODE_DIFFERENCE:
3105 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
3107 break;
3108 case GIMP_LAYER_MODE_DARKEN_ONLY:
3109 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
3111 break;
3112 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3113 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
3115 break;
3116 case GIMP_LAYER_MODE_DODGE:
3117 case GIMP_LAYER_MODE_DODGE_LEGACY:
3119 break;
3120 case GIMP_LAYER_MODE_BURN:
3121 case GIMP_LAYER_MODE_BURN_LEGACY:
3123 break;
3124 case GIMP_LAYER_MODE_HARDLIGHT:
3125 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY:
3127 break;
3128 case GIMP_LAYER_MODE_SOFTLIGHT:
3129 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY:
3131 break;
3132 case GIMP_LAYER_MODE_ADDITION:
3133 case GIMP_LAYER_MODE_ADDITION_LEGACY:
3134 painterMode = QPainter::CompositionMode_Plus;
3135 break;
3136 case GIMP_LAYER_MODE_EXCLUSION:
3138 break;
3139
3140 // Not bothered to find what the QPainter equivalent is, or there is none
3141 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3142 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY:
3143 case GIMP_LAYER_MODE_GRAIN_MERGE:
3144 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY:
3145 case GIMP_LAYER_MODE_COLOR_ERASE:
3146 case GIMP_LAYER_MODE_COLOR_ERASE_LEGACY:
3147 case GIMP_LAYER_MODE_LCH_HUE:
3148 case GIMP_LAYER_MODE_LCH_CHROMA:
3149 case GIMP_LAYER_MODE_LCH_COLOR:
3150 case GIMP_LAYER_MODE_LCH_LIGHTNESS:
3151 case GIMP_LAYER_MODE_BEHIND:
3152 case GIMP_LAYER_MODE_BEHIND_LEGACY:
3153 case GIMP_LAYER_MODE_SUBTRACT:
3154 case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
3155 case GIMP_LAYER_MODE_HSV_HUE:
3156 case GIMP_LAYER_MODE_HSV_SATURATION:
3157 case GIMP_LAYER_MODE_HSL_COLOR:
3158 case GIMP_LAYER_MODE_HSV_VALUE:
3159 case GIMP_LAYER_MODE_DIVIDE:
3160 case GIMP_LAYER_MODE_VIVID_LIGHT:
3161 case GIMP_LAYER_MODE_PIN_LIGHT:
3162 case GIMP_LAYER_MODE_LINEAR_LIGHT:
3163 case GIMP_LAYER_MODE_HARD_MIX:
3164 case GIMP_LAYER_MODE_LINEAR_BURN:
3165 case GIMP_LAYER_MODE_LUMA_DARKEN_ONLY:
3166 case GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY:
3167 case GIMP_LAYER_MODE_LUMINANCE:
3168 case GIMP_LAYER_MODE_ERASE:
3169 case GIMP_LAYER_MODE_MERGE:
3170 case GIMP_LAYER_MODE_SPLIT:
3171 case GIMP_LAYER_MODE_PASS_THROUGH:
3172 case GIMP_LAYER_MODE_HSV_HUE_LEGACY:
3173 case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY:
3174 case GIMP_LAYER_MODE_HSL_COLOR_LEGACY:
3175 case GIMP_LAYER_MODE_HSV_VALUE_LEGACY:
3176 case GIMP_LAYER_MODE_DIVIDE_LEGACY:
3177 qCDebug(XCFPLUGIN) << "No QPainter equivalent to" << layer.mode;
3178 break;
3179
3180 // Special
3181 case GIMP_LAYER_MODE_DISSOLVE:
3182 case GIMP_LAYER_MODE_COUNT:
3183 break;
3184 }
3185
3186 if (painterMode != -1) {
3187 QPainter painter(&image);
3188 painter.setOpacity(layer.opacity / 255.0);
3189 painter.setCompositionMode(QPainter::CompositionMode(painterMode));
3190 qCDebug(XCFPLUGIN) << "Using QPainter for mode" << layer.mode;
3191
3192 for (uint j = 0; j < layer.nrows; j++) {
3193 qint32 y = qint32(j * TILE_HEIGHT);
3194
3195 for (uint i = 0; i < layer.ncols; i++) {
3196 qint32 x = qint32(i * TILE_WIDTH);
3197
3198 QImage &tile = layer.image_tiles[j][i];
3199 if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
3200 y + layer.y_offset < MAX_IMAGE_HEIGHT) {
3201 painter.drawImage(x + layer.x_offset, y + layer.y_offset, tile);
3202 }
3203 }
3204 }
3205
3206 return;
3207 }
3208 }
3209
3210#ifndef DISABLE_IMAGE_PROFILE_CONV // The final profile should be the one in the Parasite
3211 if (layer.compositeSpace == XCFImageFormat::RgbPerceptualSpace && image.colorSpace() != QColorSpace::SRgb) {
3212 qCDebug(XCFPLUGIN) << "Converting to composite color space" << layer.compositeSpace;
3214 }
3215 if (layer.compositeSpace == XCFImageFormat::RgbLinearSpace && image.colorSpace() != QColorSpace::SRgbLinear) {
3216 qCDebug(XCFPLUGIN) << "Converting to composite color space" << layer.compositeSpace;
3218 }
3219#endif
3220
3221 for (uint j = 0; j < layer.nrows; j++) {
3222 qint32 y = qint32(j * TILE_HEIGHT);
3223
3224 for (uint i = 0; i < layer.ncols; i++) {
3225 qint32 x = qint32(i * TILE_WIDTH);
3226
3227 // This seems the best place to apply the dissolve because it
3228 // depends on the global position of each tile's
3229 // pixels. Apparently it's the only mode which can apply to a
3230 // single layer.
3231
3232 if (layer.mode == GIMP_LAYER_MODE_DISSOLVE) {
3233 if (!random_table_initialized) {
3234 initializeRandomTable();
3235 random_table_initialized = true;
3236 }
3237 if (layer.type == RGBA_GIMAGE) {
3238 dissolveRGBPixels(layer.image_tiles[j][i], x, y);
3239 }
3240
3241 else if (layer.type == GRAYA_GIMAGE) {
3242 dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
3243 }
3244 }
3245
3246 // Shortcut for common case
3247 if (merge == mergeRGBToRGB && layer.apply_mask != 1 && layer.mode == GIMP_LAYER_MODE_NORMAL_LEGACY) {
3248 QPainter painter(&image);
3249 painter.setOpacity(layer.opacity / 255.0);
3250 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
3251 if (x + layer.x_offset < MAX_IMAGE_WIDTH &&
3252 y + layer.y_offset < MAX_IMAGE_HEIGHT) {
3253 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
3254 }
3255 continue;
3256 }
3257
3258#ifndef DISABLE_TILE_PROFILE_CONV // not sure about that: left as old plugin
3259 QImage &tile = layer.image_tiles[j][i];
3260 if (layer.compositeSpace == XCFImageFormat::RgbPerceptualSpace && tile.colorSpace() != QColorSpace::SRgb) {
3262 }
3263 if (layer.compositeSpace == XCFImageFormat::RgbLinearSpace && tile.colorSpace() != QColorSpace::SRgbLinear) {
3265 }
3266#endif
3267
3268 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
3269 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
3270 int m = x + k + layer.x_offset;
3271 int n = y + l + layer.y_offset;
3272
3273 if (m < 0 || m >= image.width() || n < 0 || n >= image.height()) {
3274 continue;
3275 }
3276
3277 if (!(*merge)(layer, i, j, k, l, image, m, n)) {
3278 return;
3279 }
3280 }
3281 }
3282 }
3283 }
3284}
3285
3286/*!
3287 * Merge an RGB pixel from the layer to the RGB image. Straight-forward.
3288 * The only thing this has to take account of is the opacity of the
3289 * layer. Evidently, the GIMP exporter itself does not actually do this.
3290 * \param layer source layer.
3291 * \param i x tile index.
3292 * \param j y tile index.
3293 * \param k x pixel index of tile i,j.
3294 * \param l y pixel index of tile i,j.
3295 * \param image destination image.
3296 * \param m x pixel of destination image.
3297 * \param n y pixel of destination image.
3298 */
3299bool XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3300{
3301 QRgb src = layer.image_tiles[j][i].pixel(k, l);
3302 QRgb dst = image.pixel(m, n);
3303
3304 uchar src_r = qRed(src);
3305 uchar src_g = qGreen(src);
3306 uchar src_b = qBlue(src);
3307 uchar src_a = qAlpha(src);
3308
3309 uchar dst_r = qRed(dst);
3310 uchar dst_g = qGreen(dst);
3311 uchar dst_b = qBlue(dst);
3312 uchar dst_a = qAlpha(dst);
3313
3314 if (!src_a) {
3315 return false; // nothing to merge
3316 }
3317
3318 switch (layer.mode) {
3319 case GIMP_LAYER_MODE_NORMAL:
3320 case GIMP_LAYER_MODE_NORMAL_LEGACY:
3321 break;
3322 case GIMP_LAYER_MODE_MULTIPLY:
3323 case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
3324 src_r = INT_MULT(src_r, dst_r);
3325 src_g = INT_MULT(src_g, dst_g);
3326 src_b = INT_MULT(src_b, dst_b);
3327 src_a = qMin(src_a, dst_a);
3328 break;
3329 case GIMP_LAYER_MODE_DIVIDE:
3330 case GIMP_LAYER_MODE_DIVIDE_LEGACY:
3331 src_r = qMin((dst_r * 256) / (1 + src_r), 255);
3332 src_g = qMin((dst_g * 256) / (1 + src_g), 255);
3333 src_b = qMin((dst_b * 256) / (1 + src_b), 255);
3334 src_a = qMin(src_a, dst_a);
3335 break;
3336 case GIMP_LAYER_MODE_SCREEN:
3337 case GIMP_LAYER_MODE_SCREEN_LEGACY:
3338 src_r = 255 - INT_MULT(255 - dst_r, 255 - src_r);
3339 src_g = 255 - INT_MULT(255 - dst_g, 255 - src_g);
3340 src_b = 255 - INT_MULT(255 - dst_b, 255 - src_b);
3341 src_a = qMin(src_a, dst_a);
3342 break;
3343 case GIMP_LAYER_MODE_OVERLAY:
3344 case GIMP_LAYER_MODE_OVERLAY_LEGACY:
3345 src_r = INT_MULT(dst_r, dst_r + INT_MULT(2 * src_r, 255 - dst_r));
3346 src_g = INT_MULT(dst_g, dst_g + INT_MULT(2 * src_g, 255 - dst_g));
3347 src_b = INT_MULT(dst_b, dst_b + INT_MULT(2 * src_b, 255 - dst_b));
3348 src_a = qMin(src_a, dst_a);
3349 break;
3350 case GIMP_LAYER_MODE_DIFFERENCE:
3351 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
3352 src_r = dst_r > src_r ? dst_r - src_r : src_r - dst_r;
3353 src_g = dst_g > src_g ? dst_g - src_g : src_g - dst_g;
3354 src_b = dst_b > src_b ? dst_b - src_b : src_b - dst_b;
3355 src_a = qMin(src_a, dst_a);
3356 break;
3357 case GIMP_LAYER_MODE_ADDITION:
3358 case GIMP_LAYER_MODE_ADDITION_LEGACY:
3359 src_r = add_lut(dst_r, src_r);
3360 src_g = add_lut(dst_g, src_g);
3361 src_b = add_lut(dst_b, src_b);
3362 src_a = qMin(src_a, dst_a);
3363 break;
3364 case GIMP_LAYER_MODE_SUBTRACT:
3365 case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
3366 src_r = dst_r > src_r ? dst_r - src_r : 0;
3367 src_g = dst_g > src_g ? dst_g - src_g : 0;
3368 src_b = dst_b > src_b ? dst_b - src_b : 0;
3369 src_a = qMin(src_a, dst_a);
3370 break;
3371 case GIMP_LAYER_MODE_DARKEN_ONLY:
3372 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
3373 src_r = dst_r < src_r ? dst_r : src_r;
3374 src_g = dst_g < src_g ? dst_g : src_g;
3375 src_b = dst_b < src_b ? dst_b : src_b;
3376 src_a = qMin(src_a, dst_a);
3377 break;
3378 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3379 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
3380 src_r = dst_r < src_r ? src_r : dst_r;
3381 src_g = dst_g < src_g ? src_g : dst_g;
3382 src_b = dst_b < src_b ? src_b : dst_b;
3383 src_a = qMin(src_a, dst_a);
3384 break;
3385 case GIMP_LAYER_MODE_HSV_HUE:
3386 case GIMP_LAYER_MODE_HSV_HUE_LEGACY: {
3387 uchar new_r = dst_r;
3388 uchar new_g = dst_g;
3389 uchar new_b = dst_b;
3390
3391 RGBTOHSV(src_r, src_g, src_b);
3392 RGBTOHSV(new_r, new_g, new_b);
3393
3394 new_r = src_r;
3395
3396 HSVTORGB(new_r, new_g, new_b);
3397
3398 src_r = new_r;
3399 src_g = new_g;
3400 src_b = new_b;
3401 src_a = qMin(src_a, dst_a);
3402 } break;
3403 case GIMP_LAYER_MODE_HSV_SATURATION:
3404 case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY: {
3405 uchar new_r = dst_r;
3406 uchar new_g = dst_g;
3407 uchar new_b = dst_b;
3408
3409 RGBTOHSV(src_r, src_g, src_b);
3410 RGBTOHSV(new_r, new_g, new_b);
3411
3412 new_g = src_g;
3413
3414 HSVTORGB(new_r, new_g, new_b);
3415
3416 src_r = new_r;
3417 src_g = new_g;
3418 src_b = new_b;
3419 src_a = qMin(src_a, dst_a);
3420 } break;
3421 case GIMP_LAYER_MODE_HSV_VALUE:
3422 case GIMP_LAYER_MODE_HSV_VALUE_LEGACY: {
3423 uchar new_r = dst_r;
3424 uchar new_g = dst_g;
3425 uchar new_b = dst_b;
3426
3427 RGBTOHSV(src_r, src_g, src_b);
3428 RGBTOHSV(new_r, new_g, new_b);
3429
3430 new_b = src_b;
3431
3432 HSVTORGB(new_r, new_g, new_b);
3433
3434 src_r = new_r;
3435 src_g = new_g;
3436 src_b = new_b;
3437 src_a = qMin(src_a, dst_a);
3438 } break;
3439 case GIMP_LAYER_MODE_HSL_COLOR:
3440 case GIMP_LAYER_MODE_HSL_COLOR_LEGACY: {
3441 uchar new_r = dst_r;
3442 uchar new_g = dst_g;
3443 uchar new_b = dst_b;
3444
3445 RGBTOHLS(src_r, src_g, src_b);
3446 RGBTOHLS(new_r, new_g, new_b);
3447
3448 new_r = src_r;
3449 new_b = src_b;
3450
3451 HLSTORGB(new_r, new_g, new_b);
3452
3453 src_r = new_r;
3454 src_g = new_g;
3455 src_b = new_b;
3456 src_a = qMin(src_a, dst_a);
3457 } break;
3458 case GIMP_LAYER_MODE_DODGE:
3459 case GIMP_LAYER_MODE_DODGE_LEGACY: {
3460 uint tmp;
3461
3462 tmp = dst_r << 8;
3463 tmp /= 256 - src_r;
3464 src_r = (uchar)qMin(tmp, 255u);
3465
3466 tmp = dst_g << 8;
3467 tmp /= 256 - src_g;
3468 src_g = (uchar)qMin(tmp, 255u);
3469
3470 tmp = dst_b << 8;
3471 tmp /= 256 - src_b;
3472 src_b = (uchar)qMin(tmp, 255u);
3473
3474 src_a = qMin(src_a, dst_a);
3475 } break;
3476 case GIMP_LAYER_MODE_BURN:
3477 case GIMP_LAYER_MODE_BURN_LEGACY: {
3478 uint tmp;
3479
3480 tmp = (255 - dst_r) << 8;
3481 tmp /= src_r + 1;
3482 src_r = (uchar)qMin(tmp, 255u);
3483 src_r = 255 - src_r;
3484
3485 tmp = (255 - dst_g) << 8;
3486 tmp /= src_g + 1;
3487 src_g = (uchar)qMin(tmp, 255u);
3488 src_g = 255 - src_g;
3489
3490 tmp = (255 - dst_b) << 8;
3491 tmp /= src_b + 1;
3492 src_b = (uchar)qMin(tmp, 255u);
3493 src_b = 255 - src_b;
3494
3495 src_a = qMin(src_a, dst_a);
3496 } break;
3497 case GIMP_LAYER_MODE_HARDLIGHT:
3498 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
3499 uint tmp;
3500 if (src_r > 128) {
3501 tmp = ((int)255 - dst_r) * ((int)255 - ((src_r - 128) << 1));
3502 src_r = (uchar)qMin(255 - (tmp >> 8), 255u);
3503 } else {
3504 tmp = (int)dst_r * ((int)src_r << 1);
3505 src_r = (uchar)qMin(tmp >> 8, 255u);
3506 }
3507
3508 if (src_g > 128) {
3509 tmp = ((int)255 - dst_g) * ((int)255 - ((src_g - 128) << 1));
3510 src_g = (uchar)qMin(255 - (tmp >> 8), 255u);
3511 } else {
3512 tmp = (int)dst_g * ((int)src_g << 1);
3513 src_g = (uchar)qMin(tmp >> 8, 255u);
3514 }
3515
3516 if (src_b > 128) {
3517 tmp = ((int)255 - dst_b) * ((int)255 - ((src_b - 128) << 1));
3518 src_b = (uchar)qMin(255 - (tmp >> 8), 255u);
3519 } else {
3520 tmp = (int)dst_b * ((int)src_b << 1);
3521 src_b = (uchar)qMin(tmp >> 8, 255u);
3522 }
3523 src_a = qMin(src_a, dst_a);
3524 } break;
3525 case GIMP_LAYER_MODE_SOFTLIGHT:
3526 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
3527 uint tmpS;
3528 uint tmpM;
3529
3530 tmpM = INT_MULT(dst_r, src_r);
3531 tmpS = 255 - INT_MULT((255 - dst_r), (255 - src_r));
3532 src_r = INT_MULT((255 - dst_r), tmpM) + INT_MULT(dst_r, tmpS);
3533
3534 tmpM = INT_MULT(dst_g, src_g);
3535 tmpS = 255 - INT_MULT((255 - dst_g), (255 - src_g));
3536 src_g = INT_MULT((255 - dst_g), tmpM) + INT_MULT(dst_g, tmpS);
3537
3538 tmpM = INT_MULT(dst_b, src_b);
3539 tmpS = 255 - INT_MULT((255 - dst_b), (255 - src_b));
3540 src_b = INT_MULT((255 - dst_b), tmpM) + INT_MULT(dst_b, tmpS);
3541
3542 src_a = qMin(src_a, dst_a);
3543 } break;
3544 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3545 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
3546 int tmp;
3547
3548 tmp = dst_r - src_r + 128;
3549 tmp = qMin(tmp, 255);
3550 tmp = qMax(tmp, 0);
3551 src_r = (uchar)tmp;
3552
3553 tmp = dst_g - src_g + 128;
3554 tmp = qMin(tmp, 255);
3555 tmp = qMax(tmp, 0);
3556 src_g = (uchar)tmp;
3557
3558 tmp = dst_b - src_b + 128;
3559 tmp = qMin(tmp, 255);
3560 tmp = qMax(tmp, 0);
3561 src_b = (uchar)tmp;
3562
3563 src_a = qMin(src_a, dst_a);
3564 } break;
3565 case GIMP_LAYER_MODE_GRAIN_MERGE:
3566 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
3567 int tmp;
3568
3569 tmp = dst_r + src_r - 128;
3570 tmp = qMin(tmp, 255);
3571 tmp = qMax(tmp, 0);
3572 src_r = (uchar)tmp;
3573
3574 tmp = dst_g + src_g - 128;
3575 tmp = qMin(tmp, 255);
3576 tmp = qMax(tmp, 0);
3577 src_g = (uchar)tmp;
3578
3579 tmp = dst_b + src_b - 128;
3580 tmp = qMin(tmp, 255);
3581 tmp = qMax(tmp, 0);
3582 src_b = (uchar)tmp;
3583
3584 src_a = qMin(src_a, dst_a);
3585 } break;
3586 case GIMP_LAYER_MODE_LINEAR_LIGHT: {
3587 if (src_r <= 128) {
3588 src_r = qBound(0, dst_r + 2 * src_r - 255, 255);
3589 } else {
3590 src_r = qBound(0, dst_r + 2 * (src_r - 128), 255);
3591 }
3592 if (src_g <= 128) {
3593 src_g = qBound(0, dst_g + 2 * src_g - 255, 255);
3594 } else {
3595 src_g = qBound(0, dst_g + 2 * (src_g - 127), 255);
3596 }
3597 if (src_b <= 128) {
3598 src_b = qBound(0, dst_b + 2 * src_b - 255, 255);
3599 } else {
3600 src_b = qBound(0, dst_b + 2 * (src_b - 127), 255);
3601 }
3602 } break;
3603 case GIMP_LAYER_MODE_VIVID_LIGHT: {
3604 // From http://www.simplefilter.de/en/basics/mixmods.html
3605 float A[3];
3606 A[0] = src_r / 255.;
3607 A[1] = src_g / 255.;
3608 A[2] = src_b / 255.;
3609 float B[3];
3610 B[0] = dst_r / 255.;
3611 B[1] = dst_g / 255.;
3612 B[2] = dst_b / 255.;
3613 float C[3]{};
3614 for (int i = 0; i < 3; i++) {
3615 if (A[i] <= 0.5f) {
3616 if (A[i] > 0.f) {
3617 C[i] = 1.f - (1.f - B[i]) / (2.f * A[i]);
3618 }
3619 } else {
3620 if (A[i] < 1.f) {
3621 C[i] = B[i] / (2.f * (1.f - A[i]));
3622 }
3623 }
3624 }
3625 src_r = qBound(0.f, C[0] * 255.f, 255.f);
3626 src_g = qBound(0.f, C[1] * 255.f, 255.f);
3627 src_b = qBound(0.f, C[2] * 255.f, 255.f);
3628 } break;
3629 default:
3630 qCWarning(XCFPLUGIN) << "Unhandled mode" << layer.mode;
3631 return false;
3632 }
3633
3634 src_a = INT_MULT(src_a, layer.opacity);
3635
3636 // Apply the mask (if any)
3637
3638 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3639 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3640 }
3641
3642 uchar new_r;
3643 uchar new_g;
3644 uchar new_b;
3645 uchar new_a;
3646 new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
3647
3648 const float src_ratio = new_a == 0 ? 1.0 : (float)src_a / new_a;
3649 float dst_ratio = 1.0 - src_ratio;
3650
3651 new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
3652 new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
3653 new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
3654
3655 if (!modeAffectsSourceAlpha(layer.mode)) {
3656 new_a = dst_a;
3657 }
3658
3659 image.setPixel(m, n, qRgba(new_r, new_g, new_b, new_a));
3660 return true;
3661}
3662
3663/*!
3664 * Merge a Gray pixel from the layer to the Gray image. Straight-forward.
3665 * \param layer source layer.
3666 * \param i x tile index.
3667 * \param j y tile index.
3668 * \param k x pixel index of tile i,j.
3669 * \param l y pixel index of tile i,j.
3670 * \param image destination image.
3671 * \param m x pixel of destination image.
3672 * \param n y pixel of destination image.
3673 */
3674bool XCFImageFormat::mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3675{
3676 int src = layer.image_tiles[j][i].pixelIndex(k, l);
3677 image.setPixel(m, n, src);
3678 return true;
3679}
3680
3681/*!
3682 * Merge a GrayA pixel from the layer to the Gray image. Straight-forward.
3683 * \param layer source layer.
3684 * \param i x tile index.
3685 * \param j y tile index.
3686 * \param k x pixel index of tile i,j.
3687 * \param l y pixel index of tile i,j.
3688 * \param image destination image.
3689 * \param m x pixel of destination image.
3690 * \param n y pixel of destination image.
3691 */
3692bool XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3693{
3694 int src = qGray(layer.image_tiles[j][i].pixel(k, l));
3695 int dst = image.pixelIndex(m, n);
3696
3697 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
3698
3699 if (!src_a) {
3700 return false; // nothing to merge
3701 }
3702
3703 switch (layer.mode) {
3704 case GIMP_LAYER_MODE_MULTIPLY:
3705 case GIMP_LAYER_MODE_MULTIPLY_LEGACY: {
3706 src = INT_MULT(src, dst);
3707 } break;
3708 case GIMP_LAYER_MODE_DIVIDE:
3709 case GIMP_LAYER_MODE_DIVIDE_LEGACY: {
3710 src = qMin((dst * 256) / (1 + src), 255);
3711 } break;
3712 case GIMP_LAYER_MODE_SCREEN:
3713 case GIMP_LAYER_MODE_SCREEN_LEGACY: {
3714 src = 255 - INT_MULT(255 - dst, 255 - src);
3715 } break;
3716 case GIMP_LAYER_MODE_OVERLAY:
3717 case GIMP_LAYER_MODE_OVERLAY_LEGACY: {
3718 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
3719 } break;
3720 case GIMP_LAYER_MODE_DIFFERENCE:
3721 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY: {
3722 src = dst > src ? dst - src : src - dst;
3723 } break;
3724 case GIMP_LAYER_MODE_ADDITION:
3725 case GIMP_LAYER_MODE_ADDITION_LEGACY: {
3726 src = add_lut(dst, src);
3727 } break;
3728 case GIMP_LAYER_MODE_SUBTRACT:
3729 case GIMP_LAYER_MODE_SUBTRACT_LEGACY: {
3730 src = dst > src ? dst - src : 0;
3731 } break;
3732 case GIMP_LAYER_MODE_DARKEN_ONLY:
3733 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY: {
3734 src = dst < src ? dst : src;
3735 } break;
3736 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3737 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY: {
3738 src = dst < src ? src : dst;
3739 } break;
3740 case GIMP_LAYER_MODE_DODGE:
3741 case GIMP_LAYER_MODE_DODGE_LEGACY: {
3742 uint tmp = dst << 8;
3743 tmp /= 256 - src;
3744 src = (uchar)qMin(tmp, 255u);
3745 } break;
3746 case GIMP_LAYER_MODE_BURN:
3747 case GIMP_LAYER_MODE_BURN_LEGACY: {
3748 uint tmp = (255 - dst) << 8;
3749 tmp /= src + 1;
3750 src = (uchar)qMin(tmp, 255u);
3751 src = 255 - src;
3752 } break;
3753 case GIMP_LAYER_MODE_HARDLIGHT:
3754 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
3755 uint tmp;
3756 if (src > 128) {
3757 tmp = ((int)255 - dst) * ((int)255 - ((src - 128) << 1));
3758 src = (uchar)qMin(255 - (tmp >> 8), 255u);
3759 } else {
3760 tmp = (int)dst * ((int)src << 1);
3761 src = (uchar)qMin(tmp >> 8, 255u);
3762 }
3763 } break;
3764 case GIMP_LAYER_MODE_SOFTLIGHT:
3765 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
3766 uint tmpS;
3767 uint tmpM;
3768
3769 tmpM = INT_MULT(dst, src);
3770 tmpS = 255 - INT_MULT((255 - dst), (255 - src));
3771 src = INT_MULT((255 - dst), tmpM) + INT_MULT(dst, tmpS);
3772
3773 } break;
3774 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3775 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
3776 int tmp;
3777
3778 tmp = dst - src + 128;
3779 tmp = qMin(tmp, 255);
3780 tmp = qMax(tmp, 0);
3781
3782 src = (uchar)tmp;
3783 } break;
3784 case GIMP_LAYER_MODE_GRAIN_MERGE:
3785 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
3786 int tmp;
3787
3788 tmp = dst + src - 128;
3789 tmp = qMin(tmp, 255);
3790 tmp = qMax(tmp, 0);
3791
3792 src = (uchar)tmp;
3793 } break;
3794 default:
3795 qCWarning(XCFPLUGIN) << "Unhandled mode" << layer.mode;
3796 return false;
3797 }
3798
3799 src_a = INT_MULT(src_a, layer.opacity);
3800
3801 // Apply the mask (if any)
3802
3803 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3804 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3805 }
3806
3807 uchar new_a = OPAQUE_OPACITY;
3808
3809 const float src_ratio = new_a == 0 ? 1.0 : (float)src_a / new_a;
3810 float dst_ratio = 1.0 - src_ratio;
3811
3812 uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
3813
3814 image.setPixel(m, n, new_g);
3815 return true;
3816}
3817
3818/*!
3819 * Merge a Gray pixel from the layer to an RGB image. Straight-forward.
3820 * The only thing this has to take account of is the opacity of the
3821 * layer. Evidently, the GIMP exporter itself does not actually do this.
3822 * \param layer source layer.
3823 * \param i x tile index.
3824 * \param j y tile index.
3825 * \param k x pixel index of tile i,j.
3826 * \param l y pixel index of tile i,j.
3827 * \param image destination image.
3828 * \param m x pixel of destination image.
3829 * \param n y pixel of destination image.
3830 */
3831bool XCFImageFormat::mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3832{
3833 QRgb src = layer.image_tiles[j][i].pixel(k, l);
3834 uchar src_a = layer.opacity;
3835 image.setPixel(m, n, qRgba(src, src_a));
3836 return true;
3837}
3838
3839/*!
3840 * Merge a GrayA pixel from the layer to an RGB image. Straight-forward.
3841 * The only thing this has to take account of is the opacity of the
3842 * layer. Evidently, the GIMP exporter itself does not actually do this.
3843 * \param layer source layer.
3844 * \param i x tile index.
3845 * \param j y tile index.
3846 * \param k x pixel index of tile i,j.
3847 * \param l y pixel index of tile i,j.
3848 * \param image destination image.
3849 * \param m x pixel of destination image.
3850 * \param n y pixel of destination image.
3851 */
3852bool XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
3853{
3854 int src = qGray(layer.image_tiles[j][i].pixel(k, l));
3855 int dst = qGray(image.pixel(m, n));
3856
3857 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
3858 uchar dst_a = qAlpha(image.pixel(m, n));
3859
3860 if (!src_a) {
3861 return false; // nothing to merge
3862 }
3863
3864 switch (layer.mode) {
3865 case GIMP_LAYER_MODE_NORMAL:
3866 case GIMP_LAYER_MODE_NORMAL_LEGACY:
3867 break;
3868 case GIMP_LAYER_MODE_MULTIPLY:
3869 case GIMP_LAYER_MODE_MULTIPLY_LEGACY: {
3870 src = INT_MULT(src, dst);
3871 src_a = qMin(src_a, dst_a);
3872 } break;
3873 case GIMP_LAYER_MODE_DIVIDE:
3874 case GIMP_LAYER_MODE_DIVIDE_LEGACY: {
3875 src = qMin((dst * 256) / (1 + src), 255);
3876 src_a = qMin(src_a, dst_a);
3877 } break;
3878 case GIMP_LAYER_MODE_SCREEN:
3879 case GIMP_LAYER_MODE_SCREEN_LEGACY: {
3880 src = 255 - INT_MULT(255 - dst, 255 - src);
3881 src_a = qMin(src_a, dst_a);
3882 } break;
3883 case GIMP_LAYER_MODE_OVERLAY:
3884 case GIMP_LAYER_MODE_OVERLAY_LEGACY: {
3885 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
3886 src_a = qMin(src_a, dst_a);
3887 } break;
3888 case GIMP_LAYER_MODE_DIFFERENCE:
3889 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY: {
3890 src = dst > src ? dst - src : src - dst;
3891 src_a = qMin(src_a, dst_a);
3892 } break;
3893 case GIMP_LAYER_MODE_ADDITION:
3894 case GIMP_LAYER_MODE_ADDITION_LEGACY: {
3895 src = add_lut(dst, src);
3896 src_a = qMin(src_a, dst_a);
3897 } break;
3898 case GIMP_LAYER_MODE_SUBTRACT:
3899 case GIMP_LAYER_MODE_SUBTRACT_LEGACY: {
3900 src = dst > src ? dst - src : 0;
3901 src_a = qMin(src_a, dst_a);
3902 } break;
3903 case GIMP_LAYER_MODE_DARKEN_ONLY:
3904 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY: {
3905 src = dst < src ? dst : src;
3906 src_a = qMin(src_a, dst_a);
3907 } break;
3908 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
3909 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY: {
3910 src = dst < src ? src : dst;
3911 src_a = qMin(src_a, dst_a);
3912 } break;
3913 case GIMP_LAYER_MODE_DODGE:
3914 case GIMP_LAYER_MODE_DODGE_LEGACY: {
3915 uint tmp = dst << 8;
3916 tmp /= 256 - src;
3917 src = (uchar)qMin(tmp, 255u);
3918 src_a = qMin(src_a, dst_a);
3919 } break;
3920 case GIMP_LAYER_MODE_BURN:
3921 case GIMP_LAYER_MODE_BURN_LEGACY: {
3922 uint tmp = (255 - dst) << 8;
3923 tmp /= src + 1;
3924 src = (uchar)qMin(tmp, 255u);
3925 src = 255 - src;
3926 src_a = qMin(src_a, dst_a);
3927 } break;
3928 case GIMP_LAYER_MODE_HARDLIGHT:
3929 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY: {
3930 uint tmp;
3931 if (src > 128) {
3932 tmp = ((int)255 - dst) * ((int)255 - ((src - 128) << 1));
3933 src = (uchar)qMin(255 - (tmp >> 8), 255u);
3934 } else {
3935 tmp = (int)dst * ((int)src << 1);
3936 src = (uchar)qMin(tmp >> 8, 255u);
3937 }
3938 src_a = qMin(src_a, dst_a);
3939 } break;
3940 case GIMP_LAYER_MODE_SOFTLIGHT:
3941 case GIMP_LAYER_MODE_SOFTLIGHT_LEGACY: {
3942 uint tmpS;
3943 uint tmpM;
3944
3945 tmpM = INT_MULT(dst, src);
3946 tmpS = 255 - INT_MULT((255 - dst), (255 - src));
3947 src = INT_MULT((255 - dst), tmpM) + INT_MULT(dst, tmpS);
3948
3949 src_a = qMin(src_a, dst_a);
3950 } break;
3951 case GIMP_LAYER_MODE_GRAIN_EXTRACT:
3952 case GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY: {
3953 int tmp;
3954
3955 tmp = dst - src + 128;
3956 tmp = qMin(tmp, 255);
3957 tmp = qMax(tmp, 0);
3958
3959 src = (uchar)tmp;
3960 src_a = qMin(src_a, dst_a);
3961 } break;
3962 case GIMP_LAYER_MODE_GRAIN_MERGE:
3963 case GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY: {
3964 int tmp;
3965
3966 tmp = dst + src - 128;
3967 tmp = qMin(tmp, 255);
3968 tmp = qMax(tmp, 0);
3969
3970 src = (uchar)tmp;
3971 src_a = qMin(src_a, dst_a);
3972 } break;
3973 default:
3974 qCWarning(XCFPLUGIN) << "Unhandled mode" << layer.mode;
3975 return false;
3976 }
3977
3978 src_a = INT_MULT(src_a, layer.opacity);
3979
3980 // Apply the mask (if any)
3981 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
3982 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
3983 }
3984
3985 uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
3986
3987 const float src_ratio = new_a == 0 ? 1.0 : (float)src_a / new_a;
3988 float dst_ratio = 1.0 - src_ratio;
3989
3990 uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
3991
3992 if (!modeAffectsSourceAlpha(layer.mode)) {
3993 new_a = dst_a;
3994 }
3995
3996 image.setPixel(m, n, qRgba(new_g, new_g, new_g, new_a));
3997 return true;
3998}
3999
4000/*!
4001 * Merge an Indexed pixel from the layer to the Indexed image. Straight-forward.
4002 * \param layer source layer.
4003 * \param i x tile index.
4004 * \param j y tile index.
4005 * \param k x pixel index of tile i,j.
4006 * \param l y pixel index of tile i,j.
4007 * \param image destination image.
4008 * \param m x pixel of destination image.
4009 * \param n y pixel of destination image.
4010 */
4011bool XCFImageFormat::mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
4012{
4013 int src = layer.image_tiles[j][i].pixelIndex(k, l);
4014 image.setPixel(m, n, src);
4015 return true;
4016}
4017
4018/*!
4019 * Merge an IndexedA pixel from the layer to the Indexed image. Straight-forward.
4020 * \param layer source layer.
4021 * \param i x tile index.
4022 * \param j y tile index.
4023 * \param k x pixel index of tile i,j.
4024 * \param l y pixel index of tile i,j.
4025 * \param image destination image.
4026 * \param m x pixel of destination image.
4027 * \param n y pixel of destination image.
4028 */
4029bool XCFImageFormat::mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
4030{
4031 uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
4032 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
4033 src_a = INT_MULT(src_a, layer.opacity);
4034
4035 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
4036 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
4037 }
4038
4039 if (src_a > 127) {
4040 src++;
4041 image.setPixel(m, n, src);
4042 }
4043 return true;
4044}
4045
4046/*!
4047 * Merge an IndexedA pixel from the layer to an RGB image. Straight-forward.
4048 * The only thing this has to take account of is the opacity of the
4049 * layer. Evidently, the GIMP exporter itself does not actually do this.
4050 * \param layer source layer.
4051 * \param i x tile index.
4052 * \param j y tile index.
4053 * \param k x pixel index of tile i,j.
4054 * \param l y pixel index of tile i,j.
4055 * \param image destination image.
4056 * \param m x pixel of destination image.
4057 * \param n y pixel of destination image.
4058 */
4059bool XCFImageFormat::mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l, QImage &image, int m, int n)
4060{
4061 QRgb src = layer.image_tiles[j][i].pixel(k, l);
4062 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
4063 src_a = INT_MULT(src_a, layer.opacity);
4064
4065 // Apply the mask (if any)
4066 if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j && layer.mask_tiles[j].size() > (int)i) {
4067 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
4068 }
4069
4070 // This is what appears in the GIMP window
4071 if (src_a <= 127) {
4072 src_a = 0;
4073 } else {
4074 src_a = OPAQUE_OPACITY;
4075 }
4076
4077 image.setPixel(m, n, qRgba(src, src_a));
4078 return true;
4079}
4080
4081/*!
4082 * Dissolving pixels: pick a random number between 0 and 255. If the pixel's
4083 * alpha is less than that, make it transparent.
4084 * \param image the image tile to dissolve.
4085 * \param x the global x position of the tile.
4086 * \param y the global y position of the tile.
4087 */
4088void XCFImageFormat::dissolveRGBPixels(QImage &image, int x, int y)
4089{
4090 // The apparently spurious rand() calls are to wind the random
4091 // numbers up to the same point for each tile.
4092
4093 for (int l = 0; l < image.height(); l++) {
4094 unsigned int next = randomTable.values[(l + y) % RANDOM_TABLE_SIZE];
4095
4096 for (int k = 0; k < x; k++) {
4097 RandomTable::rand_r(&next);
4098 }
4099
4100 for (int k = 0; k < image.width(); k++) {
4101 int rand_val = RandomTable::rand_r(&next) & 0xff;
4102 QRgb pixel = image.pixel(k, l);
4103
4104 if (rand_val > qAlpha(pixel)) {
4105 image.setPixel(k, l, qRgba(pixel, 0));
4106 }
4107 }
4108 }
4109}
4110
4111/*!
4112 * Dissolving pixels: pick a random number between 0 and 255. If the pixel's
4113 * alpha is less than that, make it transparent. This routine works for
4114 * the GRAYA and INDEXEDA image types where the pixel alpha's are stored
4115 * separately from the pixel themselves.
4116 * \param image the alpha tile to dissolve.
4117 * \param x the global x position of the tile.
4118 * \param y the global y position of the tile.
4119 */
4120void XCFImageFormat::dissolveAlphaPixels(QImage &image, int x, int y)
4121{
4122 // The apparently spurious rand() calls are to wind the random
4123 // numbers up to the same point for each tile.
4124
4125 for (int l = 0; l < image.height(); l++) {
4126 unsigned int next = randomTable.values[(l + y) % RANDOM_TABLE_SIZE];
4127
4128 for (int k = 0; k < x; k++) {
4129 RandomTable::rand_r(&next);
4130 }
4131
4132 for (int k = 0; k < image.width(); k++) {
4133 int rand_val = RandomTable::rand_r(&next) & 0xff;
4134 uchar alpha = image.pixelIndex(k, l);
4135
4136 if (rand_val > alpha) {
4137 image.setPixel(k, l, 0);
4138 }
4139 }
4140 }
4141}
4142
4143///////////////////////////////////////////////////////////////////////////////
4144
4145XCFHandler::XCFHandler()
4146{
4147}
4148
4149bool XCFHandler::canRead() const
4150{
4151 if (canRead(device())) {
4152 setFormat("xcf");
4153 return true;
4154 }
4155 return false;
4156}
4157
4158bool XCFHandler::read(QImage *image)
4159{
4160 XCFImageFormat xcfif;
4161 auto ok = xcfif.readXCF(device(), image);
4162 m_imageSize = image->size();
4163 return ok;
4164}
4165
4166bool XCFHandler::write(const QImage &)
4167{
4168 return false;
4169}
4170
4171bool XCFHandler::supportsOption(ImageOption option) const
4172{
4173 if (option == QImageIOHandler::Size)
4174 return true;
4175 return false;
4176}
4177
4178QVariant XCFHandler::option(ImageOption option) const
4179{
4180 QVariant v;
4181
4182 if (option == QImageIOHandler::Size) {
4183 if (!m_imageSize.isEmpty()) {
4184 return m_imageSize;
4185 }
4186 /*
4187 * The image structure always starts at offset 0 in the XCF file.
4188 * byte[9] "gimp xcf " File type identification
4189 * byte[4] version XCF version
4190 * "file": version 0
4191 * "v001": version 1
4192 * "v002": version 2
4193 * "v003": version 3
4194 * byte 0 Zero marks the end of the version tag.
4195 * uint32 width Width of canvas
4196 * uint32 height Height of canvas
4197 */
4198 else if (auto d = device()) {
4199 // transactions works on both random and sequential devices
4200 d->startTransaction();
4201 auto ba9 = d->read(9); // "gimp xcf "
4202 auto ba5 = d->read(4+1); // version + null terminator
4203 auto ba = d->read(8); // width and height
4204 d->rollbackTransaction();
4205 if (ba9 == QByteArray("gimp xcf ") && ba5.size() == 5) {
4206 QDataStream ds(ba);
4207 quint32 width;
4208 ds >> width;
4209 quint32 height;
4210 ds >> height;
4211 if (ds.status() == QDataStream::Ok)
4212 v = QVariant::fromValue(QSize(width, height));
4213 }
4214 }
4215 }
4216
4217 return v;
4218}
4219
4220bool XCFHandler::canRead(QIODevice *device)
4221{
4222 if (!device) {
4223 qCDebug(XCFPLUGIN) << "XCFHandler::canRead() called with no device";
4224 return false;
4225 }
4226 if (device->isSequential()) {
4227 return false;
4228 }
4229
4230 const qint64 oldPos = device->pos();
4231
4232 QDataStream ds(device);
4233 XCFImageFormat::XCFImage::Header header;
4234 bool failed = !XCFImageFormat::readXCFHeader(ds, &header);
4235 ds.setDevice(nullptr);
4236
4237 device->seek(oldPos);
4238 if (failed) {
4239 return false;
4240 }
4241
4242 switch (header.precision) {
4243 case XCFImageFormat::GIMP_PRECISION_HALF_LINEAR:
4244 case XCFImageFormat::GIMP_PRECISION_HALF_NON_LINEAR:
4245 case XCFImageFormat::GIMP_PRECISION_HALF_PERCEPTUAL:
4246 case XCFImageFormat::GIMP_PRECISION_FLOAT_LINEAR:
4247 case XCFImageFormat::GIMP_PRECISION_FLOAT_NON_LINEAR:
4248 case XCFImageFormat::GIMP_PRECISION_FLOAT_PERCEPTUAL:
4249 case XCFImageFormat::GIMP_PRECISION_U8_LINEAR:
4250 case XCFImageFormat::GIMP_PRECISION_U8_NON_LINEAR:
4251 case XCFImageFormat::GIMP_PRECISION_U8_PERCEPTUAL:
4252 case XCFImageFormat::GIMP_PRECISION_U16_LINEAR:
4253 case XCFImageFormat::GIMP_PRECISION_U16_NON_LINEAR:
4254 case XCFImageFormat::GIMP_PRECISION_U16_PERCEPTUAL:
4255 case XCFImageFormat::GIMP_PRECISION_U32_LINEAR:
4256 case XCFImageFormat::GIMP_PRECISION_U32_NON_LINEAR:
4257 case XCFImageFormat::GIMP_PRECISION_U32_PERCEPTUAL:
4258 break;
4259 case XCFImageFormat::GIMP_PRECISION_DOUBLE_LINEAR:
4260 case XCFImageFormat::GIMP_PRECISION_DOUBLE_NON_LINEAR:
4261 case XCFImageFormat::GIMP_PRECISION_DOUBLE_PERCEPTUAL:
4262 default:
4263 qCDebug(XCFPLUGIN) << "unsupported precision" << header.precision;
4264 return false;
4265 }
4266
4267 return true;
4268}
4269
4270QImageIOPlugin::Capabilities XCFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
4271{
4272 if (format == "xcf") {
4273 return Capabilities(CanRead);
4274 }
4275 if (!format.isEmpty()) {
4276 return {};
4277 }
4278 if (!device->isOpen()) {
4279 return {};
4280 }
4281
4282 Capabilities cap;
4283 if (device->isReadable() && XCFHandler::canRead(device)) {
4284 cap |= CanRead;
4285 }
4286 return cap;
4287}
4288
4289QImageIOHandler *XCFPlugin::create(QIODevice *device, const QByteArray &format) const
4290{
4291 QImageIOHandler *handler = new XCFHandler;
4292 handler->setDevice(device);
4293 handler->setFormat(format);
4294 return handler;
4295}
4296
4297// Just so I can get enum values printed
4298#include "xcf.moc"
4299
4300#include "moc_xcf_p.cpp"
Type type(const QSqlDatabase &db)
QFlags< Capability > Capabilities
QStringView merge(QStringView lhs, QStringView rhs)
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 Apr 18 2025 12:16:52 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.