• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kimgio
 

kimgio

  • kimgio
xcf.cpp
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 <stdlib.h>
23#include <tqimage.h>
24#include <tqiodevice.h>
25#include <tqvaluestack.h>
26#include <tqvaluevector.h>
27
28#include <kdebug.h>
29#include "xcf.h"
30
31
33
34
35TDE_EXPORT void kimgio_xcf_read(TQImageIO *io)
36{
37 XCFImageFormat xcfif;
38 xcfif.readXCF(io);
39}
40
41
42TDE_EXPORT void kimgio_xcf_write(TQImageIO *io)
43{
44 kdDebug(399) << "XCF: write support not implemented" << endl;
45 io->setStatus(-1);
46}
47
49
50
51
52int XCFImageFormat::random_table[RANDOM_TABLE_SIZE];
53
54//int XCFImageFormat::add_lut[256][256];
55
56
57const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
58 {true}, // NORMAL_MODE
59 {true}, // DISSOLVE_MODE
60 {true}, // BEHIND_MODE
61 {false}, // MULTIPLY_MODE
62 {false}, // SCREEN_MODE
63 {false}, // OVERLAY_MODE
64 {false}, // DIFFERENCE_MODE
65 {false}, // ADDITION_MODE
66 {false}, // SUBTRACT_MODE
67 {false}, // DARKEN_ONLY_MODE
68 {false}, // LIGHTEN_ONLY_MODE
69 {false}, // HUE_MODE
70 {false}, // SATURATION_MODE
71 {false}, // COLOR_MODE
72 {false}, // VALUE_MODE
73 {false}, // DIVIDE_MODE
74 {true}, // ERASE_MODE
75 {true}, // REPLACE_MODE
76 {true}, // ANTI_ERASE_MODE
77};
78
79
81inline TQRgb tqRgba ( TQRgb rgb, int a )
82{
83 return ((a & 0xff) << 24 | (rgb & TQT_RGB_MASK));
84}
85
86
91XCFImageFormat::XCFImageFormat()
92{
93 // From GIMP "paint_funcs.c" v1.2
94 srand(RANDOM_SEED);
95
96 for (int i = 0; i < RANDOM_TABLE_SIZE; i++)
97 random_table[i] = rand();
98
99 for (int i = 0; i < RANDOM_TABLE_SIZE; i++) {
100 int tmp;
101 int swap = i + rand() % (RANDOM_TABLE_SIZE - i);
102 tmp = random_table[i];
103 random_table[i] = random_table[swap];
104 random_table[swap] = tmp;
105 }
106
107// for (int j = 0; j < 256; j++) {
108// for (int k = 0; k < 256; k++) {
109// int tmp_sum = j + k;
110// if (tmp_sum > 255)
111// tmp_sum = 255;
112// add_lut[j][k] = tmp_sum;
113// }
114// }
115}
116
117inline
118int XCFImageFormat::add_lut( int a, int b ) {
119 return TQMIN( a + b, 255 );
120}
121
122void XCFImageFormat::readXCF(TQImageIO *io)
123{
124 XCFImage xcf_image;
125 TQDataStream xcf_io(io->ioDevice());
126
127 char tag[14];
128 xcf_io.readRawBytes(tag, sizeof(tag));
129
130 if (xcf_io.device()->status() != IO_Ok) {
131 kdDebug(399) << "XCF: read failure on header tag" << endl;
132 return;
133 }
134
135 xcf_io >> xcf_image.width >> xcf_image.height >> xcf_image.type;
136
137 if (xcf_io.device()->status() != IO_Ok) {
138 kdDebug(399) << "XCF: read failure on image info" << endl;
139 return;
140 }
141
142kdDebug() << tag << " " << xcf_image.width << " " << xcf_image.height << " " << xcf_image.type << endl;
143 if (!loadImageProperties(xcf_io, xcf_image))
144 return;
145
146 // The layers appear to be stored in top-to-bottom order. This is
147 // the reverse of how a merged image must be computed. So, the layer
148 // offsets are pushed onto a LIFO stack (thus, we don't have to load
149 // all the data of all layers before beginning to construct the
150 // merged image).
151
152 TQValueStack<TQ_INT32> layer_offsets;
153
154 while (true) {
155 TQ_INT32 layer_offset;
156
157 xcf_io >> layer_offset;
158
159 if (xcf_io.device()->status() != IO_Ok) {
160 kdDebug(399) << "XCF: read failure on layer offsets" << endl;
161 return;
162 }
163
164 if (layer_offset == 0)
165 break;
166
167 layer_offsets.push(layer_offset);
168 }
169
170 xcf_image.num_layers = layer_offsets.size();
171
172 if (layer_offsets.size() == 0) {
173 kdDebug(399) << "XCF: no layers!" << endl;
174 return;
175 }
176
177 // Load each layer and add it to the image
178 while (!layer_offsets.isEmpty()) {
179 TQ_INT32 layer_offset = layer_offsets.pop();
180
181 xcf_io.device()->at(layer_offset);
182
183 if (!loadLayer(xcf_io, xcf_image))
184 return;
185 }
186
187 if (!xcf_image.initialized) {
188 kdDebug(399) << "XCF: no visible layers!" << endl;
189 return;
190 }
191
192 io->setImage(xcf_image.image);
193 io->setStatus(0);
194}
195
196
204bool XCFImageFormat::loadImageProperties(TQDataStream& xcf_io, XCFImage& xcf_image)
205{
206 while (true) {
207 PropType type;
208 TQByteArray bytes;
209
210 if (!loadProperty(xcf_io, type, bytes)) {
211 kdDebug(399) << "XCF: error loading global image properties" << endl;
212 return false;
213 }
214
215 TQDataStream property(bytes, IO_ReadOnly);
216
217 switch (type) {
218 case PROP_END:
219 return true;
220
221 case PROP_COMPRESSION:
222 property >> xcf_image.compression;
223 break;
224
225 case PROP_RESOLUTION:
226 property >> xcf_image.x_resolution >> xcf_image.y_resolution;
227 break;
228
229 case PROP_TATTOO:
230 property >> xcf_image.tattoo;
231 break;
232
233 case PROP_PARASITES:
234 while (!property.atEnd()) {
235 char* tag;
236 TQ_UINT32 size;
237
238 property.readBytes(tag, size);
239
240 TQ_UINT32 flags;
241 char* data=0;
242 property >> flags >> data;
243
244 if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0)
245 xcf_image.image.setText("Comment", 0, data);
246
247 delete[] tag;
248 delete[] data;
249 }
250 break;
251
252 case PROP_UNIT:
253 property >> xcf_image.unit;
254 break;
255
256 case PROP_PATHS: // This property is ignored.
257 break;
258
259 case PROP_USER_UNIT: // This property is ignored.
260 break;
261
262 case PROP_COLORMAP:
263 property >> xcf_image.num_colors;
264 if(xcf_image.num_colors < 0 || xcf_image.num_colors > 65535)
265 return false;
266
267 xcf_image.palette.reserve(xcf_image.num_colors);
268
269 for (int i = 0; i < xcf_image.num_colors; i++) {
270 uchar r, g, b;
271 property >> r >> g >> b;
272 xcf_image.palette.push_back( tqRgb(r,g,b) );
273 }
274 break;
275
276 default:
277 kdDebug(399) << "XCF: unimplemented image property" << type
278 << ", size " << bytes.size() << endl;
279 }
280 }
281}
282
283
291bool XCFImageFormat::loadProperty(TQDataStream& xcf_io, PropType& type, TQByteArray& bytes)
292{
293 TQ_UINT32 foo;
294 xcf_io >> foo;
295 type=PropType(foo); // TODO urks
296
297 if (xcf_io.device()->status() != IO_Ok) {
298 kdDebug(399) << "XCF: read failure on property type" << type << endl;
299 return false;
300 }
301
302 char* data;
303 TQ_UINT32 size;
304
305 // The colormap property size is not the correct number of bytes:
306 // The GIMP source xcf.c has size = 4 + ncolors, but it should be
307 // 4 + 3 * ncolors
308
309 if (type == PROP_COLORMAP) {
310 xcf_io >> size;
311
312 if (xcf_io.device()->status() != IO_Ok) {
313 kdDebug(399) << "XCF: read failure on property " << type << " size" << endl;
314 return false;
315 }
316
317 if(size > 65535 || size < 4)
318 return false;
319
320 size = 3 * (size - 4) + 4;
321 data = new char[size];
322
323 xcf_io.readRawBytes(data, size);
324 } else if (type == PROP_USER_UNIT) {
325 // The USER UNIT property size is not correct. I'm not sure why, though.
326 float factor;
327 TQ_INT32 digits;
328 char* unit_strings;
329
330 xcf_io >> size >> factor >> digits;
331
332 if (xcf_io.device()->status() != IO_Ok) {
333 kdDebug(399) << "XCF: read failure on property " << type << endl;
334 return false;
335 }
336
337 for (int i = 0; i < 5; i++) {
338 xcf_io >> unit_strings;
339
340 if (xcf_io.device()->status() != IO_Ok) {
341 kdDebug(399) << "XCF: read failure on property " << type << endl;
342 return false;
343 }
344
345 delete[] unit_strings;
346 }
347
348 size = 0;
349 } else {
350 xcf_io >> size;
351 if(size >256000)
352 return false;
353 data = new char[size];
354 xcf_io.readRawBytes(data, size);
355 }
356
357 if (xcf_io.device()->status() != IO_Ok) {
358 kdDebug(399) << "XCF: read failure on property " << type << " data, size " << size << endl;
359 return false;
360 }
361
362 if (size != 0 && data) {
363 bytes.assign(data,size);
364 }
365
366 return true;
367}
368
369
378bool XCFImageFormat::loadLayer(TQDataStream& xcf_io, XCFImage& xcf_image)
379{
380 Layer& layer(xcf_image.layer);
381 delete[] layer.name;
382
383 xcf_io >> layer.width >> layer.height >> layer.type >> layer.name;
384
385 if (xcf_io.device()->status() != IO_Ok) {
386 kdDebug(399) << "XCF: read failure on layer" << endl;
387 return false;
388 }
389
390 if (!loadLayerProperties(xcf_io, layer))
391 return false;
392#if 0
393 cout << "layer: \"" << layer.name << "\", size: " << layer.width << " x "
394 << layer.height << ", type: " << layer.type << ", mode: " << layer.mode
395 << ", opacity: " << layer.opacity << ", visible: " << layer.visible
396 << ", offset: " << layer.x_offset << ", " << layer.y_offset << endl;
397#endif
398 // Skip reading the rest of it if it is not visible. Typically, when
399 // you export an image from the The GIMP it flattens (or merges) only
400 // the visible layers into the output image.
401
402 if (layer.visible == 0)
403 return true;
404
405 // If there are any more layers, merge them into the final TQImage.
406
407 xcf_io >> layer.hierarchy_offset >> layer.mask_offset;
408 if (xcf_io.device()->status() != IO_Ok) {
409 kdDebug(399) << "XCF: read failure on layer image offsets" << endl;
410 return false;
411 }
412
413 // Allocate the individual tile QImages based on the size and type
414 // of this layer.
415
416 if( !composeTiles(xcf_image))
417 return false;
418 xcf_io.device()->at(layer.hierarchy_offset);
419
420 // As tiles are loaded, they are copied into the layers tiles by
421 // this routine. (loadMask(), below, uses a slightly different
422 // version of assignBytes().)
423
424 layer.assignBytes = assignImageBytes;
425
426 if (!loadHierarchy(xcf_io, layer))
427 return false;
428
429 if (layer.mask_offset != 0) {
430 xcf_io.device()->at(layer.mask_offset);
431
432 if (!loadMask(xcf_io, layer))
433 return false;
434 }
435
436 // Now we should have enough information to initialize the final
437 // TQImage. The first visible layer determines the attributes
438 // of the TQImage.
439
440 if (!xcf_image.initialized) {
441 if( !initializeImage(xcf_image))
442 return false;
443 copyLayerToImage(xcf_image);
444 xcf_image.initialized = true;
445 } else
446 mergeLayerIntoImage(xcf_image);
447
448 return true;
449}
450
451
459bool XCFImageFormat::loadLayerProperties(TQDataStream& xcf_io, Layer& layer)
460{
461 while (true) {
462 PropType type;
463 TQByteArray bytes;
464
465 if (!loadProperty(xcf_io, type, bytes)) {
466 kdDebug(399) << "XCF: error loading layer properties" << endl;
467 return false;
468 }
469
470 TQDataStream property(bytes, IO_ReadOnly);
471
472 switch (type) {
473 case PROP_END:
474 return true;
475
476 case PROP_ACTIVE_LAYER:
477 layer.active = true;
478 break;
479
480 case PROP_OPACITY:
481 property >> layer.opacity;
482 break;
483
484 case PROP_VISIBLE:
485 property >> layer.visible;
486 break;
487
488 case PROP_LINKED:
489 property >> layer.linked;
490 break;
491
492 case PROP_PRESERVE_TRANSPARENCY:
493 property >> layer.preserve_transparency;
494 break;
495
496 case PROP_APPLY_MASK:
497 property >> layer.apply_mask;
498 break;
499
500 case PROP_EDIT_MASK:
501 property >> layer.edit_mask;
502 break;
503
504 case PROP_SHOW_MASK:
505 property >> layer.show_mask;
506 break;
507
508 case PROP_OFFSETS:
509 property >> layer.x_offset >> layer.y_offset;
510 break;
511
512 case PROP_MODE:
513 property >> layer.mode;
514 break;
515
516 case PROP_TATTOO:
517 property >> layer.tattoo;
518 break;
519
520 default:
521 kdDebug(399) << "XCF: unimplemented layer property " << type
522 << ", size " << bytes.size() << endl;
523 }
524 }
525}
526
527
533bool XCFImageFormat::composeTiles(XCFImage& xcf_image)
534{
535 Layer& layer(xcf_image.layer);
536
537 layer.nrows = (layer.height + TILE_HEIGHT - 1) / TILE_HEIGHT;
538 layer.ncols = (layer.width + TILE_WIDTH - 1) / TILE_WIDTH;
539
540 layer.image_tiles.resize(layer.nrows);
541
542 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
543 layer.alpha_tiles.resize(layer.nrows);
544
545 if (layer.mask_offset != 0)
546 layer.mask_tiles.resize(layer.nrows);
547
548 for (uint j = 0; j < layer.nrows; j++) {
549 layer.image_tiles[j].resize(layer.ncols);
550
551 if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE)
552 layer.alpha_tiles[j].resize(layer.ncols);
553
554 if (layer.mask_offset != 0)
555 layer.mask_tiles[j].resize(layer.ncols);
556 }
557
558 for (uint j = 0; j < layer.nrows; j++) {
559 for (uint i = 0; i < layer.ncols; i++) {
560
561 uint tile_width = (i + 1) * TILE_WIDTH <= layer.width
562 ? TILE_WIDTH : layer.width - i * TILE_WIDTH;
563
564 uint tile_height = (j + 1) * TILE_HEIGHT <= layer.height
565 ? TILE_HEIGHT : layer.height - j * TILE_HEIGHT;
566
567 // Try to create the most appropriate TQImage (each GIMP layer
568 // type is treated slightly differently)
569
570 switch (layer.type) {
571 case RGB_GIMAGE:
572 layer.image_tiles[j][i] = TQImage(tile_width, tile_height, 32, 0);
573 if( layer.image_tiles[j][i].isNull())
574 return false;
575 layer.image_tiles[j][i].setAlphaBuffer(false);
576 break;
577
578 case RGBA_GIMAGE:
579 layer.image_tiles[j][i] = TQImage(tile_width, tile_height, 32, 0);
580 if( layer.image_tiles[j][i].isNull())
581 return false;
582 layer.image_tiles[j][i].setAlphaBuffer(true);
583 break;
584
585 case GRAY_GIMAGE:
586 layer.image_tiles[j][i] = TQImage(tile_width, tile_height, 8, 256);
587 if( layer.image_tiles[j][i].isNull())
588 return false;
589 setGrayPalette(layer.image_tiles[j][i]);
590 break;
591
592 case GRAYA_GIMAGE:
593 layer.image_tiles[j][i] = TQImage(tile_width, tile_height, 8, 256);
594 if( layer.image_tiles[j][i].isNull())
595 return false;
596 setGrayPalette(layer.image_tiles[j][i]);
597
598 layer.alpha_tiles[j][i] = TQImage( tile_width, tile_height, 8, 256);
599 if( layer.alpha_tiles[j][i].isNull())
600 return false;
601 setGrayPalette(layer.alpha_tiles[j][i]);
602 break;
603
604 case INDEXED_GIMAGE:
605 layer.image_tiles[j][i] = TQImage(tile_width, tile_height, 8,
606 xcf_image.num_colors);
607 if( layer.image_tiles[j][i].isNull())
608 return false;
609 setPalette(xcf_image, layer.image_tiles[j][i]);
610 break;
611
612 case INDEXEDA_GIMAGE:
613 layer.image_tiles[j][i] = TQImage(tile_width, tile_height,8,
614 xcf_image.num_colors);
615 if( layer.image_tiles[j][i].isNull())
616 return false;
617 setPalette(xcf_image, layer.image_tiles[j][i]);
618
619 layer.alpha_tiles[j][i] = TQImage(tile_width, tile_height, 8, 256);
620 if( layer.alpha_tiles[j][i].isNull())
621 return false;
622 setGrayPalette(layer.alpha_tiles[j][i]);
623 }
624
625 if (layer.mask_offset != 0) {
626 layer.mask_tiles[j][i] = TQImage(tile_width, tile_height, 8, 256);
627 if( layer.mask_tiles[j][i].isNull())
628 return false;
629 setGrayPalette(layer.mask_tiles[j][i]);
630 }
631 }
632 }
633 return true;
634}
635
636
643void XCFImageFormat::setGrayPalette(TQImage& image)
644{
645 for (int i = 0; i < 256; i++)
646 image.setColor(i, tqRgb(i, i, i));
647}
648
649
655void XCFImageFormat::setPalette(XCFImage& xcf_image, TQImage& image)
656{
657 for (int i = 0; i < xcf_image.num_colors; i++)
658 image.setColor(i, xcf_image.palette[i]);
659}
660
661
669void XCFImageFormat::assignImageBytes(Layer& layer, uint i, uint j)
670{
671 uchar* tile = layer.tile;
672
673 switch (layer.type) {
674 case RGB_GIMAGE:
675 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
676 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
677 layer.image_tiles[j][i].setPixel(k, l,
678 tqRgb(tile[0], tile[1], tile[2]));
679 tile += sizeof(TQRgb);
680 }
681 }
682 break;
683
684 case RGBA_GIMAGE:
685 for ( int l = 0; l < layer.image_tiles[j][i].height(); l++ ) {
686 for ( int k = 0; k < layer.image_tiles[j][i].width(); k++ ) {
687 layer.image_tiles[j][i].setPixel(k, l,
688 tqRgba(tile[0], tile[1], tile[2], tile[3]));
689 tile += sizeof(TQRgb);
690 }
691 }
692 break;
693
694 case GRAY_GIMAGE:
695 case INDEXED_GIMAGE:
696 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
697 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
698 layer.image_tiles[j][i].setPixel(k, l, tile[0]);
699 tile += sizeof(TQRgb);
700 }
701 }
702 break;
703
704 case GRAYA_GIMAGE:
705 case INDEXEDA_GIMAGE:
706 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
707 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
708
709 // The "if" here should not be necessary, but apparently there
710 // are some cases where the image can contain larger indices
711 // than there are colors in the palette. (A bug in The GIMP?)
712
713 if (tile[0] < layer.image_tiles[j][i].numColors())
714 layer.image_tiles[j][i].setPixel(k, l, tile[0]);
715
716 layer.alpha_tiles[j][i].setPixel(k, l, tile[1]);
717 tile += sizeof(TQRgb);
718 }
719 }
720 break;
721 }
722}
723
724
733bool XCFImageFormat::loadHierarchy(TQDataStream& xcf_io, Layer& layer)
734{
735 TQ_INT32 width;
736 TQ_INT32 height;
737 TQ_INT32 bpp;
738 TQ_UINT32 offset;
739
740 xcf_io >> width >> height >> bpp >> offset;
741
742 if (xcf_io.device()->status() != IO_Ok) {
743 kdDebug(399) << "XCF: read failure on layer " << layer.name << " image header" << endl;
744 return false;
745 }
746
747 // GIMP stores images in a "mipmap"-like format (multiple levels of
748 // increasingly lower resolution). Only the top level is used here,
749 // however.
750
751 TQ_UINT32 junk;
752 do {
753 xcf_io >> junk;
754
755 if (xcf_io.device()->status() != IO_Ok) {
756 kdDebug(399) << "XCF: read failure on layer " << layer.name << " level offsets" << endl;
757 return false;
758 }
759 } while (junk != 0);
760
761 TQIODevice::Offset saved_pos = xcf_io.device()->at();
762
763 xcf_io.device()->at(offset);
764 if (!loadLevel(xcf_io, layer, bpp))
765 return false;
766
767 xcf_io.device()->at(saved_pos);
768 return true;
769}
770
771
780bool XCFImageFormat::loadLevel(TQDataStream& xcf_io, Layer& layer, TQ_INT32 bpp)
781{
782 TQ_INT32 width;
783 TQ_INT32 height;
784 TQ_UINT32 offset;
785
786 xcf_io >> width >> height >> offset;
787
788 if (xcf_io.device()->status() != IO_Ok) {
789 kdDebug(399) << "XCF: read failure on layer " << layer.name << " level info" << endl;
790 return false;
791 }
792
793 if (offset == 0)
794 return true;
795
796 for (uint j = 0; j < layer.nrows; j++) {
797 for (uint i = 0; i < layer.ncols; i++) {
798
799 if (offset == 0) {
800 kdDebug(399) << "XCF: incorrect number of tiles in layer " << layer.name << endl;
801 return false;
802 }
803
804 TQIODevice::Offset saved_pos = xcf_io.device()->at();
805 TQ_UINT32 offset2;
806 xcf_io >> offset2;
807
808 if (xcf_io.device()->status() != IO_Ok) {
809 kdDebug(399) << "XCF: read failure on layer " << layer.name << " level offset look-ahead" << endl;
810 return false;
811 }
812
813 // Evidently, RLE can occasionally expand a tile instead of compressing it!
814
815 if (offset2 == 0)
816 offset2 = offset + (uint)(TILE_WIDTH * TILE_HEIGHT * 4 * 1.5);
817
818 xcf_io.device()->at(offset);
819 int size = layer.image_tiles[j][i].width() * layer.image_tiles[j][i].height();
820
821 if (!loadTileRLE(xcf_io, layer.tile, size, offset2 - offset, bpp))
822 return false;
823
824 // The bytes in the layer tile are juggled differently depending on
825 // the target TQImage. The caller has set layer.assignBytes to the
826 // appropriate routine.
827
828 layer.assignBytes(layer, i, j);
829
830 xcf_io.device()->at(saved_pos);
831 xcf_io >> offset;
832
833 if (xcf_io.device()->status() != IO_Ok) {
834 kdDebug(399) << "XCF: read failure on layer " << layer.name << " level offset" << endl;
835 return false;
836 }
837 }
838 }
839
840 return true;
841}
842
843
850bool XCFImageFormat::loadMask(TQDataStream& xcf_io, Layer& layer)
851{
852 TQ_INT32 width;
853 TQ_INT32 height;
854 char* name;
855
856 xcf_io >> width >> height >> name;
857
858 if (xcf_io.device()->status() != IO_Ok) {
859 kdDebug(399) << "XCF: read failure on mask info" << endl;
860 return false;
861 }
862
863 delete name;
864
865 if (!loadChannelProperties(xcf_io, layer))
866 return false;
867
868 TQ_UINT32 hierarchy_offset;
869 xcf_io >> hierarchy_offset;
870
871 if (xcf_io.device()->status() != IO_Ok) {
872 kdDebug(399) << "XCF: read failure on mask image offset" << endl;
873 return false;
874 }
875
876 xcf_io.device()->at(hierarchy_offset);
877 layer.assignBytes = assignMaskBytes;
878
879 if (!loadHierarchy(xcf_io, layer))
880 return false;
881
882 return true;
883}
884
885
909bool XCFImageFormat::loadTileRLE(TQDataStream& xcf_io, uchar* tile, int image_size,
910 int data_length, TQ_INT32 bpp)
911{
912 uchar* data;
913
914 uchar* xcfdata;
915 uchar* xcfodata;
916 uchar* xcfdatalimit;
917
918 xcfdata = xcfodata = new uchar[data_length];
919
920 xcf_io.readRawBytes((char*)xcfdata, data_length);
921
922 if (xcf_io.device()->status() != IO_Ok) {
923 delete[] xcfodata;
924 kdDebug(399) << "XCF: read failure on tile" << endl;
925 return false;
926 }
927
928 xcfdatalimit = &xcfodata[data_length - 1];
929
930 for (int i = 0; i < bpp; ++i) {
931
932 data = tile + i;
933
934 int count = 0;
935 int size = image_size;
936
937 while (size > 0) {
938 if (xcfdata > xcfdatalimit)
939 goto bogus_rle;
940
941 uchar val = *xcfdata++;
942 uint length = val;
943
944 if (length >= 128) {
945 length = 255 - (length - 1);
946 if (length == 128) {
947 if (xcfdata >= xcfdatalimit)
948 goto bogus_rle;
949
950 length = (*xcfdata << 8) + xcfdata[1];
951
952 xcfdata += 2;
953 }
954
955 count += length;
956 size -= length;
957
958 if (size < 0)
959 goto bogus_rle;
960
961 if (&xcfdata[length - 1] > xcfdatalimit)
962 goto bogus_rle;
963
964 while (length-- > 0) {
965 *data = *xcfdata++;
966 data += sizeof(TQRgb);
967 }
968 } else {
969 length += 1;
970 if (length == 128) {
971 if (xcfdata >= xcfdatalimit)
972 goto bogus_rle;
973
974 length = (*xcfdata << 8) + xcfdata[1];
975 xcfdata += 2;
976 }
977
978 count += length;
979 size -= length;
980
981 if (size < 0)
982 goto bogus_rle;
983
984 if (xcfdata > xcfdatalimit)
985 goto bogus_rle;
986
987 val = *xcfdata++;
988
989 while (length-- > 0) {
990 *data = val;
991 data += sizeof(TQRgb);
992 }
993 }
994 }
995 }
996
997 delete[] xcfodata;
998 return true;
999
1000bogus_rle:
1001
1002 kdDebug(399) << "The run length encoding could not be decoded properly" << endl;
1003 delete[] xcfodata;
1004 return false;
1005}
1006
1007
1015bool XCFImageFormat::loadChannelProperties(TQDataStream& xcf_io, Layer& layer)
1016{
1017 while (true) {
1018 PropType type;
1019 TQByteArray bytes;
1020
1021 if (!loadProperty(xcf_io, type, bytes)) {
1022 kdDebug(399) << "XCF: error loading channel properties" << endl;
1023 return false;
1024 }
1025
1026 TQDataStream property(bytes, IO_ReadOnly);
1027
1028 switch (type) {
1029 case PROP_END:
1030 return true;
1031
1032 case PROP_OPACITY:
1033 property >> layer.mask_channel.opacity;
1034 break;
1035
1036 case PROP_VISIBLE:
1037 property >> layer.mask_channel.visible;
1038 break;
1039
1040 case PROP_SHOW_MASKED:
1041 property >> layer.mask_channel.show_masked;
1042 break;
1043
1044 case PROP_COLOR:
1045 property >> layer.mask_channel.red >> layer.mask_channel.green
1046 >> layer.mask_channel.blue;
1047 break;
1048
1049 case PROP_TATTOO:
1050 property >> layer.mask_channel.tattoo;
1051 break;
1052
1053 default:
1054 kdDebug(399) << "XCF: unimplemented channel property " << type
1055 << ", size " << bytes.size() << endl;
1056 }
1057 }
1058}
1059
1060
1067void XCFImageFormat::assignMaskBytes(Layer& layer, uint i, uint j)
1068{
1069 uchar* tile = layer.tile;
1070
1071 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
1072 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
1073 layer.mask_tiles[j][i].setPixel(k, l, tile[0]);
1074 tile += sizeof(TQRgb);
1075 }
1076 }
1077}
1078
1079
1108bool XCFImageFormat::initializeImage(XCFImage& xcf_image)
1109{
1110 // (Aliases to make the code look a little better.)
1111 Layer& layer(xcf_image.layer);
1112 TQImage& image(xcf_image.image);
1113
1114 switch (layer.type) {
1115 case RGB_GIMAGE:
1116 if (layer.opacity == OPAQUE_OPACITY) {
1117 image.create( xcf_image.width, xcf_image.height, 32);
1118 if( image.isNull())
1119 return false;
1120 image.fill(tqRgb(255, 255, 255));
1121 break;
1122 } // else, fall through to 32-bit representation
1123
1124 case RGBA_GIMAGE:
1125 image.create(xcf_image.width, xcf_image.height, 32);
1126 if( image.isNull())
1127 return false;
1128 image.fill(tqRgba(255, 255, 255, 0));
1129 // Turning this on prevents fill() from affecting the alpha channel,
1130 // by the way.
1131 image.setAlphaBuffer(true);
1132 break;
1133
1134 case GRAY_GIMAGE:
1135 if (layer.opacity == OPAQUE_OPACITY) {
1136 image.create(xcf_image.width, xcf_image.height, 8, 256);
1137 if( image.isNull())
1138 return false;
1139 setGrayPalette(image);
1140 image.fill(255);
1141 break;
1142 } // else, fall through to 32-bit representation
1143
1144 case GRAYA_GIMAGE:
1145 image.create(xcf_image.width, xcf_image.height, 32);
1146 if( image.isNull())
1147 return false;
1148 image.fill(tqRgba(255, 255, 255, 0));
1149 image.setAlphaBuffer(true);
1150 break;
1151
1152 case INDEXED_GIMAGE:
1153 // As noted in the table above, there are quite a few combinations
1154 // which are possible with indexed images, depending on the
1155 // presense of transparency (note: not translucency, which is not
1156 // supported by The GIMP for indexed images) and the number of
1157 // individual colors.
1158
1159 // Note: Qt treats a bitmap with a Black and White color palette
1160 // as a mask, so only the "on" bits are drawn, regardless of the
1161 // order color table entries. Otherwise (i.e., at least one of the
1162 // color table entries is not black or white), it obeys the one-
1163 // or two-color palette. Have to ask about this...
1164
1165 if (xcf_image.num_colors <= 2) {
1166 image.create(xcf_image.width, xcf_image.height,
1167 1, xcf_image.num_colors,
1168 TQImage::LittleEndian);
1169 if( image.isNull())
1170 return false;
1171 image.fill(0);
1172 setPalette(xcf_image, image);
1173 } else if (xcf_image.num_colors <= 256) {
1174 image.create(xcf_image.width, xcf_image.height,
1175 8, xcf_image.num_colors,
1176 TQImage::LittleEndian);
1177 if( image.isNull())
1178 return false;
1179 image.fill(0);
1180 setPalette(xcf_image, image);
1181 }
1182 break;
1183
1184 case INDEXEDA_GIMAGE:
1185 if (xcf_image.num_colors == 1) {
1186 // Plenty(!) of room to add a transparent color
1187 xcf_image.num_colors++;
1188 xcf_image.palette.resize(xcf_image.num_colors);
1189 xcf_image.palette[1] = xcf_image.palette[0];
1190 xcf_image.palette[0] = tqRgba(255, 255, 255, 0);
1191
1192 image.create(xcf_image.width, xcf_image.height,
1193 1, xcf_image.num_colors,
1194 TQImage::LittleEndian);
1195 if( image.isNull())
1196 return false;
1197 image.fill(0);
1198 setPalette(xcf_image, image);
1199 image.setAlphaBuffer(true);
1200 } else if (xcf_image.num_colors < 256) {
1201 // Plenty of room to add a transparent color
1202 xcf_image.num_colors++;
1203 xcf_image.palette.resize(xcf_image.num_colors);
1204 for (int c = xcf_image.num_colors - 1; c >= 1; c--)
1205 xcf_image.palette[c] = xcf_image.palette[c - 1];
1206
1207 xcf_image.palette[0] = tqRgba(255, 255, 255, 0);
1208 image.create( xcf_image.width, xcf_image.height,
1209 8, xcf_image.num_colors);
1210 if( image.isNull())
1211 return false;
1212 image.fill(0);
1213 setPalette(xcf_image, image);
1214 image.setAlphaBuffer(true);
1215 } else {
1216 // No room for a transparent color, so this has to be promoted to
1217 // true color. (There is no equivalent PNG representation output
1218 // from The GIMP as of v1.2.)
1219 image.create(xcf_image.width, xcf_image.height, 32);
1220 if( image.isNull())
1221 return false;
1222 image.fill(tqRgba(255, 255, 255, 0));
1223 image.setAlphaBuffer(true);
1224 }
1225 break;
1226 }
1227
1228 image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER));
1229 image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER));
1230 return true;
1231}
1232
1233
1239void XCFImageFormat::copyLayerToImage(XCFImage& xcf_image)
1240{
1241 Layer& layer(xcf_image.layer);
1242 TQImage& image(xcf_image.image);
1243 PixelCopyOperation copy = 0;
1244
1245 switch (layer.type) {
1246 case RGB_GIMAGE:
1247 case RGBA_GIMAGE:
1248 copy = copyRGBToRGB;
1249 break;
1250 case GRAY_GIMAGE:
1251 if (layer.opacity == OPAQUE_OPACITY)
1252 copy = copyGrayToGray;
1253 else
1254 copy = copyGrayToRGB;
1255 break;
1256 case GRAYA_GIMAGE:
1257 copy = copyGrayAToRGB;
1258 break;
1259 case INDEXED_GIMAGE:
1260 copy = copyIndexedToIndexed;
1261 break;
1262 case INDEXEDA_GIMAGE:
1263 if (xcf_image.image.depth() <= 8)
1264 copy = copyIndexedAToIndexed;
1265 else
1266 copy = copyIndexedAToRGB;
1267 }
1268
1269 // For each tile...
1270
1271 for (uint j = 0; j < layer.nrows; j++) {
1272 uint y = j * TILE_HEIGHT;
1273
1274 for (uint i = 0; i < layer.ncols; i++) {
1275 uint x = i * TILE_WIDTH;
1276
1277 // This seems the best place to apply the dissolve because it
1278 // depends on the global position of each tile's
1279 // pixels. Apparently it's the only mode which can apply to a
1280 // single layer.
1281
1282 if (layer.mode == DISSOLVE_MODE) {
1283 if (layer.type == RGBA_GIMAGE)
1284 dissolveRGBPixels(layer.image_tiles[j][i], x, y);
1285
1286 else if (layer.type == GRAYA_GIMAGE)
1287 dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
1288 }
1289
1290 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
1291 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
1292
1293 int m = x + k + layer.x_offset;
1294 int n = y + l + layer.y_offset;
1295
1296 if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
1297 continue;
1298
1299 (*copy)(layer, i, j, k, l, image, m, n);
1300 }
1301 }
1302 }
1303 }
1304}
1305
1306
1320void XCFImageFormat::copyRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
1321 TQImage& image, int m, int n)
1322{
1323 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
1324 uchar src_a = layer.opacity;
1325
1326 if (layer.type == RGBA_GIMAGE)
1327 src_a = INT_MULT(src_a, tqAlpha(src));
1328
1329 // Apply the mask (if any)
1330
1331 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
1332 layer.mask_tiles[j].size() > i)
1333 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1334
1335 image.setPixel(m, n, tqRgba(src, src_a));
1336}
1337
1338
1350void XCFImageFormat::copyGrayToGray(Layer& layer, uint i, uint j, int k, int l,
1351 TQImage& image, int m, int n)
1352{
1353 int src = layer.image_tiles[j][i].pixelIndex(k, l);
1354 image.setPixel(m, n, src);
1355}
1356
1357
1371void XCFImageFormat::copyGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
1372 TQImage& image, int m, int n)
1373{
1374 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
1375 uchar src_a = layer.opacity;
1376 image.setPixel(m, n, tqRgba(src, src_a));
1377}
1378
1379
1393void XCFImageFormat::copyGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
1394 TQImage& image, int m, int n)
1395{
1396 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
1397 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1398 src_a = INT_MULT(src_a, layer.opacity);
1399
1400 // Apply the mask (if any)
1401
1402 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
1403 layer.mask_tiles[j].size() > i)
1404 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1405
1406 image.setPixel(m, n, tqRgba(src, src_a));
1407}
1408
1409
1421void XCFImageFormat::copyIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
1422 TQImage& image, int m, int n)
1423{
1424 int src = layer.image_tiles[j][i].pixelIndex(k, l);
1425 image.setPixel(m, n, src);
1426}
1427
1428
1440void XCFImageFormat::copyIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
1441 TQImage& image, int m, int n)
1442{
1443 uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
1444 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1445 src_a = INT_MULT(src_a, layer.opacity);
1446
1447 if (layer.apply_mask == 1 &&
1448 layer.mask_tiles.size() > j &&
1449 layer.mask_tiles[j].size() > i)
1450 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1451
1452 if (src_a > 127)
1453 src++;
1454 else
1455 src = 0;
1456
1457image.setPixel(m, n, src);
1458}
1459
1460
1474void XCFImageFormat::copyIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
1475 TQImage& image, int m, int n)
1476{
1477 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
1478 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1479 src_a = INT_MULT(src_a, layer.opacity);
1480
1481 // Apply the mask (if any)
1482 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
1483 layer.mask_tiles[j].size() > i)
1484 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1485
1486 // This is what appears in the GIMP window
1487 if (src_a <= 127)
1488 src_a = 0;
1489 else
1490 src_a = OPAQUE_OPACITY;
1491
1492 image.setPixel(m, n, tqRgba(src, src_a));
1493}
1494
1495
1500void XCFImageFormat::mergeLayerIntoImage(XCFImage& xcf_image)
1501{
1502 Layer& layer(xcf_image.layer);
1503 TQImage& image(xcf_image.image);
1504
1505 PixelMergeOperation merge = 0;
1506
1507 switch (layer.type) {
1508 case RGB_GIMAGE:
1509 case RGBA_GIMAGE:
1510 merge = mergeRGBToRGB;
1511 break;
1512 case GRAY_GIMAGE:
1513 if (layer.opacity == OPAQUE_OPACITY)
1514 merge = mergeGrayToGray;
1515 else
1516 merge = mergeGrayToRGB;
1517 break;
1518 case GRAYA_GIMAGE:
1519 if (xcf_image.image.depth() <= 8)
1520 merge = mergeGrayAToGray;
1521 else
1522 merge = mergeGrayAToRGB;
1523 break;
1524 case INDEXED_GIMAGE:
1525 merge = mergeIndexedToIndexed;
1526 break;
1527 case INDEXEDA_GIMAGE:
1528 if (xcf_image.image.depth() <= 8)
1529 merge = mergeIndexedAToIndexed;
1530 else
1531 merge = mergeIndexedAToRGB;
1532 }
1533
1534 for (uint j = 0; j < layer.nrows; j++) {
1535 uint y = j * TILE_HEIGHT;
1536
1537 for (uint i = 0; i < layer.ncols; i++) {
1538 uint x = i * TILE_WIDTH;
1539
1540 // This seems the best place to apply the dissolve because it
1541 // depends on the global position of each tile's
1542 // pixels. Apparently it's the only mode which can apply to a
1543 // single layer.
1544
1545 if (layer.mode == DISSOLVE_MODE) {
1546 if (layer.type == RGBA_GIMAGE)
1547 dissolveRGBPixels(layer.image_tiles[j][i], x, y);
1548
1549 else if (layer.type == GRAYA_GIMAGE)
1550 dissolveAlphaPixels(layer.alpha_tiles[j][i], x, y);
1551 }
1552
1553 for (int l = 0; l < layer.image_tiles[j][i].height(); l++) {
1554 for (int k = 0; k < layer.image_tiles[j][i].width(); k++) {
1555
1556 int m = x + k + layer.x_offset;
1557 int n = y + l + layer.y_offset;
1558
1559 if (m < 0 || m >= image.width() || n < 0 || n >= image.height())
1560 continue;
1561
1562 (*merge)(layer, i, j, k, l, image, m, n);
1563 }
1564 }
1565 }
1566 }
1567}
1568
1569
1583void XCFImageFormat::mergeRGBToRGB(Layer& layer, uint i, uint j, int k, int l,
1584 TQImage& image, int m, int n)
1585{
1586 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
1587 TQRgb dst = image.pixel(m, n);
1588
1589 uchar src_r = tqRed(src);
1590 uchar src_g = tqGreen(src);
1591 uchar src_b = tqBlue(src);
1592 uchar src_a = tqAlpha(src);
1593
1594 uchar dst_r = tqRed(dst);
1595 uchar dst_g = tqGreen(dst);
1596 uchar dst_b = tqBlue(dst);
1597 uchar dst_a = tqAlpha(dst);
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 = KMIN(src_a, dst_a);
1605 }
1606 break;
1607 case DIVIDE_MODE: {
1608 src_r = KMIN((dst_r * 256) / (1 + src_r), 255);
1609 src_g = KMIN((dst_g * 256) / (1 + src_g), 255);
1610 src_b = KMIN((dst_b * 256) / (1 + src_b), 255);
1611 src_a = KMIN(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 = KMIN(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 = KMIN(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 = KMIN(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 = KMIN(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 = KMIN(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 = KMIN( 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 = KMIN(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 = KMIN( 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 = KMIN(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 = KMIN(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 = KMIN(src_a, dst_a);
1734 }
1735 break;
1736 }
1737
1738 src_a = INT_MULT(src_a, layer.opacity);
1739
1740 // Apply the mask (if any)
1741
1742 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
1743 layer.mask_tiles[j].size() > i)
1744 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1745
1746 uchar new_r, new_g, new_b, new_a;
1747 new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
1748
1749 float src_ratio = (float)src_a / new_a;
1750 float dst_ratio = 1.0 - src_ratio;
1751
1752 new_r = (uchar)(src_ratio * src_r + dst_ratio * dst_r + EPSILON);
1753 new_g = (uchar)(src_ratio * src_g + dst_ratio * dst_g + EPSILON);
1754 new_b = (uchar)(src_ratio * src_b + dst_ratio * dst_b + EPSILON);
1755
1756 if (!layer_modes[layer.mode].affect_alpha)
1757 new_a = dst_a;
1758
1759 image.setPixel(m, n, tqRgba(new_r, new_g, new_b, new_a));
1760}
1761
1762
1774void XCFImageFormat::mergeGrayToGray(Layer& layer, uint i, uint j, int k, int l,
1775 TQImage& image, int m, int n)
1776{
1777 int src = layer.image_tiles[j][i].pixelIndex(k, l);
1778 image.setPixel(m, n, src);
1779}
1780
1781
1793void XCFImageFormat::mergeGrayAToGray(Layer& layer, uint i, uint j, int k, int l,
1794 TQImage& image, int m, int n)
1795{
1796 int src = tqGray(layer.image_tiles[j][i].pixel(k, l));
1797 int dst = image.pixelIndex(m, n);
1798
1799 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1800
1801 switch (layer.mode) {
1802 case MULTIPLY_MODE: {
1803 src = INT_MULT( src, dst );
1804 }
1805 break;
1806 case DIVIDE_MODE: {
1807 src = KMIN((dst * 256) / (1 + src), 255);
1808 }
1809 break;
1810 case SCREEN_MODE: {
1811 src = 255 - INT_MULT(255 - dst, 255 - src);
1812 }
1813 break;
1814 case OVERLAY_MODE: {
1815 src = INT_MULT(dst, dst + INT_MULT(2 * src, 255 - dst));
1816 }
1817 break;
1818 case DIFFERENCE_MODE: {
1819 src = dst > src ? dst - src : src - dst;
1820 }
1821 break;
1822 case ADDITION_MODE: {
1823 src = add_lut(dst,src);
1824 }
1825 break;
1826 case SUBTRACT_MODE: {
1827 src = dst > src ? dst - src : 0;
1828 }
1829 break;
1830 case DARKEN_ONLY_MODE: {
1831 src = dst < src ? dst : src;
1832 }
1833 break;
1834 case LIGHTEN_ONLY_MODE: {
1835 src = dst < src ? src : dst;
1836 }
1837 break;
1838 }
1839
1840 src_a = INT_MULT(src_a, layer.opacity);
1841
1842 // Apply the mask (if any)
1843
1844 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
1845 layer.mask_tiles[j].size() > i)
1846 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1847
1848 uchar new_a = OPAQUE_OPACITY;
1849
1850 float src_ratio = (float)src_a / new_a;
1851 float dst_ratio = 1.0 - src_ratio;
1852
1853 uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
1854
1855 image.setPixel(m, n, new_g);
1856}
1857
1858
1872void XCFImageFormat::mergeGrayToRGB(Layer& layer, uint i, uint j, int k, int l,
1873 TQImage& image, int m, int n)
1874{
1875 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
1876 uchar src_a = layer.opacity;
1877 image.setPixel(m, n, tqRgba(src, src_a));
1878}
1879
1880
1894void XCFImageFormat::mergeGrayAToRGB(Layer& layer, uint i, uint j, int k, int l,
1895 TQImage& image, int m, int n)
1896{
1897 int src = tqGray(layer.image_tiles[j][i].pixel(k, l));
1898 int dst = tqGray(image.pixel(m, n));
1899
1900 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
1901 uchar dst_a = tqAlpha(image.pixel(m, n));
1902
1903 switch (layer.mode) {
1904 case MULTIPLY_MODE: {
1905 src = INT_MULT(src, dst);
1906 src_a = KMIN(src_a, dst_a);
1907 }
1908 break;
1909 case DIVIDE_MODE: {
1910 src = KMIN((dst * 256) / (1 + src), 255);
1911 src_a = KMIN(src_a, dst_a);
1912 }
1913 break;
1914 case SCREEN_MODE: {
1915 src = 255 - INT_MULT(255 - dst, 255 - src);
1916 src_a = KMIN(src_a, dst_a);
1917 }
1918 break;
1919 case OVERLAY_MODE: {
1920 src = INT_MULT( dst, dst + INT_MULT(2 * src, 255 - dst));
1921 src_a = KMIN(src_a, dst_a);
1922 }
1923 break;
1924 case DIFFERENCE_MODE: {
1925 src = dst > src ? dst - src : src - dst;
1926 src_a = KMIN(src_a, dst_a);
1927 }
1928 break;
1929 case ADDITION_MODE: {
1930 src = add_lut(dst,src);
1931 src_a = KMIN(src_a, dst_a);
1932 }
1933 break;
1934 case SUBTRACT_MODE: {
1935 src = dst > src ? dst - src : 0;
1936 src_a = KMIN(src_a, dst_a);
1937 }
1938 break;
1939 case DARKEN_ONLY_MODE: {
1940 src = dst < src ? dst : src;
1941 src_a = KMIN(src_a, dst_a);
1942 }
1943 break;
1944 case LIGHTEN_ONLY_MODE: {
1945 src = dst < src ? src : dst;
1946 src_a = KMIN(src_a, dst_a);
1947 }
1948 break;
1949 }
1950
1951 src_a = INT_MULT(src_a, layer.opacity);
1952
1953 // Apply the mask (if any)
1954 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
1955 layer.mask_tiles[j].size() > i)
1956 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
1957
1958 uchar new_a = dst_a + INT_MULT(OPAQUE_OPACITY - dst_a, src_a);
1959
1960 float src_ratio = (float)src_a / new_a;
1961 float dst_ratio = 1.0 - src_ratio;
1962
1963 uchar new_g = (uchar)(src_ratio * src + dst_ratio * dst + EPSILON);
1964
1965 if (!layer_modes[layer.mode].affect_alpha)
1966 new_a = dst_a;
1967
1968 image.setPixel(m, n, tqRgba(new_g, new_g, new_g, new_a));
1969}
1970
1971
1983void XCFImageFormat::mergeIndexedToIndexed(Layer& layer, uint i, uint j, int k, int l,
1984 TQImage& image, int m, int n)
1985{
1986 int src = layer.image_tiles[j][i].pixelIndex(k, l);
1987 image.setPixel(m, n, src);
1988}
1989
1990
2002void XCFImageFormat::mergeIndexedAToIndexed(Layer& layer, uint i, uint j, int k, int l,
2003 TQImage& image, int m, int n)
2004{
2005 uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
2006 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2007 src_a = INT_MULT( src_a, layer.opacity );
2008
2009 if ( layer.apply_mask == 1 &&
2010 layer.mask_tiles.size() > j &&
2011 layer.mask_tiles[j].size() > i)
2012 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2013
2014 if (src_a > 127) {
2015 src++;
2016 image.setPixel(m, n, src);
2017 }
2018}
2019
2020
2034void XCFImageFormat::mergeIndexedAToRGB(Layer& layer, uint i, uint j, int k, int l,
2035 TQImage& image, int m, int n)
2036{
2037 TQRgb src = layer.image_tiles[j][i].pixel(k, l);
2038 uchar src_a = layer.alpha_tiles[j][i].pixelIndex(k, l);
2039 src_a = INT_MULT(src_a, layer.opacity);
2040
2041 // Apply the mask (if any)
2042 if (layer.apply_mask == 1 && layer.mask_tiles.size() > j &&
2043 layer.mask_tiles[j].size() > i)
2044 src_a = INT_MULT(src_a, layer.mask_tiles[j][i].pixelIndex(k, l));
2045
2046 // This is what appears in the GIMP window
2047 if (src_a <= 127)
2048 src_a = 0;
2049 else
2050 src_a = OPAQUE_OPACITY;
2051
2052 image.setPixel(m, n, tqRgba(src, src_a));
2053}
2054
2055
2063void XCFImageFormat::dissolveRGBPixels ( TQImage& image, int x, int y )
2064{
2065 // The apparently spurious rand() calls are to wind the random
2066 // numbers up to the same point for each tile.
2067
2068 for (int l = 0; l < image.height(); l++) {
2069 srand(random_table[( l + y ) % RANDOM_TABLE_SIZE]);
2070
2071 for (int k = 0; k < x; k++)
2072 rand();
2073
2074 for (int k = 0; k < image.width(); k++) {
2075 int rand_val = rand() & 0xff;
2076 TQRgb pixel = image.pixel(k, l);
2077
2078 if (rand_val > tqAlpha(pixel)) {
2079 image.setPixel(k, l, tqRgba(pixel, 0));
2080 }
2081 }
2082 }
2083}
2084
2085
2095void XCFImageFormat::dissolveAlphaPixels ( TQImage& image, int x, int y )
2096{
2097 // The apparently spurious rand() calls are to wind the random
2098 // numbers up to the same point for each tile.
2099
2100 for (int l = 0; l < image.height(); l++) {
2101 srand( random_table[(l + y) % RANDOM_TABLE_SIZE]);
2102
2103 for (int k = 0; k < x; k++)
2104 rand();
2105
2106 for (int k = 0; k < image.width(); k++) {
2107 int rand_val = rand() & 0xff;
2108 uchar alpha = image.pixelIndex(k, l);
2109
2110 if (rand_val > alpha) {
2111 image.setPixel(k, l, 0);
2112 }
2113 }
2114 }
2115}
2116

kimgio

Skip menu "kimgio"
  • Main Page
  • File List
  • Related Pages

kimgio

Skip menu "kimgio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.9.4
This website is maintained by Timothy Pearson.