summaryrefslogtreecommitdiffstats
path: root/kimgio/xcf.h
blob: 3e92f27c22b0740f7ef4a15e174745b8a325a162 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#ifndef XCF_H
#define XCF_H
/*
 * qxcfi.cpp: A Qt 3 plug-in for reading GIMP XCF image files
 * Copyright (C) 2001 lignum Computing, Inc. <allen@lignumcomputing.com>
 * Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org>
 *
 * This plug-in is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <tqimage.h>
#include <tqiodevice.h>
#include <tqvaluestack.h>
#include <tqvaluevector.h>

#include "gimp.h"


extern "C" {
void kimgio_xcf_read(TQImageIO *);
void kimgio_xcf_write(TQImageIO *);
}

const float INCHESPERMETER = (100.0 / 2.54);

/*!
 * Each layer in an XCF file is stored as a matrix of
 * 64-pixel by 64-pixel images. The GIMP has a sophisticated
 * method of handling very large images as well as implementing
 * parallel processing on a tile-by-tile basis. Here, though,
 * we just read them in en-masse and store them in a matrix.
 */
typedef TQValueVector<TQValueVector<TQImage> > Tiles;



class XCFImageFormat {
public:
	XCFImageFormat();
	void readXCF(TQImageIO* image_io);


private:
	/*!
	 * Each GIMP image is composed of one or more layers. A layer can
	 * be one of any three basic types: RGB, grayscale or indexed. With an
	 * optional alpha channel, there are six possible types altogether.
	 *
	 * Note: there is only ever one instance of this structure. The
	 * layer info is discarded after it is merged into the final TQImage.
	 */
	class Layer {
	public:
		Q_UINT32 width;			//!< Width of the layer
		Q_UINT32 height;		//!< Height of the layer
		Q_INT32 type;			//!< Type of the layer (GimpImageType)
		char* name;			//!< Name of the layer
		Q_UINT32 hierarchy_offset;	//!< File position of Tile hierarchy
		Q_UINT32 mask_offset;		//!< File position of mask image

		uint nrows;			//!< Number of rows of tiles (y direction)
		uint ncols;			//!< Number of columns of tiles (x direction)

		Tiles image_tiles;		//!< The basic image
		//! For Grayscale and Indexed images, the alpha channel is stored
		//! separately (in this data structure, anyway).
		Tiles alpha_tiles;
		Tiles mask_tiles;		//!< The layer mask (optional)

		//! Additional information about a layer mask.
		struct {
			Q_UINT32 opacity;
			Q_UINT32 visible;
			Q_UINT32 show_masked;
			uchar red, green, blue;
			Q_UINT32 tattoo;
		} mask_channel;

		bool active;			//!< Is this layer the active layer?
		Q_UINT32 opacity;		//!< The opacity of the layer
		Q_UINT32 visible;		//!< Is the layer visible?
		Q_UINT32 linked;		//!< Is this layer linked (geometrically)
		Q_UINT32 preserve_transparency; //!< Preserve alpha when drawing on layer?
		Q_UINT32 apply_mask;		//!< Apply the layer mask?
		Q_UINT32 edit_mask;		//!< Is the layer mask the being edited?
		Q_UINT32 show_mask;		//!< Show the layer mask rather than the image?
		Q_INT32 x_offset;		//!< x offset of the layer relative to the image
		Q_INT32 y_offset;		//!< y offset of the layer relative to the image
		Q_UINT32 mode;			//!< Combining mode of layer (LayerModeEffects)
		Q_UINT32 tattoo;		//!< (unique identifier?)

		//! As each tile is read from the file, it is buffered here.
		uchar tile[TILE_WIDTH * TILE_HEIGHT * sizeof(QRgb)];

		//! The data from tile buffer is copied to the Tile by this
		//! method.  Depending on the type of the tile (RGB, Grayscale,
		//! Indexed) and use (image or mask), the bytes in the buffer are
		//! copied in different ways.
		void (*assignBytes)(Layer& layer, uint i, uint j);

		Layer(void) : name(0) {}
		~Layer(void) { delete[] name; }
	};


	/*!
	 * The in-memory representation of the XCF Image. It contains a few
	 * metadata items, but is mostly a container for the layer information.
	 */
	class XCFImage {
	public:
		Q_UINT32 width;			//!< width of the XCF image
		Q_UINT32 height;		//!< height of the XCF image
		Q_INT32 type;			//!< type of the XCF image (GimpImageBaseType)

		Q_UINT8 compression;		//!< tile compression method (CompressionType)
		float x_resolution;		//!< x resolution in dots per inch
		float y_resolution;		//!< y resolution in dots per inch
		Q_INT32 tattoo;			//!< (unique identifier?)
		Q_UINT32 unit;			//!< Units of The GIMP (inch, mm, pica, etc...)
		Q_INT32 num_colors;		//!< number of colors in an indexed image
		TQValueVector<QRgb> palette;	//!< indexed image color palette

		int num_layers;			//!< number of layers
		Layer layer;			//!< most recently read layer

		bool initialized;		//!< Is the TQImage initialized?
		TQImage image;			//!< final QImage

		XCFImage(void) : initialized(false) {}
	};


	//! In layer DISSOLVE mode, a random number is chosen to compare to a
	//! pixel's alpha. If the alpha is greater than the random number, the
	//! pixel is drawn. This table merely contains the random number seeds
	//! for each ROW of an image. Therefore, the random numbers chosen
	//! are consistent from run to run.
	static int random_table[RANDOM_TABLE_SIZE];

	//! This table provides the add_pixel saturation values (i.e. 250 + 250 = 255).
	//static int add_lut[256][256]; - this is so lame waste of 256k of memory
	static int add_lut( int, int );

	//! The bottom-most layer is copied into the final TQImage by this
	//! routine.
	typedef void (*PixelCopyOperation)(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);

	//! Higher layers are merged into the the final TQImage by this routine.
	typedef void (*PixelMergeOperation)(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);

	//! Layer mode static data.
	typedef struct {
		bool affect_alpha;		//!< Does this mode affect the source alpha?
	} LayerModes;

	//! Array of layer mode structures for the modes described by
	//! LayerModeEffects.
	static const LayerModes layer_modes[];

	bool loadImageProperties(TQDataStream& xcf_io, XCFImage& image);
	bool loadProperty(TQDataStream& xcf_io, PropType& type, TQByteArray& bytes);
	bool loadLayer(TQDataStream& xcf_io, XCFImage& xcf_image);
	bool loadLayerProperties(TQDataStream& xcf_io, Layer& layer);
	bool composeTiles(XCFImage& xcf_image);
	void setGrayPalette(TQImage& image);
	void setPalette(XCFImage& xcf_image, TQImage& image);
	static void assignImageBytes(Layer& layer, uint i, uint j);
	bool loadHierarchy(TQDataStream& xcf_io, Layer& layer);
	bool loadLevel(TQDataStream& xcf_io, Layer& layer, Q_INT32 bpp);
	static void assignMaskBytes(Layer& layer, uint i, uint j);
	bool loadMask(TQDataStream& xcf_io, Layer& layer);
	bool loadChannelProperties(TQDataStream& xcf_io, Layer& layer);
	bool initializeImage(XCFImage& xcf_image);
	bool loadTileRLE(TQDataStream& xcf_io, uchar* tile, int size,
			int data_length, Q_INT32 bpp);
	static void copyLayerToImage(XCFImage& xcf_image);
	static void copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);

	static void copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);

	static void mergeLayerIntoImage(XCFImage& xcf_image);
	static void mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);
	static void mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
			TQImage& image, int m, int n);

	static void dissolveRGBPixels(TQImage& image, int x, int y);
	static void dissolveAlphaPixels(TQImage& image, int x, int y);
};

#endif