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