• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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 <QtCore/QIODevice>
00027 #include <QtCore/QStack>
00028 #include <QtCore/QVector>
00029 
00030 #include <kdebug.h>
00031 
00032 
00033 int XCFImageFormat::random_table[RANDOM_TABLE_SIZE];
00034 
00035 //int XCFImageFormat::add_lut[256][256];
00036 
00037 
00038 const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
00039     {true},     // NORMAL_MODE
00040     {true},     // DISSOLVE_MODE
00041     {true},     // BEHIND_MODE
00042     {false},    // MULTIPLY_MODE
00043     {false},    // SCREEN_MODE
00044     {false},    // OVERLAY_MODE
00045     {false},    // DIFFERENCE_MODE
00046     {false},    // ADDITION_MODE
00047     {false},    // SUBTRACT_MODE
00048     {false},    // DARKEN_ONLY_MODE
00049     {false},    // LIGHTEN_ONLY_MODE
00050     {false},    // HUE_MODE
00051     {false},    // SATURATION_MODE
00052     {false},    // COLOR_MODE
00053     {false},    // VALUE_MODE
00054     {false},    // DIVIDE_MODE
00055     {true},     // ERASE_MODE
00056     {true},     // REPLACE_MODE
00057     {true},     // ANTI_ERASE_MODE
00058 };
00059 
00060 
00062 inline QRgb qRgba ( const QRgb& rgb, int a )
00063 {
00064     return ((a & 0xff) << 24 | (rgb & RGB_MASK));
00065 }
00066 
00067 
00072 XCFImageFormat::XCFImageFormat()
00073 {
00074     // From GIMP "paint_funcs.c" v1.2
00075     srand(RANDOM_SEED);
00076 
00077     for (int i = 0; i < RANDOM_TABLE_SIZE; i++)
00078         random_table[i] = rand();
00079 
00080     for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
00081         int tmp;
00082         int swap = i + rand() % (RANDOM_TABLE_SIZE - i);
00083         tmp = random_table[i];
00084         random_table[i] = random_table[swap];
00085         random_table[swap] = tmp;
00086     }
00087 
00088 //  for (int j = 0; j < 256; j++) {
00089 //      for (int k = 0; k < 256; k++) {
00090 //          int tmp_sum = j + k;
00091 //          if (tmp_sum > 255)
00092 //              tmp_sum = 255;
00093 //          add_lut[j][k] = tmp_sum;
00094 //      }
00095 //  }
00096 }
00097 
00098 inline
00099 int XCFImageFormat::add_lut( int a, int b ) {
00100     return qMin( a + b, 255 );
00101 }
00102 
00103 bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
00104 {
00105     XCFImage xcf_image;
00106     QDataStream xcf_io(device);
00107 
00108     char tag[14];;
00109 
00110     if (xcf_io.readRawData(tag, sizeof(tag)) != sizeof(tag)) {
00111             kDebug(399) << "XCF: read failure on header tag";
00112             return false;
00113     }
00114 
00115     xcf_io >> xcf_image.width >> xcf_image.height >> xcf_image.type;
00116 
00117 kDebug() << tag << " " << xcf_image.width << " " << xcf_image.height << " " <<  xcf_image.type;
00118     if (!loadImageProperties(xcf_io, xcf_image))
00119         return false;
00120 
00121     // The layers appear to be stored in top-to-bottom order. This is
00122     // the reverse of how a merged image must be computed. So, the layer
00123     // offsets are pushed onto a LIFO stack (thus, we don't have to load
00124     // all the data of all layers before beginning to construct the
00125     // merged image).
00126 
00127     QStack<qint32> layer_offsets;
00128 
00129     while (true) {
00130         qint32 layer_offset;
00131 
00132         xcf_io >> layer_offset;
00133 
00134         if (layer_offset == 0)
00135             break;
00136 
00137         layer_offsets.push(layer_offset);
00138     }
00139 
00140     xcf_image.num_layers = layer_offsets.size();
00141 
00142     if (layer_offsets.size() == 0) {
00143         kDebug(399) << "XCF: no layers!";
00144         return false;
00145     }
00146 
00147     // Load each layer and add it to the image
00148     while (!layer_offsets.isEmpty()) {
00149         qint32 layer_offset = layer_offsets.pop();
00150 
00151         xcf_io.device()->seek(layer_offset);
00152 
00153         if (!loadLayer(xcf_io, xcf_image))
00154             return false;
00155     }
00156 
00157     if (!xcf_image.initialized) {
00158         kDebug(399) << "XCF: no visible layers!";
00159         return false;
00160     }
00161 
00162         *outImage = xcf_image.image;
00163         return true;
00164 }
00165 
00166 
00174 bool XCFImageFormat::loadImageProperties(QDataStream& xcf_io, XCFImage& xcf_image)
00175 {
00176     while (true) {
00177         PropType type;
00178         QByteArray bytes;
00179 
00180         if (!loadProperty(xcf_io, type, bytes)) {
00181             kDebug(399) << "XCF: error loading global image properties";
00182             return false;
00183         }
00184 
00185         QDataStream property(bytes);
00186 
00187         switch (type) {
00188             case PROP_END:
00189                 return true;
00190 
00191             case PROP_COMPRESSION:
00192                 property >> xcf_image.compression;
00193                 break;
00194 
00195             case PROP_RESOLUTION:
00196                 property >> xcf_image.x_resolution >> xcf_image.y_resolution;
00197                 break;
00198 
00199             case PROP_TATTOO:
00200                 property >> xcf_image.tattoo;
00201                 break;
00202 
00203             case PROP_PARASITES:
00204                 while (!property.atEnd()) {
00205                     char* tag;
00206                     quint32 size;
00207 
00208                     property.readBytes(tag, size);
00209 
00210                     quint32 flags;
00211                     char* data=0;
00212                     property >> flags >> data;
00213 
00214                     if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0)
00215                         xcf_image.image.setText("Comment", 0, data);
00216 
00217                     delete[] tag;
00218                     delete[] data;
00219                 }
00220                 break;
00221 
00222                 case PROP_UNIT:
00223                     property >> xcf_image.unit;
00224                     break;
00225 
00226                 case PROP_PATHS:    // This property is ignored.
00227                     break;
00228 
00229                 case PROP_USER_UNIT:    // This property is ignored.
00230                     break;
00231 
00232                 case PROP_COLORMAP:
00233                     property >> xcf_image.num_colors;
00234                                         if(xcf_image.num_colors < 0 || xcf_image.num_colors > 65535)
00235                                             return false;
00236 
00237                     xcf_image.palette.reserve(xcf_image.num_colors);
00238 
00239                     for (int i = 0; i < xcf_image.num_colors; i++) {
00240                         uchar r, g, b;
00241                         property >> r >> g >> b;
00242                         xcf_image.palette.push_back( qRgb(r,g,b) );
00243                     }
00244                     break;
00245 
00246                 default:
00247                     kDebug(399) << "XCF: unimplemented image property" << type
00248                             << ", size " << bytes.size() << endl;
00249         }
00250     }
00251 }
00252 
00253 
00261 bool XCFImageFormat::loadProperty(QDataStream& xcf_io, PropType& type, QByteArray& bytes)
00262 {
00263     quint32 foo;
00264     xcf_io >> foo;
00265     type=PropType(foo); // TODO urks
00266 
00267     char* data = 0;
00268     quint32 size;
00269 
00270     // The colormap property size is not the correct number of bytes:
00271     // The GIMP source xcf.c has size = 4 + ncolors, but it should be
00272     // 4 + 3 * ncolors
00273 
00274     if (type == PROP_COLORMAP) {
00275         xcf_io >> size;
00276 
00277                 if(size > 65535 || size < 4)
00278                     return false;
00279 
00280         size = 3 * (size - 4) + 4;
00281         data = new char[size];
00282 
00283         xcf_io.readRawData(data, size);
00284     } else if (type == PROP_USER_UNIT) {
00285         // The USER UNIT property size is not correct. I'm not sure why, though.
00286         float factor;
00287         qint32 digits;
00288 
00289         xcf_io >> size >> factor >> digits;
00290 
00291         for (int i = 0; i < 5; i++) {
00292             char* unit_strings;
00293 
00294             xcf_io >> unit_strings;
00295 
00296             delete[] unit_strings;
00297 
00298             if (xcf_io.device()->atEnd()) {
00299                 kDebug(399) << "XCF: read failure on property " << type;
00300                 return false;
00301             }
00302         }
00303 
00304         size = 0;
00305     } else {
00306                 xcf_io >> size;
00307                 if(size >256000)
00308                     return false;
00309                 data = new char[size];
00310         xcf_io.readRawData(data, size);
00311         }
00312 
00313     if (size != 0 && data)
00314             bytes = QByteArray(data,size);
00315     
00316         delete [] data;
00317 
00318     return true;
00319 }
00320 
00321 
00330 bool XCFImageFormat::loadLayer(QDataStream& xcf_io, XCFImage& xcf_image)
00331 {
00332     Layer& layer(xcf_image.layer);
00333     delete[] layer.name;
00334 
00335     xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
00336 
00337     if (!loadLayerProperties(xcf_io, layer))
00338         return false;
00339 #if 0
00340   cout << "layer: \"" << layer.name << "\", size: " << layer.width << " x "
00341        << layer.height << ", type: " << layer.type << ", mode: " << layer.mode
00342        << ", opacity: " << layer.opacity << ", visible: " << layer.visible
00343        << ", offset: " << layer.x_offset << ", " << layer.y_offset << endl;
00344 #endif
00345   // Skip reading the rest of it if it is not visible. Typically, when
00346   // you export an image from the The GIMP it flattens (or merges) only
00347   // the visible layers into the output image.
00348 
00349     if (layer.visible == 0)
00350         return true;
00351 
00352     // If there are any more layers, merge them into the final QImage.
00353 
00354     xcf_io >> layer.hierarchy_offset >> layer.mask_offset;
00355 
00356     // Allocate the individual tile QImages based on the size and type
00357     // of this layer.
00358 
00359     if( !composeTiles(xcf_image))
00360         return false;
00361     xcf_io.device()->seek(layer.hierarchy_offset);
00362 
00363     // As tiles are loaded, they are copied into the layers tiles by
00364     // this routine. (loadMask(), below, uses a slightly different
00365     // version of assignBytes().)
00366 
00367     layer.assignBytes = assignImageBytes;
00368 
00369     if (!loadHierarchy(xcf_io, layer))
00370         return false;
00371 
00372     if (layer.mask_offset != 0) {
00373         xcf_io.device()->seek(layer.mask_offset);
00374 
00375         if (!loadMask(xcf_io, layer))
00376             return false;
00377     }
00378 
00379     // Now we should have enough information to initialize the final
00380     // QImage. The first visible layer determines the attributes
00381     // of the QImage.
00382 
00383     if (!xcf_image.initialized) {
00384         if( !initializeImage(xcf_image))
00385             return false;
00386         copyLayerToImage(xcf_image);
00387         xcf_image.initialized = true;
00388     } else
00389         mergeLayerIntoImage(xcf_image);
00390 
00391     return true;
00392 }
00393 
00394 
00402 bool XCFImageFormat::loadLayerProperties(QDataStream& xcf_io, Layer& layer)
00403 {
00404     while (true) {
00405         PropType type;
00406         QByteArray bytes;
00407 
00408         if (!loadProperty(xcf_io, type, bytes)) {
00409             kDebug(399) << "XCF: error loading layer properties";
00410             return false;
00411         }
00412 
00413         QDataStream property(bytes);
00414 
00415         switch (type) {
00416             case PROP_END:
00417                 return true;
00418 
00419             case PROP_ACTIVE_LAYER:
00420                 layer.active = true;
00421                 break;
00422 
00423             case PROP_OPACITY:
00424                 property >> layer.opacity;
00425                 break;
00426 
00427             case PROP_VISIBLE:
00428                 property >> layer.visible;
00429                 break;
00430 
00431             case PROP_LINKED:
00432                 property >> layer.linked;
00433                 break;
00434 
00435             case PROP_PRESERVE_TRANSPARENCY:
00436                 property >> layer.preserve_transparency;
00437                 break;
00438 
00439             case PROP_APPLY_MASK:
00440                 property >> layer.apply_mask;
00441                 break;
00442 
00443             case PROP_EDIT_MASK:
00444                 property >> layer.edit_mask;
00445                 break;
00446 
00447             case PROP_SHOW_MASK:
00448                 property >> layer.show_mask;
00449                 break;
00450 
00451             case PROP_OFFSETS:
00452                 property >> layer.x_offset >> layer.y_offset;
00453                 break;
00454 
00455             case PROP_MODE:
00456                 property >> layer.mode;
00457                 break;
00458 
00459             case PROP_TATTOO:
00460                 property >> layer.tattoo;
00461                 break;
00462 
00463             default:
00464                 kDebug(399) << "XCF: unimplemented layer property " << type
00465                         << ", size " << bytes.size() << endl;
00466         }
00467     }
00468 }
00469 
00470 
00476 bool XCFImageFormat::composeTiles(XCFImage& xcf_image)
00477 {
00478     Layer& layer(xcf_image.layer);
00479 
00480     layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
00481     layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
00482 
00483     layer.image_tiles.resize(layer.nrows);
00484 
00485     if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00486         layer.alpha_tiles.resize(layer.nrows);
00487 
00488     if (layer.mask_offset != 0)
00489         layer.mask_tiles.resize(layer.nrows);
00490 
00491     for (uint j = 0; j < layer.nrows; j++) {
00492         layer.image_tiles[j].resize(layer.ncols);
00493 
00494         if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00495             layer.alpha_tiles[j].resize(layer.ncols);
00496 
00497         if (layer.mask_offset != 0)
00498             layer.mask_tiles[j].resize(layer.ncols);
00499     }
00500 
00501     for (uint j = 0; j < layer.nrows; j++) {
00502         for (uint i = 0; i < layer.ncols; i++) {
00503 
00504             uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
00505                     ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
00506 
00507             uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
00508                     ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
00509 
00510             // Try to create the most appropriate QImage (each GIMP layer
00511             // type is treated slightly differently)
00512 
00513             switch (layer.type) {
00514                 case RGB_GIMAGE:
00515                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_RGB32);
00516                     layer.image_tiles[j][i].setNumColors(0);
00517                     if( layer.image_tiles[j][i].isNull())
00518                         return false;
00519                     break;
00520 
00521                 case RGBA_GIMAGE:
00522                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_ARGB32);
00523                     layer.image_tiles[j][i].setNumColors(0);
00524                     if( layer.image_tiles[j][i].isNull())
00525                         return false;
00526                     break;
00527 
00528                 case GRAY_GIMAGE:
00529                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00530                     layer.image_tiles[j][i].setNumColors(256);
00531                     if( layer.image_tiles[j][i].isNull())
00532                         return false;
00533                     setGrayPalette(layer.image_tiles[j][i]);
00534                     break;
00535 
00536                 case GRAYA_GIMAGE:
00537                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00538                     layer.image_tiles[j][i].setNumColors(256);
00539                     if( layer.image_tiles[j][i].isNull())
00540                         return false;
00541                     setGrayPalette(layer.image_tiles[j][i]);
00542 
00543                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00544                     layer.alpha_tiles[j][i].setNumColors(256);
00545                     if( layer.alpha_tiles[j][i].isNull())
00546                         return false;
00547                     setGrayPalette(layer.alpha_tiles[j][i]);
00548                     break;
00549 
00550                 case INDEXED_GIMAGE:
00551                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00552                     layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
00553                     if( layer.image_tiles[j][i].isNull())
00554                         return false;
00555                     setPalette(xcf_image, layer.image_tiles[j][i]);
00556                     break;
00557 
00558                 case INDEXEDA_GIMAGE:
00559                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00560                     layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
00561                     if( layer.image_tiles[j][i].isNull())
00562                         return false;
00563                     setPalette(xcf_image, layer.image_tiles[j][i]);
00564 
00565                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00566                     layer.alpha_tiles[j][i].setNumColors(256);
00567                     if( layer.alpha_tiles[j][i].isNull())
00568                         return false;
00569                     setGrayPalette(layer.alpha_tiles[j][i]);
00570             }
00571 
00572             if (layer.mask_offset != 0) {
00573                 layer.mask_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
00574                 layer.mask_tiles[j][i].setNumColors(256);
00575                 if( layer.mask_tiles[j][i].isNull())
00576                     return false;
00577                 setGrayPalette(layer.mask_tiles[j][i]);
00578             }
00579         }
00580     }
00581     return true;
00582 }
00583 
00584 
00591 void XCFImageFormat::setGrayPalette(QImage& image)
00592 {
00593     for (int i = 0; i < 256; i++)
00594         image.setColor(i, qRgb(i, i, i));
00595 }
00596 
00597 
00603 void XCFImageFormat::setPalette(XCFImage& xcf_image, QImage& image)
00604 {
00605     for (int i = 0; i < xcf_image.num_colors; i++)
00606         image.setColor(i, xcf_image.palette[i]);
00607 }
00608 
00609 
00617 void XCFImageFormat::assignImageBytes(Layer& layer, uint i, uint j)
00618 {
00619     uchar* tile = layer.tile;
00620 
00621     switch (layer.type) {
00622         case RGB_GIMAGE:
00623             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00624                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00625                     layer.image_tiles[j][i].setPixel(k, l,
00626                             qRgb(tile[0], tile[1], tile[2]));
00627                     tile += sizeof(QRgb);
00628                 }
00629             }
00630             break;
00631 
00632         case RGBA_GIMAGE:
00633             for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) {
00634                 for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) {
00635                     layer.image_tiles[j][i].setPixel(k, l,
00636                             qRgba(tile[0], tile[1], tile[2], tile[3]));
00637                     tile += sizeof(QRgb);
00638                 }
00639             }
00640             break;
00641 
00642         case GRAY_GIMAGE:
00643         case INDEXED_GIMAGE:
00644             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00645                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00646                     layer.image_tiles[j][i].setPixel(k, l, tile[0]);
00647                     tile += sizeof(QRgb);
00648                 }
00649             }
00650             break;
00651 
00652         case GRAYA_GIMAGE:
00653         case INDEXEDA_GIMAGE:
00654             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00655                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00656 
00657                 // The "if" here should not be necessary, but apparently there
00658                 // are some cases where the image can contain larger indices
00659                 // than there are colors in the palette. (A bug in The GIMP?)
00660 
00661                     if (tile[0] < layer.image_tiles[j][i].numColors())
00662                         layer.image_tiles[j][i].setPixel(k, l, tile[0]);
00663 
00664                     layer.alpha_tiles[j][i].setPixel(k, l, tile[1]);
00665                     tile += sizeof(QRgb);
00666                 }
00667             }
00668             break;
00669     }
00670 }
00671 
00672 
00681 bool XCFImageFormat::loadHierarchy(QDataStream& xcf_io, Layer& layer)
00682 {
00683     qint32 width;
00684     qint32 height;
00685     qint32 bpp;
00686     quint32 offset;
00687 
00688     xcf_io >> width >> height >> bpp >> offset;
00689 
00690     // GIMP stores images in a "mipmap"-like format (multiple levels of
00691     // increasingly lower resolution). Only the top level is used here,
00692     // however.
00693 
00694     quint32 junk;
00695     do {
00696         xcf_io >> junk;
00697 
00698         if (xcf_io.device()->atEnd()) {
00699             kDebug(399) << "XCF: read failure on layer " << layer.name << " level offsets";
00700             return false;
00701         }
00702     } while (junk != 0);
00703 
00704     qint64 saved_pos = xcf_io.device()->pos();
00705 
00706     xcf_io.device()->seek(offset);
00707     if (!loadLevel(xcf_io, layer, bpp))
00708         return false;
00709 
00710     xcf_io.device()->seek(saved_pos);
00711     return true;
00712 }
00713 
00714 
00723 bool XCFImageFormat::loadLevel(QDataStream& xcf_io, Layer& layer, qint32 bpp)
00724 {
00725     qint32 width;
00726     qint32 height;
00727     quint32 offset;
00728 
00729     xcf_io >> width >> height >> offset;
00730 
00731     if (offset == 0)
00732         return true;
00733 
00734     for (uint j = 0; j < layer.nrows; j++) {
00735         for (uint i = 0; i < layer.ncols; i++) {
00736 
00737             if (offset == 0) {
00738                 kDebug(399) << "XCF: incorrect number of tiles in layer " << layer.name;
00739                 return false;
00740             }
00741 
00742             qint64 saved_pos = xcf_io.device()->pos();
00743             quint32 offset2;
00744             xcf_io >> offset2;
00745 
00746             // Evidently, RLE can occasionally expand a tile instead of compressing it!
00747 
00748             if (offset2 == 0)
00749                 offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
00750 
00751             xcf_io.device()->seek(offset);
00752             int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
00753 
00754             if (!loadTileRLE(xcf_io, layer.tile, size, offset2 - offset, bpp))
00755                 return false;
00756 
00757             // The bytes in the layer tile are juggled differently depending on
00758             // the target QImage. The caller has set layer.assignBytes to the
00759             // appropriate routine.
00760 
00761             layer.assignBytes(layer, i, j);
00762 
00763             xcf_io.device()->seek(saved_pos);
00764             xcf_io >> offset;
00765         }
00766     }
00767 
00768     return true;
00769 }
00770 
00771 
00778 bool XCFImageFormat::loadMask(QDataStream& xcf_io, Layer& layer)
00779 {
00780     qint32 width;
00781     qint32 height;
00782     char* name;
00783 
00784     xcf_io >> width >> height >> name;
00785 
00786     delete name;
00787 
00788     if (!loadChannelProperties(xcf_io, layer))
00789         return false;
00790 
00791     quint32 hierarchy_offset;
00792     xcf_io >> hierarchy_offset;
00793 
00794     xcf_io.device()->seek(hierarchy_offset);
00795     layer.assignBytes = assignMaskBytes;
00796 
00797     if (!loadHierarchy(xcf_io, layer))
00798         return false;
00799 
00800     return true;
00801 }
00802 
00803 
00827 bool XCFImageFormat::loadTileRLE(QDataStream& xcf_io, uchar* tile, int image_size,
00828         int data_length, qint32 bpp)
00829 {
00830     uchar* data;
00831 
00832     uchar* xcfdata;
00833     uchar* xcfodata;
00834     uchar* xcfdatalimit;
00835 
00836     xcfdata = xcfodata = new uchar[data_length];
00837 
00838     xcf_io.readRawData((char*)xcfdata, data_length);
00839 
00840     if (!xcf_io.device()->isOpen()) {
00841         delete[] xcfodata;
00842         kDebug(399) << "XCF: read failure on tile";
00843         return false;
00844     }
00845 
00846     xcfdatalimit = &xcfodata[data_length - 1];
00847 
00848     for (int i = 0; i < bpp; ++i) {
00849 
00850         data = tile + i;
00851 
00852         int count = 0;
00853         int size = image_size;
00854 
00855         while (size > 0) {
00856             if (xcfdata > xcfdatalimit)
00857                 goto bogus_rle;
00858 
00859             uchar val = *xcfdata++;
00860             uint length = val;
00861 
00862             if (length >= 128) {
00863                 length = 255 - (length - 1);
00864                 if (length == 128) {
00865                     if (xcfdata >= xcfdatalimit)
00866                         goto bogus_rle;
00867 
00868                     length = (*xcfdata << 8) + xcfdata[1];
00869 
00870                     xcfdata += 2;
00871                 }
00872 
00873                 count += length;
00874                 size -= length;
00875 
00876                 if (size < 0)
00877                     goto bogus_rle;
00878 
00879                 if (&xcfdata[length - 1] > xcfdatalimit)
00880                     goto bogus_rle;
00881 
00882                 while (length-- > 0) {
00883                     *data = *xcfdata++;
00884                     data += sizeof(QRgb);
00885                 }
00886             } else {
00887                 length += 1;
00888                 if (length == 128) {
00889                     if (xcfdata >= xcfdatalimit)
00890                         goto bogus_rle;
00891 
00892                     length = (*xcfdata << 8) + xcfdata[1];
00893                     xcfdata += 2;
00894                 }
00895 
00896                 count += length;
00897                 size -= length;
00898 
00899                 if (size < 0)
00900                     goto bogus_rle;
00901 
00902                 if (xcfdata > xcfdatalimit)
00903                     goto bogus_rle;
00904 
00905                 val = *xcfdata++;
00906 
00907                 while (length-- > 0) {
00908                     *data = val;
00909                     data += sizeof(QRgb);
00910                 }
00911             }
00912         }
00913     }
00914 
00915     delete[] xcfodata;
00916     return true;
00917 
00918 bogus_rle:
00919 
00920     kDebug(399) << "The run length encoding could not be decoded properly";
00921     delete[] xcfodata;
00922     return false;
00923 }
00924 
00925 
00933 bool XCFImageFormat::loadChannelProperties(QDataStream& xcf_io, Layer& layer)
00934 {
00935     while (true) {
00936         PropType type;
00937         QByteArray bytes;
00938 
00939         if (!loadProperty(xcf_io, type, bytes)) {
00940             kDebug(399) << "XCF: error loading channel properties";
00941             return false;
00942         }
00943 
00944         QDataStream property(bytes);
00945 
00946         switch (type) {
00947             case PROP_END:
00948                 return true;
00949 
00950             case PROP_OPACITY:
00951                 property >> layer.mask_channel.opacity;
00952                 break;
00953 
00954             case PROP_VISIBLE:
00955                 property >> layer.mask_channel.visible;
00956                 break;
00957 
00958             case PROP_SHOW_MASKED:
00959                 property >> layer.mask_channel.show_masked;
00960                 break;
00961 
00962             case PROP_COLOR:
00963                 property >> layer.mask_channel.red >> layer.mask_channel.green
00964                         >> layer.mask_channel.blue;
00965                 break;
00966 
00967             case PROP_TATTOO:
00968                 property >> layer.mask_channel.tattoo;
00969                 break;
00970 
00971             default:
00972                 kDebug(399) << "XCF: unimplemented channel property " << type
00973                         << ", size " << bytes.size() << endl;
00974         }
00975     }
00976 }
00977 
00978 
00985 void XCFImageFormat::assignMaskBytes(Layer& layer, uint i, uint j)
00986 {
00987     uchar* tile = layer.tile;
00988 
00989     for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00990         for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00991             layer.mask_tiles[j][i].setPixel(k, l, tile[0]);
00992             tile += sizeof(QRgb);
00993         }
00994     }
00995 }
00996 
00997 
01026 bool XCFImageFormat::initializeImage(XCFImage& xcf_image)
01027 {
01028     // (Aliases to make the code look a little better.)
01029     Layer& layer(xcf_image.layer);
01030     QImage& image(xcf_image.image);
01031 
01032     switch (layer.type) {
01033         case RGB_GIMAGE:
01034             if (layer.opacity == OPAQUE_OPACITY) {
01035                 image = QImage( xcf_image.width, xcf_image.height, QImage::Format_RGB32);
01036                 if( image.isNull())
01037                     return false;
01038                 image.fill(qRgb(255, 255, 255));
01039                 break;
01040             } // else, fall through to 32-bit representation
01041 
01042         case RGBA_GIMAGE:
01043             image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01044             if( image.isNull())
01045                 return false;
01046             image.fill(qRgba(255, 255, 255, 0));
01047             break;
01048 
01049         case GRAY_GIMAGE:
01050             if (layer.opacity == OPAQUE_OPACITY) {
01051                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01052                 image.setNumColors(256);
01053                 if( image.isNull())
01054                     return false;
01055                 setGrayPalette(image);
01056                 image.fill(255);
01057                 break;
01058             } // else, fall through to 32-bit representation
01059 
01060         case GRAYA_GIMAGE:
01061             image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01062             if( image.isNull())
01063                 return false;
01064             image.fill(qRgba(255, 255, 255, 0));
01065             break;
01066 
01067         case INDEXED_GIMAGE:
01068             // As noted in the table above, there are quite a few combinations
01069             // which are possible with indexed images, depending on the
01070             // presence of transparency (note: not translucency, which is not
01071             // supported by The GIMP for indexed images) and the number of
01072             // individual colors.
01073 
01074             // Note: Qt treats a bitmap with a Black and White color palette
01075             // as a mask, so only the "on" bits are drawn, regardless of the
01076             // order color table entries. Otherwise (i.e., at least one of the
01077             // color table entries is not black or white), it obeys the one-
01078             // or two-color palette. Have to ask about this...
01079 
01080             if (xcf_image.num_colors <= 2) {
01081                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
01082                 image.setNumColors(xcf_image.num_colors);
01083                 if( image.isNull())
01084                     return false;
01085                 image.fill(0);
01086                 setPalette(xcf_image, image);
01087             } else if (xcf_image.num_colors <= 256) {
01088                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01089                 image.setNumColors(xcf_image.num_colors);
01090                 if( image.isNull())
01091                     return false;
01092                 image.fill(0);
01093                 setPalette(xcf_image, image);
01094             }
01095             break;
01096 
01097         case INDEXEDA_GIMAGE:
01098             if (xcf_image.num_colors == 1) {
01099                 // Plenty(!) of room to add a transparent color
01100                 xcf_image.num_colors++;
01101                 xcf_image.palette.resize(xcf_image.num_colors);
01102                 xcf_image.palette[1] = xcf_image.palette[0];
01103                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01104 
01105                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
01106                 image.setNumColors(xcf_image.num_colors);
01107                 if( image.isNull())
01108                     return false;
01109                 image.fill(0);
01110                 setPalette(xcf_image, image);
01111             } else if (xcf_image.num_colors < 256) {
01112                 // Plenty of room to add a transparent color
01113                 xcf_image.num_colors++;
01114                 xcf_image.palette.resize(xcf_image.num_colors);
01115                 for (int c = xcf_image.num_colors - 1; c >= 1; c--)
01116                     xcf_image.palette[c] = xcf_image.palette[c - 1];
01117 
01118                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01119                 image = QImage( xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
01120                 image.setNumColors(xcf_image.num_colors);
01121                 if( image.isNull())
01122                     return false;
01123                 image.fill(0);
01124                 setPalette(xcf_image, image);
01125             } else {
01126                 // No room for a transparent color, so this has to be promoted to
01127                 // true color. (There is no equivalent PNG representation output
01128                 // from The GIMP as of v1.2.)
01129                 image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
01130                 if( image.isNull())
01131                     return false;
01132                 image.fill(qRgba(255, 255, 255, 0));
01133             }
01134             break;
01135     }
01136 
01137     image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER));
01138     image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER));
01139     return true;
01140 }
01141 
01142 
01148 void XCFImageFormat::copyLayerToImage(XCFImage& xcf_image)
01149 {
01150     Layer& layer(xcf_image.layer);
01151     QImage& image(xcf_image.image);
01152     PixelCopyOperation copy = 0;
01153 
01154     switch (layer.type) {
01155         case RGB_GIMAGE:
01156         case RGBA_GIMAGE:
01157             copy = copyRGBToRGB;
01158             break;
01159         case GRAY_GIMAGE:
01160             if (layer.opacity == OPAQUE_OPACITY)
01161                 copy = copyGrayToGray;
01162             else
01163                 copy = copyGrayToRGB;
01164             break;
01165         case GRAYA_GIMAGE:
01166             copy = copyGrayAToRGB;
01167             break;
01168         case INDEXED_GIMAGE:
01169             copy = copyIndexedToIndexed;
01170             break;
01171         case INDEXEDA_GIMAGE:
01172             if (xcf_image.image.depth() <= 8)
01173                 copy = copyIndexedAToIndexed;
01174             else
01175                 copy = copyIndexedAToRGB;
01176     }
01177 
01178     // For each tile...
01179 
01180     for (uint j = 0; j < layer.nrows; j++) {
01181         uint y = j * TILE_HEIGHT;
01182 
01183         for (uint i = 0; i < layer.ncols; i++) {
01184             uint x = i * TILE_WIDTH;
01185 
01186             // This seems the best place to apply the dissolve because it
01187             // depends on the global position of each tile's
01188             // pixels. Apparently it's the only mode which can apply to a
01189             // single layer.
01190 
01191             if (layer.mode == DISSOLVE_MODE) {
01192                 if (layer.type == RGBA_GIMAGE)
01193                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01194 
01195                 else if (layer.type == GRAYA_GIMAGE)
01196                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01197             }
01198 
01199             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01200                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01201 
01202                     int m = x + k + layer.x_offset;
01203                     int n = y + l + layer.y_offset;
01204 
01205                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01206                         continue;
01207 
01208                     (*copy)(layer, i, j, k, l, image, m, n);
01209                 }
01210             }
01211         }
01212     }
01213 }
01214 
01215 
01229 void XCFImageFormat::copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01230         QImage& image, int m, int n)
01231 {
01232     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01233     uchar src_a = layer.opacity;
01234 
01235     if (layer.type == RGBA_GIMAGE)
01236         src_a = INT_MULT(src_a, qAlpha(src));
01237 
01238     // Apply the mask (if any)
01239 
01240     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01241             layer.mask_tiles[j].size() > (int)i)
01242         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01243 
01244     image.setPixel(m, n, qRgba(src, src_a));
01245 }
01246 
01247 
01259 void XCFImageFormat::copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01260         QImage& image, int m, int n)
01261 {
01262     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01263     image.setPixel(m, n, src);
01264 }
01265 
01266 
01280 void XCFImageFormat::copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
01281         QImage& image, int m, int n)
01282 {
01283     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01284     uchar src_a = layer.opacity;
01285     image.setPixel(m, n, qRgba(src, src_a));
01286 }
01287 
01288 
01302 void XCFImageFormat::copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
01303                       QImage& image, int m, int n)
01304 {
01305     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01306     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01307     src_a = INT_MULT(src_a, layer.opacity);
01308 
01309     // Apply the mask (if any)
01310 
01311     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01312             layer.mask_tiles[j].size() > (int)i)
01313         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01314 
01315     image.setPixel(m, n, qRgba(src, src_a));
01316 }
01317 
01318 
01330 void XCFImageFormat::copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
01331         QImage& image, int m, int n)
01332 {
01333     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01334     image.setPixel(m, n, src);
01335 }
01336 
01337 
01349 void XCFImageFormat::copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
01350         QImage& image, int m, int n)
01351 {
01352     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
01353     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01354     src_a = INT_MULT(src_a, layer.opacity);
01355 
01356     if (layer.apply_mask == 1 &&
01357             layer.mask_tiles.size() > (int)j &&
01358             layer.mask_tiles[j].size() > (int)i)
01359         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01360 
01361     if (src_a > 127)
01362         src++;
01363     else
01364         src = 0;
01365 
01366 image.setPixel(m, n, src);
01367 }
01368 
01369 
01383 void XCFImageFormat::copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
01384         QImage& image, int m, int n)
01385 {
01386     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01387     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01388     src_a = INT_MULT(src_a, layer.opacity);
01389 
01390     // Apply the mask (if any)
01391     if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
01392             layer.mask_tiles[j].size() > (int)i)
01393         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01394 
01395     // This is what appears in the GIMP window
01396     if (src_a <= 127)
01397         src_a = 0;
01398     else
01399         src_a = OPAQUE_OPACITY;
01400 
01401     image.setPixel(m, n, qRgba(src, src_a));
01402 }
01403 
01404 
01409 void XCFImageFormat::mergeLayerIntoImage(XCFImage& xcf_image)
01410 {
01411     Layer& layer(xcf_image.layer);
01412     QImage& image(xcf_image.image);
01413 
01414     PixelMergeOperation merge = 0;
01415 
01416     switch (layer.type) {
01417         case RGB_GIMAGE:
01418         case RGBA_GIMAGE:
01419             merge = mergeRGBToRGB;
01420             break;
01421         case GRAY_GIMAGE:
01422             if (layer.opacity == OPAQUE_OPACITY)
01423                 merge = mergeGrayToGray;
01424             else
01425                 merge = mergeGrayToRGB;
01426             break;
01427         case GRAYA_GIMAGE:
01428             if (xcf_image.image.depth() <= 8)
01429                 merge = mergeGrayAToGray;
01430             else
01431                 merge = mergeGrayAToRGB;
01432             break;
01433         case INDEXED_GIMAGE:
01434             merge = mergeIndexedToIndexed;
01435             break;
01436         case INDEXEDA_GIMAGE:
01437             if (xcf_image.image.depth() <= 8)
01438                 merge = mergeIndexedAToIndexed;
01439             else
01440                 merge = mergeIndexedAToRGB;
01441     }
01442 
01443     for (uint j = 0; j < layer.nrows; j++) {
01444         uint y = j * TILE_HEIGHT;
01445 
01446         for (uint i = 0; i < layer.ncols; i++) {
01447             uint x = i * TILE_WIDTH;
01448 
01449             // This seems the best place to apply the dissolve because it
01450             // depends on the global position of each tile's
01451             // pixels. Apparently it's the only mode which can apply to a
01452             // single layer.
01453 
01454             if (layer.mode == DISSOLVE_MODE) {
01455                 if (layer.type == RGBA_GIMAGE)
01456                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01457 
01458                 else if (layer.type == GRAYA_GIMAGE)
01459                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01460             }
01461 
01462             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01463                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01464 
01465                     int m = x + k + layer.x_offset;
01466                     int n = y + l + layer.y_offset;
01467 
01468                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01469                         continue;
01470 
01471                     (*merge)(layer, i, j, k, l, image, m, n);
01472                 }
01473             }
01474         }
01475     }
01476 }
01477 
01478 
01492 void XCFImageFormat::mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01493         QImage& image, int m, int n)
01494 {