1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % X X CCCC FFFFF %
7 % X X C F %
8 % X C FFF %
9 % X X C F %
10 % X X CCCC F %
11 % %
12 % %
13 % Read GIMP XCF Image Format %
14 % %
15 % Software Design %
16 % Leonard Rosenthol %
17 % November 2001 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/color.h"
47 #include "MagickCore/composite.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/image-private.h"
52 #include "MagickCore/list.h"
53 #include "MagickCore/magick.h"
54 #include "MagickCore/memory_.h"
55 #include "MagickCore/pixel.h"
56 #include "MagickCore/pixel-accessor.h"
57 #include "MagickCore/property.h"
58 #include "MagickCore/quantize.h"
59 #include "MagickCore/quantum-private.h"
60 #include "MagickCore/resource_.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/string-private.h"
64 #include "MagickCore/module.h"
65
66 /*
67 Typedef declarations.
68 */
69 typedef enum
70 {
71 GIMP_RGB,
72 GIMP_GRAY,
73 GIMP_INDEXED
74 } GimpImageBaseType;
75
76 typedef enum
77 {
78 PROP_END = 0,
79 PROP_COLORMAP = 1,
80 PROP_ACTIVE_LAYER = 2,
81 PROP_ACTIVE_CHANNEL = 3,
82 PROP_SELECTION = 4,
83 PROP_FLOATING_SELECTION = 5,
84 PROP_OPACITY = 6,
85 PROP_MODE = 7,
86 PROP_VISIBLE = 8,
87 PROP_LINKED = 9,
88 PROP_PRESERVE_TRANSPARENCY = 10,
89 PROP_APPLY_MASK = 11,
90 PROP_EDIT_MASK = 12,
91 PROP_SHOW_MASK = 13,
92 PROP_SHOW_MASKED = 14,
93 PROP_OFFSETS = 15,
94 PROP_COLOR = 16,
95 PROP_COMPRESSION = 17,
96 PROP_GUIDES = 18,
97 PROP_RESOLUTION = 19,
98 PROP_TATTOO = 20,
99 PROP_PARASITES = 21,
100 PROP_UNIT = 22,
101 PROP_PATHS = 23,
102 PROP_USER_UNIT = 24
103 } PropType;
104
105 typedef enum
106 {
107 COMPRESS_NONE = 0,
108 COMPRESS_RLE = 1,
109 COMPRESS_ZLIB = 2, /* unused */
110 COMPRESS_FRACTAL = 3 /* unused */
111 } XcfCompressionType;
112
113 typedef struct
114 {
115 size_t
116 version,
117 width,
118 height,
119 image_type,
120 bytes_per_pixel;
121
122 int
123 compression;
124
125 size_t
126 file_size;
127
128 size_t
129 number_layers;
130 } XCFDocInfo;
131
132 typedef struct
133 {
134 char
135 name[1024];
136
137 unsigned int
138 active;
139
140 size_t
141 width,
142 height,
143 type,
144 alpha,
145 visible,
146 linked,
147 preserve_trans,
148 apply_mask,
149 show_mask,
150 edit_mask,
151 floating_offset;
152
153 ssize_t
154 offset_x,
155 offset_y;
156
157 size_t
158 mode,
159 tattoo;
160
161 Image
162 *image;
163 } XCFLayerInfo;
164
165 #define TILE_WIDTH 64
166 #define TILE_HEIGHT 64
167
168 typedef struct
169 {
170 unsigned char
171 red,
172 green,
173 blue,
174 alpha;
175 } XCFPixelInfo;
176
177 /*
178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179 % %
180 % %
181 % %
182 % I s X C F %
183 % %
184 % %
185 % %
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 %
188 % IsXCF() returns MagickTrue if the image format type, identified by the
189 % magick string, is XCF (GIMP native format).
190 %
191 % The format of the IsXCF method is:
192 %
193 % MagickBooleanType IsXCF(const unsigned char *magick,const size_t length)
194 %
195 % A description of each parameter follows:
196 %
197 % o magick: compare image format pattern against these bytes.
198 %
199 % o length: Specifies the length of the magick string.
200 %
201 %
202 */
IsXCF(const unsigned char * magick,const size_t length)203 static MagickBooleanType IsXCF(const unsigned char *magick,const size_t length)
204 {
205 if (length < 8)
206 return(MagickFalse);
207 if (LocaleNCompare((char *) magick,"gimp xcf",8) == 0)
208 return(MagickTrue);
209 return(MagickFalse);
210 }
211
212 typedef enum
213 {
214 GIMP_LAYER_MODE_NORMAL_LEGACY,
215 GIMP_LAYER_MODE_DISSOLVE,
216 GIMP_LAYER_MODE_BEHIND_LEGACY,
217 GIMP_LAYER_MODE_MULTIPLY_LEGACY,
218 GIMP_LAYER_MODE_SCREEN_LEGACY,
219 GIMP_LAYER_MODE_OVERLAY_LEGACY,
220 GIMP_LAYER_MODE_DIFFERENCE_LEGACY,
221 GIMP_LAYER_MODE_ADDITION_LEGACY,
222 GIMP_LAYER_MODE_SUBTRACT_LEGACY,
223 GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY,
224 GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY,
225 GIMP_LAYER_MODE_HSV_HUE_LEGACY,
226 GIMP_LAYER_MODE_HSV_SATURATION_LEGACY,
227 GIMP_LAYER_MODE_HSL_COLOR_LEGACY,
228 GIMP_LAYER_MODE_HSV_VALUE_LEGACY,
229 GIMP_LAYER_MODE_DIVIDE_LEGACY,
230 GIMP_LAYER_MODE_DODGE_LEGACY,
231 GIMP_LAYER_MODE_BURN_LEGACY,
232 GIMP_LAYER_MODE_HARDLIGHT_LEGACY,
233 GIMP_LAYER_MODE_SOFTLIGHT_LEGACY,
234 GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY,
235 GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY,
236 GIMP_LAYER_MODE_COLOR_ERASE_LEGACY,
237 GIMP_LAYER_MODE_OVERLAY,
238 GIMP_LAYER_MODE_LCH_HUE,
239 GIMP_LAYER_MODE_LCH_CHROMA,
240 GIMP_LAYER_MODE_LCH_COLOR,
241 GIMP_LAYER_MODE_LCH_LIGHTNESS,
242 GIMP_LAYER_MODE_NORMAL,
243 GIMP_LAYER_MODE_BEHIND,
244 GIMP_LAYER_MODE_MULTIPLY,
245 GIMP_LAYER_MODE_SCREEN,
246 GIMP_LAYER_MODE_DIFFERENCE,
247 GIMP_LAYER_MODE_ADDITION,
248 GIMP_LAYER_MODE_SUBTRACT,
249 GIMP_LAYER_MODE_DARKEN_ONLY,
250 GIMP_LAYER_MODE_LIGHTEN_ONLY,
251 GIMP_LAYER_MODE_HSV_HUE,
252 GIMP_LAYER_MODE_HSV_SATURATION,
253 GIMP_LAYER_MODE_HSL_COLOR,
254 GIMP_LAYER_MODE_HSV_VALUE,
255 GIMP_LAYER_MODE_DIVIDE,
256 GIMP_LAYER_MODE_DODGE,
257 GIMP_LAYER_MODE_BURN,
258 GIMP_LAYER_MODE_HARDLIGHT,
259 GIMP_LAYER_MODE_SOFTLIGHT,
260 GIMP_LAYER_MODE_GRAIN_EXTRACT,
261 GIMP_LAYER_MODE_GRAIN_MERGE,
262 GIMP_LAYER_MODE_VIVID_LIGHT,
263 GIMP_LAYER_MODE_PIN_LIGHT,
264 GIMP_LAYER_MODE_LINEAR_LIGHT,
265 GIMP_LAYER_MODE_HARD_MIX,
266 GIMP_LAYER_MODE_EXCLUSION,
267 GIMP_LAYER_MODE_LINEAR_BURN,
268 GIMP_LAYER_MODE_LUMA_DARKEN_ONLY,
269 GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY,
270 GIMP_LAYER_MODE_LUMINANCE,
271 GIMP_LAYER_MODE_COLOR_ERASE,
272 GIMP_LAYER_MODE_ERASE,
273 GIMP_LAYER_MODE_MERGE,
274 GIMP_LAYER_MODE_SPLIT,
275 GIMP_LAYER_MODE_PASS_THROUGH,
276 } GimpLayerMode;
277
278 /*
279 Simple utility routine to convert between PSD blending modes and
280 ImageMagick compositing operators
281 */
GIMPBlendModeToCompositeOperator(size_t blendMode)282 static CompositeOperator GIMPBlendModeToCompositeOperator(
283 size_t blendMode)
284 {
285 switch ( blendMode )
286 {
287 case GIMP_LAYER_MODE_NORMAL_LEGACY:
288 case GIMP_LAYER_MODE_NORMAL:
289 return(OverCompositeOp);
290 case GIMP_LAYER_MODE_DISSOLVE:
291 return(DissolveCompositeOp);
292 case GIMP_LAYER_MODE_MULTIPLY_LEGACY:
293 case GIMP_LAYER_MODE_MULTIPLY:
294 return(MultiplyCompositeOp);
295 case GIMP_LAYER_MODE_SCREEN_LEGACY:
296 case GIMP_LAYER_MODE_SCREEN:
297 return(ScreenCompositeOp);
298 case GIMP_LAYER_MODE_OVERLAY_LEGACY:
299 case GIMP_LAYER_MODE_OVERLAY:
300 return(OverlayCompositeOp);
301 case GIMP_LAYER_MODE_DIFFERENCE_LEGACY:
302 case GIMP_LAYER_MODE_DIFFERENCE:
303 return(DifferenceCompositeOp);
304 case GIMP_LAYER_MODE_ADDITION_LEGACY:
305 case GIMP_LAYER_MODE_ADDITION:
306 return(ModulusAddCompositeOp);
307 case GIMP_LAYER_MODE_SUBTRACT_LEGACY:
308 case GIMP_LAYER_MODE_SUBTRACT:
309 return(ModulusSubtractCompositeOp);
310 case GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY:
311 case GIMP_LAYER_MODE_DARKEN_ONLY:
312 case GIMP_LAYER_MODE_LUMA_DARKEN_ONLY:
313 return(DarkenCompositeOp);
314 case GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY:
315 case GIMP_LAYER_MODE_LIGHTEN_ONLY:
316 return(LightenCompositeOp);
317 case GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY:
318 return(LightenCompositeOp);
319 case GIMP_LAYER_MODE_HSV_HUE_LEGACY:
320 case GIMP_LAYER_MODE_HSV_HUE:
321 return(HueCompositeOp);
322 case GIMP_LAYER_MODE_HSV_SATURATION_LEGACY:
323 case GIMP_LAYER_MODE_HSV_SATURATION:
324 return(SaturateCompositeOp);
325 case GIMP_LAYER_MODE_HSL_COLOR_LEGACY:
326 case GIMP_LAYER_MODE_HSL_COLOR:
327 return(ColorizeCompositeOp);
328 case GIMP_LAYER_MODE_DODGE_LEGACY:
329 case GIMP_LAYER_MODE_DODGE:
330 return(ColorDodgeCompositeOp);
331 case GIMP_LAYER_MODE_BURN_LEGACY:
332 case GIMP_LAYER_MODE_BURN:
333 return(ColorBurnCompositeOp);
334 case GIMP_LAYER_MODE_HARDLIGHT_LEGACY:
335 case GIMP_LAYER_MODE_HARDLIGHT:
336 return(HardLightCompositeOp);
337 case GIMP_LAYER_MODE_DIVIDE_LEGACY:
338 case GIMP_LAYER_MODE_DIVIDE:
339 return(DivideDstCompositeOp);
340 /* these are the ones we don't support...yet */
341 default:
342 return(OverCompositeOp);
343 }
344 }
345
346 /*
347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348 % %
349 % %
350 % %
351 + R e a d B l o b S t r i n g W i t h L o n g S i z e %
352 % %
353 % %
354 % %
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 %
357 % ReadBlobStringWithLongSize reads characters from a blob or file
358 % starting with a ssize_t length byte and then characters to that length
359 %
360 % The format of the ReadBlobStringWithLongSize method is:
361 %
362 % char *ReadBlobStringWithLongSize(Image *image,char *string,
363 % ExceptionInfo *exception)
364 %
365 % A description of each parameter follows:
366 %
367 % o image: the image.
368 %
369 % o string: the address of a character buffer.
370 %
371 % o exception: return any errors or warnings in this structure.
372 %
373 */
374
ReadBlobStringWithLongSize(Image * image,char * string,size_t max,ExceptionInfo * exception)375 static char *ReadBlobStringWithLongSize(Image *image,char *string,size_t max,
376 ExceptionInfo *exception)
377 {
378 int
379 c;
380
381 MagickOffsetType
382 offset;
383
384 register ssize_t
385 i;
386
387 size_t
388 length;
389
390 assert(image != (Image *) NULL);
391 assert(image->signature == MagickCoreSignature);
392 assert(max != 0);
393 if (image->debug != MagickFalse)
394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
395 length=ReadBlobMSBLong(image);
396 for (i=0; i < (ssize_t) MagickMin(length,max-1); i++)
397 {
398 c=ReadBlobByte(image);
399 if (c == EOF)
400 return((char *) NULL);
401 string[i]=(char) c;
402 }
403 string[i]='\0';
404 offset=SeekBlob(image,(MagickOffsetType) (length-i),SEEK_CUR);
405 if (offset < 0)
406 (void) ThrowMagickException(exception,GetMagickModule(),
407 CorruptImageError,"ImproperImageHeader","`%s'",image->filename);
408 return(string);
409 }
410
GetXCFOffset(Image * image,XCFDocInfo * inDocInfo)411 static MagickOffsetType GetXCFOffset(Image *image, XCFDocInfo *inDocInfo)
412 {
413 if (inDocInfo->version >= 4)
414 return (MagickOffsetType) ReadBlobMSBLongLong(image);
415 else
416 return (MagickOffsetType) ReadBlobMSBLong(image);
417 }
418
load_tile(Image * image,Image * tile_image,XCFDocInfo * inDocInfo,XCFLayerInfo * inLayerInfo,size_t data_length,ExceptionInfo * exception)419 static MagickBooleanType load_tile(Image *image,Image *tile_image,
420 XCFDocInfo *inDocInfo,XCFLayerInfo *inLayerInfo,size_t data_length,
421 ExceptionInfo *exception)
422 {
423 ssize_t
424 y;
425
426 register ssize_t
427 x;
428
429 register Quantum
430 *q;
431
432 size_t
433 extent;
434
435 ssize_t
436 count;
437
438 unsigned char
439 *graydata;
440
441 XCFPixelInfo
442 *xcfdata,
443 *xcfodata;
444
445 extent=0;
446 if (inDocInfo->image_type == GIMP_GRAY)
447 extent=tile_image->columns*tile_image->rows*sizeof(*graydata);
448 else
449 if (inDocInfo->image_type == GIMP_RGB)
450 extent=tile_image->columns*tile_image->rows*sizeof(*xcfdata);
451 if (extent > data_length)
452 ThrowBinaryException(CorruptImageError,"NotEnoughPixelData",
453 image->filename);
454 xcfdata=(XCFPixelInfo *) AcquireQuantumMemory(MagickMax(data_length,
455 tile_image->columns*tile_image->rows),sizeof(*xcfdata));
456 if (xcfdata == (XCFPixelInfo *) NULL)
457 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
458 image->filename);
459 xcfodata=xcfdata;
460 graydata=(unsigned char *) xcfdata; /* used by gray and indexed */
461 count=ReadBlob(image,data_length,(unsigned char *) xcfdata);
462 if (count != (ssize_t) data_length)
463 {
464 xcfodata=(XCFPixelInfo *) RelinquishMagickMemory(xcfodata);
465 ThrowBinaryException(CorruptImageError,"NotEnoughPixelData",
466 image->filename);
467 }
468 for (y=0; y < (ssize_t) tile_image->rows; y++)
469 {
470 q=GetAuthenticPixels(tile_image,0,y,tile_image->columns,1,exception);
471 if (q == (Quantum *) NULL)
472 break;
473 if (inDocInfo->image_type == GIMP_GRAY)
474 {
475 for (x=0; x < (ssize_t) tile_image->columns; x++)
476 {
477 SetPixelGray(tile_image,ScaleCharToQuantum(*graydata),q);
478 SetPixelAlpha(tile_image,ScaleCharToQuantum((unsigned char)
479 inLayerInfo->alpha),q);
480 graydata++;
481 q+=GetPixelChannels(tile_image);
482 }
483 }
484 else
485 if (inDocInfo->image_type == GIMP_RGB)
486 {
487 for (x=0; x < (ssize_t) tile_image->columns; x++)
488 {
489 SetPixelRed(tile_image,ScaleCharToQuantum(xcfdata->red),q);
490 SetPixelGreen(tile_image,ScaleCharToQuantum(xcfdata->green),q);
491 SetPixelBlue(tile_image,ScaleCharToQuantum(xcfdata->blue),q);
492 SetPixelAlpha(tile_image,xcfdata->alpha == 255U ? TransparentAlpha :
493 ScaleCharToQuantum((unsigned char) inLayerInfo->alpha),q);
494 xcfdata++;
495 q+=GetPixelChannels(tile_image);
496 }
497 }
498 if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
499 break;
500 }
501 xcfodata=(XCFPixelInfo *) RelinquishMagickMemory(xcfodata);
502 return MagickTrue;
503 }
504
load_tile_rle(Image * image,Image * tile_image,XCFDocInfo * inDocInfo,XCFLayerInfo * inLayerInfo,size_t data_length,ExceptionInfo * exception)505 static MagickBooleanType load_tile_rle(Image *image,Image *tile_image,
506 XCFDocInfo *inDocInfo,XCFLayerInfo *inLayerInfo,size_t data_length,
507 ExceptionInfo *exception)
508 {
509 MagickOffsetType
510 size;
511
512 Quantum
513 alpha,
514 data;
515
516 register Quantum
517 *q;
518
519 size_t
520 length;
521
522 ssize_t
523 bytes_per_pixel,
524 count,
525 i,
526 j;
527
528 unsigned char
529 pixel,
530 *xcfdata,
531 *xcfodata,
532 *xcfdatalimit;
533
534 bytes_per_pixel=(ssize_t) inDocInfo->bytes_per_pixel;
535 xcfdata=(unsigned char *) AcquireQuantumMemory(data_length,sizeof(*xcfdata));
536 if (xcfdata == (unsigned char *) NULL)
537 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
538 image->filename);
539 xcfodata=xcfdata;
540 count=ReadBlob(image, (size_t) data_length, xcfdata);
541 xcfdatalimit = xcfodata+count-1;
542 alpha=ScaleCharToQuantum((unsigned char) inLayerInfo->alpha);
543 for (i=0; i < bytes_per_pixel; i++)
544 {
545 q=GetAuthenticPixels(tile_image,0,0,tile_image->columns,tile_image->rows,
546 exception);
547 if (q == (Quantum *) NULL)
548 continue;
549 size=(MagickOffsetType) tile_image->rows*tile_image->columns;
550 while (size > 0)
551 {
552 if (xcfdata > xcfdatalimit)
553 goto bogus_rle;
554 pixel=(*xcfdata++);
555 length=(size_t) pixel;
556 if (length >= 128)
557 {
558 length=255-(length-1);
559 if (length == 128)
560 {
561 if (xcfdata >= xcfdatalimit)
562 goto bogus_rle;
563 length=(size_t) ((*xcfdata << 8) + xcfdata[1]);
564 xcfdata+=2;
565 }
566 size-=length;
567 if (size < 0)
568 goto bogus_rle;
569 if (&xcfdata[length-1] > xcfdatalimit)
570 goto bogus_rle;
571 while (length-- > 0)
572 {
573 data=ScaleCharToQuantum(*xcfdata++);
574 switch (i)
575 {
576 case 0:
577 {
578 if (inDocInfo->image_type == GIMP_GRAY)
579 SetPixelGray(tile_image,data,q);
580 else
581 {
582 SetPixelRed(tile_image,data,q);
583 SetPixelGreen(tile_image,data,q);
584 SetPixelBlue(tile_image,data,q);
585 }
586 SetPixelAlpha(tile_image,alpha,q);
587 break;
588 }
589 case 1:
590 {
591 if (inDocInfo->image_type == GIMP_GRAY)
592 SetPixelAlpha(tile_image,data,q);
593 else
594 SetPixelGreen(tile_image,data,q);
595 break;
596 }
597 case 2:
598 {
599 SetPixelBlue(tile_image,data,q);
600 break;
601 }
602 case 3:
603 {
604 SetPixelAlpha(tile_image,data,q);
605 break;
606 }
607 }
608 q+=GetPixelChannels(tile_image);
609 }
610 }
611 else
612 {
613 length+=1;
614 if (length == 128)
615 {
616 if (xcfdata >= xcfdatalimit)
617 goto bogus_rle;
618 length=(size_t) ((*xcfdata << 8) + xcfdata[1]);
619 xcfdata+=2;
620 }
621 size-=length;
622 if (size < 0)
623 goto bogus_rle;
624 if (xcfdata > xcfdatalimit)
625 goto bogus_rle;
626 pixel=(*xcfdata++);
627 for (j=0; j < (ssize_t) length; j++)
628 {
629 data=ScaleCharToQuantum(pixel);
630 switch (i)
631 {
632 case 0:
633 {
634 if (inDocInfo->image_type == GIMP_GRAY)
635 SetPixelGray(tile_image,data,q);
636 else
637 {
638 SetPixelRed(tile_image,data,q);
639 SetPixelGreen(tile_image,data,q);
640 SetPixelBlue(tile_image,data,q);
641 }
642 SetPixelAlpha(tile_image,alpha,q);
643 break;
644 }
645 case 1:
646 {
647 if (inDocInfo->image_type == GIMP_GRAY)
648 SetPixelAlpha(tile_image,data,q);
649 else
650 SetPixelGreen(tile_image,data,q);
651 break;
652 }
653 case 2:
654 {
655 SetPixelBlue(tile_image,data,q);
656 break;
657 }
658 case 3:
659 {
660 SetPixelAlpha(tile_image,data,q);
661 break;
662 }
663 }
664 q+=GetPixelChannels(tile_image);
665 }
666 }
667 }
668 if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
669 break;
670 }
671 xcfodata=(unsigned char *) RelinquishMagickMemory(xcfodata);
672 return(MagickTrue);
673
674 bogus_rle:
675 if (xcfodata != (unsigned char *) NULL)
676 xcfodata=(unsigned char *) RelinquishMagickMemory(xcfodata);
677 return(MagickFalse);
678 }
679
load_level(Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * inLayerInfo,ExceptionInfo * exception)680 static MagickBooleanType load_level(Image *image,XCFDocInfo *inDocInfo,
681 XCFLayerInfo *inLayerInfo,ExceptionInfo *exception)
682 {
683 int
684 destLeft = 0,
685 destTop = 0;
686
687 Image*
688 tile_image;
689
690 MagickBooleanType
691 status;
692
693 MagickOffsetType
694 saved_pos,
695 offset,
696 offset2;
697
698 register ssize_t
699 i;
700
701 size_t
702 width,
703 height,
704 ntiles,
705 ntile_rows,
706 ntile_cols,
707 tile_image_width,
708 tile_image_height;
709
710 /* start reading the data */
711 width=ReadBlobMSBLong(image);
712 height=ReadBlobMSBLong(image);
713
714 /*
715 Read in the first tile offset. If it is '0', then this tile level is empty
716 and we can simply return.
717 */
718 offset=GetXCFOffset(image,inDocInfo);
719 if (offset == 0)
720 return(MagickTrue);
721 /*
722 Initialise the reference for the in-memory tile-compression
723 */
724 ntile_rows=(height+TILE_HEIGHT-1)/TILE_HEIGHT;
725 ntile_cols=(width+TILE_WIDTH-1)/TILE_WIDTH;
726 ntiles=ntile_rows*ntile_cols;
727 for (i = 0; i < (ssize_t) ntiles; i++)
728 {
729 status=MagickFalse;
730 if (offset == 0)
731 ThrowBinaryException(CorruptImageError,"NotEnoughTiles",image->filename);
732 /*
733 Save the current position as it is where the next tile offset is stored.
734 */
735 saved_pos=TellBlob(image);
736 /* read in the offset of the next tile so we can calculate the amount
737 of data needed for this tile*/
738 offset2=GetXCFOffset(image,inDocInfo);
739 if ((MagickSizeType) offset2 >= inDocInfo->file_size)
740 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
741 image->filename);
742 /* if the offset is 0 then we need to read in the maximum possible
743 allowing for negative compression */
744 if (offset2 == 0)
745 offset2=(MagickOffsetType) (offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5);
746 /* seek to the tile offset */
747 if ((offset > offset2) || (SeekBlob(image, offset, SEEK_SET) != offset))
748 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
749 image->filename);
750
751 /*
752 Allocate the image for the tile. NOTE: the last tile in a row or
753 column may not be a full tile!
754 */
755 tile_image_width=(size_t) (destLeft == (int) ntile_cols-1 ?
756 (int) width % TILE_WIDTH : TILE_WIDTH);
757 if (tile_image_width == 0)
758 tile_image_width=TILE_WIDTH;
759 tile_image_height = (size_t) (destTop == (int) ntile_rows-1 ?
760 (int) height % TILE_HEIGHT : TILE_HEIGHT);
761 if (tile_image_height == 0)
762 tile_image_height=TILE_HEIGHT;
763 tile_image=CloneImage(inLayerInfo->image,tile_image_width,
764 tile_image_height,MagickTrue,exception);
765 if (tile_image == (Image *) NULL)
766 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
767 image->filename);
768 (void) SetImageBackgroundColor(tile_image,exception);
769
770 /* read in the tile */
771 switch (inDocInfo->compression)
772 {
773 case COMPRESS_NONE:
774 status=load_tile(image,tile_image,inDocInfo,inLayerInfo,(size_t)
775 (offset2-offset),exception);
776 break;
777 case COMPRESS_RLE:
778 status=load_tile_rle(image,tile_image,inDocInfo,inLayerInfo,(size_t)
779 (offset2-offset),exception);
780 break;
781 case COMPRESS_ZLIB:
782 tile_image=DestroyImage(tile_image);
783 ThrowBinaryException(CoderError,"ZipCompressNotSupported",
784 image->filename)
785 case COMPRESS_FRACTAL:
786 tile_image=DestroyImage(tile_image);
787 ThrowBinaryException(CoderError,"FractalCompressNotSupported",
788 image->filename)
789 }
790
791 /* composite the tile onto the layer's image, and then destroy it */
792 if (status != MagickFalse)
793 (void) CompositeImage(inLayerInfo->image,tile_image,CopyCompositeOp,
794 MagickTrue,destLeft * TILE_WIDTH,destTop*TILE_HEIGHT,exception);
795 tile_image=DestroyImage(tile_image);
796
797 if (status == MagickFalse)
798 return(MagickFalse);
799 /* adjust tile position */
800 destLeft++;
801 if (destLeft >= (int) ntile_cols)
802 {
803 destLeft = 0;
804 destTop++;
805 }
806 /* restore the saved position so we'll be ready to
807 * read the next offset.
808 */
809 offset=SeekBlob(image, saved_pos, SEEK_SET);
810 /* read in the offset of the next tile */
811 offset=GetXCFOffset(image,inDocInfo);
812 }
813 if (offset != 0)
814 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename)
815 return(MagickTrue);
816 }
817
load_hierarchy(Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * inLayer,ExceptionInfo * exception)818 static MagickBooleanType load_hierarchy(Image *image,XCFDocInfo *inDocInfo,
819 XCFLayerInfo *inLayer, ExceptionInfo *exception)
820 {
821 MagickOffsetType
822 saved_pos,
823 offset,
824 junk;
825
826 (void) ReadBlobMSBLong(image); /* width */
827 (void) ReadBlobMSBLong(image); /* height */
828 inDocInfo->bytes_per_pixel=ReadBlobMSBLong(image);
829
830 /* load in the levels...we make sure that the number of levels
831 * calculated when the TileManager was created is the same
832 * as the number of levels found in the file.
833 */
834 offset=GetXCFOffset(image,inDocInfo); /* top level */
835 if ((MagickSizeType) offset >= GetBlobSize(image))
836 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
837 image->filename);
838
839 /* discard offsets for layers below first, if any.
840 */
841 do
842 {
843 junk=(MagickOffsetType) ReadBlobMSBLong(image);
844 }
845 while (junk != 0);
846
847 /* save the current position as it is where the
848 * next level offset is stored.
849 */
850 saved_pos=TellBlob(image);
851
852 /* seek to the level offset */
853 if (SeekBlob(image, offset, SEEK_SET) != offset)
854 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
855 image->filename);
856
857 /* read in the level */
858 if (load_level (image, inDocInfo, inLayer, exception) == 0)
859 return(MagickFalse);
860 /* restore the saved position so we'll be ready to
861 * read the next offset.
862 */
863 offset=SeekBlob(image, saved_pos, SEEK_SET);
864 return(MagickTrue);
865 }
866
InitXCFImage(XCFLayerInfo * outLayer,ExceptionInfo * exception)867 static void InitXCFImage(XCFLayerInfo *outLayer,ExceptionInfo *exception)
868 {
869 outLayer->image->page.x=outLayer->offset_x;
870 outLayer->image->page.y=outLayer->offset_y;
871 outLayer->image->page.width=outLayer->width;
872 outLayer->image->page.height=outLayer->height;
873 (void) SetImageProperty(outLayer->image,"label",(char *)outLayer->name,
874 exception);
875 }
876
ReadOneLayer(const ImageInfo * image_info,Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * outLayer,const ssize_t layer,ExceptionInfo * exception)877 static MagickBooleanType ReadOneLayer(const ImageInfo *image_info,Image* image,
878 XCFDocInfo* inDocInfo,XCFLayerInfo *outLayer,const ssize_t layer,
879 ExceptionInfo *exception)
880 {
881 MagickBooleanType
882 status;
883
884 MagickOffsetType
885 offset;
886
887 unsigned int
888 foundPropEnd = 0;
889
890 MagickOffsetType
891 hierarchy_offset,
892 layer_mask_offset;
893
894 /* clear the block! */
895 (void) memset( outLayer, 0, sizeof( XCFLayerInfo ) );
896 /* read in the layer width, height, type and name */
897 outLayer->width = ReadBlobMSBLong(image);
898 outLayer->height = ReadBlobMSBLong(image);
899 outLayer->type = ReadBlobMSBLong(image);
900 (void) ReadBlobStringWithLongSize(image, outLayer->name,
901 sizeof(outLayer->name),exception);
902 if (EOFBlob(image) != MagickFalse)
903 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
904 image->filename);
905 if ((outLayer->width == 0) || (outLayer->height == 0))
906 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
907 image->filename);
908 /* read the layer properties! */
909 foundPropEnd = 0;
910 while ( (foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse) ) {
911 PropType prop_type = (PropType) ReadBlobMSBLong(image);
912 size_t prop_size = ReadBlobMSBLong(image);
913 switch (prop_type)
914 {
915 case PROP_END:
916 foundPropEnd = 1;
917 break;
918 case PROP_ACTIVE_LAYER:
919 outLayer->active = 1;
920 break;
921 case PROP_FLOATING_SELECTION:
922 outLayer->floating_offset = ReadBlobMSBLong(image);
923 break;
924 case PROP_OPACITY:
925 outLayer->alpha = ReadBlobMSBLong(image);
926 break;
927 case PROP_VISIBLE:
928 outLayer->visible = ReadBlobMSBLong(image);
929 break;
930 case PROP_LINKED:
931 outLayer->linked = ReadBlobMSBLong(image);
932 break;
933 case PROP_PRESERVE_TRANSPARENCY:
934 outLayer->preserve_trans = ReadBlobMSBLong(image);
935 break;
936 case PROP_APPLY_MASK:
937 outLayer->apply_mask = ReadBlobMSBLong(image);
938 break;
939 case PROP_EDIT_MASK:
940 outLayer->edit_mask = ReadBlobMSBLong(image);
941 break;
942 case PROP_SHOW_MASK:
943 outLayer->show_mask = ReadBlobMSBLong(image);
944 break;
945 case PROP_OFFSETS:
946 outLayer->offset_x = ReadBlobMSBSignedLong(image);
947 outLayer->offset_y = ReadBlobMSBSignedLong(image);
948 break;
949 case PROP_MODE:
950 outLayer->mode = ReadBlobMSBLong(image);
951 break;
952 case PROP_TATTOO:
953 outLayer->preserve_trans = ReadBlobMSBLong(image);
954 break;
955 case PROP_PARASITES:
956 {
957 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
958 ThrowFileException(exception,CorruptImageError,
959 "UnexpectedEndOfFile",image->filename);
960
961 /*
962 ssize_t base = info->cp;
963 GimpParasite *p;
964 while (info->cp - base < prop_size)
965 {
966 p = xcf_load_parasite(info);
967 gimp_drawable_parasite_attach(GIMP_DRAWABLE(layer), p);
968 gimp_parasite_free(p);
969 }
970 if (info->cp - base != prop_size)
971 g_message ("Error detected while loading a layer's parasites");
972 */
973 }
974 break;
975 default:
976 /* g_message ("unexpected/unknown layer property: %d (skipping)",
977 prop_type); */
978
979 {
980 int buf[16];
981 ssize_t amount;
982
983 /* read over it... */
984 while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
985 {
986 amount = (ssize_t) MagickMin(16, prop_size);
987 amount = ReadBlob(image, (size_t) amount, (unsigned char *) &buf);
988 if (!amount)
989 ThrowBinaryException(CorruptImageError,"CorruptImage",
990 image->filename);
991 prop_size -= (size_t) MagickMin(16, (size_t) amount);
992 }
993 }
994 break;
995 }
996 }
997 if (EOFBlob(image) != MagickFalse)
998 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
999 image->filename);
1000 if (foundPropEnd == MagickFalse)
1001 return(MagickFalse);
1002 /* allocate the image for this layer */
1003 if (image_info->number_scenes != 0)
1004 {
1005 ssize_t
1006 scene;
1007
1008 scene=inDocInfo->number_layers-layer-1;
1009 if (scene > (ssize_t) (image_info->scene+image_info->number_scenes-1))
1010 {
1011 outLayer->image=CloneImage(image,0,0,MagickTrue,exception);
1012 if (outLayer->image == (Image *) NULL)
1013 return(MagickFalse);
1014 InitXCFImage(outLayer,exception);
1015 return(MagickTrue);
1016 }
1017 }
1018 outLayer->image=CloneImage(image,outLayer->width, outLayer->height,MagickTrue,
1019 exception);
1020 if (outLayer->image == (Image *) NULL)
1021 return(MagickFalse);
1022 outLayer->width=outLayer->image->columns;
1023 status=SetImageExtent(outLayer->image,outLayer->image->columns,
1024 outLayer->image->rows,exception);
1025 if (status != MagickFalse)
1026 status=ResetImagePixels(image,exception);
1027 if (status == MagickFalse)
1028 {
1029 outLayer->image=DestroyImageList(outLayer->image);
1030 return(MagickFalse);
1031 }
1032 /* clear the image based on the layer opacity */
1033 outLayer->image->background_color.alpha=
1034 ScaleCharToQuantum((unsigned char) outLayer->alpha);
1035 if (outLayer->alpha != 255U)
1036 {
1037 outLayer->image->background_color.alpha_trait=BlendPixelTrait;
1038 outLayer->image->alpha_trait=BlendPixelTrait;
1039 }
1040
1041 InitXCFImage(outLayer,exception);
1042
1043 /* set the compositing mode */
1044 outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode );
1045 if ( outLayer->visible == MagickFalse )
1046 {
1047 /* BOGUS: should really be separate member var! */
1048 outLayer->image->compose = NoCompositeOp;
1049 }
1050
1051 /* read the hierarchy and layer mask offsets */
1052 hierarchy_offset = GetXCFOffset(image,inDocInfo);
1053 layer_mask_offset = GetXCFOffset(image,inDocInfo);
1054
1055 /* read in the hierarchy */
1056 offset=SeekBlob(image, hierarchy_offset, SEEK_SET);
1057 if (offset != hierarchy_offset)
1058 (void) ThrowMagickException(exception,GetMagickModule(),
1059 CorruptImageError,"InvalidImageHeader","`%s'",image->filename);
1060 if (load_hierarchy (image, inDocInfo, outLayer, exception) == 0)
1061 return(MagickFalse);
1062
1063 /* read in the layer mask */
1064 if (layer_mask_offset != 0)
1065 {
1066 offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET);
1067
1068 #if 0 /* BOGUS: support layer masks! */
1069 layer_mask = xcf_load_layer_mask (info, gimage);
1070 if (layer_mask == 0)
1071 goto error;
1072
1073 /* set the offsets of the layer_mask */
1074 GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
1075 GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
1076
1077 gimp_layer_add_mask (layer, layer_mask, MagickFalse);
1078
1079 layer->mask->apply_mask = apply_mask;
1080 layer->mask->edit_mask = edit_mask;
1081 layer->mask->show_mask = show_mask;
1082 #endif
1083 }
1084
1085 /* attach the floating selection... */
1086 #if 0 /* BOGUS: we may need to read this, even if we don't support it! */
1087 if (add_floating_sel)
1088 {
1089 GimpLayer *floating_sel;
1090
1091 floating_sel = info->floating_sel;
1092 floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
1093 }
1094 #endif
1095
1096 return MagickTrue;
1097 }
1098
1099 /*
1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101 % %
1102 % %
1103 % %
1104 % R e a d X C F I m a g e %
1105 % %
1106 % %
1107 % %
1108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 %
1110 % ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image
1111 % file and returns it. It allocates the memory necessary for the new Image
1112 % structure and returns a pointer to the new image.
1113 %
1114 % The format of the ReadXCFImage method is:
1115 %
1116 % image=ReadXCFImage(image_info)
1117 %
1118 % A description of each parameter follows:
1119 %
1120 % o image_info: the image info.
1121 %
1122 % o exception: return any errors or warnings in this structure.
1123 %
1124 */
ReadXCFImage(const ImageInfo * image_info,ExceptionInfo * exception)1125 static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception)
1126 {
1127 char
1128 magick[14];
1129
1130 Image
1131 *image;
1132
1133 int
1134 foundPropEnd = 0;
1135
1136 MagickBooleanType
1137 status;
1138
1139 MagickOffsetType
1140 offset;
1141
1142 register ssize_t
1143 i;
1144
1145 size_t
1146 image_type,
1147 precision,
1148 length;
1149
1150 ssize_t
1151 count;
1152
1153 XCFDocInfo
1154 doc_info;
1155
1156 /*
1157 Open image file.
1158 */
1159 assert(image_info != (const ImageInfo *) NULL);
1160 assert(image_info->signature == MagickCoreSignature);
1161 if (image_info->debug != MagickFalse)
1162 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1163 image_info->filename);
1164 assert(exception != (ExceptionInfo *) NULL);
1165 assert(exception->signature == MagickCoreSignature);
1166 image=AcquireImage(image_info,exception);
1167 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1168 if (status == MagickFalse)
1169 {
1170 image=DestroyImageList(image);
1171 return((Image *) NULL);
1172 }
1173 count=ReadBlob(image,sizeof(magick),(unsigned char *) magick);
1174 if ((count != sizeof(magick)) ||
1175 (LocaleNCompare((char *) magick,"gimp xcf",8) != 0))
1176 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1177 (void) memset(&doc_info,0,sizeof(XCFDocInfo));
1178 doc_info.version=StringToUnsignedLong(magick+10);
1179 doc_info.width=ReadBlobMSBLong(image);
1180 doc_info.height=ReadBlobMSBLong(image);
1181 if ((doc_info.width > 262144) || (doc_info.height > 262144))
1182 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1183 doc_info.image_type=ReadBlobMSBLong(image);
1184 precision=150;
1185 if (doc_info.version >= 4)
1186 {
1187 precision=ReadBlobMSBLong(image);
1188 if (precision == 0)
1189 precision=150;
1190 if (precision != 150)
1191 ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
1192 }
1193 /*
1194 Initialize image attributes.
1195 */
1196 image->columns=doc_info.width;
1197 image->rows=doc_info.height;
1198 image_type=doc_info.image_type;
1199 doc_info.file_size=GetBlobSize(image);
1200 image->compression=NoCompression;
1201 image->depth=8;
1202 status=SetImageExtent(image,image->columns,image->rows,exception);
1203 if (status == MagickFalse)
1204 return(DestroyImageList(image));
1205 if (status != MagickFalse)
1206 status=ResetImagePixels(image,exception);
1207 if (image_type == GIMP_INDEXED)
1208 ThrowReaderException(CoderError,"ColormapTypeNotSupported");
1209 if (image_type == GIMP_RGB)
1210 SetImageColorspace(image,sRGBColorspace,exception);
1211 else if (image_type == GIMP_GRAY)
1212 SetImageColorspace(image,GRAYColorspace,exception);
1213 else
1214 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1215 (void) SetImageBackgroundColor(image,exception);
1216 (void) SetImageAlpha(image,OpaqueAlpha,exception);
1217 /*
1218 Read properties.
1219 */
1220 while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse))
1221 {
1222 PropType prop_type = (PropType) ReadBlobMSBLong(image);
1223 size_t prop_size = ReadBlobMSBLong(image);
1224
1225 switch (prop_type)
1226 {
1227 case PROP_END:
1228 foundPropEnd=1;
1229 break;
1230 case PROP_COLORMAP:
1231 {
1232 /* Cannot rely on prop_size here--the value is set incorrectly
1233 by some Gimp versions.
1234 */
1235 size_t num_colours = ReadBlobMSBLong(image);
1236 if (DiscardBlobBytes(image,3*num_colours) == MagickFalse)
1237 ThrowFileException(exception,CorruptImageError,
1238 "UnexpectedEndOfFile",image->filename);
1239 /*
1240 if (info->file_version == 0)
1241 {
1242 gint i;
1243
1244 g_message (_("XCF warning: version 0 of XCF file format\n"
1245 "did not save indexed colormaps correctly.\n"
1246 "Substituting grayscale map."));
1247 info->cp +=
1248 xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1249 gimage->cmap = g_new (guchar, gimage->num_cols*3);
1250 xcf_seek_pos (info, info->cp + gimage->num_cols);
1251 for (i = 0; i<gimage->num_cols; i++)
1252 {
1253 gimage->cmap[i*3+0] = i;
1254 gimage->cmap[i*3+1] = i;
1255 gimage->cmap[i*3+2] = i;
1256 }
1257 }
1258 else
1259 {
1260 info->cp +=
1261 xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1262 gimage->cmap = g_new (guchar, gimage->num_cols*3);
1263 info->cp +=
1264 xcf_read_int8 (info->fp,
1265 (guint8*) gimage->cmap, gimage->num_cols*3);
1266 }
1267 */
1268 break;
1269 }
1270 case PROP_COMPRESSION:
1271 {
1272 doc_info.compression = ReadBlobByte(image);
1273 if ((doc_info.compression != COMPRESS_NONE) &&
1274 (doc_info.compression != COMPRESS_RLE) &&
1275 (doc_info.compression != COMPRESS_ZLIB) &&
1276 (doc_info.compression != COMPRESS_FRACTAL))
1277 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
1278 }
1279 break;
1280
1281 case PROP_GUIDES:
1282 {
1283 /* just skip it - we don't care about guides */
1284 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1285 ThrowFileException(exception,CorruptImageError,
1286 "UnexpectedEndOfFile",image->filename);
1287 }
1288 break;
1289
1290 case PROP_RESOLUTION:
1291 {
1292 /* float xres = (float) */ (void) ReadBlobMSBLong(image);
1293 /* float yres = (float) */ (void) ReadBlobMSBLong(image);
1294
1295 /*
1296 if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
1297 yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
1298 {
1299 g_message ("Warning, resolution out of range in XCF file");
1300 xres = gimage->gimp->config->default_xresolution;
1301 yres = gimage->gimp->config->default_yresolution;
1302 }
1303 */
1304
1305
1306 /* BOGUS: we don't write these yet because we aren't
1307 reading them properly yet :(
1308 image->resolution.x = xres;
1309 image->resolution.y = yres;
1310 */
1311 }
1312 break;
1313
1314 case PROP_TATTOO:
1315 {
1316 /* we need to read it, even if we ignore it */
1317 /*size_t tattoo_state = */ (void) ReadBlobMSBLong(image);
1318 }
1319 break;
1320
1321 case PROP_PARASITES:
1322 {
1323 /* BOGUS: we may need these for IPTC stuff */
1324 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1325 ThrowFileException(exception,CorruptImageError,
1326 "UnexpectedEndOfFile",image->filename);
1327 /*
1328 gssize_t base = info->cp;
1329 GimpParasite *p;
1330
1331 while (info->cp - base < prop_size)
1332 {
1333 p = xcf_load_parasite (info);
1334 gimp_image_parasite_attach (gimage, p);
1335 gimp_parasite_free (p);
1336 }
1337 if (info->cp - base != prop_size)
1338 g_message ("Error detected while loading an image's parasites");
1339 */
1340 }
1341 break;
1342
1343 case PROP_UNIT:
1344 {
1345 /* BOGUS: ignore for now... */
1346 /*size_t unit = */ (void) ReadBlobMSBLong(image);
1347 }
1348 break;
1349
1350 case PROP_PATHS:
1351 {
1352 /* BOGUS: just skip it for now */
1353 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1354 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1355 image->filename);
1356
1357 /*
1358 PathList *paths = xcf_load_bzpaths (gimage, info);
1359 gimp_image_set_paths (gimage, paths);
1360 */
1361 }
1362 break;
1363
1364 case PROP_USER_UNIT:
1365 {
1366 char unit_string[1000];
1367 /*BOGUS: ignored for now */
1368 /*float factor = (float) */ (void) ReadBlobMSBLong(image);
1369 /* size_t digits = */ (void) ReadBlobMSBLong(image);
1370 for (i=0; i<5; i++)
1371 (void) ReadBlobStringWithLongSize(image, unit_string,
1372 sizeof(unit_string),exception);
1373 }
1374 break;
1375
1376 default:
1377 {
1378 int buf[16];
1379 ssize_t amount;
1380
1381 /* read over it... */
1382 while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
1383 {
1384 amount=(ssize_t) MagickMin(16, prop_size);
1385 amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf);
1386 if (!amount)
1387 ThrowReaderException(CorruptImageError,"CorruptImage");
1388 prop_size -= (size_t) MagickMin(16,(size_t) amount);
1389 }
1390 }
1391 break;
1392 }
1393 }
1394 if (foundPropEnd == MagickFalse)
1395 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1396
1397 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1398 {
1399 ; /* do nothing, were just pinging! */
1400 }
1401 else
1402 {
1403 int
1404 current_layer = 0,
1405 foundAllLayers = MagickFalse,
1406 number_layers = 0;
1407
1408 MagickOffsetType
1409 oldPos=TellBlob(image);
1410
1411 XCFLayerInfo
1412 *layer_info;
1413
1414 /*
1415 The read pointer.
1416 */
1417 do
1418 {
1419 offset=GetXCFOffset(image,&doc_info);
1420 if (offset == 0)
1421 foundAllLayers=MagickTrue;
1422 else
1423 number_layers++;
1424 if (EOFBlob(image) != MagickFalse)
1425 {
1426 ThrowFileException(exception,CorruptImageError,
1427 "UnexpectedEndOfFile",image->filename);
1428 break;
1429 }
1430 } while (foundAllLayers == MagickFalse);
1431 if (AcquireMagickResource(ListLengthResource,number_layers) == MagickFalse)
1432 ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1433 doc_info.number_layers=number_layers;
1434 offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */
1435 if (offset < 0)
1436 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1437 /* allocate our array of layer info blocks */
1438 length=(size_t) number_layers;
1439 layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length,
1440 sizeof(*layer_info));
1441 if (layer_info == (XCFLayerInfo *) NULL)
1442 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1443 (void) memset(layer_info,0,number_layers*sizeof(XCFLayerInfo));
1444 for ( ; ; )
1445 {
1446 MagickBooleanType
1447 layer_ok;
1448
1449 MagickOffsetType
1450 saved_pos;
1451
1452 /* read in the offset of the next layer */
1453 offset=GetXCFOffset(image,&doc_info);
1454 /* if the offset is 0 then we are at the end
1455 * of the layer list.
1456 */
1457 if (offset == 0)
1458 break;
1459 /* save the current position as it is where the
1460 * next layer offset is stored.
1461 */
1462 saved_pos=TellBlob(image);
1463 /* seek to the layer offset */
1464 layer_ok=MagickFalse;
1465 if (SeekBlob(image,offset,SEEK_SET) == offset)
1466 {
1467 /* read in the layer */
1468 layer_ok=ReadOneLayer(image_info,image,&doc_info,
1469 &layer_info[current_layer],current_layer,exception);
1470 }
1471 if (layer_ok == MagickFalse)
1472 {
1473 ssize_t j;
1474
1475 for (j=0; j <= current_layer; j++)
1476 if (layer_info[j].image != (Image *) NULL)
1477 layer_info[j].image=DestroyImage(layer_info[j].image);
1478 layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1479 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1480 }
1481 /* restore the saved position so we'll be ready to
1482 * read the next offset.
1483 */
1484 offset=SeekBlob(image, saved_pos, SEEK_SET);
1485 current_layer++;
1486 }
1487 #if 0
1488 {
1489 /* NOTE: XCF layers are REVERSED from composite order! */
1490 signed int j;
1491 for (j=number_layers-1; j>=0; j--) {
1492 /* BOGUS: need to consider layer blending modes!! */
1493
1494 if ( layer_info[j].visible ) { /* only visible ones, please! */
1495 CompositeImage(image, OverCompositeOp, layer_info[j].image,
1496 layer_info[j].offset_x, layer_info[j].offset_y );
1497 layer_info[j].image =DestroyImage( layer_info[j].image );
1498
1499 /* If we do this, we'll get REAL gray images! */
1500 if ( image_type == GIMP_GRAY ) {
1501 QuantizeInfo qi;
1502 GetQuantizeInfo(&qi);
1503 qi.colorspace = GRAYColorspace;
1504 QuantizeImage( &qi, layer_info[j].image );
1505 }
1506 }
1507 }
1508 }
1509 #else
1510 {
1511 /* NOTE: XCF layers are REVERSED from composite order! */
1512 ssize_t j;
1513
1514 /* now reverse the order of the layers as they are put
1515 into subimages
1516 */
1517 for (j=(ssize_t) number_layers-1; j >= 0; j--)
1518 AppendImageToList(&image,layer_info[j].image);
1519 }
1520 #endif
1521
1522 layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1523
1524 #if 0 /* BOGUS: do we need the channels?? */
1525 while (MagickTrue)
1526 {
1527 /* read in the offset of the next channel */
1528 info->cp += xcf_read_int32 (info->fp, &offset, 1);
1529
1530 /* if the offset is 0 then we are at the end
1531 * of the channel list.
1532 */
1533 if (offset == 0)
1534 break;
1535
1536 /* save the current position as it is where the
1537 * next channel offset is stored.
1538 */
1539 saved_pos = info->cp;
1540
1541 /* seek to the channel offset */
1542 xcf_seek_pos (info, offset);
1543
1544 /* read in the layer */
1545 channel = xcf_load_channel (info, gimage);
1546 if (channel == 0)
1547 goto error;
1548
1549 num_successful_elements++;
1550
1551 /* add the channel to the image if its not the selection */
1552 if (channel != gimage->selection_mask)
1553 gimp_image_add_channel (gimage, channel, -1);
1554
1555 /* restore the saved position so we'll be ready to
1556 * read the next offset.
1557 */
1558 xcf_seek_pos (info, saved_pos);
1559 }
1560 #endif
1561 }
1562
1563 (void) CloseBlob(image);
1564 if (GetNextImageInList(image) != (Image *) NULL)
1565 DestroyImage(RemoveFirstImageFromList(&image));
1566 if (image_type == GIMP_GRAY)
1567 image->type=GrayscaleType;
1568 return(GetFirstImageInList(image));
1569 }
1570
1571 /*
1572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573 % %
1574 % %
1575 % %
1576 % R e g i s t e r X C F I m a g e %
1577 % %
1578 % %
1579 % %
1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 %
1582 % RegisterXCFImage() adds attributes for the XCF image format to
1583 % the list of supported formats. The attributes include the image format
1584 % tag, a method to read and/or write the format, whether the format
1585 % supports the saving of more than one frame to the same file or blob,
1586 % whether the format supports native in-memory I/O, and a brief
1587 % description of the format.
1588 %
1589 % The format of the RegisterXCFImage method is:
1590 %
1591 % size_t RegisterXCFImage(void)
1592 %
1593 */
RegisterXCFImage(void)1594 ModuleExport size_t RegisterXCFImage(void)
1595 {
1596 MagickInfo
1597 *entry;
1598
1599 entry=AcquireMagickInfo("XCF","XCF","GIMP image");
1600 entry->decoder=(DecodeImageHandler *) ReadXCFImage;
1601 entry->magick=(IsImageFormatHandler *) IsXCF;
1602 entry->flags|=CoderDecoderSeekableStreamFlag;
1603 (void) RegisterMagickInfo(entry);
1604 return(MagickImageCoderSignature);
1605 }
1606
1607 /*
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1609 % %
1610 % %
1611 % %
1612 % U n r e g i s t e r X C F I m a g e %
1613 % %
1614 % %
1615 % %
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 %
1618 % UnregisterXCFImage() removes format registrations made by the
1619 % XCF module from the list of supported formats.
1620 %
1621 % The format of the UnregisterXCFImage method is:
1622 %
1623 % UnregisterXCFImage(void)
1624 %
1625 */
UnregisterXCFImage(void)1626 ModuleExport void UnregisterXCFImage(void)
1627 {
1628 (void) UnregisterMagickInfo("XCF");
1629 }
1630