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>
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.
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.
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
25 #include <QtGui/QImageIOPlugin>
26 #include <QtGui/QImage>
27 #include <QtCore/QIODevice>
28 #include <QtCore/QVector>
32 class XCFHandler
: public QImageIOHandler
38 bool read(QImage
*image
);
39 bool write(const QImage
&image
);
41 QByteArray
name() const;
43 static bool canRead(QIODevice
*device
);
46 const float INCHESPERMETER
= (100.0f
/ 2.54f
);
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.
55 typedef QVector
<QVector
<QImage
> > Tiles
;
59 class XCFImageFormat
{
62 bool readXCF(QIODevice
*device
, QImage
*image
);
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.
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.
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
83 uint nrows
; //!< Number of rows of tiles (y direction)
84 uint ncols
; //!< Number of columns of tiles (x direction)
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).
90 Tiles mask_tiles
; //!< The layer mask (optional)
92 //! Additional information about a layer mask.
97 uchar red
, green
, blue
;
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?)
114 //! As each tile is read from the file, it is buffered here.
115 uchar tile
[TILE_WIDTH
* TILE_HEIGHT
* sizeof(QRgb
)];
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
);
123 Layer(void) : name(0) {}
124 ~Layer(void) { delete[] name
; }
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.
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)
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
146 int num_layers
; //!< number of layers
147 Layer layer
; //!< most recently read layer
149 bool initialized
; //!< Is the QImage initialized?
150 QImage image
; //!< final QImage
152 XCFImage(void) : initialized(false) {}
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
];
163 //! This table provides the add_pixel saturation values (i.e. 250 + 250 = 255).
164 //static int add_lut[256][256]; - this is so lame waste of 256k of memory
165 static int add_lut( int, int );
167 //! The bottom-most layer is copied into the final QImage by this
169 typedef void (*PixelCopyOperation
)(Layer
& layer
, uint i
, uint j
, int k
, int l
,
170 QImage
& image
, int m
, int n
);
172 //! Higher layers are merged into the final QImage by this routine.
173 typedef void (*PixelMergeOperation
)(Layer
& layer
, uint i
, uint j
, int k
, int l
,
174 QImage
& image
, int m
, int n
);
176 //! Layer mode static data.
178 bool affect_alpha
; //!< Does this mode affect the source alpha?
181 //! Array of layer mode structures for the modes described by
182 //! LayerModeEffects.
183 static const LayerModes layer_modes
[];
185 bool loadImageProperties(QDataStream
& xcf_io
, XCFImage
& image
);
186 bool loadProperty(QDataStream
& xcf_io
, PropType
& type
, QByteArray
& bytes
);
187 bool loadLayer(QDataStream
& xcf_io
, XCFImage
& xcf_image
);
188 bool loadLayerProperties(QDataStream
& xcf_io
, Layer
& layer
);
189 bool composeTiles(XCFImage
& xcf_image
);
190 void setGrayPalette(QImage
& image
);
191 void setPalette(XCFImage
& xcf_image
, QImage
& image
);
192 static void assignImageBytes(Layer
& layer
, uint i
, uint j
);
193 bool loadHierarchy(QDataStream
& xcf_io
, Layer
& layer
);
194 bool loadLevel(QDataStream
& xcf_io
, Layer
& layer
, qint32 bpp
);
195 static void assignMaskBytes(Layer
& layer
, uint i
, uint j
);
196 bool loadMask(QDataStream
& xcf_io
, Layer
& layer
);
197 bool loadChannelProperties(QDataStream
& xcf_io
, Layer
& layer
);
198 bool initializeImage(XCFImage
& xcf_image
);
199 bool loadTileRLE(QDataStream
& xcf_io
, uchar
* tile
, int size
,
200 int data_length
, qint32 bpp
);
201 static void copyLayerToImage(XCFImage
& xcf_image
);
202 static void copyRGBToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
203 QImage
& image
, int m
, int n
);
205 static void copyGrayToGray(Layer
& layer
, uint i
, uint j
, int k
, int l
,
206 QImage
& image
, int m
, int n
);
207 static void copyGrayToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
208 QImage
& image
, int m
, int n
);
209 static void copyGrayAToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
210 QImage
& image
, int m
, int n
);
211 static void copyIndexedToIndexed(Layer
& layer
, uint i
, uint j
, int k
, int l
,
212 QImage
& image
, int m
, int n
);
213 static void copyIndexedAToIndexed(Layer
& layer
, uint i
, uint j
, int k
, int l
,
214 QImage
& image
, int m
, int n
);
215 static void copyIndexedAToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
216 QImage
& image
, int m
, int n
);
218 static void mergeLayerIntoImage(XCFImage
& xcf_image
);
219 static void mergeRGBToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
220 QImage
& image
, int m
, int n
);
221 static void mergeGrayToGray(Layer
& layer
, uint i
, uint j
, int k
, int l
,
222 QImage
& image
, int m
, int n
);
223 static void mergeGrayAToGray(Layer
& layer
, uint i
, uint j
, int k
, int l
,
224 QImage
& image
, int m
, int n
);
225 static void mergeGrayToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
226 QImage
& image
, int m
, int n
);
227 static void mergeGrayAToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
228 QImage
& image
, int m
, int n
);
229 static void mergeIndexedToIndexed(Layer
& layer
, uint i
, uint j
, int k
, int l
,
230 QImage
& image
, int m
, int n
);
231 static void mergeIndexedAToIndexed(Layer
& layer
, uint i
, uint j
, int k
, int l
,
232 QImage
& image
, int m
, int n
);
233 static void mergeIndexedAToRGB(Layer
& layer
, uint i
, uint j
, int k
, int l
,
234 QImage
& image
, int m
, int n
);
236 static void dissolveRGBPixels(QImage
& image
, int x
, int y
);
237 static void dissolveAlphaPixels(QImage
& image
, int x
, int y
);