1#ifndef XCF_H
2#define XCF_H
3/*
4 * qxcfi.cpp: A Qt 3 plug-in for reading GIMP XCF image files
5 * Copyright (C) 2001 lignum Computing, Inc. <allen@lignumcomputing.com>
6 * Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org>
7 *
8 * This plug-in is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24
25#include <QtGui/QImageIOPlugin>
26#include <QtGui/QImage>
27#include <QtCore/QIODevice>
28#include <QtCore/QVector>
29
30#include "gimp.h"
31
32class XCFHandler : public QImageIOHandler
33{
34public:
35 XCFHandler();
36
37 bool canRead() const;
38 bool read(QImage *image);
39 bool write(const QImage &image);
40
41 QByteArray name() const;
42
43 static bool canRead(QIODevice *device);
44};
45
46const float INCHESPERMETER = (100.0f / 2.54f);
47
48/*!
49 * Each layer in an XCF file is stored as a matrix of
50 * 64-pixel by 64-pixel images. The GIMP has a sophisticated
51 * method of handling very large images as well as implementing
52 * parallel processing on a tile-by-tile basis. Here, though,
53 * we just read them in en-masse and store them in a matrix.
54 */
55typedef QVector<QVector<QImage> > Tiles;
56
57
58
59class XCFImageFormat {
60public:
61 XCFImageFormat();
62 bool readXCF(QIODevice *device, QImage *image);
63
64
65private:
66 /*!
67 * Each GIMP image is composed of one or more layers. A layer can
68 * be one of any three basic types: RGB, grayscale or indexed. With an
69 * optional alpha channel, there are six possible types altogether.
70 *
71 * Note: there is only ever one instance of this structure. The
72 * layer info is discarded after it is merged into the final QImage.
73 */
74 class Layer {
75 public:
76 quint32 width; //!< Width of the layer
77 quint32 height; //!< Height of the layer
78 qint32 type; //!< Type of the layer (GimpImageType)
79 char* name; //!< Name of the layer
80 quint32 hierarchy_offset; //!< File position of Tile hierarchy
81 quint32 mask_offset; //!< File position of mask image
82
83 uint nrows; //!< Number of rows of tiles (y direction)
84 uint ncols; //!< Number of columns of tiles (x direction)
85
86 Tiles image_tiles; //!< The basic image
87 //! For Grayscale and Indexed images, the alpha channel is stored
88 //! separately (in this data structure, anyway).
89 Tiles alpha_tiles;
90 Tiles mask_tiles; //!< The layer mask (optional)
91
92 //! Additional information about a layer mask.
93 struct {
94 quint32 opacity;
95 quint32 visible;
96 quint32 show_masked;
97 uchar red, green, blue;
98 quint32 tattoo;
99 } mask_channel;
100
101 bool active; //!< Is this layer the active layer?
102 quint32 opacity; //!< The opacity of the layer
103 quint32 visible; //!< Is the layer visible?
104 quint32 linked; //!< Is this layer linked (geometrically)
105 quint32 preserve_transparency; //!< Preserve alpha when drawing on layer?
106 quint32 apply_mask; //!< Apply the layer mask?
107 quint32 edit_mask; //!< Is the layer mask the being edited?
108 quint32 show_mask; //!< Show the layer mask rather than the image?
109 qint32 x_offset; //!< x offset of the layer relative to the image
110 qint32 y_offset; //!< y offset of the layer relative to the image
111 quint32 mode; //!< Combining mode of layer (LayerModeEffects)
112 quint32 tattoo; //!< (unique identifier?)
113
114 //! As each tile is read from the file, it is buffered here.
115 uchar tile[TILE_WIDTH * TILE_HEIGHT * sizeof(QRgb)];
116
117 //! The data from tile buffer is copied to the Tile by this
118 //! method. Depending on the type of the tile (RGB, Grayscale,
119 //! Indexed) and use (image or mask), the bytes in the buffer are
120 //! copied in different ways.
121 void (*assignBytes)(Layer& layer, uint i, uint j);
122
123 Layer(void) : name(0) {}
124 ~Layer(void) { delete[] name; }
125 };
126
127
128 /*!
129 * The in-memory representation of the XCF Image. It contains a few
130 * metadata items, but is mostly a container for the layer information.
131 */
132 class XCFImage {
133 public:
134 quint32 width; //!< width of the XCF image
135 quint32 height; //!< height of the XCF image
136 qint32 type; //!< type of the XCF image (GimpImageBaseType)
137
138 quint8 compression; //!< tile compression method (CompressionType)
139 float x_resolution; //!< x resolution in dots per inch
140 float y_resolution; //!< y resolution in dots per inch
141 qint32 tattoo; //!< (unique identifier?)
142 quint32 unit; //!< Units of The GIMP (inch, mm, pica, etc...)
143 qint32 num_colors; //!< number of colors in an indexed image
144 QVector<QRgb> palette; //!< indexed image color palette
145
146 int num_layers; //!< number of layers
147 Layer layer; //!< most recently read layer
148
149 bool initialized; //!< Is the QImage initialized?
150 QImage image; //!< final QImage
151
152 XCFImage(void) : initialized(false) {}
153 };
154
155
156 //! In layer DISSOLVE mode, a random number is chosen to compare to a
157 //! pixel's alpha. If the alpha is greater than the random number, the
158 //! pixel is drawn. This table merely contains the random number seeds
159 //! for each ROW of an image. Therefore, the random numbers chosen
160 //! are consistent from run to run.
161 static int random_table[RANDOM_TABLE_SIZE];
162 static bool random_table_initialized;
163
164 //! This table is used as a shared grayscale ramp to be set on grayscale
165 //! images. This is because Qt does not differentiate between indexed and
166 //! grayscale images.
167 static QVector<QRgb> grayTable;
168
169 //! This table provides the add_pixel saturation values (i.e. 250 + 250 = 255).
170 //static int add_lut[256][256]; - this is so lame waste of 256k of memory
171 static int add_lut( int, int );
172
173 //! The bottom-most layer is copied into the final QImage by this
174 //! routine.
175 typedef void (*PixelCopyOperation)(Layer& layer, uint i, uint j, int k, int l,
176 QImage& image, int m, int n);
177
178 //! Higher layers are merged into the final QImage by this routine.
179 typedef void (*PixelMergeOperation)(Layer& layer, uint i, uint j, int k, int l,
180 QImage& image, int m, int n);
181
182 //! Layer mode static data.
183 typedef struct {
184 bool affect_alpha; //!< Does this mode affect the source alpha?
185 } LayerModes;
186
187 //! Array of layer mode structures for the modes described by
188 //! LayerModeEffects.
189 static const LayerModes layer_modes[];
190
191 bool loadImageProperties(QDataStream& xcf_io, XCFImage& image);
192 bool loadProperty(QDataStream& xcf_io, PropType& type, QByteArray& bytes);
193 bool loadLayer(QDataStream& xcf_io, XCFImage& xcf_image);
194 bool loadLayerProperties(QDataStream& xcf_io, Layer& layer);
195 bool composeTiles(XCFImage& xcf_image);
196 void setGrayPalette(QImage& image);
197 void setPalette(XCFImage& xcf_image, QImage& image);
198 static void assignImageBytes(Layer& layer, uint i, uint j);
199 bool loadHierarchy(QDataStream& xcf_io, Layer& layer);
200 bool loadLevel(QDataStream& xcf_io, Layer& layer, qint32 bpp);
201 static void assignMaskBytes(Layer& layer, uint i, uint j);
202 bool loadMask(QDataStream& xcf_io, Layer& layer);
203 bool loadChannelProperties(QDataStream& xcf_io, Layer& layer);
204 bool initializeImage(XCFImage& xcf_image);
205 bool loadTileRLE(QDataStream& xcf_io, uchar* tile, int size,
206 int data_length, qint32 bpp);
207
208 static void copyLayerToImage(XCFImage& xcf_image);
209 static void copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
210 QImage& image, int m, int n);
211 static void copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
212 QImage& image, int m, int n);
213 static void copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
214 QImage& image, int m, int n);
215 static void copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
216 QImage& image, int m, int n);
217 static void copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
218 QImage& image, int m, int n);
219 static void copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
220 QImage& image, int m, int n);
221 static void copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
222 QImage& image, int m, int n);
223
224 static void mergeLayerIntoImage(XCFImage& xcf_image);
225 static void mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
226 QImage& image, int m, int n);
227 static void mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
228 QImage& image, int m, int n);
229 static void mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
230 QImage& image, int m, int n);
231 static void mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
232 QImage& image, int m, int n);
233 static void mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
234 QImage& image, int m, int n);
235 static void mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
236 QImage& image, int m, int n);
237 static void mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
238 QImage& image, int m, int n);
239 static void mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
240 QImage& image, int m, int n);
241
242 static void initializeRandomTable();
243 static void dissolveRGBPixels(QImage& image, int x, int y);
244 static void dissolveAlphaPixels(QImage& image, int x, int y);
245};
246
247#endif
248