2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % FFFFF L IIIII FFFFF %
13 % Read/Write Free Lossless Image Format %
20 % Copyright 1999-2016 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 % http://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);
167 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
168 flifdec=flif_create_decoder();
169 if (image_info->quality != UndefinedCompressionQuality)
170 flif_decoder_set_quality(flifdec,(int32_t) image_info->quality);
171 if (!flif_decoder_decode_memory(flifdec,stream,length))
173 flif_destroy_decoder(flifdec);
174 ThrowReaderException(CorruptImageError,"CorruptImage");
176 image_count=flif_decoder_num_images(flifdec);
177 flifimage=flif_decoder_get_image(flifdec,0);
178 length=sizeof(unsigned short)*4*flif_image_get_width(flifimage);
179 pixels=(unsigned short *) AcquireMagickMemory(length);
180 if (pixels == (unsigned short *) NULL)
182 flif_destroy_decoder(flifdec);
183 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
186 for (count=0; count < image_count; count++)
191 Allocate next image structure.
193 AcquireNextImage(image_info,image,exception);
194 if (GetNextImageInList(image) == (Image *) NULL)
196 image=DestroyImageList(image);
197 flif_destroy_decoder(flifdec);
198 pixels=(unsigned short *) RelinquishMagickMemory(pixels);
199 return((Image *) NULL);
201 image=SyncNextImageInList(image);
203 flifimage=flif_decoder_get_image(flifdec,count);
204 image->columns=(size_t) flif_image_get_width(flifimage);
205 image->rows=(size_t) flif_image_get_height(flifimage);
206 image->depth=flif_image_get_depth(flifimage);
207 image->alpha_trait=(flif_image_get_nb_channels(flifimage) > 3 ?
208 BlendPixelTrait : UndefinedPixelTrait);
209 image->delay=flif_image_get_frame_delay(flifimage);
210 image->ticks_per_second=1000;
212 image->dispose=BackgroundDispose;
213 for (y=0; y < (ssize_t) image->rows; y++)
215 flif_image_read_row_RGBA16(flifimage,y,pixels,length);
217 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
218 if (q == (Quantum *) NULL)
220 for (x=0; x < (ssize_t) image->columns; x++)
222 SetPixelRed(image,ScaleShortToQuantum(*p++),q);
223 SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
224 SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
225 SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
226 q+=GetPixelChannels(image);
228 if (SyncAuthenticPixels(image,exception) == MagickFalse)
230 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
232 if (status == MagickFalse)
236 flif_destroy_decoder(flifdec);
237 pixels=(unsigned short *) RelinquishMagickMemory(pixels);
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 % IsFLIF() returns MagickTrue if the image format type, identified by the
254 % magick string, is FLIF.
256 % The format of the IsFLIF method is:
258 % MagickBooleanType IsFLIF(const unsigned char *magick,
259 % const size_t length)
261 % A description of each parameter follows:
263 % o magick: compare image format pattern against these bytes.
265 % o length: Specifies the length of the magick string.
268 static MagickBooleanType IsFLIF(const unsigned char *magick,
273 if (LocaleNCompare((char *) magick,"FLIF",4) == 0)
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 % R e g i s t e r F L I F I m a g e %
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289 % RegisterFLIFImage() adds attributes for the FLIF image format to
290 % the list of supported formats. The attributes include the image format
291 % tag, a method to read and/or write the format, whether the format
292 % supports the saving of more than one frame to the same file or blob,
293 % whether the format supports native in-memory I/O, and a brief
294 % description of the format.
296 % The format of the RegisterFLIFImage method is:
298 % size_t RegisterFLIFImage(void)
301 ModuleExport size_t RegisterFLIFImage(void)
304 version[MagickPathExtent];
310 entry=AcquireMagickInfo("FLIF","FLIF","Free Lossless Image Format");
311 #if defined(MAGICKCORE_FLIF_DELEGATE)
312 entry->decoder=(DecodeImageHandler *) ReadFLIFImage;
313 entry->encoder=(EncodeImageHandler *) WriteFLIFImage;
314 (void) FormatLocaleString(version,MagickPathExtent,"libflif %d.%d.%d [%04X]",
315 (FLIF_VERSION >> 16) & 0xff,
316 (FLIF_VERSION >> 8) & 0xff,
317 (FLIF_VERSION >> 0) & 0xff,FLIF_ABI_VERSION);
319 entry->mime_type=ConstantString("image/flif");
320 entry->magick=(IsImageFormatHandler *) IsFLIF;
321 if (*version != '\0')
322 entry->version=ConstantString(version);
323 (void) RegisterMagickInfo(entry);
324 return(MagickImageCoderSignature);
328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 % U n r e g i s t e r F L I F I m a g e %
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338 % UnregisterFLIFImage() removes format registrations made by the FLIF module
339 % from the list of supported formats.
341 % The format of the UnregisterFLIFImage method is:
343 % UnregisterFLIFImage(void)
346 ModuleExport void UnregisterFLIFImage(void)
348 (void) UnregisterMagickInfo("FLIF");
351 #if defined(MAGICKCORE_FLIF_DELEGATE)
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357 % W r i t e F L I F I m a g e %
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363 % WriteFLIFImage() writes an image in the FLIF image format.
365 % The format of the WriteFLIFImage method is:
367 % MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
370 % A description of each parameter follows.
372 % o image_info: the image info.
374 % o image: The image.
377 static MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
378 Image *image, ExceptionInfo *exception)
395 register const Quantum
401 register unsigned char
404 register unsigned short
421 assert(image_info != (const ImageInfo *) NULL);
422 assert(image_info->signature == MagickCoreSignature);
423 assert(image != (Image *) NULL);
424 assert(image->signature == MagickCoreSignature);
425 if (image->debug != MagickFalse)
426 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
427 if ((image->columns > 0xFFFF) || (image->rows > 0xFFFF))
428 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
429 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
430 if (status == MagickFalse)
432 flifenc=flif_create_encoder();
433 if (image_info->quality != UndefinedCompressionQuality)
434 flif_encoder_set_lossy(flifenc,3*(100-(int32_t) image_info->quality));
436 /* relatively fast encoding */
437 flif_encoder_set_learn_repeat(flifenc,1);
438 flif_encoder_set_split_threshold(flifenc,5461*8*5);
440 columns=image->columns;
443 /* Convert image to FLIFIMAGE */
444 if (image->depth > 8)
446 flifimage=flif_create_image_HDR((uint32_t) image->columns,
447 (uint32_t) image->rows);
448 length=sizeof(unsigned short)*4*image->columns;
452 flifimage=flif_create_image((uint32_t) image->columns,
453 (uint32_t) image->rows);
454 length=sizeof(unsigned char)*4*image->columns;
456 if (flifimage == (FLIF_IMAGE *) NULL)
458 flif_destroy_encoder(flifenc);
459 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
461 pixels=AcquireMagickMemory(length);
462 if (pixels == (void *) NULL)
464 flif_destroy_image(flifimage);
465 flif_destroy_encoder(flifenc);
466 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
472 for (y=0; y < (ssize_t) image->rows; y++)
474 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
475 if (p == (Quantum *) NULL)
478 if (image->depth > 8)
480 qs=(unsigned short *) pixels;
481 for (x=0; x < (ssize_t) image->columns; x++)
483 *qs++=ScaleQuantumToShort(GetPixelRed(image,p));
484 *qs++=ScaleQuantumToShort(GetPixelGreen(image,p));
485 *qs++=ScaleQuantumToShort(GetPixelBlue(image,p));
486 if (image->alpha_trait != UndefinedPixelTrait)
487 *qs++=ScaleQuantumToShort(GetPixelAlpha(image,p));
490 p+=GetPixelChannels(image);
492 flif_image_write_row_RGBA16(flifimage,y,pixels,length);
497 for (x=0; x < (ssize_t) image->columns; x++)
499 *qc++=ScaleQuantumToChar(GetPixelRed(image,p));
500 *qc++=ScaleQuantumToChar(GetPixelGreen(image,p));
501 *qc++=ScaleQuantumToChar(GetPixelBlue(image,p));
502 if (image->alpha_trait != UndefinedPixelTrait)
503 *qc++=ScaleQuantumToChar(GetPixelAlpha(image,p));
506 p+=GetPixelChannels(image);
508 flif_image_write_row_RGBA8(flifimage,y,pixels,length);
511 flif_image_set_frame_delay(flifimage,(uint32_t) image->delay*100/
512 image->ticks_per_second);
513 flif_encoder_add_image(flifenc,flifimage);
514 if (GetNextImageInList(image) == (Image *) NULL)
516 image=SyncNextImageInList(image);
517 if ((columns != image->columns) || (rows != image->rows))
519 flif_destroy_image(flifimage);
520 flif_destroy_encoder(flifenc);
521 pixels=RelinquishMagickMemory(pixels);
522 ThrowWriterException(ImageError,"FramesNotSameDimensions");
525 status=SetImageProgress(image,SaveImagesTag,scene,GetImageListLength(
527 if (status == MagickFalse)
529 } while (image_info->adjoin != MagickFalse);
531 flif_destroy_image(flifimage);
532 pixels=RelinquishMagickMemory(pixels);
533 flif_status=flif_encoder_encode_memory(flifenc,&buffer,&length);
535 WriteBlob(image,length,buffer);
537 flif_destroy_encoder(flifenc);
538 buffer=RelinquishMagickMemory(buffer);
539 return(flif_status == 0 ? MagickFalse : MagickTrue);