• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • 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 <stdlib.h>
00023 #include <qimage.h>
00024 #include <qiodevice.h>
00025 #include <qvaluestack.h>
00026 #include <qvaluevector.h>
00027 
00028 #include <kdebug.h>
00029 #include "xcf.h"
00030 
00031 
00033 
00034 
00035 KDE_EXPORT void kimgio_xcf_read(QImageIO *io)
00036 {
00037     XCFImageFormat xcfif;
00038     xcfif.readXCF(io);
00039 }
00040 
00041 
00042 KDE_EXPORT void kimgio_xcf_write(QImageIO *io)
00043 {
00044     kdDebug(399) << "XCF: write support not implemented" << endl;
00045     io->setStatus(-1);
00046 }
00047 
00049 
00050 
00051 
00052 int XCFImageFormat::random_table[RANDOM_TABLE_SIZE];
00053 
00054 //int XCFImageFormat::add_lut[256][256];
00055 
00056 
00057 const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
00058     {true},     // NORMAL_MODE
00059     {true},     // DISSOLVE_MODE
00060     {true},     // BEHIND_MODE
00061     {false},    // MULTIPLY_MODE
00062     {false},    // SCREEN_MODE
00063     {false},    // OVERLAY_MODE
00064     {false},    // DIFFERENCE_MODE
00065     {false},    // ADDITION_MODE
00066     {false},    // SUBTRACT_MODE
00067     {false},    // DARKEN_ONLY_MODE
00068     {false},    // LIGHTEN_ONLY_MODE
00069     {false},    // HUE_MODE
00070     {false},    // SATURATION_MODE
00071     {false},    // COLOR_MODE
00072     {false},    // VALUE_MODE
00073     {false},    // DIVIDE_MODE
00074     {true},     // ERASE_MODE
00075     {true},     // REPLACE_MODE
00076     {true},     // ANTI_ERASE_MODE
00077 };
00078 
00079 
00081 inline QRgb qRgba ( QRgb rgb, int a )
00082 {
00083     return ((a & 0xff) << 24 | (rgb & RGB_MASK));
00084 }
00085 
00086 
00091 XCFImageFormat::XCFImageFormat()
00092 {
00093     // From GIMP "paint_funcs.c" v1.2
00094     srand(RANDOM_SEED);
00095 
00096     for (int i = 0; i < RANDOM_TABLE_SIZE; i++)
00097         random_table[i] = rand();
00098 
00099     for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
00100         int tmp;
00101         int swap = i + rand() % (RANDOM_TABLE_SIZE - i);
00102         tmp = random_table[i];
00103         random_table[i] = random_table[swap];
00104         random_table[swap] = tmp;
00105     }
00106 
00107 //  for (int j = 0; j < 256; j++) {
00108 //      for (int k = 0; k < 256; k++) {
00109 //          int tmp_sum = j + k;
00110 //          if (tmp_sum > 255)
00111 //              tmp_sum = 255;
00112 //          add_lut[j][k] = tmp_sum;
00113 //      }
00114 //  }
00115 }
00116 
00117 inline
00118 int XCFImageFormat::add_lut( int a, int b ) {
00119     return QMIN( a + b, 255 );
00120 }
00121 
00122 void XCFImageFormat::readXCF(QImageIO *io)
00123 {
00124     XCFImage xcf_image;
00125     QDataStream xcf_io(io->ioDevice());
00126 
00127     char tag[14];
00128     xcf_io.readRawBytes(tag, sizeof(tag));
00129 
00130     if (xcf_io.device()->status() != IO_Ok) {
00131         kdDebug(399) << "XCF: read failure on header tag" << endl;
00132         return;
00133     }
00134 
00135     xcf_io >> xcf_image.width >> xcf_image.height >> xcf_image.type;
00136 
00137     if (xcf_io.device()->status() != IO_Ok) {
00138         kdDebug(399) << "XCF: read failure on image info" << endl;
00139         return;
00140     }
00141 
00142 kdDebug() << tag << " " << xcf_image.width << " " << xcf_image.height << " " <<  xcf_image.type << endl;
00143     if (!loadImageProperties(xcf_io, xcf_image))
00144         return;
00145 
00146     // The layers appear to be stored in top-to-bottom order. This is
00147     // the reverse of how a merged image must be computed. So, the layer
00148     // offsets are pushed onto a LIFO stack (thus, we don't have to load
00149     // all the data of all layers before beginning to construct the
00150     // merged image).
00151 
00152     QValueStack<Q_INT32> layer_offsets;
00153 
00154     while (true) {
00155         Q_INT32 layer_offset;
00156 
00157         xcf_io >> layer_offset;
00158 
00159         if (xcf_io.device()->status() != IO_Ok) {
00160             kdDebug(399) << "XCF: read failure on layer offsets" << endl;
00161             return;
00162         }
00163 
00164         if (layer_offset == 0)
00165             break;
00166 
00167         layer_offsets.push(layer_offset);
00168     }
00169 
00170     xcf_image.num_layers = layer_offsets.size();
00171 
00172     if (layer_offsets.size() == 0) {
00173         kdDebug(399) << "XCF: no layers!" << endl;
00174         return;
00175     }
00176 
00177     // Load each layer and add it to the image
00178     while (!layer_offsets.isEmpty()) {
00179         Q_INT32 layer_offset = layer_offsets.pop();
00180 
00181         xcf_io.device()->at(layer_offset);
00182 
00183         if (!loadLayer(xcf_io, xcf_image))
00184             return;
00185     }
00186 
00187     if (!xcf_image.initialized) {
00188         kdDebug(399) << "XCF: no visible layers!" << endl;
00189         return;
00190     }
00191 
00192     io->setImage(xcf_image.image);
00193     io->setStatus(0);
00194 }
00195 
00196 
00204 bool XCFImageFormat::loadImageProperties(QDataStream& xcf_io, XCFImage& xcf_image)
00205 {
00206     while (true) {
00207         PropType type;
00208         QByteArray bytes;
00209 
00210         if (!loadProperty(xcf_io, type, bytes)) {
00211             kdDebug(399) << "XCF: error loading global image properties" << endl;
00212             return false;
00213         }
00214 
00215         QDataStream property(bytes, IO_ReadOnly);
00216 
00217         switch (type) {
00218             case PROP_END:
00219                 return true;
00220 
00221             case PROP_COMPRESSION:
00222                 property >> xcf_image.compression;
00223                 break;
00224 
00225             case PROP_RESOLUTION:
00226                 property >> xcf_image.x_resolution >> xcf_image.y_resolution;
00227                 break;
00228 
00229             case PROP_TATTOO:
00230                 property >> xcf_image.tattoo;
00231                 break;
00232 
00233             case PROP_PARASITES:
00234                 while (!property.atEnd()) {
00235                     char* tag;
00236                     Q_UINT32 size;
00237 
00238                     property.readBytes(tag, size);
00239 
00240                     Q_UINT32 flags;
00241                     char* data=0;
00242                     property >> flags >> data;
00243 
00244                     if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0)
00245                         xcf_image.image.setText("Comment", 0, data);
00246 
00247                     delete[] tag;
00248                     delete[] data;
00249                 }
00250                 break;
00251 
00252                 case PROP_UNIT:
00253                     property >> xcf_image.unit;
00254                     break;
00255 
00256                 case PROP_PATHS:    // This property is ignored.
00257                     break;
00258 
00259                 case PROP_USER_UNIT:    // This property is ignored.
00260                     break;
00261 
00262                 case PROP_COLORMAP:
00263                     property >> xcf_image.num_colors;
00264                                         if(xcf_image.num_colors < 0 || xcf_image.num_colors > 65535)
00265                                             return false;
00266 
00267                     xcf_image.palette.reserve(xcf_image.num_colors);
00268 
00269                     for (int i = 0; i < xcf_image.num_colors; i++) {
00270                         uchar r, g, b;
00271                         property >> r >> g >> b;
00272                         xcf_image.palette.push_back( qRgb(r,g,b) );
00273                     }
00274                     break;
00275 
00276                 default:
00277                     kdDebug(399) << "XCF: unimplemented image property" << type
00278                             << ", size " << bytes.size() << endl;
00279         }
00280     }
00281 }
00282 
00283 
00291 bool XCFImageFormat::loadProperty(QDataStream& xcf_io, PropType& type, QByteArray& bytes)
00292 {
00293     Q_UINT32 foo;
00294     xcf_io >> foo;
00295     type=PropType(foo); // TODO urks
00296 
00297     if (xcf_io.device()->status() != IO_Ok) {
00298         kdDebug(399) << "XCF: read failure on property type" << type << endl;
00299         return false;
00300     }
00301 
00302     char* data;
00303     Q_UINT32 size;
00304 
00305     // The colormap property size is not the correct number of bytes:
00306     // The GIMP source xcf.c has size = 4 + ncolors, but it should be
00307     // 4 + 3 * ncolors
00308 
00309     if (type == PROP_COLORMAP) {
00310         xcf_io >> size;
00311 
00312         if (xcf_io.device()->status() != IO_Ok) {
00313             kdDebug(399) << "XCF: read failure on property " << type << " size" << endl;
00314             return false;
00315         }
00316 
00317                 if(size > 65535 || size < 4)
00318                     return false;
00319 
00320         size = 3 * (size - 4) + 4;
00321         data = new char[size];
00322 
00323         xcf_io.readRawBytes(data, size);
00324     } else if (type == PROP_USER_UNIT) {
00325         // The USER UNIT property size is not correct. I'm not sure why, though.
00326         float factor;
00327         Q_INT32 digits;
00328         char* unit_strings;
00329 
00330         xcf_io >> size >> factor >> digits;
00331 
00332         if (xcf_io.device()->status() != IO_Ok) {
00333             kdDebug(399) << "XCF: read failure on property " << type << endl;
00334             return false;
00335         }
00336 
00337         for (int i = 0; i < 5; i++) {
00338             xcf_io >> unit_strings;
00339 
00340             if (xcf_io.device()->status() != IO_Ok) {
00341                 kdDebug(399) << "XCF: read failure on property " << type << endl;
00342                 return false;
00343             }
00344 
00345             delete[] unit_strings;
00346         }
00347 
00348         size = 0;
00349     } else {
00350                 xcf_io >> size;
00351                 if(size >256000)
00352                     return false;
00353                 data = new char[size];
00354         xcf_io.readRawBytes(data, size);
00355         }
00356 
00357     if (xcf_io.device()->status() != IO_Ok) {
00358         kdDebug(399) << "XCF: read failure on property " << type << " data, size " << size << endl;
00359         return false;
00360     }
00361 
00362     if (size != 0 && data) {
00363                 bytes.assign(data,size);
00364     }
00365 
00366     return true;
00367 }
00368 
00369 
00378 bool XCFImageFormat::loadLayer(QDataStream& xcf_io, XCFImage& xcf_image)
00379 {
00380     Layer& layer(xcf_image.layer);
00381     delete[] layer.name;
00382 
00383     xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
00384 
00385     if (xcf_io.device()->status() != IO_Ok) {
00386         kdDebug(399) << "XCF: read failure on layer" << endl;
00387         return false;
00388     }
00389 
00390     if (!loadLayerProperties(xcf_io, layer))
00391         return false;
00392 #if 0
00393   cout << "layer: \"" << layer.name << "\", size: " << layer.width << " x "
00394        << layer.height << ", type: " << layer.type << ", mode: " << layer.mode
00395        << ", opacity: " << layer.opacity << ", visible: " << layer.visible
00396        << ", offset: " << layer.x_offset << ", " << layer.y_offset << endl;
00397 #endif
00398   // Skip reading the rest of it if it is not visible. Typically, when
00399   // you export an image from the The GIMP it flattens (or merges) only
00400   // the visible layers into the output image.
00401 
00402     if (layer.visible == 0)
00403         return true;
00404 
00405     // If there are any more layers, merge them into the final QImage.
00406 
00407     xcf_io >> layer.hierarchy_offset >> layer.mask_offset;
00408     if (xcf_io.device()->status() != IO_Ok) {
00409         kdDebug(399) << "XCF: read failure on layer image offsets" << endl;
00410         return false;
00411     }
00412 
00413     // Allocate the individual tile QImages based on the size and type
00414     // of this layer.
00415 
00416     if( !composeTiles(xcf_image))
00417         return false;
00418     xcf_io.device()->at(layer.hierarchy_offset);
00419 
00420     // As tiles are loaded, they are copied into the layers tiles by
00421     // this routine. (loadMask(), below, uses a slightly different
00422     // version of assignBytes().)
00423 
00424     layer.assignBytes = assignImageBytes;
00425 
00426     if (!loadHierarchy(xcf_io, layer))
00427         return false;
00428 
00429     if (layer.mask_offset != 0) {
00430         xcf_io.device()->at(layer.mask_offset);
00431 
00432         if (!loadMask(xcf_io, layer))
00433             return false;
00434     }
00435 
00436     // Now we should have enough information to initialize the final
00437     // QImage. The first visible layer determines the attributes
00438     // of the QImage.
00439 
00440     if (!xcf_image.initialized) {
00441         if( !initializeImage(xcf_image))
00442             return false;
00443         copyLayerToImage(xcf_image);
00444         xcf_image.initialized = true;
00445     } else
00446         mergeLayerIntoImage(xcf_image);
00447 
00448     return true;
00449 }
00450 
00451 
00459 bool XCFImageFormat::loadLayerProperties(QDataStream& xcf_io, Layer& layer)
00460 {
00461     while (true) {
00462         PropType type;
00463         QByteArray bytes;
00464 
00465         if (!loadProperty(xcf_io, type, bytes)) {
00466             kdDebug(399) << "XCF: error loading layer properties" << endl;
00467             return false;
00468         }
00469 
00470         QDataStream property(bytes, IO_ReadOnly);
00471 
00472         switch (type) {
00473             case PROP_END:
00474                 return true;
00475 
00476             case PROP_ACTIVE_LAYER:
00477                 layer.active = true;
00478                 break;
00479 
00480             case PROP_OPACITY:
00481                 property >> layer.opacity;
00482                 break;
00483 
00484             case PROP_VISIBLE:
00485                 property >> layer.visible;
00486                 break;
00487 
00488             case PROP_LINKED:
00489                 property >> layer.linked;
00490                 break;
00491 
00492             case PROP_PRESERVE_TRANSPARENCY:
00493                 property >> layer.preserve_transparency;
00494                 break;
00495 
00496             case PROP_APPLY_MASK:
00497                 property >> layer.apply_mask;
00498                 break;
00499 
00500             case PROP_EDIT_MASK:
00501                 property >> layer.edit_mask;
00502                 break;
00503 
00504             case PROP_SHOW_MASK:
00505                 property >> layer.show_mask;
00506                 break;
00507 
00508             case PROP_OFFSETS:
00509                 property >> layer.x_offset >> layer.y_offset;
00510                 break;
00511 
00512             case PROP_MODE:
00513                 property >> layer.mode;
00514                 break;
00515 
00516             case PROP_TATTOO:
00517                 property >> layer.tattoo;
00518                 break;
00519 
00520             default:
00521                 kdDebug(399) << "XCF: unimplemented layer property " << type
00522                         << ", size " << bytes.size() << endl;
00523         }
00524     }
00525 }
00526 
00527 
00533 bool XCFImageFormat::composeTiles(XCFImage& xcf_image)
00534 {
00535     Layer& layer(xcf_image.layer);
00536 
00537     layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
00538     layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
00539 
00540     layer.image_tiles.resize(layer.nrows);
00541 
00542     if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00543         layer.alpha_tiles.resize(layer.nrows);
00544 
00545     if (layer.mask_offset != 0)
00546         layer.mask_tiles.resize(layer.nrows);
00547 
00548     for (uint j = 0; j < layer.nrows; j++) {
00549         layer.image_tiles[j].resize(layer.ncols);
00550 
00551         if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
00552             layer.alpha_tiles[j].resize(layer.ncols);
00553 
00554         if (layer.mask_offset != 0)
00555             layer.mask_tiles[j].resize(layer.ncols);
00556     }
00557 
00558     for (uint j = 0; j < layer.nrows; j++) {
00559         for (uint i = 0; i < layer.ncols; i++) {
00560 
00561             uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
00562                     ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
00563 
00564             uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
00565                     ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
00566 
00567             // Try to create the most appropriate QImage (each GIMP layer
00568             // type is treated slightly differently)
00569 
00570             switch (layer.type) {
00571                 case RGB_GIMAGE:
00572                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, 32, 0);
00573                     if( layer.image_tiles[j][i].isNull())
00574                         return false;
00575                     layer.image_tiles[j][i].setAlphaBuffer(false);
00576                     break;
00577 
00578                 case RGBA_GIMAGE:
00579                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, 32, 0);
00580                     if( layer.image_tiles[j][i].isNull())
00581                         return false;
00582                     layer.image_tiles[j][i].setAlphaBuffer(true);
00583                     break;
00584 
00585                 case GRAY_GIMAGE:
00586                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, 8, 256);
00587                     if( layer.image_tiles[j][i].isNull())
00588                         return false;
00589                     setGrayPalette(layer.image_tiles[j][i]);
00590                     break;
00591 
00592                 case GRAYA_GIMAGE:
00593                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, 8, 256);
00594                     if( layer.image_tiles[j][i].isNull())
00595                         return false;
00596                     setGrayPalette(layer.image_tiles[j][i]);
00597 
00598                     layer.alpha_tiles[j][i] = QImage( tile_width, tile_height, 8, 256);
00599                     if( layer.alpha_tiles[j][i].isNull())
00600                         return false;
00601                     setGrayPalette(layer.alpha_tiles[j][i]);
00602                     break;
00603 
00604                 case INDEXED_GIMAGE:
00605                     layer.image_tiles[j][i] = QImage(tile_width, tile_height, 8,
00606                             xcf_image.num_colors);
00607                     if( layer.image_tiles[j][i].isNull())
00608                         return false;
00609                     setPalette(xcf_image, layer.image_tiles[j][i]);
00610                     break;
00611 
00612                 case INDEXEDA_GIMAGE:
00613                     layer.image_tiles[j][i] = QImage(tile_width, tile_height,8,
00614                             xcf_image.num_colors);
00615                     if( layer.image_tiles[j][i].isNull())
00616                         return false;
00617                     setPalette(xcf_image, layer.image_tiles[j][i]);
00618 
00619                     layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, 8, 256);
00620                     if( layer.alpha_tiles[j][i].isNull())
00621                         return false;
00622                     setGrayPalette(layer.alpha_tiles[j][i]);
00623             }
00624 
00625             if (layer.mask_offset != 0) {
00626                 layer.mask_tiles[j][i] = QImage(tile_width, tile_height, 8, 256);
00627                 if( layer.mask_tiles[j][i].isNull())
00628                     return false;
00629                 setGrayPalette(layer.mask_tiles[j][i]);
00630             }
00631         }
00632     }
00633     return true;
00634 }
00635 
00636 
00643 void XCFImageFormat::setGrayPalette(QImage& image)
00644 {
00645     for (int i = 0; i < 256; i++)
00646         image.setColor(i, qRgb(i, i, i));
00647 }
00648 
00649 
00655 void XCFImageFormat::setPalette(XCFImage& xcf_image, QImage& image)
00656 {
00657     for (int i = 0; i < xcf_image.num_colors; i++)
00658         image.setColor(i, xcf_image.palette[i]);
00659 }
00660 
00661 
00669 void XCFImageFormat::assignImageBytes(Layer& layer, uint i, uint j)
00670 {
00671     uchar* tile = layer.tile;
00672 
00673     switch (layer.type) {
00674         case RGB_GIMAGE:
00675             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00676                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00677                     layer.image_tiles[j][i].setPixel(k, l,
00678                             qRgb(tile[0], tile[1], tile[2]));
00679                     tile += sizeof(QRgb);
00680                 }
00681             }
00682             break;
00683 
00684         case RGBA_GIMAGE:
00685             for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) {
00686                 for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) {
00687                     layer.image_tiles[j][i].setPixel(k, l,
00688                             qRgba(tile[0], tile[1], tile[2], tile[3]));
00689                     tile += sizeof(QRgb);
00690                 }
00691             }
00692             break;
00693 
00694         case GRAY_GIMAGE:
00695         case INDEXED_GIMAGE:
00696             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00697                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00698                     layer.image_tiles[j][i].setPixel(k, l, tile[0]);
00699                     tile += sizeof(QRgb);
00700                 }
00701             }
00702             break;
00703 
00704         case GRAYA_GIMAGE:
00705         case INDEXEDA_GIMAGE:
00706             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
00707                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
00708 
00709                 // The "if" here should not be necessary, but apparently there
00710                 // are some cases where the image can contain larger indices
00711                 // than there are colors in the palette. (A bug in The GIMP?)
00712 
00713                     if (tile[0] < layer.image_tiles[j][i].numColors())
00714                         layer.image_tiles[j][i].setPixel(k, l, tile[0]);
00715 
00716                     layer.alpha_tiles[j][i].setPixel(k, l, tile[1]);
00717                     tile += sizeof(QRgb);
00718                 }
00719             }
00720             break;
00721     }
00722 }
00723 
00724 
00733 bool XCFImageFormat::loadHierarchy(QDataStream& xcf_io, Layer& layer)
00734 {
00735     Q_INT32 width;
00736     Q_INT32 height;
00737     Q_INT32 bpp;
00738     Q_UINT32 offset;
00739 
00740     xcf_io >> width >> height >> bpp >> offset;
00741 
00742     if (xcf_io.device()->status() != IO_Ok) {
00743         kdDebug(399) << "XCF: read failure on layer " << layer.name << " image header" << endl;
00744         return false;
00745     }
00746 
00747     // GIMP stores images in a "mipmap"-like format (multiple levels of
00748     // increasingly lower resolution). Only the top level is used here,
00749     // however.
00750 
00751     Q_UINT32 junk;
00752     do {
00753         xcf_io >> junk;
00754 
00755         if (xcf_io.device()->status() != IO_Ok) {
00756             kdDebug(399) << "XCF: read failure on layer " << layer.name << " level offsets" << endl;
00757             return false;
00758         }
00759     } while (junk != 0);
00760 
00761     QIODevice::Offset saved_pos = xcf_io.device()->at();
00762 
00763     xcf_io.device()->at(offset);
00764     if (!loadLevel(xcf_io, layer, bpp))
00765         return false;
00766 
00767     xcf_io.device()->at(saved_pos);
00768     return true;
00769 }
00770 
00771 
00780 bool XCFImageFormat::loadLevel(QDataStream& xcf_io, Layer& layer, Q_INT32 bpp)
00781 {
00782     Q_INT32 width;
00783     Q_INT32 height;
00784     Q_UINT32 offset;
00785 
00786     xcf_io >> width >> height >> offset;
00787 
00788     if (xcf_io.device()->status() != IO_Ok) {
00789         kdDebug(399) << "XCF: read failure on layer " << layer.name << " level info" << endl;
00790         return false;
00791     }
00792 
00793     if (offset == 0)
00794         return true;
00795 
00796     for (uint j = 0; j < layer.nrows; j++) {
00797         for (uint i = 0; i < layer.ncols; i++) {
00798 
00799             if (offset == 0) {
00800                 kdDebug(399) << "XCF: incorrect number of tiles in layer " << layer.name << endl;
00801                 return false;
00802             }
00803 
00804             QIODevice::Offset saved_pos = xcf_io.device()->at();
00805             Q_UINT32 offset2;
00806             xcf_io >> offset2;
00807 
00808             if (xcf_io.device()->status() != IO_Ok) {
00809                 kdDebug(399) << "XCF: read failure on layer " << layer.name << " level offset look-ahead" << endl;
00810                 return false;
00811             }
00812 
00813             // Evidently, RLE can occasionally expand a tile instead of compressing it!
00814 
00815             if (offset2 == 0)
00816                 offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
00817 
00818             xcf_io.device()->at(offset);
00819             int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
00820 
00821             if (!loadTileRLE(xcf_io, layer.tile, size, offset2 - offset, bpp))
00822                 return false;
00823 
00824             // The bytes in the layer tile are juggled differently depending on
00825             // the target QImage. The caller has set layer.assignBytes to the
00826             // appropriate routine.
00827 
00828             layer.assignBytes(layer, i, j);
00829 
00830             xcf_io.device()->at(saved_pos);
00831             xcf_io >> offset;
00832 
00833             if (xcf_io.device()->status() != IO_Ok) {
00834                 kdDebug(399) << "XCF: read failure on layer " << layer.name << " level offset" << endl;
00835                 return false;
00836             }
00837         }
00838     }
00839 
00840     return true;
00841 }
00842 
00843 
00850 bool XCFImageFormat::loadMask(QDataStream& xcf_io, Layer& layer)
00851 {
00852     Q_INT32 width;
00853     Q_INT32 height;
00854     char* name;
00855 
00856     xcf_io >> width >> height >> name;
00857 
00858     if (xcf_io.device()->status() != IO_Ok) {
00859         kdDebug(399) << "XCF: read failure on mask info" << endl;
00860         return false;
00861     }
00862 
00863     delete name;
00864 
00865     if (!loadChannelProperties(xcf_io, layer))
00866         return false;
00867 
00868     Q_UINT32 hierarchy_offset;
00869     xcf_io >> hierarchy_offset;
00870 
00871     if (xcf_io.device()->status() != IO_Ok) {
00872         kdDebug(399) << "XCF: read failure on mask image offset" << endl;
00873         return false;
00874     }
00875 
00876     xcf_io.device()->at(hierarchy_offset);
00877     layer.assignBytes = assignMaskBytes;
00878 
00879     if (!loadHierarchy(xcf_io, layer))
00880         return false;
00881 
00882     return true;
00883 }
00884 
00885 
00909 bool XCFImageFormat::loadTileRLE(QDataStream& xcf_io, uchar* tile, int image_size,
00910         int data_length, Q_INT32 bpp)
00911 {
00912     uchar* data;
00913 
00914     uchar* xcfdata;
00915     uchar* xcfodata;
00916     uchar* xcfdatalimit;
00917 
00918     xcfdata = xcfodata = new uchar[data_length];
00919 
00920     xcf_io.readRawBytes((char*)xcfdata, data_length);
00921 
00922     if (xcf_io.device()->status() != IO_Ok) {
00923         delete[] xcfodata;
00924         kdDebug(399) << "XCF: read failure on tile" << endl;
00925         return false;
00926     }
00927 
00928     xcfdatalimit = &xcfodata[data_length - 1];
00929 
00930     for (int i = 0; i < bpp; ++i) {
00931 
00932         data = tile + i;
00933 
00934         int count = 0;
00935         int size = image_size;
00936 
00937         while (size > 0) {
00938             if (xcfdata > xcfdatalimit)
00939                 goto bogus_rle;
00940 
00941             uchar val = *xcfdata++;
00942             uint length = val;
00943 
00944             if (length >= 128) {
00945                 length = 255 - (length - 1);
00946                 if (length == 128) {
00947                     if (xcfdata >= xcfdatalimit)
00948                         goto bogus_rle;
00949 
00950                     length = (*xcfdata << 8) + xcfdata[1];
00951 
00952                     xcfdata += 2;
00953                 }
00954 
00955                 count += length;
00956                 size -= length;
00957 
00958                 if (size < 0)
00959                     goto bogus_rle;
00960 
00961                 if (&xcfdata[length - 1] > xcfdatalimit)
00962                     goto bogus_rle;
00963 
00964                 while (length-- > 0) {
00965                     *data = *xcfdata++;
00966                     data += sizeof(QRgb);
00967                 }
00968             } else {
00969                 length += 1;
00970                 if (length == 128) {
00971                     if (xcfdata >= xcfdatalimit)
00972                         goto bogus_rle;
00973 
00974                     length = (*xcfdata << 8) + xcfdata[1];
00975                     xcfdata += 2;
00976                 }
00977 
00978                 count += length;
00979                 size -= length;
00980 
00981                 if (size < 0)
00982                     goto bogus_rle;
00983 
00984                 if (xcfdata > xcfdatalimit)
00985                     goto bogus_rle;
00986 
00987                 val = *xcfdata++;
00988 
00989                 while (length-- > 0) {
00990                     *data = val;
00991                     data += sizeof(QRgb);
00992                 }
00993             }
00994         }
00995     }
00996 
00997     delete[] xcfodata;
00998     return true;
00999 
01000 bogus_rle:
01001 
01002     kdDebug(399) << "The run length encoding could not be decoded properly" << endl;
01003     delete[] xcfodata;
01004     return false;
01005 }
01006 
01007 
01015 bool XCFImageFormat::loadChannelProperties(QDataStream& xcf_io, Layer& layer)
01016 {
01017     while (true) {
01018         PropType type;
01019         QByteArray bytes;
01020 
01021         if (!loadProperty(xcf_io, type, bytes)) {
01022             kdDebug(399) << "XCF: error loading channel properties" << endl;
01023             return false;
01024         }
01025 
01026         QDataStream property(bytes, IO_ReadOnly);
01027 
01028         switch (type) {
01029             case PROP_END:
01030                 return true;
01031 
01032             case PROP_OPACITY:
01033                 property >> layer.mask_channel.opacity;
01034                 break;
01035 
01036             case PROP_VISIBLE:
01037                 property >> layer.mask_channel.visible;
01038                 break;
01039 
01040             case PROP_SHOW_MASKED:
01041                 property >> layer.mask_channel.show_masked;
01042                 break;
01043 
01044             case PROP_COLOR:
01045                 property >> layer.mask_channel.red >> layer.mask_channel.green
01046                         >> layer.mask_channel.blue;
01047                 break;
01048 
01049             case PROP_TATTOO:
01050                 property >> layer.mask_channel.tattoo;
01051                 break;
01052 
01053             default:
01054                 kdDebug(399) << "XCF: unimplemented channel property " << type
01055                         << ", size " << bytes.size() << endl;
01056         }
01057     }
01058 }
01059 
01060 
01067 void XCFImageFormat::assignMaskBytes(Layer& layer, uint i, uint j)
01068 {
01069     uchar* tile = layer.tile;
01070 
01071     for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01072         for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01073             layer.mask_tiles[j][i].setPixel(k, l, tile[0]);
01074             tile += sizeof(QRgb);
01075         }
01076     }
01077 }
01078 
01079 
01108 bool XCFImageFormat::initializeImage(XCFImage& xcf_image)
01109 {
01110     // (Aliases to make the code look a little better.)
01111     Layer& layer(xcf_image.layer);
01112     QImage& image(xcf_image.image);
01113 
01114     switch (layer.type) {
01115         case RGB_GIMAGE:
01116             if (layer.opacity == OPAQUE_OPACITY) {
01117                 image.create( xcf_image.width, xcf_image.height, 32);
01118                 if( image.isNull())
01119                     return false;
01120                 image.fill(qRgb(255, 255, 255));
01121                 break;
01122             } // else, fall through to 32-bit representation
01123 
01124         case RGBA_GIMAGE:
01125             image.create(xcf_image.width, xcf_image.height, 32);
01126             if( image.isNull())
01127                 return false;
01128             image.fill(qRgba(255, 255, 255, 0));
01129             // Turning this on prevents fill() from affecting the alpha channel,
01130             // by the way.
01131             image.setAlphaBuffer(true);
01132             break;
01133 
01134         case GRAY_GIMAGE:
01135             if (layer.opacity == OPAQUE_OPACITY) {
01136                 image.create(xcf_image.width, xcf_image.height, 8, 256);
01137                 if( image.isNull())
01138                     return false;
01139                 setGrayPalette(image);
01140                 image.fill(255);
01141                 break;
01142             } // else, fall through to 32-bit representation
01143 
01144         case GRAYA_GIMAGE:
01145             image.create(xcf_image.width, xcf_image.height, 32);
01146             if( image.isNull())
01147                 return false;
01148             image.fill(qRgba(255, 255, 255, 0));
01149             image.setAlphaBuffer(true);
01150             break;
01151 
01152         case INDEXED_GIMAGE:
01153             // As noted in the table above, there are quite a few combinations
01154             // which are possible with indexed images, depending on the
01155             // presense of transparency (note: not translucency, which is not
01156             // supported by The GIMP for indexed images) and the number of
01157             // individual colors.
01158 
01159             // Note: Qt treats a bitmap with a Black and White color palette
01160             // as a mask, so only the "on" bits are drawn, regardless of the
01161             // order color table entries. Otherwise (i.e., at least one of the
01162             // color table entries is not black or white), it obeys the one-
01163             // or two-color palette. Have to ask about this...
01164 
01165             if (xcf_image.num_colors <= 2) {
01166                 image.create(xcf_image.width, xcf_image.height,
01167                         1, xcf_image.num_colors,
01168                         QImage::LittleEndian);
01169                 if( image.isNull())
01170                     return false;
01171                 image.fill(0);
01172                 setPalette(xcf_image, image);
01173             } else if (xcf_image.num_colors <= 256) {
01174                 image.create(xcf_image.width, xcf_image.height,
01175                 8, xcf_image.num_colors,
01176                 QImage::LittleEndian);
01177                 if( image.isNull())
01178                     return false;
01179                 image.fill(0);
01180                 setPalette(xcf_image, image);
01181             }
01182             break;
01183 
01184         case INDEXEDA_GIMAGE:
01185             if (xcf_image.num_colors == 1) {
01186                 // Plenty(!) of room to add a transparent color
01187                 xcf_image.num_colors++;
01188                 xcf_image.palette.resize(xcf_image.num_colors);
01189                 xcf_image.palette[1] = xcf_image.palette[0];
01190                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01191 
01192                 image.create(xcf_image.width, xcf_image.height,
01193                         1, xcf_image.num_colors,
01194                         QImage::LittleEndian);
01195                 if( image.isNull())
01196                     return false;
01197                 image.fill(0);
01198                 setPalette(xcf_image, image);
01199                 image.setAlphaBuffer(true);
01200             } else if (xcf_image.num_colors < 256) {
01201                 // Plenty of room to add a transparent color
01202                 xcf_image.num_colors++;
01203                 xcf_image.palette.resize(xcf_image.num_colors);
01204                 for (int c = xcf_image.num_colors - 1; c >= 1; c--)
01205                     xcf_image.palette[c] = xcf_image.palette[c - 1];
01206 
01207                 xcf_image.palette[0] = qRgba(255, 255, 255, 0);
01208                 image.create( xcf_image.width, xcf_image.height,
01209                         8, xcf_image.num_colors);
01210                 if( image.isNull())
01211                     return false;
01212                 image.fill(0);
01213                 setPalette(xcf_image, image);
01214                 image.setAlphaBuffer(true);
01215             } else {
01216                 // No room for a transparent color, so this has to be promoted to
01217                 // true color. (There is no equivalent PNG representation output
01218                 // from The GIMP as of v1.2.)
01219                 image.create(xcf_image.width, xcf_image.height, 32);
01220                 if( image.isNull())
01221                     return false;
01222                 image.fill(qRgba(255, 255, 255, 0));
01223                 image.setAlphaBuffer(true);
01224             }
01225             break;
01226     }
01227 
01228     image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER));
01229     image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER));
01230     return true;
01231 }
01232 
01233 
01239 void XCFImageFormat::copyLayerToImage(XCFImage& xcf_image)
01240 {
01241     Layer& layer(xcf_image.layer);
01242     QImage& image(xcf_image.image);
01243     PixelCopyOperation copy = 0;
01244 
01245     switch (layer.type) {
01246         case RGB_GIMAGE:
01247         case RGBA_GIMAGE:
01248             copy = copyRGBToRGB;
01249             break;
01250         case GRAY_GIMAGE:
01251             if (layer.opacity == OPAQUE_OPACITY)
01252                 copy = copyGrayToGray;
01253             else
01254                 copy = copyGrayToRGB;
01255             break;
01256         case GRAYA_GIMAGE:
01257             copy = copyGrayAToRGB;
01258             break;
01259         case INDEXED_GIMAGE:
01260             copy = copyIndexedToIndexed;
01261             break;
01262         case INDEXEDA_GIMAGE:
01263             if (xcf_image.image.depth() <= 8)
01264                 copy = copyIndexedAToIndexed;
01265             else
01266                 copy = copyIndexedAToRGB;
01267     }
01268 
01269     // For each tile...
01270 
01271     for (uint j = 0; j < layer.nrows; j++) {
01272         uint y = j * TILE_HEIGHT;
01273 
01274         for (uint i = 0; i < layer.ncols; i++) {
01275             uint x = i * TILE_WIDTH;
01276 
01277             // This seems the best place to apply the dissolve because it
01278             // depends on the global position of each tile's
01279             // pixels. Apparently it's the only mode which can apply to a
01280             // single layer.
01281 
01282             if (layer.mode == DISSOLVE_MODE) {
01283                 if (layer.type == RGBA_GIMAGE)
01284                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01285 
01286                 else if (layer.type == GRAYA_GIMAGE)
01287                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01288             }
01289 
01290             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01291                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01292 
01293                     int m = x + k + layer.x_offset;
01294                     int n = y + l + layer.y_offset;
01295 
01296                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01297                         continue;
01298 
01299                     (*copy)(layer, i, j, k, l, image, m, n);
01300                 }
01301             }
01302         }
01303     }
01304 }
01305 
01306 
01320 void XCFImageFormat::copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01321         QImage& image, int m, int n)
01322 {
01323     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01324     uchar src_a = layer.opacity;
01325 
01326     if (layer.type == RGBA_GIMAGE)
01327         src_a = INT_MULT(src_a, qAlpha(src));
01328 
01329     // Apply the mask (if any)
01330 
01331     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
01332             layer.mask_tiles[j].size() > i)
01333         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01334 
01335     image.setPixel(m, n, qRgba(src, src_a));
01336 }
01337 
01338 
01350 void XCFImageFormat::copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01351         QImage& image, int m, int n)
01352 {
01353     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01354     image.setPixel(m, n, src);
01355 }
01356 
01357 
01371 void XCFImageFormat::copyGrayToRGB(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.opacity;
01376     image.setPixel(m, n, qRgba(src, src_a));
01377 }
01378 
01379 
01393 void XCFImageFormat::copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
01394                       QImage& image, int m, int n)
01395 {
01396     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01397     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01398     src_a = INT_MULT(src_a, layer.opacity);
01399 
01400     // Apply the mask (if any)
01401 
01402     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
01403             layer.mask_tiles[j].size() > i)
01404         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01405 
01406     image.setPixel(m, n, qRgba(src, src_a));
01407 }
01408 
01409 
01421 void XCFImageFormat::copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
01422         QImage& image, int m, int n)
01423 {
01424     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01425     image.setPixel(m, n, src);
01426 }
01427 
01428 
01440 void XCFImageFormat::copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
01441         QImage& image, int m, int n)
01442 {
01443     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
01444     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01445     src_a = INT_MULT(src_a, layer.opacity);
01446 
01447     if (layer.apply_mask == 1 &&
01448             layer.mask_tiles.size() > j &&
01449             layer.mask_tiles[j].size() > i)
01450         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01451 
01452     if (src_a > 127)
01453         src++;
01454     else
01455         src = 0;
01456 
01457 image.setPixel(m, n, src);
01458 }
01459 
01460 
01474 void XCFImageFormat::copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
01475         QImage& image, int m, int n)
01476 {
01477     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01478     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01479     src_a = INT_MULT(src_a, layer.opacity);
01480 
01481     // Apply the mask (if any)
01482     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
01483             layer.mask_tiles[j].size() > i)
01484         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01485 
01486     // This is what appears in the GIMP window
01487     if (src_a <= 127)
01488         src_a = 0;
01489     else
01490         src_a = OPAQUE_OPACITY;
01491 
01492     image.setPixel(m, n, qRgba(src, src_a));
01493 }
01494 
01495 
01500 void XCFImageFormat::mergeLayerIntoImage(XCFImage& xcf_image)
01501 {
01502     Layer& layer(xcf_image.layer);
01503     QImage& image(xcf_image.image);
01504 
01505     PixelMergeOperation merge = 0;
01506 
01507     switch (layer.type) {
01508         case RGB_GIMAGE:
01509         case RGBA_GIMAGE:
01510             merge = mergeRGBToRGB;
01511             break;
01512         case GRAY_GIMAGE:
01513             if (layer.opacity == OPAQUE_OPACITY)
01514                 merge = mergeGrayToGray;
01515             else
01516                 merge = mergeGrayToRGB;
01517             break;
01518         case GRAYA_GIMAGE:
01519             if (xcf_image.image.depth() <= 8)
01520                 merge = mergeGrayAToGray;
01521             else
01522                 merge = mergeGrayAToRGB;
01523             break;
01524         case INDEXED_GIMAGE:
01525             merge = mergeIndexedToIndexed;
01526             break;
01527         case INDEXEDA_GIMAGE:
01528             if (xcf_image.image.depth() <= 8)
01529                 merge = mergeIndexedAToIndexed;
01530             else
01531                 merge = mergeIndexedAToRGB;
01532     }
01533 
01534     for (uint j = 0; j < layer.nrows; j++) {
01535         uint y = j * TILE_HEIGHT;
01536 
01537         for (uint i = 0; i < layer.ncols; i++) {
01538             uint x = i * TILE_WIDTH;
01539 
01540             // This seems the best place to apply the dissolve because it
01541             // depends on the global position of each tile's
01542             // pixels. Apparently it's the only mode which can apply to a
01543             // single layer.
01544 
01545             if (layer.mode == DISSOLVE_MODE) {
01546                 if (layer.type == RGBA_GIMAGE)
01547                     dissolveRGBPixels(layer.image_tiles[j][i], x, y);
01548 
01549                 else if (layer.type == GRAYA_GIMAGE)
01550                     dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
01551             }
01552 
01553             for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
01554                 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
01555 
01556                     int m = x + k + layer.x_offset;
01557                     int n = y + l + layer.y_offset;
01558 
01559                     if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
01560                         continue;
01561 
01562                     (*merge)(layer, i, j, k, l, image, m, n);
01563                 }
01564             }
01565         }
01566     }
01567 }
01568 
01569 
01583 void XCFImageFormat::mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
01584         QImage& image, int m, int n)
01585 {
01586     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01587     QRgb dst = image.pixel(m, n);
01588 
01589     uchar src_r = qRed(src);
01590     uchar src_g = qGreen(src);
01591     uchar src_b = qBlue(src);
01592     uchar src_a = qAlpha(src);
01593 
01594     uchar dst_r = qRed(dst);
01595     uchar dst_g = qGreen(dst);
01596     uchar dst_b = qBlue(dst);
01597     uchar dst_a = qAlpha(dst);
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 = KMIN(src_a, dst_a);
01605             }
01606             break;
01607         case DIVIDE_MODE: {
01608             src_r = KMIN((dst_r * 256) / (1 + src_r), 255);
01609             src_g = KMIN((dst_g * 256) / (1 + src_g), 255);
01610             src_b = KMIN((dst_b * 256) / (1 + src_b), 255);
01611             src_a = KMIN(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 = KMIN(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 = KMIN(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 = KMIN(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 = KMIN(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 = KMIN(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 = KMIN( 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 = KMIN(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 = KMIN( 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 = KMIN(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 = KMIN(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 = KMIN(src_a, dst_a);
01734             }
01735             break;
01736     }
01737 
01738     src_a = INT_MULT(src_a, layer.opacity);
01739 
01740     // Apply the mask (if any)
01741 
01742     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
01743             layer.mask_tiles[j].size() > i)
01744         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01745 
01746     uchar new_r, new_g, new_b, new_a;
01747     new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
01748 
01749     float src_ratio = (float)src_a / new_a;
01750     float dst_ratio = 1.0 - src_ratio;
01751 
01752     new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
01753     new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
01754     new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
01755 
01756     if (!layer_modes[layer.mode].affect_alpha)
01757         new_a = dst_a;
01758 
01759     image.setPixel(m, n, qRgba(new_r, new_g, new_b, new_a));
01760 }
01761 
01762 
01774 void XCFImageFormat::mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
01775         QImage& image, int m, int n)
01776 {
01777     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01778     image.setPixel(m, n, src);
01779 }
01780 
01781 
01793 void XCFImageFormat::mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
01794         QImage& image, int m, int n)
01795 {
01796     int src = qGray(layer.image_tiles[j][i].pixel(k, l));
01797     int dst = image.pixelIndex(m, n);
01798 
01799     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01800 
01801     switch (layer.mode) {
01802         case MULTIPLY_MODE: {
01803                 src = INT_MULT( src, dst );
01804             }
01805             break;
01806         case DIVIDE_MODE: {
01807                 src = KMIN((dst * 256) / (1 + src), 255);
01808             }
01809             break;
01810         case SCREEN_MODE: {
01811                 src = 255 - INT_MULT(255 - dst, 255 - src);
01812             }
01813             break;
01814         case OVERLAY_MODE: {
01815                 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
01816             }
01817             break;
01818         case DIFFERENCE_MODE: {
01819                 src = dst > src ? dst - src : src - dst;
01820             }
01821             break;
01822         case ADDITION_MODE: {
01823                 src = add_lut(dst,src);
01824             }
01825             break;
01826         case SUBTRACT_MODE: {
01827                 src = dst > src ? dst - src : 0;
01828             }
01829             break;
01830         case DARKEN_ONLY_MODE: {
01831                 src = dst < src ? dst : src;
01832             }
01833             break;
01834         case LIGHTEN_ONLY_MODE: {
01835                 src = dst < src ? src : dst;
01836             }
01837             break;
01838     }
01839 
01840     src_a = INT_MULT(src_a, layer.opacity);
01841 
01842     // Apply the mask (if any)
01843 
01844     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
01845             layer.mask_tiles[j].size() > i)
01846         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01847 
01848     uchar new_a = OPAQUE_OPACITY;
01849 
01850     float src_ratio = (float)src_a / new_a;
01851     float dst_ratio = 1.0 - src_ratio;
01852 
01853     uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
01854 
01855     image.setPixel(m, n, new_g);
01856 }
01857 
01858 
01872 void XCFImageFormat::mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
01873         QImage& image, int m, int n)
01874 {
01875     QRgb src = layer.image_tiles[j][i].pixel(k, l);
01876     uchar src_a = layer.opacity;
01877     image.setPixel(m, n, qRgba(src, src_a));
01878 }
01879 
01880 
01894 void XCFImageFormat::mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
01895         QImage& image, int m, int n)
01896 {
01897     int src = qGray(layer.image_tiles[j][i].pixel(k, l));
01898     int dst = qGray(image.pixel(m, n));
01899 
01900     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
01901     uchar dst_a = qAlpha(image.pixel(m, n));
01902 
01903     switch (layer.mode) {
01904         case MULTIPLY_MODE: {
01905                 src = INT_MULT(src, dst);
01906                 src_a = KMIN(src_a, dst_a);
01907             }
01908             break;
01909         case DIVIDE_MODE: {
01910                 src = KMIN((dst * 256) / (1 + src), 255);
01911                 src_a = KMIN(src_a, dst_a);
01912             }
01913             break;
01914         case SCREEN_MODE: {
01915                 src = 255 - INT_MULT(255 - dst, 255 - src);
01916                 src_a = KMIN(src_a, dst_a);
01917             }
01918             break;
01919         case OVERLAY_MODE: {
01920                 src = INT_MULT( dst, dst + INT_MULT(2 * src, 255 - dst));
01921                 src_a = KMIN(src_a, dst_a);
01922             }
01923             break;
01924         case DIFFERENCE_MODE: {
01925                 src = dst > src ? dst - src : src - dst;
01926                 src_a = KMIN(src_a, dst_a);
01927             }
01928             break;
01929         case ADDITION_MODE: {
01930                 src = add_lut(dst,src);
01931                 src_a = KMIN(src_a, dst_a);
01932             }
01933             break;
01934         case SUBTRACT_MODE: {
01935                 src = dst > src ? dst - src : 0;
01936                 src_a = KMIN(src_a, dst_a);
01937             }
01938             break;
01939         case DARKEN_ONLY_MODE: {
01940                 src = dst < src ? dst : src;
01941                 src_a = KMIN(src_a, dst_a);
01942             }
01943             break;
01944         case LIGHTEN_ONLY_MODE: {
01945                 src = dst < src ? src : dst;
01946                 src_a = KMIN(src_a, dst_a);
01947             }
01948             break;
01949     }
01950 
01951     src_a = INT_MULT(src_a, layer.opacity);
01952 
01953     // Apply the mask (if any)
01954     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
01955             layer.mask_tiles[j].size() > i)
01956         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
01957 
01958     uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
01959 
01960     float src_ratio = (float)src_a / new_a;
01961     float dst_ratio = 1.0 - src_ratio;
01962 
01963     uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
01964 
01965     if (!layer_modes[layer.mode].affect_alpha)
01966         new_a = dst_a;
01967 
01968     image.setPixel(m, n, qRgba(new_g, new_g, new_g, new_a));
01969 }
01970 
01971 
01983 void XCFImageFormat::mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
01984         QImage& image, int m, int n)
01985 {
01986     int src = layer.image_tiles[j][i].pixelIndex(k, l);
01987     image.setPixel(m, n, src);
01988 }
01989 
01990 
02002 void XCFImageFormat::mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
02003         QImage& image, int m, int n)
02004 {
02005     uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
02006     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02007     src_a = INT_MULT( src_a, layer.opacity );
02008 
02009     if ( layer.apply_mask == 1 &&
02010             layer.mask_tiles.size() > j &&
02011             layer.mask_tiles[j].size() > i)
02012         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02013 
02014     if (src_a > 127) {
02015         src++;
02016         image.setPixel(m, n, src);
02017     }
02018 }
02019 
02020 
02034 void XCFImageFormat::mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
02035         QImage& image, int m, int n)
02036 {
02037     QRgb src = layer.image_tiles[j][i].pixel(k, l);
02038     uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
02039     src_a = INT_MULT(src_a, layer.opacity);
02040 
02041     // Apply the mask (if any)
02042     if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
02043             layer.mask_tiles[j].size() > i)
02044         src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
02045 
02046     // This is what appears in the GIMP window
02047     if (src_a <= 127)
02048         src_a = 0;
02049     else
02050         src_a = OPAQUE_OPACITY;
02051 
02052     image.setPixel(m, n, qRgba(src, src_a));
02053 }
02054 
02055 
02063 void XCFImageFormat::dissolveRGBPixels ( QImage& image, int x, int y )
02064 {
02065     // The apparently spurious rand() calls are to wind the random
02066     // numbers up to the same point for each tile.
02067 
02068     for (int l = 0; l < image.height(); l++) {
02069         srand(random_table[( l + y ) % RANDOM_TABLE_SIZE]);
02070 
02071         for (int k = 0; k < x; k++)
02072             rand();
02073 
02074         for (int k = 0; k < image.width(); k++) {
02075             int rand_val = rand() & 0xff;
02076             QRgb pixel = image.pixel(k, l);
02077 
02078             if (rand_val > qAlpha(pixel)) {
02079                 image.setPixel(k, l, qRgba(pixel, 0));
02080             }
02081         }
02082     }
02083 }
02084 
02085 
02095 void XCFImageFormat::dissolveAlphaPixels ( QImage& image, int x, int y )
02096 {
02097     // The apparently spurious rand() calls are to wind the random
02098     // numbers up to the same point for each tile.
02099 
02100     for (int l = 0; l < image.height(); l++) {
02101         srand( random_table[(l + y) % RANDOM_TABLE_SIZE]);
02102 
02103         for (int k = 0; k < x; k++)
02104             rand();
02105 
02106         for (int k = 0; k < image.width(); k++) {
02107             int rand_val = rand() & 0xff;
02108             uchar alpha = image.pixelIndex(k, l);
02109 
02110             if (rand_val > alpha) {
02111                 image.setPixel(k, l, 0);
02112             }
02113         }
02114     }
02115 }
02116 

KImgIO

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal