• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KImgIO

xcf.cpp
Go to the documentation of this file.
00001 /*
00002  * qxcfi.cpp: A Qt 3 plug-in for reading GIMP XCF image files
00003  * Copyright (C) 2001 lignum Computing, Inc. <allen@lignumcomputing.com>
00004  * Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org>
00005  *
00006  * This plug-in is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019  *
00020  */
00021 
00022 #include "xcf.h"
00023 
00024 #include <stdlib.h>
00025 #include <QtGui/QImage>
00026 #include <QtGui/QPainter>
00027 #include <QtCore/QIODevice>
00028 #include <QtCore/QStack>
00029 #include <QtCore/QVector>
00030 
00031 #include <kdebug.h>
00032 
00033 
00034 int XCFImageFormat::random_table[RANDOM_TABLE_SIZE];
00035 bool XCFImageFormat::random_table_initialized;
00036 
00037 QVector<QRgb> XCFImageFormat::grayTable;
00038 
00039 
00040 const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
00041     {true},     // NORMAL_MODE
00042     {true},     // DISSOLVE_MODE
00043     {true},     // BEHIND_MODE
00044     {false},    // MULTIPLY_MODE
00045     {false},    // SCREEN_MODE
00046     {false},    // OVERLAY_MODE
00047     {false},    // DIFFERENCE_MODE
00048     {false},    // ADDITION_MODE
00049     {false},    // SUBTRACT_MODE
00050     {false},    // DARKEN_ONLY_MODE
00051     {false},    // LIGHTEN_ONLY_MODE
00052     {false},    // HUE_MODE
00053     {false},    // SATURATION_MODE
00054     {false},    // COLOR_MODE
00055     {false},    // VALUE_MODE
00056     {false},    // DIVIDE_MODE
00057     {false},    // DODGE_MODE
00058     {false},    // BURN_MODE
00059     {false},    // HARDLIGHT_MODE
00060     {false},    // SOFTLIGHT_MODE
00061     {false},    // GRAIN_EXTRACT_MODE
00062     {false},    // GRAIN_MERGE_MODE
00063 };
00064 
00065 
00067 inline QRgb qRgba ( const QRgb& rgb, int a )
00068 {
00069     return ((a & 0xff) << 24 | (rgb & RGB_MASK));
00070 }
00071 
00072 
00076 XCFImageFormat::XCFImageFormat()
00077 {
00078 }
00079 
00083 void XCFImageFormat::initializeRandomTable()
00084 {
00085     // From GIMP "paint_funcs.c" v1.2
00086     srand(RANDOM_SEED);
00087 
00088     for (int i = 0; i < RANDOM_TABLE_SIZE; i++)
00089         random_table[i] = rand();
00090 
00091     for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
00092         int tmp;
00093         int swap = i + rand() % (RANDOM_TABLE_SIZE - i);
00094         tmp = random_table[i];
00095         random_table[i] = random_table[swap];
00096         random_table[swap] = tmp;
00097     }
00098 }
00099 
00100 inline
00101 int XCFImageFormat::add_lut( int a, int b ) {
00102     return qMin( a + b, 255 );
00103 }
00104 
00105 bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
00106 {
00107     XCFImage xcf_image;
00108     QDataStream xcf_io(device);
00109 
00110     char tag[14];;
00111 
00112     if (xcf_io.readRawData(tag, sizeof(tag)) != sizeof(tag)) {
00113             kDebug(399) << "XCF: read failure on header tag";
00114             return false;
00115     }
00116     if (qstrncmp(tag, "gimp xcf", 8) != 0) {
00117             kDebug(399) << "XCF: read called on non-XCF file";
00118             return false;
00119     }
00120 
00121     xcf_io >> xcf_image.width >> xcf_image.height >> xcf_image.type;
00122 
00123 kDebug() << tag << " " << xcf_image.width << " " << xcf_image.height << " " <<  xcf_image.type;
00124     if (!loadImageProperties(xcf_io, xcf_image))
00125         return false;
00126 
00127     // The layers appear to be stored in top-to-bottom order. This is
00128     // the reverse of how a merged image must be computed. So, the layer
00129     // offsets are pushed onto a LIFO stack (thus, we don't have to load
00130     // all the data of all layers before beginning to construct the
00131     // merged image).
00132 
00133     QStack<qint32> layer_offsets;
00134 
00135     while (true) {
00136         qint32 layer_offset;
00137 
00138         xcf_io >> layer_offset;
00139 
00140         if (layer_offset == 0)
00141             break;
00142 
00143         layer_offsets.push(layer_offset);
00144     }
00145 
00146     xcf_image.num_layers = layer_offsets.size();
00147 
00148     if (layer_offsets.size() == 0) {
00149         kDebug(399) << "XCF: no layers!";
00150         return false;
00151     }
00152 
00153     // Load each layer and add it to the image
00154     while (!layer_offsets.isEmpty()) {
00155         qint32 layer_offset = layer_offsets.pop();
00156 
00157         xcf_io.device()->seek(layer_offset);
00158 
00159         if (!loadLayer(xcf_io, xcf_image))
00160             return false;
00161     }
00162 
00163     if (!xcf_image.initialized) {
00164         kDebug(399) << "XCF: no visible layers!";
00165         return false;
00166     }
00167 
00168         *outImage = xcf_image.image;
00169         return true;
00170 }
00171 
00172 
00180 bool XCFImageFormat::loadImageProperties(QDataStream& xcf_io, XCFImage& xcf_image)
00181 {
00182     while (true) {
00183         PropType type;
00184         QByteArray bytes;
00185 
00186         if (!loadProperty(xcf_io, type, bytes)) {
00187             kDebug(399) << "XCF: error loading global image properties";
00188             return false;
00189         }
00190 
00191         QDataStream property(bytes);
00192 
00193         switch (type) {
00194             case PROP_END:
00195                 return true;
00196 
00197             case PROP_COMPRESSION:
00198                 property >> xcf_image.compression;
00199                 break;
00200 
00201             case PROP_RESOLUTION:
00202                 property >> xcf_image.x_resolution >> xcf_image.y_resolution;
00203                 break;
00204 
00205             case PROP_TATTOO:
00206                 property >> xcf_image.tattoo;
00207                 break;
00208 
00209             case PROP_PARASITES:
00210                 while (!property.atEnd()) {
00211                     char* tag;
00212                     quint32 size;
00213 
00214                     property.readBytes(tag, size);
00215 
00216                     quint32 flags;
00217                     char* data=0;
00218                     property >> flags >> data;
00219 
00220                     if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0)
00221                         xcf_image.image.setText("Comment", 0, data);
00222 
00223                     delete[] tag;
00224                     delete[] data;
00225                 }
00226                 break;
00227 
00228                 case PROP_UNIT:
00229                     property >> xcf_image.unit;
00230                     break;
00231 
00232                 case PROP_PATHS:    // This property is ignored.
00233                     break;
00234 
00235                 case PROP_USER_UNIT:    // This property is ignored.
00236                     break;
00237 
00238                 case PROP_COLORMAP:
00239                     property >> xcf_image.num_colors;
00240                                         if(xcf_image.num_colors < 0 || xcf_image.num_colors > 65535)
00241                                             return false;
00242 
00243                     xcf_image.palette.reserve(xcf_image.num_colors);
00244 
00245                     for (int i = 0; i < xcf_image.num_colors; i++) {
00246                         uchar r, g, b;
00247                         property >> r >> g >> b;
00248                         xcf_image.palette.push_back( qRgb(r,g,b) );
00249                     }
00250                     break;
00251 
00252                 default:
00253                     kDebug(399) << "XCF: unimplemented image property" << type
00254                             << ", size " << bytes.size() << endl;
00255         }
00256     }
00257 }
00258 
00259 
00267 bool XCFImageFormat::loadProperty(QDataStream& xcf_io, PropType& type, QByteArray& bytes)
00268 {
00269     quint32 foo;
00270     xcf_io >> foo;
00271     type=PropType(foo); // TODO urks
00272 
00273     char* data = 0;
00274     quint32 size;
00275 
00276     // The colormap property size is not the correct number of bytes:
00277     // The GIMP source xcf.c has size = 4 + ncolors, but it should be
00278     // 4 + 3 * ncolors
00279 
00280     if (type == PROP_COLORMAP) {
00281         xcf_io >> size;
00282                 quint32 ncolors;
00283                 xcf_io >> ncolors;
00284 
00285                 if(size > 65535 || size < 4)
00286                     return false;
00287 
00288         size = 3 * ncolors + 4;
00289         data = new char[size];
00290 
00291                 // since we already read "ncolors" from the stream, we put that data back
00292                 data[0] = 0;
00293                 data[1] = 0;
00294                 data[2] = ncolors >> 8;
00295                 data[3] = ncolors & 255;
00296 
00297                 // ... and read the remaining bytes from the stream
00298         xcf_io.readRawData(data + 4, size - 4);
00299     } else if (type == PROP_USER_UNIT) {
00300         // The USER UNIT property size is not correct. I'm not sure why, though.
00301         float factor;
00302         qint32 digits;
00303 
00304         xcf_io >> size >> factor >> digits;
00305 
00306         for (int i = 0; i < 5; i++) {
00307             char* unit_strings;
00308 
00309             xcf_io >> unit_strings;
00310 
00311             delete[] unit_strings;
00312 
00313             if (xcf_io.device()->atEnd()) {
00314                 kDebug(399) << "XCF: read failure on property " << type;
00315                 return false;
00316             }
00317         }
00318 
00319         size = 0;
00320     } else {
00321                 xcf_io >> size;
00322                 if(size >256000)
00323                     return false;
00324                 data = new char[size];
00325         xcf_io.readRawData(data, size);
00326         }
00327 
00328     if (size != 0 && data)
00329             bytes = QByteArray(data,size);
00330     
00331         delete [] data;
00332 
00333     return true;
00334 }
00335 
00336 
00345 bool XCFImageFormat::loadLayer(QDataStream& xcf_io, XCFImage& xcf_image)
00346 {
00347     Layer& layer(xcf_image.layer);
00348     delete[] layer.name;
00349 
00350     xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
00351 
00352     if (!loadLayerProperties(xcf_io, layer))
00353         return false;
00354 #if 0
00355   cout << "layer: \"" << layer.name << "\", size: " << layer.width << " x "
00356        << layer.height << ", type: " << layer.type << ", mode: " << layer.mode
00357        << ", opacity: " << layer.opacity << ", visible: " << layer.visible
00358        << ", offset: " << layer.x_offset << ", " << layer.y_offset << endl;
00359 #endif
00360   // Skip reading the rest of it if it is not visible. Typically, when
00361   // you export an image from the The GIMP it flattens (or merges) only
00362   // the visible layers into the output image.
00363 
00364     if (layer.visible == 0)
00365         return true;
00366 
00367     // If there are any more layers, merge them into the final QImage.
00368 
00369     xcf_io >> layer.hierarchy_offset >> layer.mask_offset;
00370 
00371     // Allocate the individual tile QImages based on the size and type
00372     // of this layer.
00373 
00374     if( !composeTiles(xcf_image))
00375         return false;
00376     xcf_io.device()->seek(layer.hierarchy_offset);
00377 
00378     // As tiles are loaded, they are copied into the layers tiles by
00379     // this routine. (loadMask(), below, uses a slightly different
00380     // version of assignBytes().)
00381 
00382     layer.assignBytes = assignImageBytes;
00383 
00384     if (!loadHierarchy(xcf_io, layer))
00385         return false;
00386 
00387     if (layer.mask_offset != 0) {
00388         xcf_io.device()->seek(layer.mask_offset);
00389 
00390         if (!loadMask(xcf_io, layer))
00391             return false;
00392     }
00393 
00394     // Now we should have enough information to initialize the final
00395     // QImage. The first visible layer determines the attributes
00396     // of the QImage.
00397 
00398     if (!xcf_image.initialized) {
00399         if( !initializeImage(xcf_image))
00400             return false;
00401         copyLayerToImage(xcf_image);
00402         xcf_image.initialized = true;
00403     } else
00404         mergeLayerIntoImage(xcf_image);
00405 
00406     return true;
00407 }
00408 
00409 
00417 bool XCFImageFormat::loadLayerProperties(QDataStream& xcf_io, Layer& layer)
00418 {
00419     while (true) {
00420         PropType type;
00421         QByteArray bytes;
00422 
00423         if (!loadProperty(xcf_io, type, bytes)) {
00424             kDebug(399) << "XCF: error loading layer properties";
00425             return false;
00426         }
00427 
00428         QDataStream property(bytes);
00429 
00430         switch (type) {
00431             case PROP_END:
00432                 return true;
00433 
00434             case PROP_ACTIVE_LAYER:
00435                 layer.active = true;
00436                 break;
00437 
00438             case PROP_OPACITY:
00439                 property >> layer.opacity;
00440                 break;
00441 
00442             case PROP_VISIBLE:
00443                 property >> layer.visible;
00444                 break;
00445 
00446             case PROP_LINKED:
00447                 property >> layer.linked;
00448                 break;
00449 
00450             case PROP_PRESERVE_TRANSPARENCY:
00451                 property >> layer.preserve_transparency;
00452                 break;
00453 
00454             case PROP_APPLY_MASK:
00455                 property >> layer.apply_mask;
00456                 break;
00457 
00458             case PROP_EDIT_MASK:
00459                 property >> layer.edit_mask;
00460                 break;
00461 
00462             case PROP_SHOW_MASK:
00463                 property >> layer.show_mask;
00464                 break;
00465 
00466             case PROP_OFFSETS:
00467                 property >> layer.x_offset >> layer.y_offset;
00468                 break;
00469 
00470             case PROP_MODE:
00471                 property >> layer.mode;
00472                 break;
00473 
00474             case PROP_TATTOO:
00475                 property >> layer.tattoo;
00476                 break;
00477 
00478             default:
00479                 kDebug(399) << "XCF: unimplemented layer property " << type
00480                         << ", size " << bytes.size() << endl;
00481         }
00482     }
00483 }
00484 
00485 
00491 bool XCFImageFormat::composeTiles(XCFImage& xcf_image)
00492 {
00493     Layer& layer(xcf_image.layer);
00494 
00495     layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
00496     layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
00497 
00498     layer.image_tiles.resize(layer.nrows);
00499 
00500     if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00501         layer.alpha_tiles.resize(layer.nrows);
00502 
00503     if (layer.mask_offset != 0)
00504         layer.mask_tiles.resize(layer.nrows);
00505 
00506     for (uint j = 0; j < layer.nrows; j++) {
00507         layer.image_tiles[j].resize(layer.ncols);
00508 
00509         if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00510             layer.alpha_tiles[j].resize(layer.ncols);
00511 
00512         if (layer.mask_offset != 0)
00513             layer.mask_tiles[j].resize(layer.ncols);
00514     }
00515 
00516     for (uint j = 0; j < layer.nrows; j++) {
00517         for (uint i = 0; i < layer.ncols; i++) {
00518 
00519             uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
00520                     ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
00521 
00522             uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
00523                     ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
00524 
00525             // Try to create the most appropriate QImage (each GIMP layer
00526             // type is treated slightly differently)
00527 
00528             switch (layer.type) {
00529                 case RGB_GIMAGE:
00530                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_RGB32);
00531                     layer.image_tiles[j][i].setNumColors(0);
00532                     if( layer.image_tiles[j][i].isNull())
00533                         return false;
00534                     break;
00535 
00536                 case RGBA_GIMAGE:
00537                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_ARGB32);
00538                     layer.image_tiles[j][i].setNumColors(0);
00539                     if( layer.image_tiles[j][i].isNull())
00540                         return false;
00541                     break;
00542 
00543                 case GRAY_GIMAGE:
00544                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00545                     layer.image_tiles[j][i].setNumColors(256);
00546                     if( layer.image_tiles[j][i].isNull())
00547                         return false;
00548                     setGrayPalette(layer.image_tiles[j][i]);
00549                     break;
00550 
00551                 case GRAYA_GIMAGE:
00552                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00553                     layer.image_tiles[j][i].setNumColors(256);
00554                     if( layer.image_tiles[j][i].isNull())
00555                         return false;
00556                     setGrayPalette(layer.image_tiles[j][i]);
00557 
00558                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00559                     layer.alpha_tiles[j][i].setNumColors(256);
00560                     if( layer.alpha_tiles[j][i].isNull())
00561                         return false;
00562                     setGrayPalette(layer.alpha_tiles[j][i]);
00563                     break;
00564 
00565                 case INDEXED_GIMAGE:
00566                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00567                     layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
00568                     if( layer.image_tiles[j][i].isNull())
00569                         return false;
00570                     setPalette(xcf_image, layer.image_tiles[j][i]);
00571                     break;
00572 
00573                 case INDEXEDA_GIMAGE:
00574                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00575                     layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
00576                     if( layer.image_tiles[j][i].isNull())
00577                         return false;
00578                     setPalette(xcf_image, layer.image_tiles[j][i]);
00579 
00580                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00581                     layer.alpha_tiles[j][i].setNumColors(256);
00582                     if( layer.alpha_tiles[j][i].isNull())
00583                         return false;
00584                     setGrayPalette(layer.alpha_tiles[j][i]);
00585             }
00586 
00587             if (layer.mask_offset != 0) {
00588                 layer.mask_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00589                 layer.mask_tiles[j][i].setNumColors(256);
00590                 if( layer.mask_tiles[j][i].isNull())
00591                     return false;
00592                 setGrayPalette(layer.mask_tiles[j][i]);
00593             }
00594         }
00595     }
00596     return true;
00597 }
00598 
00599 
00606 void XCFImageFormat::setGrayPalette(QImage& image)
00607 {
00608     if (grayTable.isEmpty()) {
00609         grayTable.resize(256);
00610 
00611         for (int i = 0; i < 256; i++)
00612             grayTable[i] = qRgb(i, i, i);
00613     }
00614 
00615     image.setColorTable(grayTable);
00616 }
00617 
00618 
00624 void XCFImageFormat::setPalette(XCFImage& xcf_image, QImage& image)
00625 {
00626     Q_ASSERT (xcf_image.num_colors == xcf_image.palette.size());
00627 
00628     image.setColorTable(xcf_image.palette);
00629 }
00630 
00631 
00639 void XCFImageFormat::assignImageBytes(Layer& layer, uint i, uint j)
00640 {
00641     QImage &image = layer.image_tiles[j][i];
00642     uchar* tile = layer.tile;
00643     const int width = image.width();
00644     const int height = image.height();
00645     const int bytesPerLine = image.bytesPerLine();
00646     uchar *bits = image.bits();
00647 
00648     switch (layer.type) {
00649         case RGB_GIMAGE:
00650             for (int y = 0; y < height; y++) {
00651                 QRgb *dataPtr = (QRgb *) (bits + y * bytesPerLine);
00652                 for (int x = 0; x < width; x++) {
00653                     *dataPtr++ = qRgb(tile[0], tile[1], tile[2]);
00654                     tile += sizeof(QRgb);
00655                 }
00656             }
00657             break;
00658 
00659         case RGBA_GIMAGE:
00660             for (int y = 0; y < height; y++) {
00661                 QRgb *dataPtr = (QRgb *) (bits + y * bytesPerLine);
00662                 for (int x = 0; x < width; x++) {
00663                     *dataPtr++ =    qRgba(tile[0], tile[1], tile[2], tile[3]);
00664                     tile += sizeof(QRgb);
00665                 }
00666             }
00667             break;
00668 
00669         case GRAY_GIMAGE:
00670         case INDEXED_GIMAGE:
00671             for (int y = 0; y < height; y++) {
00672                 uchar *dataPtr = bits + y * bytesPerLine;
00673                 for (int x = 0; x < width; x++) {
00674                     *dataPtr++ = tile[0];
00675                     tile += sizeof(QRgb);
00676                 }
00677             }
00678             break;
00679 
00680         case GRAYA_GIMAGE:
00681         case INDEXEDA_GIMAGE:
00682             for (int y = 0; y < height; y++) {
00683                 uchar *dataPtr = bits + y * bytesPerLine;
00684                 uchar *alphaPtr = layer.alpha_tiles[j][i].scanLine(y);
00685                 for (int x = 0; x < width; x++) {
00686 
00687                 // The "if" here should not be necessary, but apparently there
00688                 // are some cases where the image can contain larger indices
00689                 // than there are colors in the palette. (A bug in The GIMP?)
00690 
00691                     if (tile[0] < image.numColors())
00692                         *dataPtr = tile[0];
00693 
00694                     *alphaPtr = tile[1];
00695                     dataPtr += 1;
00696                     alphaPtr += 1;
00697                     tile += sizeof(QRgb);
00698                 }
00699             }
00700             break;
00701     }
00702 }
00703 
00704 
00713 bool XCFImageFormat::loadHierarchy(QDataStream& xcf_io, Layer& layer)
00714 {
00715     qint32 width;
00716     qint32 height;
00717     qint32 bpp;
00718     quint32 offset;
00719 
00720     xcf_io >> width >> height >> bpp >> offset;
00721 
00722     // GIMP stores images in a "mipmap"-like format (multiple levels of
00723     // increasingly lower resolution). Only the top level is used here,
00724     // however.
00725 
00726     quint32 junk;
00727     do {
00728         xcf_io >> junk;
00729 
00730         if (xcf_io.device()->atEnd()) {
00731             kDebug(399) << "XCF: read failure on layer " << layer.name << " level offsets";
00732             return false;
00733         }
00734     } while (junk != 0);
00735 
00736     qint64 saved_pos = xcf_io.device()->pos();
00737 
00738     xcf_io.device()->seek(offset);
00739     if (!loadLevel(xcf_io, layer, bpp))
00740         return false;
00741 
00742     xcf_io.device()->seek(saved_pos);
00743     return true;
00744 }
00745 
00746 
00755 bool XCFImageFormat::loadLevel(QDataStream& xcf_io, Layer& layer, qint32 bpp)
00756 {
00757     qint32 width;
00758     qint32 height;
00759     quint32 offset;
00760 
00761     xcf_io >> width >> height >> offset;
00762 
00763     if (offset == 0)
00764         return true;
00765 
00766     for (uint j = 0; j < layer.nrows; j++) {
00767         for (uint i = 0; i < layer.ncols; i++) {
00768 
00769             if (offset == 0) {
00770                 kDebug(399) << "XCF: incorrect number of tiles in layer " << layer.name;
00771                 return false;
00772             }
00773 
00774             qint64 saved_pos = xcf_io.device()->pos();
00775             quint32 offset2;
00776             xcf_io >> offset2;
00777 
00778             // Evidently, RLE can occasionally expand a tile instead of compressing it!
00779 
00780             if (offset2 == 0)
00781                 offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
00782 
00783             xcf_io.device()->seek(offset);
00784             int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
00785 
00786             if (!loadTileRLE(xcf_io, layer.tile, size, offset2 - offset, bpp))
00787                 return false;
00788 
00789             // The bytes in the layer tile are juggled differently depending on
00790             // the target QImage. The caller has set layer.assignBytes to the
00791             // appropriate routine.
00792 
00793             layer.assignBytes(layer, i, j);
00794 
00795             xcf_io.device()->seek(saved_pos);
00796             xcf_io >> offset;
00797         }
00798     }
00799 
00800     return true;
00801 }
00802 
00803 
00810 bool XCFImageFormat::loadMask(QDataStream& xcf_io, Layer& layer)
00811 {
00812     qint32 width;
00813     qint32 height;
00814     char* name;
00815 
00816     xcf_io >> width >> height >> name;
00817 
00818     delete name;
00819 
00820     if (!loadChannelProperties(xcf_io, layer))
00821         return false;
00822 
00823     quint32 hierarchy_offset;
00824     xcf_io >> hierarchy_offset;
00825 
00826     xcf_io.device()->seek(hierarchy_offset);
00827     layer.assignBytes = assignMaskBytes;
00828 
00829     if (!loadHierarchy(xcf_io, layer))
00830         return false;
00831 
00832     return true;
00833 }
00834 
00835 
00859 bool XCFImageFormat::loadTileRLE(QDataStream& xcf_io, uchar* tile, int image_size,
00860         int data_length, qint32 bpp)
00861 {
00862     uchar* data;
00863 
00864     uchar* xcfdata;
00865     uchar* xcfodata;
00866     uchar* xcfdatalimit;
00867 
00868     if (data_length < 0 || data_length > int(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5)) {
00869         kDebug(399) << "XCF: invalid tile data length" << data_length;
00870         return false;
00871     }
00872 
00873     xcfdata = xcfodata = new uchar[data_length];
00874 
00875     xcf_io.readRawData((char*)xcfdata, data_length);
00876 
00877     if (!xcf_io.device()->isOpen()) {
00878         delete[] xcfodata;
00879         kDebug(399) << "XCF: read failure on tile";
00880         return false;
00881     }
00882 
00883     xcfdatalimit = &xcfodata[data_length - 1];
00884 
00885     for (int i = 0; i < bpp; ++i) {
00886 
00887         data = tile + i;
00888 
00889         int count = 0;
00890         int size = image_size;
00891 
00892         while (size > 0) {
00893             if (xcfdata > xcfdatalimit)
00894                 goto bogus_rle;
00895 
00896             uchar val = *xcfdata++;
00897             uint length = val;
00898 
00899             if (length >= 128) {
00900                 length = 255 - (length - 1);
00901                 if (length == 128) {
00902                     if (xcfdata >= xcfdatalimit)
00903                         goto bogus_rle;
00904 
00905                     length = (*xcfdata << 8) + xcfdata[1];
00906 
00907                     xcfdata += 2;
00908                 }
00909 
00910                 count += length;
00911                 size -= length;
00912 
00913                 if (size < 0)
00914                     goto bogus_rle;
00915 
00916                 if (&xcfdata[length - 1] > xcfdatalimit)
00917                     goto bogus_rle;
00918 
00919                 while (length-- > 0) {
00920                     *data = *xcfdata++;
00921                     data += sizeof(QRgb);
00922                 }
00923             } else {
00924                 length += 1;
00925                 if (length == 128) {
00926                     if (xcfdata >= xcfdatalimit)
00927                         goto bogus_rle;
00928 
00929                     length = (*xcfdata << 8) + xcfdata[1];
00930                     xcfdata += 2;
00931                 }
00932 
00933                 count += length;
00934                 size -= length;
00935 
00936                 if (size < 0)
00937                     goto bogus_rle;
00938 
00939                 if (xcfdata > xcfdatalimit)
00940                     goto bogus_rle;
00941 
00942                 val = *xcfdata++;
00943 
00944                 while (length-- > 0) {
00945                     *data = val;
00946                     data += sizeof(QRgb);
00947                 }
00948             }
00949         }
00950     }
00951 
00952     delete[] xcfodata;
00953     return true;
00954 
00955 bogus_rle:
00956 
00957     kDebug(399) << "The run length encoding could not be decoded properly";
00958     delete[] xcfodata;
00959     return false;
00960 }
00961 
00962 
00970 bool XCFImageFormat::loadChannelProperties(QDataStream& xcf_io, Layer& layer)
00971 {
00972     while (true) {
00973         PropType type;
00974         QByteArray bytes;
00975 
00976         if (!loadProperty(xcf_io, type, bytes)) {
00977             kDebug(399) << "XCF: error loading channel properties";
00978             return false;
00979         }
00980 
00981         QDataStream property(bytes);
00982 
00983         switch (type) {
00984             case PROP_END:
00985                 return true;
00986 
00987             case PROP_OPACITY:
00988                 property >> layer.mask_channel.opacity;
00989                 break;
00990 
00991             case PROP_VISIBLE:
00992                 property >> layer.mask_channel.visible;
00993                 break;
00994 
00995             case PROP_SHOW_MASKED:
00996                 property >> layer.mask_channel.show_masked;
00997                 break;
00998 
00999             case PROP_COLOR:
01000                 property >> layer.mask_channel.red >> layer.mask_channel.green
01001                         >> layer.mask_channel.blue;
01002                 break;
01003 
01004             case PROP_TATTOO:
01005                 property >> layer.mask_channel.tattoo;
01006                 break;
01007 
01008             default:
01009                 kDebug(399) << "XCF: unimplemented channel property " << type
01010                         << ", size " << bytes.size() << endl;
01011         }
01012     }
01013 }
01014 
01015 
01022 void XCFImageFormat::assignMaskBytes(Layer& layer, uint i, uint j)
01023 {
01024     QImage &image = layer.mask_tiles[j][i];
01025     uchar* tile = layer.tile;
01026     const int width = image.width();
01027     const int height = image.height();
01028     const int bytesPerLine = image.bytesPerLine();
01029     uchar *bits = image.bits();
01030 
01031     for (int y = 0; y < height; y++) {
01032         uchar *dataPtr = bits + y * bytesPerLine;
01033         for (int x = 0; x < width; x++) {
01034             *dataPtr++ = tile[0];
01035             tile += sizeof(QRgb);
01036         }
01037     }
01038 }
01039 
01040 
01069 bool XCFImageFormat::initializeImage(XCFImage& xcf_image)
01070 {
01071     // (Aliases to make the code look a little better.)
01072     Layer& layer(xcf_image.layer);
01073     QImage& image(xcf_image.image);
01074 
01075     switch (layer.type) {
01076         case RGB_GIMAGE:
01077             if (layer.opacity == OPAQUE_OPACITY) {
01078                 image = QImage( xcf_image.width, xcf_image.height, QImage::Format_RGB32);
01079                 if( image.isNull())
01080                     return false;
01081                 image.fill(qRgb(255, 255, 255));
01082                 break;
01083             } // else, fall through to 32-bit representation
01084 
01085         case RGBA_GIMAGE:
01086             image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01087             if( image.isNull())
01088                 return false;
01089             image.fill(qRgba(255, 255, 255, 0));
01090             break;
01091 
01092         case GRAY_GIMAGE:
01093             if (layer.opacity == OPAQUE_OPACITY) {
01094                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01095                 image.setNumColors(256);
01096                 if( image.isNull())
01097                     return false;
01098                 setGrayPalette(image);
01099                 image.fill(255);
01100                 break;
01101             } // else, fall through to 32-bit representation
01102 
01103         case GRAYA_GIMAGE:
01104             image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01105             if( image.isNull())
01106                 return false;
01107             image.fill(qRgba(255, 255, 255, 0));
01108             break;
01109 
01110         case INDEXED_GIMAGE:
01111             // As noted in the table above, there are quite a few combinations
01112             // which are possible with indexed images, depending on the
01113             // presence of transparency (note: not translucency, which is not
01114             // supported by The GIMP for indexed images) and the number of
01115             // individual colors.
01116 
01117             // Note: Qt treats a bitmap with a Black and White color palette
01118             // as a mask, so only the "on" bits are drawn, regardless of the
01119             // order color table entries. Otherwise (i.e., at least one of the
01120             // color table entries is not black or white), it obeys the one-
01121             // or two-color palette. Have to ask about this...
01122 
01123             if (xcf_image.num_colors <= 2) {
01124                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
01125                 image.setNumColors(xcf_image.num_colors);
01126                 if( image.isNull())
01127                     return false;
01128                 image.fill(0);
01129                 setPalette(xcf_image, image);
01130             } else if (xcf_image.num_colors <= 256) {
01131                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01132                 image.setNumColors(xcf_image.num_colors);
01133                 if( image.isNull())
01134                     return false;
01135                 image.fill(0);
01136                 setPalette(xcf_image, image);
01137             }
01138             break;
01139 
01140         case INDEXEDA_GIMAGE:
01141             if (xcf_image.num_colors == 1) {
01142                 // Plenty(!) of room to add a transparent color
01143                 xcf_image.num_colors++;
01144                 xcf_image.palette.resize(xcf_image.num_colors);
01145                 xcf_image.palette[1] = xcf_image.palette[0];
01146                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01147 
01148                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
01149                 image.setNumColors(xcf_image.num_colors);
01150                 if( image.isNull())
01151                     return false;
01152                 image.fill(0);
01153                 setPalette(xcf_image, image);
01154             } else if (xcf_image.num_colors < 256) {
01155                 // Plenty of room to add a transparent color
01156                 xcf_image.num_colors++;
01157                 xcf_image.palette.resize(xcf_image.num_colors);
01158                 for (int c = xcf_image.num_colors - 1; c >= 1; c--)
01159                     xcf_image.palette[c] = xcf_image.palette[c - 1];
01160 
01161                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01162                 image = QImage( xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01163                 image.setNumColors(xcf_image.num_colors);
01164                 if( image.isNull())
01165                     return false;
01166                 image.fill(0);
01167                 setPalette(xcf_image, image);
01168             } else {
01169                 // No room for a transparent color, so this has to be promoted to
01170                 // true color. (There is no equivalent PNG representation output
01171                 // from The GIMP as of v1.2.)
01172                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01173                 if( image.isNull())
01174                     return false;
01175                 image.fill(qRgba(255, 255, 255, 0));
01176             }
01177             break;
01178     }
01179 
01180     image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER));
01181     image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER));
01182     return true;
01183 }
01184 
01185 
01191 void XCFImageFormat::copyLayerToImage(XCFImage& xcf_image)
01192 {
01193     Layer& layer(xcf_image.layer);
01194     QImage& image(xcf_image.image);
01195     PixelCopyOperation copy = 0;
01196 
01197     switch (layer.type) {
01198         case RGB_GIMAGE:
01199         case RGBA_GIMAGE:
01200             copy = copyRGBToRGB;
01201             break;
01202         case GRAY_GIMAGE:
01203             if (layer.opacity == OPAQUE_OPACITY)
01204                 copy = copyGrayToGray;
01205             else
01206                 copy = copyGrayToRGB;
01207             break;
01208         case GRAYA_GIMAGE:
01209             copy = copyGrayAToRGB;
01210             break;
01211         case INDEXED_GIMAGE:
01212             copy = copyIndexedToIndexed;
01213             break;
01214         case INDEXEDA_GIMAGE:
01215             if (xcf_image.image.depth() <= 8)
01216                 copy = copyIndexedAToIndexed;
01217             else
01218                 copy = copyIndexedAToRGB;
01219     }
01220 
01221     if (!copy) {
01222         return;
01223     }
01224 
01225     // For each tile...
01226 
01227     for (uint j = 0; j < layer.nrows; j++) {
01228         uint y = j * TILE_HEIGHT;
01229 
01230         for (uint i = 0; i < layer.ncols; i++) {
01231             uint x = i * TILE_WIDTH;
01232 
01233             // This seems the best place to apply the dissolve because it
01234             // depends on the global position of each tile's
01235             // pixels. Apparently it's the only mode which can apply to a
01236             // single layer.
01237 
01238             if (layer.mode == DISSOLVE_MODE) {
01239                 if (!random_table_initialized) {
01240                     initializeRandomTable();
01241                     random_table_initialized = true;
01242                 }
01243                 if (layer.type == RGBA_GIMAGE)
01244                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01245 
01246                 else if (layer.type == GRAYA_GIMAGE)
01247                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01248             }
01249 
01250             // Shortcut for common case
01251             if (copy == copyRGBToRGB && layer.apply_mask != 1) {
01252                 QPainter painter(&image);
01253                 painter.setOpacity(layer.opacity / 255.0);
01254                 painter.setCompositionMode(QPainter::CompositionMode_Source);
01255                 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
01256                 continue;
01257             }
01258 
01259             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01260                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01261 
01262                     int m = x + k + layer.x_offset;
01263                     int n = y + l + layer.y_offset;
01264 
01265                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01266                         continue;
01267 
01268                     (*copy)(layer, i, j, k, l, image, m, n);
01269                 }
01270             }
01271         }
01272     }
01273 }
01274 
01275 
01289 void XCFImageFormat::copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01290         QImage& image, int m, int n)
01291 {
01292     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01293     uchar src_a = layer.opacity;
01294 
01295     if (layer.type == RGBA_GIMAGE)
01296         src_a = INT_MULT(src_a, qAlpha(src));
01297 
01298     // Apply the mask (if any)
01299 
01300     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01301             layer.mask_tiles[j].size() > (int)i)
01302         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01303 
01304     image.setPixel(m, n, qRgba(src, src_a));
01305 }
01306 
01307 
01319 void XCFImageFormat::copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01320         QImage& image, int m, int n)
01321 {
01322     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01323     image.setPixel(m, n, src);
01324 }
01325 
01326 
01340 void XCFImageFormat::copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
01341         QImage& image, int m, int n)
01342 {
01343     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01344     uchar src_a = layer.opacity;
01345     image.setPixel(m, n, qRgba(src, src_a));
01346 }
01347 
01348 
01362 void XCFImageFormat::copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
01363                       QImage& image, int m, int n)
01364 {
01365     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01366     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01367     src_a = INT_MULT(src_a, layer.opacity);
01368 
01369     // Apply the mask (if any)
01370 
01371     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01372             layer.mask_tiles[j].size() > (int)i)
01373         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01374 
01375     image.setPixel(m, n, qRgba(src, src_a));
01376 }
01377 
01378 
01390 void XCFImageFormat::copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
01391         QImage& image, int m, int n)
01392 {
01393     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01394     image.setPixel(m, n, src);
01395 }
01396 
01397 
01409 void XCFImageFormat::copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
01410         QImage& image, int m, int n)
01411 {
01412     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
01413     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01414     src_a = INT_MULT(src_a, layer.opacity);
01415 
01416     if (layer.apply_mask == 1 &&
01417             layer.mask_tiles.size() > (int)j &&
01418             layer.mask_tiles[j].size() > (int)i)
01419         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01420 
01421     if (src_a > 127)
01422         src++;
01423     else
01424         src = 0;
01425 
01426 image.setPixel(m, n, src);
01427 }
01428 
01429 
01443 void XCFImageFormat::copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
01444         QImage& image, int m, int n)
01445 {
01446     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01447     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01448     src_a = INT_MULT(src_a, layer.opacity);
01449 
01450     // Apply the mask (if any)
01451     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01452             layer.mask_tiles[j].size() > (int)i)
01453         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01454 
01455     // This is what appears in the GIMP window
01456     if (src_a <= 127)
01457         src_a = 0;
01458     else
01459         src_a = OPAQUE_OPACITY;
01460 
01461     image.setPixel(m, n, qRgba(src, src_a));
01462 }
01463 
01464 
01469 void XCFImageFormat::mergeLayerIntoImage(XCFImage& xcf_image)
01470 {
01471     Layer& layer(xcf_image.layer);
01472     QImage& image(xcf_image.image);
01473 
01474     PixelMergeOperation merge = 0;
01475 
01476     if (!layer.opacity) return; // don't bother doing anything
01477 
01478     switch (layer.type) {
01479         case RGB_GIMAGE:
01480         case RGBA_GIMAGE:
01481             merge = mergeRGBToRGB;
01482             break;
01483         case GRAY_GIMAGE:
01484             if (layer.opacity == OPAQUE_OPACITY)
01485                 merge = mergeGrayToGray;
01486             else
01487                 merge = mergeGrayToRGB;
01488             break;
01489         case GRAYA_GIMAGE:
01490             if (xcf_image.image.depth() <= 8)
01491                 merge = mergeGrayAToGray;
01492             else
01493                 merge = mergeGrayAToRGB;
01494             break;
01495         case INDEXED_GIMAGE:
01496             merge = mergeIndexedToIndexed;
01497             break;
01498         case INDEXEDA_GIMAGE:
01499             if (xcf_image.image.depth() <= 8)
01500                 merge = mergeIndexedAToIndexed;
01501             else
01502                 merge = mergeIndexedAToRGB;
01503     }
01504 
01505     if (!merge) {
01506         return;
01507     }
01508 
01509     for (uint j = 0; j < layer.nrows; j++) {
01510         uint y = j * TILE_HEIGHT;
01511 
01512         for (uint i = 0; i < layer.ncols; i++) {
01513             uint x = i * TILE_WIDTH;
01514 
01515             // This seems the best place to apply the dissolve because it
01516             // depends on the global position of each tile's
01517             // pixels. Apparently it's the only mode which can apply to a
01518             // single layer.
01519 
01520             if (layer.mode == DISSOLVE_MODE) {
01521                 if (!random_table_initialized) {
01522                     initializeRandomTable();
01523                     random_table_initialized = true;
01524                 }
01525                 if (layer.type == RGBA_GIMAGE)
01526                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01527 
01528                 else if (layer.type == GRAYA_GIMAGE)
01529                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01530             }
01531 
01532             // Shortcut for common case
01533             if (merge == mergeRGBToRGB && layer.apply_mask != 1
01534                 && layer.mode == NORMAL_MODE) {
01535                 QPainter painter(&image);
01536                 painter.setOpacity(layer.opacity / 255.0);
01537                 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
01538                 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
01539                 continue;
01540             }
01541 
01542             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01543                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01544 
01545                     int m = x + k + layer.x_offset;
01546                     int n = y + l + layer.y_offset;
01547 
01548                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01549                         continue;
01550 
01551                     (*merge)(layer, i, j, k, l, image, m, n);
01552                 }
01553             }
01554         }
01555     }
01556 }
01557 
01558 
01572 void XCFImageFormat::mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01573         QImage& image, int m, int n)
01574 {
01575     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01576     QRgb dst = image.pixel(m, n);
01577 
01578     uchar src_r = qRed(src);
01579     uchar src_g = qGreen(src);
01580     uchar src_b = qBlue(src);
01581     uchar src_a = qAlpha(src);
01582 
01583     uchar dst_r = qRed(dst);
01584     uchar dst_g = qGreen(dst);
01585     uchar dst_b = qBlue(dst);
01586     uchar dst_a = qAlpha(dst);
01587 
01588     if (!src_a) return; // nothing to merge
01589 
01590     switch (layer.mode) {
01591         case MULTIPLY_MODE: {
01592             src_r = INT_MULT(src_r, dst_r);
01593             src_g = INT_MULT(src_g, dst_g);
01594             src_b = INT_MULT(src_b, dst_b);
01595             src_a = qMin(src_a, dst_a);
01596             }
01597             break;
01598         case DIVIDE_MODE: {
01599             src_r = qMin((dst_r * 256) / (1 + src_r), 255);
01600             src_g = qMin((dst_g * 256) / (1 + src_g), 255);
01601             src_b = qMin((dst_b * 256) / (1 + src_b), 255);
01602             src_a = qMin(src_a, dst_a);
01603             }
01604             break;
01605         case SCREEN_MODE: {
01606             src_r = 255 - INT_MULT(255 - dst_r, 255 - src_r);
01607             src_g = 255 - INT_MULT(255 - dst_g, 255 - src_g);
01608             src_b = 255 - INT_MULT(255 - dst_b, 255 - src_b);
01609             src_a = qMin(src_a, dst_a);
01610             }
01611             break;
01612         case OVERLAY_MODE: {
01613             src_r = INT_MULT(dst_r, dst_r + INT_MULT(2 * src_r, 255 - dst_r));
01614             src_g = INT_MULT(dst_g, dst_g + INT_MULT(2 * src_g, 255 - dst_g));
01615             src_b = INT_MULT(dst_b, dst_b + INT_MULT(2 * src_b, 255 - dst_b));
01616             src_a = qMin(src_a, dst_a);
01617             }
01618             break;
01619         case DIFFERENCE_MODE: {
01620             src_r = dst_r > src_r ? dst_r - src_r : src_r - dst_r;
01621             src_g = dst_g > src_g ? dst_g - src_g : src_g - dst_g;
01622             src_b = dst_b > src_b ? dst_b - src_b : src_b - dst_b;
01623             src_a = qMin(src_a, dst_a);
01624             }
01625             break;
01626         case ADDITION_MODE: {
01627               src_r = add_lut(dst_r,src_r);
01628               src_g = add_lut(dst_g,src_g);
01629               src_b = add_lut(dst_b,src_b);
01630               src_a = qMin(src_a, dst_a);
01631             }
01632             break;
01633         case SUBTRACT_MODE: {
01634             src_r = dst_r > src_r ? dst_r - src_r : 0;
01635             src_g = dst_g > src_g ? dst_g - src_g : 0;
01636             src_b = dst_b > src_b ? dst_b - src_b : 0;
01637             src_a = qMin(src_a, dst_a);
01638             }
01639             break;
01640         case DARKEN_ONLY_MODE: {
01641             src_r = dst_r < src_r ? dst_r : src_r;
01642             src_g = dst_g < src_g ? dst_g : src_g;
01643             src_b = dst_b < src_b ? dst_b : src_b;
01644             src_a = qMin( src_a, dst_a );
01645             }
01646             break;
01647         case LIGHTEN_ONLY_MODE: {
01648             src_r = dst_r < src_r ? src_r : dst_r;
01649             src_g = dst_g < src_g ? src_g : dst_g;
01650             src_b = dst_b < src_b ? src_b : dst_b;
01651             src_a = qMin(src_a, dst_a);
01652             }
01653             break;
01654         case HUE_MODE: {
01655             uchar new_r = dst_r;
01656             uchar new_g = dst_g;
01657             uchar new_b = dst_b;
01658 
01659             RGBTOHSV(src_r, src_g, src_b);
01660             RGBTOHSV(new_r, new_g, new_b);
01661 
01662             new_r = src_r;
01663 
01664             HSVTORGB(new_r, new_g, new_b);
01665 
01666             src_r = new_r;
01667             src_g = new_g;
01668             src_b = new_b;
01669             src_a = qMin( src_a, dst_a );
01670             }
01671             break;
01672         case SATURATION_MODE: {
01673             uchar new_r = dst_r;
01674             uchar new_g = dst_g;
01675             uchar new_b = dst_b;
01676 
01677             RGBTOHSV(src_r, src_g, src_b);
01678             RGBTOHSV(new_r, new_g, new_b);
01679 
01680             new_g = src_g;
01681 
01682             HSVTORGB(new_r, new_g, new_b);
01683 
01684             src_r = new_r;
01685             src_g = new_g;
01686             src_b = new_b;
01687             src_a = qMin(src_a, dst_a);
01688             }
01689             break;
01690         case VALUE_MODE: {
01691             uchar new_r = dst_r;
01692             uchar new_g = dst_g;
01693             uchar new_b = dst_b;
01694 
01695             RGBTOHSV(src_r, src_g, src_b);
01696             RGBTOHSV(new_r, new_g, new_b);
01697 
01698             new_b = src_b;
01699 
01700             HSVTORGB(new_r, new_g, new_b);
01701 
01702             src_r = new_r;
01703             src_g = new_g;
01704             src_b = new_b;
01705             src_a = qMin(src_a, dst_a);
01706             }
01707             break;
01708         case COLOR_MODE: {
01709             uchar new_r = dst_r;
01710             uchar new_g = dst_g;
01711             uchar new_b = dst_b;
01712 
01713             RGBTOHLS(src_r, src_g, src_b);
01714             RGBTOHLS(new_r, new_g, new_b);
01715 
01716             new_r = src_r;
01717             new_b = src_b;
01718 
01719             HLSTORGB(new_r, new_g, new_b);
01720 
01721             src_r = new_r;
01722             src_g = new_g;
01723             src_b = new_b;
01724             src_a = qMin(src_a, dst_a);
01725             }
01726             break;
01727         case DODGE_MODE: {
01728             uint tmp;
01729 
01730             tmp = dst_r << 8;
01731             tmp /= 256 - src_r;
01732             src_r = (uchar) qMin(tmp, 255u);
01733 
01734             tmp = dst_g << 8;
01735             tmp /= 256 - src_g;
01736             src_g = (uchar) qMin(tmp, 255u);
01737 
01738             tmp = dst_b << 8;
01739             tmp /= 256 - src_b;
01740             src_b = (uchar) qMin(tmp, 255u);
01741 
01742             src_a = qMin(src_a, dst_a);
01743             }
01744             break;
01745         case BURN_MODE: {
01746             uint tmp;
01747 
01748             tmp = (255 - dst_r) << 8;
01749             tmp /= src_r + 1;
01750             src_r = (uchar) qMin(tmp, 255u);
01751             src_r = 255 - src_r;
01752 
01753             tmp = (255 - dst_g) << 8;
01754             tmp /= src_g + 1;
01755             src_g = (uchar) qMin(tmp, 255u);
01756             src_g = 255 - src_g;
01757 
01758             tmp = (255 - dst_b) << 8;
01759             tmp /= src_b + 1;
01760             src_b = (uchar) qMin(tmp, 255u);
01761             src_b = 255 - src_b;
01762 
01763             src_a = qMin(src_a, dst_a);
01764             }
01765             break;
01766         case HARDLIGHT_MODE: {
01767             uint tmp;
01768             if (src_r > 128) {
01769                 tmp = ((int)255-dst_r) * ((int) 255 - ((src_r-128) << 1));
01770                 src_r = (uchar) qMin(255 - (tmp >> 8), 255u);
01771             } else {
01772                 tmp = (int) dst_r * ((int) src_r << 1);
01773                 src_r = (uchar) qMin(tmp >> 8, 255u);
01774             }
01775 
01776             if (src_g > 128) {
01777                 tmp = ((int)255-dst_g) * ((int) 255 - ((src_g-128) << 1));
01778                 src_g = (uchar) qMin(255 - (tmp >> 8), 255u);
01779             } else {
01780                 tmp = (int) dst_g * ((int) src_g << 1);
01781                 src_g = (uchar) qMin(tmp >> 8, 255u);
01782             }
01783 
01784             if (src_b > 128) {
01785                 tmp = ((int)255-dst_b) * ((int) 255 - ((src_b-128) << 1));
01786                 src_b = (uchar) qMin(255 - (tmp >> 8), 255u);
01787             } else {
01788                 tmp = (int) dst_b * ((int) src_b << 1);
01789                 src_b = (uchar) qMin(tmp >> 8, 255u);
01790             }
01791             src_a = qMin(src_a, dst_a);
01792             }
01793             break;
01794         case SOFTLIGHT_MODE: {
01795             uint tmpS, tmpM;
01796 
01797             tmpM = INT_MULT(dst_r, src_r);
01798             tmpS = 255 - INT_MULT((255 - dst_r), (255-src_r));
01799             src_r = INT_MULT((255 - dst_r), tmpM)
01800                 + INT_MULT(dst_r, tmpS);
01801 
01802             tmpM = INT_MULT(dst_g, src_g);
01803             tmpS = 255 - INT_MULT((255 - dst_g), (255-src_g));
01804             src_g = INT_MULT((255 - dst_g), tmpM)
01805                 + INT_MULT(dst_g, tmpS);
01806 
01807             tmpM = INT_MULT(dst_b, src_b);
01808             tmpS = 255 - INT_MULT((255 - dst_b), (255-src_b));
01809             src_b = INT_MULT((255 - dst_b), tmpM)
01810                 + INT_MULT(dst_b, tmpS);
01811 
01812             src_a = qMin(src_a, dst_a);
01813             }
01814             break;
01815         case GRAIN_EXTRACT_MODE: {
01816             int tmp;
01817             
01818             tmp = dst_r - src_r + 128;
01819             tmp = qMin(tmp, 255);
01820             tmp = qMax(tmp, 0);
01821             src_r = (uchar) tmp;
01822 
01823             tmp = dst_g - src_g + 128;
01824             tmp = qMin(tmp, 255);
01825             tmp = qMax(tmp, 0);
01826             src_g = (uchar) tmp;
01827 
01828             tmp = dst_b - src_b + 128;
01829             tmp = qMin(tmp, 255);
01830             tmp = qMax(tmp, 0);
01831             src_b = (uchar) tmp;
01832 
01833             src_a = qMin(src_a, dst_a);
01834             }
01835             break;
01836         case GRAIN_MERGE_MODE: {
01837             int tmp;
01838             
01839             tmp = dst_r + src_r - 128;
01840             tmp = qMin(tmp, 255);
01841             tmp = qMax(tmp, 0);
01842             src_r = (uchar) tmp;
01843 
01844             tmp = dst_g + src_g - 128;
01845             tmp = qMin(tmp, 255);
01846             tmp = qMax(tmp, 0);
01847             src_g = (uchar) tmp;
01848 
01849             tmp = dst_b + src_b - 128;
01850             tmp = qMin(tmp, 255);
01851             tmp = qMax(tmp, 0);
01852             src_b = (uchar) tmp;
01853 
01854             src_a = qMin(src_a, dst_a);
01855             }
01856             break;
01857     }
01858 
01859     src_a = INT_MULT(src_a, layer.opacity);
01860 
01861     // Apply the mask (if any)
01862 
01863     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01864             layer.mask_tiles[j].size() > (int)i)
01865         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01866 
01867     uchar new_r, new_g, new_b, new_a;
01868     new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
01869 
01870     float src_ratio = (float)src_a / new_a;
01871     float dst_ratio = 1.0 - src_ratio;
01872 
01873     new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
01874     new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
01875     new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
01876 
01877     if (!layer_modes[layer.mode].affect_alpha)
01878         new_a = dst_a;
01879 
01880     image.setPixel(m, n, qRgba(new_r, new_g, new_b, new_a));
01881 }
01882 
01883 
01895 void XCFImageFormat::mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01896         QImage& image, int m, int n)
01897 {
01898     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01899     image.setPixel(m, n, src);
01900 }
01901 
01902 
01914 void XCFImageFormat::mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
01915         QImage& image, int m, int n)
01916 {
01917     int src = qGray(layer.image_tiles[j][i].pixel(k, l));
01918     int dst = image.pixelIndex(m, n);
01919 
01920     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01921 
01922     if (!src_a) return; // nothing to merge
01923 
01924     switch (layer.mode) {
01925         case MULTIPLY_MODE: {
01926                 src = INT_MULT( src, dst );
01927             }
01928             break;
01929         case DIVIDE_MODE: {
01930                 src = qMin((dst * 256) / (1 + src), 255);
01931             }
01932             break;
01933         case SCREEN_MODE: {
01934                 src = 255 - INT_MULT(255 - dst, 255 - src);
01935             }
01936             break;
01937         case OVERLAY_MODE: {
01938                 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
01939             }
01940             break;
01941         case DIFFERENCE_MODE: {
01942                 src = dst > src ? dst - src : src - dst;
01943             }
01944             break;
01945         case ADDITION_MODE: {
01946                 src = add_lut(dst,src);
01947             }
01948             break;
01949         case SUBTRACT_MODE: {
01950                 src = dst > src ? dst - src : 0;
01951             }
01952             break;
01953         case DARKEN_ONLY_MODE: {
01954                 src = dst < src ? dst : src;
01955             }
01956             break;
01957         case LIGHTEN_ONLY_MODE: {
01958                 src = dst < src ? src : dst;
01959             }
01960             break;
01961         case DODGE_MODE: {
01962                 uint tmp = dst << 8;
01963                 tmp /= 256 - src;
01964                 src = (uchar) qMin(tmp, 255u);
01965             }
01966             break;
01967         case BURN_MODE: {
01968                 uint tmp = (255-dst) << 8;
01969                 tmp /= src + 1;
01970                 src = (uchar) qMin(tmp, 255u);
01971                 src = 255 - src;
01972             }
01973             break;
01974         case HARDLIGHT_MODE: {
01975                 uint tmp;
01976                 if (src > 128) {
01977                     tmp = ((int)255-dst) * ((int) 255 - ((src-128) << 1));
01978                     src = (uchar) qMin(255 - (tmp >> 8), 255u);
01979                 } else {
01980                     tmp = (int) dst * ((int) src << 1);
01981                     src = (uchar) qMin(tmp >> 8, 255u);
01982                 }
01983             }
01984             break;
01985         case SOFTLIGHT_MODE: {
01986                 uint tmpS, tmpM;
01987 
01988                 tmpM = INT_MULT(dst, src);
01989                 tmpS = 255 - INT_MULT((255-dst), (255-src));
01990                 src = INT_MULT((255 - dst), tmpM)
01991                     + INT_MULT(dst, tmpS);
01992 
01993             }
01994             break;
01995         case GRAIN_EXTRACT_MODE: {
01996                 int tmp;
01997                 
01998                 tmp = dst - src + 128;
01999                 tmp = qMin(tmp, 255);
02000                 tmp = qMax(tmp, 0);
02001 
02002                 src = (uchar) tmp;
02003             }
02004             break;
02005         case GRAIN_MERGE_MODE: {
02006                 int tmp;
02007                 
02008                 tmp = dst + src - 128;
02009                 tmp = qMin(tmp, 255);
02010                 tmp = qMax(tmp, 0);
02011 
02012                 src = (uchar) tmp;
02013             }
02014             break;
02015     }
02016 
02017     src_a = INT_MULT(src_a, layer.opacity);
02018 
02019     // Apply the mask (if any)
02020 
02021     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
02022             layer.mask_tiles[j].size() > (int)i)
02023         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02024 
02025     uchar new_a = OPAQUE_OPACITY;
02026 
02027     float src_ratio = (float)src_a / new_a;
02028     float dst_ratio = 1.0 - src_ratio;
02029 
02030     uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
02031 
02032     image.setPixel(m, n, new_g);
02033 }
02034 
02035 
02049 void XCFImageFormat::mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
02050         QImage& image, int m, int n)
02051 {
02052     QRgb src = layer.image_tiles[j][i].pixel(k, l);
02053     uchar src_a = layer.opacity;
02054     image.setPixel(m, n, qRgba(src, src_a));
02055 }
02056 
02057 
02071 void XCFImageFormat::mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
02072         QImage& image, int m, int n)
02073 {
02074     int src = qGray(layer.image_tiles[j][i].pixel(k, l));
02075     int dst = qGray(image.pixel(m, n));
02076 
02077     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02078     uchar dst_a = qAlpha(image.pixel(m, n));
02079 
02080     if (!src_a) return; // nothing to merge
02081 
02082     switch (layer.mode) {
02083         case MULTIPLY_MODE: {
02084                 src = INT_MULT(src, dst);
02085                 src_a = qMin(src_a, dst_a);
02086             }
02087             break;
02088         case DIVIDE_MODE: {
02089                 src = qMin((dst * 256) / (1 + src), 255);
02090                 src_a = qMin(src_a, dst_a);
02091             }
02092             break;
02093         case SCREEN_MODE: {
02094                 src = 255 - INT_MULT(255 - dst, 255 - src);
02095                 src_a = qMin(src_a, dst_a);
02096             }
02097             break;
02098         case OVERLAY_MODE: {
02099                 src = INT_MULT( dst, dst + INT_MULT(2 * src, 255 - dst));
02100                 src_a = qMin(src_a, dst_a);
02101             }
02102             break;
02103         case DIFFERENCE_MODE: {
02104                 src = dst > src ? dst - src : src - dst;
02105                 src_a = qMin(src_a, dst_a);
02106             }
02107             break;
02108         case ADDITION_MODE: {
02109                 src = add_lut(dst,src);
02110                 src_a = qMin(src_a, dst_a);
02111             }
02112             break;
02113         case SUBTRACT_MODE: {
02114                 src = dst > src ? dst - src : 0;
02115                 src_a = qMin(src_a, dst_a);
02116             }
02117             break;
02118         case DARKEN_ONLY_MODE: {
02119                 src = dst < src ? dst : src;
02120                 src_a = qMin(src_a, dst_a);
02121             }
02122             break;
02123         case LIGHTEN_ONLY_MODE: {
02124                 src = dst < src ? src : dst;
02125                 src_a = qMin(src_a, dst_a);
02126             }
02127             break;
02128         case DODGE_MODE: {
02129                 uint tmp = dst << 8;
02130                 tmp /= 256 - src;
02131                 src = (uchar) qMin(tmp, 255u);
02132                 src_a = qMin(src_a, dst_a);
02133             }
02134             break;
02135         case BURN_MODE: {
02136                 uint tmp = (255-dst) << 8;
02137                 tmp /= src + 1;
02138                 src = (uchar) qMin(tmp, 255u);
02139                 src = 255 - src;
02140                 src_a = qMin(src_a, dst_a);
02141             }
02142             break;
02143         case HARDLIGHT_MODE: {
02144                 uint tmp;
02145                 if (src > 128) {
02146                     tmp = ((int)255-dst) * ((int) 255 - ((src-128) << 1));
02147                     src = (uchar) qMin(255 - (tmp >> 8), 255u);
02148                 } else {
02149                     tmp = (int) dst * ((int) src << 1);
02150                     src = (uchar) qMin(tmp >> 8, 255u);
02151                 }
02152                 src_a = qMin(src_a, dst_a);
02153             }
02154             break;
02155         case SOFTLIGHT_MODE: {
02156                 uint tmpS, tmpM;
02157 
02158                 tmpM = INT_MULT(dst, src);
02159                 tmpS = 255 - INT_MULT((255 - dst), (255-src));
02160                 src = INT_MULT((255 - dst), tmpM)
02161                     + INT_MULT(dst, tmpS);
02162 
02163                 src_a = qMin(src_a, dst_a);
02164             }
02165             break;
02166         case GRAIN_EXTRACT_MODE: {
02167                 int tmp;
02168                 
02169                 tmp = dst - src + 128;
02170                 tmp = qMin(tmp, 255);
02171                 tmp = qMax(tmp, 0);
02172 
02173                 src = (uchar) tmp;
02174                 src_a = qMin(src_a, dst_a);
02175             }
02176             break;
02177         case GRAIN_MERGE_MODE: {
02178                 int tmp;
02179                 
02180                 tmp = dst + src - 128;
02181                 tmp = qMin(tmp, 255);
02182                 tmp = qMax(tmp, 0);
02183 
02184                 src = (uchar) tmp;
02185                 src_a = qMin(src_a, dst_a);
02186             }
02187             break;
02188     }
02189 
02190     src_a = INT_MULT(src_a, layer.opacity);
02191 
02192     // Apply the mask (if any)
02193     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
02194             layer.mask_tiles[j].size() > (int)i)
02195         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02196 
02197     uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
02198 
02199     float src_ratio = (float)src_a / new_a;
02200     float dst_ratio = 1.0 - src_ratio;
02201 
02202     uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
02203 
02204     if (!layer_modes[layer.mode].affect_alpha)
02205         new_a = dst_a;
02206 
02207     image.setPixel(m, n, qRgba(new_g, new_g, new_g, new_a));
02208 }
02209 
02210 
02222 void XCFImageFormat::mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
02223         QImage& image, int m, int n)
02224 {
02225     int src = layer.image_tiles[j][i].pixelIndex(k, l);
02226     image.setPixel(m, n, src);
02227 }
02228 
02229 
02241 void XCFImageFormat::mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
02242         QImage& image, int m, int n)
02243 {
02244     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
02245     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02246     src_a = INT_MULT( src_a, layer.opacity );
02247 
02248     if ( layer.apply_mask == 1 &&
02249             layer.mask_tiles.size() > (int)j &&
02250             layer.mask_tiles[j].size() > (int)i)
02251         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02252 
02253     if (src_a > 127) {
02254         src++;
02255         image.setPixel(m, n, src);
02256     }
02257 }
02258 
02259 
02273 void XCFImageFormat::mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
02274         QImage& image, int m, int n)
02275 {
02276     QRgb src = layer.image_tiles[j][i].pixel(k, l);
02277     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02278     src_a = INT_MULT(src_a, layer.opacity);
02279 
02280     // Apply the mask (if any)
02281     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
02282             layer.mask_tiles[j].size() > (int)i)
02283         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02284 
02285     // This is what appears in the GIMP window
02286     if (src_a <= 127)
02287         src_a = 0;
02288     else
02289         src_a = OPAQUE_OPACITY;
02290 
02291     image.setPixel(m, n, qRgba(src, src_a));
02292 }
02293 
02294 
02302 void XCFImageFormat::dissolveRGBPixels ( QImage& image, int x, int y )
02303 {
02304     // The apparently spurious rand() calls are to wind the random
02305     // numbers up to the same point for each tile.
02306 
02307     for (int l = 0; l < image.height(); l++) {
02308         srand(random_table[( l + y ) % RANDOM_TABLE_SIZE]);
02309 
02310         for (int k = 0; k < x; k++)
02311             rand();
02312 
02313         for (int k = 0; k < image.width(); k++) {
02314             int rand_val = rand() & 0xff;
02315             QRgb pixel = image.pixel(k, l);
02316 
02317             if (rand_val > qAlpha(pixel)) {
02318                 image.setPixel(k, l, qRgba(pixel, 0));
02319             }
02320         }
02321     }
02322 }
02323 
02324 
02334 void XCFImageFormat::dissolveAlphaPixels ( QImage& image, int x, int y )
02335 {
02336     // The apparently spurious rand() calls are to wind the random
02337     // numbers up to the same point for each tile.
02338 
02339     for (int l = 0; l < image.height(); l++) {
02340         srand( random_table[(l + y) % RANDOM_TABLE_SIZE]);
02341 
02342         for (int k = 0; k < x; k++)
02343             rand();
02344 
02345         for (int k = 0; k < image.width(); k++) {
02346             int rand_val = rand() & 0xff;
02347             uchar alpha = image.pixelIndex(k, l);
02348 
02349             if (rand_val > alpha) {
02350                 image.setPixel(k, l, 0);
02351             }
02352         }
02353     }
02354 }
02355 
02356 
02358 
02359 XCFHandler::XCFHandler()
02360 {
02361 }
02362 
02363 bool XCFHandler::canRead() const
02364 {
02365     if (canRead(device())) {
02366         setFormat("xcf");
02367         return true;
02368     }
02369     return false;
02370 }
02371 
02372 bool XCFHandler::read(QImage *image)
02373 {
02374     XCFImageFormat xcfif;
02375     return xcfif.readXCF(device(), image);
02376 }
02377 
02378 bool XCFHandler::write(const QImage &)
02379 {
02380     return false;
02381 }
02382 
02383 QByteArray XCFHandler::name() const
02384 {
02385     return "xcf";
02386 }
02387 
02388 bool XCFHandler::canRead(QIODevice *device)
02389 {
02390       if (!device) {
02391         qWarning("DDSHandler::canRead() called with no device");
02392         return false;
02393     }
02394 
02395     qint64 oldPos = device->pos();
02396 
02397     char head[8];
02398     qint64 readBytes = device->read(head, sizeof(head));
02399     if (readBytes != sizeof(head)) {
02400         if (device->isSequential()) {
02401             while (readBytes > 0)
02402                 device->ungetChar(head[readBytes-- - 1]);
02403         } else {
02404             device->seek(oldPos);
02405         }
02406         return false;
02407     }
02408 
02409     if (device->isSequential()) {
02410         while (readBytes > 0)
02411             device->ungetChar(head[readBytes-- - 1]);
02412     } else {
02413         device->seek(oldPos);
02414     }
02415 
02416     return qstrncmp(head, "gimp xcf", 8) == 0;
02417 }
02418 
02419 
02420 class XCFPlugin : public QImageIOPlugin
02421 {
02422 public:
02423     QStringList keys() const;
02424     Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
02425     QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
02426 };
02427 
02428 QStringList XCFPlugin::keys() const
02429 {
02430     return QStringList() << "xcf" << "XCF";
02431 }
02432 
02433 QImageIOPlugin::Capabilities XCFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
02434 {
02435     if (format == "xcf" || format == "XCF")
02436         return Capabilities(CanRead);
02437     if (!format.isEmpty())
02438         return 0;
02439     if (!device->isOpen())
02440         return 0;
02441 
02442     Capabilities cap;
02443     if (device->isReadable() && XCFHandler::canRead(device))
02444         cap |= CanRead;
02445     return cap;
02446 }
02447 
02448 QImageIOHandler *XCFPlugin::create(QIODevice *device, const QByteArray &format) const
02449 {
02450     QImageIOHandler *handler = new XCFHandler;
02451     handler->setDevice(device);
02452     handler->setFormat(format);
02453     return handler;
02454 }
02455 
02456 Q_EXPORT_STATIC_PLUGIN(XCFPlugin)
02457 Q_EXPORT_PLUGIN2(xcf,XCFPlugin)

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal