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

KImgIO

  • sources
  • kde-4.12
  • kdelibs
  • kimgio
xcf.cpp
Go to the documentation of this file.
1 /*
2  * qxcfi.cpp: A Qt 3 plug-in for reading GIMP XCF image files
3  * Copyright (C) 2001 lignum Computing, Inc. <allen@lignumcomputing.com>
4  * Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org>
5  *
6  * This plug-in is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  */
21 
22 #include "xcf.h"
23 
24 #include <stdlib.h>
25 #include <QtGui/QImage>
26 #include <QtGui/QPainter>
27 #include <QtCore/QIODevice>
28 #include <QtCore/QStack>
29 #include <QtCore/QVector>
30 
31 #include <kdebug.h>
32 
33 
34 int XCFImageFormat::random_table[RANDOM_TABLE_SIZE];
35 bool XCFImageFormat::random_table_initialized;
36 
37 QVector<QRgb> XCFImageFormat::grayTable;
38 
39 
40 const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
41  {true}, // NORMAL_MODE
42  {true}, // DISSOLVE_MODE
43  {true}, // BEHIND_MODE
44  {false}, // MULTIPLY_MODE
45  {false}, // SCREEN_MODE
46  {false}, // OVERLAY_MODE
47  {false}, // DIFFERENCE_MODE
48  {false}, // ADDITION_MODE
49  {false}, // SUBTRACT_MODE
50  {false}, // DARKEN_ONLY_MODE
51  {false}, // LIGHTEN_ONLY_MODE
52  {false}, // HUE_MODE
53  {false}, // SATURATION_MODE
54  {false}, // COLOR_MODE
55  {false}, // VALUE_MODE
56  {false}, // DIVIDE_MODE
57  {false}, // DODGE_MODE
58  {false}, // BURN_MODE
59  {false}, // HARDLIGHT_MODE
60  {false}, // SOFTLIGHT_MODE
61  {false}, // GRAIN_EXTRACT_MODE
62  {false}, // GRAIN_MERGE_MODE
63 };
64 
65 
67 inline QRgb qRgba ( const QRgb& rgb, int a )
68 {
69  return ((a & 0xff) << 24 | (rgb & RGB_MASK));
70 }
71 
72 
76 XCFImageFormat::XCFImageFormat()
77 {
78 }
79 
83 void XCFImageFormat::initializeRandomTable()
84 {
85  // From GIMP "paint_funcs.c" v1.2
86  srand(RANDOM_SEED);
87 
88  for (int i = 0; i < RANDOM_TABLE_SIZE; i++)
89  random_table[i] = rand();
90 
91  for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
92  int tmp;
93  int swap = i + rand() % (RANDOM_TABLE_SIZE - i);
94  tmp = random_table[i];
95  random_table[i] = random_table[swap];
96  random_table[swap] = tmp;
97  }
98 }
99 
100 inline
101 int XCFImageFormat::add_lut( int a, int b ) {
102  return qMin( a + b, 255 );
103 }
104 
105 bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
106 {
107  XCFImage xcf_image;
108  QDataStream xcf_io(device);
109 
110  char tag[14];;
111 
112  if (xcf_io.readRawData(tag, sizeof(tag)) != sizeof(tag)) {
113  kDebug(399) << "XCF: read failure on header tag";
114  return false;
115  }
116  if (qstrncmp(tag, "gimp xcf", 8) != 0) {
117  kDebug(399) << "XCF: read called on non-XCF file";
118  return false;
119  }
120 
121  xcf_io >> xcf_image.width >> xcf_image.height >> xcf_image.type;
122 
123 kDebug() << tag << " " << xcf_image.width << " " << xcf_image.height << " " << xcf_image.type;
124  if (!loadImageProperties(xcf_io, xcf_image))
125  return false;
126 
127  // The layers appear to be stored in top-to-bottom order. This is
128  // the reverse of how a merged image must be computed. So, the layer
129  // offsets are pushed onto a LIFO stack (thus, we don't have to load
130  // all the data of all layers before beginning to construct the
131  // merged image).
132 
133  QStack<qint32> layer_offsets;
134 
135  while (true) {
136  qint32 layer_offset;
137 
138  xcf_io >> layer_offset;
139 
140  if (layer_offset == 0)
141  break;
142 
143  layer_offsets.push(layer_offset);
144  }
145 
146  xcf_image.num_layers = layer_offsets.size();
147 
148  if (layer_offsets.size() == 0) {
149  kDebug(399) << "XCF: no layers!";
150  return false;
151  }
152 
153  // Load each layer and add it to the image
154  while (!layer_offsets.isEmpty()) {
155  qint32 layer_offset = layer_offsets.pop();
156 
157  xcf_io.device()->seek(layer_offset);
158 
159  if (!loadLayer(xcf_io, xcf_image))
160  return false;
161  }
162 
163  if (!xcf_image.initialized) {
164  kDebug(399) << "XCF: no visible layers!";
165  return false;
166  }
167 
168  *outImage = xcf_image.image;
169  return true;
170 }
171 
172 
180 bool XCFImageFormat::loadImageProperties(QDataStream& xcf_io, XCFImage& xcf_image)
181 {
182  while (true) {
183  PropType type;
184  QByteArray bytes;
185 
186  if (!loadProperty(xcf_io, type, bytes)) {
187  kDebug(399) << "XCF: error loading global image properties";
188  return false;
189  }
190 
191  QDataStream property(bytes);
192 
193  switch (type) {
194  case PROP_END:
195  return true;
196 
197  case PROP_COMPRESSION:
198  property >> xcf_image.compression;
199  break;
200 
201  case PROP_RESOLUTION:
202  property >> xcf_image.x_resolution >> xcf_image.y_resolution;
203  break;
204 
205  case PROP_TATTOO:
206  property >> xcf_image.tattoo;
207  break;
208 
209  case PROP_PARASITES:
210  while (!property.atEnd()) {
211  char* tag;
212  quint32 size;
213 
214  property.readBytes(tag, size);
215 
216  quint32 flags;
217  char* data=0;
218  property >> flags >> data;
219 
220  if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0)
221  xcf_image.image.setText("Comment", 0, data);
222 
223  delete[] tag;
224  delete[] data;
225  }
226  break;
227 
228  case PROP_UNIT:
229  property >> xcf_image.unit;
230  break;
231 
232  case PROP_PATHS: // This property is ignored.
233  break;
234 
235  case PROP_USER_UNIT: // This property is ignored.
236  break;
237 
238  case PROP_COLORMAP:
239  property >> xcf_image.num_colors;
240  if(xcf_image.num_colors < 0 || xcf_image.num_colors > 65535)
241  return false;
242 
243  xcf_image.palette.reserve(xcf_image.num_colors);
244 
245  for (int i = 0; i < xcf_image.num_colors; i++) {
246  uchar r, g, b;
247  property >> r >> g >> b;
248  xcf_image.palette.push_back( qRgb(r,g,b) );
249  }
250  break;
251 
252  default:
253  kDebug(399) << "XCF: unimplemented image property" << type
254  << ", size " << bytes.size() << endl;
255  }
256  }
257 }
258 
259 
267 bool XCFImageFormat::loadProperty(QDataStream& xcf_io, PropType& type, QByteArray& bytes)
268 {
269  quint32 foo;
270  xcf_io >> foo;
271  type=PropType(foo); // TODO urks
272 
273  char* data = 0;
274  quint32 size;
275 
276  // The colormap property size is not the correct number of bytes:
277  // The GIMP source xcf.c has size = 4 + ncolors, but it should be
278  // 4 + 3 * ncolors
279 
280  if (type == PROP_COLORMAP) {
281  xcf_io >> size;
282  quint32 ncolors;
283  xcf_io >> ncolors;
284 
285  if(size > 65535 || size < 4)
286  return false;
287 
288  size = 3 * ncolors + 4;
289  data = new char[size];
290 
291  // since we already read "ncolors" from the stream, we put that data back
292  data[0] = 0;
293  data[1] = 0;
294  data[2] = ncolors >> 8;
295  data[3] = ncolors & 255;
296 
297  // ... and read the remaining bytes from the stream
298  xcf_io.readRawData(data + 4, size - 4);
299  } else if (type == PROP_USER_UNIT) {
300  // The USER UNIT property size is not correct. I'm not sure why, though.
301  float factor;
302  qint32 digits;
303 
304  xcf_io >> size >> factor >> digits;
305 
306  for (int i = 0; i < 5; i++) {
307  char* unit_strings;
308 
309  xcf_io >> unit_strings;
310 
311  delete[] unit_strings;
312 
313  if (xcf_io.device()->atEnd()) {
314  kDebug(399) << "XCF: read failure on property " << type;
315  return false;
316  }
317  }
318 
319  size = 0;
320  } else {
321  xcf_io >> size;
322  if(size >256000)
323  return false;
324  data = new char[size];
325  xcf_io.readRawData(data, size);
326  }
327 
328  if (size != 0 && data)
329  bytes = QByteArray(data,size);
330 
331  delete [] data;
332 
333  return true;
334 }
335 
336 
345 bool XCFImageFormat::loadLayer(QDataStream& xcf_io, XCFImage& xcf_image)
346 {
347  Layer& layer(xcf_image.layer);
348  delete[] layer.name;
349 
350  xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
351 
352  if (!loadLayerProperties(xcf_io, layer))
353  return false;
354 #if 0
355  cout << "layer: \"" << layer.name << "\", size: " << layer.width << " x "
356  << layer.height << ", type: " << layer.type << ", mode: " << layer.mode
357  << ", opacity: " << layer.opacity << ", visible: " << layer.visible
358  << ", offset: " << layer.x_offset << ", " << layer.y_offset << endl;
359 #endif
360  // Skip reading the rest of it if it is not visible. Typically, when
361  // you export an image from the The GIMP it flattens (or merges) only
362  // the visible layers into the output image.
363 
364  if (layer.visible == 0)
365  return true;
366 
367  // If there are any more layers, merge them into the final QImage.
368 
369  xcf_io >> layer.hierarchy_offset >> layer.mask_offset;
370 
371  // Allocate the individual tile QImages based on the size and type
372  // of this layer.
373 
374  if( !composeTiles(xcf_image))
375  return false;
376  xcf_io.device()->seek(layer.hierarchy_offset);
377 
378  // As tiles are loaded, they are copied into the layers tiles by
379  // this routine. (loadMask(), below, uses a slightly different
380  // version of assignBytes().)
381 
382  layer.assignBytes = assignImageBytes;
383 
384  if (!loadHierarchy(xcf_io, layer))
385  return false;
386 
387  if (layer.mask_offset != 0) {
388  xcf_io.device()->seek(layer.mask_offset);
389 
390  if (!loadMask(xcf_io, layer))
391  return false;
392  }
393 
394  // Now we should have enough information to initialize the final
395  // QImage. The first visible layer determines the attributes
396  // of the QImage.
397 
398  if (!xcf_image.initialized) {
399  if( !initializeImage(xcf_image))
400  return false;
401  copyLayerToImage(xcf_image);
402  xcf_image.initialized = true;
403  } else
404  mergeLayerIntoImage(xcf_image);
405 
406  return true;
407 }
408 
409 
417 bool XCFImageFormat::loadLayerProperties(QDataStream& xcf_io, Layer& layer)
418 {
419  while (true) {
420  PropType type;
421  QByteArray bytes;
422 
423  if (!loadProperty(xcf_io, type, bytes)) {
424  kDebug(399) << "XCF: error loading layer properties";
425  return false;
426  }
427 
428  QDataStream property(bytes);
429 
430  switch (type) {
431  case PROP_END:
432  return true;
433 
434  case PROP_ACTIVE_LAYER:
435  layer.active = true;
436  break;
437 
438  case PROP_OPACITY:
439  property >> layer.opacity;
440  break;
441 
442  case PROP_VISIBLE:
443  property >> layer.visible;
444  break;
445 
446  case PROP_LINKED:
447  property >> layer.linked;
448  break;
449 
450  case PROP_PRESERVE_TRANSPARENCY:
451  property >> layer.preserve_transparency;
452  break;
453 
454  case PROP_APPLY_MASK:
455  property >> layer.apply_mask;
456  break;
457 
458  case PROP_EDIT_MASK:
459  property >> layer.edit_mask;
460  break;
461 
462  case PROP_SHOW_MASK:
463  property >> layer.show_mask;
464  break;
465 
466  case PROP_OFFSETS:
467  property >> layer.x_offset >> layer.y_offset;
468  break;
469 
470  case PROP_MODE:
471  property >> layer.mode;
472  break;
473 
474  case PROP_TATTOO:
475  property >> layer.tattoo;
476  break;
477 
478  default:
479  kDebug(399) << "XCF: unimplemented layer property " << type
480  << ", size " << bytes.size() << endl;
481  }
482  }
483 }
484 
485 
491 bool XCFImageFormat::composeTiles(XCFImage& xcf_image)
492 {
493  Layer& layer(xcf_image.layer);
494 
495  layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
496  layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
497 
498  //kDebug(399) << "IMAGE: height=" << xcf_image.height << ", width=" << xcf_image.width;
499  //kDebug(399) << "LAYER: height=" << layer.height << ", width=" << layer.width;
500  //kDebug(399) << "LAYER: rows=" << layer.nrows << ", columns=" << layer.ncols;
501 
502  // SANITY CHECK: Catch corrupted XCF image file where the width or height
503  // of a tile is reported are bogus. See Bug# 234030.
504  if (layer.width > 32767 || layer.height > 32767 || layer.width * layer.height > 16384 * 16384)
505  return false;
506 
507  layer.image_tiles.resize(layer.nrows);
508 
509  if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
510  layer.alpha_tiles.resize(layer.nrows);
511 
512  if (layer.mask_offset != 0)
513  layer.mask_tiles.resize(layer.nrows);
514 
515  for (uint j = 0; j < layer.nrows; j++) {
516  layer.image_tiles[j].resize(layer.ncols);
517 
518  if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
519  layer.alpha_tiles[j].resize(layer.ncols);
520 
521  if (layer.mask_offset != 0)
522  layer.mask_tiles[j].resize(layer.ncols);
523  }
524 
525  for (uint j = 0; j < layer.nrows; j++) {
526  for (uint i = 0; i < layer.ncols; i++) {
527 
528  uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
529  ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
530 
531  uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
532  ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
533 
534  // Try to create the most appropriate QImage (each GIMP layer
535  // type is treated slightly differently)
536 
537  switch (layer.type) {
538  case RGB_GIMAGE:
539  layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_RGB32);
540  layer.image_tiles[j][i].setNumColors(0);
541  if( layer.image_tiles[j][i].isNull())
542  return false;
543  break;
544 
545  case RGBA_GIMAGE:
546  layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_ARGB32);
547  layer.image_tiles[j][i].setNumColors(0);
548  if( layer.image_tiles[j][i].isNull())
549  return false;
550  break;
551 
552  case GRAY_GIMAGE:
553  layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
554  layer.image_tiles[j][i].setNumColors(256);
555  if( layer.image_tiles[j][i].isNull())
556  return false;
557  setGrayPalette(layer.image_tiles[j][i]);
558  break;
559 
560  case GRAYA_GIMAGE:
561  layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
562  layer.image_tiles[j][i].setNumColors(256);
563  if( layer.image_tiles[j][i].isNull())
564  return false;
565  setGrayPalette(layer.image_tiles[j][i]);
566 
567  layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
568  layer.alpha_tiles[j][i].setNumColors(256);
569  if( layer.alpha_tiles[j][i].isNull())
570  return false;
571  setGrayPalette(layer.alpha_tiles[j][i]);
572  break;
573 
574  case INDEXED_GIMAGE:
575  layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
576  layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
577  if( layer.image_tiles[j][i].isNull())
578  return false;
579  setPalette(xcf_image, layer.image_tiles[j][i]);
580  break;
581 
582  case INDEXEDA_GIMAGE:
583  layer.image_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
584  layer.image_tiles[j][i].setNumColors(xcf_image.num_colors);
585  if( layer.image_tiles[j][i].isNull())
586  return false;
587  setPalette(xcf_image, layer.image_tiles[j][i]);
588 
589  layer.alpha_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
590  layer.alpha_tiles[j][i].setNumColors(256);
591  if( layer.alpha_tiles[j][i].isNull())
592  return false;
593  setGrayPalette(layer.alpha_tiles[j][i]);
594  }
595 
596  if (layer.mask_offset != 0) {
597  layer.mask_tiles[j][i] = QImage(tile_width, tile_height, QImage::Format_Indexed8);
598  layer.mask_tiles[j][i].setNumColors(256);
599  if( layer.mask_tiles[j][i].isNull())
600  return false;
601  setGrayPalette(layer.mask_tiles[j][i]);
602  }
603  }
604  }
605  return true;
606 }
607 
608 
615 void XCFImageFormat::setGrayPalette(QImage& image)
616 {
617  if (grayTable.isEmpty()) {
618  grayTable.resize(256);
619 
620  for (int i = 0; i < 256; i++)
621  grayTable[i] = qRgb(i, i, i);
622  }
623 
624  image.setColorTable(grayTable);
625 }
626 
627 
633 void XCFImageFormat::setPalette(XCFImage& xcf_image, QImage& image)
634 {
635  Q_ASSERT (xcf_image.num_colors == xcf_image.palette.size());
636 
637  image.setColorTable(xcf_image.palette);
638 }
639 
640 
648 void XCFImageFormat::assignImageBytes(Layer& layer, uint i, uint j)
649 {
650  QImage &image = layer.image_tiles[j][i];
651  uchar* tile = layer.tile;
652  const int width = image.width();
653  const int height = image.height();
654  const int bytesPerLine = image.bytesPerLine();
655  uchar *bits = image.bits();
656 
657  switch (layer.type) {
658  case RGB_GIMAGE:
659  for (int y = 0; y < height; y++) {
660  QRgb *dataPtr = (QRgb *) (bits + y * bytesPerLine);
661  for (int x = 0; x < width; x++) {
662  *dataPtr++ = qRgb(tile[0], tile[1], tile[2]);
663  tile += sizeof(QRgb);
664  }
665  }
666  break;
667 
668  case RGBA_GIMAGE:
669  for (int y = 0; y < height; y++) {
670  QRgb *dataPtr = (QRgb *) (bits + y * bytesPerLine);
671  for (int x = 0; x < width; x++) {
672  *dataPtr++ = qRgba(tile[0], tile[1], tile[2], tile[3]);
673  tile += sizeof(QRgb);
674  }
675  }
676  break;
677 
678  case GRAY_GIMAGE:
679  case INDEXED_GIMAGE:
680  for (int y = 0; y < height; y++) {
681  uchar *dataPtr = bits + y * bytesPerLine;
682  for (int x = 0; x < width; x++) {
683  *dataPtr++ = tile[0];
684  tile += sizeof(QRgb);
685  }
686  }
687  break;
688 
689  case GRAYA_GIMAGE:
690  case INDEXEDA_GIMAGE:
691  for (int y = 0; y < height; y++) {
692  uchar *dataPtr = bits + y * bytesPerLine;
693  uchar *alphaPtr = layer.alpha_tiles[j][i].scanLine(y);
694  for (int x = 0; x < width; x++) {
695 
696  // The "if" here should not be necessary, but apparently there
697  // are some cases where the image can contain larger indices
698  // than there are colors in the palette. (A bug in The GIMP?)
699 
700  if (tile[0] < image.numColors())
701  *dataPtr = tile[0];
702 
703  *alphaPtr = tile[1];
704  dataPtr += 1;
705  alphaPtr += 1;
706  tile += sizeof(QRgb);
707  }
708  }
709  break;
710  }
711 }
712 
713 
722 bool XCFImageFormat::loadHierarchy(QDataStream& xcf_io, Layer& layer)
723 {
724  qint32 width;
725  qint32 height;
726  qint32 bpp;
727  quint32 offset;
728 
729  xcf_io >> width >> height >> bpp >> offset;
730 
731  // GIMP stores images in a "mipmap"-like format (multiple levels of
732  // increasingly lower resolution). Only the top level is used here,
733  // however.
734 
735  quint32 junk;
736  do {
737  xcf_io >> junk;
738 
739  if (xcf_io.device()->atEnd()) {
740  kDebug(399) << "XCF: read failure on layer " << layer.name << " level offsets";
741  return false;
742  }
743  } while (junk != 0);
744 
745  qint64 saved_pos = xcf_io.device()->pos();
746 
747  xcf_io.device()->seek(offset);
748  if (!loadLevel(xcf_io, layer, bpp))
749  return false;
750 
751  xcf_io.device()->seek(saved_pos);
752  return true;
753 }
754 
755 
764 bool XCFImageFormat::loadLevel(QDataStream& xcf_io, Layer& layer, qint32 bpp)
765 {
766  qint32 width;
767  qint32 height;
768  quint32 offset;
769 
770  xcf_io >> width >> height >> offset;
771 
772  if (offset == 0)
773  return true;
774 
775  for (uint j = 0; j < layer.nrows; j++) {
776  for (uint i = 0; i < layer.ncols; i++) {
777 
778  if (offset == 0) {
779  kDebug(399) << "XCF: incorrect number of tiles in layer " << layer.name;
780  return false;
781  }
782 
783  qint64 saved_pos = xcf_io.device()->pos();
784  quint32 offset2;
785  xcf_io >> offset2;
786 
787  // Evidently, RLE can occasionally expand a tile instead of compressing it!
788 
789  if (offset2 == 0)
790  offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
791 
792  xcf_io.device()->seek(offset);
793  int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
794 
795  if (!loadTileRLE(xcf_io, layer.tile, size, offset2 - offset, bpp))
796  return false;
797 
798  // The bytes in the layer tile are juggled differently depending on
799  // the target QImage. The caller has set layer.assignBytes to the
800  // appropriate routine.
801 
802  layer.assignBytes(layer, i, j);
803 
804  xcf_io.device()->seek(saved_pos);
805  xcf_io >> offset;
806  }
807  }
808 
809  return true;
810 }
811 
812 
819 bool XCFImageFormat::loadMask(QDataStream& xcf_io, Layer& layer)
820 {
821  qint32 width;
822  qint32 height;
823  char* name;
824 
825  xcf_io >> width >> height >> name;
826 
827  delete name;
828 
829  if (!loadChannelProperties(xcf_io, layer))
830  return false;
831 
832  quint32 hierarchy_offset;
833  xcf_io >> hierarchy_offset;
834 
835  xcf_io.device()->seek(hierarchy_offset);
836  layer.assignBytes = assignMaskBytes;
837 
838  if (!loadHierarchy(xcf_io, layer))
839  return false;
840 
841  return true;
842 }
843 
844 
868 bool XCFImageFormat::loadTileRLE(QDataStream& xcf_io, uchar* tile, int image_size,
869  int data_length, qint32 bpp)
870 {
871  uchar* data;
872 
873  uchar* xcfdata;
874  uchar* xcfodata;
875  uchar* xcfdatalimit;
876 
877  if (data_length < 0 || data_length > int(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5)) {
878  kDebug(399) << "XCF: invalid tile data length" << data_length;
879  return false;
880  }
881 
882  xcfdata = xcfodata = new uchar[data_length];
883 
884  xcf_io.readRawData((char*)xcfdata, data_length);
885 
886  if (!xcf_io.device()->isOpen()) {
887  delete[] xcfodata;
888  kDebug(399) << "XCF: read failure on tile";
889  return false;
890  }
891 
892  xcfdatalimit = &xcfodata[data_length - 1];
893 
894  for (int i = 0; i < bpp; ++i) {
895 
896  data = tile + i;
897 
898  int count = 0;
899  int size = image_size;
900 
901  while (size > 0) {
902  if (xcfdata > xcfdatalimit)
903  goto bogus_rle;
904 
905  uchar val = *xcfdata++;
906  uint length = val;
907 
908  if (length >= 128) {
909  length = 255 - (length - 1);
910  if (length == 128) {
911  if (xcfdata >= xcfdatalimit)
912  goto bogus_rle;
913 
914  length = (*xcfdata << 8) + xcfdata[1];
915 
916  xcfdata += 2;
917  }
918 
919  count += length;
920  size -= length;
921 
922  if (size < 0)
923  goto bogus_rle;
924 
925  if (&xcfdata[length - 1] > xcfdatalimit)
926  goto bogus_rle;
927 
928  while (length-- > 0) {
929  *data = *xcfdata++;
930  data += sizeof(QRgb);
931  }
932  } else {
933  length += 1;
934  if (length == 128) {
935  if (xcfdata >= xcfdatalimit)
936  goto bogus_rle;
937 
938  length = (*xcfdata << 8) + xcfdata[1];
939  xcfdata += 2;
940  }
941 
942  count += length;
943  size -= length;
944 
945  if (size < 0)
946  goto bogus_rle;
947 
948  if (xcfdata > xcfdatalimit)
949  goto bogus_rle;
950 
951  val = *xcfdata++;
952 
953  while (length-- > 0) {
954  *data = val;
955  data += sizeof(QRgb);
956  }
957  }
958  }
959  }
960 
961  delete[] xcfodata;
962  return true;
963 
964 bogus_rle:
965 
966  kDebug(399) << "The run length encoding could not be decoded properly";
967  delete[] xcfodata;
968  return false;
969 }
970 
971 
979 bool XCFImageFormat::loadChannelProperties(QDataStream& xcf_io, Layer& layer)
980 {
981  while (true) {
982  PropType type;
983  QByteArray bytes;
984 
985  if (!loadProperty(xcf_io, type, bytes)) {
986  kDebug(399) << "XCF: error loading channel properties";
987  return false;
988  }
989 
990  QDataStream property(bytes);
991 
992  switch (type) {
993  case PROP_END:
994  return true;
995 
996  case PROP_OPACITY:
997  property >> layer.mask_channel.opacity;
998  break;
999 
1000  case PROP_VISIBLE:
1001  property >> layer.mask_channel.visible;
1002  break;
1003 
1004  case PROP_SHOW_MASKED:
1005  property >> layer.mask_channel.show_masked;
1006  break;
1007 
1008  case PROP_COLOR:
1009  property >> layer.mask_channel.red >> layer.mask_channel.green
1010  >> layer.mask_channel.blue;
1011  break;
1012 
1013  case PROP_TATTOO:
1014  property >> layer.mask_channel.tattoo;
1015  break;
1016 
1017  default:
1018  kDebug(399) << "XCF: unimplemented channel property " << type
1019  << ", size " << bytes.size() << endl;
1020  }
1021  }
1022 }
1023 
1024 
1031 void XCFImageFormat::assignMaskBytes(Layer& layer, uint i, uint j)
1032 {
1033  QImage &image = layer.mask_tiles[j][i];
1034  uchar* tile = layer.tile;
1035  const int width = image.width();
1036  const int height = image.height();
1037  const int bytesPerLine = image.bytesPerLine();
1038  uchar *bits = image.bits();
1039 
1040  for (int y = 0; y < height; y++) {
1041  uchar *dataPtr = bits + y * bytesPerLine;
1042  for (int x = 0; x < width; x++) {
1043  *dataPtr++ = tile[0];
1044  tile += sizeof(QRgb);
1045  }
1046  }
1047 }
1048 
1049 
1078 bool XCFImageFormat::initializeImage(XCFImage& xcf_image)
1079 {
1080  // (Aliases to make the code look a little better.)
1081  Layer& layer(xcf_image.layer);
1082  QImage& image(xcf_image.image);
1083 
1084  switch (layer.type) {
1085  case RGB_GIMAGE:
1086  if (layer.opacity == OPAQUE_OPACITY) {
1087  image = QImage( xcf_image.width, xcf_image.height, QImage::Format_RGB32);
1088  if( image.isNull())
1089  return false;
1090  image.fill(qRgb(255, 255, 255));
1091  break;
1092  } // else, fall through to 32-bit representation
1093 
1094  case RGBA_GIMAGE:
1095  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
1096  if( image.isNull())
1097  return false;
1098  image.fill(qRgba(255, 255, 255, 0));
1099  break;
1100 
1101  case GRAY_GIMAGE:
1102  if (layer.opacity == OPAQUE_OPACITY) {
1103  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
1104  image.setNumColors(256);
1105  if( image.isNull())
1106  return false;
1107  setGrayPalette(image);
1108  image.fill(255);
1109  break;
1110  } // else, fall through to 32-bit representation
1111 
1112  case GRAYA_GIMAGE:
1113  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
1114  if( image.isNull())
1115  return false;
1116  image.fill(qRgba(255, 255, 255, 0));
1117  break;
1118 
1119  case INDEXED_GIMAGE:
1120  // As noted in the table above, there are quite a few combinations
1121  // which are possible with indexed images, depending on the
1122  // presence of transparency (note: not translucency, which is not
1123  // supported by The GIMP for indexed images) and the number of
1124  // individual colors.
1125 
1126  // Note: Qt treats a bitmap with a Black and White color palette
1127  // as a mask, so only the "on" bits are drawn, regardless of the
1128  // order color table entries. Otherwise (i.e., at least one of the
1129  // color table entries is not black or white), it obeys the one-
1130  // or two-color palette. Have to ask about this...
1131 
1132  if (xcf_image.num_colors <= 2) {
1133  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
1134  image.setNumColors(xcf_image.num_colors);
1135  if( image.isNull())
1136  return false;
1137  image.fill(0);
1138  setPalette(xcf_image, image);
1139  } else if (xcf_image.num_colors <= 256) {
1140  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
1141  image.setNumColors(xcf_image.num_colors);
1142  if( image.isNull())
1143  return false;
1144  image.fill(0);
1145  setPalette(xcf_image, image);
1146  }
1147  break;
1148 
1149  case INDEXEDA_GIMAGE:
1150  if (xcf_image.num_colors == 1) {
1151  // Plenty(!) of room to add a transparent color
1152  xcf_image.num_colors++;
1153  xcf_image.palette.resize(xcf_image.num_colors);
1154  xcf_image.palette[1] = xcf_image.palette[0];
1155  xcf_image.palette[0] = qRgba(255, 255, 255, 0);
1156 
1157  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_MonoLSB);
1158  image.setNumColors(xcf_image.num_colors);
1159  if( image.isNull())
1160  return false;
1161  image.fill(0);
1162  setPalette(xcf_image, image);
1163  } else if (xcf_image.num_colors < 256) {
1164  // Plenty of room to add a transparent color
1165  xcf_image.num_colors++;
1166  xcf_image.palette.resize(xcf_image.num_colors);
1167  for (int c = xcf_image.num_colors - 1; c >= 1; c--)
1168  xcf_image.palette[c] = xcf_image.palette[c - 1];
1169 
1170  xcf_image.palette[0] = qRgba(255, 255, 255, 0);
1171  image = QImage( xcf_image.width, xcf_image.height, QImage::Format_Indexed8);
1172  image.setNumColors(xcf_image.num_colors);
1173  if( image.isNull())
1174  return false;
1175  image.fill(0);
1176  setPalette(xcf_image, image);
1177  } else {
1178  // No room for a transparent color, so this has to be promoted to
1179  // true color. (There is no equivalent PNG representation output
1180  // from The GIMP as of v1.2.)
1181  image = QImage(xcf_image.width, xcf_image.height, QImage::Format_ARGB32);
1182  if( image.isNull())
1183  return false;
1184  image.fill(qRgba(255, 255, 255, 0));
1185  }
1186  break;
1187  }
1188 
1189  image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER));
1190  image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER));
1191  return true;
1192 }
1193 
1194 
1200 void XCFImageFormat::copyLayerToImage(XCFImage& xcf_image)
1201 {
1202  Layer& layer(xcf_image.layer);
1203  QImage& image(xcf_image.image);
1204  PixelCopyOperation copy = 0;
1205 
1206  switch (layer.type) {
1207  case RGB_GIMAGE:
1208  case RGBA_GIMAGE:
1209  copy = copyRGBToRGB;
1210  break;
1211  case GRAY_GIMAGE:
1212  if (layer.opacity == OPAQUE_OPACITY)
1213  copy = copyGrayToGray;
1214  else
1215  copy = copyGrayToRGB;
1216  break;
1217  case GRAYA_GIMAGE:
1218  copy = copyGrayAToRGB;
1219  break;
1220  case INDEXED_GIMAGE:
1221  copy = copyIndexedToIndexed;
1222  break;
1223  case INDEXEDA_GIMAGE:
1224  if (xcf_image.image.depth() <= 8)
1225  copy = copyIndexedAToIndexed;
1226  else
1227  copy = copyIndexedAToRGB;
1228  }
1229 
1230  if (!copy) {
1231  return;
1232  }
1233 
1234  // For each tile...
1235 
1236  for (uint j = 0; j < layer.nrows; j++) {
1237  uint y = j * TILE_HEIGHT;
1238 
1239  for (uint i = 0; i < layer.ncols; i++) {
1240  uint x = i * TILE_WIDTH;
1241 
1242  // This seems the best place to apply the dissolve because it
1243  // depends on the global position of each tile's
1244  // pixels. Apparently it's the only mode which can apply to a
1245  // single layer.
1246 
1247  if (layer.mode == DISSOLVE_MODE) {
1248  if (!random_table_initialized) {
1249  initializeRandomTable();
1250  random_table_initialized = true;
1251  }
1252  if (layer.type == RGBA_GIMAGE)
1253  dissolveRGBPixels(layer.image_tiles[j][i], x, y);
1254 
1255  else if (layer.type == GRAYA_GIMAGE)
1256  dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
1257  }
1258 
1259  // Shortcut for common case
1260  if (copy == copyRGBToRGB && layer.apply_mask != 1) {
1261  QPainter painter(&image);
1262  painter.setOpacity(layer.opacity / 255.0);
1263  painter.setCompositionMode(QPainter::CompositionMode_Source);
1264  painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
1265  continue;
1266  }
1267 
1268  for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
1269  for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
1270 
1271  int m = x + k + layer.x_offset;
1272  int n = y + l + layer.y_offset;
1273 
1274  if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
1275  continue;
1276 
1277  (*copy)(layer, i, j, k, l, image, m, n);
1278  }
1279  }
1280  }
1281  }
1282 }
1283 
1284 
1298 void XCFImageFormat::copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
1299  QImage& image, int m, int n)
1300 {
1301  QRgb src = layer.image_tiles[j][i].pixel(k, l);
1302  uchar src_a = layer.opacity;
1303 
1304  if (layer.type == RGBA_GIMAGE)
1305  src_a = INT_MULT(src_a, qAlpha(src));
1306 
1307  // Apply the mask (if any)
1308 
1309  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
1310  layer.mask_tiles[j].size() > (int)i)
1311  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1312 
1313  image.setPixel(m, n, qRgba(src, src_a));
1314 }
1315 
1316 
1328 void XCFImageFormat::copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
1329  QImage& image, int m, int n)
1330 {
1331  int src = layer.image_tiles[j][i].pixelIndex(k, l);
1332  image.setPixel(m, n, src);
1333 }
1334 
1335 
1349 void XCFImageFormat::copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
1350  QImage& image, int m, int n)
1351 {
1352  QRgb src = layer.image_tiles[j][i].pixel(k, l);
1353  uchar src_a = layer.opacity;
1354  image.setPixel(m, n, qRgba(src, src_a));
1355 }
1356 
1357 
1371 void XCFImageFormat::copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
1372  QImage& image, int m, int n)
1373 {
1374  QRgb src = layer.image_tiles[j][i].pixel(k, l);
1375  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1376  src_a = INT_MULT(src_a, layer.opacity);
1377 
1378  // Apply the mask (if any)
1379 
1380  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
1381  layer.mask_tiles[j].size() > (int)i)
1382  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1383 
1384  image.setPixel(m, n, qRgba(src, src_a));
1385 }
1386 
1387 
1399 void XCFImageFormat::copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
1400  QImage& image, int m, int n)
1401 {
1402  int src = layer.image_tiles[j][i].pixelIndex(k, l);
1403  image.setPixel(m, n, src);
1404 }
1405 
1406 
1418 void XCFImageFormat::copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
1419  QImage& image, int m, int n)
1420 {
1421  uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
1422  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1423  src_a = INT_MULT(src_a, layer.opacity);
1424 
1425  if (layer.apply_mask == 1 &&
1426  layer.mask_tiles.size() > (int)j &&
1427  layer.mask_tiles[j].size() > (int)i)
1428  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1429 
1430  if (src_a > 127)
1431  src++;
1432  else
1433  src = 0;
1434 
1435 image.setPixel(m, n, src);
1436 }
1437 
1438 
1452 void XCFImageFormat::copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
1453  QImage& image, int m, int n)
1454 {
1455  QRgb src = layer.image_tiles[j][i].pixel(k, l);
1456  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1457  src_a = INT_MULT(src_a, layer.opacity);
1458 
1459  // Apply the mask (if any)
1460  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
1461  layer.mask_tiles[j].size() > (int)i)
1462  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1463 
1464  // This is what appears in the GIMP window
1465  if (src_a <= 127)
1466  src_a = 0;
1467  else
1468  src_a = OPAQUE_OPACITY;
1469 
1470  image.setPixel(m, n, qRgba(src, src_a));
1471 }
1472 
1473 
1478 void XCFImageFormat::mergeLayerIntoImage(XCFImage& xcf_image)
1479 {
1480  Layer& layer(xcf_image.layer);
1481  QImage& image(xcf_image.image);
1482 
1483  PixelMergeOperation merge = 0;
1484 
1485  if (!layer.opacity) return; // don't bother doing anything
1486 
1487  switch (layer.type) {
1488  case RGB_GIMAGE:
1489  case RGBA_GIMAGE:
1490  merge = mergeRGBToRGB;
1491  break;
1492  case GRAY_GIMAGE:
1493  if (layer.opacity == OPAQUE_OPACITY)
1494  merge = mergeGrayToGray;
1495  else
1496  merge = mergeGrayToRGB;
1497  break;
1498  case GRAYA_GIMAGE:
1499  if (xcf_image.image.depth() <= 8)
1500  merge = mergeGrayAToGray;
1501  else
1502  merge = mergeGrayAToRGB;
1503  break;
1504  case INDEXED_GIMAGE:
1505  merge = mergeIndexedToIndexed;
1506  break;
1507  case INDEXEDA_GIMAGE:
1508  if (xcf_image.image.depth() <= 8)
1509  merge = mergeIndexedAToIndexed;
1510  else
1511  merge = mergeIndexedAToRGB;
1512  }
1513 
1514  if (!merge) {
1515  return;
1516  }
1517 
1518  for (uint j = 0; j < layer.nrows; j++) {
1519  uint y = j * TILE_HEIGHT;
1520 
1521  for (uint i = 0; i < layer.ncols; i++) {
1522  uint x = i * TILE_WIDTH;
1523 
1524  // This seems the best place to apply the dissolve because it
1525  // depends on the global position of each tile's
1526  // pixels. Apparently it's the only mode which can apply to a
1527  // single layer.
1528 
1529  if (layer.mode == DISSOLVE_MODE) {
1530  if (!random_table_initialized) {
1531  initializeRandomTable();
1532  random_table_initialized = true;
1533  }
1534  if (layer.type == RGBA_GIMAGE)
1535  dissolveRGBPixels(layer.image_tiles[j][i], x, y);
1536 
1537  else if (layer.type == GRAYA_GIMAGE)
1538  dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
1539  }
1540 
1541  // Shortcut for common case
1542  if (merge == mergeRGBToRGB && layer.apply_mask != 1
1543  && layer.mode == NORMAL_MODE) {
1544  QPainter painter(&image);
1545  painter.setOpacity(layer.opacity / 255.0);
1546  painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
1547  painter.drawImage(x + layer.x_offset, y + layer.y_offset, layer.image_tiles[j][i]);
1548  continue;
1549  }
1550 
1551  for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
1552  for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
1553 
1554  int m = x + k + layer.x_offset;
1555  int n = y + l + layer.y_offset;
1556 
1557  if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
1558  continue;
1559 
1560  (*merge)(layer, i, j, k, l, image, m, n);
1561  }
1562  }
1563  }
1564  }
1565 }
1566 
1567 
1581 void XCFImageFormat::mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
1582  QImage& image, int m, int n)
1583 {
1584  QRgb src = layer.image_tiles[j][i].pixel(k, l);
1585  QRgb dst = image.pixel(m, n);
1586 
1587  uchar src_r = qRed(src);
1588  uchar src_g = qGreen(src);
1589  uchar src_b = qBlue(src);
1590  uchar src_a = qAlpha(src);
1591 
1592  uchar dst_r = qRed(dst);
1593  uchar dst_g = qGreen(dst);
1594  uchar dst_b = qBlue(dst);
1595  uchar dst_a = qAlpha(dst);
1596 
1597  if (!src_a) return; // nothing to merge
1598 
1599  switch (layer.mode) {
1600  case MULTIPLY_MODE: {
1601  src_r = INT_MULT(src_r, dst_r);
1602  src_g = INT_MULT(src_g, dst_g);
1603  src_b = INT_MULT(src_b, dst_b);
1604  src_a = qMin(src_a, dst_a);
1605  }
1606  break;
1607  case DIVIDE_MODE: {
1608  src_r = qMin((dst_r * 256) / (1 + src_r), 255);
1609  src_g = qMin((dst_g * 256) / (1 + src_g), 255);
1610  src_b = qMin((dst_b * 256) / (1 + src_b), 255);
1611  src_a = qMin(src_a, dst_a);
1612  }
1613  break;
1614  case SCREEN_MODE: {
1615  src_r = 255 - INT_MULT(255 - dst_r, 255 - src_r);
1616  src_g = 255 - INT_MULT(255 - dst_g, 255 - src_g);
1617  src_b = 255 - INT_MULT(255 - dst_b, 255 - src_b);
1618  src_a = qMin(src_a, dst_a);
1619  }
1620  break;
1621  case OVERLAY_MODE: {
1622  src_r = INT_MULT(dst_r, dst_r + INT_MULT(2 * src_r, 255 - dst_r));
1623  src_g = INT_MULT(dst_g, dst_g + INT_MULT(2 * src_g, 255 - dst_g));
1624  src_b = INT_MULT(dst_b, dst_b + INT_MULT(2 * src_b, 255 - dst_b));
1625  src_a = qMin(src_a, dst_a);
1626  }
1627  break;
1628  case DIFFERENCE_MODE: {
1629  src_r = dst_r > src_r ? dst_r - src_r : src_r - dst_r;
1630  src_g = dst_g > src_g ? dst_g - src_g : src_g - dst_g;
1631  src_b = dst_b > src_b ? dst_b - src_b : src_b - dst_b;
1632  src_a = qMin(src_a, dst_a);
1633  }
1634  break;
1635  case ADDITION_MODE: {
1636  src_r = add_lut(dst_r,src_r);
1637  src_g = add_lut(dst_g,src_g);
1638  src_b = add_lut(dst_b,src_b);
1639  src_a = qMin(src_a, dst_a);
1640  }
1641  break;
1642  case SUBTRACT_MODE: {
1643  src_r = dst_r > src_r ? dst_r - src_r : 0;
1644  src_g = dst_g > src_g ? dst_g - src_g : 0;
1645  src_b = dst_b > src_b ? dst_b - src_b : 0;
1646  src_a = qMin(src_a, dst_a);
1647  }
1648  break;
1649  case DARKEN_ONLY_MODE: {
1650  src_r = dst_r < src_r ? dst_r : src_r;
1651  src_g = dst_g < src_g ? dst_g : src_g;
1652  src_b = dst_b < src_b ? dst_b : src_b;
1653  src_a = qMin( src_a, dst_a );
1654  }
1655  break;
1656  case LIGHTEN_ONLY_MODE: {
1657  src_r = dst_r < src_r ? src_r : dst_r;
1658  src_g = dst_g < src_g ? src_g : dst_g;
1659  src_b = dst_b < src_b ? src_b : dst_b;
1660  src_a = qMin(src_a, dst_a);
1661  }
1662  break;
1663  case HUE_MODE: {
1664  uchar new_r = dst_r;
1665  uchar new_g = dst_g;
1666  uchar new_b = dst_b;
1667 
1668  RGBTOHSV(src_r, src_g, src_b);
1669  RGBTOHSV(new_r, new_g, new_b);
1670 
1671  new_r = src_r;
1672 
1673  HSVTORGB(new_r, new_g, new_b);
1674 
1675  src_r = new_r;
1676  src_g = new_g;
1677  src_b = new_b;
1678  src_a = qMin( src_a, dst_a );
1679  }
1680  break;
1681  case SATURATION_MODE: {
1682  uchar new_r = dst_r;
1683  uchar new_g = dst_g;
1684  uchar new_b = dst_b;
1685 
1686  RGBTOHSV(src_r, src_g, src_b);
1687  RGBTOHSV(new_r, new_g, new_b);
1688 
1689  new_g = src_g;
1690 
1691  HSVTORGB(new_r, new_g, new_b);
1692 
1693  src_r = new_r;
1694  src_g = new_g;
1695  src_b = new_b;
1696  src_a = qMin(src_a, dst_a);
1697  }
1698  break;
1699  case VALUE_MODE: {
1700  uchar new_r = dst_r;
1701  uchar new_g = dst_g;
1702  uchar new_b = dst_b;
1703 
1704  RGBTOHSV(src_r, src_g, src_b);
1705  RGBTOHSV(new_r, new_g, new_b);
1706 
1707  new_b = src_b;
1708 
1709  HSVTORGB(new_r, new_g, new_b);
1710 
1711  src_r = new_r;
1712  src_g = new_g;
1713  src_b = new_b;
1714  src_a = qMin(src_a, dst_a);
1715  }
1716  break;
1717  case COLOR_MODE: {
1718  uchar new_r = dst_r;
1719  uchar new_g = dst_g;
1720  uchar new_b = dst_b;
1721 
1722  RGBTOHLS(src_r, src_g, src_b);
1723  RGBTOHLS(new_r, new_g, new_b);
1724 
1725  new_r = src_r;
1726  new_b = src_b;
1727 
1728  HLSTORGB(new_r, new_g, new_b);
1729 
1730  src_r = new_r;
1731  src_g = new_g;
1732  src_b = new_b;
1733  src_a = qMin(src_a, dst_a);
1734  }
1735  break;
1736  case DODGE_MODE: {
1737  uint tmp;
1738 
1739  tmp = dst_r << 8;
1740  tmp /= 256 - src_r;
1741  src_r = (uchar) qMin(tmp, 255u);
1742 
1743  tmp = dst_g << 8;
1744  tmp /= 256 - src_g;
1745  src_g = (uchar) qMin(tmp, 255u);
1746 
1747  tmp = dst_b << 8;
1748  tmp /= 256 - src_b;
1749  src_b = (uchar) qMin(tmp, 255u);
1750 
1751  src_a = qMin(src_a, dst_a);
1752  }
1753  break;
1754  case BURN_MODE: {
1755  uint tmp;
1756 
1757  tmp = (255 - dst_r) << 8;
1758  tmp /= src_r + 1;
1759  src_r = (uchar) qMin(tmp, 255u);
1760  src_r = 255 - src_r;
1761 
1762  tmp = (255 - dst_g) << 8;
1763  tmp /= src_g + 1;
1764  src_g = (uchar) qMin(tmp, 255u);
1765  src_g = 255 - src_g;
1766 
1767  tmp = (255 - dst_b) << 8;
1768  tmp /= src_b + 1;
1769  src_b = (uchar) qMin(tmp, 255u);
1770  src_b = 255 - src_b;
1771 
1772  src_a = qMin(src_a, dst_a);
1773  }
1774  break;
1775  case HARDLIGHT_MODE: {
1776  uint tmp;
1777  if (src_r > 128) {
1778  tmp = ((int)255-dst_r) * ((int) 255 - ((src_r-128) << 1));
1779  src_r = (uchar) qMin(255 - (tmp >> 8), 255u);
1780  } else {
1781  tmp = (int) dst_r * ((int) src_r << 1);
1782  src_r = (uchar) qMin(tmp >> 8, 255u);
1783  }
1784 
1785  if (src_g > 128) {
1786  tmp = ((int)255-dst_g) * ((int) 255 - ((src_g-128) << 1));
1787  src_g = (uchar) qMin(255 - (tmp >> 8), 255u);
1788  } else {
1789  tmp = (int) dst_g * ((int) src_g << 1);
1790  src_g = (uchar) qMin(tmp >> 8, 255u);
1791  }
1792 
1793  if (src_b > 128) {
1794  tmp = ((int)255-dst_b) * ((int) 255 - ((src_b-128) << 1));
1795  src_b = (uchar) qMin(255 - (tmp >> 8), 255u);
1796  } else {
1797  tmp = (int) dst_b * ((int) src_b << 1);
1798  src_b = (uchar) qMin(tmp >> 8, 255u);
1799  }
1800  src_a = qMin(src_a, dst_a);
1801  }
1802  break;
1803  case SOFTLIGHT_MODE: {
1804  uint tmpS, tmpM;
1805 
1806  tmpM = INT_MULT(dst_r, src_r);
1807  tmpS = 255 - INT_MULT((255 - dst_r), (255-src_r));
1808  src_r = INT_MULT((255 - dst_r), tmpM)
1809  + INT_MULT(dst_r, tmpS);
1810 
1811  tmpM = INT_MULT(dst_g, src_g);
1812  tmpS = 255 - INT_MULT((255 - dst_g), (255-src_g));
1813  src_g = INT_MULT((255 - dst_g), tmpM)
1814  + INT_MULT(dst_g, tmpS);
1815 
1816  tmpM = INT_MULT(dst_b, src_b);
1817  tmpS = 255 - INT_MULT((255 - dst_b), (255-src_b));
1818  src_b = INT_MULT((255 - dst_b), tmpM)
1819  + INT_MULT(dst_b, tmpS);
1820 
1821  src_a = qMin(src_a, dst_a);
1822  }
1823  break;
1824  case GRAIN_EXTRACT_MODE: {
1825  int tmp;
1826 
1827  tmp = dst_r - src_r + 128;
1828  tmp = qMin(tmp, 255);
1829  tmp = qMax(tmp, 0);
1830  src_r = (uchar) tmp;
1831 
1832  tmp = dst_g - src_g + 128;
1833  tmp = qMin(tmp, 255);
1834  tmp = qMax(tmp, 0);
1835  src_g = (uchar) tmp;
1836 
1837  tmp = dst_b - src_b + 128;
1838  tmp = qMin(tmp, 255);
1839  tmp = qMax(tmp, 0);
1840  src_b = (uchar) tmp;
1841 
1842  src_a = qMin(src_a, dst_a);
1843  }
1844  break;
1845  case GRAIN_MERGE_MODE: {
1846  int tmp;
1847 
1848  tmp = dst_r + src_r - 128;
1849  tmp = qMin(tmp, 255);
1850  tmp = qMax(tmp, 0);
1851  src_r = (uchar) tmp;
1852 
1853  tmp = dst_g + src_g - 128;
1854  tmp = qMin(tmp, 255);
1855  tmp = qMax(tmp, 0);
1856  src_g = (uchar) tmp;
1857 
1858  tmp = dst_b + src_b - 128;
1859  tmp = qMin(tmp, 255);
1860  tmp = qMax(tmp, 0);
1861  src_b = (uchar) tmp;
1862 
1863  src_a = qMin(src_a, dst_a);
1864  }
1865  break;
1866  }
1867 
1868  src_a = INT_MULT(src_a, layer.opacity);
1869 
1870  // Apply the mask (if any)
1871 
1872  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
1873  layer.mask_tiles[j].size() > (int)i)
1874  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1875 
1876  uchar new_r, new_g, new_b, new_a;
1877  new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
1878 
1879  float src_ratio = (float)src_a / new_a;
1880  float dst_ratio = 1.0 - src_ratio;
1881 
1882  new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
1883  new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
1884  new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
1885 
1886  if (!layer_modes[layer.mode].affect_alpha)
1887  new_a = dst_a;
1888 
1889  image.setPixel(m, n, qRgba(new_r, new_g, new_b, new_a));
1890 }
1891 
1892 
1904 void XCFImageFormat::mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
1905  QImage& image, int m, int n)
1906 {
1907  int src = layer.image_tiles[j][i].pixelIndex(k, l);
1908  image.setPixel(m, n, src);
1909 }
1910 
1911 
1923 void XCFImageFormat::mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
1924  QImage& image, int m, int n)
1925 {
1926  int src = qGray(layer.image_tiles[j][i].pixel(k, l));
1927  int dst = image.pixelIndex(m, n);
1928 
1929  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1930 
1931  if (!src_a) return; // nothing to merge
1932 
1933  switch (layer.mode) {
1934  case MULTIPLY_MODE: {
1935  src = INT_MULT( src, dst );
1936  }
1937  break;
1938  case DIVIDE_MODE: {
1939  src = qMin((dst * 256) / (1 + src), 255);
1940  }
1941  break;
1942  case SCREEN_MODE: {
1943  src = 255 - INT_MULT(255 - dst, 255 - src);
1944  }
1945  break;
1946  case OVERLAY_MODE: {
1947  src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
1948  }
1949  break;
1950  case DIFFERENCE_MODE: {
1951  src = dst > src ? dst - src : src - dst;
1952  }
1953  break;
1954  case ADDITION_MODE: {
1955  src = add_lut(dst,src);
1956  }
1957  break;
1958  case SUBTRACT_MODE: {
1959  src = dst > src ? dst - src : 0;
1960  }
1961  break;
1962  case DARKEN_ONLY_MODE: {
1963  src = dst < src ? dst : src;
1964  }
1965  break;
1966  case LIGHTEN_ONLY_MODE: {
1967  src = dst < src ? src : dst;
1968  }
1969  break;
1970  case DODGE_MODE: {
1971  uint tmp = dst << 8;
1972  tmp /= 256 - src;
1973  src = (uchar) qMin(tmp, 255u);
1974  }
1975  break;
1976  case BURN_MODE: {
1977  uint tmp = (255-dst) << 8;
1978  tmp /= src + 1;
1979  src = (uchar) qMin(tmp, 255u);
1980  src = 255 - src;
1981  }
1982  break;
1983  case HARDLIGHT_MODE: {
1984  uint tmp;
1985  if (src > 128) {
1986  tmp = ((int)255-dst) * ((int) 255 - ((src-128) << 1));
1987  src = (uchar) qMin(255 - (tmp >> 8), 255u);
1988  } else {
1989  tmp = (int) dst * ((int) src << 1);
1990  src = (uchar) qMin(tmp >> 8, 255u);
1991  }
1992  }
1993  break;
1994  case SOFTLIGHT_MODE: {
1995  uint tmpS, tmpM;
1996 
1997  tmpM = INT_MULT(dst, src);
1998  tmpS = 255 - INT_MULT((255-dst), (255-src));
1999  src = INT_MULT((255 - dst), tmpM)
2000  + INT_MULT(dst, tmpS);
2001 
2002  }
2003  break;
2004  case GRAIN_EXTRACT_MODE: {
2005  int tmp;
2006 
2007  tmp = dst - src + 128;
2008  tmp = qMin(tmp, 255);
2009  tmp = qMax(tmp, 0);
2010 
2011  src = (uchar) tmp;
2012  }
2013  break;
2014  case GRAIN_MERGE_MODE: {
2015  int tmp;
2016 
2017  tmp = dst + src - 128;
2018  tmp = qMin(tmp, 255);
2019  tmp = qMax(tmp, 0);
2020 
2021  src = (uchar) tmp;
2022  }
2023  break;
2024  }
2025 
2026  src_a = INT_MULT(src_a, layer.opacity);
2027 
2028  // Apply the mask (if any)
2029 
2030  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
2031  layer.mask_tiles[j].size() > (int)i)
2032  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2033 
2034  uchar new_a = OPAQUE_OPACITY;
2035 
2036  float src_ratio = (float)src_a / new_a;
2037  float dst_ratio = 1.0 - src_ratio;
2038 
2039  uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
2040 
2041  image.setPixel(m, n, new_g);
2042 }
2043 
2044 
2058 void XCFImageFormat::mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
2059  QImage& image, int m, int n)
2060 {
2061  QRgb src = layer.image_tiles[j][i].pixel(k, l);
2062  uchar src_a = layer.opacity;
2063  image.setPixel(m, n, qRgba(src, src_a));
2064 }
2065 
2066 
2080 void XCFImageFormat::mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
2081  QImage& image, int m, int n)
2082 {
2083  int src = qGray(layer.image_tiles[j][i].pixel(k, l));
2084  int dst = qGray(image.pixel(m, n));
2085 
2086  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2087  uchar dst_a = qAlpha(image.pixel(m, n));
2088 
2089  if (!src_a) return; // nothing to merge
2090 
2091  switch (layer.mode) {
2092  case MULTIPLY_MODE: {
2093  src = INT_MULT(src, dst);
2094  src_a = qMin(src_a, dst_a);
2095  }
2096  break;
2097  case DIVIDE_MODE: {
2098  src = qMin((dst * 256) / (1 + src), 255);
2099  src_a = qMin(src_a, dst_a);
2100  }
2101  break;
2102  case SCREEN_MODE: {
2103  src = 255 - INT_MULT(255 - dst, 255 - src);
2104  src_a = qMin(src_a, dst_a);
2105  }
2106  break;
2107  case OVERLAY_MODE: {
2108  src = INT_MULT( dst, dst + INT_MULT(2 * src, 255 - dst));
2109  src_a = qMin(src_a, dst_a);
2110  }
2111  break;
2112  case DIFFERENCE_MODE: {
2113  src = dst > src ? dst - src : src - dst;
2114  src_a = qMin(src_a, dst_a);
2115  }
2116  break;
2117  case ADDITION_MODE: {
2118  src = add_lut(dst,src);
2119  src_a = qMin(src_a, dst_a);
2120  }
2121  break;
2122  case SUBTRACT_MODE: {
2123  src = dst > src ? dst - src : 0;
2124  src_a = qMin(src_a, dst_a);
2125  }
2126  break;
2127  case DARKEN_ONLY_MODE: {
2128  src = dst < src ? dst : src;
2129  src_a = qMin(src_a, dst_a);
2130  }
2131  break;
2132  case LIGHTEN_ONLY_MODE: {
2133  src = dst < src ? src : dst;
2134  src_a = qMin(src_a, dst_a);
2135  }
2136  break;
2137  case DODGE_MODE: {
2138  uint tmp = dst << 8;
2139  tmp /= 256 - src;
2140  src = (uchar) qMin(tmp, 255u);
2141  src_a = qMin(src_a, dst_a);
2142  }
2143  break;
2144  case BURN_MODE: {
2145  uint tmp = (255-dst) << 8;
2146  tmp /= src + 1;
2147  src = (uchar) qMin(tmp, 255u);
2148  src = 255 - src;
2149  src_a = qMin(src_a, dst_a);
2150  }
2151  break;
2152  case HARDLIGHT_MODE: {
2153  uint tmp;
2154  if (src > 128) {
2155  tmp = ((int)255-dst) * ((int) 255 - ((src-128) << 1));
2156  src = (uchar) qMin(255 - (tmp >> 8), 255u);
2157  } else {
2158  tmp = (int) dst * ((int) src << 1);
2159  src = (uchar) qMin(tmp >> 8, 255u);
2160  }
2161  src_a = qMin(src_a, dst_a);
2162  }
2163  break;
2164  case SOFTLIGHT_MODE: {
2165  uint tmpS, tmpM;
2166 
2167  tmpM = INT_MULT(dst, src);
2168  tmpS = 255 - INT_MULT((255 - dst), (255-src));
2169  src = INT_MULT((255 - dst), tmpM)
2170  + INT_MULT(dst, tmpS);
2171 
2172  src_a = qMin(src_a, dst_a);
2173  }
2174  break;
2175  case GRAIN_EXTRACT_MODE: {
2176  int tmp;
2177 
2178  tmp = dst - src + 128;
2179  tmp = qMin(tmp, 255);
2180  tmp = qMax(tmp, 0);
2181 
2182  src = (uchar) tmp;
2183  src_a = qMin(src_a, dst_a);
2184  }
2185  break;
2186  case GRAIN_MERGE_MODE: {
2187  int tmp;
2188 
2189  tmp = dst + src - 128;
2190  tmp = qMin(tmp, 255);
2191  tmp = qMax(tmp, 0);
2192 
2193  src = (uchar) tmp;
2194  src_a = qMin(src_a, dst_a);
2195  }
2196  break;
2197  }
2198 
2199  src_a = INT_MULT(src_a, layer.opacity);
2200 
2201  // Apply the mask (if any)
2202  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
2203  layer.mask_tiles[j].size() > (int)i)
2204  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2205 
2206  uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
2207 
2208  float src_ratio = (float)src_a / new_a;
2209  float dst_ratio = 1.0 - src_ratio;
2210 
2211  uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
2212 
2213  if (!layer_modes[layer.mode].affect_alpha)
2214  new_a = dst_a;
2215 
2216  image.setPixel(m, n, qRgba(new_g, new_g, new_g, new_a));
2217 }
2218 
2219 
2231 void XCFImageFormat::mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
2232  QImage& image, int m, int n)
2233 {
2234  int src = layer.image_tiles[j][i].pixelIndex(k, l);
2235  image.setPixel(m, n, src);
2236 }
2237 
2238 
2250 void XCFImageFormat::mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
2251  QImage& image, int m, int n)
2252 {
2253  uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
2254  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2255  src_a = INT_MULT( src_a, layer.opacity );
2256 
2257  if ( layer.apply_mask == 1 &&
2258  layer.mask_tiles.size() > (int)j &&
2259  layer.mask_tiles[j].size() > (int)i)
2260  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2261 
2262  if (src_a > 127) {
2263  src++;
2264  image.setPixel(m, n, src);
2265  }
2266 }
2267 
2268 
2282 void XCFImageFormat::mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
2283  QImage& image, int m, int n)
2284 {
2285  QRgb src = layer.image_tiles[j][i].pixel(k, l);
2286  uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2287  src_a = INT_MULT(src_a, layer.opacity);
2288 
2289  // Apply the mask (if any)
2290  if (layer.apply_mask == 1 && layer.mask_tiles.size() > (int)j &&
2291  layer.mask_tiles[j].size() > (int)i)
2292  src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2293 
2294  // This is what appears in the GIMP window
2295  if (src_a <= 127)
2296  src_a = 0;
2297  else
2298  src_a = OPAQUE_OPACITY;
2299 
2300  image.setPixel(m, n, qRgba(src, src_a));
2301 }
2302 
2303 
2311 void XCFImageFormat::dissolveRGBPixels ( QImage& image, int x, int y )
2312 {
2313  // The apparently spurious rand() calls are to wind the random
2314  // numbers up to the same point for each tile.
2315 
2316  for (int l = 0; l < image.height(); l++) {
2317  srand(random_table[( l + y ) % RANDOM_TABLE_SIZE]);
2318 
2319  for (int k = 0; k < x; k++)
2320  rand();
2321 
2322  for (int k = 0; k < image.width(); k++) {
2323  int rand_val = rand() & 0xff;
2324  QRgb pixel = image.pixel(k, l);
2325 
2326  if (rand_val > qAlpha(pixel)) {
2327  image.setPixel(k, l, qRgba(pixel, 0));
2328  }
2329  }
2330  }
2331 }
2332 
2333 
2343 void XCFImageFormat::dissolveAlphaPixels ( QImage& image, int x, int y )
2344 {
2345  // The apparently spurious rand() calls are to wind the random
2346  // numbers up to the same point for each tile.
2347 
2348  for (int l = 0; l < image.height(); l++) {
2349  srand( random_table[(l + y) % RANDOM_TABLE_SIZE]);
2350 
2351  for (int k = 0; k < x; k++)
2352  rand();
2353 
2354  for (int k = 0; k < image.width(); k++) {
2355  int rand_val = rand() & 0xff;
2356  uchar alpha = image.pixelIndex(k, l);
2357 
2358  if (rand_val > alpha) {
2359  image.setPixel(k, l, 0);
2360  }
2361  }
2362  }
2363 }
2364 
2365 
2367 
2368 XCFHandler::XCFHandler()
2369 {
2370 }
2371 
2372 bool XCFHandler::canRead() const
2373 {
2374  if (canRead(device())) {
2375  setFormat("xcf");
2376  return true;
2377  }
2378  return false;
2379 }
2380 
2381 bool XCFHandler::read(QImage *image)
2382 {
2383  XCFImageFormat xcfif;
2384  return xcfif.readXCF(device(), image);
2385 }
2386 
2387 bool XCFHandler::write(const QImage &)
2388 {
2389  return false;
2390 }
2391 
2392 QByteArray XCFHandler::name() const
2393 {
2394  return "xcf";
2395 }
2396 
2397 bool XCFHandler::canRead(QIODevice *device)
2398 {
2399  if (!device) {
2400  qWarning("DDSHandler::canRead() called with no device");
2401  return false;
2402  }
2403 
2404  qint64 oldPos = device->pos();
2405 
2406  char head[8];
2407  qint64 readBytes = device->read(head, sizeof(head));
2408  if (readBytes != sizeof(head)) {
2409  if (device->isSequential()) {
2410  while (readBytes > 0)
2411  device->ungetChar(head[readBytes-- - 1]);
2412  } else {
2413  device->seek(oldPos);
2414  }
2415  return false;
2416  }
2417 
2418  if (device->isSequential()) {
2419  while (readBytes > 0)
2420  device->ungetChar(head[readBytes-- - 1]);
2421  } else {
2422  device->seek(oldPos);
2423  }
2424 
2425  return qstrncmp(head, "gimp xcf", 8) == 0;
2426 }
2427 
2428 
2429 class XCFPlugin : public QImageIOPlugin
2430 {
2431 public:
2432  QStringList keys() const;
2433  Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
2434  QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
2435 };
2436 
2437 QStringList XCFPlugin::keys() const
2438 {
2439  return QStringList() << "xcf" << "XCF";
2440 }
2441 
2442 QImageIOPlugin::Capabilities XCFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
2443 {
2444  if (format == "xcf" || format == "XCF")
2445  return Capabilities(CanRead);
2446  if (!format.isEmpty())
2447  return 0;
2448  if (!device->isOpen())
2449  return 0;
2450 
2451  Capabilities cap;
2452  if (device->isReadable() && XCFHandler::canRead(device))
2453  cap |= CanRead;
2454  return cap;
2455 }
2456 
2457 QImageIOHandler *XCFPlugin::create(QIODevice *device, const QByteArray &format) const
2458 {
2459  QImageIOHandler *handler = new XCFHandler;
2460  handler->setDevice(device);
2461  handler->setFormat(format);
2462  return handler;
2463 }
2464 
2465 Q_EXPORT_STATIC_PLUGIN(XCFPlugin)
2466 Q_EXPORT_PLUGIN2(xcf,XCFPlugin)
GRAIN_EXTRACT_MODE
Definition: gimp.h:98
PROP_PRESERVE_TRANSPARENCY
Definition: gimp.h:118
INCHESPERMETER
const float INCHESPERMETER
Definition: xcf.h:46
PROP_COLORMAP
Definition: gimp.h:109
RANDOM_TABLE_SIZE
const int RANDOM_TABLE_SIZE
Size of dissolve random number table.
Definition: gimp.h:39
NORMAL_MODE
Definition: gimp.h:78
DIFFERENCE_MODE
Definition: gimp.h:84
PROP_MODE
Definition: gimp.h:115
PROP_VISIBLE
Definition: gimp.h:116
XCFHandler::canRead
bool canRead() const
Definition: xcf.cpp:2372
PropType
PropType
Properties which can be stored in an XCF file.
Definition: gimp.h:106
RGB_GIMAGE
Definition: gimp.h:64
COLOR_MODE
Definition: gimp.h:91
PROP_EDIT_MASK
Definition: gimp.h:120
SCREEN_MODE
Definition: gimp.h:82
PROP_TATTOO
Definition: gimp.h:128
XCFImageFormat::XCFImageFormat
XCFImageFormat()
Definition: xcf.cpp:76
QVector
PROP_SHOW_MASK
Definition: gimp.h:121
DIVIDE_MODE
Definition: gimp.h:93
DODGE_MODE
Definition: gimp.h:94
PROP_RESOLUTION
Definition: gimp.h:127
XCFHandler::read
bool read(QImage *image)
Definition: xcf.cpp:2381
HLSTORGB
static void HLSTORGB(uchar &hue, uchar &lightness, uchar &saturation)
Definition: gimp.h:390
EPSILON
const double EPSILON
Roundup in alpha blending.
Definition: gimp.h:41
XCFHandler
Definition: xcf.h:32
GRAYA_GIMAGE
Definition: gimp.h:67
XCFHandler::name
QByteArray name() const
Definition: xcf.cpp:2392
GRAIN_MERGE_MODE
Definition: gimp.h:99
HARDLIGHT_MODE
Definition: gimp.h:96
XCFHandler::XCFHandler
XCFHandler()
Definition: xcf.cpp:2368
PROP_ACTIVE_LAYER
Definition: gimp.h:110
PROP_OFFSETS
Definition: gimp.h:123
PROP_USER_UNIT
Definition: gimp.h:132
SATURATION_MODE
Definition: gimp.h:90
PROP_OPACITY
Definition: gimp.h:114
BURN_MODE
Definition: gimp.h:95
LIGHTEN_ONLY_MODE
Definition: gimp.h:88
TILE_HEIGHT
const uint TILE_HEIGHT
Height of a tile in the XCF file.
Definition: gimp.h:35
uchar
quint8 uchar
Definition: dds.cpp:38
SOFTLIGHT_MODE
Definition: gimp.h:97
HSVTORGB
static void HSVTORGB(uchar &hue, uchar &saturation, uchar &value)
Definition: gimp.h:243
PROP_LINKED
Definition: gimp.h:117
DISSOLVE_MODE
Definition: gimp.h:79
PROP_PATHS
Definition: gimp.h:131
QImageIOHandler
TILE_WIDTH
const uint TILE_WIDTH
Width of a tile in the XCF file.
Definition: gimp.h:34
RGBTOHSV
static void RGBTOHSV(uchar &red, uchar &green, uchar &blue)
Definition: gimp.h:186
PROP_UNIT
Definition: gimp.h:130
DARKEN_ONLY_MODE
Definition: gimp.h:87
RGBA_GIMAGE
Definition: gimp.h:65
PROP_COLOR
Definition: gimp.h:124
PROP_COMPRESSION
Definition: gimp.h:125
HUE_MODE
Definition: gimp.h:89
PROP_SHOW_MASKED
Definition: gimp.h:122
RANDOM_SEED
const int RANDOM_SEED
Seed for dissolve random number table.
Definition: gimp.h:40
qRgba
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
Definition: xcf.cpp:67
ADDITION_MODE
Definition: gimp.h:85
SUBTRACT_MODE
Definition: gimp.h:86
XCFHandler::write
bool write(const QImage &image)
Definition: xcf.cpp:2387
XCFImageFormat
Definition: xcf.h:59
uint
quint32 uint
Definition: dds.cpp:36
OVERLAY_MODE
Definition: gimp.h:83
PROP_END
Definition: gimp.h:108
PROP_APPLY_MASK
Definition: gimp.h:119
MULTIPLY_MODE
Definition: gimp.h:81
INDEXEDA_GIMAGE
Definition: gimp.h:69
OPAQUE_OPACITY
const uchar OPAQUE_OPACITY
Opaque value for 8-bit alpha component.
Definition: gimp.h:45
XCFImageFormat::readXCF
bool readXCF(QIODevice *device, QImage *image)
Definition: xcf.cpp:105
GRAY_GIMAGE
Definition: gimp.h:66
INT_MULT
int INT_MULT(int a, int b)
Definition: gimp.h:156
xcf.h
PROP_PARASITES
Definition: gimp.h:129
RGBTOHLS
static void RGBTOHLS(uchar &red, uchar &green, uchar &blue)
Definition: gimp.h:303
VALUE_MODE
Definition: gimp.h:92
INDEXED_GIMAGE
Definition: gimp.h:68
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:47:50 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KImgIO

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

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