2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
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/pixel-accessor.h"
74 #include "MagickCore/profile.h"
75 #include "MagickCore/property.h"
76 #include "MagickCore/quantum-private.h"
77 #include "MagickCore/resource_.h"
78 #include "MagickCore/semaphore.h"
79 #include "MagickCore/splay-tree.h"
80 #include "MagickCore/static.h"
81 #include "MagickCore/string_.h"
82 #include "MagickCore/string-private.h"
83 #include "MagickCore/token.h"
84 #include "MagickCore/utility.h"
85 #include "MagickCore/xml-tree.h"
86 #include "MagickCore/xml-tree-private.h"
88 #if defined(MAGICKCORE_JPEG_DELEGATE)
89 #define JPEG_INTERNAL_OPTIONS
90 #if defined(__MINGW32__) || defined(__MINGW64__)
91 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
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
110 Typedef declarations.
112 #if defined(MAGICKCORE_JPEG_DELEGATE)
113 typedef struct _DestinationManager
115 struct jpeg_destination_mgr
123 } DestinationManager;
125 typedef struct _ErrorManager
143 typedef struct _SourceManager
145 struct jpeg_source_mgr
159 typedef struct _QuantizationTable
178 Forward declarations.
180 #if defined(MAGICKCORE_JPEG_DELEGATE)
181 static MagickBooleanType
182 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 % IsJPEG() returns MagickTrue if the image format type, identified by the
198 % magick string, is JPEG.
200 % The format of the IsJPEG method is:
202 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
204 % A description of each parameter follows:
206 % o magick: compare image format pattern against these bytes.
208 % o length: Specifies the length of the magick string.
211 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
215 if (memcmp(magick,"\377\330\377",3) == 0)
221 #if defined(MAGICKCORE_JPEG_DELEGATE)
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % R e a d J P E G I m a g e %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
234 % the memory necessary for the new Image structure and returns a pointer to
237 % The format of the ReadJPEGImage method is:
239 % Image *ReadJPEGImage(const ImageInfo *image_info,
240 % ExceptionInfo *exception)
242 % A description of each parameter follows:
244 % o image_info: the image info.
246 % o exception: return any errors or warnings in this structure.
250 static boolean FillInputBuffer(j_decompress_ptr cinfo)
255 source=(SourceManager *) cinfo->src;
256 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
257 MaxBufferExtent,source->buffer);
258 if (source->manager.bytes_in_buffer == 0)
260 if (source->start_of_blob != FALSE)
261 ERREXIT(cinfo,JERR_INPUT_EMPTY);
262 WARNMS(cinfo,JWRN_JPEG_EOF);
263 source->buffer[0]=(JOCTET) 0xff;
264 source->buffer[1]=(JOCTET) JPEG_EOI;
265 source->manager.bytes_in_buffer=2;
267 source->manager.next_input_byte=source->buffer;
268 source->start_of_blob=FALSE;
272 static int GetCharacter(j_decompress_ptr jpeg_info)
274 if (jpeg_info->src->bytes_in_buffer == 0)
275 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
276 jpeg_info->src->bytes_in_buffer--;
277 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
280 static void InitializeSource(j_decompress_ptr cinfo)
285 source=(SourceManager *) cinfo->src;
286 source->start_of_blob=TRUE;
289 static MagickBooleanType IsITUFaxImage(const Image *image)
297 profile=GetImageProfile(image,"8bim");
298 if (profile == (const StringInfo *) NULL)
300 if (GetStringInfoLength(profile) < 5)
302 datum=GetStringInfoDatum(profile);
303 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
304 (datum[3] == 0x41) && (datum[4] == 0x58))
309 static void JPEGErrorHandler(j_common_ptr jpeg_info)
312 message[JMSG_LENGTH_MAX];
324 error_manager=(ErrorManager *) jpeg_info->client_data;
325 image=error_manager->image;
326 exception=error_manager->exception;
327 (jpeg_info->err->format_message)(jpeg_info,message);
328 if (image->debug != MagickFalse)
329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
330 "[%s] JPEG Trace: \"%s\"",image->filename,message);
331 if (error_manager->finished != MagickFalse)
332 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
333 (char *) message,"`%s'",image->filename);
335 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
336 (char *) message,"`%s'",image->filename);
337 longjmp(error_manager->error_recovery,1);
340 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
342 #define JPEGExcessiveWarnings 1000
345 message[JMSG_LENGTH_MAX];
357 error_manager=(ErrorManager *) jpeg_info->client_data;
358 exception=error_manager->exception;
359 image=error_manager->image;
363 Process warning message.
365 (jpeg_info->err->format_message)(jpeg_info,message);
366 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
367 JPEGErrorHandler(jpeg_info);
368 ThrowBinaryException(CorruptImageWarning,(char *) message,
372 if ((image->debug != MagickFalse) &&
373 (level >= jpeg_info->err->trace_level))
376 Process trace message.
378 (jpeg_info->err->format_message)(jpeg_info,message);
379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
380 "[%s] JPEG Trace: \"%s\"",image->filename,message);
385 static boolean ReadComment(j_decompress_ptr jpeg_info)
396 register unsigned char
409 Determine length of comment.
411 error_manager=(ErrorManager *) jpeg_info->client_data;
412 exception=error_manager->exception;
413 image=error_manager->image;
414 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
415 length+=GetCharacter(jpeg_info);
419 comment=BlobToStringInfo((const void *) NULL,length);
420 if (comment == (StringInfo *) NULL)
422 (void) ThrowMagickException(exception,GetMagickModule(),
423 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
429 error_manager->profile=comment;
430 p=GetStringInfoDatum(comment);
431 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
432 *p++=(unsigned char) GetCharacter(jpeg_info);
434 error_manager->profile=NULL;
435 p=GetStringInfoDatum(comment);
436 (void) SetImageProperty(image,"comment",(const char *) p,exception);
437 comment=DestroyStringInfo(comment);
441 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
461 register unsigned char
474 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
475 length+=(size_t) GetCharacter(jpeg_info);
480 (void) GetCharacter(jpeg_info);
483 for (i=0; i < 12; i++)
484 magick[i]=(char) GetCharacter(jpeg_info);
485 if (LocaleCompare(magick,ICC_PROFILE) != 0)
488 Not a ICC profile, return.
490 for (i=0; i < (ssize_t) (length-12); i++)
491 (void) GetCharacter(jpeg_info);
494 (void) GetCharacter(jpeg_info); /* id */
495 (void) GetCharacter(jpeg_info); /* markers */
497 error_manager=(ErrorManager *) jpeg_info->client_data;
498 exception=error_manager->exception;
499 image=error_manager->image;
500 profile=BlobToStringInfo((const void *) NULL,length);
501 if (profile == (StringInfo *) NULL)
503 (void) ThrowMagickException(exception,GetMagickModule(),
504 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
507 error_manager->profile=profile;
508 p=GetStringInfoDatum(profile);
509 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
510 *p++=(unsigned char) GetCharacter(jpeg_info);
511 error_manager->profile=NULL;
512 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
513 if (icc_profile != (StringInfo *) NULL)
515 ConcatenateStringInfo(icc_profile,profile);
516 profile=DestroyStringInfo(profile);
520 status=SetImageProfile(image,"icc",profile,exception);
521 profile=DestroyStringInfo(profile);
522 if (status == MagickFalse)
524 (void) ThrowMagickException(exception,GetMagickModule(),
525 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
529 if (image->debug != MagickFalse)
530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
531 "Profile: ICC, %.20g bytes",(double) length);
535 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
538 magick[MaxTextExtent];
555 register unsigned char
566 Determine length of binary data stored here.
568 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
569 length+=(size_t) GetCharacter(jpeg_info);
574 (void) GetCharacter(jpeg_info);
578 Validate that this was written as a Photoshop resource format slug.
580 for (i=0; i < 10; i++)
581 magick[i]=(char) GetCharacter(jpeg_info);
586 if (LocaleCompare(magick,"Photoshop ") != 0)
589 Not a IPTC profile, return.
591 for (i=0; i < (ssize_t) length; i++)
592 (void) GetCharacter(jpeg_info);
596 Remove the version number.
598 for (i=0; i < 4; i++)
599 (void) GetCharacter(jpeg_info);
603 error_manager=(ErrorManager *) jpeg_info->client_data;
604 exception=error_manager->exception;
605 image=error_manager->image;
606 profile=BlobToStringInfo((const void *) NULL,length);
607 if (profile == (StringInfo *) NULL)
609 (void) ThrowMagickException(exception,GetMagickModule(),
610 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
613 error_manager->profile=profile;
614 p=GetStringInfoDatum(profile);
615 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
616 *p++=(unsigned char) GetCharacter(jpeg_info);
617 error_manager->profile=NULL;
618 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
619 if (iptc_profile != (StringInfo *) NULL)
621 ConcatenateStringInfo(iptc_profile,profile);
622 profile=DestroyStringInfo(profile);
626 status=SetImageProfile(image,"8bim",profile,exception);
627 profile=DestroyStringInfo(profile);
628 if (status == MagickFalse)
630 (void) ThrowMagickException(exception,GetMagickModule(),
631 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
635 if (image->debug != MagickFalse)
636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
637 "Profile: iptc, %.20g bytes",(double) length);
641 static boolean ReadProfile(j_decompress_ptr jpeg_info)
667 register unsigned char
677 Read generic profile.
679 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
680 length+=(size_t) GetCharacter(jpeg_info);
684 marker=jpeg_info->unread_marker-JPEG_APP0;
685 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
686 error_manager=(ErrorManager *) jpeg_info->client_data;
687 exception=error_manager->exception;
688 image=error_manager->image;
689 profile=BlobToStringInfo((const void *) NULL,length);
690 if (profile == (StringInfo *) NULL)
692 (void) ThrowMagickException(exception,GetMagickModule(),
693 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
696 error_manager->profile=profile;
697 p=GetStringInfoDatum(profile);
698 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
699 *p++=(unsigned char) GetCharacter(jpeg_info);
700 error_manager->profile=NULL;
703 p=GetStringInfoDatum(profile);
704 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
705 (void) CopyMagickString(name,"exif",MaxTextExtent);
706 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
712 Extract namespace from XMP profile.
714 p=GetStringInfoDatum(profile);
715 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
721 if (j < (ssize_t) GetStringInfoLength(profile))
722 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
723 (void) CopyMagickString(name,"xmp",MaxTextExtent);
726 previous_profile=GetImageProfile(image,name);
727 if (previous_profile != (const StringInfo *) NULL)
732 length=GetStringInfoLength(profile);
733 SetStringInfoLength(profile,GetStringInfoLength(profile)+
734 GetStringInfoLength(previous_profile));
735 (void) memmove(GetStringInfoDatum(profile)+
736 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
738 (void) memcpy(GetStringInfoDatum(profile),
739 GetStringInfoDatum(previous_profile),
740 GetStringInfoLength(previous_profile));
742 status=SetImageProfile(image,name,profile,exception);
743 profile=DestroyStringInfo(profile);
744 if (status == MagickFalse)
746 (void) ThrowMagickException(exception,GetMagickModule(),
747 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
750 if (image->debug != MagickFalse)
751 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
752 "Profile: %s, %.20g bytes",name,(double) length);
756 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
761 if (number_bytes <= 0)
763 source=(SourceManager *) cinfo->src;
764 while (number_bytes > (long) source->manager.bytes_in_buffer)
766 number_bytes-=(long) source->manager.bytes_in_buffer;
767 (void) FillInputBuffer(cinfo);
769 source->manager.next_input_byte+=number_bytes;
770 source->manager.bytes_in_buffer-=number_bytes;
773 static void TerminateSource(j_decompress_ptr cinfo)
778 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
783 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
784 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
785 source=(SourceManager *) cinfo->src;
786 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
787 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
788 source=(SourceManager *) cinfo->src;
789 source->manager.init_source=InitializeSource;
790 source->manager.fill_input_buffer=FillInputBuffer;
791 source->manager.skip_input_data=SkipInputData;
792 source->manager.resync_to_restart=jpeg_resync_to_restart;
793 source->manager.term_source=TerminateSource;
794 source->manager.bytes_in_buffer=0;
795 source->manager.next_input_byte=NULL;
799 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
800 Image *image, ExceptionInfo *exception)
802 image->quality=UndefinedCompressionQuality;
803 #if defined(D_PROGRESSIVE_SUPPORTED)
804 if (image->compression == LosslessJPEGCompression)
807 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
808 "Quality: 100 (lossless)");
822 Determine the JPEG compression quality from the quantization tables.
825 for (i=0; i < NUM_QUANT_TBLS; i++)
827 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
828 for (j=0; j < DCTSIZE2; j++)
829 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
831 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
832 (jpeg_info->quant_tbl_ptrs[1] != NULL))
837 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
838 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
839 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
840 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
841 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
842 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
843 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
844 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
845 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
846 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
851 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
852 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
853 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
854 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
855 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
856 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
857 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
858 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
859 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
860 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
861 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
865 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
866 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
867 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
868 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
869 for (i=0; i < 100; i++)
871 if ((qvalue < hash[i]) && (sum < sums[i]))
873 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
874 image->quality=(size_t) i+1;
875 if (image->debug != MagickFalse)
876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
877 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
878 (sum <= sums[i]) ? "exact" : "approximate");
883 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
888 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
889 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
890 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
891 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
892 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
893 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
894 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
895 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
896 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
897 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
902 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
903 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
904 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
905 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
906 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
907 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
908 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
909 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
910 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
911 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
912 667, 592, 518, 441, 369, 292, 221, 151, 86,
916 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
917 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
918 for (i=0; i < 100; i++)
920 if ((qvalue < hash[i]) && (sum < sums[i]))
922 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
923 image->quality=(size_t)i+1;
924 if (image->debug != MagickFalse)
925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
926 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
927 (sum <= sums[i]) ? "exact" : "approximate");
934 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
937 sampling_factor[MaxTextExtent];
939 switch (jpeg_info->out_color_space)
943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
944 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
945 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
946 jpeg_info->comp_info[0].v_samp_factor,
947 jpeg_info->comp_info[1].h_samp_factor,
948 jpeg_info->comp_info[1].v_samp_factor,
949 jpeg_info->comp_info[2].h_samp_factor,
950 jpeg_info->comp_info[2].v_samp_factor,
951 jpeg_info->comp_info[3].h_samp_factor,
952 jpeg_info->comp_info[3].v_samp_factor);
957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
958 "Colorspace: GRAYSCALE");
959 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
960 jpeg_info->comp_info[0].h_samp_factor,
961 jpeg_info->comp_info[0].v_samp_factor);
966 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
967 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
968 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
969 jpeg_info->comp_info[0].v_samp_factor,
970 jpeg_info->comp_info[1].h_samp_factor,
971 jpeg_info->comp_info[1].v_samp_factor,
972 jpeg_info->comp_info[2].h_samp_factor,
973 jpeg_info->comp_info[2].v_samp_factor);
978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
979 jpeg_info->out_color_space);
980 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
981 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
982 jpeg_info->comp_info[0].v_samp_factor,
983 jpeg_info->comp_info[1].h_samp_factor,
984 jpeg_info->comp_info[1].v_samp_factor,
985 jpeg_info->comp_info[2].h_samp_factor,
986 jpeg_info->comp_info[2].v_samp_factor,
987 jpeg_info->comp_info[3].h_samp_factor,
988 jpeg_info->comp_info[3].v_samp_factor);
992 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
998 static Image *ReadJPEGImage(const ImageInfo *image_info,
999 ExceptionInfo *exception)
1002 value[MaxTextExtent];
1014 *volatile jpeg_pixels;
1035 struct jpeg_decompress_struct
1038 struct jpeg_error_mgr
1053 assert(image_info != (const ImageInfo *) NULL);
1054 assert(image_info->signature == MagickSignature);
1055 if (image_info->debug != MagickFalse)
1056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1057 image_info->filename);
1058 assert(exception != (ExceptionInfo *) NULL);
1059 assert(exception->signature == MagickSignature);
1060 debug=IsEventLogging();
1062 image=AcquireImage(image_info,exception);
1063 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1064 if (status == MagickFalse)
1066 image=DestroyImageList(image);
1067 return((Image *) NULL);
1070 Initialize JPEG parameters.
1072 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1073 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1074 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1075 jpeg_info.err=jpeg_std_error(&jpeg_error);
1076 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1077 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1078 memory_info=(MemoryInfo *) NULL;
1079 error_manager.exception=exception;
1080 error_manager.image=image;
1081 if (setjmp(error_manager.error_recovery) != 0)
1083 jpeg_destroy_decompress(&jpeg_info);
1084 if (error_manager.profile != (StringInfo *) NULL)
1085 error_manager.profile=DestroyStringInfo(error_manager.profile);
1086 (void) CloseBlob(image);
1087 number_pixels=(MagickSizeType) image->columns*image->rows;
1088 if (number_pixels != 0)
1089 return(GetFirstImageInList(image));
1090 return(DestroyImage(image));
1092 jpeg_info.client_data=(void *) &error_manager;
1093 jpeg_create_decompress(&jpeg_info);
1094 JPEGSourceManager(&jpeg_info,image);
1095 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1096 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1097 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1098 for (i=1; i < 16; i++)
1099 if ((i != 2) && (i != 13) && (i != 14))
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;
1107 Set image resolution.
1110 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1111 (jpeg_info.Y_density != 1))
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;
1118 image->units=PixelsPerInchResolution;
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)
1137 flags=ParseGeometry(option,&geometry_info);
1138 if ((flags & SigmaValue) == 0)
1139 geometry_info.sigma=geometry_info.rho;
1140 jpeg_calc_output_dimensions(&jpeg_info);
1141 image->magick_columns=jpeg_info.output_width;
1142 image->magick_rows=jpeg_info.output_height;
1144 if (geometry_info.rho != 0.0)
1145 scale_factor=jpeg_info.output_width/geometry_info.rho;
1146 if ((geometry_info.sigma != 0.0) &&
1147 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1148 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1149 jpeg_info.scale_num=1U;
1150 jpeg_info.scale_denom=(unsigned int) scale_factor;
1151 jpeg_calc_output_dimensions(&jpeg_info);
1152 if (image->debug != MagickFalse)
1153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1154 "Scale factor: %.20g",(double) scale_factor);
1156 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1157 #if defined(D_LOSSLESS_SUPPORTED)
1158 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1159 JPEGInterlace : NoInterlace;
1160 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1161 LosslessJPEGCompression : JPEGCompression;
1162 if (jpeg_info.data_precision > 8)
1163 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1164 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1166 if (jpeg_info.data_precision == 16)
1167 jpeg_info.data_precision=12;
1169 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1171 image->compression=JPEGCompression;
1174 image->compression=JPEGCompression;
1175 image->interlace=JPEGInterlace;
1177 option=GetImageOption(image_info,"jpeg:colors");
1178 if (option != (const char *) NULL)
1181 Let the JPEG library quantize the image.
1183 jpeg_info.quantize_colors=TRUE;
1184 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1186 option=GetImageOption(image_info,"jpeg:block-smoothing");
1187 if (option != (const char *) NULL)
1188 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1190 jpeg_info.dct_method=JDCT_FLOAT;
1191 option=GetImageOption(image_info,"jpeg:dct-method");
1192 if (option != (const char *) NULL)
1198 if (LocaleCompare(option,"default") == 0)
1199 jpeg_info.dct_method=JDCT_DEFAULT;
1205 if (LocaleCompare(option,"fastest") == 0)
1206 jpeg_info.dct_method=JDCT_FASTEST;
1207 if (LocaleCompare(option,"float") == 0)
1208 jpeg_info.dct_method=JDCT_FLOAT;
1214 if (LocaleCompare(option,"ifast") == 0)
1215 jpeg_info.dct_method=JDCT_IFAST;
1216 if (LocaleCompare(option,"islow") == 0)
1217 jpeg_info.dct_method=JDCT_ISLOW;
1221 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1222 if (option != (const char *) NULL)
1223 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1225 (void) jpeg_start_decompress(&jpeg_info);
1226 image->columns=jpeg_info.output_width;
1227 image->rows=jpeg_info.output_height;
1228 image->depth=(size_t) jpeg_info.data_precision;
1229 switch (jpeg_info.out_color_space)
1234 (void) SetImageColorspace(image,sRGBColorspace,exception);
1239 (void) SetImageColorspace(image,GRAYColorspace,exception);
1244 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1249 (void) SetImageColorspace(image,CMYKColorspace,exception);
1253 if (IsITUFaxImage(image) != MagickFalse)
1255 (void) SetImageColorspace(image,LabColorspace,exception);
1256 jpeg_info.out_color_space=JCS_YCbCr;
1258 option=GetImageOption(image_info,"jpeg:colors");
1259 if (option != (const char *) NULL)
1260 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1262 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1263 if ((jpeg_info.output_components == 1) &&
1264 (jpeg_info.quantize_colors == MagickFalse))
1269 colors=(size_t) GetQuantumRange(image->depth)+1;
1270 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1271 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1273 if (image->debug != MagickFalse)
1275 if (image->interlace != NoInterlace)
1276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1277 "Interlace: progressive");
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);
1286 JPEGSetImageQuality(&jpeg_info,image,exception);
1287 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1288 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1289 jpeg_info.out_color_space);
1290 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1291 if (image_info->ping != MagickFalse)
1293 jpeg_destroy_decompress(&jpeg_info);
1294 (void) CloseBlob(image);
1295 return(GetFirstImageInList(image));
1297 memory_info=AcquireVirtualMemory((size_t) image->columns,
1298 jpeg_info.output_components*sizeof(*jpeg_pixels));
1299 if (memory_info == (MemoryInfo *) NULL)
1301 jpeg_destroy_decompress(&jpeg_info);
1302 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1304 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1306 Convert JPEG pixels to pixel packets.
1308 if (setjmp(error_manager.error_recovery) != 0)
1310 if (memory_info != (MemoryInfo *) NULL)
1311 memory_info=RelinquishVirtualMemory(memory_info);
1312 jpeg_destroy_decompress(&jpeg_info);
1313 (void) CloseBlob(image);
1314 number_pixels=(MagickSizeType) image->columns*image->rows;
1315 if (number_pixels != 0)
1316 return(GetFirstImageInList(image));
1317 return(DestroyImage(image));
1319 if (jpeg_info.quantize_colors != MagickFalse)
1321 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1322 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1323 for (i=0; i < (ssize_t) image->colors; i++)
1325 image->colormap[i].red=(double) ScaleCharToQuantum(
1326 jpeg_info.colormap[0][i]);
1327 image->colormap[i].green=image->colormap[i].red;
1328 image->colormap[i].blue=image->colormap[i].red;
1329 image->colormap[i].alpha=OpaqueAlpha;
1332 for (i=0; i < (ssize_t) image->colors; i++)
1334 image->colormap[i].red=(double) ScaleCharToQuantum(
1335 jpeg_info.colormap[0][i]);
1336 image->colormap[i].green=(double) ScaleCharToQuantum(
1337 jpeg_info.colormap[1][i]);
1338 image->colormap[i].blue=(double) ScaleCharToQuantum(
1339 jpeg_info.colormap[2][i]);
1340 image->colormap[i].alpha=OpaqueAlpha;
1343 scanline[0]=(JSAMPROW) jpeg_pixels;
1344 for (y=0; y < (ssize_t) image->rows; y++)
1352 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1354 (void) ThrowMagickException(exception,GetMagickModule(),
1355 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1359 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1360 if (q == (Quantum *) NULL)
1362 if (jpeg_info.data_precision > 8)
1367 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1368 if (jpeg_info.output_components == 1)
1369 for (x=0; x < (ssize_t) image->columns; x++)
1374 pixel=(size_t) (scale*GETJSAMPLE(*p));
1375 index=ConstrainColormapIndex(image,pixel,exception);
1376 SetPixelIndex(image,index,q);
1377 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1379 q+=GetPixelChannels(image);
1382 if (image->colorspace != CMYKColorspace)
1383 for (x=0; x < (ssize_t) image->columns; x++)
1385 SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1387 SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1389 SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1391 SetPixelAlpha(image,OpaqueAlpha,q);
1392 q+=GetPixelChannels(image);
1395 for (x=0; x < (ssize_t) image->columns; x++)
1397 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(scale*
1398 GETJSAMPLE(*p++)),q);
1399 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(scale*
1400 GETJSAMPLE(*p++)),q);
1401 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(scale*
1402 GETJSAMPLE(*p++)),q);
1403 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(scale*
1404 GETJSAMPLE(*p++)),q);
1405 SetPixelAlpha(image,OpaqueAlpha,q);
1406 q+=GetPixelChannels(image);
1410 if (jpeg_info.output_components == 1)
1411 for (x=0; x < (ssize_t) image->columns; x++)
1413 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1414 SetPixelIndex(image,index,q);
1415 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1417 q+=GetPixelChannels(image);
1420 if (image->colorspace != CMYKColorspace)
1421 for (x=0; x < (ssize_t) image->columns; x++)
1423 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1424 GETJSAMPLE(*p++)),q);
1425 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1426 GETJSAMPLE(*p++)),q);
1427 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1428 GETJSAMPLE(*p++)),q);
1429 SetPixelAlpha(image,OpaqueAlpha,q);
1430 q+=GetPixelChannels(image);
1433 for (x=0; x < (ssize_t) image->columns; x++)
1435 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1436 (unsigned char) GETJSAMPLE(*p++)),q);
1437 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1438 (unsigned char) GETJSAMPLE(*p++)),q);
1439 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1440 (unsigned char) GETJSAMPLE(*p++)),q);
1441 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1442 (unsigned char) GETJSAMPLE(*p++)),q);
1443 SetPixelAlpha(image,OpaqueAlpha,q);
1444 q+=GetPixelChannels(image);
1446 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1448 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1450 if (status == MagickFalse)
1452 jpeg_abort_decompress(&jpeg_info);
1456 if (status != MagickFalse)
1458 error_manager.finished=MagickTrue;
1459 if (setjmp(error_manager.error_recovery) == 0)
1460 (void) jpeg_finish_decompress(&jpeg_info);
1463 Free jpeg resources.
1465 jpeg_destroy_decompress(&jpeg_info);
1466 memory_info=RelinquishVirtualMemory(memory_info);
1467 (void) CloseBlob(image);
1468 return(GetFirstImageInList(image));
1474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1478 % R e g i s t e r J P E G I m a g e %
1482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484 % RegisterJPEGImage() adds properties for the JPEG image format to
1485 % the list of supported formats. The properties include the image format
1486 % tag, a method to read and/or write the format, whether the format
1487 % supports the saving of more than one frame to the same file or blob,
1488 % whether the format supports native in-memory I/O, and a brief
1489 % description of the format.
1491 % The format of the RegisterJPEGImage method is:
1493 % size_t RegisterJPEGImage(void)
1496 ModuleExport size_t RegisterJPEGImage(void)
1499 version[MaxTextExtent];
1505 description[] = "Joint Photographic Experts Group JFIF format";
1508 #if defined(JPEG_LIB_VERSION)
1509 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1511 entry=SetMagickInfo("JPEG");
1512 entry->thread_support=NoThreadSupport;
1513 #if defined(MAGICKCORE_JPEG_DELEGATE)
1514 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1515 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1517 entry->magick=(IsImageFormatHandler *) IsJPEG;
1518 entry->adjoin=MagickFalse;
1519 entry->description=ConstantString(description);
1520 if (*version != '\0')
1521 entry->version=ConstantString(version);
1522 entry->mime_type=ConstantString("image/jpeg");
1523 entry->module=ConstantString("JPEG");
1524 (void) RegisterMagickInfo(entry);
1525 entry=SetMagickInfo("JPG");
1526 entry->thread_support=NoThreadSupport;
1527 #if defined(MAGICKCORE_JPEG_DELEGATE)
1528 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1529 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1531 entry->adjoin=MagickFalse;
1532 entry->description=ConstantString(description);
1533 if (*version != '\0')
1534 entry->version=ConstantString(version);
1535 entry->mime_type=ConstantString("image/jpeg");
1536 entry->module=ConstantString("JPEG");
1537 (void) RegisterMagickInfo(entry);
1538 entry=SetMagickInfo("PJPEG");
1539 entry->thread_support=NoThreadSupport;
1540 #if defined(MAGICKCORE_JPEG_DELEGATE)
1541 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1542 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1544 entry->adjoin=MagickFalse;
1545 entry->description=ConstantString(description);
1546 if (*version != '\0')
1547 entry->version=ConstantString(version);
1548 entry->mime_type=ConstantString("image/jpeg");
1549 entry->module=ConstantString("JPEG");
1550 (void) RegisterMagickInfo(entry);
1551 return(MagickImageCoderSignature);
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560 % U n r e g i s t e r J P E G I m a g e %
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 % UnregisterJPEGImage() removes format registrations made by the
1567 % JPEG module from the list of supported formats.
1569 % The format of the UnregisterJPEGImage method is:
1571 % UnregisterJPEGImage(void)
1574 ModuleExport void UnregisterJPEGImage(void)
1576 (void) UnregisterMagickInfo("PJPG");
1577 (void) UnregisterMagickInfo("JPEG");
1578 (void) UnregisterMagickInfo("JPG");
1582 #if defined(MAGICKCORE_JPEG_DELEGATE)
1584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 % W r i t e J P E G I m a g e %
1592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594 % WriteJPEGImage() writes a JPEG image file and returns it. It
1595 % allocates the memory necessary for the new Image structure and returns a
1596 % pointer to the new image.
1598 % The format of the WriteJPEGImage method is:
1600 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1601 % Image *image,ExceptionInfo *exception)
1603 % A description of each parameter follows:
1605 % o image_info: the image info.
1607 % o jpeg_image: The image.
1609 % o exception: return any errors or warnings in this structure.
1613 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1615 assert(table != (QuantizationTable *) NULL);
1616 if (table->slot != (char *) NULL)
1617 table->slot=DestroyString(table->slot);
1618 if (table->description != (char *) NULL)
1619 table->description=DestroyString(table->description);
1620 if (table->levels != (unsigned int *) NULL)
1621 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1622 table=(QuantizationTable *) RelinquishMagickMemory(table);
1626 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1631 destination=(DestinationManager *) cinfo->dest;
1632 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1633 MaxBufferExtent,destination->buffer);
1634 if (destination->manager.free_in_buffer != MaxBufferExtent)
1635 ERREXIT(cinfo,JERR_FILE_WRITE);
1636 destination->manager.next_output_byte=destination->buffer;
1640 static QuantizationTable *GetQuantizationTable(const char *filename,
1641 const char *slot,ExceptionInfo *exception)
1669 *quantization_tables,
1672 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1673 "Loading quantization tables \"%s\" ...",filename);
1674 table=(QuantizationTable *) NULL;
1675 xml=FileToString(filename,~0UL,exception);
1676 if (xml == (char *) NULL)
1678 quantization_tables=NewXMLTree(xml,exception);
1679 if (quantization_tables == (XMLTreeInfo *) NULL)
1681 xml=DestroyString(xml);
1684 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1685 table_iterator != (XMLTreeInfo *) NULL;
1686 table_iterator=GetNextXMLTreeTag(table_iterator))
1688 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1689 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1691 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1692 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1695 if (table_iterator == (XMLTreeInfo *) NULL)
1697 xml=DestroyString(xml);
1700 description=GetXMLTreeChild(table_iterator,"description");
1701 if (description == (XMLTreeInfo *) NULL)
1703 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1704 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1705 quantization_tables=DestroyXMLTree(quantization_tables);
1706 xml=DestroyString(xml);
1709 levels=GetXMLTreeChild(table_iterator,"levels");
1710 if (levels == (XMLTreeInfo *) NULL)
1712 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1713 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1714 quantization_tables=DestroyXMLTree(quantization_tables);
1715 xml=DestroyString(xml);
1718 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1719 if (table == (QuantizationTable *) NULL)
1720 ThrowFatalException(ResourceLimitFatalError,
1721 "UnableToAcquireQuantizationTable");
1722 table->slot=(char *) NULL;
1723 table->description=(char *) NULL;
1724 table->levels=(unsigned int *) NULL;
1725 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1726 if (attribute != (char *) NULL)
1727 table->slot=ConstantString(attribute);
1728 content=GetXMLTreeContent(description);
1729 if (content != (char *) NULL)
1730 table->description=ConstantString(content);
1731 attribute=GetXMLTreeAttribute(levels,"width");
1732 if (attribute == (char *) NULL)
1734 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1735 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1736 quantization_tables=DestroyXMLTree(quantization_tables);
1737 table=DestroyQuantizationTable(table);
1738 xml=DestroyString(xml);
1741 table->width=StringToUnsignedLong(attribute);
1742 if (table->width == 0)
1744 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1745 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1746 quantization_tables=DestroyXMLTree(quantization_tables);
1747 table=DestroyQuantizationTable(table);
1748 xml=DestroyString(xml);
1751 attribute=GetXMLTreeAttribute(levels,"height");
1752 if (attribute == (char *) NULL)
1754 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1755 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1756 quantization_tables=DestroyXMLTree(quantization_tables);
1757 table=DestroyQuantizationTable(table);
1758 xml=DestroyString(xml);
1761 table->height=StringToUnsignedLong(attribute);
1762 if (table->height == 0)
1764 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1765 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1766 quantization_tables=DestroyXMLTree(quantization_tables);
1767 table=DestroyQuantizationTable(table);
1768 xml=DestroyString(xml);
1771 attribute=GetXMLTreeAttribute(levels,"divisor");
1772 if (attribute == (char *) NULL)
1774 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1775 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1776 quantization_tables=DestroyXMLTree(quantization_tables);
1777 table=DestroyQuantizationTable(table);
1778 xml=DestroyString(xml);
1781 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1782 if (table->divisor == 0.0)
1784 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1785 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1786 quantization_tables=DestroyXMLTree(quantization_tables);
1787 table=DestroyQuantizationTable(table);
1788 xml=DestroyString(xml);
1791 content=GetXMLTreeContent(levels);
1792 if (content == (char *) NULL)
1794 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1795 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1796 quantization_tables=DestroyXMLTree(quantization_tables);
1797 table=DestroyQuantizationTable(table);
1798 xml=DestroyString(xml);
1801 length=(size_t) table->width*table->height;
1804 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1805 sizeof(*table->levels));
1806 if (table->levels == (unsigned int *) NULL)
1807 ThrowFatalException(ResourceLimitFatalError,
1808 "UnableToAcquireQuantizationTable");
1809 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1811 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1812 table->divisor+0.5);
1813 while (isspace((int) ((unsigned char) *p)) != 0)
1819 value=InterpretLocaleValue(content,&p);
1823 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1824 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1825 quantization_tables=DestroyXMLTree(quantization_tables);
1826 table=DestroyQuantizationTable(table);
1827 xml=DestroyString(xml);
1830 for (j=i; j < 64; j++)
1831 table->levels[j]=table->levels[j-1];
1832 quantization_tables=DestroyXMLTree(quantization_tables);
1833 xml=DestroyString(xml);
1837 static void InitializeDestination(j_compress_ptr cinfo)
1842 destination=(DestinationManager *) cinfo->dest;
1843 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1844 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1845 destination->manager.next_output_byte=destination->buffer;
1846 destination->manager.free_in_buffer=MaxBufferExtent;
1849 static inline size_t MagickMin(const size_t x,const size_t y)
1856 static void TerminateDestination(j_compress_ptr cinfo)
1861 destination=(DestinationManager *) cinfo->dest;
1862 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1867 count=WriteBlob(destination->image,MaxBufferExtent-
1868 destination->manager.free_in_buffer,destination->buffer);
1869 if (count != (ssize_t)
1870 (MaxBufferExtent-destination->manager.free_in_buffer))
1871 ERREXIT(cinfo,JERR_FILE_WRITE);
1875 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1897 Save image profile as a APP marker.
1900 custom_profile=AcquireStringInfo(65535L);
1901 ResetImageProfileIterator(image);
1902 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1904 register unsigned char
1907 profile=GetImageProfile(image,name);
1908 p=GetStringInfoDatum(custom_profile);
1909 if (LocaleCompare(name,"EXIF") == 0)
1910 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1912 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1913 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1914 (unsigned int) length);
1916 if (LocaleCompare(name,"ICC") == 0)
1918 register unsigned char
1921 tag_length=strlen(ICC_PROFILE);
1922 p=GetStringInfoDatum(custom_profile);
1923 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1925 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1927 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1928 p[12]=(unsigned char) ((i/65519L)+1);
1929 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1930 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1932 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1933 custom_profile),(unsigned int) (length+tag_length+3));
1936 if (((LocaleCompare(name,"IPTC") == 0) ||
1937 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1943 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1945 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1946 roundup=(size_t) (length & 0x01);
1947 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1949 (void) memcpy(p,"Photoshop 3.0 ",14);
1954 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1956 p[24]=(unsigned char) (length >> 8);
1957 p[25]=(unsigned char) (length & 0xff);
1960 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1962 p[length+tag_length]='\0';
1963 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1964 custom_profile),(unsigned int) (length+tag_length+roundup));
1967 if (LocaleCompare(name,"XMP") == 0)
1973 Add namespace to XMP profile.
1975 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1976 if (xmp_profile != (StringInfo *) NULL)
1978 if (profile != (StringInfo *) NULL)
1979 ConcatenateStringInfo(xmp_profile,profile);
1980 GetStringInfoDatum(xmp_profile)[28]='\0';
1981 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1983 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1984 jpeg_write_marker(jpeg_info,XML_MARKER,
1985 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1987 xmp_profile=DestroyStringInfo(xmp_profile);
1990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1991 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1992 name=GetNextImageProfile(image);
1994 custom_profile=DestroyStringInfo(custom_profile);
1997 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2002 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2003 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2004 destination=(DestinationManager *) cinfo->dest;
2005 destination->manager.init_destination=InitializeDestination;
2006 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2007 destination->manager.term_destination=TerminateDestination;
2008 destination->image=image;
2011 static char **SamplingFactorToList(const char *text)
2028 if (text == (char *) NULL)
2029 return((char **) NULL);
2031 Convert string to an ASCII list.
2034 for (p=text; *p != '\0'; p++)
2037 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2039 if (textlist == (char **) NULL)
2040 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2042 for (i=0; i < (ssize_t) lines; i++)
2044 for (q=(char *) p; *q != '\0'; q++)
2047 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2048 sizeof(*textlist[i]));
2049 if (textlist[i] == (char *) NULL)
2050 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2051 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2056 textlist[i]=(char *) NULL;
2060 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2061 Image *image,ExceptionInfo *exception)
2076 *volatile jpeg_pixels;
2096 struct jpeg_compress_struct
2099 struct jpeg_error_mgr
2108 assert(image_info != (const ImageInfo *) NULL);
2109 assert(image_info->signature == MagickSignature);
2110 assert(image != (Image *) NULL);
2111 assert(image->signature == MagickSignature);
2112 if (image->debug != MagickFalse)
2113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2114 assert(exception != (ExceptionInfo *) NULL);
2115 assert(exception->signature == MagickSignature);
2116 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2117 if (status == MagickFalse)
2120 Initialize JPEG parameters.
2122 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2123 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2124 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2125 jpeg_info.client_data=(void *) image;
2126 jpeg_info.err=jpeg_std_error(&jpeg_error);
2127 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2128 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2129 error_manager.exception=exception;
2130 error_manager.image=image;
2131 memory_info=(MemoryInfo *) NULL;
2132 if (setjmp(error_manager.error_recovery) != 0)
2134 jpeg_destroy_compress(&jpeg_info);
2135 (void) CloseBlob(image);
2136 return(MagickFalse);
2138 jpeg_info.client_data=(void *) &error_manager;
2139 jpeg_create_compress(&jpeg_info);
2140 JPEGDestinationManager(&jpeg_info,image);
2141 if ((image->columns != (unsigned int) image->columns) ||
2142 (image->rows != (unsigned int) image->rows))
2143 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2144 jpeg_info.image_width=(unsigned int) image->columns;
2145 jpeg_info.image_height=(unsigned int) image->rows;
2146 jpeg_info.input_components=3;
2147 jpeg_info.data_precision=8;
2148 jpeg_info.in_color_space=JCS_RGB;
2149 switch (image->colorspace)
2151 case CMYKColorspace:
2153 jpeg_info.input_components=4;
2154 jpeg_info.in_color_space=JCS_CMYK;
2157 case YCbCrColorspace:
2158 case Rec601YCbCrColorspace:
2159 case Rec709YCbCrColorspace:
2161 jpeg_info.in_color_space=JCS_YCbCr;
2164 case GRAYColorspace:
2166 if (image_info->type == TrueColorType)
2168 jpeg_info.input_components=1;
2169 jpeg_info.in_color_space=JCS_GRAYSCALE;
2174 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2175 if (image_info->type == TrueColorType)
2177 if (IsImageGray(image,exception) != MagickFalse)
2179 jpeg_info.input_components=1;
2180 jpeg_info.in_color_space=JCS_GRAYSCALE;
2185 jpeg_set_defaults(&jpeg_info);
2186 if (jpeg_info.in_color_space == JCS_CMYK)
2187 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2188 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2189 jpeg_info.data_precision=8;
2191 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2192 jpeg_info.density_unit=(UINT8) 1;
2193 if (image->debug != MagickFalse)
2194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2195 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2196 floor(image->resolution.y+0.5));
2197 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2200 Set image resolution.
2202 jpeg_info.write_JFIF_header=TRUE;
2203 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2204 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2206 Set image resolution units.
2208 jpeg_info.density_unit=(UINT8) 0;
2209 if (image->units == PixelsPerInchResolution)
2210 jpeg_info.density_unit=(UINT8) 1;
2211 if (image->units == PixelsPerCentimeterResolution)
2212 jpeg_info.density_unit=(UINT8) 2;
2214 jpeg_info.dct_method=JDCT_FLOAT;
2215 option=GetImageOption(image_info,"jpeg:dct-method");
2216 if (option != (const char *) NULL)
2222 if (LocaleCompare(option,"default") == 0)
2223 jpeg_info.dct_method=JDCT_DEFAULT;
2229 if (LocaleCompare(option,"fastest") == 0)
2230 jpeg_info.dct_method=JDCT_FASTEST;
2231 if (LocaleCompare(option,"float") == 0)
2232 jpeg_info.dct_method=JDCT_FLOAT;
2238 if (LocaleCompare(option,"ifast") == 0)
2239 jpeg_info.dct_method=JDCT_IFAST;
2240 if (LocaleCompare(option,"islow") == 0)
2241 jpeg_info.dct_method=JDCT_ISLOW;
2245 option=GetImageOption(image_info,"jpeg:optimize-coding");
2246 if (option != (const char *) NULL)
2247 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : FALSE;
2253 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2254 image->rows*sizeof(JSAMPLE);
2255 if (length == (MagickSizeType) ((size_t) length))
2258 Perform optimization only if available memory resources permit it.
2260 status=AcquireMagickResource(MemoryResource,length);
2261 RelinquishMagickResource(MemoryResource,length);
2262 jpeg_info.optimize_coding=status;
2265 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2266 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2267 (image_info->interlace != NoInterlace))
2269 if (image->debug != MagickFalse)
2270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2271 "Interlace: progressive");
2272 jpeg_simple_progression(&jpeg_info);
2275 if (image->debug != MagickFalse)
2276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2277 "Interlace: non-progressive");
2279 if (image->debug != MagickFalse)
2280 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2281 "Interlace: nonprogressive");
2284 if ((image_info->compression != LosslessJPEGCompression) &&
2285 (image->quality <= 100))
2287 if (image->quality != UndefinedCompressionQuality)
2288 quality=(int) image->quality;
2289 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2291 (double) image->quality);
2295 #if !defined(C_LOSSLESS_SUPPORTED)
2297 if (image->debug != MagickFalse)
2298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2300 if (image->quality < 100)
2301 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2302 "LosslessToLossyJPEGConversion",image->filename);
2309 predictor=image->quality/100; /* range 1-7 */
2310 point_transform=image->quality % 20; /* range 0-15 */
2311 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2312 if (image->debug != MagickFalse)
2314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2315 "Compression: lossless");
2316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2317 "Predictor: %d",predictor);
2318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2319 "Point Transform: %d",point_transform);
2324 option=GetImageOption(image_info,"jpeg:extent");
2325 if (option != (const char *) NULL)
2333 jpeg_info=CloneImageInfo(image_info);
2334 jpeg_info->blob=NULL;
2335 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2336 if (jpeg_image != (Image *) NULL)
2346 Search for compression quality that does not exceed image extent.
2348 jpeg_info->quality=0;
2349 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2350 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2351 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2353 for (minimum=2; minimum < maximum; )
2355 (void) AcquireUniqueFilename(jpeg_image->filename);
2356 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2357 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2358 if (GetBlobSize(jpeg_image) <= extent)
2359 minimum=jpeg_image->quality+1;
2361 maximum=jpeg_image->quality-1;
2362 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2365 jpeg_image=DestroyImage(jpeg_image);
2367 jpeg_info=DestroyImageInfo(jpeg_info);
2369 jpeg_set_quality(&jpeg_info,quality,TRUE);
2370 #if (JPEG_LIB_VERSION >= 70)
2371 option=GetImageOption(image_info,"quality");
2372 if (option != (const char *) NULL)
2381 Set quality scaling for luminance and chrominance separately.
2383 flags=ParseGeometry(option,&geometry_info);
2384 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2386 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2387 (geometry_info.rho+0.5));
2388 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2389 (geometry_info.sigma+0.5));
2390 jpeg_default_qtables(&jpeg_info,TRUE);
2394 colorspace=jpeg_info.in_color_space;
2395 value=GetImageOption(image_info,"jpeg:colorspace");
2396 if (value == (char *) NULL)
2397 value=GetImageProperty(image,"jpeg:colorspace",exception);
2398 if (value != (char *) NULL)
2399 colorspace=StringToInteger(value);
2400 sampling_factor=(const char *) NULL;
2401 if (colorspace == jpeg_info.in_color_space)
2403 value=GetImageOption(image_info,"jpeg:sampling-factor");
2404 if (value == (char *) NULL)
2405 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2406 if (value != (char *) NULL)
2408 sampling_factor=value;
2409 if (image->debug != MagickFalse)
2410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411 " Input sampling-factors=%s",sampling_factor);
2414 value=GetImageOption(image_info,"jpeg:sampling-factor");
2415 if (image_info->sampling_factor != (char *) NULL)
2416 sampling_factor=image_info->sampling_factor;
2417 if (sampling_factor == (const char *) NULL)
2419 if (image->quality >= 90)
2420 for (i=0; i < MAX_COMPONENTS; i++)
2422 jpeg_info.comp_info[i].h_samp_factor=1;
2423 jpeg_info.comp_info[i].v_samp_factor=1;
2438 Set sampling factor.
2441 factors=SamplingFactorToList(sampling_factor);
2442 if (factors != (char **) NULL)
2444 for (i=0; i < MAX_COMPONENTS; i++)
2446 if (factors[i] == (char *) NULL)
2448 flags=ParseGeometry(factors[i],&geometry_info);
2449 if ((flags & SigmaValue) == 0)
2450 geometry_info.sigma=geometry_info.rho;
2451 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2452 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2453 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2455 factors=(char **) RelinquishMagickMemory(factors);
2457 for ( ; i < MAX_COMPONENTS; i++)
2459 jpeg_info.comp_info[i].h_samp_factor=1;
2460 jpeg_info.comp_info[i].v_samp_factor=1;
2463 option=GetImageOption(image_info,"jpeg:q-table");
2464 if (option != (const char *) NULL)
2470 Custom quantization tables.
2472 table=GetQuantizationTable(option,"0",exception);
2473 if (table != (QuantizationTable *) NULL)
2475 for (i=0; i < MAX_COMPONENTS; i++)
2476 jpeg_info.comp_info[i].quant_tbl_no=0;
2477 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2478 jpeg_quality_scaling(quality),0);
2479 table=DestroyQuantizationTable(table);
2481 table=GetQuantizationTable(option,"1",exception);
2482 if (table != (QuantizationTable *) NULL)
2484 for (i=1; i < MAX_COMPONENTS; i++)
2485 jpeg_info.comp_info[i].quant_tbl_no=1;
2486 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2487 jpeg_quality_scaling(quality),0);
2488 table=DestroyQuantizationTable(table);
2490 table=GetQuantizationTable(option,"2",exception);
2491 if (table != (QuantizationTable *) NULL)
2493 for (i=2; i < MAX_COMPONENTS; i++)
2494 jpeg_info.comp_info[i].quant_tbl_no=2;
2495 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2496 jpeg_quality_scaling(quality),0);
2497 table=DestroyQuantizationTable(table);
2499 table=GetQuantizationTable(option,"3",exception);
2500 if (table != (QuantizationTable *) NULL)
2502 for (i=3; i < MAX_COMPONENTS; i++)
2503 jpeg_info.comp_info[i].quant_tbl_no=3;
2504 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2505 jpeg_quality_scaling(quality),0);
2506 table=DestroyQuantizationTable(table);
2509 jpeg_start_compress(&jpeg_info,TRUE);
2510 if (image->debug != MagickFalse)
2512 if (image->storage_class == PseudoClass)
2513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2514 "Storage class: PseudoClass");
2516 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2517 "Storage class: DirectClass");
2518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2519 (double) image->depth);
2520 if (image->colors != 0)
2521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2522 "Number of colors: %.20g",(double) image->colors);
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525 "Number of colors: unspecified");
2526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2527 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2528 switch (image->colorspace)
2530 case CMYKColorspace:
2532 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2533 "Storage class: DirectClass");
2534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2535 "Colorspace: CMYK");
2538 case YCbCrColorspace:
2539 case Rec601YCbCrColorspace:
2540 case Rec709YCbCrColorspace:
2542 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2543 "Colorspace: YCbCr");
2549 switch (image->colorspace)
2551 case CMYKColorspace:
2553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2554 "Colorspace: CMYK");
2555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2556 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2557 jpeg_info.comp_info[0].h_samp_factor,
2558 jpeg_info.comp_info[0].v_samp_factor,
2559 jpeg_info.comp_info[1].h_samp_factor,
2560 jpeg_info.comp_info[1].v_samp_factor,
2561 jpeg_info.comp_info[2].h_samp_factor,
2562 jpeg_info.comp_info[2].v_samp_factor,
2563 jpeg_info.comp_info[3].h_samp_factor,
2564 jpeg_info.comp_info[3].v_samp_factor);
2567 case GRAYColorspace:
2569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2570 "Colorspace: GRAY");
2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2572 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2573 jpeg_info.comp_info[0].v_samp_factor);
2576 case sRGBColorspace:
2579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2580 "Image colorspace is RGB");
2581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2582 "Sampling factors: %dx%d,%dx%d,%dx%d",
2583 jpeg_info.comp_info[0].h_samp_factor,
2584 jpeg_info.comp_info[0].v_samp_factor,
2585 jpeg_info.comp_info[1].h_samp_factor,
2586 jpeg_info.comp_info[1].v_samp_factor,
2587 jpeg_info.comp_info[2].h_samp_factor,
2588 jpeg_info.comp_info[2].v_samp_factor);
2591 case YCbCrColorspace:
2592 case Rec601YCbCrColorspace:
2593 case Rec709YCbCrColorspace:
2595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2596 "Colorspace: YCbCr");
2597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2598 "Sampling factors: %dx%d,%dx%d,%dx%d",
2599 jpeg_info.comp_info[0].h_samp_factor,
2600 jpeg_info.comp_info[0].v_samp_factor,
2601 jpeg_info.comp_info[1].h_samp_factor,
2602 jpeg_info.comp_info[1].v_samp_factor,
2603 jpeg_info.comp_info[2].h_samp_factor,
2604 jpeg_info.comp_info[2].v_samp_factor);
2609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2612 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2613 jpeg_info.comp_info[0].h_samp_factor,
2614 jpeg_info.comp_info[0].v_samp_factor,
2615 jpeg_info.comp_info[1].h_samp_factor,
2616 jpeg_info.comp_info[1].v_samp_factor,
2617 jpeg_info.comp_info[2].h_samp_factor,
2618 jpeg_info.comp_info[2].v_samp_factor,
2619 jpeg_info.comp_info[3].h_samp_factor,
2620 jpeg_info.comp_info[3].v_samp_factor);
2626 Write JPEG profiles.
2628 value=GetImageProperty(image,"comment",exception);
2629 if (value != (char *) NULL)
2630 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2631 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2632 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2633 if (image->profiles != (void *) NULL)
2634 WriteProfile(&jpeg_info,image);
2636 Convert MIFF to JPEG raster pixels.
2638 memory_info=AcquireVirtualMemory((size_t) image->columns,
2639 jpeg_info.input_components*sizeof(*jpeg_pixels));
2640 if (memory_info == (MemoryInfo *) NULL)
2641 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2642 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2643 if (setjmp(error_manager.error_recovery) != 0)
2645 jpeg_destroy_compress(&jpeg_info);
2646 if (memory_info != (MemoryInfo *) NULL)
2647 memory_info=RelinquishVirtualMemory(memory_info);
2648 (void) CloseBlob(image);
2649 return(MagickFalse);
2651 scanline[0]=(JSAMPROW) jpeg_pixels;
2652 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2655 if (jpeg_info.data_precision <= 8)
2657 if ((jpeg_info.in_color_space == JCS_RGB) ||
2658 (jpeg_info.in_color_space == JCS_YCbCr))
2659 for (y=0; y < (ssize_t) image->rows; y++)
2661 register const Quantum
2667 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2668 if (p == (const Quantum *) NULL)
2671 for (x=0; x < (ssize_t) image->columns; x++)
2673 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2674 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2675 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2676 p+=GetPixelChannels(image);
2678 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2679 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2681 if (status == MagickFalse)
2685 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2686 for (y=0; y < (ssize_t) image->rows; y++)
2688 register const Quantum
2694 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2695 if (p == (const Quantum *) NULL)
2698 for (x=0; x < (ssize_t) image->columns; x++)
2700 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2702 p+=GetPixelChannels(image);
2704 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2705 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2707 if (status == MagickFalse)
2711 for (y=0; y < (ssize_t) image->rows; y++)
2713 register const Quantum
2719 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2720 if (p == (const Quantum *) NULL)
2723 for (x=0; x < (ssize_t) image->columns; x++)
2726 Convert DirectClass packets to contiguous CMYK scanlines.
2728 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2729 GetPixelCyan(image,p))));
2730 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2731 GetPixelMagenta(image,p))));
2732 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2733 GetPixelYellow(image,p))));
2734 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2735 GetPixelBlack(image,p))));
2736 p+=GetPixelChannels(image);
2738 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2739 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2741 if (status == MagickFalse)
2746 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2747 for (y=0; y < (ssize_t) image->rows; y++)
2749 register const Quantum
2755 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2756 if (p == (const Quantum *) NULL)
2759 for (x=0; x < (ssize_t) image->columns; x++)
2761 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2763 p+=GetPixelChannels(image);
2765 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2766 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2768 if (status == MagickFalse)
2772 if ((jpeg_info.in_color_space == JCS_RGB) ||
2773 (jpeg_info.in_color_space == JCS_YCbCr))
2774 for (y=0; y < (ssize_t) image->rows; y++)
2776 register const Quantum
2782 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2783 if (p == (const Quantum *) NULL)
2786 for (x=0; x < (ssize_t) image->columns; x++)
2788 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2789 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2790 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2791 p+=GetPixelChannels(image);
2793 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2794 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2796 if (status == MagickFalse)
2800 for (y=0; y < (ssize_t) image->rows; y++)
2802 register const Quantum
2808 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2809 if (p == (const Quantum *) NULL)
2812 for (x=0; x < (ssize_t) image->columns; x++)
2815 Convert DirectClass packets to contiguous CMYK scanlines.
2817 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2819 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2821 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2823 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2825 p+=GetPixelChannels(image);
2827 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2828 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2830 if (status == MagickFalse)
2833 if (y == (ssize_t) image->rows)
2834 jpeg_finish_compress(&jpeg_info);
2836 Relinquish resources.
2838 jpeg_destroy_compress(&jpeg_info);
2839 memory_info=RelinquishVirtualMemory(memory_info);
2840 (void) CloseBlob(image);