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