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