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-2016 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 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|=CoderSeekableStreamFlag; 511 entry->flags^=CoderBlobSupportFlag; 512 (void) RegisterMagickInfo(entry); 513 return(MagickImageCoderSignature); 514 } 515 516 /* 518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 519 % % 520 % % 521 % % 522 % U n r e g i s t e r F P X I m a g e % 523 % % 524 % % 525 % % 526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 527 % 528 % UnregisterFPXImage() removes format registrations made by the 529 % FPX module from the list of supported formats. 530 % 531 % The format of the UnregisterFPXImage method is: 532 % 533 % UnregisterFPXImage(void) 534 % 535 */ 536 ModuleExport void UnregisterFPXImage(void) 537 { 538 (void) UnregisterMagickInfo("FPX"); 539 } 540 541 #if defined(MAGICKCORE_FPX_DELEGATE) 543 /* 544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 545 % % 546 % % 547 % % 548 % W r i t e F P X I m a g e % 549 % % 550 % % 551 % % 552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 553 % 554 % WriteFPXImage() writes an image in the FlashPix image format. This 555 % method was contributed by BillR (at) corbis.com. 556 % 557 % The format of the WriteFPXImage method is: 558 % 559 % MagickBooleanType WriteFPXImage(const ImageInfo *image_info, 560 % Image *image,ExceptionInfo *exception) 561 % 562 % A description of each parameter follows. 563 % 564 % o image_info: the image info. 565 % 566 % o image: The image. 567 % 568 % o exception: return any errors or warnings in this structure. 569 % 570 */ 571 572 static void ColorTwistMultiply(FPXColorTwistMatrix first, 573 FPXColorTwistMatrix second,FPXColorTwistMatrix *color_twist) 574 { 575 /* 576 Matrix multiply. 577 */ 578 assert(color_twist != (FPXColorTwistMatrix *) NULL); 579 color_twist->byy=(first.byy*second.byy)+(first.byc1*second.bc1y)+ 580 (first.byc2*second.bc2y)+(first.dummy1_zero*second.dummy4_zero); 581 color_twist->byc1=(first.byy*second.byc1)+(first.byc1*second.bc1c1)+ 582 (first.byc2*second.bc2c1)+(first.dummy1_zero*second.dummy5_zero); 583 color_twist->byc2=(first.byy*second.byc2)+(first.byc1*second.bc1c2)+ 584 (first.byc2*second.bc2c2)+(first.dummy1_zero*second.dummy6_zero); 585 color_twist->dummy1_zero=(first.byy*second.dummy1_zero)+ 586 (first.byc1*second.dummy2_zero)+(first.byc2*second.dummy3_zero)+ 587 (first.dummy1_zero*second.dummy7_one); 588 color_twist->bc1y=(first.bc1y*second.byy)+(first.bc1c1*second.bc1y)+ 589 (first.bc1c2*second.bc2y)+(first.dummy2_zero*second.dummy4_zero); 590 color_twist->bc1c1=(first.bc1y*second.byc1)+(first.bc1c1*second.bc1c1)+ 591 (first.bc1c2*second.bc2c1)+(first.dummy2_zero*second.dummy5_zero); 592 color_twist->bc1c2=(first.bc1y*second.byc2)+(first.bc1c1*second.bc1c2)+ 593 (first.bc1c2*second.bc2c2)+(first.dummy2_zero*second.dummy6_zero); 594 color_twist->dummy2_zero=(first.bc1y*second.dummy1_zero)+ 595 (first.bc1c1*second.dummy2_zero)+(first.bc1c2*second.dummy3_zero)+ 596 (first.dummy2_zero*second.dummy7_one); 597 color_twist->bc2y=(first.bc2y*second.byy)+(first.bc2c1*second.bc1y)+ 598 (first.bc2c2*second.bc2y)+(first.dummy3_zero*second.dummy4_zero); 599 color_twist->bc2c1=(first.bc2y*second.byc1)+(first.bc2c1*second.bc1c1)+ 600 (first.bc2c2*second.bc2c1)+(first.dummy3_zero*second.dummy5_zero); 601 color_twist->bc2c2=(first.bc2y*second.byc2)+(first.bc2c1*second.bc1c2)+ 602 (first.bc2c2*second.bc2c2)+(first.dummy3_zero*second.dummy6_zero); 603 color_twist->dummy3_zero=(first.bc2y*second.dummy1_zero)+ 604 (first.bc2c1*second.dummy2_zero)+(first.bc2c2*second.dummy3_zero)+ 605 (first.dummy3_zero*second.dummy7_one); 606 color_twist->dummy4_zero=(first.dummy4_zero*second.byy)+ 607 (first.dummy5_zero*second.bc1y)+(first.dummy6_zero*second.bc2y)+ 608 (first.dummy7_one*second.dummy4_zero); 609 color_twist->dummy5_zero=(first.dummy4_zero*second.byc1)+ 610 (first.dummy5_zero*second.bc1c1)+(first.dummy6_zero*second.bc2c1)+ 611 (first.dummy7_one*second.dummy5_zero); 612 color_twist->dummy6_zero=(first.dummy4_zero*second.byc2)+ 613 (first.dummy5_zero*second.bc1c2)+(first.dummy6_zero*second.bc2c2)+ 614 (first.dummy7_one*second.dummy6_zero); 615 color_twist->dummy7_one=(first.dummy4_zero*second.dummy1_zero)+ 616 (first.dummy5_zero*second.dummy2_zero)+ 617 (first.dummy6_zero*second.dummy3_zero)+(first.dummy7_one*second.dummy7_one); 618 } 619 620 static void SetBrightness(double brightness,FPXColorTwistMatrix *color_twist) 621 { 622 FPXColorTwistMatrix 623 effect, 624 result; 625 626 /* 627 Set image brightness in color twist matrix. 628 */ 629 assert(color_twist != (FPXColorTwistMatrix *) NULL); 630 brightness=sqrt((double) brightness); 631 effect.byy=brightness; 632 effect.byc1=0.0; 633 effect.byc2=0.0; 634 effect.dummy1_zero=0.0; 635 effect.bc1y=0.0; 636 effect.bc1c1=brightness; 637 effect.bc1c2=0.0; 638 effect.dummy2_zero=0.0; 639 effect.bc2y=0.0; 640 effect.bc2c1=0.0; 641 effect.bc2c2=brightness; 642 effect.dummy3_zero=0.0; 643 effect.dummy4_zero=0.0; 644 effect.dummy5_zero=0.0; 645 effect.dummy6_zero=0.0; 646 effect.dummy7_one=1.0; 647 ColorTwistMultiply(*color_twist,effect,&result); 648 *color_twist=result; 649 } 650 651 static void SetColorBalance(double red,double green,double blue, 652 FPXColorTwistMatrix *color_twist) 653 { 654 FPXColorTwistMatrix 655 blue_effect, 656 green_effect, 657 result, 658 rgb_effect, 659 rg_effect, 660 red_effect; 661 662 /* 663 Set image color balance in color twist matrix. 664 */ 665 assert(color_twist != (FPXColorTwistMatrix *) NULL); 666 red=sqrt((double) red)-1.0; 667 green=sqrt((double) green)-1.0; 668 blue=sqrt((double) blue)-1.0; 669 red_effect.byy=1.0; 670 red_effect.byc1=0.0; 671 red_effect.byc2=0.299*red; 672 red_effect.dummy1_zero=0.0; 673 red_effect.bc1y=(-0.299)*red; 674 red_effect.bc1c1=1.0-0.299*red; 675 red_effect.bc1c2=(-0.299)*red; 676 red_effect.dummy2_zero=0.0; 677 red_effect.bc2y=0.701*red; 678 red_effect.bc2c1=0.0; 679 red_effect.bc2c2=1.0+0.402*red; 680 red_effect.dummy3_zero=0.0; 681 red_effect.dummy4_zero=0.0; 682 red_effect.dummy5_zero=0.0; 683 red_effect.dummy6_zero=0.0; 684 red_effect.dummy7_one=1.0; 685 green_effect.byy=1.0; 686 green_effect.byc1=(-0.114)*green; 687 green_effect.byc2=(-0.299)*green; 688 green_effect.dummy1_zero=0.0; 689 green_effect.bc1y=(-0.587)*green; 690 green_effect.bc1c1=1.0-0.473*green; 691 green_effect.bc1c2=0.299*green; 692 green_effect.dummy2_zero=0.0; 693 green_effect.bc2y=(-0.587)*green; 694 green_effect.bc2c1=0.114*green; 695 green_effect.bc2c2=1.0-0.288*green; 696 green_effect.dummy3_zero=0.0; 697 green_effect.dummy4_zero=0.0; 698 green_effect.dummy5_zero=0.0; 699 green_effect.dummy6_zero=0.0; 700 green_effect.dummy7_one=1.0; 701 blue_effect.byy=1.0; 702 blue_effect.byc1=0.114*blue; 703 blue_effect.byc2=0.0; 704 blue_effect.dummy1_zero=0.0; 705 blue_effect.bc1y=0.886*blue; 706 blue_effect.bc1c1=1.0+0.772*blue; 707 blue_effect.bc1c2=0.0; 708 blue_effect.dummy2_zero=0.0; 709 blue_effect.bc2y=(-0.114)*blue; 710 blue_effect.bc2c1=(-0.114)*blue; 711 blue_effect.bc2c2=1.0-0.114*blue; 712 blue_effect.dummy3_zero=0.0; 713 blue_effect.dummy4_zero=0.0; 714 blue_effect.dummy5_zero=0.0; 715 blue_effect.dummy6_zero=0.0; 716 blue_effect.dummy7_one=1.0; 717 ColorTwistMultiply(red_effect,green_effect,&rg_effect); 718 ColorTwistMultiply(rg_effect,blue_effect,&rgb_effect); 719 ColorTwistMultiply(*color_twist,rgb_effect,&result); 720 *color_twist=result; 721 } 722 723 static void SetSaturation(double saturation,FPXColorTwistMatrix *color_twist) 724 { 725 FPXColorTwistMatrix 726 effect, 727 result; 728 729 /* 730 Set image saturation in color twist matrix. 731 */ 732 assert(color_twist != (FPXColorTwistMatrix *) NULL); 733 effect.byy=1.0; 734 effect.byc1=0.0; 735 effect.byc2=0.0; 736 effect.dummy1_zero=0.0; 737 effect.bc1y=0.0; 738 effect.bc1c1=saturation; 739 effect.bc1c2=0.0; 740 effect.dummy2_zero=0.0; 741 effect.bc2y=0.0; 742 effect.bc2c1=0.0; 743 effect.bc2c2=saturation; 744 effect.dummy3_zero=0.0; 745 effect.dummy4_zero=0.0; 746 effect.dummy5_zero=0.0; 747 effect.dummy6_zero=0.0; 748 effect.dummy7_one=1.0; 749 ColorTwistMultiply(*color_twist,effect,&result); 750 *color_twist=result; 751 } 752 753 static MagickBooleanType WriteFPXImage(const ImageInfo *image_info,Image *image, 754 ExceptionInfo *exception) 755 { 756 FPXBackground 757 background_color; 758 759 FPXColorspace 760 colorspace = 761 { 762 TRUE, 4, 763 { 764 { NIFRGB_R, DATA_TYPE_UNSIGNED_BYTE }, 765 { NIFRGB_G, DATA_TYPE_UNSIGNED_BYTE }, 766 { NIFRGB_B, DATA_TYPE_UNSIGNED_BYTE }, 767 { ALPHA, DATA_TYPE_UNSIGNED_BYTE } 768 } 769 }; 770 771 const char 772 *comment, 773 *label, 774 *option; 775 776 FPXCompressionOption 777 compression; 778 779 FPXImageDesc 780 fpx_info; 781 782 FPXImageHandle 783 *flashpix; 784 785 FPXStatus 786 fpx_status; 787 788 FPXSummaryInformation 789 summary_info; 790 791 MagickBooleanType 792 status; 793 794 QuantumInfo 795 *quantum_info; 796 797 QuantumType 798 quantum_type; 799 800 register const Quantum 801 *p; 802 803 register ssize_t 804 i; 805 806 size_t 807 length, 808 memory_limit; 809 810 ssize_t 811 y; 812 813 unsigned char 814 *pixels; 815 816 unsigned int 817 tile_height, 818 tile_width; 819 820 /* 821 Open input file. 822 */ 823 assert(image_info != (const ImageInfo *) NULL); 824 assert(image_info->signature == MagickCoreSignature); 825 assert(image != (Image *) NULL); 826 assert(image->signature == MagickCoreSignature); 827 if (image->debug != MagickFalse) 828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 829 assert(exception != (ExceptionInfo *) NULL); 830 assert(exception->signature == MagickCoreSignature); 831 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 832 if (status == MagickFalse) 833 return(status); 834 (void) TransformImageColorspace(image,sRGBColorspace,exception); 835 (void) CloseBlob(image); 836 /* 837 Initialize FPX toolkit. 838 */ 839 image->depth=8; 840 memory_limit=20000000; 841 fpx_status=FPX_SetToolkitMemoryLimit(&memory_limit); 842 if (fpx_status != FPX_OK) 843 ThrowWriterException(DelegateError,"UnableToInitializeFPXLibrary"); 844 tile_width=64; 845 tile_height=64; 846 colorspace.numberOfComponents=3; 847 if (image->alpha_trait != UndefinedPixelTrait) 848 colorspace.numberOfComponents=4; 849 if ((image_info->type != TrueColorType) && 850 (SetImageGray(image,exception) != MagickFalse)) 851 { 852 colorspace.numberOfComponents=1; 853 colorspace.theComponents[0].myColor=MONOCHROME; 854 } 855 background_color.color1_value=0; 856 background_color.color2_value=0; 857 background_color.color3_value=0; 858 background_color.color4_value=0; 859 compression=NONE; 860 if (image->compression == JPEGCompression) 861 compression=JPEG_UNSPECIFIED; 862 if (image_info->compression == JPEGCompression) 863 compression=JPEG_UNSPECIFIED; 864 { 865 #if defined(macintosh) 866 FSSpec 867 fsspec; 868 869 FilenameToFSSpec(filename,&fsspec); 870 fpx_status=FPX_CreateImageByFilename((const FSSpec &) fsspec,image->columns, 871 #else 872 fpx_status=FPX_CreateImageByFilename(image->filename,image->columns, 873 #endif 874 image->rows,tile_width,tile_height,colorspace,background_color, 875 compression,&flashpix); 876 } 877 if (fpx_status != FPX_OK) 878 return(status); 879 if (compression == JPEG_UNSPECIFIED) 880 { 881 /* 882 Initialize the compression by quality for the entire image. 883 */ 884 fpx_status=FPX_SetJPEGCompression(flashpix,(unsigned short) 885 image->quality == UndefinedCompressionQuality ? 75 : image->quality); 886 if (fpx_status != FPX_OK) 887 ThrowWriterException(DelegateError,"UnableToSetJPEGLevel"); 888 } 889 /* 890 Set image summary info. 891 */ 892 summary_info.title_valid=MagickFalse; 893 summary_info.subject_valid=MagickFalse; 894 summary_info.author_valid=MagickFalse; 895 summary_info.comments_valid=MagickFalse; 896 summary_info.keywords_valid=MagickFalse; 897 summary_info.OLEtemplate_valid=MagickFalse; 898 summary_info.last_author_valid=MagickFalse; 899 summary_info.rev_number_valid=MagickFalse; 900 summary_info.edit_time_valid=MagickFalse; 901 summary_info.last_printed_valid=MagickFalse; 902 summary_info.create_dtm_valid=MagickFalse; 903 summary_info.last_save_dtm_valid=MagickFalse; 904 summary_info.page_count_valid=MagickFalse; 905 summary_info.word_count_valid=MagickFalse; 906 summary_info.char_count_valid=MagickFalse; 907 summary_info.thumbnail_valid=MagickFalse; 908 summary_info.appname_valid=MagickFalse; 909 summary_info.security_valid=MagickFalse; 910 summary_info.title.ptr=(unsigned char *) NULL; 911 label=GetImageProperty(image,"label",exception); 912 if (label != (const char *) NULL) 913 { 914 /* 915 Note image label. 916 */ 917 summary_info.title_valid=MagickTrue; 918 length=strlen(label); 919 summary_info.title.length=length; 920 if (~length >= (MagickPathExtent-1)) 921 summary_info.title.ptr=(unsigned char *) AcquireQuantumMemory( 922 length+MagickPathExtent,sizeof(*summary_info.title.ptr)); 923 if (summary_info.title.ptr == (unsigned char *) NULL) 924 ThrowWriterException(DelegateError,"UnableToSetImageTitle"); 925 (void) CopyMagickString((char *) summary_info.title.ptr,label, 926 MagickPathExtent); 927 } 928 comment=GetImageProperty(image,"comment",exception); 929 if (comment != (const char *) NULL) 930 { 931 /* 932 Note image comment. 933 */ 934 summary_info.comments_valid=MagickTrue; 935 summary_info.comments.ptr=(unsigned char *) AcquireString(comment); 936 summary_info.comments.length=strlen(comment); 937 } 938 fpx_status=FPX_SetSummaryInformation(flashpix,&summary_info); 939 if (fpx_status != FPX_OK) 940 ThrowWriterException(DelegateError,"UnableToSetSummaryInfo"); 941 /* 942 Initialize FlashPix image description. 943 */ 944 quantum_info=AcquireQuantumInfo(image_info,image); 945 if (quantum_info == (QuantumInfo *) NULL) 946 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 947 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 948 fpx_info.numberOfComponents=colorspace.numberOfComponents; 949 for (i=0; i < (ssize_t) fpx_info.numberOfComponents; i++) 950 { 951 fpx_info.components[i].myColorType.myDataType=DATA_TYPE_UNSIGNED_BYTE; 952 fpx_info.components[i].horzSubSampFactor=1; 953 fpx_info.components[i].vertSubSampFactor=1; 954 fpx_info.components[i].columnStride=fpx_info.numberOfComponents; 955 fpx_info.components[i].lineStride= 956 image->columns*fpx_info.components[i].columnStride; 957 fpx_info.components[i].theData=pixels+i; 958 } 959 fpx_info.components[0].myColorType.myColor=fpx_info.numberOfComponents != 1 ? 960 NIFRGB_R : MONOCHROME; 961 fpx_info.components[1].myColorType.myColor=NIFRGB_G; 962 fpx_info.components[2].myColorType.myColor=NIFRGB_B; 963 fpx_info.components[3].myColorType.myColor=ALPHA; 964 /* 965 Write image pixels. 966 */ 967 quantum_type=RGBQuantum; 968 if (image->alpha_trait != UndefinedPixelTrait) 969 quantum_type=RGBAQuantum; 970 if (fpx_info.numberOfComponents == 1) 971 quantum_type=GrayQuantum; 972 for (y=0; y < (ssize_t) image->rows; y++) 973 { 974 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 975 if (p == (const Quantum *) NULL) 976 break; 977 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, 978 quantum_type,pixels,exception); 979 fpx_status=FPX_WriteImageLine(flashpix,&fpx_info); 980 if (fpx_status != FPX_OK) 981 break; 982 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 983 image->rows); 984 if (status == MagickFalse) 985 break; 986 } 987 quantum_info=DestroyQuantumInfo(quantum_info); 988 option=GetImageOption(image_info,"fpx:view"); 989 if (option != (const char *) NULL) 990 { 991 FPXAffineMatrix 992 affine; 993 994 FPXColorTwistMatrix 995 color_twist; 996 997 FPXContrastAdjustment 998 contrast; 999 1000 FPXFilteringValue 1001 sharpen; 1002 1003 FPXResultAspectRatio 1004 aspect_ratio; 1005 1006 FPXROI 1007 view_rect; 1008 1009 MagickBooleanType 1010 affine_valid, 1011 aspect_ratio_valid, 1012 color_twist_valid, 1013 contrast_valid, 1014 sharpen_valid, 1015 view_rect_valid; 1016 1017 /* 1018 Initialize default viewing parameters. 1019 */ 1020 contrast=1.0; 1021 contrast_valid=MagickTrue; 1022 color_twist.byy=1.0; 1023 color_twist.byc1=0.0; 1024 color_twist.byc2=0.0; 1025 color_twist.dummy1_zero=0.0; 1026 color_twist.bc1y=0.0; 1027 color_twist.bc1c1=1.0; 1028 color_twist.bc1c2=0.0; 1029 color_twist.dummy2_zero=0.0; 1030 color_twist.bc2y=0.0; 1031 color_twist.bc2c1=0.0; 1032 color_twist.bc2c2=1.0; 1033 color_twist.dummy3_zero=0.0; 1034 color_twist.dummy4_zero=0.0; 1035 color_twist.dummy5_zero=0.0; 1036 color_twist.dummy6_zero=0.0; 1037 color_twist.dummy7_one=1.0; 1038 color_twist_valid=MagickTrue; 1039 sharpen=0.0; 1040 sharpen_valid=MagickTrue; 1041 aspect_ratio=(double) image->columns/image->rows; 1042 aspect_ratio_valid=MagickTrue; 1043 view_rect.left=(float) 0.1; 1044 view_rect.width=aspect_ratio-0.2; 1045 view_rect.top=(float) 0.1; 1046 view_rect.height=(float) 0.8; /* 1.0-0.2 */ 1047 view_rect_valid=MagickTrue; 1048 affine.a11=1.0; 1049 affine.a12=0.0; 1050 affine.a13=0.0; 1051 affine.a14=0.0; 1052 affine.a21=0.0; 1053 affine.a22=1.0; 1054 affine.a23=0.0; 1055 affine.a24=0.0; 1056 affine.a31=0.0; 1057 affine.a32=0.0; 1058 affine.a33=1.0; 1059 affine.a34=0.0; 1060 affine.a41=0.0; 1061 affine.a42=0.0; 1062 affine.a43=0.0; 1063 affine.a44=1.0; 1064 affine_valid=MagickTrue; 1065 if (0) 1066 { 1067 /* 1068 Color color twist. 1069 */ 1070 SetBrightness(0.5,&color_twist); 1071 SetSaturation(0.5,&color_twist); 1072 SetColorBalance(0.5,1.0,1.0,&color_twist); 1073 color_twist_valid=MagickTrue; 1074 } 1075 if (affine_valid != MagickFalse) 1076 { 1077 fpx_status=FPX_SetImageAffineMatrix(flashpix,&affine); 1078 if (fpx_status != FPX_OK) 1079 ThrowWriterException(DelegateError,"UnableToSetAffineMatrix"); 1080 } 1081 if (aspect_ratio_valid != MagickFalse) 1082 { 1083 fpx_status=FPX_SetImageResultAspectRatio(flashpix,&aspect_ratio); 1084 if (fpx_status != FPX_OK) 1085 ThrowWriterException(DelegateError,"UnableToSetAspectRatio"); 1086 } 1087 if (color_twist_valid != MagickFalse) 1088 { 1089 fpx_status=FPX_SetImageColorTwistMatrix(flashpix,&color_twist); 1090 if (fpx_status != FPX_OK) 1091 ThrowWriterException(DelegateError,"UnableToSetColorTwist"); 1092 } 1093 if (contrast_valid != MagickFalse) 1094 { 1095 fpx_status=FPX_SetImageContrastAdjustment(flashpix,&contrast); 1096 if (fpx_status != FPX_OK) 1097 ThrowWriterException(DelegateError,"UnableToSetContrast"); 1098 } 1099 if (sharpen_valid != MagickFalse) 1100 { 1101 fpx_status=FPX_SetImageFilteringValue(flashpix,&sharpen); 1102 if (fpx_status != FPX_OK) 1103 ThrowWriterException(DelegateError,"UnableToSetFilteringValue"); 1104 } 1105 if (view_rect_valid != MagickFalse) 1106 { 1107 fpx_status=FPX_SetImageROI(flashpix,&view_rect); 1108 if (fpx_status != FPX_OK) 1109 ThrowWriterException(DelegateError,"UnableToSetRegionOfInterest"); 1110 } 1111 } 1112 (void) FPX_CloseImage(flashpix); 1113 FPX_ClearSystem(); 1114 return(MagickTrue); 1115 } 1116 #endif 1117