2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % FFFFF L IIIII FFFFF %
13 % Read/Write Free Lossless Image Format %
20 % Copyright 1999-2017 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/artifact.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/client.h"
47 #include "MagickCore/colorspace-private.h"
48 #include "MagickCore/display.h"
49 #include "MagickCore/exception.h"
50 #include "MagickCore/exception-private.h"
51 #include "MagickCore/image.h"
52 #include "MagickCore/image-private.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/magick.h"
55 #include "MagickCore/monitor.h"
56 #include "MagickCore/monitor-private.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/option.h"
59 #include "MagickCore/pixel-accessor.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/string-private.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/utility.h"
66 #include "MagickCore/xwindow.h"
67 #include "MagickCore/xwindow-private.h"
68 #if defined(MAGICKCORE_FLIF_DELEGATE)
75 #if defined(MAGICKCORE_FLIF_DELEGATE)
76 static MagickBooleanType
77 WriteFLIFImage(const ImageInfo *,Image *,ExceptionInfo *);
80 #if defined(MAGICKCORE_FLIF_DELEGATE)
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 % R e a d F L I F I m a g e %
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 % ReadFLIFImage() reads an image in the FLIF image format.
94 % The format of the ReadFLIFImage method is:
96 % Image *ReadFLIFImage(const ImageInfo *image_info,
97 % ExceptionInfo *exception)
99 % A description of each parameter follows:
101 % o image_info: the image info.
103 % o exception: return any errors or warnings in this structure.
106 static Image *ReadFLIFImage(const ImageInfo *image_info,
107 ExceptionInfo *exception)
127 register unsigned short
147 assert(image_info != (const ImageInfo *) NULL);
148 assert(image_info->signature == MagickCoreSignature);
149 if (image_info->debug != MagickFalse)
150 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
151 image_info->filename);
152 assert(exception != (ExceptionInfo *) NULL);
153 assert(exception->signature == MagickCoreSignature);
154 image=AcquireImage(image_info,exception);
155 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
156 if (status == MagickFalse)
158 image=DestroyImageList(image);
159 return((Image *) NULL);
161 length=(size_t) GetBlobSize(image);
162 stream=(unsigned char *) AcquireQuantumMemory(length,sizeof(*stream));
163 if (stream == (unsigned char *) NULL)
164 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
165 count=ReadBlob(image,length,stream);
168 stream=(unsigned char *) RelinquishMagickMemory(stream);
169 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
171 flifdec=flif_create_decoder();
172 if (image_info->quality != UndefinedCompressionQuality)
173 flif_decoder_set_quality(flifdec,(int32_t) image_info->quality);
174 if (!flif_decoder_decode_memory(flifdec,stream,length))
176 flif_destroy_decoder(flifdec);
177 ThrowReaderException(CorruptImageError,"CorruptImage");
179 image_count=flif_decoder_num_images(flifdec);
180 flifimage=flif_decoder_get_image(flifdec,0);
181 length=sizeof(unsigned short)*4*flif_image_get_width(flifimage);
182 pixels=(unsigned short *) AcquireMagickMemory(length);
183 if (pixels == (unsigned short *) NULL)
185 flif_destroy_decoder(flifdec);
186 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
189 for (count=0; count < image_count; count++)
194 Allocate next image structure.
196 AcquireNextImage(image_info,image,exception);
197 if (GetNextImageInList(image) == (Image *) NULL)
199 image=DestroyImageList(image);
200 flif_destroy_decoder(flifdec);
201 pixels=(unsigned short *) RelinquishMagickMemory(pixels);
202 return((Image *) NULL);
204 image=SyncNextImageInList(image);
206 flifimage=flif_decoder_get_image(flifdec,count);
207 image->columns=(size_t) flif_image_get_width(flifimage);
208 image->rows=(size_t) flif_image_get_height(flifimage);
209 image->depth=flif_image_get_depth(flifimage);
210 image->alpha_trait=(flif_image_get_nb_channels(flifimage) > 3 ?
211 BlendPixelTrait : UndefinedPixelTrait);
212 image->delay=flif_image_get_frame_delay(flifimage);
213 image->ticks_per_second=1000;
215 image->dispose=BackgroundDispose;
216 for (y=0; y < (ssize_t) image->rows; y++)
218 flif_image_read_row_RGBA16(flifimage,y,pixels,length);
220 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
221 if (q == (Quantum *) NULL)
223 for (x=0; x < (ssize_t) image->columns; x++)
225 SetPixelRed(image,ScaleShortToQuantum(*p++),q);
226 SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
227 SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
228 SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
229 q+=GetPixelChannels(image);
231 if (SyncAuthenticPixels(image,exception) == MagickFalse)
233 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
235 if (status == MagickFalse)
239 flif_destroy_decoder(flifdec);
240 pixels=(unsigned short *) RelinquishMagickMemory(pixels);
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256 % IsFLIF() returns MagickTrue if the image format type, identified by the
257 % magick string, is FLIF.
259 % The format of the IsFLIF method is:
261 % MagickBooleanType IsFLIF(const unsigned char *magick,
262 % const size_t length)
264 % A description of each parameter follows:
266 % o magick: compare image format pattern against these bytes.
268 % o length: Specifies the length of the magick string.
271 static MagickBooleanType IsFLIF(const unsigned char *magick,
276 if (LocaleNCompare((char *) magick,"FLIF",4) == 0)
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 % R e g i s t e r F L I F I m a g e %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % RegisterFLIFImage() adds attributes for the FLIF image format to
293 % the list of supported formats. The attributes include the image format
294 % tag, a method to read and/or write the format, whether the format
295 % supports the saving of more than one frame to the same file or blob,
296 % whether the format supports native in-memory I/O, and a brief
297 % description of the format.
299 % The format of the RegisterFLIFImage method is:
301 % size_t RegisterFLIFImage(void)
304 ModuleExport size_t RegisterFLIFImage(void)
307 version[MagickPathExtent];
313 entry=AcquireMagickInfo("FLIF","FLIF","Free Lossless Image Format");
314 #if defined(MAGICKCORE_FLIF_DELEGATE)
315 entry->decoder=(DecodeImageHandler *) ReadFLIFImage;
316 entry->encoder=(EncodeImageHandler *) WriteFLIFImage;
317 (void) FormatLocaleString(version,MagickPathExtent,"libflif %d.%d.%d [%04X]",
318 (FLIF_VERSION >> 16) & 0xff,
319 (FLIF_VERSION >> 8) & 0xff,
320 (FLIF_VERSION >> 0) & 0xff,FLIF_ABI_VERSION);
322 entry->mime_type=ConstantString("image/flif");
323 entry->magick=(IsImageFormatHandler *) IsFLIF;
324 if (*version != '\0')
325 entry->version=ConstantString(version);
326 (void) RegisterMagickInfo(entry);
327 return(MagickImageCoderSignature);
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 % U n r e g i s t e r F L I F I m a g e %
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 % UnregisterFLIFImage() removes format registrations made by the FLIF module
342 % from the list of supported formats.
344 % The format of the UnregisterFLIFImage method is:
346 % UnregisterFLIFImage(void)
349 ModuleExport void UnregisterFLIFImage(void)
351 (void) UnregisterMagickInfo("FLIF");
354 #if defined(MAGICKCORE_FLIF_DELEGATE)
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360 % W r i t e F L I F I m a g e %
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 % WriteFLIFImage() writes an image in the FLIF image format.
368 % The format of the WriteFLIFImage method is:
370 % MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
373 % A description of each parameter follows.
375 % o image_info: the image info.
377 % o image: The image.
380 static MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
381 Image *image, ExceptionInfo *exception)
398 register const Quantum
404 register unsigned char
407 register unsigned short
424 assert(image_info != (const ImageInfo *) NULL);
425 assert(image_info->signature == MagickCoreSignature);
426 assert(image != (Image *) NULL);
427 assert(image->signature == MagickCoreSignature);
428 if (image->debug != MagickFalse)
429 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
430 if ((image->columns > 0xFFFF) || (image->rows > 0xFFFF))
431 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
432 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
433 if (status == MagickFalse)
435 flifenc=flif_create_encoder();
436 if (image_info->quality != UndefinedCompressionQuality)
437 flif_encoder_set_lossy(flifenc,3*(100-(int32_t) image_info->quality));
439 /* relatively fast encoding */
440 flif_encoder_set_learn_repeat(flifenc,1);
441 flif_encoder_set_split_threshold(flifenc,5461*8*5);
443 columns=image->columns;
446 /* Convert image to FLIFIMAGE */
447 if (image->depth > 8)
449 flifimage=flif_create_image_HDR((uint32_t) image->columns,
450 (uint32_t) image->rows);
451 length=sizeof(unsigned short)*4*image->columns;
455 flifimage=flif_create_image((uint32_t) image->columns,
456 (uint32_t) image->rows);
457 length=sizeof(unsigned char)*4*image->columns;
459 if (flifimage == (FLIF_IMAGE *) NULL)
461 flif_destroy_encoder(flifenc);
462 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
464 pixels=AcquireMagickMemory(length);
465 if (pixels == (void *) NULL)
467 flif_destroy_image(flifimage);
468 flif_destroy_encoder(flifenc);
469 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
475 for (y=0; y < (ssize_t) image->rows; y++)
477 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
478 if (p == (Quantum *) NULL)
481 if (image->depth > 8)
483 qs=(unsigned short *) pixels;
484 for (x=0; x < (ssize_t) image->columns; x++)
486 *qs++=ScaleQuantumToShort(GetPixelRed(image,p));
487 *qs++=ScaleQuantumToShort(GetPixelGreen(image,p));
488 *qs++=ScaleQuantumToShort(GetPixelBlue(image,p));
489 if (image->alpha_trait != UndefinedPixelTrait)
490 *qs++=ScaleQuantumToShort(GetPixelAlpha(image,p));
493 p+=GetPixelChannels(image);
495 flif_image_write_row_RGBA16(flifimage,y,pixels,length);
500 for (x=0; x < (ssize_t) image->columns; x++)
502 *qc++=ScaleQuantumToChar(GetPixelRed(image,p));
503 *qc++=ScaleQuantumToChar(GetPixelGreen(image,p));
504 *qc++=ScaleQuantumToChar(GetPixelBlue(image,p));
505 if (image->alpha_trait != UndefinedPixelTrait)
506 *qc++=ScaleQuantumToChar(GetPixelAlpha(image,p));
509 p+=GetPixelChannels(image);
511 flif_image_write_row_RGBA8(flifimage,y,pixels,length);
514 flif_image_set_frame_delay(flifimage,(uint32_t) image->delay*100/
515 image->ticks_per_second);
516 flif_encoder_add_image(flifenc,flifimage);
517 if (GetNextImageInList(image) == (Image *) NULL)
519 image=SyncNextImageInList(image);
520 if ((columns != image->columns) || (rows != image->rows))
522 flif_destroy_image(flifimage);
523 flif_destroy_encoder(flifenc);
524 pixels=RelinquishMagickMemory(pixels);
525 ThrowWriterException(ImageError,"FramesNotSameDimensions");
528 status=SetImageProgress(image,SaveImagesTag,scene,GetImageListLength(
530 if (status == MagickFalse)
532 } while (image_info->adjoin != MagickFalse);
534 flif_destroy_image(flifimage);
535 pixels=RelinquishMagickMemory(pixels);
536 flif_status=flif_encoder_encode_memory(flifenc,&buffer,&length);
538 WriteBlob(image,length,buffer);
540 flif_destroy_encoder(flifenc);
541 buffer=RelinquishMagickMemory(buffer);
542 return(flif_status == 0 ? MagickFalse : MagickTrue);