xcf.cpp
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