kdelibs/kimgio/xcf.h
2014-11-13 01:04:59 +02:00

247 lines
9.3 KiB
C++

#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 <QtGui/QImageIOPlugin>
#include <QtGui/QImage>
#include <QtCore/QIODevice>
#include <QtCore/QVector>
#include "gimp.h"
class XCFHandler : public QImageIOHandler
{
public:
XCFHandler();
bool canRead() const;
bool read(QImage *image);
bool write(const QImage &image);
QByteArray name() const;
static bool canRead(QIODevice *device);
};
const float INCHESPERMETER = (100.0f / 2.54f);
/*!
* 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 QVector<QVector<QImage> > Tiles;
class XCFImageFormat {
public:
XCFImageFormat();
bool readXCF(QIODevice *device, QImage *image);
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:
quint32 width; //!< Width of the layer
quint32 height; //!< Height of the layer
qint32 type; //!< Type of the layer (GimpImageType)
char* name; //!< Name of the layer
quint32 hierarchy_offset; //!< File position of Tile hierarchy
quint32 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 {
quint32 opacity;
quint32 visible;
quint32 show_masked;
uchar red, green, blue;
quint32 tattoo;
} mask_channel;
bool active; //!< Is this layer the active layer?
quint32 opacity; //!< The opacity of the layer
quint32 visible; //!< Is the layer visible?
quint32 linked; //!< Is this layer linked (geometrically)
quint32 preserve_transparency; //!< Preserve alpha when drawing on layer?
quint32 apply_mask; //!< Apply the layer mask?
quint32 edit_mask; //!< Is the layer mask the being edited?
quint32 show_mask; //!< Show the layer mask rather than the image?
qint32 x_offset; //!< x offset of the layer relative to the image
qint32 y_offset; //!< y offset of the layer relative to the image
quint32 mode; //!< Combining mode of layer (LayerModeEffects)
quint32 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:
quint32 width; //!< width of the XCF image
quint32 height; //!< height of the XCF image
qint32 type; //!< type of the XCF image (GimpImageBaseType)
quint8 compression; //!< tile compression method (CompressionType)
float x_resolution; //!< x resolution in dots per inch
float y_resolution; //!< y resolution in dots per inch
qint32 tattoo; //!< (unique identifier?)
quint32 unit; //!< Units of The GIMP (inch, mm, pica, etc...)
qint32 num_colors; //!< number of colors in an indexed image
QVector<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];
static bool random_table_initialized;
//! This table is used as a shared grayscale ramp to be set on grayscale
//! images. This is because Qt does not differentiate between indexed and
//! grayscale images.
static QVector<QRgb> grayTable;
//! 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 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, qint32 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, qint32 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 initializeRandomTable();
static void dissolveRGBPixels(QImage& image, int x, int y);
static void dissolveAlphaPixels(QImage& image, int x, int y);
};
#endif