2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read GIMP XCF Image Format %
20 % Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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/module.h"
79 PROP_ACTIVE_LAYER = 2,
80 PROP_ACTIVE_CHANNEL = 3,
82 PROP_FLOATING_SELECTION = 5,
87 PROP_PRESERVE_TRANSPARENCY = 10,
91 PROP_SHOW_MASKED = 14,
94 PROP_COMPRESSION = 17,
108 COMPRESS_ZLIB = 2, /* unused */
109 COMPRESS_FRACTAL = 3 /* unused */
110 } XcfCompressionType;
163 #define TILE_WIDTH 64
164 #define TILE_HEIGHT 64
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 % IsXCF() returns MagickTrue if the image format type, identified by the
187 % magick string, is XCF (GIMP native format).
189 % The format of the IsXCF method is:
191 % MagickBooleanType IsXCF(const unsigned char *magick,const size_t length)
193 % A description of each parameter follows:
195 % o magick: compare image format pattern against these bytes.
197 % o length: Specifies the length of the magick string.
201 static MagickBooleanType IsXCF(const unsigned char *magick,const size_t length)
205 if (LocaleNCompare((char *) magick,"gimp xcf",8) == 0)
218 GIMP_DIFFERENCE_MODE,
221 GIMP_DARKEN_ONLY_MODE,
222 GIMP_LIGHTEN_ONLY_MODE,
224 GIMP_SATURATION_MODE,
231 } GimpLayerModeEffects;
234 Simple utility routine to convert between PSD blending modes and
235 ImageMagick compositing operators
237 static CompositeOperator GIMPBlendModeToCompositeOperator(
242 case GIMP_NORMAL_MODE: return(OverCompositeOp);
243 case GIMP_DISSOLVE_MODE: return(DissolveCompositeOp);
244 case GIMP_MULTIPLY_MODE: return(MultiplyCompositeOp);
245 case GIMP_SCREEN_MODE: return(ScreenCompositeOp);
246 case GIMP_OVERLAY_MODE: return(OverlayCompositeOp);
247 case GIMP_DIFFERENCE_MODE: return(DifferenceCompositeOp);
248 case GIMP_ADDITION_MODE: return(ModulusAddCompositeOp);
249 case GIMP_SUBTRACT_MODE: return(ModulusSubtractCompositeOp);
250 case GIMP_DARKEN_ONLY_MODE: return(DarkenCompositeOp);
251 case GIMP_LIGHTEN_ONLY_MODE: return(LightenCompositeOp);
252 case GIMP_HUE_MODE: return(HueCompositeOp);
253 case GIMP_SATURATION_MODE: return(SaturateCompositeOp);
254 case GIMP_COLOR_MODE: return(ColorizeCompositeOp);
255 case GIMP_DODGE_MODE: return(ColorDodgeCompositeOp);
256 case GIMP_BURN_MODE: return(ColorBurnCompositeOp);
257 case GIMP_HARDLIGHT_MODE: return(HardLightCompositeOp);
258 case GIMP_DIVIDE_MODE: return(DivideDstCompositeOp);
259 /* these are the ones we don't support...yet */
260 case GIMP_BEHIND_MODE: return(OverCompositeOp);
261 case GIMP_VALUE_MODE: return(OverCompositeOp);
262 default: return(OverCompositeOp);
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271 + 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 %
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 % ReadBlobStringWithLongSize reads characters from a blob or file
278 % starting with a ssize_t length byte and then characters to that length
280 % The format of the ReadBlobStringWithLongSize method is:
282 % char *ReadBlobStringWithLongSize(Image *image,char *string,
283 % ExceptionInfo *exception)
285 % A description of each parameter follows:
287 % o image: the image.
289 % o string: the address of a character buffer.
291 % o exception: return any errors or warnings in this structure.
295 static char *ReadBlobStringWithLongSize(Image *image,char *string,size_t max,
296 ExceptionInfo *exception)
310 assert(image != (Image *) NULL);
311 assert(image->signature == MagickCoreSignature);
313 if (image->debug != MagickFalse)
314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
315 length=ReadBlobMSBLong(image);
316 for (i=0; i < (ssize_t) MagickMin(length,max-1); i++)
318 c=ReadBlobByte(image);
320 return((char *) NULL);
324 offset=SeekBlob(image,(MagickOffsetType) (length-i),SEEK_CUR);
326 (void) ThrowMagickException(exception,GetMagickModule(),
327 CorruptImageError,"ImproperImageHeader","`%s'",image->filename);
331 static MagickBooleanType load_tile(Image *image,Image *tile_image,
332 XCFDocInfo *inDocInfo,XCFLayerInfo *inLayerInfo,size_t data_length,
333 ExceptionInfo *exception)
358 if (inDocInfo->image_type == GIMP_GRAY)
359 extent=tile_image->columns*tile_image->rows*sizeof(*graydata);
361 if (inDocInfo->image_type == GIMP_RGB)
362 extent=tile_image->columns*tile_image->rows*sizeof(*xcfdata);
363 if (extent > data_length)
364 ThrowBinaryException(CorruptImageError,"NotEnoughPixelData",
366 xcfdata=(XCFPixelInfo *) AcquireQuantumMemory(MagickMax(data_length,
367 tile_image->columns*tile_image->rows),sizeof(*xcfdata));
368 if (xcfdata == (XCFPixelInfo *) NULL)
369 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
372 graydata=(unsigned char *) xcfdata; /* used by gray and indexed */
373 count=ReadBlob(image,data_length,(unsigned char *) xcfdata);
374 if (count != (ssize_t) data_length)
376 xcfodata=(XCFPixelInfo *) RelinquishMagickMemory(xcfodata);
377 ThrowBinaryException(CorruptImageError,"NotEnoughPixelData",
380 for (y=0; y < (ssize_t) tile_image->rows; y++)
382 q=GetAuthenticPixels(tile_image,0,y,tile_image->columns,1,exception);
383 if (q == (Quantum *) NULL)
385 if (inDocInfo->image_type == GIMP_GRAY)
387 for (x=0; x < (ssize_t) tile_image->columns; x++)
389 SetPixelGray(tile_image,ScaleCharToQuantum(*graydata),q);
390 SetPixelAlpha(tile_image,ScaleCharToQuantum((unsigned char)
391 inLayerInfo->alpha),q);
393 q+=GetPixelChannels(tile_image);
397 if (inDocInfo->image_type == GIMP_RGB)
399 for (x=0; x < (ssize_t) tile_image->columns; x++)
401 SetPixelRed(tile_image,ScaleCharToQuantum(xcfdata->red),q);
402 SetPixelGreen(tile_image,ScaleCharToQuantum(xcfdata->green),q);
403 SetPixelBlue(tile_image,ScaleCharToQuantum(xcfdata->blue),q);
404 SetPixelAlpha(tile_image,xcfdata->alpha == 255U ? TransparentAlpha :
405 ScaleCharToQuantum((unsigned char) inLayerInfo->alpha),q);
407 q+=GetPixelChannels(tile_image);
410 if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
413 xcfodata=(XCFPixelInfo *) RelinquishMagickMemory(xcfodata);
417 static MagickBooleanType load_tile_rle(Image *image,Image *tile_image,
418 XCFDocInfo *inDocInfo,XCFLayerInfo *inLayerInfo,size_t data_length,
419 ExceptionInfo *exception)
446 bytes_per_pixel=(ssize_t) inDocInfo->bytes_per_pixel;
447 xcfdata=(unsigned char *) AcquireQuantumMemory(data_length,sizeof(*xcfdata));
448 if (xcfdata == (unsigned char *) NULL)
449 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
452 count=ReadBlob(image, (size_t) data_length, xcfdata);
453 xcfdatalimit = xcfodata+count-1;
454 alpha=ScaleCharToQuantum((unsigned char) inLayerInfo->alpha);
455 for (i=0; i < bytes_per_pixel; i++)
457 q=GetAuthenticPixels(tile_image,0,0,tile_image->columns,tile_image->rows,
459 if (q == (Quantum *) NULL)
461 size=(MagickOffsetType) tile_image->rows*tile_image->columns;
464 if (xcfdata > xcfdatalimit)
467 length=(size_t) pixel;
470 length=255-(length-1);
473 if (xcfdata >= xcfdatalimit)
475 length=(size_t) ((*xcfdata << 8) + xcfdata[1]);
481 if (&xcfdata[length-1] > xcfdatalimit)
485 data=ScaleCharToQuantum(*xcfdata++);
490 if (inDocInfo->image_type == GIMP_GRAY)
491 SetPixelGray(tile_image,data,q);
494 SetPixelRed(tile_image,data,q);
495 SetPixelGreen(tile_image,data,q);
496 SetPixelBlue(tile_image,data,q);
498 SetPixelAlpha(tile_image,alpha,q);
503 if (inDocInfo->image_type == GIMP_GRAY)
504 SetPixelAlpha(tile_image,data,q);
506 SetPixelGreen(tile_image,data,q);
511 SetPixelBlue(tile_image,data,q);
516 SetPixelAlpha(tile_image,data,q);
520 q+=GetPixelChannels(tile_image);
528 if (xcfdata >= xcfdatalimit)
530 length=(size_t) ((*xcfdata << 8) + xcfdata[1]);
536 if (xcfdata > xcfdatalimit)
539 for (j=0; j < (ssize_t) length; j++)
541 data=ScaleCharToQuantum(pixel);
546 if (inDocInfo->image_type == GIMP_GRAY)
547 SetPixelGray(tile_image,data,q);
550 SetPixelRed(tile_image,data,q);
551 SetPixelGreen(tile_image,data,q);
552 SetPixelBlue(tile_image,data,q);
554 SetPixelAlpha(tile_image,alpha,q);
559 if (inDocInfo->image_type == GIMP_GRAY)
560 SetPixelAlpha(tile_image,data,q);
562 SetPixelGreen(tile_image,data,q);
567 SetPixelBlue(tile_image,data,q);
572 SetPixelAlpha(tile_image,data,q);
576 q+=GetPixelChannels(tile_image);
580 if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
583 xcfodata=(unsigned char *) RelinquishMagickMemory(xcfodata);
587 if (xcfodata != (unsigned char *) NULL)
588 xcfodata=(unsigned char *) RelinquishMagickMemory(xcfodata);
592 static MagickBooleanType load_level(Image *image,XCFDocInfo *inDocInfo,
593 XCFLayerInfo *inLayerInfo,ExceptionInfo *exception)
622 /* start reading the data */
623 width=ReadBlobMSBLong(image);
624 height=ReadBlobMSBLong(image);
627 Read in the first tile offset. If it is '0', then this tile level is empty
628 and we can simply return.
630 offset=(MagickOffsetType) ReadBlobMSBLong(image);
634 Initialise the reference for the in-memory tile-compression
636 ntile_rows=(height+TILE_HEIGHT-1)/TILE_HEIGHT;
637 ntile_cols=(width+TILE_WIDTH-1)/TILE_WIDTH;
638 ntiles=ntile_rows*ntile_cols;
639 for (i = 0; i < (ssize_t) ntiles; i++)
643 ThrowBinaryException(CorruptImageError,"NotEnoughTiles",image->filename);
645 Save the current position as it is where the next tile offset is stored.
647 saved_pos=TellBlob(image);
648 /* read in the offset of the next tile so we can calculate the amount
649 of data needed for this tile*/
650 offset2=(MagickOffsetType) ReadBlobMSBLong(image);
651 if ((MagickSizeType) offset2 >= inDocInfo->file_size)
652 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
654 /* if the offset is 0 then we need to read in the maximum possible
655 allowing for negative compression */
657 offset2=(MagickOffsetType) (offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5);
658 /* seek to the tile offset */
659 if (SeekBlob(image, offset, SEEK_SET) != offset)
660 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
664 Allocate the image for the tile. NOTE: the last tile in a row or
665 column may not be a full tile!
667 tile_image_width=(size_t) (destLeft == (int) ntile_cols-1 ?
668 (int) width % TILE_WIDTH : TILE_WIDTH);
669 if (tile_image_width == 0)
670 tile_image_width=TILE_WIDTH;
671 tile_image_height = (size_t) (destTop == (int) ntile_rows-1 ?
672 (int) height % TILE_HEIGHT : TILE_HEIGHT);
673 if (tile_image_height == 0)
674 tile_image_height=TILE_HEIGHT;
675 tile_image=CloneImage(inLayerInfo->image,tile_image_width,
676 tile_image_height,MagickTrue,exception);
677 if (tile_image == (Image *) NULL)
678 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
680 (void) SetImageBackgroundColor(tile_image,exception);
682 /* read in the tile */
683 switch (inDocInfo->compression)
686 status=load_tile(image,tile_image,inDocInfo,inLayerInfo,(size_t)
687 (offset2-offset),exception);
690 status=load_tile_rle(image,tile_image,inDocInfo,inLayerInfo,(size_t)
691 (offset2-offset),exception);
694 tile_image=DestroyImage(tile_image);
695 ThrowBinaryException(CoderError,"ZipCompressNotSupported",
697 case COMPRESS_FRACTAL:
698 tile_image=DestroyImage(tile_image);
699 ThrowBinaryException(CoderError,"FractalCompressNotSupported",
703 /* composite the tile onto the layer's image, and then destroy it */
704 if (status != MagickFalse)
705 (void) CompositeImage(inLayerInfo->image,tile_image,CopyCompositeOp,
706 MagickTrue,destLeft * TILE_WIDTH,destTop*TILE_HEIGHT,exception);
707 tile_image=DestroyImage(tile_image);
709 if (status == MagickFalse)
711 /* adjust tile position */
713 if (destLeft >= (int) ntile_cols)
718 /* restore the saved position so we'll be ready to
719 * read the next offset.
721 offset=SeekBlob(image, saved_pos, SEEK_SET);
722 /* read in the offset of the next tile */
723 offset=(MagickOffsetType) ReadBlobMSBLong(image);
726 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename)
730 static MagickBooleanType load_hierarchy(Image *image,XCFDocInfo *inDocInfo,
731 XCFLayerInfo *inLayer, ExceptionInfo *exception)
738 (void) ReadBlobMSBLong(image); /* width */
739 (void) ReadBlobMSBLong(image); /* height */
740 inDocInfo->bytes_per_pixel=ReadBlobMSBLong(image);
742 /* load in the levels...we make sure that the number of levels
743 * calculated when the TileManager was created is the same
744 * as the number of levels found in the file.
746 offset=(MagickOffsetType) ReadBlobMSBLong(image); /* top level */
747 if ((MagickSizeType) offset >= GetBlobSize(image))
748 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
751 /* discard offsets for layers below first, if any.
755 junk=(MagickOffsetType) ReadBlobMSBLong(image);
759 /* save the current position as it is where the
760 * next level offset is stored.
762 saved_pos=TellBlob(image);
764 /* seek to the level offset */
765 if (SeekBlob(image, offset, SEEK_SET) != offset)
766 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
769 /* read in the level */
770 if (load_level (image, inDocInfo, inLayer, exception) == 0)
772 /* restore the saved position so we'll be ready to
773 * read the next offset.
775 offset=SeekBlob(image, saved_pos, SEEK_SET);
779 static void InitXCFImage(XCFLayerInfo *outLayer,ExceptionInfo *exception)
781 outLayer->image->page.x=outLayer->offset_x;
782 outLayer->image->page.y=outLayer->offset_y;
783 outLayer->image->page.width=outLayer->width;
784 outLayer->image->page.height=outLayer->height;
785 (void) SetImageProperty(outLayer->image,"label",(char *)outLayer->name,
789 static MagickBooleanType ReadOneLayer(const ImageInfo *image_info,Image* image,
790 XCFDocInfo* inDocInfo,XCFLayerInfo *outLayer,const ssize_t layer,
791 ExceptionInfo *exception)
806 /* clear the block! */
807 (void) memset( outLayer, 0, sizeof( XCFLayerInfo ) );
808 /* read in the layer width, height, type and name */
809 outLayer->width = ReadBlobMSBLong(image);
810 outLayer->height = ReadBlobMSBLong(image);
811 outLayer->type = ReadBlobMSBLong(image);
812 (void) ReadBlobStringWithLongSize(image, outLayer->name,
813 sizeof(outLayer->name),exception);
814 if (EOFBlob(image) != MagickFalse)
815 ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
817 if ((outLayer->width == 0) || (outLayer->height == 0))
818 ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
820 /* read the layer properties! */
822 while ( (foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse) ) {
823 PropType prop_type = (PropType) ReadBlobMSBLong(image);
824 size_t prop_size = ReadBlobMSBLong(image);
830 case PROP_ACTIVE_LAYER:
831 outLayer->active = 1;
833 case PROP_FLOATING_SELECTION:
834 outLayer->floating_offset = ReadBlobMSBLong(image);
837 outLayer->alpha = ReadBlobMSBLong(image);
840 outLayer->visible = ReadBlobMSBLong(image);
843 outLayer->linked = ReadBlobMSBLong(image);
845 case PROP_PRESERVE_TRANSPARENCY:
846 outLayer->preserve_trans = ReadBlobMSBLong(image);
848 case PROP_APPLY_MASK:
849 outLayer->apply_mask = ReadBlobMSBLong(image);
852 outLayer->edit_mask = ReadBlobMSBLong(image);
855 outLayer->show_mask = ReadBlobMSBLong(image);
858 outLayer->offset_x = ReadBlobMSBSignedLong(image);
859 outLayer->offset_y = ReadBlobMSBSignedLong(image);
862 outLayer->mode = ReadBlobMSBLong(image);
865 outLayer->preserve_trans = ReadBlobMSBLong(image);
869 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
870 ThrowFileException(exception,CorruptImageError,
871 "UnexpectedEndOfFile",image->filename);
874 ssize_t base = info->cp;
876 while (info->cp - base < prop_size)
878 p = xcf_load_parasite(info);
879 gimp_drawable_parasite_attach(GIMP_DRAWABLE(layer), p);
880 gimp_parasite_free(p);
882 if (info->cp - base != prop_size)
883 g_message ("Error detected while loading a layer's parasites");
888 /* g_message ("unexpected/unknown layer property: %d (skipping)",
895 /* read over it... */
896 while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
898 amount = (ssize_t) MagickMin(16, prop_size);
899 amount = ReadBlob(image, (size_t) amount, (unsigned char *) &buf);
901 ThrowBinaryException(CorruptImageError,"CorruptImage",
903 prop_size -= (size_t) MagickMin(16, (size_t) amount);
909 if (EOFBlob(image) != MagickFalse)
910 ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
912 if (foundPropEnd == MagickFalse)
914 /* allocate the image for this layer */
915 if (image_info->number_scenes != 0)
920 scene=inDocInfo->number_layers-layer-1;
921 if (scene > (ssize_t) (image_info->scene+image_info->number_scenes-1))
923 outLayer->image=CloneImage(image,0,0,MagickTrue,exception);
924 if (outLayer->image == (Image *) NULL)
926 InitXCFImage(outLayer,exception);
930 outLayer->image=CloneImage(image,outLayer->width, outLayer->height,MagickTrue,
932 if (outLayer->image == (Image *) NULL)
934 outLayer->width=outLayer->image->columns;
935 status=SetImageExtent(outLayer->image,outLayer->image->columns,
936 outLayer->image->rows,exception);
937 if (status != MagickFalse)
938 status=ResetImagePixels(image,exception);
939 if (status == MagickFalse)
941 outLayer->image=DestroyImageList(outLayer->image);
944 /* clear the image based on the layer opacity */
945 outLayer->image->background_color.alpha=
946 ScaleCharToQuantum((unsigned char) outLayer->alpha);
947 if (outLayer->alpha != 255U)
949 outLayer->image->background_color.alpha_trait=BlendPixelTrait;
950 outLayer->image->alpha_trait=BlendPixelTrait;
953 InitXCFImage(outLayer,exception);
955 /* set the compositing mode */
956 outLayer->image->compose = GIMPBlendModeToCompositeOperator( outLayer->mode );
957 if ( outLayer->visible == MagickFalse )
959 /* BOGUS: should really be separate member var! */
960 outLayer->image->compose = NoCompositeOp;
963 /* read the hierarchy and layer mask offsets */
964 hierarchy_offset = ReadBlobMSBLong(image);
965 layer_mask_offset = ReadBlobMSBLong(image);
967 /* read in the hierarchy */
968 offset=SeekBlob(image, (MagickOffsetType) hierarchy_offset, SEEK_SET);
969 if (offset != (MagickOffsetType) hierarchy_offset)
970 (void) ThrowMagickException(exception,GetMagickModule(),
971 CorruptImageError,"InvalidImageHeader","`%s'",image->filename);
972 if (load_hierarchy (image, inDocInfo, outLayer, exception) == 0)
975 /* read in the layer mask */
976 if (layer_mask_offset != 0)
978 offset=SeekBlob(image, (MagickOffsetType) layer_mask_offset, SEEK_SET);
980 #if 0 /* BOGUS: support layer masks! */
981 layer_mask = xcf_load_layer_mask (info, gimage);
985 /* set the offsets of the layer_mask */
986 GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
987 GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
989 gimp_layer_add_mask (layer, layer_mask, MagickFalse);
991 layer->mask->apply_mask = apply_mask;
992 layer->mask->edit_mask = edit_mask;
993 layer->mask->show_mask = show_mask;
997 /* attach the floating selection... */
998 #if 0 /* BOGUS: we may need to read this, even if we don't support it! */
999 if (add_floating_sel)
1001 GimpLayer *floating_sel;
1003 floating_sel = info->floating_sel;
1004 floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
1012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % R e a d X C F I m a g e %
1020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 % ReadXCFImage() reads a GIMP (GNU Image Manipulation Program) image
1023 % file and returns it. It allocates the memory necessary for the new Image
1024 % structure and returns a pointer to the new image.
1026 % The format of the ReadXCFImage method is:
1028 % image=ReadXCFImage(image_info)
1030 % A description of each parameter follows:
1032 % o image_info: the image info.
1034 % o exception: return any errors or warnings in this structure.
1037 static Image *ReadXCFImage(const ImageInfo *image_info,ExceptionInfo *exception)
1070 assert(image_info != (const ImageInfo *) NULL);
1071 assert(image_info->signature == MagickCoreSignature);
1072 if (image_info->debug != MagickFalse)
1073 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1074 image_info->filename);
1075 assert(exception != (ExceptionInfo *) NULL);
1076 assert(exception->signature == MagickCoreSignature);
1077 image=AcquireImage(image_info,exception);
1078 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1079 if (status == MagickFalse)
1081 image=DestroyImageList(image);
1082 return((Image *) NULL);
1084 count=ReadBlob(image,14,(unsigned char *) magick);
1085 if ((count != 14) ||
1086 (LocaleNCompare((char *) magick,"gimp xcf",8) != 0))
1087 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1088 (void) memset(&doc_info,0,sizeof(XCFDocInfo));
1089 doc_info.width=ReadBlobMSBLong(image);
1090 doc_info.height=ReadBlobMSBLong(image);
1091 if ((doc_info.width > 262144) || (doc_info.height > 262144))
1092 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1093 doc_info.image_type=ReadBlobMSBLong(image);
1095 Initialize image attributes.
1097 image->columns=doc_info.width;
1098 image->rows=doc_info.height;
1099 image_type=doc_info.image_type;
1100 doc_info.file_size=GetBlobSize(image);
1101 image->compression=NoCompression;
1103 status=SetImageExtent(image,image->columns,image->rows,exception);
1104 if (status == MagickFalse)
1105 return(DestroyImageList(image));
1106 if (image_type == GIMP_INDEXED)
1107 ThrowReaderException(CoderError,"ColormapTypeNotSupported");
1108 if (image_type == GIMP_RGB)
1109 SetImageColorspace(image,sRGBColorspace,exception);
1110 else if (image_type == GIMP_GRAY)
1111 SetImageColorspace(image,GRAYColorspace,exception);
1113 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1114 (void) SetImageBackgroundColor(image,exception);
1115 (void) SetImageAlpha(image,OpaqueAlpha,exception);
1119 while ((foundPropEnd == MagickFalse) && (EOFBlob(image) == MagickFalse))
1121 PropType prop_type = (PropType) ReadBlobMSBLong(image);
1122 size_t prop_size = ReadBlobMSBLong(image);
1131 /* Cannot rely on prop_size here--the value is set incorrectly
1132 by some Gimp versions.
1134 size_t num_colours = ReadBlobMSBLong(image);
1135 if (DiscardBlobBytes(image,3*num_colours) == MagickFalse)
1136 ThrowFileException(exception,CorruptImageError,
1137 "UnexpectedEndOfFile",image->filename);
1139 if (info->file_version == 0)
1143 g_message (_("XCF warning: version 0 of XCF file format\n"
1144 "did not save indexed colormaps correctly.\n"
1145 "Substituting grayscale map."));
1147 xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1148 gimage->cmap = g_new (guchar, gimage->num_cols*3);
1149 xcf_seek_pos (info, info->cp + gimage->num_cols);
1150 for (i = 0; i<gimage->num_cols; i++)
1152 gimage->cmap[i*3+0] = i;
1153 gimage->cmap[i*3+1] = i;
1154 gimage->cmap[i*3+2] = i;
1160 xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
1161 gimage->cmap = g_new (guchar, gimage->num_cols*3);
1163 xcf_read_int8 (info->fp,
1164 (guint8*) gimage->cmap, gimage->num_cols*3);
1169 case PROP_COMPRESSION:
1171 doc_info.compression = ReadBlobByte(image);
1172 if ((doc_info.compression != COMPRESS_NONE) &&
1173 (doc_info.compression != COMPRESS_RLE) &&
1174 (doc_info.compression != COMPRESS_ZLIB) &&
1175 (doc_info.compression != COMPRESS_FRACTAL))
1176 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
1182 /* just skip it - we don't care about guides */
1183 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1184 ThrowFileException(exception,CorruptImageError,
1185 "UnexpectedEndOfFile",image->filename);
1189 case PROP_RESOLUTION:
1191 /* float xres = (float) */ (void) ReadBlobMSBLong(image);
1192 /* float yres = (float) */ (void) ReadBlobMSBLong(image);
1195 if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
1196 yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
1198 g_message ("Warning, resolution out of range in XCF file");
1199 xres = gimage->gimp->config->default_xresolution;
1200 yres = gimage->gimp->config->default_yresolution;
1205 /* BOGUS: we don't write these yet because we aren't
1206 reading them properly yet :(
1207 image->resolution.x = xres;
1208 image->resolution.y = yres;
1215 /* we need to read it, even if we ignore it */
1216 /*size_t tattoo_state = */ (void) ReadBlobMSBLong(image);
1220 case PROP_PARASITES:
1222 /* BOGUS: we may need these for IPTC stuff */
1223 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1224 ThrowFileException(exception,CorruptImageError,
1225 "UnexpectedEndOfFile",image->filename);
1227 gssize_t base = info->cp;
1230 while (info->cp - base < prop_size)
1232 p = xcf_load_parasite (info);
1233 gimp_image_parasite_attach (gimage, p);
1234 gimp_parasite_free (p);
1236 if (info->cp - base != prop_size)
1237 g_message ("Error detected while loading an image's parasites");
1244 /* BOGUS: ignore for now... */
1245 /*size_t unit = */ (void) ReadBlobMSBLong(image);
1251 /* BOGUS: just skip it for now */
1252 if (DiscardBlobBytes(image,prop_size) == MagickFalse)
1253 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1257 PathList *paths = xcf_load_bzpaths (gimage, info);
1258 gimp_image_set_paths (gimage, paths);
1263 case PROP_USER_UNIT:
1265 char unit_string[1000];
1266 /*BOGUS: ignored for now */
1267 /*float factor = (float) */ (void) ReadBlobMSBLong(image);
1268 /* size_t digits = */ (void) ReadBlobMSBLong(image);
1270 (void) ReadBlobStringWithLongSize(image, unit_string,
1271 sizeof(unit_string),exception);
1280 /* read over it... */
1281 while ((prop_size > 0) && (EOFBlob(image) == MagickFalse))
1283 amount=(ssize_t) MagickMin(16, prop_size);
1284 amount=(ssize_t) ReadBlob(image,(size_t) amount,(unsigned char *) &buf);
1286 ThrowReaderException(CorruptImageError,"CorruptImage");
1287 prop_size -= (size_t) MagickMin(16,(size_t) amount);
1293 if (foundPropEnd == MagickFalse)
1294 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1296 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1298 ; /* do nothing, were just pinging! */
1304 foundAllLayers = MagickFalse,
1308 oldPos=TellBlob(image);
1318 ssize_t offset = ReadBlobMSBSignedLong(image);
1320 foundAllLayers=MagickTrue;
1323 if (EOFBlob(image) != MagickFalse)
1325 ThrowFileException(exception,CorruptImageError,
1326 "UnexpectedEndOfFile",image->filename);
1329 } while (foundAllLayers == MagickFalse);
1330 if (AcquireMagickResource(ListLengthResource,number_layers) == MagickFalse)
1331 ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1332 doc_info.number_layers=number_layers;
1333 offset=SeekBlob(image,oldPos,SEEK_SET); /* restore the position! */
1335 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1336 /* allocate our array of layer info blocks */
1337 length=(size_t) number_layers;
1338 layer_info=(XCFLayerInfo *) AcquireQuantumMemory(length,
1339 sizeof(*layer_info));
1340 if (layer_info == (XCFLayerInfo *) NULL)
1341 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1342 (void) memset(layer_info,0,number_layers*sizeof(XCFLayerInfo));
1352 /* read in the offset of the next layer */
1353 offset=(MagickOffsetType) ReadBlobMSBLong(image);
1354 /* if the offset is 0 then we are at the end
1355 * of the layer list.
1359 /* save the current position as it is where the
1360 * next layer offset is stored.
1362 saved_pos=TellBlob(image);
1363 /* seek to the layer offset */
1364 layer_ok=MagickFalse;
1365 if (SeekBlob(image,offset,SEEK_SET) == offset)
1367 /* read in the layer */
1368 layer_ok=ReadOneLayer(image_info,image,&doc_info,
1369 &layer_info[current_layer],current_layer,exception);
1371 if (layer_ok == MagickFalse)
1375 for (j=0; j <= current_layer; j++)
1376 if (layer_info[j].image != (Image *) NULL)
1377 layer_info[j].image=DestroyImage(layer_info[j].image);
1378 layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1379 ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
1381 /* restore the saved position so we'll be ready to
1382 * read the next offset.
1384 offset=SeekBlob(image, saved_pos, SEEK_SET);
1389 /* NOTE: XCF layers are REVERSED from composite order! */
1391 for (j=number_layers-1; j>=0; j--) {
1392 /* BOGUS: need to consider layer blending modes!! */
1394 if ( layer_info[j].visible ) { /* only visible ones, please! */
1395 CompositeImage(image, OverCompositeOp, layer_info[j].image,
1396 layer_info[j].offset_x, layer_info[j].offset_y );
1397 layer_info[j].image =DestroyImage( layer_info[j].image );
1399 /* If we do this, we'll get REAL gray images! */
1400 if ( image_type == GIMP_GRAY ) {
1402 GetQuantizeInfo(&qi);
1403 qi.colorspace = GRAYColorspace;
1404 QuantizeImage( &qi, layer_info[j].image );
1411 /* NOTE: XCF layers are REVERSED from composite order! */
1414 /* now reverse the order of the layers as they are put
1417 for (j=(ssize_t) number_layers-1; j >= 0; j--)
1418 AppendImageToList(&image,layer_info[j].image);
1422 layer_info=(XCFLayerInfo *) RelinquishMagickMemory(layer_info);
1424 #if 0 /* BOGUS: do we need the channels?? */
1427 /* read in the offset of the next channel */
1428 info->cp += xcf_read_int32 (info->fp, &offset, 1);
1430 /* if the offset is 0 then we are at the end
1431 * of the channel list.
1436 /* save the current position as it is where the
1437 * next channel offset is stored.
1439 saved_pos = info->cp;
1441 /* seek to the channel offset */
1442 xcf_seek_pos (info, offset);
1444 /* read in the layer */
1445 channel = xcf_load_channel (info, gimage);
1449 num_successful_elements++;
1451 /* add the channel to the image if its not the selection */
1452 if (channel != gimage->selection_mask)
1453 gimp_image_add_channel (gimage, channel, -1);
1455 /* restore the saved position so we'll be ready to
1456 * read the next offset.
1458 xcf_seek_pos (info, saved_pos);
1463 (void) CloseBlob(image);
1464 if (GetNextImageInList(image) != (Image *) NULL)
1465 DestroyImage(RemoveFirstImageFromList(&image));
1466 if (image_type == GIMP_GRAY)
1467 image->type=GrayscaleType;
1468 return(GetFirstImageInList(image));
1472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476 % R e g i s t e r X C F I m a g e %
1480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482 % RegisterXCFImage() adds attributes for the XCF image format to
1483 % the list of supported formats. The attributes include the image format
1484 % tag, a method to read and/or write the format, whether the format
1485 % supports the saving of more than one frame to the same file or blob,
1486 % whether the format supports native in-memory I/O, and a brief
1487 % description of the format.
1489 % The format of the RegisterXCFImage method is:
1491 % size_t RegisterXCFImage(void)
1494 ModuleExport size_t RegisterXCFImage(void)
1499 entry=AcquireMagickInfo("XCF","XCF","GIMP image");
1500 entry->decoder=(DecodeImageHandler *) ReadXCFImage;
1501 entry->magick=(IsImageFormatHandler *) IsXCF;
1502 entry->flags|=CoderDecoderSeekableStreamFlag;
1503 (void) RegisterMagickInfo(entry);
1504 return(MagickImageCoderSignature);
1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % U n r e g i s t e r X C F I m a g e %
1516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518 % UnregisterXCFImage() removes format registrations made by the
1519 % XCF module from the list of supported formats.
1521 % The format of the UnregisterXCFImage method is:
1523 % UnregisterXCFImage(void)
1526 ModuleExport void UnregisterXCFImage(void)
1528 (void) UnregisterMagickInfo("XCF");