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-2021 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 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 ssize_t
427 x;
428
429 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 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 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 (EOFBlob(image) != MagickFalse)
720 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
721 image->filename);
722 if (offset == 0)
723 {
724 (void) SetImageBackgroundColor(image,exception);
725 return(MagickTrue);
726 }
727 /*
728 Initialise the reference for the in-memory tile-compression
729 */
730 ntile_rows=(height+TILE_HEIGHT-1)/TILE_HEIGHT;
731 ntile_cols=(width+TILE_WIDTH-1)/TILE_WIDTH;
732 ntiles=ntile_rows*ntile_cols;
733 for (i = 0; i < (ssize_t) ntiles; i++)
734 {
735 status=MagickFalse;
736 if (offset == 0)
737 ThrowBinaryException(CorruptImageError,"NotEnoughTiles",image->filename);
738 /*
739 Save the current position as it is where the next tile offset is stored.
740 */
741 saved_pos=TellBlob(image);
742 /* read in the offset of the next tile so we can calculate the amount
743 of data needed for this tile*/
744 offset2=GetXCFOffset(image,inDocInfo);
745 if ((MagickSizeType) offset2 >= inDocInfo->file_size)
746 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
747 image->filename);
748 /* if the offset is 0 then we need to read in the maximum possible
749 allowing for negative compression */
750 if (offset2 == 0)
751 offset2=(MagickOffsetType) (offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5);
752 /* seek to the tile offset */
753 if ((offset > offset2) || (SeekBlob(image, offset, SEEK_SET) != offset))
754 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
755 image->filename);
756
757 /*
758 Allocate the image for the tile. NOTE: the last tile in a row or
759 column may not be a full tile!
760 */
761 tile_image_width=(size_t) (destLeft == (int) ntile_cols-1 ?
762 (int) width % TILE_WIDTH : TILE_WIDTH);
763 if (tile_image_width == 0)
764 tile_image_width=TILE_WIDTH;
765 tile_image_height = (size_t) (destTop == (int) ntile_rows-1 ?
766 (int) height % TILE_HEIGHT : TILE_HEIGHT);
767 if (tile_image_height == 0)
768 tile_image_height=TILE_HEIGHT;
769 tile_image=CloneImage(inLayerInfo->image,tile_image_width,
770 tile_image_height,MagickTrue,exception);
771 if (tile_image == (Image *) NULL)
772 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
773 image->filename);
774 (void) SetImageBackgroundColor(tile_image,exception);
775
776 /* read in the tile */
777 switch (inDocInfo->compression)
778 {
779 case COMPRESS_NONE:
780 status=load_tile(image,tile_image,inDocInfo,inLayerInfo,(size_t)
781 (offset2-offset),exception);
782 break;
783 case COMPRESS_RLE:
784 status=load_tile_rle(image,tile_image,inDocInfo,inLayerInfo,(size_t)
785 (offset2-offset),exception);
786 break;
787 case COMPRESS_ZLIB:
788 tile_image=DestroyImage(tile_image);
789 ThrowBinaryException(CoderError,"ZipCompressNotSupported",
790 image->filename)
791 case COMPRESS_FRACTAL:
792 tile_image=DestroyImage(tile_image);
793 ThrowBinaryException(CoderError,"FractalCompressNotSupported",
794 image->filename)
795 }
796
797 /* composite the tile onto the layer's image, and then destroy it */
798 if (status != MagickFalse)
799 (void) CompositeImage(inLayerInfo->image,tile_image,CopyCompositeOp,
800 MagickTrue,destLeft * TILE_WIDTH,destTop*TILE_HEIGHT,exception);
801 tile_image=DestroyImage(tile_image);
802
803 if (status == MagickFalse)
804 return(MagickFalse);
805 /* adjust tile position */
806 destLeft++;
807 if (destLeft >= (int) ntile_cols)
808 {
809 destLeft = 0;
810 destTop++;
811 }
812 /* restore the saved position so we'll be ready to
813 * read the next offset.
814 */
815 offset=SeekBlob(image, saved_pos, SEEK_SET);
816 /* read in the offset of the next tile */
817 offset=GetXCFOffset(image,inDocInfo);
818 }
819 if (offset != 0)
820 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename)
821 return(MagickTrue);
822 }
823
load_hierarchy(Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * inLayer,ExceptionInfo * exception)824 static MagickBooleanType load_hierarchy(Image *image,XCFDocInfo *inDocInfo,
825 XCFLayerInfo *inLayer, ExceptionInfo *exception)
826 {
827 MagickOffsetType
828 saved_pos,
829 offset,
830 junk;
831
832 (void) ReadBlobMSBLong(image); /* width */
833 (void) ReadBlobMSBLong(image); /* height */
834 inDocInfo->bytes_per_pixel=ReadBlobMSBLong(image);
835
836 /* load in the levels...we make sure that the number of levels
837 * calculated when the TileManager was created is the same
838 * as the number of levels found in the file.
839 */
840 offset=GetXCFOffset(image,inDocInfo); /* top level */
841 if ((MagickSizeType) offset >= GetBlobSize(image))
842 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
843 image->filename);
844
845 /* discard offsets for layers below first, if any.
846 */
847 do
848 {
849 junk=(MagickOffsetType) ReadBlobMSBLong(image);
850 }
851 while (junk != 0);
852
853 /* save the current position as it is where the
854 * next level offset is stored.
855 */
856 saved_pos=TellBlob(image);
857
858 /* seek to the level offset */
859 if (SeekBlob(image, offset, SEEK_SET) != offset)
860 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
861 image->filename);
862
863 /* read in the level */
864 if (load_level (image, inDocInfo, inLayer, exception) == 0)
865 return(MagickFalse);
866 /* restore the saved position so we'll be ready to
867 * read the next offset.
868 */
869 offset=SeekBlob(image, saved_pos, SEEK_SET);
870 return(MagickTrue);
871 }
872
InitXCFImage(XCFLayerInfo * outLayer,ExceptionInfo * exception)873 static void InitXCFImage(XCFLayerInfo *outLayer,ExceptionInfo *exception)
874 {
875 outLayer->image->page.x=outLayer->offset_x;
876 outLayer->image->page.y=outLayer->offset_y;
877 outLayer->image->page.width=outLayer->width;
878 outLayer->image->page.height=outLayer->height;
879 (void) SetImageProperty(outLayer->image,"label",(char *) outLayer->name,
880 exception);
881 }
882
ReadOneLayer(const ImageInfo * image_info,Image * image,XCFDocInfo * inDocInfo,XCFLayerInfo * outLayer,const ssize_t layer,ExceptionInfo * exception)883 static MagickBooleanType ReadOneLayer(const ImageInfo *image_info,Image* image,
884 XCFDocInfo* inDocInfo,XCFLayerInfo *outLayer,const ssize_t layer,
885 ExceptionInfo *exception)
886 {
887 MagickBooleanType
888 status;
889
890 MagickOffsetType
891 offset;
892
893 unsigned int
894 foundPropEnd = 0;
895
896 MagickOffsetType
897 hierarchy_offset,
898 layer_mask_offset;
899
900 /* clear the block! */
901 (void) memset( outLayer, 0, sizeof( XCFLayerInfo ) );
902 /* read in the layer width, height, type and name */
903 outLayer->width = ReadBlobMSBLong(image);
904 outLayer->height = ReadBlobMSBLong(image);
905 outLayer->type = ReadBlobMSBLong(image);
906 (void) ReadBlobStringWithLongSize(image, outLayer->name,
907 sizeof(outLayer->name),exception);
908 if (EOFBlob(image) != MagickFalse)
909 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
910 image->filename);
911 if ((outLayer->width == 0) || (outLayer->height == 0))
912 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
913 image->filename);
914 /* read the layer properties! */
915 foundPropEnd = 0;
916 while ( (foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse) ) {
917 PropType prop_type = (PropType) ReadBlobMSBLong(image);
918 size_t prop_size = ReadBlobMSBLong(image);
919 switch (prop_type)
920 {
921 case PROP_END:
922 foundPropEnd = 1;
923 break;
924 case PROP_ACTIVE_LAYER:
925 outLayer->active = 1;
926 break;
927 case PROP_FLOATING_SELECTION:
928 outLayer->floating_offset = ReadBlobMSBLong(image);
929 break;
930 case PROP_OPACITY:
931 outLayer->alpha = ReadBlobMSBLong(image);
932 break;
933 case PROP_VISIBLE:
934 outLayer->visible = ReadBlobMSBLong(image);
935 break;
936 case PROP_LINKED:
937 outLayer->linked = ReadBlobMSBLong(image);
938 break;
939 case PROP_PRESERVE_TRANSPARENCY:
940 outLayer->preserve_trans = ReadBlobMSBLong(image);
941 break;
942 case PROP_APPLY_MASK:
943 outLayer->apply_mask = ReadBlobMSBLong(image);
944 break;
945 case PROP_EDIT_MASK:
946 outLayer->edit_mask = ReadBlobMSBLong(image);
947 break;
948 case PROP_SHOW_MASK:
949 outLayer->show_mask = ReadBlobMSBLong(image);
950 break;
951 case PROP_OFFSETS:
952 outLayer->offset_x = ReadBlobMSBSignedLong(image);
953 outLayer->offset_y = ReadBlobMSBSignedLong(image);
954 break;
955 case PROP_MODE:
956 outLayer->mode = ReadBlobMSBLong(image);
957 break;
958 case PROP_TATTOO:
959 outLayer->preserve_trans = ReadBlobMSBLong(image);
960 break;
961 case PROP_PARASITES:
962 {
963 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
964 ThrowFileException(exception,CorruptImageError,
965 "UnexpectedEndOfFile",image->filename);
966
967 /*
968 ssize_t base = info->cp;
969 GimpParasite *p;
970 while (info->cp - base < prop_size)
971 {
972 p = xcf_load_parasite(info);
973 gimp_drawable_parasite_attach(GIMP_DRAWABLE(layer), p);
974 gimp_parasite_free(p);
975 }
976 if (info->cp - base != prop_size)
977 g_message ("Error detected while loading a layer's parasites");
978 */
979 }
980 break;
981 default:
982 /* g_message ("unexpected/unknown layer property: %d (skipping)",
983 prop_type); */
984
985 {
986 int buf[16];
987 ssize_t amount;
988
989 /* read over it... */
990 while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
991 {
992 amount = (ssize_t) MagickMin(16, prop_size);
993 amount = ReadBlob(image, (size_t) amount, (unsigned char *) &buf);
994 if (!amount)
995 ThrowBinaryException(CorruptImageError,"CorruptImage",
996 image->filename);
997 prop_size -= (size_t) MagickMin(16, (size_t) amount);
998 }
999 }
1000 break;
1001 }
1002 }
1003 if (EOFBlob(image) != MagickFalse)
1004 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1005 image->filename);
1006 if (foundPropEnd == MagickFalse)
1007 return(MagickFalse);
1008 /* allocate the image for this layer */
1009 if (image_info->number_scenes != 0)
1010 {
1011 ssize_t
1012 scene;
1013
1014 scene=inDocInfo->number_layers-layer-1;
1015 if (scene > (ssize_t) (image_info->scene+image_info->number_scenes-1))
1016 {
1017 outLayer->image=CloneImage(image,0,0,MagickTrue,exception);
1018 if (outLayer->image == (Image *) NULL)
1019 return(MagickFalse);
1020 InitXCFImage(outLayer,exception);
1021 return(MagickTrue);
1022 }
1023 }
1024 outLayer->image=CloneImage(image,outLayer->width, outLayer->height,MagickTrue,
1025 exception);
1026 if (outLayer->image == (Image *) NULL)
1027 return(MagickFalse);
1028 outLayer->width=outLayer->image->columns;
1029 status=SetImageExtent(outLayer->image,outLayer->image->columns,
1030 outLayer->image->rows,exception);
1031 if (status != MagickFalse)
1032 status=ResetImagePixels(outLayer->image,exception);
1033 if (status == MagickFalse)
1034 {
1035 outLayer->image=DestroyImageList(outLayer->image);
1036 return(MagickFalse);
1037 }
1038 /* clear the image based on the layer opacity */
1039 outLayer->image->background_color.alpha=
1040 ScaleCharToQuantum((unsigned char) outLayer->alpha);
1041 if (outLayer->alpha != 255U)
1042 {
1043 outLayer->image->background_color.alpha_trait=BlendPixelTrait;
1044 outLayer->image->alpha_trait=BlendPixelTrait;
1045 (void) SetImageBackgroundColor(outLayer->image,exception);
1046 }
1047
1048 InitXCFImage(outLayer,exception);
1049
1050 /* set the compositing mode */
1051 outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode );
1052 if ( outLayer->visible == MagickFalse )
1053 {
1054 /* BOGUS: should really be separate member var! */
1055 outLayer->image->compose = NoCompositeOp;
1056 }
1057
1058 /* read the hierarchy and layer mask offsets */
1059 hierarchy_offset = GetXCFOffset(image,inDocInfo);
1060 layer_mask_offset = GetXCFOffset(image,inDocInfo);
1061
1062 /* read in the hierarchy */
1063 offset=SeekBlob(image, hierarchy_offset, SEEK_SET);
1064 if (offset != hierarchy_offset)
1065 ThrowBinaryException(CorruptImageError,"InvalidImageHeader",
1066 image->filename);
1067 if (load_hierarchy (image, inDocInfo, outLayer, exception) == 0)
1068 return(MagickFalse);
1069
1070 /* read in the layer mask */
1071 if (layer_mask_offset != 0)
1072 {
1073 offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET);
1074
1075 #if 0 /* BOGUS: support layer masks! */
1076 layer_mask = xcf_load_layer_mask (info, gimage);
1077 if (layer_mask == 0)
1078 goto error;
1079
1080 /* set the offsets of the layer_mask */
1081 GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
1082 GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
1083
1084 gimp_layer_add_mask (layer, layer_mask, MagickFalse);
1085
1086 layer->mask->apply_mask = apply_mask;
1087 layer->mask->edit_mask = edit_mask;
1088 layer->mask->show_mask = show_mask;
1089 #endif
1090 }
1091
1092 /* attach the floating selection... */
1093 #if 0 /* BOGUS: we may need to read this, even if we don't support it! */
1094 if (add_floating_sel)
1095 {
1096 GimpLayer *floating_sel;
1097
1098 floating_sel = info->floating_sel;
1099 floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
1100 }
1101 #endif
1102
1103 return MagickTrue;
1104 }
1105
1106 /*
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 % %
1109 % %
1110 % %
1111 % R e a d X C F I m a g e %
1112 % %
1113 % %
1114 % %
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 %
1117 % ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image
1118 % file and returns it. It allocates the memory necessary for the new Image
1119 % structure and returns a pointer to the new image.
1120 %
1121 % The format of the ReadXCFImage method is:
1122 %
1123 % image=ReadXCFImage(image_info)
1124 %
1125 % A description of each parameter follows:
1126 %
1127 % o image_info: the image info.
1128 %
1129 % o exception: return any errors or warnings in this structure.
1130 %
1131 */
ReadXCFImage(const ImageInfo * image_info,ExceptionInfo * exception)1132 static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception)
1133 {
1134 char
1135 magick[14];
1136
1137 Image
1138 *image;
1139
1140 int
1141 foundPropEnd = 0;
1142
1143 MagickBooleanType
1144 status;
1145
1146 MagickOffsetType
1147 offset;
1148
1149 ssize_t
1150 i;
1151
1152 size_t
1153 image_type,
1154 precision,
1155 length;
1156
1157 ssize_t
1158 count;
1159
1160 XCFDocInfo
1161 doc_info;
1162
1163 /*
1164 Open image file.
1165 */
1166 assert(image_info != (const ImageInfo *) NULL);
1167 assert(image_info->signature == MagickCoreSignature);
1168 if (image_info->debug != MagickFalse)
1169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1170 image_info->filename);
1171 assert(exception != (ExceptionInfo *) NULL);
1172 assert(exception->signature == MagickCoreSignature);
1173 image=AcquireImage(image_info,exception);
1174 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1175 if (status == MagickFalse)
1176 {
1177 image=DestroyImageList(image);
1178 return((Image *) NULL);
1179 }
1180 count=ReadBlob(image,sizeof(magick),(unsigned char *) magick);
1181 if ((count != sizeof(magick)) ||
1182 (LocaleNCompare((char *) magick,"gimp xcf",8) != 0))
1183 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1184 (void) memset(&doc_info,0,sizeof(XCFDocInfo));
1185 doc_info.version=StringToUnsignedLong(magick+10);
1186 doc_info.width=ReadBlobMSBLong(image);
1187 doc_info.height=ReadBlobMSBLong(image);
1188 if ((doc_info.width > 262144) || (doc_info.height > 262144))
1189 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1190 doc_info.image_type=ReadBlobMSBLong(image);
1191 precision=150;
1192 if (doc_info.version >= 4)
1193 {
1194 precision=ReadBlobMSBLong(image);
1195 if (precision == 0)
1196 precision=150;
1197 if (precision != 150)
1198 ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
1199 }
1200 /*
1201 Initialize image attributes.
1202 */
1203 image->columns=doc_info.width;
1204 image->rows=doc_info.height;
1205 image_type=doc_info.image_type;
1206 doc_info.file_size=GetBlobSize(image);
1207 image->compression=NoCompression;
1208 image->depth=8;
1209 status=SetImageExtent(image,image->columns,image->rows,exception);
1210 if (status == MagickFalse)
1211 return(DestroyImageList(image));
1212 if (status != MagickFalse)
1213 status=ResetImagePixels(image,exception);
1214 if (image_type == GIMP_INDEXED)
1215 ThrowReaderException(CoderError,"ColormapTypeNotSupported");
1216 if (image_type == GIMP_RGB)
1217 SetImageColorspace(image,sRGBColorspace,exception);
1218 else if (image_type == GIMP_GRAY)
1219 SetImageColorspace(image,GRAYColorspace,exception);
1220 else
1221 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1222 (void) SetImageBackgroundColor(image,exception);
1223 (void) SetImageAlpha(image,OpaqueAlpha,exception);
1224 /*
1225 Read properties.
1226 */
1227 while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse))
1228 {
1229 PropType prop_type = (PropType) ReadBlobMSBLong(image);
1230 size_t prop_size = ReadBlobMSBLong(image);
1231
1232 switch (prop_type)
1233 {
1234 case PROP_END:
1235 foundPropEnd=1;
1236 break;
1237 case PROP_COLORMAP:
1238 {
1239 /* Cannot rely on prop_size here--the value is set incorrectly
1240 by some Gimp versions.
1241 */
1242 size_t num_colors = ReadBlobMSBLong(image);
1243 if (DiscardBlobBytes(image,3*num_colors) == MagickFalse)
1244 ThrowFileException(exception,CorruptImageError,
1245 "UnexpectedEndOfFile",image->filename);
1246 /*
1247 if (info->file_version == 0)
1248 {
1249 gint i;
1250
1251 g_message (_("XCF warning: version 0 of XCF file format\n"
1252 "did not save indexed colormaps correctly.\n"
1253 "Substituting grayscale map."));
1254 info->cp +=
1255 xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1256 gimage->cmap = g_new (guchar, gimage->num_cols*3);
1257 xcf_seek_pos (info, info->cp + gimage->num_cols);
1258 for (i = 0; i<gimage->num_cols; i++)
1259 {
1260 gimage->cmap[i*3+0] = i;
1261 gimage->cmap[i*3+1] = i;
1262 gimage->cmap[i*3+2] = i;
1263 }
1264 }
1265 else
1266 {
1267 info->cp +=
1268 xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1269 gimage->cmap = g_new (guchar, gimage->num_cols*3);
1270 info->cp +=
1271 xcf_read_int8 (info->fp,
1272 (guint8*) gimage->cmap, gimage->num_cols*3);
1273 }
1274 */
1275 break;
1276 }
1277 case PROP_COMPRESSION:
1278 {
1279 doc_info.compression = ReadBlobByte(image);
1280 if ((doc_info.compression != COMPRESS_NONE) &&
1281 (doc_info.compression != COMPRESS_RLE) &&
1282 (doc_info.compression != COMPRESS_ZLIB) &&
1283 (doc_info.compression != COMPRESS_FRACTAL))
1284 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
1285 }
1286 break;
1287
1288 case PROP_GUIDES:
1289 {
1290 /* just skip it - we don't care about guides */
1291 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1292 ThrowFileException(exception,CorruptImageError,
1293 "UnexpectedEndOfFile",image->filename);
1294 }
1295 break;
1296
1297 case PROP_RESOLUTION:
1298 {
1299 /* float xres = (float) */ (void) ReadBlobMSBLong(image);
1300 /* float yres = (float) */ (void) ReadBlobMSBLong(image);
1301
1302 /*
1303 if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
1304 yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
1305 {
1306 g_message ("Warning, resolution out of range in XCF file");
1307 xres = gimage->gimp->config->default_xresolution;
1308 yres = gimage->gimp->config->default_yresolution;
1309 }
1310 */
1311
1312
1313 /* BOGUS: we don't write these yet because we aren't
1314 reading them properly yet :(
1315 image->resolution.x = xres;
1316 image->resolution.y = yres;
1317 */
1318 }
1319 break;
1320
1321 case PROP_TATTOO:
1322 {
1323 /* we need to read it, even if we ignore it */
1324 /*size_t tattoo_state = */ (void) ReadBlobMSBLong(image);
1325 }
1326 break;
1327
1328 case PROP_PARASITES:
1329 {
1330 /* BOGUS: we may need these for IPTC stuff */
1331 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1332 ThrowFileException(exception,CorruptImageError,
1333 "UnexpectedEndOfFile",image->filename);
1334 /*
1335 gssize_t base = info->cp;
1336 GimpParasite *p;
1337
1338 while (info->cp - base < prop_size)
1339 {
1340 p = xcf_load_parasite (info);
1341 gimp_image_parasite_attach (gimage, p);
1342 gimp_parasite_free (p);
1343 }
1344 if (info->cp - base != prop_size)
1345 g_message ("Error detected while loading an image's parasites");
1346 */
1347 }
1348 break;
1349
1350 case PROP_UNIT:
1351 {
1352 /* BOGUS: ignore for now... */
1353 /*size_t unit = */ (void) ReadBlobMSBLong(image);
1354 }
1355 break;
1356
1357 case PROP_PATHS:
1358 {
1359 /* BOGUS: just skip it for now */
1360 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1361 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1362 image->filename);
1363
1364 /*
1365 PathList *paths = xcf_load_bzpaths (gimage, info);
1366 gimp_image_set_paths (gimage, paths);
1367 */
1368 }
1369 break;
1370
1371 case PROP_USER_UNIT:
1372 {
1373 char unit_string[1000];
1374 /*BOGUS: ignored for now */
1375 /*float factor = (float) */ (void) ReadBlobMSBLong(image);
1376 /* size_t digits = */ (void) ReadBlobMSBLong(image);
1377 for (i=0; i<5; i++)
1378 (void) ReadBlobStringWithLongSize(image, unit_string,
1379 sizeof(unit_string),exception);
1380 }
1381 break;
1382
1383 default:
1384 {
1385 int buf[16];
1386 ssize_t amount;
1387
1388 /* read over it... */
1389 while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
1390 {
1391 amount=(ssize_t) MagickMin(16, prop_size);
1392 amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf);
1393 if (!amount)
1394 ThrowReaderException(CorruptImageError,"CorruptImage");
1395 prop_size -= (size_t) MagickMin(16,(size_t) amount);
1396 }
1397 }
1398 break;
1399 }
1400 }
1401 if (foundPropEnd == MagickFalse)
1402 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1403
1404 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1405 {
1406 ; /* do nothing, were just pinging! */
1407 }
1408 else
1409 {
1410 int
1411 current_layer = 0,
1412 foundAllLayers = MagickFalse,
1413 number_layers = 0;
1414
1415 MagickOffsetType
1416 oldPos=TellBlob(image);
1417
1418 XCFLayerInfo
1419 *layer_info;
1420
1421 /*
1422 The read pointer.
1423 */
1424 do
1425 {
1426 offset=GetXCFOffset(image,&doc_info);
1427 if (offset == 0)
1428 foundAllLayers=MagickTrue;
1429 else
1430 number_layers++;
1431 if (EOFBlob(image) != MagickFalse)
1432 {
1433 ThrowFileException(exception,CorruptImageError,
1434 "UnexpectedEndOfFile",image->filename);
1435 break;
1436 }
1437 } while (foundAllLayers == MagickFalse);
1438 if (AcquireMagickResource(ListLengthResource,number_layers) == MagickFalse)
1439 ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1440 doc_info.number_layers=number_layers;
1441 offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */
1442 if (offset < 0)
1443 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1444 /* allocate our array of layer info blocks */
1445 length=(size_t) number_layers;
1446 layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length,
1447 sizeof(*layer_info));
1448 if (layer_info == (XCFLayerInfo *) NULL)
1449 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1450 (void) memset(layer_info,0,number_layers*sizeof(XCFLayerInfo));
1451 for ( ; ; )
1452 {
1453 MagickBooleanType
1454 layer_ok;
1455
1456 MagickOffsetType
1457 saved_pos;
1458
1459 /* read in the offset of the next layer */
1460 offset=GetXCFOffset(image,&doc_info);
1461 /* if the offset is 0 then we are at the end
1462 * of the layer list.
1463 */
1464 if (offset == 0)
1465 break;
1466 /* save the current position as it is where the
1467 * next layer offset is stored.
1468 */
1469 saved_pos=TellBlob(image);
1470 /* seek to the layer offset */
1471 layer_ok=MagickFalse;
1472 if (SeekBlob(image,offset,SEEK_SET) == offset)
1473 {
1474 /* read in the layer */
1475 layer_ok=ReadOneLayer(image_info,image,&doc_info,
1476 &layer_info[current_layer],current_layer,exception);
1477 }
1478 if (layer_ok == MagickFalse)
1479 {
1480 ssize_t j;
1481
1482 for (j=0; j <= current_layer; j++)
1483 if (layer_info[j].image != (Image *) NULL)
1484 layer_info[j].image=DestroyImage(layer_info[j].image);
1485 layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1486 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1487 }
1488 /* restore the saved position so we'll be ready to
1489 * read the next offset.
1490 */
1491 offset=SeekBlob(image, saved_pos, SEEK_SET);
1492 current_layer++;
1493 }
1494 #if 0
1495 {
1496 /* NOTE: XCF layers are REVERSED from composite order! */
1497 signed int j;
1498 for (j=number_layers-1; j>=0; j--) {
1499 /* BOGUS: need to consider layer blending modes!! */
1500
1501 if ( layer_info[j].visible ) { /* only visible ones, please! */
1502 CompositeImage(image, OverCompositeOp, layer_info[j].image,
1503 layer_info[j].offset_x, layer_info[j].offset_y );
1504 layer_info[j].image =DestroyImage( layer_info[j].image );
1505
1506 /* If we do this, we'll get REAL gray images! */
1507 if ( image_type == GIMP_GRAY ) {
1508 QuantizeInfo qi;
1509 GetQuantizeInfo(&qi);
1510 qi.colorspace = GRAYColorspace;
1511 QuantizeImage( &qi, layer_info[j].image );
1512 }
1513 }
1514 }
1515 }
1516 #else
1517 {
1518 /* NOTE: XCF layers are REVERSED from composite order! */
1519 ssize_t j;
1520
1521 /* now reverse the order of the layers as they are put
1522 into subimages
1523 */
1524 for (j=(ssize_t) number_layers-1; j >= 0; j--)
1525 AppendImageToList(&image,layer_info[j].image);
1526 }
1527 #endif
1528
1529 layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1530
1531 #if 0 /* BOGUS: do we need the channels?? */
1532 while (MagickTrue)
1533 {
1534 /* read in the offset of the next channel */
1535 info->cp += xcf_read_int32 (info->fp, &offset, 1);
1536
1537 /* if the offset is 0 then we are at the end
1538 * of the channel list.
1539 */
1540 if (offset == 0)
1541 break;
1542
1543 /* save the current position as it is where the
1544 * next channel offset is stored.
1545 */
1546 saved_pos = info->cp;
1547
1548 /* seek to the channel offset */
1549 xcf_seek_pos (info, offset);
1550
1551 /* read in the layer */
1552 channel = xcf_load_channel (info, gimage);
1553 if (channel == 0)
1554 goto error;
1555
1556 num_successful_elements++;
1557
1558 /* add the channel to the image if its not the selection */
1559 if (channel != gimage->selection_mask)
1560 gimp_image_add_channel (gimage, channel, -1);
1561
1562 /* restore the saved position so we'll be ready to
1563 * read the next offset.
1564 */
1565 xcf_seek_pos (info, saved_pos);
1566 }
1567 #endif
1568 }
1569
1570 (void) CloseBlob(image);
1571 if (GetNextImageInList(image) != (Image *) NULL)
1572 DestroyImage(RemoveFirstImageFromList(&image));
1573 if (image_type == GIMP_GRAY)
1574 image->type=GrayscaleType;
1575 return(GetFirstImageInList(image));
1576 }
1577
1578 /*
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580 % %
1581 % %
1582 % %
1583 % R e g i s t e r X C F I m a g e %
1584 % %
1585 % %
1586 % %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 %
1589 % RegisterXCFImage() adds attributes for the XCF image format to
1590 % the list of supported formats. The attributes include the image format
1591 % tag, a method to read and/or write the format, whether the format
1592 % supports the saving of more than one frame to the same file or blob,
1593 % whether the format supports native in-memory I/O, and a brief
1594 % description of the format.
1595 %
1596 % The format of the RegisterXCFImage method is:
1597 %
1598 % size_t RegisterXCFImage(void)
1599 %
1600 */
RegisterXCFImage(void)1601 ModuleExport size_t RegisterXCFImage(void)
1602 {
1603 MagickInfo
1604 *entry;
1605
1606 entry=AcquireMagickInfo("XCF","XCF","GIMP image");
1607 entry->decoder=(DecodeImageHandler *) ReadXCFImage;
1608 entry->magick=(IsImageFormatHandler *) IsXCF;
1609 entry->flags|=CoderDecoderSeekableStreamFlag;
1610 (void) RegisterMagickInfo(entry);
1611 return(MagickImageCoderSignature);
1612 }
1613
1614 /*
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616 % %
1617 % %
1618 % %
1619 % U n r e g i s t e r X C F I m a g e %
1620 % %
1621 % %
1622 % %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624 %
1625 % UnregisterXCFImage() removes format registrations made by the
1626 % XCF module from the list of supported formats.
1627 %
1628 % The format of the UnregisterXCFImage method is:
1629 %
1630 % UnregisterXCFImage(void)
1631 %
1632 */
UnregisterXCFImage(void)1633 ModuleExport void UnregisterXCFImage(void)
1634 {
1635 (void) UnregisterMagickInfo("XCF");
1636 }
1637