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