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