summaryrefslogtreecommitdiffstats
path: root/src/gvcore/qxcfi.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gvcore/qxcfi.h')
-rw-r--r--src/gvcore/qxcfi.h332
1 files changed, 332 insertions, 0 deletions
diff --git a/src/gvcore/qxcfi.h b/src/gvcore/qxcfi.h
new file mode 100644
index 0000000..ac82173
--- /dev/null
+++ b/src/gvcore/qxcfi.h
@@ -0,0 +1,332 @@
+#ifndef QXCFI_H
+#define QXCFI_H
+
+#include <qimage.h>
+#include <qimageformatplugin.h>
+#include <qvaluestack.h>
+#include <qvaluevector.h>
+
+#include "gimp.h"
+namespace Gwenview {
+
+// Safe readBlock helper functions
+class SafeDataStream {
+public:
+ SafeDataStream(QIODevice* device)
+ : mDevice(device), mFailed(false) {}
+
+ bool failed() const { return mFailed; }
+ QIODevice* device() const { return mDevice; }
+
+ SafeDataStream& readRawBytes(char* data, uint length) {
+ if (mFailed) return *this;
+ int read_length=mDevice->readBlock(data, length);
+ if (read_length==-1) mFailed=true;
+ if ((uint)read_length!=length) mFailed=true;
+ return *this;
+ }
+
+ SafeDataStream& operator>>(Q_INT8& value) {
+ return readRawBytes((char*)&value, 1);
+ }
+
+ SafeDataStream& operator>>(Q_UINT32& value) {
+ if (mFailed) return *this;
+ uchar *p = (uchar *)(&value);
+ char b[4];
+ if (mDevice->readBlock( b, 4 )==4) {
+ *p++ = b[3];
+ *p++ = b[2];
+ *p++ = b[1];
+ *p = b[0];
+ } else {
+ mFailed=true;
+ }
+ return *this;
+ }
+
+ SafeDataStream& operator>>(Q_INT32& value) {
+ return *this >>((Q_UINT32&)value);
+ }
+
+ SafeDataStream& operator>>(float& value) {
+ return *this >>((Q_UINT32&)value);
+ }
+
+ SafeDataStream& operator>>(char*& value) {
+ if (mFailed) return *this;
+
+ Q_UINT32 len;
+ *this >> len;
+ if (mFailed) return *this;
+ if ( len == 0 ) {
+ value = 0;
+ return *this;
+ }
+ if (mDevice->atEnd() ) {
+ value = 0;
+ mFailed=true;
+ return *this;
+ }
+ value = new char[len];
+ Q_CHECK_PTR( value );
+ if ( !value ) {
+ mFailed=true;
+ return *this;
+ }
+ return readRawBytes(value, len);
+ }
+
+ SafeDataStream& readBytes(char*& data, uint& len) {
+ if (mFailed) return *this;
+
+ *this >> len;
+ if (mFailed) return *this;
+ data=new char[len];
+ Q_CHECK_PTR( data );
+ if ( !data ) {
+ mFailed=true;
+ return *this;
+ }
+ return readRawBytes(data, len);
+ }
+
+ // This method is usefull to debug with gdb. Do not inline it!
+ int at() const;
+
+private:
+ QIODevice* mDevice;
+ bool mFailed;
+};
+
+//! Plug-in for loading a GIMP XCF image file directly.
+/*!
+ * This class uses the Qt 3.0 Image format plug-in loader to provide
+ * the ability to read The GIMP XCF image files. This plug-in will
+ * be dynamically loaded as needed.
+ */
+class XCFImageFormat : public QImageFormatPlugin {
+
+ /*!
+ * 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;
+
+ /*!
+ * 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.
+ */
+ struct Layer {
+ 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 );
+
+ //! Construct a layer.
+ Layer ( void ) : name( 0 ) {}
+ //! Destruct the layer.
+ ~Layer ( void ) { if ( name != 0 ) 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.
+ */
+ struct XCFImage {
+ 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
+
+ //! Simple constructor.
+ XCFImage ( void ) : initialized( false ) {}
+ };
+
+ //! 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 );
+
+ //! 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];
+
+ //! 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 LayerModes layer_modes[];
+
+public:
+ /*!
+ * The constructor for the XCF image loader. This initializes the
+ * tables used in the layer merging routines.
+ */
+ XCFImageFormat ();
+
+
+ /*!
+ * The image loader makes no (direct) use of dynamic memory
+ * and the Qt infrastructure takes care of constructing and destructing
+ * the loader so there is not much to do here.
+ */
+ ~XCFImageFormat () {}
+
+ /*!
+ * You can query Qt about the types of image file formats it knows about
+ * via QImage::inputFormats or QImage::inputFormatList().
+ * This method returns "xcf".
+ */
+ QStringList keys () const {
+ return QStringList() << "XCF";
+ }
+
+ /*!
+ * This method installs the XCF reader on demand.
+ */
+ bool installIOHandler ( const QString& );
+
+ static void registerFormat();
+
+private:
+ static void readXCF ( QImageIO* image_io );
+#ifdef TMP_WRITE
+ static void writeXCF ( QImageIO* ) {}
+#endif
+ static void initializeImage ( XCFImage& xcf_image );
+ static void composeTiles ( XCFImage& xcf_image );
+ static bool loadImageProperties ( SafeDataStream& xcf_io, XCFImage& image );
+ static bool loadLayer ( SafeDataStream& xcf_io, XCFImage& xcf_image );
+ static bool loadLayerProperties ( SafeDataStream& xcf_io, Layer& layer );
+ static bool loadChannelProperties ( SafeDataStream& xcf_io, Layer& layer );
+ static bool loadHierarchy ( SafeDataStream& xcf_io, Layer& layer );
+ static bool loadMask ( SafeDataStream& xcf_io, Layer& layer );
+ static bool loadLevel ( SafeDataStream& xcf_io, Layer& layer, Q_INT32 bpp );
+ static bool loadTileRLE ( SafeDataStream& xcf_io, uchar* tile, int size,
+ int data_length, Q_INT32 bpp );
+ static bool loadProperty ( SafeDataStream& xcf_io, PropType& type,
+ QByteArray& bytes );
+ static void setGrayPalette ( QImage& image );
+ static void setPalette ( XCFImage& xcf_image, QImage& image );
+ static void assignImageBytes ( Layer& layer, uint i, uint j );
+ static void assignMaskBytes ( Layer& layer, uint i, uint j );
+
+ 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 );
+};
+
+} // namespace
+#endif
+