1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % JJJJJ PPPP EEEEE GGGG % 7 % J P P E G % 8 % J PPPP EEE G GG % 9 % J J P E G G % 10 % JJJ P EEEEE GGG % 11 % % 12 % % 13 % Read/Write JPEG Image Format % 14 % % 15 % Software Design % 16 % John Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2013 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 % This software is based in part on the work of the Independent JPEG Group. 37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and 38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson. 39 % 40 % 41 */ 42 43 44 /* 45 Include declarations. 46 */ 47 #include "MagickCore/studio.h" 48 #include "MagickCore/artifact.h" 49 #include "MagickCore/attribute.h" 50 #include "MagickCore/blob.h" 51 #include "MagickCore/blob-private.h" 52 #include "MagickCore/cache.h" 53 #include "MagickCore/color.h" 54 #include "MagickCore/colormap-private.h" 55 #include "MagickCore/color-private.h" 56 #include "MagickCore/colormap.h" 57 #include "MagickCore/colorspace.h" 58 #include "MagickCore/colorspace-private.h" 59 #include "MagickCore/constitute.h" 60 #include "MagickCore/exception.h" 61 #include "MagickCore/exception-private.h" 62 #include "MagickCore/geometry.h" 63 #include "MagickCore/image.h" 64 #include "MagickCore/image-private.h" 65 #include "MagickCore/list.h" 66 #include "MagickCore/log.h" 67 #include "MagickCore/magick.h" 68 #include "MagickCore/memory_.h" 69 #include "MagickCore/module.h" 70 #include "MagickCore/monitor.h" 71 #include "MagickCore/monitor-private.h" 72 #include "MagickCore/option.h" 73 #include "MagickCore/option-private.h" 74 #include "MagickCore/pixel-accessor.h" 75 #include "MagickCore/profile.h" 76 #include "MagickCore/property.h" 77 #include "MagickCore/quantum-private.h" 78 #include "MagickCore/resource_.h" 79 #include "MagickCore/semaphore.h" 80 #include "MagickCore/splay-tree.h" 81 #include "MagickCore/static.h" 82 #include "MagickCore/string_.h" 83 #include "MagickCore/string-private.h" 84 #include "MagickCore/token.h" 85 #include "MagickCore/utility.h" 86 #include "MagickCore/xml-tree.h" 87 #include "MagickCore/xml-tree-private.h" 88 #include <setjmp.h> 89 #if defined(MAGICKCORE_JPEG_DELEGATE) 90 #define JPEG_INTERNAL_OPTIONS 91 #if defined(__MINGW32__) || defined(__MINGW64__) 92 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */ 93 #endif 94 #undef HAVE_STDLIB_H 95 #include "jpeglib.h" 96 #include "jerror.h" 97 #endif 98 99 /* 101 Define declarations. 102 */ 103 #define ICC_MARKER (JPEG_APP0+2) 104 #define ICC_PROFILE "ICC_PROFILE" 105 #define IPTC_MARKER (JPEG_APP0+13) 106 #define XML_MARKER (JPEG_APP0+1) 107 #define MaxBufferExtent 16384 108 109 /* 111 Typedef declarations. 112 */ 113 #if defined(MAGICKCORE_JPEG_DELEGATE) 114 typedef struct _DestinationManager 115 { 116 struct jpeg_destination_mgr 117 manager; 118 119 Image 120 *image; 121 122 JOCTET 123 *buffer; 124 } DestinationManager; 125 126 typedef struct _ErrorManager 127 { 128 ExceptionInfo 129 *exception; 130 131 Image 132 *image; 133 134 MagickBooleanType 135 finished; 136 137 StringInfo 138 *profile; 139 140 jmp_buf 141 error_recovery; 142 } ErrorManager; 143 144 typedef struct _SourceManager 145 { 146 struct jpeg_source_mgr 147 manager; 148 149 Image 150 *image; 151 152 JOCTET 153 *buffer; 154 155 boolean 156 start_of_blob; 157 } SourceManager; 158 #endif 159 160 typedef struct _QuantizationTable 161 { 162 char 163 *slot, 164 *description; 165 166 size_t 167 width, 168 height; 169 170 double 171 divisor; 172 173 unsigned int 174 *levels; 175 } QuantizationTable; 176 177 /* 179 Forward declarations. 180 */ 181 #if defined(MAGICKCORE_JPEG_DELEGATE) 182 static MagickBooleanType 183 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *); 184 #endif 185 186 /* 188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 189 % % 190 % % 191 % % 192 % I s J P E G % 193 % % 194 % % 195 % % 196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 197 % 198 % IsJPEG() returns MagickTrue if the image format type, identified by the 199 % magick string, is JPEG. 200 % 201 % The format of the IsJPEG method is: 202 % 203 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length) 204 % 205 % A description of each parameter follows: 206 % 207 % o magick: compare image format pattern against these bytes. 208 % 209 % o length: Specifies the length of the magick string. 210 % 211 */ 212 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length) 213 { 214 if (length < 3) 215 return(MagickFalse); 216 if (memcmp(magick,"\377\330\377",3) == 0) 217 return(MagickTrue); 218 return(MagickFalse); 219 } 220 221 #if defined(MAGICKCORE_JPEG_DELEGATE) 223 /* 224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 225 % % 226 % % 227 % % 228 % R e a d J P E G I m a g e % 229 % % 230 % % 231 % % 232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 233 % 234 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates 235 % the memory necessary for the new Image structure and returns a pointer to 236 % the new image. 237 % 238 % The format of the ReadJPEGImage method is: 239 % 240 % Image *ReadJPEGImage(const ImageInfo *image_info, 241 % ExceptionInfo *exception) 242 % 243 % A description of each parameter follows: 244 % 245 % o image_info: the image info. 246 % 247 % o exception: return any errors or warnings in this structure. 248 % 249 */ 250 251 static boolean FillInputBuffer(j_decompress_ptr cinfo) 252 { 253 SourceManager 254 *source; 255 256 source=(SourceManager *) cinfo->src; 257 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image, 258 MaxBufferExtent,source->buffer); 259 if (source->manager.bytes_in_buffer == 0) 260 { 261 if (source->start_of_blob != FALSE) 262 ERREXIT(cinfo,JERR_INPUT_EMPTY); 263 WARNMS(cinfo,JWRN_JPEG_EOF); 264 source->buffer[0]=(JOCTET) 0xff; 265 source->buffer[1]=(JOCTET) JPEG_EOI; 266 source->manager.bytes_in_buffer=2; 267 } 268 source->manager.next_input_byte=source->buffer; 269 source->start_of_blob=FALSE; 270 return(TRUE); 271 } 272 273 static int GetCharacter(j_decompress_ptr jpeg_info) 274 { 275 if (jpeg_info->src->bytes_in_buffer == 0) 276 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info); 277 jpeg_info->src->bytes_in_buffer--; 278 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++)); 279 } 280 281 static void InitializeSource(j_decompress_ptr cinfo) 282 { 283 SourceManager 284 *source; 285 286 source=(SourceManager *) cinfo->src; 287 source->start_of_blob=TRUE; 288 } 289 290 static MagickBooleanType IsITUFaxImage(const Image *image) 291 { 292 const StringInfo 293 *profile; 294 295 const unsigned char 296 *datum; 297 298 profile=GetImageProfile(image,"8bim"); 299 if (profile == (const StringInfo *) NULL) 300 return(MagickFalse); 301 if (GetStringInfoLength(profile) < 5) 302 return(MagickFalse); 303 datum=GetStringInfoDatum(profile); 304 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) && 305 (datum[3] == 0x41) && (datum[4] == 0x58)) 306 return(MagickTrue); 307 return(MagickFalse); 308 } 309 310 static void JPEGErrorHandler(j_common_ptr jpeg_info) 311 { 312 char 313 message[JMSG_LENGTH_MAX]; 314 315 ErrorManager 316 *error_manager; 317 318 ExceptionInfo 319 *exception; 320 321 Image 322 *image; 323 324 *message='\0'; 325 error_manager=(ErrorManager *) jpeg_info->client_data; 326 image=error_manager->image; 327 exception=error_manager->exception; 328 (jpeg_info->err->format_message)(jpeg_info,message); 329 if (image->debug != MagickFalse) 330 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 331 "[%s] JPEG Trace: \"%s\"",image->filename,message); 332 if (error_manager->finished != MagickFalse) 333 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning, 334 (char *) message,"`%s'",image->filename); 335 else 336 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, 337 (char *) message,"`%s'",image->filename); 338 longjmp(error_manager->error_recovery,1); 339 } 340 341 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level) 342 { 343 #define JPEGExcessiveWarnings 1000 344 345 char 346 message[JMSG_LENGTH_MAX]; 347 348 ErrorManager 349 *error_manager; 350 351 ExceptionInfo 352 *exception; 353 354 Image 355 *image; 356 357 *message='\0'; 358 error_manager=(ErrorManager *) jpeg_info->client_data; 359 exception=error_manager->exception; 360 image=error_manager->image; 361 if (level < 0) 362 { 363 /* 364 Process warning message. 365 */ 366 (jpeg_info->err->format_message)(jpeg_info,message); 367 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings) 368 JPEGErrorHandler(jpeg_info); 369 ThrowBinaryException(CorruptImageWarning,(char *) message, 370 image->filename); 371 } 372 else 373 if ((image->debug != MagickFalse) && 374 (level >= jpeg_info->err->trace_level)) 375 { 376 /* 377 Process trace message. 378 */ 379 (jpeg_info->err->format_message)(jpeg_info,message); 380 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 381 "[%s] JPEG Trace: \"%s\"",image->filename,message); 382 } 383 return(MagickTrue); 384 } 385 386 static boolean ReadComment(j_decompress_ptr jpeg_info) 387 { 388 ErrorManager 389 *error_manager; 390 391 ExceptionInfo 392 *exception; 393 394 Image 395 *image; 396 397 register unsigned char 398 *p; 399 400 register ssize_t 401 i; 402 403 size_t 404 length; 405 406 StringInfo 407 *comment; 408 409 /* 410 Determine length of comment. 411 */ 412 error_manager=(ErrorManager *) jpeg_info->client_data; 413 exception=error_manager->exception; 414 image=error_manager->image; 415 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8); 416 length+=GetCharacter(jpeg_info); 417 if (length <= 2) 418 return(TRUE); 419 length-=2; 420 comment=BlobToStringInfo((const void *) NULL,length); 421 if (comment == (StringInfo *) NULL) 422 { 423 (void) ThrowMagickException(exception,GetMagickModule(), 424 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 425 return(FALSE); 426 } 427 /* 428 Read comment. 429 */ 430 error_manager->profile=comment; 431 p=GetStringInfoDatum(comment); 432 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++) 433 *p++=(unsigned char) GetCharacter(jpeg_info); 434 *p='\0'; 435 error_manager->profile=NULL; 436 p=GetStringInfoDatum(comment); 437 (void) SetImageProperty(image,"comment",(const char *) p,exception); 438 comment=DestroyStringInfo(comment); 439 return(TRUE); 440 } 441 442 static boolean ReadICCProfile(j_decompress_ptr jpeg_info) 443 { 444 char 445 magick[12]; 446 447 ErrorManager 448 *error_manager; 449 450 ExceptionInfo 451 *exception; 452 453 Image 454 *image; 455 456 MagickBooleanType 457 status; 458 459 register ssize_t 460 i; 461 462 register unsigned char 463 *p; 464 465 size_t 466 length; 467 468 StringInfo 469 *icc_profile, 470 *profile; 471 472 /* 473 Read color profile. 474 */ 475 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8); 476 length+=(size_t) GetCharacter(jpeg_info); 477 length-=2; 478 if (length <= 14) 479 { 480 while (length-- > 0) 481 (void) GetCharacter(jpeg_info); 482 return(TRUE); 483 } 484 for (i=0; i < 12; i++) 485 magick[i]=(char) GetCharacter(jpeg_info); 486 if (LocaleCompare(magick,ICC_PROFILE) != 0) 487 { 488 /* 489 Not a ICC profile, return. 490 */ 491 for (i=0; i < (ssize_t) (length-12); i++) 492 (void) GetCharacter(jpeg_info); 493 return(TRUE); 494 } 495 (void) GetCharacter(jpeg_info); /* id */ 496 (void) GetCharacter(jpeg_info); /* markers */ 497 length-=14; 498 error_manager=(ErrorManager *) jpeg_info->client_data; 499 exception=error_manager->exception; 500 image=error_manager->image; 501 profile=BlobToStringInfo((const void *) NULL,length); 502 if (profile == (StringInfo *) NULL) 503 { 504 (void) ThrowMagickException(exception,GetMagickModule(), 505 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 506 return(FALSE); 507 } 508 error_manager->profile=profile; 509 p=GetStringInfoDatum(profile); 510 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--) 511 *p++=(unsigned char) GetCharacter(jpeg_info); 512 error_manager->profile=NULL; 513 icc_profile=(StringInfo *) GetImageProfile(image,"icc"); 514 if (icc_profile != (StringInfo *) NULL) 515 { 516 ConcatenateStringInfo(icc_profile,profile); 517 profile=DestroyStringInfo(profile); 518 } 519 else 520 { 521 status=SetImageProfile(image,"icc",profile,exception); 522 profile=DestroyStringInfo(profile); 523 if (status == MagickFalse) 524 { 525 (void) ThrowMagickException(exception,GetMagickModule(), 526 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 527 return(FALSE); 528 } 529 } 530 if (image->debug != MagickFalse) 531 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 532 "Profile: ICC, %.20g bytes",(double) length); 533 return(TRUE); 534 } 535 536 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info) 537 { 538 char 539 magick[MagickPathExtent]; 540 541 ErrorManager 542 *error_manager; 543 544 ExceptionInfo 545 *exception; 546 547 Image 548 *image; 549 550 MagickBooleanType 551 status; 552 553 register ssize_t 554 i; 555 556 register unsigned char 557 *p; 558 559 size_t 560 length; 561 562 StringInfo 563 *iptc_profile, 564 *profile; 565 566 /* 567 Determine length of binary data stored here. 568 */ 569 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8); 570 length+=(size_t) GetCharacter(jpeg_info); 571 length-=2; 572 if (length <= 14) 573 { 574 while (length-- > 0) 575 (void) GetCharacter(jpeg_info); 576 return(TRUE); 577 } 578 /* 579 Validate that this was written as a Photoshop resource format slug. 580 */ 581 for (i=0; i < 10; i++) 582 magick[i]=(char) GetCharacter(jpeg_info); 583 magick[10]='\0'; 584 length-=10; 585 if (length <= 10) 586 return(TRUE); 587 if (LocaleCompare(magick,"Photoshop ") != 0) 588 { 589 /* 590 Not a IPTC profile, return. 591 */ 592 for (i=0; i < (ssize_t) length; i++) 593 (void) GetCharacter(jpeg_info); 594 return(TRUE); 595 } 596 /* 597 Remove the version number. 598 */ 599 for (i=0; i < 4; i++) 600 (void) GetCharacter(jpeg_info); 601 if (length <= 11) 602 return(TRUE); 603 length-=4; 604 error_manager=(ErrorManager *) jpeg_info->client_data; 605 exception=error_manager->exception; 606 image=error_manager->image; 607 profile=BlobToStringInfo((const void *) NULL,length); 608 if (profile == (StringInfo *) NULL) 609 { 610 (void) ThrowMagickException(exception,GetMagickModule(), 611 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 612 return(FALSE); 613 } 614 error_manager->profile=profile; 615 p=GetStringInfoDatum(profile); 616 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++) 617 *p++=(unsigned char) GetCharacter(jpeg_info); 618 error_manager->profile=NULL; 619 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim"); 620 if (iptc_profile != (StringInfo *) NULL) 621 { 622 ConcatenateStringInfo(iptc_profile,profile); 623 profile=DestroyStringInfo(profile); 624 } 625 else 626 { 627 status=SetImageProfile(image,"8bim",profile,exception); 628 profile=DestroyStringInfo(profile); 629 if (status == MagickFalse) 630 { 631 (void) ThrowMagickException(exception,GetMagickModule(), 632 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 633 return(FALSE); 634 } 635 } 636 if (image->debug != MagickFalse) 637 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 638 "Profile: iptc, %.20g bytes",(double) length); 639 return(TRUE); 640 } 641 642 static boolean ReadProfile(j_decompress_ptr jpeg_info) 643 { 644 char 645 name[MagickPathExtent]; 646 647 const StringInfo 648 *previous_profile; 649 650 ErrorManager 651 *error_manager; 652 653 ExceptionInfo 654 *exception; 655 656 Image 657 *image; 658 659 int 660 marker; 661 662 MagickBooleanType 663 status; 664 665 register ssize_t 666 i; 667 668 register unsigned char 669 *p; 670 671 size_t 672 length; 673 674 StringInfo 675 *profile; 676 677 /* 678 Read generic profile. 679 */ 680 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8); 681 length+=(size_t) GetCharacter(jpeg_info); 682 if (length <= 2) 683 return(TRUE); 684 length-=2; 685 marker=jpeg_info->unread_marker-JPEG_APP0; 686 (void) FormatLocaleString(name,MagickPathExtent,"APP%d",marker); 687 error_manager=(ErrorManager *) jpeg_info->client_data; 688 exception=error_manager->exception; 689 image=error_manager->image; 690 profile=BlobToStringInfo((const void *) NULL,length); 691 if (profile == (StringInfo *) NULL) 692 { 693 (void) ThrowMagickException(exception,GetMagickModule(), 694 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 695 return(FALSE); 696 } 697 error_manager->profile=profile; 698 p=GetStringInfoDatum(profile); 699 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++) 700 *p++=(unsigned char) GetCharacter(jpeg_info); 701 error_manager->profile=NULL; 702 if (marker == 1) 703 { 704 p=GetStringInfoDatum(profile); 705 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0)) 706 (void) CopyMagickString(name,"exif",MagickPathExtent); 707 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0)) 708 { 709 ssize_t 710 j; 711 712 /* 713 Extract namespace from XMP profile. 714 */ 715 p=GetStringInfoDatum(profile); 716 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++) 717 { 718 if (*p == '\0') 719 break; 720 p++; 721 } 722 if (j < (ssize_t) GetStringInfoLength(profile)) 723 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1))); 724 (void) CopyMagickString(name,"xmp",MagickPathExtent); 725 } 726 } 727 previous_profile=GetImageProfile(image,name); 728 if (previous_profile != (const StringInfo *) NULL) 729 { 730 size_t 731 profile_length; 732 733 profile_length=GetStringInfoLength(profile); 734 SetStringInfoLength(profile,GetStringInfoLength(profile)+ 735 GetStringInfoLength(previous_profile)); 736 (void) memmove(GetStringInfoDatum(profile)+ 737 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile), 738 profile_length); 739 (void) memcpy(GetStringInfoDatum(profile), 740 GetStringInfoDatum(previous_profile), 741 GetStringInfoLength(previous_profile)); 742 } 743 status=SetImageProfile(image,name,profile,exception); 744 profile=DestroyStringInfo(profile); 745 if (status == MagickFalse) 746 { 747 (void) ThrowMagickException(exception,GetMagickModule(), 748 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename); 749 return(FALSE); 750 } 751 if (image->debug != MagickFalse) 752 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 753 "Profile: %s, %.20g bytes",name,(double) length); 754 return(TRUE); 755 } 756 757 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes) 758 { 759 SourceManager 760 *source; 761 762 if (number_bytes <= 0) 763 return; 764 source=(SourceManager *) cinfo->src; 765 while (number_bytes > (long) source->manager.bytes_in_buffer) 766 { 767 number_bytes-=(long) source->manager.bytes_in_buffer; 768 (void) FillInputBuffer(cinfo); 769 } 770 source->manager.next_input_byte+=number_bytes; 771 source->manager.bytes_in_buffer-=number_bytes; 772 } 773 774 static void TerminateSource(j_decompress_ptr cinfo) 775 { 776 (void) cinfo; 777 } 778 779 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image) 780 { 781 SourceManager 782 *source; 783 784 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) 785 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager)); 786 source=(SourceManager *) cinfo->src; 787 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small) 788 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET)); 789 source=(SourceManager *) cinfo->src; 790 source->manager.init_source=InitializeSource; 791 source->manager.fill_input_buffer=FillInputBuffer; 792 source->manager.skip_input_data=SkipInputData; 793 source->manager.resync_to_restart=jpeg_resync_to_restart; 794 source->manager.term_source=TerminateSource; 795 source->manager.bytes_in_buffer=0; 796 source->manager.next_input_byte=NULL; 797 source->image=image; 798 } 799 800 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info, 801 Image *image) 802 { 803 image->quality=UndefinedCompressionQuality; 804 #if defined(D_PROGRESSIVE_SUPPORTED) 805 if (image->compression == LosslessJPEGCompression) 806 { 807 image->quality=100; 808 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 809 "Quality: 100 (lossless)"); 810 } 811 else 812 #endif 813 { 814 ssize_t 815 j, 816 qvalue, 817 sum; 818 819 register ssize_t 820 i; 821 822 /* 823 Determine the JPEG compression quality from the quantization tables. 824 */ 825 sum=0; 826 for (i=0; i < NUM_QUANT_TBLS; i++) 827 { 828 if (jpeg_info->quant_tbl_ptrs[i] != NULL) 829 for (j=0; j < DCTSIZE2; j++) 830 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j]; 831 } 832 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) && 833 (jpeg_info->quant_tbl_ptrs[1] != NULL)) 834 { 835 ssize_t 836 hash[101] = 837 { 838 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645, 839 632, 623, 613, 607, 600, 594, 589, 585, 581, 571, 840 555, 542, 529, 514, 494, 474, 457, 439, 424, 410, 841 397, 386, 373, 364, 351, 341, 334, 324, 317, 309, 842 299, 294, 287, 279, 274, 267, 262, 257, 251, 247, 843 243, 237, 232, 227, 222, 217, 213, 207, 202, 198, 844 192, 188, 183, 177, 173, 168, 163, 157, 153, 148, 845 143, 139, 132, 128, 125, 119, 115, 108, 104, 99, 846 94, 90, 84, 79, 74, 70, 64, 59, 55, 49, 847 45, 40, 34, 30, 25, 20, 15, 11, 6, 4, 848 0 849 }, 850 sums[101] = 851 { 852 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104, 853 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946, 854 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998, 855 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702, 856 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208, 857 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458, 858 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788, 859 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128, 860 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509, 861 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846, 862 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201, 863 128, 0 864 }; 865 866 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+ 867 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+ 868 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+ 869 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]); 870 for (i=0; i < 100; i++) 871 { 872 if ((qvalue < hash[i]) && (sum < sums[i])) 873 continue; 874 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50)) 875 image->quality=(size_t) i+1; 876 if (image->debug != MagickFalse) 877 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 878 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) && 879 (sum <= sums[i]) ? "exact" : "approximate"); 880 break; 881 } 882 } 883 else 884 if (jpeg_info->quant_tbl_ptrs[0] != NULL) 885 { 886 ssize_t 887 hash[101] = 888 { 889 510, 505, 422, 380, 355, 338, 326, 318, 311, 305, 890 300, 297, 293, 291, 288, 286, 284, 283, 281, 280, 891 279, 278, 277, 273, 262, 251, 243, 233, 225, 218, 892 211, 205, 198, 193, 186, 181, 177, 172, 168, 164, 893 158, 156, 152, 148, 145, 142, 139, 136, 133, 131, 894 129, 126, 123, 120, 118, 115, 113, 110, 107, 105, 895 102, 100, 97, 94, 92, 89, 87, 83, 81, 79, 896 76, 74, 70, 68, 66, 63, 61, 57, 55, 52, 897 50, 48, 44, 42, 39, 37, 34, 31, 29, 26, 898 24, 21, 18, 16, 13, 11, 8, 6, 3, 2, 899 0 900 }, 901 sums[101] = 902 { 903 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859, 904 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679, 905 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823, 906 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086, 907 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092, 908 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396, 909 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727, 910 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068, 911 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398, 912 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736, 913 667, 592, 518, 441, 369, 292, 221, 151, 86, 914 64, 0 915 }; 916 917 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+ 918 jpeg_info->quant_tbl_ptrs[0]->quantval[53]); 919 for (i=0; i < 100; i++) 920 { 921 if ((qvalue < hash[i]) && (sum < sums[i])) 922 continue; 923 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50)) 924 image->quality=(size_t)i+1; 925 if (image->debug != MagickFalse) 926 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 927 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) && 928 (sum <= sums[i]) ? "exact" : "approximate"); 929 break; 930 } 931 } 932 } 933 } 934 935 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception) 936 { 937 char 938 sampling_factor[MagickPathExtent]; 939 940 switch (jpeg_info->out_color_space) 941 { 942 case JCS_CMYK: 943 { 944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK"); 945 (void) FormatLocaleString(sampling_factor,MagickPathExtent, 946 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor, 947 jpeg_info->comp_info[0].v_samp_factor, 948 jpeg_info->comp_info[1].h_samp_factor, 949 jpeg_info->comp_info[1].v_samp_factor, 950 jpeg_info->comp_info[2].h_samp_factor, 951 jpeg_info->comp_info[2].v_samp_factor, 952 jpeg_info->comp_info[3].h_samp_factor, 953 jpeg_info->comp_info[3].v_samp_factor); 954 break; 955 } 956 case JCS_GRAYSCALE: 957 { 958 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 959 "Colorspace: GRAYSCALE"); 960 (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d", 961 jpeg_info->comp_info[0].h_samp_factor, 962 jpeg_info->comp_info[0].v_samp_factor); 963 break; 964 } 965 case JCS_RGB: 966 { 967 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB"); 968 (void) FormatLocaleString(sampling_factor,MagickPathExtent, 969 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor, 970 jpeg_info->comp_info[0].v_samp_factor, 971 jpeg_info->comp_info[1].h_samp_factor, 972 jpeg_info->comp_info[1].v_samp_factor, 973 jpeg_info->comp_info[2].h_samp_factor, 974 jpeg_info->comp_info[2].v_samp_factor); 975 break; 976 } 977 default: 978 { 979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d", 980 jpeg_info->out_color_space); 981 (void) FormatLocaleString(sampling_factor,MagickPathExtent, 982 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor, 983 jpeg_info->comp_info[0].v_samp_factor, 984 jpeg_info->comp_info[1].h_samp_factor, 985 jpeg_info->comp_info[1].v_samp_factor, 986 jpeg_info->comp_info[2].h_samp_factor, 987 jpeg_info->comp_info[2].v_samp_factor, 988 jpeg_info->comp_info[3].h_samp_factor, 989 jpeg_info->comp_info[3].v_samp_factor); 990 break; 991 } 992 } 993 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor, 994 exception); 995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s", 996 sampling_factor); 997 } 998 999 static Image *ReadJPEGImage(const ImageInfo *image_info, 1000 ExceptionInfo *exception) 1001 { 1002 char 1003 value[MagickPathExtent]; 1004 1005 const char 1006 *option; 1007 1008 ErrorManager 1009 error_manager; 1010 1011 Image 1012 *image; 1013 1014 JSAMPLE 1015 *volatile jpeg_pixels; 1016 1017 JSAMPROW 1018 scanline[1]; 1019 1020 MagickBooleanType 1021 debug, 1022 status; 1023 1024 MagickSizeType 1025 number_pixels; 1026 1027 MemoryInfo 1028 *memory_info; 1029 1030 Quantum 1031 index; 1032 1033 register ssize_t 1034 i; 1035 1036 struct jpeg_decompress_struct 1037 jpeg_info; 1038 1039 struct jpeg_error_mgr 1040 jpeg_error; 1041 1042 register JSAMPLE 1043 *p; 1044 1045 size_t 1046 units; 1047 1048 ssize_t 1049 y; 1050 1051 /* 1052 Open image file. 1053 */ 1054 assert(image_info != (const ImageInfo *) NULL); 1055 assert(image_info->signature == MagickCoreSignature); 1056 if (image_info->debug != MagickFalse) 1057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 1058 image_info->filename); 1059 assert(exception != (ExceptionInfo *) NULL); 1060 assert(exception->signature == MagickCoreSignature); 1061 debug=IsEventLogging(); 1062 (void) debug; 1063 image=AcquireImage(image_info,exception); 1064 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 1065 if (status == MagickFalse) 1066 { 1067 image=DestroyImageList(image); 1068 return((Image *) NULL); 1069 } 1070 /* 1071 Initialize JPEG parameters. 1072 */ 1073 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager)); 1074 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info)); 1075 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error)); 1076 jpeg_info.err=jpeg_std_error(&jpeg_error); 1077 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler; 1078 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler; 1079 memory_info=(MemoryInfo *) NULL; 1080 error_manager.exception=exception; 1081 error_manager.image=image; 1082 if (setjmp(error_manager.error_recovery) != 0) 1083 { 1084 jpeg_destroy_decompress(&jpeg_info); 1085 if (error_manager.profile != (StringInfo *) NULL) 1086 error_manager.profile=DestroyStringInfo(error_manager.profile); 1087 (void) CloseBlob(image); 1088 number_pixels=(MagickSizeType) image->columns*image->rows; 1089 if (number_pixels != 0) 1090 return(GetFirstImageInList(image)); 1091 return(DestroyImage(image)); 1092 } 1093 jpeg_info.client_data=(void *) &error_manager; 1094 jpeg_create_decompress(&jpeg_info); 1095 JPEGSourceManager(&jpeg_info,image); 1096 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment); 1097 option=GetImageOption(image_info,"profile:skip"); 1098 if (IsOptionMember("ICC",option) == MagickFalse) 1099 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile); 1100 if (IsOptionMember("IPTC",option) == MagickFalse) 1101 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile); 1102 for (i=1; i < 16; i++) 1103 if ((i != 2) && (i != 13) && (i != 14)) 1104 if (IsOptionMember("APP",option) == MagickFalse) 1105 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile); 1106 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE); 1107 if ((image_info->colorspace == YCbCrColorspace) || 1108 (image_info->colorspace == Rec601YCbCrColorspace) || 1109 (image_info->colorspace == Rec709YCbCrColorspace)) 1110 jpeg_info.out_color_space=JCS_YCbCr; 1111 /* 1112 Set image resolution. 1113 */ 1114 units=0; 1115 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) && 1116 (jpeg_info.Y_density != 1)) 1117 { 1118 image->resolution.x=(double) jpeg_info.X_density; 1119 image->resolution.y=(double) jpeg_info.Y_density; 1120 units=(size_t) jpeg_info.density_unit; 1121 } 1122 if (units == 1) 1123 image->units=PixelsPerInchResolution; 1124 if (units == 2) 1125 image->units=PixelsPerCentimeterResolution; 1126 number_pixels=(MagickSizeType) image->columns*image->rows; 1127 option=GetImageOption(image_info,"jpeg:size"); 1128 if ((option != (const char *) NULL) && 1129 (jpeg_info.out_color_space != JCS_YCbCr)) 1130 { 1131 double 1132 scale_factor; 1133 1134 GeometryInfo 1135 geometry_info; 1136 1137 MagickStatusType 1138 flags; 1139 1140 /* 1141 Scale the image. 1142 */ 1143 flags=ParseGeometry(option,&geometry_info); 1144 if ((flags & SigmaValue) == 0) 1145 geometry_info.sigma=geometry_info.rho; 1146 jpeg_calc_output_dimensions(&jpeg_info); 1147 image->magick_columns=jpeg_info.output_width; 1148 image->magick_rows=jpeg_info.output_height; 1149 scale_factor=1.0; 1150 if (geometry_info.rho != 0.0) 1151 scale_factor=jpeg_info.output_width/geometry_info.rho; 1152 if ((geometry_info.sigma != 0.0) && 1153 (scale_factor > (jpeg_info.output_height/geometry_info.sigma))) 1154 scale_factor=jpeg_info.output_height/geometry_info.sigma; 1155 jpeg_info.scale_num=1U; 1156 jpeg_info.scale_denom=(unsigned int) scale_factor; 1157 jpeg_calc_output_dimensions(&jpeg_info); 1158 if (image->debug != MagickFalse) 1159 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1160 "Scale factor: %.20g",(double) scale_factor); 1161 } 1162 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED) 1163 #if defined(D_LOSSLESS_SUPPORTED) 1164 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ? 1165 JPEGInterlace : NoInterlace; 1166 image->compression=jpeg_info.process == JPROC_LOSSLESS ? 1167 LosslessJPEGCompression : JPEGCompression; 1168 if (jpeg_info.data_precision > 8) 1169 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1170 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'", 1171 image->filename); 1172 if (jpeg_info.data_precision == 16) 1173 jpeg_info.data_precision=12; 1174 #else 1175 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace : 1176 NoInterlace; 1177 image->compression=JPEGCompression; 1178 #endif 1179 #else 1180 image->compression=JPEGCompression; 1181 image->interlace=JPEGInterlace; 1182 #endif 1183 option=GetImageOption(image_info,"jpeg:colors"); 1184 if (option != (const char *) NULL) 1185 { 1186 /* 1187 Let the JPEG library quantize the image. 1188 */ 1189 jpeg_info.quantize_colors=TRUE; 1190 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option); 1191 } 1192 option=GetImageOption(image_info,"jpeg:block-smoothing"); 1193 if (option != (const char *) NULL) 1194 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE : 1195 FALSE; 1196 jpeg_info.dct_method=JDCT_FLOAT; 1197 option=GetImageOption(image_info,"jpeg:dct-method"); 1198 if (option != (const char *) NULL) 1199 switch (*option) 1200 { 1201 case 'D': 1202 case 'd': 1203 { 1204 if (LocaleCompare(option,"default") == 0) 1205 jpeg_info.dct_method=JDCT_DEFAULT; 1206 break; 1207 } 1208 case 'F': 1209 case 'f': 1210 { 1211 if (LocaleCompare(option,"fastest") == 0) 1212 jpeg_info.dct_method=JDCT_FASTEST; 1213 if (LocaleCompare(option,"float") == 0) 1214 jpeg_info.dct_method=JDCT_FLOAT; 1215 break; 1216 } 1217 case 'I': 1218 case 'i': 1219 { 1220 if (LocaleCompare(option,"ifast") == 0) 1221 jpeg_info.dct_method=JDCT_IFAST; 1222 if (LocaleCompare(option,"islow") == 0) 1223 jpeg_info.dct_method=JDCT_ISLOW; 1224 break; 1225 } 1226 } 1227 option=GetImageOption(image_info,"jpeg:fancy-upsampling"); 1228 if (option != (const char *) NULL) 1229 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE : 1230 FALSE; 1231 (void) jpeg_start_decompress(&jpeg_info); 1232 image->columns=jpeg_info.output_width; 1233 image->rows=jpeg_info.output_height; 1234 image->depth=(size_t) jpeg_info.data_precision; 1235 switch (jpeg_info.out_color_space) 1236 { 1237 case JCS_RGB: 1238 default: 1239 { 1240 (void) SetImageColorspace(image,sRGBColorspace,exception); 1241 break; 1242 } 1243 case JCS_GRAYSCALE: 1244 { 1245 (void) SetImageColorspace(image,GRAYColorspace,exception); 1246 break; 1247 } 1248 case JCS_YCbCr: 1249 { 1250 (void) SetImageColorspace(image,YCbCrColorspace,exception); 1251 break; 1252 } 1253 case JCS_CMYK: 1254 { 1255 (void) SetImageColorspace(image,CMYKColorspace,exception); 1256 break; 1257 } 1258 } 1259 if (IsITUFaxImage(image) != MagickFalse) 1260 { 1261 (void) SetImageColorspace(image,LabColorspace,exception); 1262 jpeg_info.out_color_space=JCS_YCbCr; 1263 } 1264 option=GetImageOption(image_info,"jpeg:colors"); 1265 if (option != (const char *) NULL) 1266 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception) 1267 == MagickFalse) 1268 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1269 if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0)) 1270 { 1271 size_t 1272 colors; 1273 1274 colors=(size_t) GetQuantumRange(image->depth)+1; 1275 if (AcquireImageColormap(image,colors,exception) == MagickFalse) 1276 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1277 } 1278 if (image->debug != MagickFalse) 1279 { 1280 if (image->interlace != NoInterlace) 1281 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1282 "Interlace: progressive"); 1283 else 1284 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 1285 "Interlace: nonprogressive"); 1286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d", 1287 (int) jpeg_info.data_precision); 1288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d", 1289 (int) jpeg_info.output_width,(int) jpeg_info.output_height); 1290 } 1291 JPEGSetImageQuality(&jpeg_info,image); 1292 JPEGSetImageSamplingFactor(&jpeg_info,image,exception); 1293 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 1294 jpeg_info.out_color_space); 1295 (void) SetImageProperty(image,"jpeg:colorspace",value,exception); 1296 if (image_info->ping != MagickFalse) 1297 { 1298 jpeg_destroy_decompress(&jpeg_info); 1299 (void) CloseBlob(image); 1300 return(GetFirstImageInList(image)); 1301 } 1302 status=SetImageExtent(image,image->columns,image->rows,exception); 1303 if (status == MagickFalse) 1304 { 1305 jpeg_destroy_decompress(&jpeg_info); 1306 return(DestroyImageList(image)); 1307 } 1308 if ((jpeg_info.output_components != 1) && 1309 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4)) 1310 { 1311 jpeg_destroy_decompress(&jpeg_info); 1312 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported"); 1313 } 1314 memory_info=AcquireVirtualMemory((size_t) image->columns, 1315 jpeg_info.output_components*sizeof(*jpeg_pixels)); 1316 if (memory_info == (MemoryInfo *) NULL) 1317 { 1318 jpeg_destroy_decompress(&jpeg_info); 1319 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 1320 } 1321 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info); 1322 /* 1323 Convert JPEG pixels to pixel packets. 1324 */ 1325 if (setjmp(error_manager.error_recovery) != 0) 1326 { 1327 if (memory_info != (MemoryInfo *) NULL) 1328 memory_info=RelinquishVirtualMemory(memory_info); 1329 jpeg_destroy_decompress(&jpeg_info); 1330 (void) CloseBlob(image); 1331 number_pixels=(MagickSizeType) image->columns*image->rows; 1332 if (number_pixels != 0) 1333 return(GetFirstImageInList(image)); 1334 return(DestroyImage(image)); 1335 } 1336 if (jpeg_info.quantize_colors != 0) 1337 { 1338 image->colors=(size_t) jpeg_info.actual_number_of_colors; 1339 if (jpeg_info.out_color_space == JCS_GRAYSCALE) 1340 for (i=0; i < (ssize_t) image->colors; i++) 1341 { 1342 image->colormap[i].red=(double) ScaleCharToQuantum( 1343 jpeg_info.colormap[0][i]); 1344 image->colormap[i].green=image->colormap[i].red; 1345 image->colormap[i].blue=image->colormap[i].red; 1346 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha; 1347 } 1348 else 1349 for (i=0; i < (ssize_t) image->colors; i++) 1350 { 1351 image->colormap[i].red=(double) ScaleCharToQuantum( 1352 jpeg_info.colormap[0][i]); 1353 image->colormap[i].green=(double) ScaleCharToQuantum( 1354 jpeg_info.colormap[1][i]); 1355 image->colormap[i].blue=(double) ScaleCharToQuantum( 1356 jpeg_info.colormap[2][i]); 1357 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha; 1358 } 1359 } 1360 scanline[0]=(JSAMPROW) jpeg_pixels; 1361 for (y=0; y < (ssize_t) image->rows; y++) 1362 { 1363 register ssize_t 1364 x; 1365 1366 register Quantum 1367 *magick_restrict q; 1368 1369 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1) 1370 { 1371 (void) ThrowMagickException(exception,GetMagickModule(), 1372 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename); 1373 continue; 1374 } 1375 p=jpeg_pixels; 1376 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 1377 if (q == (Quantum *) NULL) 1378 break; 1379 if (jpeg_info.data_precision > 8) 1380 { 1381 unsigned short 1382 scale; 1383 1384 scale=65535/(unsigned short) GetQuantumRange((size_t) 1385 jpeg_info.data_precision); 1386 if (jpeg_info.output_components == 1) 1387 for (x=0; x < (ssize_t) image->columns; x++) 1388 { 1389 ssize_t 1390 pixel; 1391 1392 pixel=(ssize_t) (scale*GETJSAMPLE(*p)); 1393 index=(Quantum) ConstrainColormapIndex(image,pixel,exception); 1394 SetPixelIndex(image,index,q); 1395 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); 1396 p++; 1397 q+=GetPixelChannels(image); 1398 } 1399 else 1400 if (image->colorspace != CMYKColorspace) 1401 for (x=0; x < (ssize_t) image->columns; x++) 1402 { 1403 SetPixelRed(image,ScaleShortToQuantum( 1404 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1405 SetPixelGreen(image,ScaleShortToQuantum( 1406 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1407 SetPixelBlue(image,ScaleShortToQuantum( 1408 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1409 SetPixelAlpha(image,OpaqueAlpha,q); 1410 q+=GetPixelChannels(image); 1411 } 1412 else 1413 for (x=0; x < (ssize_t) image->columns; x++) 1414 { 1415 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum( 1416 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1417 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum( 1418 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1419 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum( 1420 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1421 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum( 1422 (unsigned short) (scale*GETJSAMPLE(*p++))),q); 1423 SetPixelAlpha(image,OpaqueAlpha,q); 1424 q+=GetPixelChannels(image); 1425 } 1426 } 1427 else 1428 if (jpeg_info.output_components == 1) 1429 for (x=0; x < (ssize_t) image->columns; x++) 1430 { 1431 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) GETJSAMPLE(*p), 1432 exception); 1433 SetPixelIndex(image,index,q); 1434 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); 1435 p++; 1436 q+=GetPixelChannels(image); 1437 } 1438 else 1439 if (image->colorspace != CMYKColorspace) 1440 for (x=0; x < (ssize_t) image->columns; x++) 1441 { 1442 SetPixelRed(image,ScaleCharToQuantum((unsigned char) 1443 GETJSAMPLE(*p++)),q); 1444 SetPixelGreen(image,ScaleCharToQuantum((unsigned char) 1445 GETJSAMPLE(*p++)),q); 1446 SetPixelBlue(image,ScaleCharToQuantum((unsigned char) 1447 GETJSAMPLE(*p++)),q); 1448 SetPixelAlpha(image,OpaqueAlpha,q); 1449 q+=GetPixelChannels(image); 1450 } 1451 else 1452 for (x=0; x < (ssize_t) image->columns; x++) 1453 { 1454 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum( 1455 (unsigned char) GETJSAMPLE(*p++)),q); 1456 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum( 1457 (unsigned char) GETJSAMPLE(*p++)),q); 1458 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum( 1459 (unsigned char) GETJSAMPLE(*p++)),q); 1460 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum( 1461 (unsigned char) GETJSAMPLE(*p++)),q); 1462 SetPixelAlpha(image,OpaqueAlpha,q); 1463 q+=GetPixelChannels(image); 1464 } 1465 if (SyncAuthenticPixels(image,exception) == MagickFalse) 1466 break; 1467 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 1468 image->rows); 1469 if (status == MagickFalse) 1470 { 1471 jpeg_abort_decompress(&jpeg_info); 1472 break; 1473 } 1474 } 1475 if (status != MagickFalse) 1476 { 1477 error_manager.finished=MagickTrue; 1478 if (setjmp(error_manager.error_recovery) == 0) 1479 (void) jpeg_finish_decompress(&jpeg_info); 1480 } 1481 /* 1482 Free jpeg resources. 1483 */ 1484 jpeg_destroy_decompress(&jpeg_info); 1485 memory_info=RelinquishVirtualMemory(memory_info); 1486 (void) CloseBlob(image); 1487 return(GetFirstImageInList(image)); 1488 } 1489 #endif 1490 1491 /* 1493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1494 % % 1495 % % 1496 % % 1497 % R e g i s t e r J P E G I m a g e % 1498 % % 1499 % % 1500 % % 1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1502 % 1503 % RegisterJPEGImage() adds properties for the JPEG image format to 1504 % the list of supported formats. The properties include the image format 1505 % tag, a method to read and/or write the format, whether the format 1506 % supports the saving of more than one frame to the same file or blob, 1507 % whether the format supports native in-memory I/O, and a brief 1508 % description of the format. 1509 % 1510 % The format of the RegisterJPEGImage method is: 1511 % 1512 % size_t RegisterJPEGImage(void) 1513 % 1514 */ 1515 ModuleExport size_t RegisterJPEGImage(void) 1516 { 1517 #define JPEGDescription "Joint Photographic Experts Group JFIF format" 1518 1519 char 1520 version[MagickPathExtent]; 1521 1522 MagickInfo 1523 *entry; 1524 1525 *version='\0'; 1526 #if defined(JPEG_LIB_VERSION) 1527 (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION); 1528 #endif 1529 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription); 1530 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION) 1531 entry->flags^=CoderDecoderThreadSupportFlag; 1532 #endif 1533 #if defined(MAGICKCORE_JPEG_DELEGATE) 1534 entry->decoder=(DecodeImageHandler *) ReadJPEGImage; 1535 entry->encoder=(EncodeImageHandler *) WriteJPEGImage; 1536 #endif 1537 entry->magick=(IsImageFormatHandler *) IsJPEG; 1538 entry->flags^=CoderAdjoinFlag; 1539 entry->flags^=CoderUseExtensionFlag; 1540 if (*version != '\0') 1541 entry->version=ConstantString(version); 1542 entry->mime_type=ConstantString("image/jpeg"); 1543 (void) RegisterMagickInfo(entry); 1544 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription); 1545 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION) 1546 entry->flags^=CoderDecoderThreadSupportFlag; 1547 #endif 1548 #if defined(MAGICKCORE_JPEG_DELEGATE) 1549 entry->decoder=(DecodeImageHandler *) ReadJPEGImage; 1550 entry->encoder=(EncodeImageHandler *) WriteJPEGImage; 1551 #endif 1552 entry->magick=(IsImageFormatHandler *) IsJPEG; 1553 entry->flags^=CoderAdjoinFlag; 1554 if (*version != '\0') 1555 entry->version=ConstantString(version); 1556 entry->mime_type=ConstantString("image/jpeg"); 1557 (void) RegisterMagickInfo(entry); 1558 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription); 1559 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION) 1560 entry->flags^=CoderDecoderThreadSupportFlag; 1561 #endif 1562 #if defined(MAGICKCORE_JPEG_DELEGATE) 1563 entry->decoder=(DecodeImageHandler *) ReadJPEGImage; 1564 entry->encoder=(EncodeImageHandler *) WriteJPEGImage; 1565 #endif 1566 entry->flags^=CoderAdjoinFlag; 1567 entry->flags^=CoderUseExtensionFlag; 1568 if (*version != '\0') 1569 entry->version=ConstantString(version); 1570 entry->mime_type=ConstantString("image/jpeg"); 1571 (void) RegisterMagickInfo(entry); 1572 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription); 1573 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION) 1574 entry->flags^=CoderDecoderThreadSupportFlag; 1575 #endif 1576 #if defined(MAGICKCORE_JPEG_DELEGATE) 1577 entry->decoder=(DecodeImageHandler *) ReadJPEGImage; 1578 entry->encoder=(EncodeImageHandler *) WriteJPEGImage; 1579 #endif 1580 entry->flags^=CoderAdjoinFlag; 1581 entry->flags^=CoderUseExtensionFlag; 1582 if (*version != '\0') 1583 entry->version=ConstantString(version); 1584 entry->mime_type=ConstantString("image/jpeg"); 1585 (void) RegisterMagickInfo(entry); 1586 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription); 1587 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION) 1588 entry->flags^=CoderDecoderThreadSupportFlag; 1589 #endif 1590 #if defined(MAGICKCORE_JPEG_DELEGATE) 1591 entry->decoder=(DecodeImageHandler *) ReadJPEGImage; 1592 entry->encoder=(EncodeImageHandler *) WriteJPEGImage; 1593 #endif 1594 entry->flags^=CoderAdjoinFlag; 1595 entry->flags^=CoderUseExtensionFlag; 1596 if (*version != '\0') 1597 entry->version=ConstantString(version); 1598 entry->mime_type=ConstantString("image/jpeg"); 1599 (void) RegisterMagickInfo(entry); 1600 return(MagickImageCoderSignature); 1601 } 1602 1603 /* 1605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1606 % % 1607 % % 1608 % % 1609 % U n r e g i s t e r J P E G I m a g e % 1610 % % 1611 % % 1612 % % 1613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1614 % 1615 % UnregisterJPEGImage() removes format registrations made by the 1616 % JPEG module from the list of supported formats. 1617 % 1618 % The format of the UnregisterJPEGImage method is: 1619 % 1620 % UnregisterJPEGImage(void) 1621 % 1622 */ 1623 ModuleExport void UnregisterJPEGImage(void) 1624 { 1625 (void) UnregisterMagickInfo("PJPG"); 1626 (void) UnregisterMagickInfo("JPS"); 1627 (void) UnregisterMagickInfo("JPG"); 1628 (void) UnregisterMagickInfo("JPEG"); 1629 (void) UnregisterMagickInfo("JPE"); 1630 } 1631 1632 #if defined(MAGICKCORE_JPEG_DELEGATE) 1634 /* 1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1636 % % 1637 % % 1638 % % 1639 % W r i t e J P E G I m a g e % 1640 % % 1641 % % 1642 % % 1643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1644 % 1645 % WriteJPEGImage() writes a JPEG image file and returns it. It 1646 % allocates the memory necessary for the new Image structure and returns a 1647 % pointer to the new image. 1648 % 1649 % The format of the WriteJPEGImage method is: 1650 % 1651 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info, 1652 % Image *image,ExceptionInfo *exception) 1653 % 1654 % A description of each parameter follows: 1655 % 1656 % o image_info: the image info. 1657 % 1658 % o jpeg_image: The image. 1659 % 1660 % o exception: return any errors or warnings in this structure. 1661 % 1662 */ 1663 1664 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table) 1665 { 1666 assert(table != (QuantizationTable *) NULL); 1667 if (table->slot != (char *) NULL) 1668 table->slot=DestroyString(table->slot); 1669 if (table->description != (char *) NULL) 1670 table->description=DestroyString(table->description); 1671 if (table->levels != (unsigned int *) NULL) 1672 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels); 1673 table=(QuantizationTable *) RelinquishMagickMemory(table); 1674 return(table); 1675 } 1676 1677 static boolean EmptyOutputBuffer(j_compress_ptr cinfo) 1678 { 1679 DestinationManager 1680 *destination; 1681 1682 destination=(DestinationManager *) cinfo->dest; 1683 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image, 1684 MaxBufferExtent,destination->buffer); 1685 if (destination->manager.free_in_buffer != MaxBufferExtent) 1686 ERREXIT(cinfo,JERR_FILE_WRITE); 1687 destination->manager.next_output_byte=destination->buffer; 1688 return(TRUE); 1689 } 1690 1691 static QuantizationTable *GetQuantizationTable(const char *filename, 1692 const char *slot,ExceptionInfo *exception) 1693 { 1694 char 1695 *p, 1696 *xml; 1697 1698 const char 1699 *attribute, 1700 *content; 1701 1702 double 1703 value; 1704 1705 register ssize_t 1706 i; 1707 1708 ssize_t 1709 j; 1710 1711 QuantizationTable 1712 *table; 1713 1714 size_t 1715 length; 1716 1717 XMLTreeInfo 1718 *description, 1719 *levels, 1720 *quantization_tables, 1721 *table_iterator; 1722 1723 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), 1724 "Loading quantization tables \"%s\" ...",filename); 1725 table=(QuantizationTable *) NULL; 1726 xml=FileToString(filename,~0UL,exception); 1727 if (xml == (char *) NULL) 1728 return(table); 1729 quantization_tables=NewXMLTree(xml,exception); 1730 if (quantization_tables == (XMLTreeInfo *) NULL) 1731 { 1732 xml=DestroyString(xml); 1733 return(table); 1734 } 1735 for (table_iterator=GetXMLTreeChild(quantization_tables,"table"); 1736 table_iterator != (XMLTreeInfo *) NULL; 1737 table_iterator=GetNextXMLTreeTag(table_iterator)) 1738 { 1739 attribute=GetXMLTreeAttribute(table_iterator,"slot"); 1740 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0)) 1741 break; 1742 attribute=GetXMLTreeAttribute(table_iterator,"alias"); 1743 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0)) 1744 break; 1745 } 1746 if (table_iterator == (XMLTreeInfo *) NULL) 1747 { 1748 xml=DestroyString(xml); 1749 return(table); 1750 } 1751 description=GetXMLTreeChild(table_iterator,"description"); 1752 if (description == (XMLTreeInfo *) NULL) 1753 { 1754 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1755 "XmlMissingElement","<description>, slot \"%s\"",slot); 1756 quantization_tables=DestroyXMLTree(quantization_tables); 1757 xml=DestroyString(xml); 1758 return(table); 1759 } 1760 levels=GetXMLTreeChild(table_iterator,"levels"); 1761 if (levels == (XMLTreeInfo *) NULL) 1762 { 1763 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1764 "XmlMissingElement","<levels>, slot \"%s\"",slot); 1765 quantization_tables=DestroyXMLTree(quantization_tables); 1766 xml=DestroyString(xml); 1767 return(table); 1768 } 1769 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table)); 1770 if (table == (QuantizationTable *) NULL) 1771 ThrowFatalException(ResourceLimitFatalError, 1772 "UnableToAcquireQuantizationTable"); 1773 table->slot=(char *) NULL; 1774 table->description=(char *) NULL; 1775 table->levels=(unsigned int *) NULL; 1776 attribute=GetXMLTreeAttribute(table_iterator,"slot"); 1777 if (attribute != (char *) NULL) 1778 table->slot=ConstantString(attribute); 1779 content=GetXMLTreeContent(description); 1780 if (content != (char *) NULL) 1781 table->description=ConstantString(content); 1782 attribute=GetXMLTreeAttribute(levels,"width"); 1783 if (attribute == (char *) NULL) 1784 { 1785 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1786 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot); 1787 quantization_tables=DestroyXMLTree(quantization_tables); 1788 table=DestroyQuantizationTable(table); 1789 xml=DestroyString(xml); 1790 return(table); 1791 } 1792 table->width=StringToUnsignedLong(attribute); 1793 if (table->width == 0) 1794 { 1795 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1796 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot); 1797 quantization_tables=DestroyXMLTree(quantization_tables); 1798 table=DestroyQuantizationTable(table); 1799 xml=DestroyString(xml); 1800 return(table); 1801 } 1802 attribute=GetXMLTreeAttribute(levels,"height"); 1803 if (attribute == (char *) NULL) 1804 { 1805 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1806 "XmlMissingAttribute","<levels height>, table \"%s\"",slot); 1807 quantization_tables=DestroyXMLTree(quantization_tables); 1808 table=DestroyQuantizationTable(table); 1809 xml=DestroyString(xml); 1810 return(table); 1811 } 1812 table->height=StringToUnsignedLong(attribute); 1813 if (table->height == 0) 1814 { 1815 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1816 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot); 1817 quantization_tables=DestroyXMLTree(quantization_tables); 1818 table=DestroyQuantizationTable(table); 1819 xml=DestroyString(xml); 1820 return(table); 1821 } 1822 attribute=GetXMLTreeAttribute(levels,"divisor"); 1823 if (attribute == (char *) NULL) 1824 { 1825 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1826 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot); 1827 quantization_tables=DestroyXMLTree(quantization_tables); 1828 table=DestroyQuantizationTable(table); 1829 xml=DestroyString(xml); 1830 return(table); 1831 } 1832 table->divisor=InterpretLocaleValue(attribute,(char **) NULL); 1833 if (table->divisor == 0.0) 1834 { 1835 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1836 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot); 1837 quantization_tables=DestroyXMLTree(quantization_tables); 1838 table=DestroyQuantizationTable(table); 1839 xml=DestroyString(xml); 1840 return(table); 1841 } 1842 content=GetXMLTreeContent(levels); 1843 if (content == (char *) NULL) 1844 { 1845 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1846 "XmlMissingContent","<levels>, table \"%s\"",slot); 1847 quantization_tables=DestroyXMLTree(quantization_tables); 1848 table=DestroyQuantizationTable(table); 1849 xml=DestroyString(xml); 1850 return(table); 1851 } 1852 length=(size_t) table->width*table->height; 1853 if (length < 64) 1854 length=64; 1855 table->levels=(unsigned int *) AcquireQuantumMemory(length, 1856 sizeof(*table->levels)); 1857 if (table->levels == (unsigned int *) NULL) 1858 ThrowFatalException(ResourceLimitFatalError, 1859 "UnableToAcquireQuantizationTable"); 1860 for (i=0; i < (ssize_t) (table->width*table->height); i++) 1861 { 1862 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/ 1863 table->divisor+0.5); 1864 while (isspace((int) ((unsigned char) *p)) != 0) 1865 p++; 1866 if (*p == ',') 1867 p++; 1868 content=p; 1869 } 1870 value=InterpretLocaleValue(content,&p); 1871 (void) value; 1872 if (p != content) 1873 { 1874 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1875 "XmlInvalidContent","<level> too many values, table \"%s\"",slot); 1876 quantization_tables=DestroyXMLTree(quantization_tables); 1877 table=DestroyQuantizationTable(table); 1878 xml=DestroyString(xml); 1879 return(table); 1880 } 1881 for (j=i; j < 64; j++) 1882 table->levels[j]=table->levels[j-1]; 1883 quantization_tables=DestroyXMLTree(quantization_tables); 1884 xml=DestroyString(xml); 1885 return(table); 1886 } 1887 1888 static void InitializeDestination(j_compress_ptr cinfo) 1889 { 1890 DestinationManager 1891 *destination; 1892 1893 destination=(DestinationManager *) cinfo->dest; 1894 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small) 1895 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET)); 1896 destination->manager.next_output_byte=destination->buffer; 1897 destination->manager.free_in_buffer=MaxBufferExtent; 1898 } 1899 1900 static void TerminateDestination(j_compress_ptr cinfo) 1901 { 1902 DestinationManager 1903 *destination; 1904 1905 destination=(DestinationManager *) cinfo->dest; 1906 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0) 1907 { 1908 ssize_t 1909 count; 1910 1911 count=WriteBlob(destination->image,MaxBufferExtent- 1912 destination->manager.free_in_buffer,destination->buffer); 1913 if (count != (ssize_t) 1914 (MaxBufferExtent-destination->manager.free_in_buffer)) 1915 ERREXIT(cinfo,JERR_FILE_WRITE); 1916 } 1917 } 1918 1919 static void WriteProfile(j_compress_ptr jpeg_info,Image *image) 1920 { 1921 const char 1922 *name; 1923 1924 const StringInfo 1925 *profile; 1926 1927 MagickBooleanType 1928 iptc; 1929 1930 register ssize_t 1931 i; 1932 1933 size_t 1934 length, 1935 tag_length; 1936 1937 StringInfo 1938 *custom_profile; 1939 1940 /* 1941 Save image profile as a APP marker. 1942 */ 1943 iptc=MagickFalse; 1944 custom_profile=AcquireStringInfo(65535L); 1945 ResetImageProfileIterator(image); 1946 for (name=GetNextImageProfile(image); name != (const char *) NULL; ) 1947 { 1948 profile=GetImageProfile(image,name); 1949 if (LocaleCompare(name,"EXIF") == 0) 1950 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L) 1951 { 1952 length=MagickMin(GetStringInfoLength(profile)-i,65533L); 1953 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i, 1954 (unsigned int) length); 1955 } 1956 if (LocaleCompare(name,"ICC") == 0) 1957 { 1958 register unsigned char 1959 *p; 1960 1961 tag_length=strlen(ICC_PROFILE); 1962 p=GetStringInfoDatum(custom_profile); 1963 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length); 1964 p[tag_length]='\0'; 1965 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L) 1966 { 1967 length=MagickMin(GetStringInfoLength(profile)-i,65519L); 1968 p[12]=(unsigned char) ((i/65519L)+1); 1969 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1); 1970 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i, 1971 length); 1972 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum( 1973 custom_profile),(unsigned int) (length+tag_length+3)); 1974 } 1975 } 1976 if (((LocaleCompare(name,"IPTC") == 0) || 1977 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse)) 1978 { 1979 register unsigned char 1980 *p; 1981 1982 size_t 1983 roundup; 1984 1985 iptc=MagickTrue; 1986 p=GetStringInfoDatum(custom_profile); 1987 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L) 1988 { 1989 length=MagickMin(GetStringInfoLength(profile)-i,65500L); 1990 roundup=(size_t) (length & 0x01); 1991 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0) 1992 { 1993 (void) memcpy(p,"Photoshop 3.0 ",14); 1994 tag_length=14; 1995 } 1996 else 1997 { 1998 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24); 1999 tag_length=26; 2000 p[24]=(unsigned char) (length >> 8); 2001 p[25]=(unsigned char) (length & 0xff); 2002 } 2003 p[13]=0x00; 2004 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length); 2005 if (roundup != 0) 2006 p[length+tag_length]='\0'; 2007 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum( 2008 custom_profile),(unsigned int) (length+tag_length+roundup)); 2009 } 2010 } 2011 if (LocaleCompare(name,"XMP") == 0) 2012 { 2013 StringInfo 2014 *xmp_profile; 2015 2016 /* 2017 Add namespace to XMP profile. 2018 */ 2019 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ "); 2020 if (xmp_profile != (StringInfo *) NULL) 2021 { 2022 if (profile != (StringInfo *) NULL) 2023 ConcatenateStringInfo(xmp_profile,profile); 2024 GetStringInfoDatum(xmp_profile)[28]='\0'; 2025 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L) 2026 { 2027 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L); 2028 jpeg_write_marker(jpeg_info,XML_MARKER, 2029 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length); 2030 } 2031 xmp_profile=DestroyStringInfo(xmp_profile); 2032 } 2033 } 2034 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2035 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile)); 2036 name=GetNextImageProfile(image); 2037 } 2038 custom_profile=DestroyStringInfo(custom_profile); 2039 } 2040 2041 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image) 2042 { 2043 DestinationManager 2044 *destination; 2045 2046 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) 2047 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager)); 2048 destination=(DestinationManager *) cinfo->dest; 2049 destination->manager.init_destination=InitializeDestination; 2050 destination->manager.empty_output_buffer=EmptyOutputBuffer; 2051 destination->manager.term_destination=TerminateDestination; 2052 destination->image=image; 2053 } 2054 2055 static char **SamplingFactorToList(const char *text) 2056 { 2057 char 2058 **textlist; 2059 2060 register char 2061 *q; 2062 2063 register const char 2064 *p; 2065 2066 register ssize_t 2067 i; 2068 2069 if (text == (char *) NULL) 2070 return((char **) NULL); 2071 /* 2072 Convert string to an ASCII list. 2073 */ 2074 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS, 2075 sizeof(*textlist)); 2076 if (textlist == (char **) NULL) 2077 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText"); 2078 p=text; 2079 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++) 2080 { 2081 for (q=(char *) p; *q != '\0'; q++) 2082 if (*q == ',') 2083 break; 2084 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent, 2085 sizeof(*textlist[i])); 2086 if (textlist[i] == (char *) NULL) 2087 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText"); 2088 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1)); 2089 if (*q == '\r') 2090 q++; 2091 if (*q == '\0') 2092 break; 2093 p=q+1; 2094 } 2095 for (i++; i < (ssize_t) MAX_COMPONENTS; i++) 2096 textlist[i]=ConstantString("1x1"); 2097 return(textlist); 2098 } 2099 2100 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info, 2101 Image *image,ExceptionInfo *exception) 2102 { 2103 const char 2104 *option, 2105 *sampling_factor, 2106 *value; 2107 2108 ErrorManager 2109 error_manager; 2110 2111 Image 2112 *volatile volatile_image; 2113 2114 int 2115 colorspace, 2116 quality; 2117 2118 JSAMPLE 2119 *volatile jpeg_pixels; 2120 2121 JSAMPROW 2122 scanline[1]; 2123 2124 MagickBooleanType 2125 status; 2126 2127 MemoryInfo 2128 *memory_info; 2129 2130 register JSAMPLE 2131 *q; 2132 2133 register ssize_t 2134 i; 2135 2136 ssize_t 2137 y; 2138 2139 struct jpeg_compress_struct 2140 jpeg_info; 2141 2142 struct jpeg_error_mgr 2143 jpeg_error; 2144 2145 unsigned short 2146 scale; 2147 2148 /* 2149 Open image file. 2150 */ 2151 assert(image_info != (const ImageInfo *) NULL); 2152 assert(image_info->signature == MagickCoreSignature); 2153 assert(image != (Image *) NULL); 2154 assert(image->signature == MagickCoreSignature); 2155 if (image->debug != MagickFalse) 2156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2157 assert(exception != (ExceptionInfo *) NULL); 2158 assert(exception->signature == MagickCoreSignature); 2159 if ((LocaleCompare(image_info->magick,"JPS") == 0) && 2160 (image->next != (Image *) NULL)) 2161 image=AppendImages(image,MagickFalse,exception); 2162 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 2163 if (status == MagickFalse) 2164 return(status); 2165 /* 2166 Initialize JPEG parameters. 2167 */ 2168 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager)); 2169 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info)); 2170 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error)); 2171 volatile_image=image; 2172 jpeg_info.client_data=(void *) volatile_image; 2173 jpeg_info.err=jpeg_std_error(&jpeg_error); 2174 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler; 2175 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler; 2176 error_manager.exception=exception; 2177 error_manager.image=volatile_image; 2178 memory_info=(MemoryInfo *) NULL; 2179 if (setjmp(error_manager.error_recovery) != 0) 2180 { 2181 jpeg_destroy_compress(&jpeg_info); 2182 (void) CloseBlob(volatile_image); 2183 return(MagickFalse); 2184 } 2185 jpeg_info.client_data=(void *) &error_manager; 2186 jpeg_create_compress(&jpeg_info); 2187 JPEGDestinationManager(&jpeg_info,image); 2188 if ((image->columns != (unsigned int) image->columns) || 2189 (image->rows != (unsigned int) image->rows)) 2190 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 2191 jpeg_info.image_width=(unsigned int) image->columns; 2192 jpeg_info.image_height=(unsigned int) image->rows; 2193 jpeg_info.input_components=3; 2194 jpeg_info.data_precision=8; 2195 jpeg_info.in_color_space=JCS_RGB; 2196 switch (image->colorspace) 2197 { 2198 case CMYKColorspace: 2199 { 2200 jpeg_info.input_components=4; 2201 jpeg_info.in_color_space=JCS_CMYK; 2202 break; 2203 } 2204 case YCbCrColorspace: 2205 case Rec601YCbCrColorspace: 2206 case Rec709YCbCrColorspace: 2207 { 2208 jpeg_info.in_color_space=JCS_YCbCr; 2209 break; 2210 } 2211 case GRAYColorspace: 2212 { 2213 if (image_info->type == TrueColorType) 2214 break; 2215 jpeg_info.input_components=1; 2216 jpeg_info.in_color_space=JCS_GRAYSCALE; 2217 break; 2218 } 2219 default: 2220 { 2221 (void) TransformImageColorspace(image,sRGBColorspace,exception); 2222 if (image_info->type == TrueColorType) 2223 break; 2224 if (SetImageGray(image,exception) != MagickFalse) 2225 { 2226 jpeg_info.input_components=1; 2227 jpeg_info.in_color_space=JCS_GRAYSCALE; 2228 } 2229 break; 2230 } 2231 } 2232 jpeg_set_defaults(&jpeg_info); 2233 if (jpeg_info.in_color_space == JCS_CMYK) 2234 jpeg_set_colorspace(&jpeg_info,JCS_YCCK); 2235 if ((jpeg_info.data_precision != 12) && (image->depth <= 8)) 2236 jpeg_info.data_precision=8; 2237 else 2238 jpeg_info.data_precision=BITS_IN_JSAMPLE; 2239 if (image->debug != MagickFalse) 2240 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2241 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y); 2242 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0)) 2243 { 2244 /* 2245 Set image resolution. 2246 */ 2247 jpeg_info.write_JFIF_header=TRUE; 2248 jpeg_info.X_density=(UINT16) image->resolution.x; 2249 jpeg_info.Y_density=(UINT16) image->resolution.y; 2250 /* 2251 Set image resolution units. 2252 */ 2253 if (image->units == PixelsPerInchResolution) 2254 jpeg_info.density_unit=(UINT8) 1; 2255 if (image->units == PixelsPerCentimeterResolution) 2256 jpeg_info.density_unit=(UINT8) 2; 2257 } 2258 jpeg_info.dct_method=JDCT_FLOAT; 2259 option=GetImageOption(image_info,"jpeg:dct-method"); 2260 if (option != (const char *) NULL) 2261 switch (*option) 2262 { 2263 case 'D': 2264 case 'd': 2265 { 2266 if (LocaleCompare(option,"default") == 0) 2267 jpeg_info.dct_method=JDCT_DEFAULT; 2268 break; 2269 } 2270 case 'F': 2271 case 'f': 2272 { 2273 if (LocaleCompare(option,"fastest") == 0) 2274 jpeg_info.dct_method=JDCT_FASTEST; 2275 if (LocaleCompare(option,"float") == 0) 2276 jpeg_info.dct_method=JDCT_FLOAT; 2277 break; 2278 } 2279 case 'I': 2280 case 'i': 2281 { 2282 if (LocaleCompare(option,"ifast") == 0) 2283 jpeg_info.dct_method=JDCT_IFAST; 2284 if (LocaleCompare(option,"islow") == 0) 2285 jpeg_info.dct_method=JDCT_ISLOW; 2286 break; 2287 } 2288 } 2289 option=GetImageOption(image_info,"jpeg:optimize-coding"); 2290 if (option != (const char *) NULL) 2291 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : 2292 FALSE; 2293 else 2294 { 2295 MagickSizeType 2296 length; 2297 2298 length=(MagickSizeType) jpeg_info.input_components*image->columns* 2299 image->rows*sizeof(JSAMPLE); 2300 if (length == (MagickSizeType) ((size_t) length)) 2301 { 2302 /* 2303 Perform optimization only if available memory resources permit it. 2304 */ 2305 status=AcquireMagickResource(MemoryResource,length); 2306 RelinquishMagickResource(MemoryResource,length); 2307 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE; 2308 } 2309 } 2310 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED) 2311 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) || 2312 (image_info->interlace != NoInterlace)) 2313 { 2314 if (image->debug != MagickFalse) 2315 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2316 "Interlace: progressive"); 2317 jpeg_simple_progression(&jpeg_info); 2318 } 2319 else 2320 if (image->debug != MagickFalse) 2321 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2322 "Interlace: non-progressive"); 2323 #else 2324 if (image->debug != MagickFalse) 2325 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2326 "Interlace: nonprogressive"); 2327 #endif 2328 quality=92; 2329 if ((image_info->compression != LosslessJPEGCompression) && 2330 (image->quality <= 100)) 2331 { 2332 if (image->quality != UndefinedCompressionQuality) 2333 quality=(int) image->quality; 2334 if (image->debug != MagickFalse) 2335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g", 2336 (double) image->quality); 2337 } 2338 else 2339 { 2340 #if !defined(C_LOSSLESS_SUPPORTED) 2341 quality=100; 2342 if (image->debug != MagickFalse) 2343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100"); 2344 #else 2345 if (image->quality < 100) 2346 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning, 2347 "LosslessToLossyJPEGConversion",image->filename); 2348 else 2349 { 2350 int 2351 point_transform, 2352 predictor; 2353 2354 predictor=image->quality/100; /* range 1-7 */ 2355 point_transform=image->quality % 20; /* range 0-15 */ 2356 jpeg_simple_lossless(&jpeg_info,predictor,point_transform); 2357 if (image->debug != MagickFalse) 2358 { 2359 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2360 "Compression: lossless"); 2361 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2362 "Predictor: %d",predictor); 2363 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2364 "Point Transform: %d",point_transform); 2365 } 2366 } 2367 #endif 2368 } 2369 option=GetImageOption(image_info,"jpeg:extent"); 2370 if (option != (const char *) NULL) 2371 { 2372 Image 2373 *jpeg_image; 2374 2375 ImageInfo 2376 *extent_info; 2377 2378 extent_info=CloneImageInfo(image_info); 2379 extent_info->blob=NULL; 2380 jpeg_image=CloneImage(image,0,0,MagickTrue,exception); 2381 if (jpeg_image != (Image *) NULL) 2382 { 2383 MagickSizeType 2384 extent; 2385 2386 size_t 2387 maximum, 2388 minimum; 2389 2390 /* 2391 Search for compression quality that does not exceed image extent. 2392 */ 2393 extent_info->quality=0; 2394 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0); 2395 (void) DeleteImageOption(extent_info,"jpeg:extent"); 2396 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent"); 2397 maximum=image_info->quality; 2398 if (maximum < 2) 2399 maximum=101; 2400 for (minimum=2; minimum < maximum; ) 2401 { 2402 (void) AcquireUniqueFilename(jpeg_image->filename); 2403 jpeg_image->quality=minimum+(maximum-minimum+1)/2; 2404 status=WriteJPEGImage(extent_info,jpeg_image,exception); 2405 if (GetBlobSize(jpeg_image) <= extent) 2406 minimum=jpeg_image->quality+1; 2407 else 2408 maximum=jpeg_image->quality-1; 2409 (void) RelinquishUniqueFileResource(jpeg_image->filename); 2410 } 2411 quality=(int) minimum-1; 2412 jpeg_image=DestroyImage(jpeg_image); 2413 } 2414 extent_info=DestroyImageInfo(extent_info); 2415 } 2416 jpeg_set_quality(&jpeg_info,quality,TRUE); 2417 #if (JPEG_LIB_VERSION >= 70) 2418 option=GetImageOption(image_info,"quality"); 2419 if (option != (const char *) NULL) 2420 { 2421 GeometryInfo 2422 geometry_info; 2423 2424 int 2425 flags; 2426 2427 /* 2428 Set quality scaling for luminance and chrominance separately. 2429 */ 2430 flags=ParseGeometry(option,&geometry_info); 2431 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0)) 2432 { 2433 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int) 2434 (geometry_info.rho+0.5)); 2435 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int) 2436 (geometry_info.sigma+0.5)); 2437 jpeg_default_qtables(&jpeg_info,TRUE); 2438 } 2439 } 2440 #endif 2441 colorspace=jpeg_info.in_color_space; 2442 value=GetImageOption(image_info,"jpeg:colorspace"); 2443 if (value == (char *) NULL) 2444 value=GetImageProperty(image,"jpeg:colorspace",exception); 2445 if (value != (char *) NULL) 2446 colorspace=StringToInteger(value); 2447 sampling_factor=(const char *) NULL; 2448 if (colorspace == jpeg_info.in_color_space) 2449 { 2450 value=GetImageOption(image_info,"jpeg:sampling-factor"); 2451 if (value == (char *) NULL) 2452 value=GetImageProperty(image,"jpeg:sampling-factor",exception); 2453 if (value != (char *) NULL) 2454 { 2455 sampling_factor=value; 2456 if (image->debug != MagickFalse) 2457 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2458 " Input sampling-factors=%s",sampling_factor); 2459 } 2460 } 2461 value=GetImageOption(image_info,"jpeg:sampling-factor"); 2462 if (image_info->sampling_factor != (char *) NULL) 2463 sampling_factor=image_info->sampling_factor; 2464 if (sampling_factor == (const char *) NULL) 2465 { 2466 if (quality >= 90) 2467 for (i=0; i < MAX_COMPONENTS; i++) 2468 { 2469 jpeg_info.comp_info[i].h_samp_factor=1; 2470 jpeg_info.comp_info[i].v_samp_factor=1; 2471 } 2472 } 2473 else 2474 { 2475 char 2476 **factors; 2477 2478 GeometryInfo 2479 geometry_info; 2480 2481 MagickStatusType 2482 flags; 2483 2484 /* 2485 Set sampling factor. 2486 */ 2487 i=0; 2488 factors=SamplingFactorToList(sampling_factor); 2489 if (factors != (char **) NULL) 2490 { 2491 for (i=0; i < MAX_COMPONENTS; i++) 2492 { 2493 if (factors[i] == (char *) NULL) 2494 break; 2495 flags=ParseGeometry(factors[i],&geometry_info); 2496 if ((flags & SigmaValue) == 0) 2497 geometry_info.sigma=geometry_info.rho; 2498 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho; 2499 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma; 2500 factors[i]=(char *) RelinquishMagickMemory(factors[i]); 2501 } 2502 factors=(char **) RelinquishMagickMemory(factors); 2503 } 2504 for ( ; i < MAX_COMPONENTS; i++) 2505 { 2506 jpeg_info.comp_info[i].h_samp_factor=1; 2507 jpeg_info.comp_info[i].v_samp_factor=1; 2508 } 2509 } 2510 option=GetImageOption(image_info,"jpeg:q-table"); 2511 if (option != (const char *) NULL) 2512 { 2513 QuantizationTable 2514 *table; 2515 2516 /* 2517 Custom quantization tables. 2518 */ 2519 table=GetQuantizationTable(option,"0",exception); 2520 if (table != (QuantizationTable *) NULL) 2521 { 2522 for (i=0; i < MAX_COMPONENTS; i++) 2523 jpeg_info.comp_info[i].quant_tbl_no=0; 2524 jpeg_add_quant_table(&jpeg_info,0,table->levels, 2525 jpeg_quality_scaling(quality),0); 2526 table=DestroyQuantizationTable(table); 2527 } 2528 table=GetQuantizationTable(option,"1",exception); 2529 if (table != (QuantizationTable *) NULL) 2530 { 2531 for (i=1; i < MAX_COMPONENTS; i++) 2532 jpeg_info.comp_info[i].quant_tbl_no=1; 2533 jpeg_add_quant_table(&jpeg_info,1,table->levels, 2534 jpeg_quality_scaling(quality),0); 2535 table=DestroyQuantizationTable(table); 2536 } 2537 table=GetQuantizationTable(option,"2",exception); 2538 if (table != (QuantizationTable *) NULL) 2539 { 2540 for (i=2; i < MAX_COMPONENTS; i++) 2541 jpeg_info.comp_info[i].quant_tbl_no=2; 2542 jpeg_add_quant_table(&jpeg_info,2,table->levels, 2543 jpeg_quality_scaling(quality),0); 2544 table=DestroyQuantizationTable(table); 2545 } 2546 table=GetQuantizationTable(option,"3",exception); 2547 if (table != (QuantizationTable *) NULL) 2548 { 2549 for (i=3; i < MAX_COMPONENTS; i++) 2550 jpeg_info.comp_info[i].quant_tbl_no=3; 2551 jpeg_add_quant_table(&jpeg_info,3,table->levels, 2552 jpeg_quality_scaling(quality),0); 2553 table=DestroyQuantizationTable(table); 2554 } 2555 } 2556 jpeg_start_compress(&jpeg_info,TRUE); 2557 if (image->debug != MagickFalse) 2558 { 2559 if (image->storage_class == PseudoClass) 2560 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2561 "Storage class: PseudoClass"); 2562 else 2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2564 "Storage class: DirectClass"); 2565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g", 2566 (double) image->depth); 2567 if (image->colors != 0) 2568 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2569 "Number of colors: %.20g",(double) image->colors); 2570 else 2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2572 "Number of colors: unspecified"); 2573 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2574 "JPEG data precision: %d",(int) jpeg_info.data_precision); 2575 switch (image->colorspace) 2576 { 2577 case CMYKColorspace: 2578 { 2579 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2580 "Storage class: DirectClass"); 2581 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2582 "Colorspace: CMYK"); 2583 break; 2584 } 2585 case YCbCrColorspace: 2586 case Rec601YCbCrColorspace: 2587 case Rec709YCbCrColorspace: 2588 { 2589 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2590 "Colorspace: YCbCr"); 2591 break; 2592 } 2593 default: 2594 break; 2595 } 2596 switch (image->colorspace) 2597 { 2598 case CMYKColorspace: 2599 { 2600 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2601 "Colorspace: CMYK"); 2602 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2603 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d", 2604 jpeg_info.comp_info[0].h_samp_factor, 2605 jpeg_info.comp_info[0].v_samp_factor, 2606 jpeg_info.comp_info[1].h_samp_factor, 2607 jpeg_info.comp_info[1].v_samp_factor, 2608 jpeg_info.comp_info[2].h_samp_factor, 2609 jpeg_info.comp_info[2].v_samp_factor, 2610 jpeg_info.comp_info[3].h_samp_factor, 2611 jpeg_info.comp_info[3].v_samp_factor); 2612 break; 2613 } 2614 case GRAYColorspace: 2615 { 2616 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2617 "Colorspace: GRAY"); 2618 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2619 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor, 2620 jpeg_info.comp_info[0].v_samp_factor); 2621 break; 2622 } 2623 case sRGBColorspace: 2624 case RGBColorspace: 2625 { 2626 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2627 "Image colorspace is RGB"); 2628 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2629 "Sampling factors: %dx%d,%dx%d,%dx%d", 2630 jpeg_info.comp_info[0].h_samp_factor, 2631 jpeg_info.comp_info[0].v_samp_factor, 2632 jpeg_info.comp_info[1].h_samp_factor, 2633 jpeg_info.comp_info[1].v_samp_factor, 2634 jpeg_info.comp_info[2].h_samp_factor, 2635 jpeg_info.comp_info[2].v_samp_factor); 2636 break; 2637 } 2638 case YCbCrColorspace: 2639 case Rec601YCbCrColorspace: 2640 case Rec709YCbCrColorspace: 2641 { 2642 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2643 "Colorspace: YCbCr"); 2644 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2645 "Sampling factors: %dx%d,%dx%d,%dx%d", 2646 jpeg_info.comp_info[0].h_samp_factor, 2647 jpeg_info.comp_info[0].v_samp_factor, 2648 jpeg_info.comp_info[1].h_samp_factor, 2649 jpeg_info.comp_info[1].v_samp_factor, 2650 jpeg_info.comp_info[2].h_samp_factor, 2651 jpeg_info.comp_info[2].v_samp_factor); 2652 break; 2653 } 2654 default: 2655 { 2656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d", 2657 image->colorspace); 2658 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 2659 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d", 2660 jpeg_info.comp_info[0].h_samp_factor, 2661 jpeg_info.comp_info[0].v_samp_factor, 2662 jpeg_info.comp_info[1].h_samp_factor, 2663 jpeg_info.comp_info[1].v_samp_factor, 2664 jpeg_info.comp_info[2].h_samp_factor, 2665 jpeg_info.comp_info[2].v_samp_factor, 2666 jpeg_info.comp_info[3].h_samp_factor, 2667 jpeg_info.comp_info[3].v_samp_factor); 2668 break; 2669 } 2670 } 2671 } 2672 /* 2673 Write JPEG profiles. 2674 */ 2675 value=GetImageProperty(image,"comment",exception); 2676 if (value != (char *) NULL) 2677 for (i=0; i < (ssize_t) strlen(value); i+=65533L) 2678 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i, 2679 (unsigned int) MagickMin((size_t) strlen(value+i),65533L)); 2680 if (image->profiles != (void *) NULL) 2681 WriteProfile(&jpeg_info,image); 2682 /* 2683 Convert MIFF to JPEG raster pixels. 2684 */ 2685 memory_info=AcquireVirtualMemory((size_t) image->columns, 2686 jpeg_info.input_components*sizeof(*jpeg_pixels)); 2687 if (memory_info == (MemoryInfo *) NULL) 2688 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 2689 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info); 2690 if (setjmp(error_manager.error_recovery) != 0) 2691 { 2692 jpeg_destroy_compress(&jpeg_info); 2693 if (memory_info != (MemoryInfo *) NULL) 2694 memory_info=RelinquishVirtualMemory(memory_info); 2695 (void) CloseBlob(image); 2696 return(MagickFalse); 2697 } 2698 scanline[0]=(JSAMPROW) jpeg_pixels; 2699 scale=65535/(unsigned short) GetQuantumRange((size_t) 2700 jpeg_info.data_precision); 2701 if (scale == 0) 2702 scale=1; 2703 if (jpeg_info.data_precision <= 8) 2704 { 2705 if ((jpeg_info.in_color_space == JCS_RGB) || 2706 (jpeg_info.in_color_space == JCS_YCbCr)) 2707 for (y=0; y < (ssize_t) image->rows; y++) 2708 { 2709 register const Quantum 2710 *p; 2711 2712 register ssize_t 2713 x; 2714 2715 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2716 if (p == (const Quantum *) NULL) 2717 break; 2718 q=jpeg_pixels; 2719 for (x=0; x < (ssize_t) image->columns; x++) 2720 { 2721 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p)); 2722 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p)); 2723 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p)); 2724 p+=GetPixelChannels(image); 2725 } 2726 (void) jpeg_write_scanlines(&jpeg_info,scanline,1); 2727 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 2728 image->rows); 2729 if (status == MagickFalse) 2730 break; 2731 } 2732 else 2733 if (jpeg_info.in_color_space == JCS_GRAYSCALE) 2734 for (y=0; y < (ssize_t) image->rows; y++) 2735 { 2736 register const Quantum 2737 *p; 2738 2739 register ssize_t 2740 x; 2741 2742 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2743 if (p == (const Quantum *) NULL) 2744 break; 2745 q=jpeg_pixels; 2746 for (x=0; x < (ssize_t) image->columns; x++) 2747 { 2748 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma( 2749 image,p))); 2750 p+=GetPixelChannels(image); 2751 } 2752 (void) jpeg_write_scanlines(&jpeg_info,scanline,1); 2753 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 2754 image->rows); 2755 if (status == MagickFalse) 2756 break; 2757 } 2758 else 2759 for (y=0; y < (ssize_t) image->rows; y++) 2760 { 2761 register const Quantum 2762 *p; 2763 2764 register ssize_t 2765 x; 2766 2767 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2768 if (p == (const Quantum *) NULL) 2769 break; 2770 q=jpeg_pixels; 2771 for (x=0; x < (ssize_t) image->columns; x++) 2772 { 2773 /* 2774 Convert DirectClass packets to contiguous CMYK scanlines. 2775 */ 2776 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange- 2777 GetPixelCyan(image,p)))); 2778 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange- 2779 GetPixelMagenta(image,p)))); 2780 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange- 2781 GetPixelYellow(image,p)))); 2782 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange- 2783 GetPixelBlack(image,p)))); 2784 p+=GetPixelChannels(image); 2785 } 2786 (void) jpeg_write_scanlines(&jpeg_info,scanline,1); 2787 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 2788 image->rows); 2789 if (status == MagickFalse) 2790 break; 2791 } 2792 } 2793 else 2794 if (jpeg_info.in_color_space == JCS_GRAYSCALE) 2795 for (y=0; y < (ssize_t) image->rows; y++) 2796 { 2797 register const Quantum 2798 *p; 2799 2800 register ssize_t 2801 x; 2802 2803 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2804 if (p == (const Quantum *) NULL) 2805 break; 2806 q=jpeg_pixels; 2807 for (x=0; x < (ssize_t) image->columns; x++) 2808 { 2809 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image, 2810 p)))/scale); 2811 p+=GetPixelChannels(image); 2812 } 2813 (void) jpeg_write_scanlines(&jpeg_info,scanline,1); 2814 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 2815 image->rows); 2816 if (status == MagickFalse) 2817 break; 2818 } 2819 else 2820 if ((jpeg_info.in_color_space == JCS_RGB) || 2821 (jpeg_info.in_color_space == JCS_YCbCr)) 2822 for (y=0; y < (ssize_t) image->rows; y++) 2823 { 2824 register const Quantum 2825 *p; 2826 2827 register ssize_t 2828 x; 2829 2830 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2831 if (p == (const Quantum *) NULL) 2832 break; 2833 q=jpeg_pixels; 2834 for (x=0; x < (ssize_t) image->columns; x++) 2835 { 2836 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale); 2837 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale); 2838 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale); 2839 p+=GetPixelChannels(image); 2840 } 2841 (void) jpeg_write_scanlines(&jpeg_info,scanline,1); 2842 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 2843 image->rows); 2844 if (status == MagickFalse) 2845 break; 2846 } 2847 else 2848 for (y=0; y < (ssize_t) image->rows; y++) 2849 { 2850 register const Quantum 2851 *p; 2852 2853 register ssize_t 2854 x; 2855 2856 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 2857 if (p == (const Quantum *) NULL) 2858 break; 2859 q=jpeg_pixels; 2860 for (x=0; x < (ssize_t) image->columns; x++) 2861 { 2862 /* 2863 Convert DirectClass packets to contiguous CMYK scanlines. 2864 */ 2865 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed( 2866 image,p))/scale); 2867 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen( 2868 image,p))/scale); 2869 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue( 2870 image,p))/scale); 2871 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack( 2872 image,p))/scale); 2873 p+=GetPixelChannels(image); 2874 } 2875 (void) jpeg_write_scanlines(&jpeg_info,scanline,1); 2876 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 2877 image->rows); 2878 if (status == MagickFalse) 2879 break; 2880 } 2881 if (y == (ssize_t) image->rows) 2882 jpeg_finish_compress(&jpeg_info); 2883 /* 2884 Relinquish resources. 2885 */ 2886 jpeg_destroy_compress(&jpeg_info); 2887 memory_info=RelinquishVirtualMemory(memory_info); 2888 (void) CloseBlob(image); 2889 return(MagickTrue); 2890 } 2891 #endif 2892