1 /*
2 % Copyright (C) 2003-2020 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
5 %
6 % This program is covered by multiple licenses, which are described in
7 % Copyright.txt. You should have received a copy of Copyright.txt with this
8 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9 %
10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 %                                                                             %
12 %                                                                             %
13 %                                                                             %
14 %                            FFFFF  PPPP   X   X                              %
15 %                            F      P   P   X X                               %
16 %                            FFF    PPPP     X                                %
17 %                            F      P       X X                               %
18 %                            F      P      X   X                              %
19 %                                                                             %
20 %                                                                             %
21 %                     Read/Write FlashPIX Image Format.                       %
22 %                                                                             %
23 %                                                                             %
24 %                              Software Design                                %
25 %                                John Cristy                                  %
26 %                                 July 1992                                   %
27 %                                                                             %
28 %                                                                             %
29 %                                                                             %
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31 %
32 %
33 */
34 
35 /*
36   Include declarations.
37 */
38 #include "magick/studio.h"
39 #include "magick/analyze.h"
40 #include "magick/attribute.h"
41 #include "magick/blob.h"
42 #include "magick/colormap.h"
43 #include "magick/constitute.h"
44 #include "magick/magick.h"
45 #include "magick/monitor.h"
46 #include "magick/pixel_cache.h"
47 #include "magick/utility.h"
48 #if defined(HasFPX)
49 #  if defined(POSIX)
50 #    include <fpxlib.h>
51 #  else
52 #    include "Fpxlib.h"
53 #  endif
54 #endif
55 
56 /*
57   Forward declarations.
58 */
59 static unsigned int
60   WriteFPXImage(const ImageInfo *,Image *);
61 
62 /*
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 %                                                                             %
65 %                                                                             %
66 %                                                                             %
67 %   I s F P X                                                                 %
68 %                                                                             %
69 %                                                                             %
70 %                                                                             %
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %
73 %  Method IsFPX returns True if the image format type, identified by the
74 %  magick string, is FPX.
75 %
76 %  The format of the IsFPX method is:
77 %
78 %      unsigned int IsFPX(const unsigned char *magick,const size_t length)
79 %
80 %  A description of each parameter follows:
81 %
82 %    o status:  Method IsFPX returns True if the image format type is FPX.
83 %
84 %    o magick: This string is generally the first few bytes of an image file
85 %      or blob.
86 %
87 %    o length: Specifies the length of the magick string.
88 %
89 %
90 */
IsFPX(const unsigned char * magick,const size_t length)91 static unsigned int IsFPX(const unsigned char *magick,const size_t length)
92 {
93   if (length < 4)
94     return(False);
95   if (memcmp(magick,"\320\317\021\340",4) == 0)
96     return(True);
97   return(False);
98 }
99 
100 #if defined(HasFPX)
101 /*
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 %                                                                             %
104 %                                                                             %
105 %                                                                             %
106 %   R e a d F P X I m a g e                                                   %
107 %                                                                             %
108 %                                                                             %
109 %                                                                             %
110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 %
112 %  Method ReadFPXImage reads a FlashPix image file and returns it.  It
113 %  allocates the memory necessary for the new Image structure and returns a
114 %  pointer to the new image.  This method was contributed by BillR@corbis.com.
115 %
116 %  The format of the ReadFPXImage method is:
117 %
118 %      Image *ReadFPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
119 %
120 %  A description of each parameter follows:
121 %
122 %    o image:  Method ReadFPXImage returns a pointer to the image after
123 %      reading. A null image is returned if there is a memory shortage or if
124 %      the image cannot be read.
125 %
126 %    o image_info: Specifies a pointer to a ImageInfo structure.
127 %
128 %    o exception: return any errors or warnings in this structure.
129 %
130 %
131 */
ReadFPXImage(const ImageInfo * image_info,ExceptionInfo * exception)132 static Image *ReadFPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
133 {
134   FPXColorspace
135     colorspace;
136 
137   FPXImageComponentDesc
138     *alpha_component,
139     *blue_component,
140     *green_component,
141     *red_component;
142 
143   FPXImageDesc
144     fpx_info;
145 
146   FPXImageHandle
147     *flashpix;
148 
149   FPXStatus
150     fpx_status;
151 
152   FPXSummaryInformation
153     summary_info;
154 
155   Image
156     *image;
157 
158   IndexPacket
159     index;
160 
161   long
162     y;
163 
164   register IndexPacket
165     *indexes;
166 
167   register long
168     i,
169     x;
170 
171   register PixelPacket
172     *q;
173 
174   register unsigned char
175     *a,
176     *b,
177     *g,
178     *r;
179 
180   unsigned char
181     *scanline;
182 
183   unsigned int
184     status,
185     subimage,
186     height,
187     tile_width,
188     tile_height,
189     width;
190 
191   size_t
192     memory_limit;
193 
194   /*
195     Open image.
196   */
197   assert(image_info != (const ImageInfo *) NULL);
198   assert(image_info->signature == MagickSignature);
199   assert(exception != (ExceptionInfo *) NULL);
200   assert(exception->signature == MagickSignature);
201   image=AllocateImage(image_info);
202   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
203   if (status == False)
204     ThrowReaderException(FileOpenError,UnableToOpenFile,image);
205   CloseBlob(image);
206 
207   /*
208     Initialize FPX toolkit.
209   */
210   fpx_status=FPX_InitSystem();
211   if (fpx_status != FPX_OK)
212     {
213       ThrowReaderException(CoderError,UnableToInitializeFPXLibrary,image);
214     }
215   memory_limit=20000000;
216   fpx_status=FPX_SetToolkitMemoryLimit(&memory_limit);
217   if (fpx_status != FPX_OK)
218     {
219       FPX_ClearSystem();
220       ThrowReaderException(CoderError,UnableToInitializeFPXLibrary,image);
221     }
222   tile_width=64;
223   tile_height=64;
224   flashpix=(FPXImageHandle *) NULL;
225   {
226     fpx_status=FPX_OpenImageByFilename(image->filename,(char *) NULL,
227       &width,&height,&tile_width,&tile_height,&colorspace,&flashpix);
228   }
229   if (fpx_status == FPX_LOW_MEMORY_ERROR)
230     {
231       FPX_ClearSystem();
232       ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
233     }
234   if (fpx_status != FPX_OK)
235     {
236       FPX_ClearSystem();
237       ThrowReaderException(FileOpenError,UnableToOpenFile,image);
238     }
239   if (image_info->view == (char *) NULL)
240     {
241       float
242         aspect_ratio;
243 
244       /*
245         Get the aspect ratio.
246       */
247       aspect_ratio=(float) width/height;
248       fpx_status=FPX_GetImageResultAspectRatio(flashpix,&aspect_ratio);
249       if (fpx_status != FPX_OK)
250         ThrowReaderException(CoderError,UnableToReadAspectRatio,image);
251       if (width != (unsigned long) ((aspect_ratio*height)+0.5))
252         Swap(width,height);
253     }
254   fpx_status=FPX_GetSummaryInformation(flashpix,&summary_info);
255   if (fpx_status != FPX_OK)
256     {
257       FPX_ClearSystem();
258       ThrowReaderException(CoderError,UnableToReadSummaryInfo,image);
259     }
260   if (summary_info.title_valid)
261     if ((summary_info.title.length != 0) &&
262         (summary_info.title.ptr != (unsigned char *) NULL))
263       {
264         char
265           *label;
266 
267         /*
268           Note image label.
269         */
270         label=MagickAllocateResourceLimitedMemory(char *,summary_info.title.length+1);
271         if (label == (char *) NULL)
272           {
273             FPX_ClearSystem();
274             ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
275               image);
276           }
277         (void) strlcpy(label,(char *) summary_info.title.ptr,
278           summary_info.title.length+1);
279         (void) SetImageAttribute(image,"label",label);
280         MagickFreeResourceLimitedMemory(label);
281       }
282   if (summary_info.comments_valid)
283     if ((summary_info.comments.length != 0) &&
284         (summary_info.comments.ptr != (unsigned char *) NULL))
285       {
286         char
287           *comments;
288 
289         /*
290           Note image comment.
291         */
292         comments=MagickAllocateResourceLimitedMemory(char *,summary_info.comments.length+1);
293         if (comments == (char *) NULL)
294           {
295             FPX_ClearSystem();
296             ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
297               image);
298           }
299         (void) strlcpy(comments,(char *) summary_info.comments.ptr,
300           summary_info.comments.length+1);
301         (void) SetImageAttribute(image,"comment",comments);
302         MagickFreeResourceLimitedMemory(comments);
303       }
304   /*
305     Determine resolution by subimage specification.
306   */
307   for (i=1; ; i++)
308     if (((width >> i) < tile_width) || ((height >> i) < tile_height))
309       break;
310   subimage=i;
311   if (image_info->subrange != 0)
312     while (subimage > image_info->subimage)
313     {
314       width>>=1;
315       height>>=1;
316       subimage--;
317     }
318   if (image_info->size != (char *) NULL)
319     while ((width > image->columns) || (height > image->rows))
320     {
321       width>>=1;
322       height>>=1;
323       subimage--;
324     }
325   image->depth=8;
326   image->columns=width;
327   image->rows=height;
328   if ((colorspace.numberOfComponents % 2) == 0)
329     image->matte=True;
330   if (colorspace.numberOfComponents == 1)
331     {
332       /*
333         Create linear colormap.
334       */
335       if (!AllocateImageColormap(image,MaxColormapSize))
336         {
337           FPX_ClearSystem();
338           ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
339             image);
340         }
341     }
342   if (image_info->ping)
343     {
344       (void) FPX_CloseImage(flashpix);
345       FPX_ClearSystem();
346       return(image);
347     }
348 
349   if (CheckImagePixelLimits(image, exception) != MagickPass)
350     ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
351 
352   /*
353     Allocate memory for the image and pixel buffer.
354   */
355   scanline=MagickAllocateResourceLimitedMemory(unsigned char *,colorspace.numberOfComponents*
356     image->columns*(tile_height+1));
357   if (scanline == (unsigned char *) NULL)
358     {
359       FPX_ClearSystem();
360       (void) FPX_CloseImage(flashpix);
361       ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
362     }
363   /*
364     Initialize FlashPix image description.
365   */
366   fpx_info.numberOfComponents=colorspace.numberOfComponents;
367   for (i=0; i < 4; i++)
368   {
369     fpx_info.components[i].myColorType.myDataType=DATA_TYPE_UNSIGNED_BYTE;
370     fpx_info.components[i].horzSubSampFactor=1;
371     fpx_info.components[i].vertSubSampFactor=1;
372     fpx_info.components[i].columnStride=fpx_info.numberOfComponents;
373     fpx_info.components[i].lineStride=
374       image->columns*fpx_info.components[i].columnStride;
375     fpx_info.components[i].theData=scanline+i;
376   }
377   fpx_info.components[0].myColorType.myColor=
378     fpx_info.numberOfComponents > 2 ? NIFRGB_R : MONOCHROME;
379   red_component=(&fpx_info.components[0]);
380   fpx_info.components[1].myColorType.myColor=
381     fpx_info.numberOfComponents > 2 ? NIFRGB_G : ALPHA;
382   green_component=(&fpx_info.components[1]);
383   fpx_info.components[2].myColorType.myColor=NIFRGB_B;
384   blue_component=(&fpx_info.components[2]);
385   fpx_info.components[3].myColorType.myColor=ALPHA;
386   alpha_component=(&fpx_info.components[fpx_info.numberOfComponents-1]);
387   FPX_SetResampleMethod(FPX_LINEAR_INTERPOLATION);
388   /*
389     Initialize image pixels.
390   */
391   for (y=0; y < (long) image->rows; y++)
392   {
393     q=SetImagePixels(image,0,y,image->columns,1);
394     if (q == (PixelPacket *) NULL)
395       break;
396     indexes=AccessMutableIndexes(image);
397     if ((y % tile_height) == 0)
398       {
399         /*
400           Read FPX image tile (with or without viewing affine)..
401         */
402         if (image_info->view != (char *) NULL)
403           fpx_status=FPX_ReadImageRectangle(flashpix,0,y,image->columns,y+
404             tile_height-1,subimage,&fpx_info);
405         else
406           fpx_status=FPX_ReadImageTransformRectangle(flashpix,0.0F,
407             (float) y/image->rows,(float) image->columns/image->rows,
408             (float) (y+tile_height-1)/image->rows,(long) image->columns,
409             (long) tile_height,&fpx_info);
410         if (fpx_status == FPX_LOW_MEMORY_ERROR)
411           {
412             MagickFreeResourceLimitedMemory(scanline);
413             (void) FPX_CloseImage(flashpix);
414             FPX_ClearSystem();
415             ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
416               image);
417           }
418       }
419     /*
420       Transfer a FPX scanline.
421     */
422     r=red_component->theData+(y % tile_height)*red_component->lineStride;
423     g=green_component->theData+(y % tile_height)*green_component->lineStride;
424     b=blue_component->theData+(y % tile_height)*blue_component->lineStride;
425     a=alpha_component->theData+(y % tile_height)*alpha_component->lineStride;
426     for (x=0; x < (long) image->columns; x++)
427     {
428       if (fpx_info.numberOfComponents > 2)
429         {
430           q->red=ScaleCharToQuantum(*r);
431           q->green=ScaleCharToQuantum(*g);
432           q->blue=ScaleCharToQuantum(*b);
433         }
434       else
435         {
436           index=ScaleCharToQuantum(*r);
437           indexes[x]=index;
438           q->red=index;
439           q->green=index;
440           q->blue=index;
441         }
442       if (image->matte)
443         q->opacity=ScaleCharToQuantum(255-*a);
444       q++;
445       r+=red_component->columnStride;
446       g+=green_component->columnStride;
447       b+=blue_component->columnStride;
448       a+=alpha_component->columnStride;
449     }
450     if (!SyncImagePixels(image))
451       break;
452     if (QuantumTick(y,image->rows))
453       if (!MagickMonitor(LoadImageText,y,image->rows,exception))
454         break;
455   }
456   MagickFreeResourceLimitedMemory(scanline);
457   (void) FPX_CloseImage(flashpix);
458   FPX_ClearSystem();
459   StopTimer(&image->timer);
460   return(image);
461 }
462 #else
ReadFPXImage(const ImageInfo * image_info,ExceptionInfo * exception)463 static Image *ReadFPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
464 {
465   ThrowException(exception,MissingDelegateError,FPXLibraryIsNotAvailable,
466     image_info->filename);
467   return((Image *) NULL);
468 }
469 #endif
470 
471 /*
472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 %                                                                             %
474 %                                                                             %
475 %                                                                             %
476 %   R e g i s t e r F P X I m a g e                                           %
477 %                                                                             %
478 %                                                                             %
479 %                                                                             %
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481 %
482 %  Method RegisterFPXImage adds attributes for the FPX image format to
483 %  the list of supported formats.  The attributes include the image format
484 %  tag, a method to read and/or write the format, whether the format
485 %  supports the saving of more than one frame to the same file or blob,
486 %  whether the format supports native in-memory I/O, and a brief
487 %  description of the format.
488 %
489 %  The format of the RegisterFPXImage method is:
490 %
491 %      RegisterFPXImage(void)
492 %
493 */
RegisterFPXImage(void)494 ModuleExport void RegisterFPXImage(void)
495 {
496   MagickInfo
497     *entry;
498 
499   entry=SetMagickInfo("FPX");
500   entry->decoder=(DecoderHandler) ReadFPXImage;
501   entry->encoder=(EncoderHandler) WriteFPXImage;
502   entry->adjoin=False;
503   entry->seekable_stream=True;
504   entry->blob_support=False;
505   entry->magick=(MagickHandler) IsFPX;
506   entry->description="FlashPix Format";
507   entry->module="FPX";
508   (void) RegisterMagickInfo(entry);
509 }
510 
511 /*
512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
513 %                                                                             %
514 %                                                                             %
515 %                                                                             %
516 %   U n r e g i s t e r F P X I m a g e                                       %
517 %                                                                             %
518 %                                                                             %
519 %                                                                             %
520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
521 %
522 %  Method UnregisterFPXImage removes format registrations made by the
523 %  FPX module from the list of supported formats.
524 %
525 %  The format of the UnregisterFPXImage method is:
526 %
527 %      UnregisterFPXImage(void)
528 %
529 */
UnregisterFPXImage(void)530 ModuleExport void UnregisterFPXImage(void)
531 {
532   (void) UnregisterMagickInfo("FPX");
533 }
534 
535 #if defined(HasFPX)
536 /*
537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538 %                                                                             %
539 %                                                                             %
540 %                                                                             %
541 %   W r i t e F P X I m a g e                                                 %
542 %                                                                             %
543 %                                                                             %
544 %                                                                             %
545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546 %
547 %  Method WriteFPXImage writes an image in the FlashPix image format.  This
548 %  method was contributed by BillR@corbis.com.
549 %
550 %  The format of the WriteFPXImage method is:
551 %
552 %      unsigned int WriteFPXImage(const ImageInfo *image_info,Image *image)
553 %
554 %  A description of each parameter follows.
555 %
556 %    o fpx_status: Method WriteFPXImage return True if the image is written.
557 %      False is returned is there is a memory shortage or if the image file
558 %      fails to write.
559 %
560 %    o image_info: Specifies a pointer to a ImageInfo structure.
561 %
562 %    o image:  A pointer to an Image structure.
563 %
564 %
565 */
566 
ColorTwistMultiply(FPXColorTwistMatrix first,FPXColorTwistMatrix second,FPXColorTwistMatrix * color_twist)567 static void ColorTwistMultiply(FPXColorTwistMatrix first,
568   FPXColorTwistMatrix second,FPXColorTwistMatrix *color_twist)
569 {
570   /*
571     Matrix multiply.
572   */
573   assert(color_twist != (FPXColorTwistMatrix *) NULL);
574   color_twist->byy=(first.byy*second.byy)+(first.byc1*second.bc1y)+
575     (first.byc2*second.bc2y)+(first.dummy1_zero*second.dummy4_zero);
576   color_twist->byc1=(first.byy*second.byc1)+(first.byc1*second.bc1c1)+
577     (first.byc2*second.bc2c1)+(first.dummy1_zero*second.dummy5_zero);
578   color_twist->byc2=(first.byy*second.byc2)+(first.byc1*second.bc1c2)+
579     (first.byc2*second.bc2c2)+(first.dummy1_zero*second.dummy6_zero);
580   color_twist->dummy1_zero=(first.byy*second.dummy1_zero)+
581     (first.byc1*second.dummy2_zero)+(first.byc2*second.dummy3_zero)+
582     (first.dummy1_zero*second.dummy7_one);
583   color_twist->bc1y=(first.bc1y*second.byy)+(first.bc1c1*second.bc1y)+
584     (first.bc1c2*second.bc2y)+(first.dummy2_zero*second.dummy4_zero);
585   color_twist->bc1c1=(first.bc1y*second.byc1)+(first.bc1c1*second.bc1c1)+
586     (first.bc1c2*second.bc2c1)+(first.dummy2_zero*second.dummy5_zero);
587   color_twist->bc1c2=(first.bc1y*second.byc2)+(first.bc1c1*second.bc1c2)+
588     (first.bc1c2*second.bc2c2)+(first.dummy2_zero*second.dummy6_zero);
589   color_twist->dummy2_zero=(first.bc1y*second.dummy1_zero)+
590     (first.bc1c1*second.dummy2_zero)+(first.bc1c2*second.dummy3_zero)+
591     (first.dummy2_zero*second.dummy7_one);
592   color_twist->bc2y=(first.bc2y*second.byy)+(first.bc2c1*second.bc1y)+
593     (first.bc2c2*second.bc2y)+(first.dummy3_zero*second.dummy4_zero);
594   color_twist->bc2c1=(first.bc2y*second.byc1)+(first.bc2c1*second.bc1c1)+
595     (first.bc2c2*second.bc2c1)+(first.dummy3_zero*second.dummy5_zero);
596   color_twist->bc2c2=(first.bc2y*second.byc2)+(first.bc2c1*second.bc1c2)+
597     (first.bc2c2*second.bc2c2)+(first.dummy3_zero*second.dummy6_zero);
598   color_twist->dummy3_zero=(first.bc2y*second.dummy1_zero)+
599     (first.bc2c1*second.dummy2_zero)+(first.bc2c2*second.dummy3_zero)+
600     (first.dummy3_zero*second.dummy7_one);
601   color_twist->dummy4_zero=(first.dummy4_zero*second.byy)+
602     (first.dummy5_zero*second.bc1y)+(first.dummy6_zero*second.bc2y)+
603     (first.dummy7_one*second.dummy4_zero);
604   color_twist->dummy5_zero=(first.dummy4_zero*second.byc1)+
605     (first.dummy5_zero*second.bc1c1)+(first.dummy6_zero*second.bc2c1)+
606     (first.dummy7_one*second.dummy5_zero);
607   color_twist->dummy6_zero=(first.dummy4_zero*second.byc2)+
608     (first.dummy5_zero*second.bc1c2)+(first.dummy6_zero*second.bc2c2)+
609     (first.dummy7_one*second.dummy6_zero);
610   color_twist->dummy7_one=(first.dummy4_zero*second.dummy1_zero)+
611     (first.dummy5_zero*second.dummy2_zero)+
612     (first.dummy6_zero*second.dummy3_zero)+(first.dummy7_one*second.dummy7_one);
613 }
614 
SetBrightness(double brightness,FPXColorTwistMatrix * color_twist)615 static void SetBrightness(double brightness,FPXColorTwistMatrix *color_twist)
616 {
617   FPXColorTwistMatrix
618     effect,
619     result;
620 
621   /*
622     Set image brightness in color twist matrix.
623   */
624   assert(color_twist != (FPXColorTwistMatrix *) NULL);
625   brightness=sqrt((double) brightness);
626   effect.byy=brightness;
627   effect.byc1=0.0;
628   effect.byc2=0.0;
629   effect.dummy1_zero=0.0;
630   effect.bc1y=0.0;
631   effect.bc1c1=brightness;
632   effect.bc1c2=0.0;
633   effect.dummy2_zero=0.0;
634   effect.bc2y=0.0;
635   effect.bc2c1=0.0;
636   effect.bc2c2=brightness;
637   effect.dummy3_zero=0.0;
638   effect.dummy4_zero=0.0;
639   effect.dummy5_zero=0.0;
640   effect.dummy6_zero=0.0;
641   effect.dummy7_one=1.0;
642   ColorTwistMultiply(*color_twist,effect,&result);
643   *color_twist=result;
644 }
645 
SetColorBalance(double red,double green,double blue,FPXColorTwistMatrix * color_twist)646 static void SetColorBalance(double red,double green,double blue,
647   FPXColorTwistMatrix *color_twist)
648 {
649   FPXColorTwistMatrix
650     blue_effect,
651     green_effect,
652     result,
653     rgb_effect,
654     rg_effect,
655     red_effect;
656 
657   /*
658     Set image color balance in color twist matrix.
659   */
660   assert(color_twist != (FPXColorTwistMatrix *) NULL);
661   red=sqrt((double) red)-1.0;
662   green=sqrt((double) green)-1.0;
663   blue=sqrt((double) blue)-1.0;
664   red_effect.byy=1.0;
665   red_effect.byc1=0.0;
666   red_effect.byc2=0.299*red;
667   red_effect.dummy1_zero=0.0;
668   red_effect.bc1y=(-0.299)*red;
669   red_effect.bc1c1=1.0-0.299*red;
670   red_effect.bc1c2=(-0.299)*red;
671   red_effect.dummy2_zero=0.0;
672   red_effect.bc2y=0.701*red;
673   red_effect.bc2c1=0.0;
674   red_effect.bc2c2=1.0+0.402*red;
675   red_effect.dummy3_zero=0.0;
676   red_effect.dummy4_zero=0.0;
677   red_effect.dummy5_zero=0.0;
678   red_effect.dummy6_zero=0.0;
679   red_effect.dummy7_one=1.0;
680   green_effect.byy=1.0;
681   green_effect.byc1=(-0.114)*green;
682   green_effect.byc2=(-0.299)*green;
683   green_effect.dummy1_zero=0.0;
684   green_effect.bc1y=(-0.587)*green;
685   green_effect.bc1c1=1.0-0.473*green;
686   green_effect.bc1c2=0.299*green;
687   green_effect.dummy2_zero=0.0;
688   green_effect.bc2y=(-0.587)*green;
689   green_effect.bc2c1=0.114*green;
690   green_effect.bc2c2=1.0-0.288*green;
691   green_effect.dummy3_zero=0.0;
692   green_effect.dummy4_zero=0.0;
693   green_effect.dummy5_zero=0.0;
694   green_effect.dummy6_zero=0.0;
695   green_effect.dummy7_one=1.0;
696   blue_effect.byy=1.0;
697   blue_effect.byc1=0.114*blue;
698   blue_effect.byc2=0.0;
699   blue_effect.dummy1_zero=0.0;
700   blue_effect.bc1y=0.886*blue;
701   blue_effect.bc1c1=1.0+0.772*blue;
702   blue_effect.bc1c2=0.0;
703   blue_effect.dummy2_zero=0.0;
704   blue_effect.bc2y=(-0.114)*blue;
705   blue_effect.bc2c1=(-0.114)*blue;
706   blue_effect.bc2c2=1.0-0.114*blue;
707   blue_effect.dummy3_zero=0.0;
708   blue_effect.dummy4_zero=0.0;
709   blue_effect.dummy5_zero=0.0;
710   blue_effect.dummy6_zero=0.0;
711   blue_effect.dummy7_one=1.0;
712   ColorTwistMultiply(red_effect,green_effect,&rg_effect);
713   ColorTwistMultiply(rg_effect,blue_effect,&rgb_effect);
714   ColorTwistMultiply(*color_twist,rgb_effect,&result);
715   *color_twist=result;
716 }
717 
SetSaturation(double saturation,FPXColorTwistMatrix * color_twist)718 static void SetSaturation(double saturation,FPXColorTwistMatrix *color_twist)
719 {
720   FPXColorTwistMatrix
721     effect,
722     result;
723 
724   /*
725     Set image saturation in color twist matrix.
726   */
727   assert(color_twist != (FPXColorTwistMatrix *) NULL);
728   effect.byy=1.0;
729   effect.byc1=0.0;
730   effect.byc2=0.0;
731   effect.dummy1_zero=0.0;
732   effect.bc1y=0.0;
733   effect.bc1c1=saturation;
734   effect.bc1c2=0.0;
735   effect.dummy2_zero=0.0;
736   effect.bc2y=0.0;
737   effect.bc2c1=0.0;
738   effect.bc2c2=saturation;
739   effect.dummy3_zero=0.0;
740   effect.dummy4_zero=0.0;
741   effect.dummy5_zero=0.0;
742   effect.dummy6_zero=0.0;
743   effect.dummy7_one=1.0;
744   ColorTwistMultiply(*color_twist,effect,&result);
745   *color_twist=result;
746 }
747 
WriteFPXImage(const ImageInfo * image_info,Image * image)748 static unsigned int WriteFPXImage(const ImageInfo *image_info,Image *image)
749 {
750   FPXBackground
751     background_color;
752 
753   FPXColorspace
754     colorspace =
755     {
756       TRUE, 4,
757       {
758         { NIFRGB_R, DATA_TYPE_UNSIGNED_BYTE },
759         { NIFRGB_G, DATA_TYPE_UNSIGNED_BYTE },
760         { NIFRGB_B, DATA_TYPE_UNSIGNED_BYTE },
761         { ALPHA, DATA_TYPE_UNSIGNED_BYTE }
762       }
763     };
764 
765   const ImageAttribute
766     *comment,
767     *label;
768 
769   FPXCompressionOption
770     compression;
771 
772   FPXImageDesc
773     fpx_info;
774 
775   FPXImageHandle
776     *flashpix;
777 
778   FPXStatus
779     fpx_status;
780 
781   FPXSummaryInformation
782     summary_info;
783 
784   long
785     y;
786 
787   register long
788     i;
789 
790   unsigned char
791     *pixels;
792 
793   size_t
794     memory_limit;
795 
796   unsigned long
797     tile_height,
798     tile_width;
799 
800   /*
801     Open output file.
802   */
803   assert(image_info != (const ImageInfo *) NULL);
804   assert(image_info->signature == MagickSignature);
805   assert(image != (Image *) NULL);
806   assert(image->signature == MagickSignature);
807   /*
808     Initialize FPX toolkit.
809   */
810   image->depth=8;
811   (void) TransformColorspace(image,RGBColorspace);
812   memory_limit=20000000;
813   fpx_status=FPX_SetToolkitMemoryLimit(&memory_limit);
814   if (fpx_status != FPX_OK)
815     ThrowWriterException(DelegateError,UnableToInitializeFPXLibrary,image);
816   tile_width=64;
817   tile_height=64;
818   colorspace.numberOfComponents=3;
819   if (image->matte)
820     colorspace.numberOfComponents=4;
821   if ((image_info->type != TrueColorType) &&
822       IsGrayImage(image,&image->exception))
823     {
824       colorspace.numberOfComponents=1;
825       colorspace.theComponents[0].myColor=MONOCHROME;
826     }
827   background_color.color1_value=0;
828   background_color.color2_value=0;
829   background_color.color3_value=0;
830   background_color.color4_value=0;
831   compression=NONE;
832   if (image_info->compression == JPEGCompression)
833     compression=JPEG_UNSPECIFIED;
834   {
835     fpx_status=FPX_CreateImageByFilename(image->filename,image->columns,
836       image->rows,tile_width,tile_height,colorspace,background_color,
837       compression,&flashpix);
838   }
839   if (fpx_status != FPX_OK)
840     ThrowWriterException(FileOpenError,UnableToOpenFile,image);
841   if (image_info->compression == JPEGCompression)
842     {
843       /*
844         Initialize the compression by quality for the entire image.
845       */
846       fpx_status=
847         FPX_SetJPEGCompression(flashpix,(unsigned short) (image_info->quality));
848       if (fpx_status != FPX_OK)
849         ThrowWriterException(CoderError,UnableToSetJPEGLevel,image);
850     }
851   /*
852     Set image summary info.
853   */
854   summary_info.title_valid=False;
855   summary_info.subject_valid=False;
856   summary_info.author_valid=False;
857   summary_info.comments_valid=False;
858   summary_info.keywords_valid=False;
859   summary_info.OLEtemplate_valid=False;
860   summary_info.last_author_valid=False;
861   summary_info.rev_number_valid=False;
862   summary_info.edit_time_valid=False;
863   summary_info.last_printed_valid=False;
864   summary_info.create_dtm_valid=False;
865   summary_info.last_save_dtm_valid=False;
866   summary_info.page_count_valid=False;
867   summary_info.word_count_valid=False;
868   summary_info.char_count_valid=False;
869   summary_info.thumbnail_valid=False;
870   summary_info.appname_valid=False;
871   summary_info.security_valid=False;
872   label=GetImageAttribute(image,"label");
873   if (label != (ImageAttribute *) NULL)
874     {
875       /*
876         Note image label.
877       */
878       summary_info.title_valid=True;
879       summary_info.title.length=strlen(label->value);
880       summary_info.title.ptr=MagickAllocateMemory(unsigned char *,
881         strlen(label->value)+1);
882       if (summary_info.title.ptr != (unsigned char *) NULL)
883         (void) strlcpy((char *) summary_info.title.ptr,label->value,
884           MaxTextExtent);
885       else
886         ThrowWriterException(CoderError,UnableToSetImageTitle,image);
887     }
888   comment=GetImageAttribute(image,"comment");
889   if (comment != (ImageAttribute *) NULL)
890     {
891       /*
892         Note image comment.
893       */
894       summary_info.comments_valid=True;
895       summary_info.comments.length=strlen(comment->value);
896       summary_info.comments.ptr=MagickAllocateMemory(unsigned char *,
897         strlen(comment->value)+1);
898       if (summary_info.comments.ptr != (unsigned char *) NULL)
899         (void) strcpy((char *) summary_info.comments.ptr,comment->value);
900       else
901         ThrowWriterException(CoderError,UnableToSetImageComments,image);
902     }
903   fpx_status=FPX_SetSummaryInformation(flashpix,&summary_info);
904   if (fpx_status != FPX_OK)
905     ThrowWriterException(CoderError,UnableToSetSummaryInfo,image);
906   /*
907     Allocate pixels.
908   */
909   pixels=MagickAllocateResourceLimitedMemory(unsigned char *,
910     colorspace.numberOfComponents*image->columns);
911   if (pixels == (unsigned char *) NULL)
912     {
913       (void) FPX_CloseImage(flashpix);
914       FPX_ClearSystem();
915       ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
916     }
917   /*
918     Initialize FlashPix image description.
919   */
920   fpx_info.numberOfComponents=colorspace.numberOfComponents;
921   for (i=0; i < (long) fpx_info.numberOfComponents; i++)
922   {
923     fpx_info.components[i].myColorType.myDataType=DATA_TYPE_UNSIGNED_BYTE;
924     fpx_info.components[i].horzSubSampFactor=1;
925     fpx_info.components[i].vertSubSampFactor=1;
926     fpx_info.components[i].columnStride=fpx_info.numberOfComponents;
927     fpx_info.components[i].lineStride=
928       image->columns*fpx_info.components[i].columnStride;
929     fpx_info.components[i].theData=pixels+i;
930   }
931   fpx_info.components[0].myColorType.myColor=
932     fpx_info.numberOfComponents != 1 ? NIFRGB_R : MONOCHROME;
933   fpx_info.components[1].myColorType.myColor=NIFRGB_G;
934   fpx_info.components[2].myColorType.myColor=NIFRGB_B;
935   fpx_info.components[3].myColorType.myColor=ALPHA;
936   /*
937     Write image scanlines.
938   */
939   for (y=0; y < (long) image->rows; y++)
940   {
941     if (!AcquireImagePixels(image,0,y,image->columns,1,&image->exception))
942       break;
943     if (fpx_info.numberOfComponents == 1)
944       (void) ExportImagePixelArea(image,GrayQuantum,8,pixels,0,0);
945     else
946       if (!image->matte)
947         (void) ExportImagePixelArea(image,RGBQuantum,8,pixels,0,0);
948       else
949         (void) ExportImagePixelArea(image,RGBAQuantum,8,pixels,0,0);
950     fpx_status=FPX_WriteImageLine(flashpix,&fpx_info);
951     if (fpx_status != FPX_OK)
952       break;
953     if (QuantumTick(y,image->rows))
954       if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
955         break;
956   }
957   if (image_info->view != (char *) NULL)
958     {
959       FPXAffineMatrix
960         affine;
961 
962       FPXColorTwistMatrix
963         color_twist;
964 
965       FPXContrastAdjustment
966         contrast;
967 
968       FPXFilteringValue
969         sharpen;
970 
971       FPXResultAspectRatio
972         aspect_ratio;
973 
974       FPXROI
975         view_rect;
976 
977       unsigned int
978         affine_valid,
979         aspect_ratio_valid,
980         color_twist_valid,
981         contrast_valid,
982         sharpen_valid,
983         view_rect_valid;
984 
985       /*
986         Initialize default viewing parameters.
987       */
988       contrast=1.0;
989       contrast_valid=False;
990       color_twist.byy=1.0;
991       color_twist.byc1=0.0;
992       color_twist.byc2=0.0;
993       color_twist.dummy1_zero=0.0;
994       color_twist.bc1y=0.0;
995       color_twist.bc1c1=1.0;
996       color_twist.bc1c2=0.0;
997       color_twist.dummy2_zero=0.0;
998       color_twist.bc2y=0.0;
999       color_twist.bc2c1=0.0;
1000       color_twist.bc2c2=1.0;
1001       color_twist.dummy3_zero=0.0;
1002       color_twist.dummy4_zero=0.0;
1003       color_twist.dummy5_zero=0.0;
1004       color_twist.dummy6_zero=0.0;
1005       color_twist.dummy7_one=1.0;
1006       color_twist_valid=False;
1007       sharpen=0.0;
1008       sharpen_valid=False;
1009       aspect_ratio=(double) image->columns/image->rows;
1010       aspect_ratio_valid=False;
1011       view_rect.left=(float) 0.1;
1012       view_rect.width=aspect_ratio-0.2;
1013       view_rect.top=(float) 0.1;
1014       view_rect.height=(float) 0.8; /* 1.0-0.2 */
1015       view_rect_valid=False;
1016       affine.a11=1.0;
1017       affine.a12=0.0;
1018       affine.a13=0.0;
1019       affine.a14=0.0;
1020       affine.a21=0.0;
1021       affine.a22=1.0;
1022       affine.a23=0.0;
1023       affine.a24=0.0;
1024       affine.a31=0.0;
1025       affine.a32=0.0;
1026       affine.a33=1.0;
1027       affine.a34=0.0;
1028       affine.a41=0.0;
1029       affine.a42=0.0;
1030       affine.a43=0.0;
1031       affine.a44=1.0;
1032       affine_valid=False;
1033       if (0)
1034         {
1035           /*
1036             Color color twist.
1037           */
1038           SetBrightness(0.5,&color_twist);
1039           SetSaturation(0.5,&color_twist);
1040           SetColorBalance(0.5,1.0,1.0,&color_twist);
1041           color_twist_valid=True;
1042         }
1043       if (affine_valid)
1044         {
1045           fpx_status=FPX_SetImageAffineMatrix(flashpix,&affine);
1046           if (fpx_status != FPX_OK)
1047             ThrowWriterException(CoderError,UnableToSetAffineMatrix,image);
1048         }
1049       if (aspect_ratio_valid)
1050         {
1051           fpx_status=FPX_SetImageResultAspectRatio(flashpix,&aspect_ratio);
1052           if (fpx_status != FPX_OK)
1053             ThrowWriterException(CoderError,UnableToSetAspectRatio,image);
1054         }
1055       if (color_twist_valid)
1056         {
1057           fpx_status=FPX_SetImageColorTwistMatrix(flashpix,&color_twist);
1058           if (fpx_status != FPX_OK)
1059             ThrowWriterException(CoderError,UnableToSetColorTwist,image);
1060         }
1061       if (contrast_valid)
1062         {
1063           fpx_status=FPX_SetImageContrastAdjustment(flashpix,&contrast);
1064           if (fpx_status != FPX_OK)
1065             ThrowWriterException(CoderError,UnableToSetContrast,image);
1066         }
1067       if (sharpen_valid)
1068         {
1069           fpx_status=FPX_SetImageFilteringValue(flashpix,&sharpen);
1070           if (fpx_status != FPX_OK)
1071             ThrowWriterException(CoderError,UnableToSetFilteringValue,
1072               image);
1073         }
1074       if (view_rect_valid)
1075         {
1076           fpx_status=FPX_SetImageROI(flashpix,&view_rect);
1077           if (fpx_status != FPX_OK)
1078             ThrowWriterException(CoderError,UnableToSetRegionOfInterest,
1079               image);
1080         }
1081     }
1082   (void) FPX_CloseImage(flashpix);
1083   FPX_ClearSystem();
1084   MagickFreeResourceLimitedMemory(pixels);
1085   return(True);
1086 }
1087 #else
WriteFPXImage(const ImageInfo * image_info,Image * image)1088 static unsigned int WriteFPXImage(const ImageInfo *image_info,Image *image)
1089 {
1090   ThrowBinaryException(MissingDelegateError,FPXLibraryIsNotAvailable,
1091     image->filename)
1092 }
1093 #endif
1094