]> granicus.if.org Git - imagemagick/blob - coders/flif.c
Remove --enable-zero-configuration as per https://github.com/ImageMagick/ImageMagick...
[imagemagick] / coders / flif.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                         FFFFF  L      IIIII  FFFFF                          %
7 %                         F      L        I    F                              %
8 %                         FFF    L        I    FFF                            %
9 %                         F      L        I    F                              %
10 %                         F      LLLLL  IIIII  F                              %
11 %                                                                             %
12 %                                                                             %
13 %                    Read/Write Free Lossless Image Format                    %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                Jon Sneyers                                  %
17 %                                April 2016                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2017 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://www.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 \f
39 /*
40   Include declarations.
41 */
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)
69 #include <flif.h>
70 #endif
71 \f
72 /*
73   Forward declarations.
74 */
75 #if defined(MAGICKCORE_FLIF_DELEGATE)
76 static MagickBooleanType
77   WriteFLIFImage(const ImageInfo *,Image *,ExceptionInfo *);
78 #endif
79 \f
80 #if defined(MAGICKCORE_FLIF_DELEGATE)
81 /*
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 %                                                                             %
84 %                                                                             %
85 %                                                                             %
86 %   R e a d F L I F I m a g e                                                 %
87 %                                                                             %
88 %                                                                             %
89 %                                                                             %
90 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 %
92 %  ReadFLIFImage() reads an image in the FLIF image format.
93 %
94 %  The format of the ReadFLIFImage method is:
95 %
96 %      Image *ReadFLIFImage(const ImageInfo *image_info,
97 %        ExceptionInfo *exception)
98 %
99 %  A description of each parameter follows:
100 %
101 %    o image_info: the image info.
102 %
103 %    o exception: return any errors or warnings in this structure.
104 %
105 */
106 static Image *ReadFLIFImage(const ImageInfo *image_info,
107   ExceptionInfo *exception)
108 {
109   FLIF_DECODER
110     *flifdec;
111
112   FLIF_IMAGE
113     *flifimage;
114
115   Image
116     *image;
117
118   MagickBooleanType
119     status;
120
121   register Quantum
122     *q;
123
124   register ssize_t
125     x;
126
127   register unsigned short
128     *p;
129
130   size_t
131     count,
132     image_count,
133     length;
134
135   ssize_t
136     y;
137
138   unsigned char
139     *stream;
140
141   unsigned short
142     *pixels;
143
144   /*
145     Open image file.
146   */
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)
157     {
158       image=DestroyImageList(image);
159       return((Image *) NULL);
160     }
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);
166   if (count != length)
167     {
168       stream=(unsigned char *) RelinquishMagickMemory(stream);
169       ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
170     }
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))
175     {
176       flif_destroy_decoder(flifdec);
177       ThrowReaderException(CorruptImageError,"CorruptImage");
178     }
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)
184     {
185       flif_destroy_decoder(flifdec);
186       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
187     }
188
189   for (count=0; count < image_count; count++)
190   {
191     if (count > 0)
192       {
193         /*
194           Allocate next image structure.
195         */
196         AcquireNextImage(image_info,image,exception);
197         if (GetNextImageInList(image) == (Image *) NULL)
198           {
199             image=DestroyImageList(image);
200             flif_destroy_decoder(flifdec);
201             pixels=(unsigned short *) RelinquishMagickMemory(pixels);
202             return((Image *) NULL);
203           }
204         image=SyncNextImageInList(image);
205       }
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;
214     image->scene=count;
215     image->dispose=BackgroundDispose;
216     for (y=0; y < (ssize_t) image->rows; y++)
217     {
218       flif_image_read_row_RGBA16(flifimage,y,pixels,length);
219       p=pixels;
220       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
221       if (q == (Quantum *) NULL)
222         break;
223       for (x=0; x < (ssize_t) image->columns; x++)
224       {
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);
230       }
231       if (SyncAuthenticPixels(image,exception) == MagickFalse)
232         break;
233       status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
234         image->rows);
235       if (status == MagickFalse)
236         break;
237     }
238   }
239   flif_destroy_decoder(flifdec);
240   pixels=(unsigned short *) RelinquishMagickMemory(pixels);
241   return(image);
242 }
243 #endif
244 \f
245 /*
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 %                                                                             %
248 %                                                                             %
249 %                                                                             %
250 %   I s F L I F                                                               %
251 %                                                                             %
252 %                                                                             %
253 %                                                                             %
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 %
256 %  IsFLIF() returns MagickTrue if the image format type, identified by the
257 %  magick string, is FLIF.
258 %
259 %  The format of the IsFLIF method is:
260 %
261 %      MagickBooleanType IsFLIF(const unsigned char *magick,
262 %        const size_t length)
263 %
264 %  A description of each parameter follows:
265 %
266 %    o magick: compare image format pattern against these bytes.
267 %
268 %    o length: Specifies the length of the magick string.
269 %
270 */
271 static MagickBooleanType IsFLIF(const unsigned char *magick,
272   const size_t length)
273 {
274   if (length < 4)
275     return(MagickFalse);
276   if (LocaleNCompare((char *) magick,"FLIF",4) == 0)
277     return(MagickTrue);
278   return(MagickFalse);
279 }
280
281 /*
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 %                                                                             %
284 %                                                                             %
285 %                                                                             %
286 %   R e g i s t e r F L I F I m a g e                                         %
287 %                                                                             %
288 %                                                                             %
289 %                                                                             %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 %
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.
298 %
299 %  The format of the RegisterFLIFImage method is:
300 %
301 %      size_t RegisterFLIFImage(void)
302 %
303 */
304 ModuleExport size_t RegisterFLIFImage(void)
305 {
306   char
307     version[MagickPathExtent];
308
309   MagickInfo
310     *entry;
311
312   *version='\0';
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);
321 #endif
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);
328 }
329 \f
330 /*
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 %                                                                             %
333 %                                                                             %
334 %                                                                             %
335 %   U n r e g i s t e r F L I F I m a g e                                     %
336 %                                                                             %
337 %                                                                             %
338 %                                                                             %
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 %
341 %  UnregisterFLIFImage() removes format registrations made by the FLIF module
342 %  from the list of supported formats.
343 %
344 %  The format of the UnregisterFLIFImage method is:
345 %
346 %      UnregisterFLIFImage(void)
347 %
348 */
349 ModuleExport void UnregisterFLIFImage(void)
350 {
351   (void) UnregisterMagickInfo("FLIF");
352 }
353
354 #if defined(MAGICKCORE_FLIF_DELEGATE)
355 /*
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357 %                                                                             %
358 %                                                                             %
359 %                                                                             %
360 %   W r i t e F L I F I m a g e                                               %
361 %                                                                             %
362 %                                                                             %
363 %                                                                             %
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 %
366 %  WriteFLIFImage() writes an image in the FLIF image format.
367 %
368 %  The format of the WriteFLIFImage method is:
369 %
370 %      MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
371 %        Image *image)
372 %
373 %  A description of each parameter follows.
374 %
375 %    o image_info: the image info.
376 %
377 %    o image:  The image.
378 %
379 */
380 static MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
381   Image *image, ExceptionInfo *exception)
382 {
383   FLIF_ENCODER
384     *flifenc;
385
386   FLIF_IMAGE
387     *flifimage;
388
389   int
390     flif_status;
391
392   MagickBooleanType
393     status;
394
395   MagickOffsetType
396     scene;
397
398   register const Quantum
399     *magick_restrict p;
400
401   register ssize_t
402     x;
403
404   register unsigned char
405     *magick_restrict qc;
406
407   register unsigned short
408     *magick_restrict qs;
409
410   size_t
411     columns,
412     length,
413     rows;
414
415   ssize_t
416     y;
417
418   void
419     *buffer;
420
421   void
422     *pixels;
423
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)
434     return(status);
435   flifenc=flif_create_encoder();
436   if (image_info->quality != UndefinedCompressionQuality)
437     flif_encoder_set_lossy(flifenc,3*(100-(int32_t) image_info->quality));
438
439   /* relatively fast encoding */
440   flif_encoder_set_learn_repeat(flifenc,1);
441   flif_encoder_set_split_threshold(flifenc,5461*8*5);
442
443   columns=image->columns;
444   rows=image->rows;
445
446   /* Convert image to FLIFIMAGE */
447   if (image->depth > 8)
448     {
449       flifimage=flif_create_image_HDR((uint32_t) image->columns,
450         (uint32_t) image->rows);
451       length=sizeof(unsigned short)*4*image->columns;
452     }
453   else
454     {
455       flifimage=flif_create_image((uint32_t) image->columns,
456         (uint32_t) image->rows);
457       length=sizeof(unsigned char)*4*image->columns;
458     }
459   if (flifimage == (FLIF_IMAGE *) NULL)
460     {
461       flif_destroy_encoder(flifenc);
462       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
463     }
464   pixels=AcquireMagickMemory(length);
465   if (pixels == (void *) NULL)
466     {
467       flif_destroy_image(flifimage);
468       flif_destroy_encoder(flifenc);
469       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
470     }
471   scene=0;
472
473   do
474   {
475     for (y=0; y < (ssize_t) image->rows; y++)
476     {
477       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
478       if (p == (Quantum *) NULL)
479         break;
480
481       if (image->depth > 8)
482         {
483           qs=(unsigned short *) pixels;
484           for (x=0; x < (ssize_t) image->columns; x++)
485           {
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));
491             else
492               *qs++=0xFFFF;
493             p+=GetPixelChannels(image);
494           }
495           flif_image_write_row_RGBA16(flifimage,y,pixels,length);
496         }
497       else
498         {
499           qc=pixels;
500           for (x=0; x < (ssize_t) image->columns; x++)
501           {
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));
507             else
508               *qc++=0xFF;
509             p+=GetPixelChannels(image);
510           }
511           flif_image_write_row_RGBA8(flifimage,y,pixels,length);
512         }
513     }
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)
518       break;
519     image=SyncNextImageInList(image);
520     if ((columns != image->columns) || (rows != image->rows))
521       {
522         flif_destroy_image(flifimage);
523         flif_destroy_encoder(flifenc);
524         pixels=RelinquishMagickMemory(pixels);
525         ThrowWriterException(ImageError,"FramesNotSameDimensions");
526       }
527     scene++;
528     status=SetImageProgress(image,SaveImagesTag,scene,GetImageListLength(
529       image));
530     if (status == MagickFalse)
531        break;
532   } while (image_info->adjoin != MagickFalse);
533
534   flif_destroy_image(flifimage);
535   pixels=RelinquishMagickMemory(pixels);
536   flif_status=flif_encoder_encode_memory(flifenc,&buffer,&length);
537   if (flif_status)
538     WriteBlob(image,length,buffer);
539   CloseBlob(image);
540   flif_destroy_encoder(flifenc);
541   buffer=RelinquishMagickMemory(buffer);
542   return(flif_status == 0 ? MagickFalse : MagickTrue);
543 }
544 #endif