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

KDE's Doxygen guidelines are available online.