]> granicus.if.org Git - imagemagick/blob - coders/flif.c
https://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=31265
[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 %    http://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     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))
172     {
173       flif_destroy_decoder(flifdec);
174       ThrowReaderException(CorruptImageError,"CorruptImage");
175     }
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)
181     {
182       flif_destroy_decoder(flifdec);
183       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
184     }
185
186   for (count=0; count < image_count; count++)
187   {
188     if (count > 0)
189       {
190         /*
191           Allocate next image structure.
192         */
193         AcquireNextImage(image_info,image,exception);
194         if (GetNextImageInList(image) == (Image *) NULL)
195           {
196             image=DestroyImageList(image);
197             flif_destroy_decoder(flifdec);
198             pixels=(unsigned short *) RelinquishMagickMemory(pixels);
199             return((Image *) NULL);
200           }
201         image=SyncNextImageInList(image);
202       }
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;
211     image->scene=count;
212     image->dispose=BackgroundDispose;
213     for (y=0; y < (ssize_t) image->rows; y++)
214     {
215       flif_image_read_row_RGBA16(flifimage,y,pixels,length);
216       p=pixels;
217       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
218       if (q == (Quantum *) NULL)
219         break;
220       for (x=0; x < (ssize_t) image->columns; x++)
221       {
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);
227       }
228       if (SyncAuthenticPixels(image,exception) == MagickFalse)
229         break;
230       status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
231         image->rows);
232       if (status == MagickFalse)
233         break;
234     }
235   }
236   flif_destroy_decoder(flifdec);
237   pixels=(unsigned short *) RelinquishMagickMemory(pixels);
238   return(image);
239 }
240 #endif
241 \f
242 /*
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 %                                                                             %
245 %                                                                             %
246 %                                                                             %
247 %   I s F L I F                                                               %
248 %                                                                             %
249 %                                                                             %
250 %                                                                             %
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 %
253 %  IsFLIF() returns MagickTrue if the image format type, identified by the
254 %  magick string, is FLIF.
255 %
256 %  The format of the IsFLIF method is:
257 %
258 %      MagickBooleanType IsFLIF(const unsigned char *magick,
259 %        const size_t length)
260 %
261 %  A description of each parameter follows:
262 %
263 %    o magick: compare image format pattern against these bytes.
264 %
265 %    o length: Specifies the length of the magick string.
266 %
267 */
268 static MagickBooleanType IsFLIF(const unsigned char *magick,
269   const size_t length)
270 {
271   if (length < 4)
272     return(MagickFalse);
273   if (LocaleNCompare((char *) magick,"FLIF",4) == 0)
274     return(MagickTrue);
275   return(MagickFalse);
276 }
277
278 /*
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 %                                                                             %
281 %                                                                             %
282 %                                                                             %
283 %   R e g i s t e r F L I F I m a g e                                         %
284 %                                                                             %
285 %                                                                             %
286 %                                                                             %
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 %
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.
295 %
296 %  The format of the RegisterFLIFImage method is:
297 %
298 %      size_t RegisterFLIFImage(void)
299 %
300 */
301 ModuleExport size_t RegisterFLIFImage(void)
302 {
303   char
304     version[MagickPathExtent];
305
306   MagickInfo
307     *entry;
308
309   *version='\0';
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);
318 #endif
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);
325 }
326 \f
327 /*
328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 %                                                                             %
330 %                                                                             %
331 %                                                                             %
332 %   U n r e g i s t e r F L I F I m a g e                                     %
333 %                                                                             %
334 %                                                                             %
335 %                                                                             %
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 %
338 %  UnregisterFLIFImage() removes format registrations made by the FLIF module
339 %  from the list of supported formats.
340 %
341 %  The format of the UnregisterFLIFImage method is:
342 %
343 %      UnregisterFLIFImage(void)
344 %
345 */
346 ModuleExport void UnregisterFLIFImage(void)
347 {
348   (void) UnregisterMagickInfo("FLIF");
349 }
350
351 #if defined(MAGICKCORE_FLIF_DELEGATE)
352 /*
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 %                                                                             %
355 %                                                                             %
356 %                                                                             %
357 %   W r i t e F L I F I m a g e                                               %
358 %                                                                             %
359 %                                                                             %
360 %                                                                             %
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 %
363 %  WriteFLIFImage() writes an image in the FLIF image format.
364 %
365 %  The format of the WriteFLIFImage method is:
366 %
367 %      MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
368 %        Image *image)
369 %
370 %  A description of each parameter follows.
371 %
372 %    o image_info: the image info.
373 %
374 %    o image:  The image.
375 %
376 */
377 static MagickBooleanType WriteFLIFImage(const ImageInfo *image_info,
378   Image *image, ExceptionInfo *exception)
379 {
380   FLIF_ENCODER
381     *flifenc;
382
383   FLIF_IMAGE
384     *flifimage;
385
386   int
387     flif_status;
388
389   MagickBooleanType
390     status;
391
392   MagickOffsetType
393     scene;
394
395   register const Quantum
396     *magick_restrict p;
397
398   register ssize_t
399     x;
400
401   register unsigned char
402     *magick_restrict qc;
403
404   register unsigned short
405     *magick_restrict qs;
406
407   size_t
408     columns,
409     length,
410     rows;
411
412   ssize_t
413     y;
414
415   void
416     *buffer;
417
418   void
419     *pixels;
420
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)
431     return(status);
432   flifenc=flif_create_encoder();
433   if (image_info->quality != UndefinedCompressionQuality)
434     flif_encoder_set_lossy(flifenc,3*(100-(int32_t) image_info->quality));
435
436   /* relatively fast encoding */
437   flif_encoder_set_learn_repeat(flifenc,1);
438   flif_encoder_set_split_threshold(flifenc,5461*8*5);
439
440   columns=image->columns;
441   rows=image->rows;
442
443   /* Convert image to FLIFIMAGE */
444   if (image->depth > 8)
445     {
446       flifimage=flif_create_image_HDR((uint32_t) image->columns,
447         (uint32_t) image->rows);
448       length=sizeof(unsigned short)*4*image->columns;
449     }
450   else
451     {
452       flifimage=flif_create_image((uint32_t) image->columns,
453         (uint32_t) image->rows);
454       length=sizeof(unsigned char)*4*image->columns;
455     }
456   if (flifimage == (FLIF_IMAGE *) NULL)
457     {
458       flif_destroy_encoder(flifenc);
459       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
460     }
461   pixels=AcquireMagickMemory(length);
462   if (pixels == (void *) NULL)
463     {
464       flif_destroy_image(flifimage);
465       flif_destroy_encoder(flifenc);
466       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
467     }
468   scene=0;
469
470   do
471   {
472     for (y=0; y < (ssize_t) image->rows; y++)
473     {
474       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
475       if (p == (Quantum *) NULL)
476         break;
477
478       if (image->depth > 8)
479         {
480           qs=(unsigned short *) pixels;
481           for (x=0; x < (ssize_t) image->columns; x++)
482           {
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));
488             else
489               *qs++=0xFFFF;
490             p+=GetPixelChannels(image);
491           }
492           flif_image_write_row_RGBA16(flifimage,y,pixels,length);
493         }
494       else
495         {
496           qc=pixels;
497           for (x=0; x < (ssize_t) image->columns; x++)
498           {
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));
504             else
505               *qc++=0xFF;
506             p+=GetPixelChannels(image);
507           }
508           flif_image_write_row_RGBA8(flifimage,y,pixels,length);
509         }
510     }
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)
515       break;
516     image=SyncNextImageInList(image);
517     if ((columns != image->columns) || (rows != image->rows))
518       {
519         flif_destroy_image(flifimage);
520         flif_destroy_encoder(flifenc);
521         pixels=RelinquishMagickMemory(pixels);
522         ThrowWriterException(ImageError,"FramesNotSameDimensions");
523       }
524     scene++;
525     status=SetImageProgress(image,SaveImagesTag,scene,GetImageListLength(
526       image));
527     if (status == MagickFalse)
528        break;
529   } while (image_info->adjoin != MagickFalse);
530
531   flif_destroy_image(flifimage);
532   pixels=RelinquishMagickMemory(pixels);
533   flif_status=flif_encoder_encode_memory(flifenc,&buffer,&length);
534   if (flif_status)
535     WriteBlob(image,length,buffer);
536   CloseBlob(image);
537   flif_destroy_encoder(flifenc);
538   buffer=RelinquishMagickMemory(buffer);
539   return(flif_status == 0 ? MagickFalse : MagickTrue);
540 }
541 #endif