• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 API Reference
  • 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         //kDebug(399) << "IMAGE: height=" << xcf_image.height << ", width=" << xcf_image.width;
00499         //kDebug(399) << "LAYER: height=" << layer.height << ", width=" << layer.width;
00500         //kDebug(399) << "LAYER: rows=" << layer.nrows << ", columns=" << layer.ncols;
00501         
00502         // SANITY CHECK: Catch corrupted XCF image file where the width or height
00503         // of a tile is reported are bogus. See Bug# 234030.
00504         if (layer.height > xcf_image.height || layer.width > xcf_image.width)
00505               return false;
00506        
00507     layer.image_tiles.resize(layer.nrows);
00508 
00509     if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00510         layer.alpha_tiles.resize(layer.nrows);
00511 
00512     if (layer.mask_offset != 0)
00513         layer.mask_tiles.resize(layer.nrows);
00514 
00515     for (uint j = 0; j < layer.nrows; j++) {
00516         layer.image_tiles[j].resize(layer.ncols);
00517 
00518         if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00519             layer.alpha_tiles[j].resize(layer.ncols);
00520 
00521         if (layer.mask_offset != 0)
00522             layer.mask_tiles[j].resize(layer.ncols);
00523     }
00524 
00525     for (uint j = 0; j < layer.nrows; j++) {
00526         for (uint i = 0; i < layer.ncols; i++) {
00527 
00528             uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
00529                     ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
00530 
00531             uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
00532                     ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
00533 
00534             // Try to create the most appropriate QImage (each GIMP layer
00535             // type is treated slightly differently)
00536 
00537             switch (layer.type) {
00538                 case RGB_GIMAGE:
00539                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_RGB32);
00540                     layer.image_tiles[j][i].setNumColors(0);
00541                     if( layer.image_tiles[j][i].isNull())
00542                         return false;
00543                     break;
00544 
00545                 case RGBA_GIMAGE:
00546                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_ARGB32);
00547                     layer.image_tiles[j][i].setNumColors(0);
00548                     if( layer.image_tiles[j][i].isNull())
00549                         return false;
00550                     break;
00551 
00552                 case GRAY_GIMAGE:
00553                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00554                     layer.image_tiles[j][i].setNumColors(256);
00555                     if( layer.image_tiles[j][i].isNull())
00556                         return false;
00557                     setGrayPalette(layer.image_tiles[j][i]);
00558                     break;
00559 
00560                 case GRAYA_GIMAGE:
00561                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00562                     layer.image_tiles[j][i].setNumColors(256);
00563                     if( layer.image_tiles[j][i].isNull())
00564                         return false;
00565                     setGrayPalette(layer.image_tiles[j][i]);
00566 
00567                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00568                     layer.alpha_tiles[j][i].setNumColors(256);
00569                     if( layer.alpha_tiles[j][i].isNull())
00570                         return false;
00571                     setGrayPalette(layer.alpha_tiles[j][i]);
00572                     break;
00573 
00574                 case INDEXED_GIMAGE:
00575                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00576                     layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
00577                     if( layer.image_tiles[j][i].isNull())
00578                         return false;
00579                     setPalette(xcf_image, layer.image_tiles[j][i]);
00580                     break;
00581 
00582                 case INDEXEDA_GIMAGE:
00583                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00584                     layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
00585                     if( layer.image_tiles[j][i].isNull())
00586                         return false;
00587                     setPalette(xcf_image, layer.image_tiles[j][i]);
00588 
00589                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00590                     layer.alpha_tiles[j][i].setNumColors(256);
00591                     if( layer.alpha_tiles[j][i].isNull())
00592                         return false;
00593                     setGrayPalette(layer.alpha_tiles[j][i]);
00594             }
00595 
00596             if (layer.mask_offset != 0) {
00597                 layer.mask_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00598                 layer.mask_tiles[j][i].setNumColors(256);
00599                 if( layer.mask_tiles[j][i].isNull())
00600                     return false;
00601                 setGrayPalette(layer.mask_tiles[j][i]);
00602             }
00603         }
00604     }
00605     return true;
00606 }
00607 
00608 
00615 void XCFImageFormat::setGrayPalette(QImage& image)
00616 {
00617     if (grayTable.isEmpty()) {
00618         grayTable.resize(256);
00619 
00620         for (int i = 0; i < 256; i++)
00621             grayTable[i] = qRgb(i, i, i);
00622     }
00623 
00624     image.setColorTable(grayTable);
00625 }
00626 
00627 
00633 void XCFImageFormat::setPalette(XCFImage& xcf_image, QImage& image)
00634 {
00635     Q_ASSERT (xcf_image.num_colors == xcf_image.palette.size());
00636 
00637     image.setColorTable(xcf_image.palette);
00638 }
00639 
00640 
00648 void XCFImageFormat::assignImageBytes(Layer& layer, uint i, uint j)
00649 {
00650     QImage &image = layer.image_tiles[j][i];
00651     uchar* tile = layer.tile;
00652     const int width = image.width();
00653     const int height = image.height();
00654     const int bytesPerLine = image.bytesPerLine();
00655     uchar *bits = image.bits();
00656 
00657     switch (layer.type) {
00658         case RGB_GIMAGE:
00659             for (int y = 0; y < height; y++) {
00660                 QRgb *dataPtr = (QRgb *) (bits + y * bytesPerLine);
00661                 for (int x = 0; x < width; x++) {
00662                     *dataPtr++ = qRgb(tile[0], tile[1], tile[2]);
00663                     tile += sizeof(QRgb);
00664                 }
00665             }
00666             break;
00667 
00668         case RGBA_GIMAGE:
00669             for (int y = 0; y < height; y++) {
00670                 QRgb *dataPtr = (QRgb *) (bits + y * bytesPerLine);
00671                 for (int x = 0; x < width; x++) {
00672                     *dataPtr++ =    qRgba(tile[0], tile[1], tile[2], tile[3]);
00673                     tile += sizeof(QRgb);
00674                 }
00675             }
00676             break;
00677 
00678         case GRAY_GIMAGE:
00679         case INDEXED_GIMAGE:
00680             for (int y = 0; y < height; y++) {
00681                 uchar *dataPtr = bits + y * bytesPerLine;
00682                 for (int x = 0; x < width; x++) {
00683                     *dataPtr++ = tile[0];
00684                     tile += sizeof(QRgb);
00685                 }
00686             }
00687             break;
00688 
00689         case GRAYA_GIMAGE:
00690         case INDEXEDA_GIMAGE:
00691             for (int y = 0; y < height; y++) {
00692                 uchar *dataPtr = bits + y * bytesPerLine;
00693                 uchar *alphaPtr = layer.alpha_tiles[j][i].scanLine(y);
00694                 for (int x = 0; x < width; x++) {
00695 
00696                 // The "if" here should not be necessary, but apparently there
00697                 // are some cases where the image can contain larger indices
00698                 // than there are colors in the palette. (A bug in The GIMP?)
00699 
00700                     if (tile[0] < image.numColors())
00701                         *dataPtr = tile[0];
00702 
00703                     *alphaPtr = tile[1];
00704                     dataPtr += 1;
00705                     alphaPtr += 1;
00706                     tile += sizeof(QRgb);
00707                 }
00708             }
00709             break;
00710     }
00711 }
00712 
00713 
00722 bool XCFImageFormat::loadHierarchy(QDataStream& xcf_io, Layer& layer)
00723 {
00724     qint32 width;
00725     qint32 height;
00726     qint32 bpp;
00727     quint32 offset;
00728 
00729     xcf_io >> width >> height >> bpp >> offset;
00730 
00731     // GIMP stores images in a "mipmap"-like format (multiple levels of
00732     // increasingly lower resolution). Only the top level is used here,
00733     // however.
00734 
00735     quint32 junk;
00736     do {
00737         xcf_io >> junk;
00738 
00739         if (xcf_io.device()->atEnd()) {
00740             kDebug(399) << "XCF: read failure on layer " << layer.name << " level offsets";
00741             return false;
00742         }
00743     } while (junk != 0);
00744 
00745     qint64 saved_pos = xcf_io.device()->pos();
00746 
00747     xcf_io.device()->seek(offset);
00748     if (!loadLevel(xcf_io, layer, bpp))
00749         return false;
00750 
00751     xcf_io.device()->seek(saved_pos);
00752     return true;
00753 }
00754 
00755 
00764 bool XCFImageFormat::loadLevel(QDataStream& xcf_io, Layer& layer, qint32 bpp)
00765 {
00766     qint32 width;
00767     qint32 height;
00768     quint32 offset;
00769 
00770     xcf_io >> width >> height >> offset;
00771 
00772     if (offset == 0)
00773         return true;
00774 
00775     for (uint j = 0; j < layer.nrows; j++) {
00776         for (uint i = 0; i < layer.ncols; i++) {
00777 
00778             if (offset == 0) {
00779                 kDebug(399) << "XCF: incorrect number of tiles in layer " << layer.name;
00780                 return false;
00781             }
00782 
00783             qint64 saved_pos = xcf_io.device()->pos();
00784             quint32 offset2;
00785             xcf_io >> offset2;
00786 
00787             // Evidently, RLE can occasionally expand a tile instead of compressing it!
00788 
00789             if (offset2 == 0)
00790                 offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
00791 
00792             xcf_io.device()->seek(offset);
00793             int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
00794 
00795             if (!loadTileRLE(xcf_io, layer.tile, size, offset2 - offset, bpp))
00796                 return false;
00797 
00798             // The bytes in the layer tile are juggled differently depending on
00799             // the target QImage. The caller has set layer.assignBytes to the
00800             // appropriate routine.
00801 
00802             layer.assignBytes(layer, i, j);
00803 
00804             xcf_io.device()->seek(saved_pos);
00805             xcf_io >> offset;
00806         }
00807     }
00808 
00809     return true;
00810 }
00811 
00812 
00819 bool XCFImageFormat::loadMask(QDataStream& xcf_io, Layer& layer)
00820 {
00821     qint32 width;
00822     qint32 height;
00823     char* name;
00824 
00825     xcf_io >> width >> height >> name;
00826 
00827     delete name;
00828 
00829     if (!loadChannelProperties(xcf_io, layer))
00830         return false;
00831 
00832     quint32 hierarchy_offset;
00833     xcf_io >> hierarchy_offset;
00834 
00835     xcf_io.device()->seek(hierarchy_offset);
00836     layer.assignBytes = assignMaskBytes;
00837 
00838     if (!loadHierarchy(xcf_io, layer))
00839         return false;
00840 
00841     return true;
00842 }
00843 
00844 
00868 bool XCFImageFormat::loadTileRLE(QDataStream& xcf_io, uchar* tile, int image_size,
00869         int data_length, qint32 bpp)
00870 {
00871     uchar* data;
00872 
00873     uchar* xcfdata;
00874     uchar* xcfodata;
00875     uchar* xcfdatalimit;
00876 
00877     if (data_length < 0 || data_length > int(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5)) {
00878         kDebug(399) << "XCF: invalid tile data length" << data_length;
00879         return false;
00880     }
00881 
00882     xcfdata = xcfodata = new uchar[data_length];
00883 
00884     xcf_io.readRawData((char*)xcfdata, data_length);
00885 
00886     if (!xcf_io.device()->isOpen()) {
00887         delete[] xcfodata;
00888         kDebug(399) << "XCF: read failure on tile";
00889         return false;
00890     }
00891 
00892     xcfdatalimit = &xcfodata[data_length - 1];
00893 
00894     for (int i = 0; i < bpp; ++i) {
00895 
00896         data = tile + i;
00897 
00898         int count = 0;
00899         int size = image_size;
00900 
00901         while (size > 0) {
00902             if (xcfdata > xcfdatalimit)
00903                 goto bogus_rle;
00904 
00905             uchar val = *xcfdata++;
00906             uint length = val;
00907 
00908             if (length >= 128) {
00909                 length = 255 - (length - 1);
00910                 if (length == 128) {
00911                     if (xcfdata >= xcfdatalimit)
00912                         goto bogus_rle;
00913 
00914                     length = (*xcfdata << 8) + xcfdata[1];
00915 
00916                     xcfdata += 2;
00917                 }
00918 
00919                 count += length;
00920                 size -= length;
00921 
00922                 if (size < 0)
00923                     goto bogus_rle;
00924 
00925                 if (&xcfdata[length - 1] > xcfdatalimit)
00926                     goto bogus_rle;
00927 
00928                 while (length-- > 0) {
00929                     *data = *xcfdata++;
00930                     data += sizeof(QRgb);
00931                 }
00932             } else {
00933                 length += 1;
00934                 if (length == 128) {
00935                     if (xcfdata >= xcfdatalimit)
00936                         goto bogus_rle;
00937 
00938                     length = (*xcfdata << 8) + xcfdata[1];
00939                     xcfdata += 2;
00940                 }
00941 
00942                 count += length;
00943                 size -= length;
00944 
00945                 if (size < 0)
00946                     goto bogus_rle;
00947 
00948                 if (xcfdata > xcfdatalimit)
00949                     goto bogus_rle;
00950 
00951                 val = *xcfdata++;
00952 
00953                 while (length-- > 0) {
00954                     *data = val;
00955                     data += sizeof(QRgb);
00956                 }
00957             }
00958         }
00959     }
00960 
00961     delete[] xcfodata;
00962     return true;
00963 
00964 bogus_rle:
00965 
00966     kDebug(399) << "The run length encoding could not be decoded properly";
00967     delete[] xcfodata;
00968     return false;
00969 }
00970 
00971 
00979 bool XCFImageFormat::loadChannelProperties(QDataStream& xcf_io, Layer& layer)
00980 {
00981     while (true) {
00982         PropType type;
00983         QByteArray bytes;
00984 
00985         if (!loadProperty(xcf_io, type, bytes)) {
00986             kDebug(399) << "XCF: error loading channel properties";
00987             return false;
00988         }
00989 
00990         QDataStream property(bytes);
00991 
00992         switch (type) {
00993             case PROP_END:
00994                 return true;
00995 
00996             case PROP_OPACITY:
00997                 property >> layer.mask_channel.opacity;
00998                 break;
00999 
01000             case PROP_VISIBLE:
01001                 property >> layer.mask_channel.visible;
01002                 break;
01003 
01004             case PROP_SHOW_MASKED:
01005                 property >> layer.mask_channel.show_masked;
01006                 break;
01007 
01008             case PROP_COLOR:
01009                 property >> layer.mask_channel.red >> layer.mask_channel.green
01010                         >> layer.mask_channel.blue;
01011                 break;
01012 
01013             case PROP_TATTOO:
01014                 property >> layer.mask_channel.tattoo;
01015                 break;
01016 
01017             default:
01018                 kDebug(399) << "XCF: unimplemented channel property " << type
01019                         << ", size " << bytes.size() << endl;
01020         }
01021     }
01022 }
01023 
01024 
01031 void XCFImageFormat::assignMaskBytes(Layer& layer, uint i, uint j)
01032 {
01033     QImage &image = layer.mask_tiles[j][i];
01034     uchar* tile = layer.tile;
01035     const int width = image.width();
01036     const int height = image.height();
01037     const int bytesPerLine = image.bytesPerLine();
01038     uchar *bits = image.bits();
01039 
01040     for (int y = 0; y < height; y++) {
01041         uchar *dataPtr = bits + y * bytesPerLine;
01042         for (int x = 0; x < width; x++) {
01043             *dataPtr++ = tile[0];
01044             tile += sizeof(QRgb);
01045         }
01046     }
01047 }
01048 
01049 
01078 bool XCFImageFormat::initializeImage(XCFImage& xcf_image)
01079 {
01080     // (Aliases to make the code look a little better.)
01081     Layer& layer(xcf_image.layer);
01082     QImage& image(xcf_image.image);
01083 
01084     switch (layer.type) {
01085         case RGB_GIMAGE:
01086             if (layer.opacity == OPAQUE_OPACITY) {
01087                 image = QImage( xcf_image.width, xcf_image.height, QImage::Format_RGB32);
01088                 if( image.isNull())
01089                     return false;
01090                 image.fill(qRgb(255, 255, 255));
01091                 break;
01092             } // else, fall through to 32-bit representation
01093 
01094         case RGBA_GIMAGE:
01095             image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01096             if( image.isNull())
01097                 return false;
01098             image.fill(qRgba(255, 255, 255, 0));
01099             break;
01100 
01101         case GRAY_GIMAGE:
01102             if (layer.opacity == OPAQUE_OPACITY) {
01103                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01104                 image.setNumColors(256);
01105                 if( image.isNull())
01106                     return false;
01107                 setGrayPalette(image);
01108                 image.fill(255);
01109                 break;
01110             } // else, fall through to 32-bit representation
01111 
01112         case GRAYA_GIMAGE:
01113             image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01114             if( image.isNull())
01115                 return false;
01116             image.fill(qRgba(255, 255, 255, 0));
01117             break;
01118 
01119         case INDEXED_GIMAGE:
01120             // As noted in the table above, there are quite a few combinations
01121             // which are possible with indexed images, depending on the
01122             // presence of transparency (note: not translucency, which is not
01123             // supported by The GIMP for indexed images) and the number of
01124             // individual colors.
01125 
01126             // Note: Qt treats a bitmap with a Black and White color palette
01127             // as a mask, so only the "on" bits are drawn, regardless of the
01128             // order color table entries. Otherwise (i.e., at least one of the
01129             // color table entries is not black or white), it obeys the one-
01130             // or two-color palette. Have to ask about this...
01131 
01132             if (xcf_image.num_colors <= 2) {
01133                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
01134                 image.setNumColors(xcf_image.num_colors);
01135                 if( image.isNull())
01136                     return false;
01137                 image.fill(0);
01138                 setPalette(xcf_image, image);
01139             } else if (xcf_image.num_colors <= 256) {
01140                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01141                 image.setNumColors(xcf_image.num_colors);
01142                 if( image.isNull())
01143                     return false;
01144                 image.fill(0);
01145                 setPalette(xcf_image, image);
01146             }
01147             break;
01148 
01149         case INDEXEDA_GIMAGE:
01150             if (xcf_image.num_colors == 1) {
01151                 // Plenty(!) of room to add a transparent color
01152                 xcf_image.num_colors++;
01153                 xcf_image.palette.resize(xcf_image.num_colors);
01154                 xcf_image.palette[1] = xcf_image.palette[0];
01155                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01156 
01157                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
01158                 image.setNumColors(xcf_image.num_colors);
01159                 if( image.isNull())
01160                     return false;
01161                 image.fill(0);
01162                 setPalette(xcf_image, image);
01163             } else if (xcf_image.num_colors < 256) {
01164                 // Plenty of room to add a transparent color
01165                 xcf_image.num_colors++;
01166                 xcf_image.palette.resize(xcf_image.num_colors);
01167                 for (int c = xcf_image.num_colors - 1; c >= 1; c--)
01168                     xcf_image.palette[c] = xcf_image.palette[c - 1];
01169 
01170                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01171                 image = QImage( xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01172                 image.setNumColors(xcf_image.num_colors);
01173                 if( image.isNull())
01174                     return false;
01175                 image.fill(0);
01176                 setPalette(xcf_image, image);
01177             } else {
01178                 // No room for a transparent color, so this has to be promoted to
01179                 // true color. (There is no equivalent PNG representation output
01180                 // from The GIMP as of v1.2.)
01181                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01182                 if( image.isNull())
01183                     return false;
01184                 image.fill(qRgba(255, 255, 255, 0));
01185             }
01186             break;
01187     }
01188 
01189     image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER));
01190     image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER));
01191     return true;
01192 }
01193 
01194 
01200 void XCFImageFormat::copyLayerToImage(XCFImage& xcf_image)
01201 {
01202     Layer& layer(xcf_image.layer);
01203     QImage& image(xcf_image.image);
01204     PixelCopyOperation copy = 0;
01205 
01206     switch (layer.type) {
01207         case RGB_GIMAGE:
01208         case RGBA_GIMAGE:
01209             copy = copyRGBToRGB;
01210             break;
01211         case GRAY_GIMAGE:
01212             if (layer.opacity == OPAQUE_OPACITY)
01213                 copy = copyGrayToGray;
01214             else
01215                 copy = copyGrayToRGB;
01216             break;
01217         case GRAYA_GIMAGE:
01218             copy = copyGrayAToRGB;
01219             break;
01220         case INDEXED_GIMAGE:
01221             copy = copyIndexedToIndexed;
01222             break;
01223         case INDEXEDA_GIMAGE:
01224             if (xcf_image.image.depth() <= 8)
01225                 copy = copyIndexedAToIndexed;
01226             else
01227                 copy = copyIndexedAToRGB;
01228     }
01229 
01230     if (!copy) {
01231         return;
01232     }
01233 
01234     // For each tile...
01235 
01236     for (uint j = 0; j < layer.nrows; j++) {
01237         uint y = j * TILE_HEIGHT;
01238 
01239         for (uint i = 0; i < layer.ncols; i++) {
01240             uint x = i * TILE_WIDTH;
01241 
01242             // This seems the best place to apply the dissolve because it
01243             // depends on the global position of each tile's
01244             // pixels. Apparently it's the only mode which can apply to a
01245             // single layer.
01246 
01247             if (layer.mode == DISSOLVE_MODE) {
01248                 if (!random_table_initialized) {
01249                     initializeRandomTable();
01250                     random_table_initialized = true;
01251                 }
01252                 if (layer.type == RGBA_GIMAGE)
01253                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01254 
01255                 else if (layer.type == GRAYA_GIMAGE)
01256                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01257             }
01258 
01259             // Shortcut for common case
01260             if (copy == copyRGBToRGB && layer.apply_mask != 1) {
01261                 QPainter painter(&image);
01262                 painter.setOpacity(layer.opacity / 255.0);
01263                 painter.setCompositionMode(QPainter::CompositionMode_Source);
01264                 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
01265                 continue;
01266             }
01267 
01268             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01269                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01270 
01271                     int m = x + k + layer.x_offset;
01272                     int n = y + l + layer.y_offset;
01273 
01274                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01275                         continue;
01276 
01277                     (*copy)(layer, i, j, k, l, image, m, n);
01278                 }
01279             }
01280         }
01281     }
01282 }
01283 
01284 
01298 void XCFImageFormat::copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01299         QImage& image, int m, int n)
01300 {
01301     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01302     uchar src_a = layer.opacity;
01303 
01304     if (layer.type == RGBA_GIMAGE)
01305         src_a = INT_MULT(src_a, qAlpha(src));
01306 
01307     // Apply the mask (if any)
01308 
01309     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01310             layer.mask_tiles[j].size() > (int)i)
01311         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01312 
01313     image.setPixel(m, n, qRgba(src, src_a));
01314 }
01315 
01316 
01328 void XCFImageFormat::copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01329         QImage& image, int m, int n)
01330 {
01331     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01332     image.setPixel(m, n, src);
01333 }
01334 
01335 
01349 void XCFImageFormat::copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
01350         QImage& image, int m, int n)
01351 {
01352     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01353     uchar src_a = layer.opacity;
01354     image.setPixel(m, n, qRgba(src, src_a));
01355 }
01356 
01357 
01371 void XCFImageFormat::copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
01372                       QImage& image, int m, int n)
01373 {
01374     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01375     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01376     src_a = INT_MULT(src_a, layer.opacity);
01377 
01378     // Apply the mask (if any)
01379 
01380     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01381             layer.mask_tiles[j].size() > (int)i)
01382         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01383 
01384     image.setPixel(m, n, qRgba(src, src_a));
01385 }
01386 
01387 
01399 void XCFImageFormat::copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
01400         QImage& image, int m, int n)
01401 {
01402     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01403     image.setPixel(m, n, src);
01404 }
01405 
01406 
01418 void XCFImageFormat::copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
01419         QImage& image, int m, int n)
01420 {
01421     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
01422     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01423     src_a = INT_MULT(src_a, layer.opacity);
01424 
01425     if (layer.apply_mask == 1 &&
01426             layer.mask_tiles.size() > (int)j &&
01427             layer.mask_tiles[j].size() > (int)i)
01428         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01429 
01430     if (src_a > 127)
01431         src++;
01432     else
01433         src = 0;
01434 
01435 image.setPixel(m, n, src);
01436 }
01437 
01438 
01452 void XCFImageFormat::copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
01453         QImage& image, int m, int n)
01454 {
01455     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01456     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01457     src_a = INT_MULT(src_a, layer.opacity);
01458 
01459     // Apply the mask (if any)
01460     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01461             layer.mask_tiles[j].size() > (int)i)
01462         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01463 
01464     // This is what appears in the GIMP window
01465     if (src_a <= 127)
01466         src_a = 0;
01467     else
01468         src_a = OPAQUE_OPACITY;
01469 
01470     image.setPixel(m, n, qRgba(src, src_a));
01471 }
01472 
01473 
01478 void XCFImageFormat::mergeLayerIntoImage(XCFImage& xcf_image)
01479 {
01480     Layer& layer(xcf_image.layer);
01481     QImage& image(xcf_image.image);
01482 
01483     PixelMergeOperation merge = 0;
01484 
01485     if (!layer.opacity) return; // don't bother doing anything
01486 
01487     switch (layer.type) {
01488         case RGB_GIMAGE:
01489         case RGBA_GIMAGE:
01490             merge = mergeRGBToRGB;
01491             break;
01492         case GRAY_GIMAGE:
01493             if (layer.opacity == OPAQUE_OPACITY)
01494                 merge = mergeGrayToGray;
01495             else
01496                 merge = mergeGrayToRGB;
01497             break;
01498         case GRAYA_GIMAGE:
01499             if (xcf_image.image.depth() <= 8)
01500                 merge = mergeGrayAToGray;
01501             else
01502                 merge = mergeGrayAToRGB;
01503             break;
01504         case INDEXED_GIMAGE:
01505             merge = mergeIndexedToIndexed;
01506             break;
01507         case INDEXEDA_GIMAGE:
01508             if (xcf_image.image.depth() <= 8)
01509                 merge = mergeIndexedAToIndexed;
01510             else
01511                 merge = mergeIndexedAToRGB;
01512     }
01513 
01514     if (!merge) {
01515         return;
01516     }
01517 
01518     for (uint j = 0; j < layer.nrows; j++) {
01519         uint y = j * TILE_HEIGHT;
01520 
01521         for (uint i = 0; i < layer.ncols; i++) {
01522             uint x = i * TILE_WIDTH;
01523 
01524             // This seems the best place to apply the dissolve because it
01525             // depends on the global position of each tile's
01526             // pixels. Apparently it's the only mode which can apply to a
01527             // single layer.
01528 
01529             if (layer.mode == DISSOLVE_MODE) {
01530                 if (!random_table_initialized) {
01531                     initializeRandomTable();
01532                     random_table_initialized = true;
01533                 }
01534                 if (layer.type == RGBA_GIMAGE)
01535                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01536 
01537                 else if (layer.type == GRAYA_GIMAGE)
01538                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01539             }
01540 
01541             // Shortcut for common case
01542             if (merge == mergeRGBToRGB && layer.apply_mask != 1
01543                 && layer.mode == NORMAL_MODE) {
01544                 QPainter painter(&image);
01545                 painter.setOpacity(layer.opacity / 255.0);
01546                 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
01547                 painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
01548                 continue;
01549             }
01550 
01551             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01552                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01553 
01554                     int m = x + k + layer.x_offset;
01555                     int n = y + l + layer.y_offset;
01556 
01557                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01558                         continue;
01559 
01560                     (*merge)(layer, i, j, k, l, image, m, n);
01561                 }
01562             }
01563         }
01564     }
01565 }
01566 
01567 
01581 void XCFImageFormat::mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01582         QImage& image, int m, int n)
01583 {
01584     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01585     QRgb dst = image.pixel(m, n);
01586 
01587     uchar src_r = qRed(src);
01588     uchar src_g = qGreen(src);
01589     uchar src_b = qBlue(src);
01590     uchar src_a = qAlpha(src);
01591 
01592     uchar dst_r = qRed(dst);
01593     uchar dst_g = qGreen(dst);
01594     uchar dst_b = qBlue(dst);
01595     uchar dst_a = qAlpha(dst);
01596 
01597     if (!src_a) return; // nothing to merge
01598 
01599     switch (layer.mode) {
01600         case MULTIPLY_MODE: {
01601             src_r = INT_MULT(src_r, dst_r);
01602             src_g = INT_MULT(src_g, dst_g);
01603             src_b = INT_MULT(src_b, dst_b);
01604             src_a = qMin(src_a, dst_a);
01605             }
01606             break;
01607         case DIVIDE_MODE: {
01608             src_r = qMin((dst_r * 256) / (1 + src_r), 255);
01609             src_g = qMin((dst_g * 256) / (1 + src_g), 255);
01610             src_b = qMin((dst_b * 256) / (1 + src_b), 255);
01611             src_a = qMin(src_a, dst_a);
01612             }
01613             break;
01614         case SCREEN_MODE: {
01615             src_r = 255 - INT_MULT(255 - dst_r, 255 - src_r);
01616             src_g = 255 - INT_MULT(255 - dst_g, 255 - src_g);
01617             src_b = 255 - INT_MULT(255 - dst_b, 255 - src_b);
01618             src_a = qMin(src_a, dst_a);
01619             }
01620             break;
01621         case OVERLAY_MODE: {
01622             src_r = INT_MULT(dst_r, dst_r + INT_MULT(2 * src_r, 255 - dst_r));
01623             src_g = INT_MULT(dst_g, dst_g + INT_MULT(2 * src_g, 255 - dst_g));
01624             src_b = INT_MULT(dst_b, dst_b + INT_MULT(2 * src_b, 255 - dst_b));
01625             src_a = qMin(src_a, dst_a);
01626             }
01627             break;
01628         case DIFFERENCE_MODE: {
01629             src_r = dst_r > src_r ? dst_r - src_r : src_r - dst_r;
01630             src_g = dst_g > src_g ? dst_g - src_g : src_g - dst_g;
01631             src_b = dst_b > src_b ? dst_b - src_b : src_b - dst_b;
01632             src_a = qMin(src_a, dst_a);
01633             }
01634             break;
01635         case ADDITION_MODE: {
01636               src_r = add_lut(dst_r,src_r);
01637               src_g = add_lut(dst_g,src_g);
01638               src_b = add_lut(dst_b,src_b);
01639               src_a = qMin(src_a, dst_a);
01640             }
01641             break;
01642         case SUBTRACT_MODE: {
01643             src_r = dst_r > src_r ? dst_r - src_r : 0;
01644             src_g = dst_g > src_g ? dst_g - src_g : 0;
01645             src_b = dst_b > src_b ? dst_b - src_b : 0;
01646             src_a = qMin(src_a, dst_a);
01647             }
01648             break;
01649         case DARKEN_ONLY_MODE: {
01650             src_r = dst_r < src_r ? dst_r : src_r;
01651             src_g = dst_g < src_g ? dst_g : src_g;
01652             src_b = dst_b < src_b ? dst_b : src_b;
01653             src_a = qMin( src_a, dst_a );
01654             }
01655             break;
01656         case LIGHTEN_ONLY_MODE: {
01657             src_r = dst_r < src_r ? src_r : dst_r;
01658             src_g = dst_g < src_g ? src_g : dst_g;
01659             src_b = dst_b < src_b ? src_b : dst_b;
01660             src_a = qMin(src_a, dst_a);
01661             }
01662             break;
01663         case HUE_MODE: {
01664             uchar new_r = dst_r;
01665             uchar new_g = dst_g;
01666             uchar new_b = dst_b;
01667 
01668             RGBTOHSV(src_r, src_g, src_b);
01669             RGBTOHSV(new_r, new_g, new_b);
01670 
01671             new_r = src_r;
01672 
01673             HSVTORGB(new_r, new_g, new_b);
01674 
01675             src_r = new_r;
01676             src_g = new_g;
01677             src_b = new_b;
01678             src_a = qMin( src_a, dst_a );
01679             }
01680             break;
01681         case SATURATION_MODE: {
01682             uchar new_r = dst_r;
01683             uchar new_g = dst_g;
01684             uchar new_b = dst_b;
01685 
01686             RGBTOHSV(src_r, src_g, src_b);
01687             RGBTOHSV(new_r, new_g, new_b);
01688 
01689             new_g = src_g;
01690 
01691             HSVTORGB(new_r, new_g, new_b);
01692 
01693             src_r = new_r;
01694             src_g = new_g;
01695             src_b = new_b;
01696             src_a = qMin(src_a, dst_a);
01697             }
01698             break;
01699         case VALUE_MODE: {
01700             uchar new_r = dst_r;
01701             uchar new_g = dst_g;
01702             uchar new_b = dst_b;
01703 
01704             RGBTOHSV(src_r, src_g, src_b);
01705             RGBTOHSV(new_r, new_g, new_b);
01706 
01707             new_b = src_b;
01708 
01709             HSVTORGB(new_r, new_g, new_b);
01710 
01711             src_r = new_r;
01712             src_g = new_g;
01713             src_b = new_b;
01714             src_a = qMin(src_a, dst_a);
01715             }
01716             break;
01717         case COLOR_MODE: {
01718             uchar new_r = dst_r;
01719             uchar new_g = dst_g;
01720             uchar new_b = dst_b;
01721 
01722             RGBTOHLS(src_r, src_g, src_b);
01723             RGBTOHLS(new_r, new_g, new_b);
01724 
01725             new_r = src_r;
01726             new_b = src_b;
01727 
01728             HLSTORGB(new_r, new_g, new_b);
01729 
01730             src_r = new_r;
01731             src_g = new_g;
01732             src_b = new_b;
01733             src_a = qMin(src_a, dst_a);
01734             }
01735             break;
01736         case DODGE_MODE: {
01737             uint tmp;
01738 
01739             tmp = dst_r << 8;
01740             tmp /= 256 - src_r;
01741             src_r = (uchar) qMin(tmp, 255u);
01742 
01743             tmp = dst_g << 8;
01744             tmp /= 256 - src_g;
01745             src_g = (uchar) qMin(tmp, 255u);
01746 
01747             tmp = dst_b << 8;
01748             tmp /= 256 - src_b;
01749             src_b = (uchar) qMin(tmp, 255u);
01750 
01751             src_a = qMin(src_a, dst_a);
01752             }
01753             break;
01754         case BURN_MODE: {
01755             uint tmp;
01756 
01757             tmp = (255 - dst_r) << 8;
01758             tmp /= src_r + 1;
01759             src_r = (uchar) qMin(tmp, 255u);
01760             src_r = 255 - src_r;
01761 
01762             tmp = (255 - dst_g) << 8;
01763             tmp /= src_g + 1;
01764             src_g = (uchar) qMin(tmp, 255u);
01765             src_g = 255 - src_g;
01766 
01767             tmp = (255 - dst_b) << 8;
01768             tmp /= src_b + 1;
01769             src_b = (uchar) qMin(tmp, 255u);
01770             src_b = 255 - src_b;
01771 
01772             src_a = qMin(src_a, dst_a);
01773             }
01774             break;
01775         case HARDLIGHT_MODE: {
01776             uint tmp;
01777             if (src_r > 128) {
01778                 tmp = ((int)255-dst_r) * ((int) 255 - ((src_r-128) << 1));
01779                 src_r = (uchar) qMin(255 - (tmp >> 8), 255u);
01780             } else {
01781                 tmp = (int) dst_r * ((int) src_r << 1);
01782                 src_r = (uchar) qMin(tmp >> 8, 255u);
01783             }
01784 
01785             if (src_g > 128) {
01786                 tmp = ((int)255-dst_g) * ((int) 255 - ((src_g-128) << 1));
01787                 src_g = (uchar) qMin(255 - (tmp >> 8), 255u);
01788             } else {
01789                 tmp = (int) dst_g * ((int) src_g << 1);
01790                 src_g = (uchar) qMin(tmp >> 8, 255u);
01791             }
01792 
01793             if (src_b > 128) {
01794                 tmp = ((int)255-dst_b) * ((int) 255 - ((src_b-128) << 1));
01795                 src_b = (uchar) qMin(255 - (tmp >> 8), 255u);
01796             } else {
01797                 tmp = (int) dst_b * ((int) src_b << 1);
01798                 src_b = (uchar) qMin(tmp >> 8, 255u);
01799             }
01800             src_a = qMin(src_a, dst_a);
01801             }
01802             break;
01803         case SOFTLIGHT_MODE: {
01804             uint tmpS, tmpM;
01805 
01806             tmpM = INT_MULT(dst_r, src_r);
01807             tmpS = 255 - INT_MULT((255 - dst_r), (255-src_r));
01808             src_r = INT_MULT((255 - dst_r), tmpM)
01809                 + INT_MULT(dst_r, tmpS);
01810 
01811             tmpM = INT_MULT(dst_g, src_g);
01812             tmpS = 255 - INT_MULT((255 - dst_g), (255-src_g));
01813             src_g = INT_MULT((255 - dst_g), tmpM)
01814                 + INT_MULT(dst_g, tmpS);
01815 
01816             tmpM = INT_MULT(dst_b, src_b);
01817             tmpS = 255 - INT_MULT((255 - dst_b), (255-src_b));
01818             src_b = INT_MULT((255 - dst_b), tmpM)
01819                 + INT_MULT(dst_b, tmpS);
01820 
01821             src_a = qMin(src_a, dst_a);
01822             }
01823             break;
01824         case GRAIN_EXTRACT_MODE: {
01825             int tmp;
01826             
01827             tmp = dst_r - src_r + 128;
01828             tmp = qMin(tmp, 255);
01829             tmp = qMax(tmp, 0);
01830             src_r = (uchar) tmp;
01831 
01832             tmp = dst_g - src_g + 128;
01833             tmp = qMin(tmp, 255);
01834             tmp = qMax(tmp, 0);
01835             src_g = (uchar) tmp;
01836 
01837             tmp = dst_b - src_b + 128;
01838             tmp = qMin(tmp, 255);
01839             tmp = qMax(tmp, 0);
01840             src_b = (uchar) tmp;
01841 
01842             src_a = qMin(src_a, dst_a);
01843             }
01844             break;
01845         case GRAIN_MERGE_MODE: {
01846             int tmp;
01847             
01848             tmp = dst_r + src_r - 128;
01849             tmp = qMin(tmp, 255);
01850             tmp = qMax(tmp, 0);
01851             src_r = (uchar) tmp;
01852 
01853             tmp = dst_g + src_g - 128;
01854             tmp = qMin(tmp, 255);
01855             tmp = qMax(tmp, 0);
01856             src_g = (uchar) tmp;
01857 
01858             tmp = dst_b + src_b - 128;
01859             tmp = qMin(tmp, 255);
01860             tmp = qMax(tmp, 0);
01861             src_b = (uchar) tmp;
01862 
01863             src_a = qMin(src_a, dst_a);
01864             }
01865             break;
01866     }
01867 
01868     src_a = INT_MULT(src_a, layer.opacity);
01869 
01870     // Apply the mask (if any)
01871 
01872     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01873             layer.mask_tiles[j].size() > (int)i)
01874         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01875 
01876     uchar new_r, new_g, new_b, new_a;
01877     new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
01878 
01879     float src_ratio = (float)src_a / new_a;
01880     float dst_ratio = 1.0 - src_ratio;
01881 
01882     new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
01883     new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
01884     new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
01885 
01886     if (!layer_modes[layer.mode].affect_alpha)
01887         new_a = dst_a;
01888 
01889     image.setPixel(m, n, qRgba(new_r, new_g, new_b, new_a));
01890 }
01891 
01892 
01904 void XCFImageFormat::mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01905         QImage& image, int m, int n)
01906 {
01907     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01908     image.setPixel(m, n, src);
01909 }
01910 
01911 
01923 void XCFImageFormat::mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
01924         QImage& image, int m, int n)
01925 {
01926     int src = qGray(layer.image_tiles[j][i].pixel(k, l));
01927     int dst = image.pixelIndex(m, n);
01928 
01929     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01930 
01931     if (!src_a) return; // nothing to merge
01932 
01933     switch (layer.mode) {
01934         case MULTIPLY_MODE: {
01935                 src = INT_MULT( src, dst );
01936             }
01937             break;
01938         case DIVIDE_MODE: {
01939                 src = qMin((dst * 256) / (1 + src), 255);
01940             }
01941             break;
01942         case SCREEN_MODE: {
01943                 src = 255 - INT_MULT(255 - dst, 255 - src);
01944             }
01945             break;
01946         case OVERLAY_MODE: {
01947                 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
01948             }
01949             break;
01950         case DIFFERENCE_MODE: {
01951                 src = dst > src ? dst - src : src - dst;
01952             }
01953             break;
01954         case ADDITION_MODE: {
01955                 src = add_lut(dst,src);
01956             }
01957             break;
01958         case SUBTRACT_MODE: {
01959                 src = dst > src ? dst - src : 0;
01960             }
01961             break;
01962         case DARKEN_ONLY_MODE: {
01963                 src = dst < src ? dst : src;
01964             }
01965             break;
01966         case LIGHTEN_ONLY_MODE: {
01967                 src = dst < src ? src : dst;
01968             }
01969             break;
01970         case DODGE_MODE: {
01971                 uint tmp = dst << 8;
01972                 tmp /= 256 - src;
01973                 src = (uchar) qMin(tmp, 255u);
01974             }
01975             break;
01976         case BURN_MODE: {
01977                 uint tmp = (255-dst) << 8;
01978                 tmp /= src + 1;
01979                 src = (uchar) qMin(tmp, 255u);
01980                 src = 255 - src;
01981             }
01982             break;
01983         case HARDLIGHT_MODE: {
01984                 uint tmp;
01985                 if (src > 128) {
01986                     tmp = ((int)255-dst) * ((int) 255 - ((src-128) << 1));
01987                     src = (uchar) qMin(255 - (tmp >> 8), 255u);
01988                 } else {
01989                     tmp = (int) dst * ((int) src << 1);
01990                     src = (uchar) qMin(tmp >> 8, 255u);
01991                 }
01992             }
01993             break;
01994         case SOFTLIGHT_MODE: {
01995                 uint tmpS, tmpM;
01996 
01997                 tmpM = INT_MULT(dst, src);
01998                 tmpS = 255 - INT_MULT((255-dst), (255-src));
01999                 src = INT_MULT((255 - dst), tmpM)
02000                     + INT_MULT(dst, tmpS);
02001 
02002             }
02003             break;
02004         case GRAIN_EXTRACT_MODE: {
02005                 int tmp;
02006                 
02007                 tmp = dst - src + 128;
02008                 tmp = qMin(tmp, 255);
02009                 tmp = qMax(tmp, 0);
02010 
02011                 src = (uchar) tmp;
02012             }
02013             break;
02014         case GRAIN_MERGE_MODE: {
02015                 int tmp;
02016                 
02017                 tmp = dst + src - 128;
02018                 tmp = qMin(tmp, 255);
02019                 tmp = qMax(tmp, 0);
02020 
02021                 src = (uchar) tmp;
02022             }
02023             break;
02024     }
02025 
02026     src_a = INT_MULT(src_a, layer.opacity);
02027 
02028     // Apply the mask (if any)
02029 
02030     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
02031             layer.mask_tiles[j].size() > (int)i)
02032         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02033 
02034     uchar new_a = OPAQUE_OPACITY;
02035 
02036     float src_ratio = (float)src_a / new_a;
02037     float dst_ratio = 1.0 - src_ratio;
02038 
02039     uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
02040 
02041     image.setPixel(m, n, new_g);
02042 }
02043 
02044 
02058 void XCFImageFormat::mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
02059         QImage& image, int m, int n)
02060 {
02061     QRgb src = layer.image_tiles[j][i].pixel(k, l);
02062     uchar src_a = layer.opacity;
02063     image.setPixel(m, n, qRgba(src, src_a));
02064 }
02065 
02066 
02080 void XCFImageFormat::mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
02081         QImage& image, int m, int n)
02082 {
02083     int src = qGray(layer.image_tiles[j][i].pixel(k, l));
02084     int dst = qGray(image.pixel(m, n));
02085 
02086     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02087     uchar dst_a = qAlpha(image.pixel(m, n));
02088 
02089     if (!src_a) return; // nothing to merge
02090 
02091     switch (layer.mode) {
02092         case MULTIPLY_MODE: {
02093                 src = INT_MULT(src, dst);
02094                 src_a = qMin(src_a, dst_a);
02095             }
02096             break;
02097         case DIVIDE_MODE: {
02098                 src = qMin((dst * 256) / (1 + src), 255);
02099                 src_a = qMin(src_a, dst_a);
02100             }
02101             break;
02102         case SCREEN_MODE: {
02103                 src = 255 - INT_MULT(255 - dst, 255 - src);
02104                 src_a = qMin(src_a, dst_a);
02105             }
02106             break;
02107         case OVERLAY_MODE: {
02108                 src = INT_MULT( dst, dst + INT_MULT(2 * src, 255 - dst));
02109                 src_a = qMin(src_a, dst_a);
02110             }
02111             break;
02112         case DIFFERENCE_MODE: {
02113                 src = dst > src ? dst - src : src - dst;
02114                 src_a = qMin(src_a, dst_a);
02115             }
02116             break;
02117         case ADDITION_MODE: {
02118                 src = add_lut(dst,src);
02119                 src_a = qMin(src_a, dst_a);
02120             }
02121             break;
02122         case SUBTRACT_MODE: {
02123                 src = dst > src ? dst - src : 0;
02124                 src_a = qMin(src_a, dst_a);
02125             }
02126             break;
02127         case DARKEN_ONLY_MODE: {
02128                 src = dst < src ? dst : src;
02129                 src_a = qMin(src_a, dst_a);
02130             }
02131             break;
02132         case LIGHTEN_ONLY_MODE: {
02133                 src = dst < src ? src : dst;
02134                 src_a = qMin(src_a, dst_a);
02135             }
02136             break;
02137         case DODGE_MODE: {
02138                 uint tmp = dst << 8;
02139                 tmp /= 256 - src;
02140                 src = (uchar) qMin(tmp, 255u);
02141                 src_a = qMin(src_a, dst_a);
02142             }
02143             break;
02144         case BURN_MODE: {
02145                 uint tmp = (255-dst) << 8;
02146                 tmp /= src + 1;
02147                 src = (uchar) qMin(tmp, 255u);
02148                 src = 255 - src;
02149                 src_a = qMin(src_a, dst_a);
02150             }
02151             break;
02152         case HARDLIGHT_MODE: {
02153                 uint tmp;
02154                 if (src > 128) {
02155                     tmp = ((int)255-dst) * ((int) 255 - ((src-128) << 1));
02156                     src = (uchar) qMin(255 - (tmp >> 8), 255u);
02157                 } else {
02158                     tmp = (int) dst * ((int) src << 1);
02159                     src = (uchar) qMin(tmp >> 8, 255u);
02160                 }
02161                 src_a = qMin(src_a, dst_a);
02162             }
02163             break;
02164         case SOFTLIGHT_MODE: {
02165                 uint tmpS, tmpM;
02166 
02167                 tmpM = INT_MULT(dst, src);
02168                 tmpS = 255 - INT_MULT((255 - dst), (255-src));
02169                 src = INT_MULT((255 - dst), tmpM)
02170                     + INT_MULT(dst, tmpS);
02171 
02172                 src_a = qMin(src_a, dst_a);
02173             }
02174             break;
02175         case GRAIN_EXTRACT_MODE: {
02176                 int tmp;
02177                 
02178                 tmp = dst - src + 128;
02179                 tmp = qMin(tmp, 255);
02180                 tmp = qMax(tmp, 0);
02181 
02182                 src = (uchar) tmp;
02183                 src_a = qMin(src_a, dst_a);
02184             }
02185             break;
02186         case GRAIN_MERGE_MODE: {
02187                 int tmp;
02188                 
02189                 tmp = dst + src - 128;
02190                 tmp = qMin(tmp, 255);
02191                 tmp = qMax(tmp, 0);
02192 
02193                 src = (uchar) tmp;
02194                 src_a = qMin(src_a, dst_a);
02195             }
02196             break;
02197     }
02198 
02199     src_a = INT_MULT(src_a, layer.opacity);
02200 
02201     // Apply the mask (if any)
02202     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
02203             layer.mask_tiles[j].size() > (int)i)
02204         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02205 
02206     uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
02207 
02208     float src_ratio = (float)src_a / new_a;
02209     float dst_ratio = 1.0 - src_ratio;
02210 
02211     uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
02212 
02213     if (!layer_modes[layer.mode].affect_alpha)
02214         new_a = dst_a;
02215 
02216     image.setPixel(m, n, qRgba(new_g, new_g, new_g, new_a));
02217 }
02218 
02219 
02231 void XCFImageFormat::mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
02232         QImage& image, int m, int n)
02233 {
02234     int src = layer.image_tiles[j][i].pixelIndex(k, l);
02235     image.setPixel(m, n, src);
02236 }
02237 
02238 
02250 void XCFImageFormat::mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
02251         QImage& image, int m, int n)
02252 {
02253     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
02254     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02255     src_a = INT_MULT( src_a, layer.opacity );
02256 
02257     if ( layer.apply_mask == 1 &&
02258             layer.mask_tiles.size() > (int)j &&
02259             layer.mask_tiles[j].size() > (int)i)
02260         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02261 
02262     if (src_a > 127) {
02263         src++;
02264         image.setPixel(m, n, src);
02265     }
02266 }
02267 
02268 
02282 void XCFImageFormat::mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
02283         QImage& image, int m, int n)
02284 {
02285     QRgb src = layer.image_tiles[j][i].pixel(k, l);
02286     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02287     src_a = INT_MULT(src_a, layer.opacity);
02288 
02289     // Apply the mask (if any)
02290     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
02291             layer.mask_tiles[j].size() > (int)i)
02292         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02293 
02294     // This is what appears in the GIMP window
02295     if (src_a <= 127)
02296         src_a = 0;
02297     else
02298         src_a = OPAQUE_OPACITY;
02299 
02300     image.setPixel(m, n, qRgba(src, src_a));
02301 }
02302 
02303 
02311 void XCFImageFormat::dissolveRGBPixels ( QImage& image, int x, int y )
02312 {
02313     // The apparently spurious rand() calls are to wind the random
02314     // numbers up to the same point for each tile.
02315 
02316     for (int l = 0; l < image.height(); l++) {
02317         srand(random_table[( l + y ) % RANDOM_TABLE_SIZE]);
02318 
02319         for (int k = 0; k < x; k++)
02320             rand();
02321 
02322         for (int k = 0; k < image.width(); k++) {
02323             int rand_val = rand() & 0xff;
02324             QRgb pixel = image.pixel(k, l);
02325 
02326             if (rand_val > qAlpha(pixel)) {
02327                 image.setPixel(k, l, qRgba(pixel, 0));
02328             }
02329         }
02330     }
02331 }
02332 
02333 
02343 void XCFImageFormat::dissolveAlphaPixels ( QImage& image, int x, int y )
02344 {
02345     // The apparently spurious rand() calls are to wind the random
02346     // numbers up to the same point for each tile.
02347 
02348     for (int l = 0; l < image.height(); l++) {
02349         srand( random_table[(l + y) % RANDOM_TABLE_SIZE]);
02350 
02351         for (int k = 0; k < x; k++)
02352             rand();
02353 
02354         for (int k = 0; k < image.width(); k++) {
02355             int rand_val = rand() & 0xff;
02356             uchar alpha = image.pixelIndex(k, l);
02357 
02358             if (rand_val > alpha) {
02359                 image.setPixel(k, l, 0);
02360             }
02361         }
02362     }
02363 }
02364 
02365 
02367 
02368 XCFHandler::XCFHandler()
02369 {
02370 }
02371 
02372 bool XCFHandler::canRead() const
02373 {
02374     if (canRead(device())) {
02375         setFormat("xcf");
02376         return true;
02377     }
02378     return false;
02379 }
02380 
02381 bool XCFHandler::read(QImage *image)
02382 {
02383     XCFImageFormat xcfif;
02384     return xcfif.readXCF(device(), image);
02385 }
02386 
02387 bool XCFHandler::write(const QImage &)
02388 {
02389     return false;
02390 }
02391 
02392 QByteArray XCFHandler::name() const
02393 {
02394     return "xcf";
02395 }
02396 
02397 bool XCFHandler::canRead(QIODevice *device)
02398 {
02399       if (!device) {
02400         qWarning("DDSHandler::canRead() called with no device");
02401         return false;
02402     }
02403 
02404     qint64 oldPos = device->pos();
02405 
02406     char head[8];
02407     qint64 readBytes = device->read(head, sizeof(head));
02408     if (readBytes != sizeof(head)) {
02409         if (device->isSequential()) {
02410             while (readBytes > 0)
02411                 device->ungetChar(head[readBytes-- - 1]);
02412         } else {
02413             device->seek(oldPos);
02414         }
02415         return false;
02416     }
02417 
02418     if (device->isSequential()) {
02419         while (readBytes > 0)
02420             device->ungetChar(head[readBytes-- - 1]);
02421     } else {
02422         device->seek(oldPos);
02423     }
02424 
02425     return qstrncmp(head, "gimp xcf", 8) == 0;
02426 }
02427 
02428 
02429 class XCFPlugin : public QImageIOPlugin
02430 {
02431 public:
02432     QStringList keys() const;
02433     Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
02434     QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
02435 };
02436 
02437 QStringList XCFPlugin::keys() const
02438 {
02439     return QStringList() << "xcf" << "XCF";
02440 }
02441 
02442 QImageIOPlugin::Capabilities XCFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
02443 {
02444     if (format == "xcf" || format == "XCF")
02445         return Capabilities(CanRead);
02446     if (!format.isEmpty())
02447         return 0;
02448     if (!device->isOpen())
02449         return 0;
02450 
02451     Capabilities cap;
02452     if (device->isReadable() && XCFHandler::canRead(device))
02453         cap |= CanRead;
02454     return cap;
02455 }
02456 
02457 QImageIOHandler *XCFPlugin::create(QIODevice *device, const QByteArray &format) const
02458 {
02459     QImageIOHandler *handler = new XCFHandler;
02460     handler->setDevice(device);
02461     handler->setFormat(format);
02462     return handler;
02463 }
02464 
02465 Q_EXPORT_STATIC_PLUGIN(XCFPlugin)
02466 Q_EXPORT_PLUGIN2(xcf,XCFPlugin)
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed May 2 2012 17:26:09 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KImgIO

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

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal