You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
8.8 KiB
232 lines
8.8 KiB
#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 <qimage.h>
|
|
#include <qiodevice.h>
|
|
#include <qvaluestack.h>
|
|
#include <qvaluevector.h>
|
|
|
|
#include "gimp.h"
|
|
|
|
|
|
extern "C" {
|
|
void kimgio_xcf_read(QImageIO *);
|
|
void kimgio_xcf_write(QImageIO *);
|
|
}
|
|
|
|
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 QValueVector<QValueVector<QImage> > Tiles;
|
|
|
|
|
|
|
|
class XCFImageFormat {
|
|
public:
|
|
XCFImageFormat();
|
|
void readXCF(QImageIO* 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 QImage.
|
|
*/
|
|
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
|
|
QValueVector<QRgb> palette; //!< indexed image color palette
|
|
|
|
int num_layers; //!< number of layers
|
|
Layer layer; //!< most recently read layer
|
|
|
|
bool initialized; //!< Is the QImage initialized?
|
|
QImage 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 QImage by this
|
|
//! routine.
|
|
typedef void (*PixelCopyOperation)(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
|
|
//! Higher layers are merged into the the final QImage by this routine.
|
|
typedef void (*PixelMergeOperation)(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& 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(QDataStream& xcf_io, XCFImage& image);
|
|
bool loadProperty(QDataStream& xcf_io, PropType& type, QByteArray& bytes);
|
|
bool loadLayer(QDataStream& xcf_io, XCFImage& xcf_image);
|
|
bool loadLayerProperties(QDataStream& xcf_io, Layer& layer);
|
|
bool composeTiles(XCFImage& xcf_image);
|
|
void setGrayPalette(QImage& image);
|
|
void setPalette(XCFImage& xcf_image, QImage& image);
|
|
static void assignImageBytes(Layer& layer, uint i, uint j);
|
|
bool loadHierarchy(QDataStream& xcf_io, Layer& layer);
|
|
bool loadLevel(QDataStream& xcf_io, Layer& layer, Q_INT32 bpp);
|
|
static void assignMaskBytes(Layer& layer, uint i, uint j);
|
|
bool loadMask(QDataStream& xcf_io, Layer& layer);
|
|
bool loadChannelProperties(QDataStream& xcf_io, Layer& layer);
|
|
bool initializeImage(XCFImage& xcf_image);
|
|
bool loadTileRLE(QDataStream& 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,
|
|
QImage& image, int m, int n);
|
|
|
|
static void copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
|
|
static void mergeLayerIntoImage(XCFImage& xcf_image);
|
|
static void mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
static void mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
|
|
QImage& image, int m, int n);
|
|
|
|
static void dissolveRGBPixels(QImage& image, int x, int y);
|
|
static void dissolveAlphaPixels(QImage& image, int x, int y);
|
|
};
|
|
|
|
#endif
|