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)
523 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
526 if (image->debug != MagickFalse)
527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
528 "Profile: ICC, %.20g bytes",(double) length);
532 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
535 magick[MaxTextExtent];
552 register unsigned char
563 Determine length of binary data stored here.
565 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
566 length+=(size_t) GetCharacter(jpeg_info);
571 (void) GetCharacter(jpeg_info);
575 Validate that this was written as a Photoshop resource format slug.
577 for (i=0; i < 10; i++)
578 magick[i]=(char) GetCharacter(jpeg_info);
583 if (LocaleCompare(magick,"Photoshop ") != 0)
586 Not a IPTC profile, return.
588 for (i=0; i < (ssize_t) length; i++)
589 (void) GetCharacter(jpeg_info);
593 Remove the version number.
595 for (i=0; i < 4; i++)
596 (void) GetCharacter(jpeg_info);
602 error_manager=(ErrorManager *) jpeg_info->client_data;
603 exception=error_manager->exception;
604 image=error_manager->image;
605 profile=BlobToStringInfo((const void *) NULL,length);
606 if (profile == (StringInfo *) NULL)
608 (void) ThrowMagickException(exception,GetMagickModule(),
609 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
612 error_manager->profile=profile;
613 p=GetStringInfoDatum(profile);
614 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
615 *p++=(unsigned char) GetCharacter(jpeg_info);
616 error_manager->profile=NULL;
617 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
618 if (iptc_profile != (StringInfo *) NULL)
620 ConcatenateStringInfo(iptc_profile,profile);
621 profile=DestroyStringInfo(profile);
625 status=SetImageProfile(image,"8bim",profile,exception);
626 profile=DestroyStringInfo(profile);
627 if (status == MagickFalse)
628 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
631 if (image->debug != MagickFalse)
632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
633 "Profile: iptc, %.20g bytes",(double) length);
637 static boolean ReadProfile(j_decompress_ptr jpeg_info)
663 register unsigned char
673 Read generic profile.
675 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
676 length+=(size_t) GetCharacter(jpeg_info);
680 marker=jpeg_info->unread_marker-JPEG_APP0;
681 (void) FormatLocaleString(name,MaxTextExtent,"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)
688 (void) ThrowMagickException(exception,GetMagickModule(),
689 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
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;
699 p=GetStringInfoDatum(profile);
700 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
701 (void) CopyMagickString(name,"exif",MaxTextExtent);
702 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
708 Extract namespace from XMP profile.
710 p=GetStringInfoDatum(profile);
711 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
717 if (j < (ssize_t) GetStringInfoLength(profile))
718 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
719 (void) CopyMagickString(name,"xmp",MaxTextExtent);
722 previous_profile=GetImageProfile(image,name);
723 if (previous_profile != (const StringInfo *) NULL)
728 length=GetStringInfoLength(profile);
729 SetStringInfoLength(profile,GetStringInfoLength(profile)+
730 GetStringInfoLength(previous_profile));
731 (void) memmove(GetStringInfoDatum(profile)+
732 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
734 (void) memcpy(GetStringInfoDatum(profile),
735 GetStringInfoDatum(previous_profile),
736 GetStringInfoLength(previous_profile));
738 status=SetImageProfile(image,name,profile,exception);
739 profile=DestroyStringInfo(profile);
740 if (status == MagickFalse)
742 (void) ThrowMagickException(exception,GetMagickModule(),
743 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
746 if (image->debug != MagickFalse)
747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
748 "Profile: %s, %.20g bytes",name,(double) length);
752 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
757 if (number_bytes <= 0)
759 source=(SourceManager *) cinfo->src;
760 while (number_bytes > (long) source->manager.bytes_in_buffer)
762 number_bytes-=(long) source->manager.bytes_in_buffer;
763 (void) FillInputBuffer(cinfo);
765 source->manager.next_input_byte+=number_bytes;
766 source->manager.bytes_in_buffer-=number_bytes;
769 static void TerminateSource(j_decompress_ptr cinfo)
774 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
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;
795 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
796 Image *image, ExceptionInfo *exception)
798 image->quality=UndefinedCompressionQuality;
799 #if defined(D_PROGRESSIVE_SUPPORTED)
800 if (image->compression == LosslessJPEGCompression)
803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
804 "Quality: 100 (lossless)");
818 Determine the JPEG compression quality from the quantization tables.
821 for (i=0; i < NUM_QUANT_TBLS; i++)
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];
827 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
828 (jpeg_info->quant_tbl_ptrs[1] != NULL))
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,
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,
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++)
867 if ((qvalue < hash[i]) && (sum < sums[i]))
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");
879 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
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,
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,
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++)
916 if ((qvalue < hash[i]) && (sum < sums[i]))
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");
930 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
933 sampling_factor[MaxTextExtent];
935 switch (jpeg_info->out_color_space)
939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
940 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
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);
953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
954 "Colorspace: GRAYSCALE");
955 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
956 jpeg_info->comp_info[0].h_samp_factor,
957 jpeg_info->comp_info[0].v_samp_factor);
962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
963 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
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);
974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
975 jpeg_info->out_color_space);
976 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
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);
988 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
994 static Image *ReadJPEGImage(const ImageInfo *image_info,
995 ExceptionInfo *exception)
998 value[MaxTextExtent];
1010 *volatile jpeg_pixels;
1031 struct jpeg_decompress_struct
1034 struct jpeg_error_mgr
1049 assert(image_info != (const ImageInfo *) NULL);
1050 assert(image_info->signature == MagickSignature);
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 == MagickSignature);
1056 debug=IsEventLogging();
1058 image=AcquireImage(image_info,exception);
1059 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1060 if (status == MagickFalse)
1062 image=DestroyImageList(image);
1063 return((Image *) NULL);
1066 Initialize JPEG parameters.
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)
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));
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 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1093 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1094 for (i=1; i < 16; i++)
1095 if ((i != 2) && (i != 13) && (i != 14))
1096 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1097 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1098 if ((image_info->colorspace == YCbCrColorspace) ||
1099 (image_info->colorspace == Rec601YCbCrColorspace) ||
1100 (image_info->colorspace == Rec709YCbCrColorspace))
1101 jpeg_info.out_color_space=JCS_YCbCr;
1103 Set image resolution.
1106 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1107 (jpeg_info.Y_density != 1))
1109 image->resolution.x=(double) jpeg_info.X_density;
1110 image->resolution.y=(double) jpeg_info.Y_density;
1111 units=(size_t) jpeg_info.density_unit;
1114 image->units=PixelsPerInchResolution;
1116 image->units=PixelsPerCentimeterResolution;
1117 number_pixels=(MagickSizeType) image->columns*image->rows;
1118 option=GetImageOption(image_info,"jpeg:size");
1119 if (option != (const char *) NULL)
1133 flags=ParseGeometry(option,&geometry_info);
1134 if ((flags & SigmaValue) == 0)
1135 geometry_info.sigma=geometry_info.rho;
1136 jpeg_calc_output_dimensions(&jpeg_info);
1137 image->magick_columns=jpeg_info.output_width;
1138 image->magick_rows=jpeg_info.output_height;
1140 if (geometry_info.rho != 0.0)
1141 scale_factor=jpeg_info.output_width/geometry_info.rho;
1142 if ((geometry_info.sigma != 0.0) &&
1143 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1144 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1145 jpeg_info.scale_num=1U;
1146 jpeg_info.scale_denom=(unsigned int) scale_factor;
1147 jpeg_calc_output_dimensions(&jpeg_info);
1148 if (image->debug != MagickFalse)
1149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1150 "Scale factor: %.20g",(double) scale_factor);
1152 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1153 #if defined(D_LOSSLESS_SUPPORTED)
1154 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1155 JPEGInterlace : NoInterlace;
1156 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1157 LosslessJPEGCompression : JPEGCompression;
1158 if (jpeg_info.data_precision > 8)
1159 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1160 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1162 if (jpeg_info.data_precision == 16)
1163 jpeg_info.data_precision=12;
1165 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1167 image->compression=JPEGCompression;
1170 image->compression=JPEGCompression;
1171 image->interlace=JPEGInterlace;
1173 option=GetImageOption(image_info,"jpeg:colors");
1174 if (option != (const char *) NULL)
1177 Let the JPEG library quantize the image.
1179 jpeg_info.quantize_colors=TRUE;
1180 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1182 option=GetImageOption(image_info,"jpeg:block-smoothing");
1183 if (option != (const char *) NULL)
1184 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1186 jpeg_info.dct_method=JDCT_FLOAT;
1187 option=GetImageOption(image_info,"jpeg:dct-method");
1188 if (option != (const char *) NULL)
1194 if (LocaleCompare(option,"default") == 0)
1195 jpeg_info.dct_method=JDCT_DEFAULT;
1201 if (LocaleCompare(option,"fastest") == 0)
1202 jpeg_info.dct_method=JDCT_FASTEST;
1203 if (LocaleCompare(option,"float") == 0)
1204 jpeg_info.dct_method=JDCT_FLOAT;
1210 if (LocaleCompare(option,"ifast") == 0)
1211 jpeg_info.dct_method=JDCT_IFAST;
1212 if (LocaleCompare(option,"islow") == 0)
1213 jpeg_info.dct_method=JDCT_ISLOW;
1217 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1218 if (option != (const char *) NULL)
1219 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1221 (void) jpeg_start_decompress(&jpeg_info);
1222 image->columns=jpeg_info.output_width;
1223 image->rows=jpeg_info.output_height;
1224 image->depth=(size_t) jpeg_info.data_precision;
1225 switch (jpeg_info.out_color_space)
1230 (void) SetImageColorspace(image,sRGBColorspace,exception);
1235 (void) SetImageColorspace(image,GRAYColorspace,exception);
1240 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1245 (void) SetImageColorspace(image,CMYKColorspace,exception);
1249 if (IsITUFaxImage(image) != MagickFalse)
1251 (void) SetImageColorspace(image,LabColorspace,exception);
1252 jpeg_info.out_color_space=JCS_YCbCr;
1254 option=GetImageOption(image_info,"jpeg:colors");
1255 if (option != (const char *) NULL)
1256 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1258 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1259 if ((jpeg_info.output_components == 1) &&
1260 (jpeg_info.quantize_colors == MagickFalse))
1265 colors=(size_t) GetQuantumRange(image->depth)+1;
1266 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1267 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1269 if (image->debug != MagickFalse)
1271 if (image->interlace != NoInterlace)
1272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1273 "Interlace: progressive");
1275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1276 "Interlace: nonprogressive");
1277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1278 (int) jpeg_info.data_precision);
1279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1280 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1282 JPEGSetImageQuality(&jpeg_info,image,exception);
1283 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1284 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1285 jpeg_info.out_color_space);
1286 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1287 if (image_info->ping != MagickFalse)
1289 jpeg_destroy_decompress(&jpeg_info);
1290 (void) CloseBlob(image);
1291 return(GetFirstImageInList(image));
1293 memory_info=AcquireVirtualMemory((size_t) image->columns,
1294 jpeg_info.output_components*sizeof(*jpeg_pixels));
1295 if (memory_info == (MemoryInfo *) NULL)
1297 jpeg_destroy_decompress(&jpeg_info);
1298 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1300 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1302 Convert JPEG pixels to pixel packets.
1304 if (setjmp(error_manager.error_recovery) != 0)
1306 if (memory_info != (MemoryInfo *) NULL)
1307 memory_info=RelinquishVirtualMemory(memory_info);
1308 jpeg_destroy_decompress(&jpeg_info);
1309 (void) CloseBlob(image);
1310 number_pixels=(MagickSizeType) image->columns*image->rows;
1311 if (number_pixels != 0)
1312 return(GetFirstImageInList(image));
1313 return(DestroyImage(image));
1315 if (jpeg_info.quantize_colors != MagickFalse)
1317 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1318 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1319 for (i=0; i < (ssize_t) image->colors; i++)
1321 image->colormap[i].red=(double) ScaleCharToQuantum(
1322 jpeg_info.colormap[0][i]);
1323 image->colormap[i].green=image->colormap[i].red;
1324 image->colormap[i].blue=image->colormap[i].red;
1325 image->colormap[i].alpha=OpaqueAlpha;
1328 for (i=0; i < (ssize_t) image->colors; i++)
1330 image->colormap[i].red=(double) ScaleCharToQuantum(
1331 jpeg_info.colormap[0][i]);
1332 image->colormap[i].green=(double) ScaleCharToQuantum(
1333 jpeg_info.colormap[1][i]);
1334 image->colormap[i].blue=(double) ScaleCharToQuantum(
1335 jpeg_info.colormap[2][i]);
1336 image->colormap[i].alpha=OpaqueAlpha;
1339 scanline[0]=(JSAMPROW) jpeg_pixels;
1340 for (y=0; y < (ssize_t) image->rows; y++)
1348 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1350 (void) ThrowMagickException(exception,GetMagickModule(),
1351 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1355 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1356 if (q == (Quantum *) NULL)
1358 if (jpeg_info.data_precision > 8)
1363 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1364 if (jpeg_info.output_components == 1)
1365 for (x=0; x < (ssize_t) image->columns; x++)
1370 pixel=(size_t) (scale*GETJSAMPLE(*p));
1371 index=ConstrainColormapIndex(image,pixel,exception);
1372 SetPixelIndex(image,index,q);
1373 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1375 q+=GetPixelChannels(image);
1378 if (image->colorspace != CMYKColorspace)
1379 for (x=0; x < (ssize_t) image->columns; x++)
1381 SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1383 SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1385 SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1387 SetPixelAlpha(image,OpaqueAlpha,q);
1388 q+=GetPixelChannels(image);
1391 for (x=0; x < (ssize_t) image->columns; x++)
1393 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(scale*
1394 GETJSAMPLE(*p++)),q);
1395 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(scale*
1396 GETJSAMPLE(*p++)),q);
1397 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(scale*
1398 GETJSAMPLE(*p++)),q);
1399 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(scale*
1400 GETJSAMPLE(*p++)),q);
1401 SetPixelAlpha(image,OpaqueAlpha,q);
1402 q+=GetPixelChannels(image);
1406 if (jpeg_info.output_components == 1)
1407 for (x=0; x < (ssize_t) image->columns; x++)
1409 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1410 SetPixelIndex(image,index,q);
1411 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1413 q+=GetPixelChannels(image);
1416 if (image->colorspace != CMYKColorspace)
1417 for (x=0; x < (ssize_t) image->columns; x++)
1419 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1420 GETJSAMPLE(*p++)),q);
1421 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1422 GETJSAMPLE(*p++)),q);
1423 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1424 GETJSAMPLE(*p++)),q);
1425 SetPixelAlpha(image,OpaqueAlpha,q);
1426 q+=GetPixelChannels(image);
1429 for (x=0; x < (ssize_t) image->columns; x++)
1431 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1432 (unsigned char) GETJSAMPLE(*p++)),q);
1433 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1434 (unsigned char) GETJSAMPLE(*p++)),q);
1435 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1436 (unsigned char) GETJSAMPLE(*p++)),q);
1437 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1438 (unsigned char) GETJSAMPLE(*p++)),q);
1439 SetPixelAlpha(image,OpaqueAlpha,q);
1440 q+=GetPixelChannels(image);
1442 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1444 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1446 if (status == MagickFalse)
1448 jpeg_abort_decompress(&jpeg_info);
1452 if (status != MagickFalse)
1454 error_manager.finished=MagickTrue;
1455 if (setjmp(error_manager.error_recovery) == 0)
1456 (void) jpeg_finish_decompress(&jpeg_info);
1459 Free jpeg resources.
1461 jpeg_destroy_decompress(&jpeg_info);
1462 memory_info=RelinquishVirtualMemory(memory_info);
1463 (void) CloseBlob(image);
1464 return(GetFirstImageInList(image));
1470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474 % R e g i s t e r J P E G I m a g e %
1478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 % RegisterJPEGImage() adds properties for the JPEG image format to
1481 % the list of supported formats. The properties include the image format
1482 % tag, a method to read and/or write the format, whether the format
1483 % supports the saving of more than one frame to the same file or blob,
1484 % whether the format supports native in-memory I/O, and a brief
1485 % description of the format.
1487 % The format of the RegisterJPEGImage method is:
1489 % size_t RegisterJPEGImage(void)
1492 ModuleExport size_t RegisterJPEGImage(void)
1495 version[MaxTextExtent];
1501 description[] = "Joint Photographic Experts Group JFIF format";
1504 #if defined(JPEG_LIB_VERSION)
1505 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1507 entry=SetMagickInfo("JPEG");
1508 entry->thread_support=NoThreadSupport;
1509 #if defined(MAGICKCORE_JPEG_DELEGATE)
1510 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1511 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1513 entry->magick=(IsImageFormatHandler *) IsJPEG;
1514 entry->adjoin=MagickFalse;
1515 entry->description=ConstantString(description);
1516 if (*version != '\0')
1517 entry->version=ConstantString(version);
1518 entry->mime_type=ConstantString("image/jpeg");
1519 entry->module=ConstantString("JPEG");
1520 (void) RegisterMagickInfo(entry);
1521 entry=SetMagickInfo("JPG");
1522 entry->thread_support=NoThreadSupport;
1523 #if defined(MAGICKCORE_JPEG_DELEGATE)
1524 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1525 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1527 entry->adjoin=MagickFalse;
1528 entry->description=ConstantString(description);
1529 if (*version != '\0')
1530 entry->version=ConstantString(version);
1531 entry->mime_type=ConstantString("image/jpeg");
1532 entry->module=ConstantString("JPEG");
1533 (void) RegisterMagickInfo(entry);
1534 entry=SetMagickInfo("PJPEG");
1535 entry->thread_support=NoThreadSupport;
1536 #if defined(MAGICKCORE_JPEG_DELEGATE)
1537 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1538 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1540 entry->adjoin=MagickFalse;
1541 entry->description=ConstantString(description);
1542 if (*version != '\0')
1543 entry->version=ConstantString(version);
1544 entry->mime_type=ConstantString("image/jpeg");
1545 entry->module=ConstantString("JPEG");
1546 (void) RegisterMagickInfo(entry);
1547 return(MagickImageCoderSignature);
1552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 % U n r e g i s t e r J P E G I m a g e %
1560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1562 % UnregisterJPEGImage() removes format registrations made by the
1563 % JPEG module from the list of supported formats.
1565 % The format of the UnregisterJPEGImage method is:
1567 % UnregisterJPEGImage(void)
1570 ModuleExport void UnregisterJPEGImage(void)
1572 (void) UnregisterMagickInfo("PJPG");
1573 (void) UnregisterMagickInfo("JPEG");
1574 (void) UnregisterMagickInfo("JPG");
1578 #if defined(MAGICKCORE_JPEG_DELEGATE)
1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584 % W r i t e J P E G I m a g e %
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590 % WriteJPEGImage() writes a JPEG image file and returns it. It
1591 % allocates the memory necessary for the new Image structure and returns a
1592 % pointer to the new image.
1594 % The format of the WriteJPEGImage method is:
1596 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1597 % Image *image,ExceptionInfo *exception)
1599 % A description of each parameter follows:
1601 % o image_info: the image info.
1603 % o jpeg_image: The image.
1605 % o exception: return any errors or warnings in this structure.
1609 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1611 assert(table != (QuantizationTable *) NULL);
1612 if (table->slot != (char *) NULL)
1613 table->slot=DestroyString(table->slot);
1614 if (table->description != (char *) NULL)
1615 table->description=DestroyString(table->description);
1616 if (table->levels != (unsigned int *) NULL)
1617 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1618 table=(QuantizationTable *) RelinquishMagickMemory(table);
1622 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1627 destination=(DestinationManager *) cinfo->dest;
1628 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1629 MaxBufferExtent,destination->buffer);
1630 if (destination->manager.free_in_buffer != MaxBufferExtent)
1631 ERREXIT(cinfo,JERR_FILE_WRITE);
1632 destination->manager.next_output_byte=destination->buffer;
1636 static QuantizationTable *GetQuantizationTable(const char *filename,
1637 const char *slot,ExceptionInfo *exception)
1665 *quantization_tables,
1668 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1669 "Loading quantization tables \"%s\" ...",filename);
1670 table=(QuantizationTable *) NULL;
1671 xml=FileToString(filename,~0UL,exception);
1672 if (xml == (char *) NULL)
1674 quantization_tables=NewXMLTree(xml,exception);
1675 if (quantization_tables == (XMLTreeInfo *) NULL)
1677 xml=DestroyString(xml);
1680 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1681 table_iterator != (XMLTreeInfo *) NULL;
1682 table_iterator=GetNextXMLTreeTag(table_iterator))
1684 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1685 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1687 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1688 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1691 if (table_iterator == (XMLTreeInfo *) NULL)
1693 xml=DestroyString(xml);
1696 description=GetXMLTreeChild(table_iterator,"description");
1697 if (description == (XMLTreeInfo *) NULL)
1699 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1700 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1701 quantization_tables=DestroyXMLTree(quantization_tables);
1702 xml=DestroyString(xml);
1705 levels=GetXMLTreeChild(table_iterator,"levels");
1706 if (levels == (XMLTreeInfo *) NULL)
1708 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1709 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1710 quantization_tables=DestroyXMLTree(quantization_tables);
1711 xml=DestroyString(xml);
1714 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1715 if (table == (QuantizationTable *) NULL)
1716 ThrowFatalException(ResourceLimitFatalError,
1717 "UnableToAcquireQuantizationTable");
1718 table->slot=(char *) NULL;
1719 table->description=(char *) NULL;
1720 table->levels=(unsigned int *) NULL;
1721 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1722 if (attribute != (char *) NULL)
1723 table->slot=ConstantString(attribute);
1724 content=GetXMLTreeContent(description);
1725 if (content != (char *) NULL)
1726 table->description=ConstantString(content);
1727 attribute=GetXMLTreeAttribute(levels,"width");
1728 if (attribute == (char *) NULL)
1730 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1731 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1732 quantization_tables=DestroyXMLTree(quantization_tables);
1733 table=DestroyQuantizationTable(table);
1734 xml=DestroyString(xml);
1737 table->width=StringToUnsignedLong(attribute);
1738 if (table->width == 0)
1740 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1741 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1742 quantization_tables=DestroyXMLTree(quantization_tables);
1743 table=DestroyQuantizationTable(table);
1744 xml=DestroyString(xml);
1747 attribute=GetXMLTreeAttribute(levels,"height");
1748 if (attribute == (char *) NULL)
1750 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1751 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1752 quantization_tables=DestroyXMLTree(quantization_tables);
1753 table=DestroyQuantizationTable(table);
1754 xml=DestroyString(xml);
1757 table->height=StringToUnsignedLong(attribute);
1758 if (table->height == 0)
1760 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1761 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1762 quantization_tables=DestroyXMLTree(quantization_tables);
1763 table=DestroyQuantizationTable(table);
1764 xml=DestroyString(xml);
1767 attribute=GetXMLTreeAttribute(levels,"divisor");
1768 if (attribute == (char *) NULL)
1770 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1771 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1772 quantization_tables=DestroyXMLTree(quantization_tables);
1773 table=DestroyQuantizationTable(table);
1774 xml=DestroyString(xml);
1777 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1778 if (table->divisor == 0.0)
1780 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1781 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1782 quantization_tables=DestroyXMLTree(quantization_tables);
1783 table=DestroyQuantizationTable(table);
1784 xml=DestroyString(xml);
1787 content=GetXMLTreeContent(levels);
1788 if (content == (char *) NULL)
1790 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1791 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1792 quantization_tables=DestroyXMLTree(quantization_tables);
1793 table=DestroyQuantizationTable(table);
1794 xml=DestroyString(xml);
1797 length=(size_t) table->width*table->height;
1800 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1801 sizeof(*table->levels));
1802 if (table->levels == (unsigned int *) NULL)
1803 ThrowFatalException(ResourceLimitFatalError,
1804 "UnableToAcquireQuantizationTable");
1805 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1807 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1808 table->divisor+0.5);
1809 while (isspace((int) ((unsigned char) *p)) != 0)
1815 value=InterpretLocaleValue(content,&p);
1819 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1820 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1821 quantization_tables=DestroyXMLTree(quantization_tables);
1822 table=DestroyQuantizationTable(table);
1823 xml=DestroyString(xml);
1826 for (j=i; j < 64; j++)
1827 table->levels[j]=table->levels[j-1];
1828 quantization_tables=DestroyXMLTree(quantization_tables);
1829 xml=DestroyString(xml);
1833 static void InitializeDestination(j_compress_ptr cinfo)
1838 destination=(DestinationManager *) cinfo->dest;
1839 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1840 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1841 destination->manager.next_output_byte=destination->buffer;
1842 destination->manager.free_in_buffer=MaxBufferExtent;
1845 static inline size_t MagickMin(const size_t x,const size_t y)
1852 static void TerminateDestination(j_compress_ptr cinfo)
1857 destination=(DestinationManager *) cinfo->dest;
1858 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1863 count=WriteBlob(destination->image,MaxBufferExtent-
1864 destination->manager.free_in_buffer,destination->buffer);
1865 if (count != (ssize_t)
1866 (MaxBufferExtent-destination->manager.free_in_buffer))
1867 ERREXIT(cinfo,JERR_FILE_WRITE);
1871 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1893 Save image profile as a APP marker.
1896 custom_profile=AcquireStringInfo(65535L);
1897 ResetImageProfileIterator(image);
1898 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1900 register unsigned char
1903 profile=GetImageProfile(image,name);
1904 p=GetStringInfoDatum(custom_profile);
1905 if (LocaleCompare(name,"EXIF") == 0)
1906 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1908 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1909 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1910 (unsigned int) length);
1912 if (LocaleCompare(name,"ICC") == 0)
1914 register unsigned char
1917 tag_length=strlen(ICC_PROFILE);
1918 p=GetStringInfoDatum(custom_profile);
1919 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1921 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1923 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1924 p[12]=(unsigned char) ((i/65519L)+1);
1925 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1926 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1928 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1929 custom_profile),(unsigned int) (length+tag_length+3));
1932 if (((LocaleCompare(name,"IPTC") == 0) ||
1933 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1939 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1941 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1942 roundup=(size_t) (length & 0x01);
1943 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1945 (void) memcpy(p,"Photoshop 3.0 ",14);
1950 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1952 p[24]=(unsigned char) (length >> 8);
1953 p[25]=(unsigned char) (length & 0xff);
1956 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1958 p[length+tag_length]='\0';
1959 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1960 custom_profile),(unsigned int) (length+tag_length+roundup));
1963 if (LocaleCompare(name,"XMP") == 0)
1969 Add namespace to XMP profile.
1971 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1972 if (xmp_profile != (StringINfo *) NULL)
1974 ConcatenateStringInfo(xmp_profile,profile);
1975 GetStringInfoDatum(xmp_profile)[28]='\0';
1976 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1978 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1979 jpeg_write_marker(jpeg_info,XML_MARKER,
1980 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1982 xmp_profile=DestroyStringInfo(xmp_profile);
1985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1986 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1987 name=GetNextImageProfile(image);
1989 custom_profile=DestroyStringInfo(custom_profile);
1992 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1997 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1998 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1999 destination=(DestinationManager *) cinfo->dest;
2000 destination->manager.init_destination=InitializeDestination;
2001 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2002 destination->manager.term_destination=TerminateDestination;
2003 destination->image=image;
2006 static char **SamplingFactorToList(const char *text)
2023 if (text == (char *) NULL)
2024 return((char **) NULL);
2026 Convert string to an ASCII list.
2029 for (p=text; *p != '\0'; p++)
2032 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2034 if (textlist == (char **) NULL)
2035 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2037 for (i=0; i < (ssize_t) lines; i++)
2039 for (q=(char *) p; *q != '\0'; q++)
2042 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2043 sizeof(*textlist[i]));
2044 if (textlist[i] == (char *) NULL)
2045 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2046 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2051 textlist[i]=(char *) NULL;
2055 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2056 Image *image,ExceptionInfo *exception)
2071 *volatile jpeg_pixels;
2091 struct jpeg_compress_struct
2094 struct jpeg_error_mgr
2103 assert(image_info != (const ImageInfo *) NULL);
2104 assert(image_info->signature == MagickSignature);
2105 assert(image != (Image *) NULL);
2106 assert(image->signature == MagickSignature);
2107 if (image->debug != MagickFalse)
2108 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2109 assert(exception != (ExceptionInfo *) NULL);
2110 assert(exception->signature == MagickSignature);
2111 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2112 if (status == MagickFalse)
2115 Initialize JPEG parameters.
2117 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2118 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2119 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2120 jpeg_info.client_data=(void *) image;
2121 jpeg_info.err=jpeg_std_error(&jpeg_error);
2122 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2123 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2124 error_manager.exception=exception;
2125 error_manager.image=image;
2126 memory_info=(MemoryInfo *) NULL;
2127 if (setjmp(error_manager.error_recovery) != 0)
2129 jpeg_destroy_compress(&jpeg_info);
2130 (void) CloseBlob(image);
2131 return(MagickFalse);
2133 jpeg_info.client_data=(void *) &error_manager;
2134 jpeg_create_compress(&jpeg_info);
2135 JPEGDestinationManager(&jpeg_info,image);
2136 if ((image->columns != (unsigned int) image->columns) ||
2137 (image->rows != (unsigned int) image->rows))
2138 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2139 jpeg_info.image_width=(unsigned int) image->columns;
2140 jpeg_info.image_height=(unsigned int) image->rows;
2141 jpeg_info.input_components=3;
2142 jpeg_info.data_precision=8;
2143 jpeg_info.in_color_space=JCS_RGB;
2144 switch (image->colorspace)
2146 case CMYKColorspace:
2148 jpeg_info.input_components=4;
2149 jpeg_info.in_color_space=JCS_CMYK;
2152 case YCbCrColorspace:
2153 case Rec601YCbCrColorspace:
2154 case Rec709YCbCrColorspace:
2156 jpeg_info.in_color_space=JCS_YCbCr;
2159 case GRAYColorspace:
2161 if (image_info->type == TrueColorType)
2163 jpeg_info.input_components=1;
2164 jpeg_info.in_color_space=JCS_GRAYSCALE;
2169 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2170 if (image_info->type == TrueColorType)
2172 if (IsImageGray(image,exception) != MagickFalse)
2174 jpeg_info.input_components=1;
2175 jpeg_info.in_color_space=JCS_GRAYSCALE;
2180 jpeg_set_defaults(&jpeg_info);
2181 if (jpeg_info.in_color_space == JCS_CMYK)
2182 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2183 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2184 jpeg_info.data_precision=8;
2186 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2187 jpeg_info.density_unit=(UINT8) 1;
2188 if (image->debug != MagickFalse)
2189 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2190 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2191 floor(image->resolution.y+0.5));
2192 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2195 Set image resolution.
2197 jpeg_info.write_JFIF_header=TRUE;
2198 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2199 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2201 Set image resolution units.
2203 jpeg_info.density_unit=(UINT8) 0;
2204 if (image->units == PixelsPerInchResolution)
2205 jpeg_info.density_unit=(UINT8) 1;
2206 if (image->units == PixelsPerCentimeterResolution)
2207 jpeg_info.density_unit=(UINT8) 2;
2209 jpeg_info.dct_method=JDCT_FLOAT;
2210 option=GetImageOption(image_info,"jpeg:dct-method");
2211 if (option != (const char *) NULL)
2217 if (LocaleCompare(option,"default") == 0)
2218 jpeg_info.dct_method=JDCT_DEFAULT;
2224 if (LocaleCompare(option,"fastest") == 0)
2225 jpeg_info.dct_method=JDCT_FASTEST;
2226 if (LocaleCompare(option,"float") == 0)
2227 jpeg_info.dct_method=JDCT_FLOAT;
2233 if (LocaleCompare(option,"ifast") == 0)
2234 jpeg_info.dct_method=JDCT_IFAST;
2235 if (LocaleCompare(option,"islow") == 0)
2236 jpeg_info.dct_method=JDCT_ISLOW;
2240 option=GetImageOption(image_info,"jpeg:optimize-coding");
2241 if (option != (const char *) NULL)
2242 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : FALSE;
2248 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2249 image->rows*sizeof(JSAMPLE);
2250 if (length == (MagickSizeType) ((size_t) length))
2253 Perform optimization only if available memory resources permit it.
2255 status=AcquireMagickResource(MemoryResource,length);
2256 RelinquishMagickResource(MemoryResource,length);
2257 jpeg_info.optimize_coding=status;
2260 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2261 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2262 (image_info->interlace != NoInterlace))
2264 if (image->debug != MagickFalse)
2265 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2266 "Interlace: progressive");
2267 jpeg_simple_progression(&jpeg_info);
2270 if (image->debug != MagickFalse)
2271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2272 "Interlace: non-progressive");
2274 if (image->debug != MagickFalse)
2275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2276 "Interlace: nonprogressive");
2279 if ((image_info->compression != LosslessJPEGCompression) &&
2280 (image->quality <= 100))
2282 if (image->quality != UndefinedCompressionQuality)
2283 quality=(int) image->quality;
2284 if (image->debug != MagickFalse)
2285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2286 (double) image->quality);
2290 #if !defined(C_LOSSLESS_SUPPORTED)
2292 if (image->debug != MagickFalse)
2293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2295 if (image->quality < 100)
2296 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2297 "LosslessToLossyJPEGConversion",image->filename);
2304 predictor=image->quality/100; /* range 1-7 */
2305 point_transform=image->quality % 20; /* range 0-15 */
2306 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2307 if (image->debug != MagickFalse)
2309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2310 "Compression: lossless");
2311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2312 "Predictor: %d",predictor);
2313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2314 "Point Transform: %d",point_transform);
2319 option=GetImageOption(image_info,"jpeg:extent");
2320 if (option != (const char *) NULL)
2328 jpeg_info=CloneImageInfo(image_info);
2329 jpeg_info->blob=NULL;
2330 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2331 if (jpeg_image != (Image *) NULL)
2341 Search for compression quality that does not exceed image extent.
2343 jpeg_info->quality=0;
2344 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2345 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2346 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2348 for (minimum=2; minimum < maximum; )
2350 (void) AcquireUniqueFilename(jpeg_image->filename);
2351 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2352 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2353 if (GetBlobSize(jpeg_image) <= extent)
2354 minimum=jpeg_image->quality+1;
2356 maximum=jpeg_image->quality-1;
2357 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2360 jpeg_image=DestroyImage(jpeg_image);
2362 jpeg_info=DestroyImageInfo(jpeg_info);
2364 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2365 #if (JPEG_LIB_VERSION >= 70)
2366 option=GetImageOption(image_info,"quality");
2367 if (option != (const char *) NULL)
2376 Set quality scaling for luminance and chrominance separately.
2378 flags=ParseGeometry(option,&geometry_info);
2379 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2381 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2382 (geometry_info.rho+0.5));
2383 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2384 (geometry_info.sigma+0.5));
2385 jpeg_default_qtables(&jpeg_info,MagickTrue);
2389 colorspace=jpeg_info.in_color_space;
2390 value=GetImageOption(image_info,"jpeg:colorspace");
2391 if (value == (char *) NULL)
2392 value=GetImageProperty(image,"jpeg:colorspace",exception);
2393 if (value != (char *) NULL)
2394 colorspace=StringToInteger(value);
2395 sampling_factor=(const char *) NULL;
2396 if (colorspace == jpeg_info.in_color_space)
2398 value=GetImageOption(image_info,"jpeg:sampling-factor");
2399 if (value == (char *) NULL)
2400 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2401 if (value != (char *) NULL)
2403 sampling_factor=value;
2404 if (image->debug != MagickFalse)
2405 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2406 " Input sampling-factors=%s",sampling_factor);
2409 value=GetImageOption(image_info,"jpeg:sampling-factor");
2410 if (image_info->sampling_factor != (char *) NULL)
2411 sampling_factor=image_info->sampling_factor;
2412 if (sampling_factor == (const char *) NULL)
2414 if (image->quality >= 90)
2415 for (i=0; i < MAX_COMPONENTS; i++)
2417 jpeg_info.comp_info[i].h_samp_factor=1;
2418 jpeg_info.comp_info[i].v_samp_factor=1;
2433 Set sampling factor.
2436 factors=SamplingFactorToList(sampling_factor);
2437 if (factors != (char **) NULL)
2439 for (i=0; i < MAX_COMPONENTS; i++)
2441 if (factors[i] == (char *) NULL)
2443 flags=ParseGeometry(factors[i],&geometry_info);
2444 if ((flags & SigmaValue) == 0)
2445 geometry_info.sigma=geometry_info.rho;
2446 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2447 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2448 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2450 factors=(char **) RelinquishMagickMemory(factors);
2452 for ( ; i < MAX_COMPONENTS; i++)
2454 jpeg_info.comp_info[i].h_samp_factor=1;
2455 jpeg_info.comp_info[i].v_samp_factor=1;
2458 option=GetImageOption(image_info,"jpeg:q-table");
2459 if (option != (const char *) NULL)
2465 Custom quantization tables.
2467 table=GetQuantizationTable(option,"0",exception);
2468 if (table != (QuantizationTable *) NULL)
2470 for (i=0; i < MAX_COMPONENTS; i++)
2471 jpeg_info.comp_info[i].quant_tbl_no=0;
2472 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2473 jpeg_quality_scaling(quality),0);
2474 table=DestroyQuantizationTable(table);
2476 table=GetQuantizationTable(option,"1",exception);
2477 if (table != (QuantizationTable *) NULL)
2479 for (i=1; i < MAX_COMPONENTS; i++)
2480 jpeg_info.comp_info[i].quant_tbl_no=1;
2481 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2482 jpeg_quality_scaling(quality),0);
2483 table=DestroyQuantizationTable(table);
2485 table=GetQuantizationTable(option,"2",exception);
2486 if (table != (QuantizationTable *) NULL)
2488 for (i=2; i < MAX_COMPONENTS; i++)
2489 jpeg_info.comp_info[i].quant_tbl_no=2;
2490 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2491 jpeg_quality_scaling(quality),0);
2492 table=DestroyQuantizationTable(table);
2494 table=GetQuantizationTable(option,"3",exception);
2495 if (table != (QuantizationTable *) NULL)
2497 for (i=3; i < MAX_COMPONENTS; i++)
2498 jpeg_info.comp_info[i].quant_tbl_no=3;
2499 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2500 jpeg_quality_scaling(quality),0);
2501 table=DestroyQuantizationTable(table);
2504 jpeg_start_compress(&jpeg_info,MagickTrue);
2505 if (image->debug != MagickFalse)
2507 if (image->storage_class == PseudoClass)
2508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2509 "Storage class: PseudoClass");
2511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2512 "Storage class: DirectClass");
2513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2514 (double) image->depth);
2515 if (image->colors != 0)
2516 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2517 "Number of colors: %.20g",(double) image->colors);
2519 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2520 "Number of colors: unspecified");
2521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2522 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2523 switch (image->colorspace)
2525 case CMYKColorspace:
2527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2528 "Storage class: DirectClass");
2529 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2530 "Colorspace: CMYK");
2533 case YCbCrColorspace:
2534 case Rec601YCbCrColorspace:
2535 case Rec709YCbCrColorspace:
2537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2538 "Colorspace: YCbCr");
2544 switch (image->colorspace)
2546 case CMYKColorspace:
2548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549 "Colorspace: CMYK");
2550 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2551 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2552 jpeg_info.comp_info[0].h_samp_factor,
2553 jpeg_info.comp_info[0].v_samp_factor,
2554 jpeg_info.comp_info[1].h_samp_factor,
2555 jpeg_info.comp_info[1].v_samp_factor,
2556 jpeg_info.comp_info[2].h_samp_factor,
2557 jpeg_info.comp_info[2].v_samp_factor,
2558 jpeg_info.comp_info[3].h_samp_factor,
2559 jpeg_info.comp_info[3].v_samp_factor);
2562 case GRAYColorspace:
2564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2565 "Colorspace: GRAY");
2566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2567 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2568 jpeg_info.comp_info[0].v_samp_factor);
2571 case sRGBColorspace:
2574 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2575 "Image colorspace is RGB");
2576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2577 "Sampling factors: %dx%d,%dx%d,%dx%d",
2578 jpeg_info.comp_info[0].h_samp_factor,
2579 jpeg_info.comp_info[0].v_samp_factor,
2580 jpeg_info.comp_info[1].h_samp_factor,
2581 jpeg_info.comp_info[1].v_samp_factor,
2582 jpeg_info.comp_info[2].h_samp_factor,
2583 jpeg_info.comp_info[2].v_samp_factor);
2586 case YCbCrColorspace:
2587 case Rec601YCbCrColorspace:
2588 case Rec709YCbCrColorspace:
2590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2591 "Colorspace: YCbCr");
2592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2593 "Sampling factors: %dx%d,%dx%d,%dx%d",
2594 jpeg_info.comp_info[0].h_samp_factor,
2595 jpeg_info.comp_info[0].v_samp_factor,
2596 jpeg_info.comp_info[1].h_samp_factor,
2597 jpeg_info.comp_info[1].v_samp_factor,
2598 jpeg_info.comp_info[2].h_samp_factor,
2599 jpeg_info.comp_info[2].v_samp_factor);
2604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2607 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2608 jpeg_info.comp_info[0].h_samp_factor,
2609 jpeg_info.comp_info[0].v_samp_factor,
2610 jpeg_info.comp_info[1].h_samp_factor,
2611 jpeg_info.comp_info[1].v_samp_factor,
2612 jpeg_info.comp_info[2].h_samp_factor,
2613 jpeg_info.comp_info[2].v_samp_factor,
2614 jpeg_info.comp_info[3].h_samp_factor,
2615 jpeg_info.comp_info[3].v_samp_factor);
2621 Write JPEG profiles.
2623 value=GetImageProperty(image,"comment",exception);
2624 if (value != (char *) NULL)
2625 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2626 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2627 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2628 if (image->profiles != (void *) NULL)
2629 WriteProfile(&jpeg_info,image);
2631 Convert MIFF to JPEG raster pixels.
2633 memory_info=AcquireVirtualMemory((size_t) image->columns,
2634 jpeg_info.input_components*sizeof(*jpeg_pixels));
2635 if (memory_info == (MemoryInfo *) NULL)
2636 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2637 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2638 if (setjmp(error_manager.error_recovery) != 0)
2640 jpeg_destroy_compress(&jpeg_info);
2641 if (memory_info != (MemoryInfo *) NULL)
2642 memory_info=RelinquishVirtualMemory(memory_info);
2643 (void) CloseBlob(image);
2644 return(MagickFalse);
2646 scanline[0]=(JSAMPROW) jpeg_pixels;
2647 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2650 if (jpeg_info.data_precision <= 8)
2652 if ((jpeg_info.in_color_space == JCS_RGB) ||
2653 (jpeg_info.in_color_space == JCS_YCbCr))
2654 for (y=0; y < (ssize_t) image->rows; y++)
2656 register const Quantum
2662 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2663 if (p == (const Quantum *) NULL)
2666 for (x=0; x < (ssize_t) image->columns; x++)
2668 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2669 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2670 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2671 p+=GetPixelChannels(image);
2673 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2674 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2676 if (status == MagickFalse)
2680 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2681 for (y=0; y < (ssize_t) image->rows; y++)
2683 register const Quantum
2689 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2690 if (p == (const Quantum *) NULL)
2693 for (x=0; x < (ssize_t) image->columns; x++)
2695 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2697 p+=GetPixelChannels(image);
2699 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2700 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2702 if (status == MagickFalse)
2706 for (y=0; y < (ssize_t) image->rows; y++)
2708 register const Quantum
2714 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2715 if (p == (const Quantum *) NULL)
2718 for (x=0; x < (ssize_t) image->columns; x++)
2721 Convert DirectClass packets to contiguous CMYK scanlines.
2723 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2724 GetPixelCyan(image,p))));
2725 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2726 GetPixelMagenta(image,p))));
2727 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2728 GetPixelYellow(image,p))));
2729 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2730 GetPixelBlack(image,p))));
2731 p+=GetPixelChannels(image);
2733 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2734 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2736 if (status == MagickFalse)
2741 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2742 for (y=0; y < (ssize_t) image->rows; y++)
2744 register const Quantum
2750 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2751 if (p == (const Quantum *) NULL)
2754 for (x=0; x < (ssize_t) image->columns; x++)
2756 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2758 p+=GetPixelChannels(image);
2760 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2761 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2763 if (status == MagickFalse)
2767 if ((jpeg_info.in_color_space == JCS_RGB) ||
2768 (jpeg_info.in_color_space == JCS_YCbCr))
2769 for (y=0; y < (ssize_t) image->rows; y++)
2771 register const Quantum
2777 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2778 if (p == (const Quantum *) NULL)
2781 for (x=0; x < (ssize_t) image->columns; x++)
2783 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2784 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2785 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2786 p+=GetPixelChannels(image);
2788 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2789 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2791 if (status == MagickFalse)
2795 for (y=0; y < (ssize_t) image->rows; y++)
2797 register const Quantum
2803 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2804 if (p == (const Quantum *) NULL)
2807 for (x=0; x < (ssize_t) image->columns; x++)
2810 Convert DirectClass packets to contiguous CMYK scanlines.
2812 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2814 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2816 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2818 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2820 p+=GetPixelChannels(image);
2822 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2823 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2825 if (status == MagickFalse)
2828 if (y == (ssize_t) image->rows)
2829 jpeg_finish_compress(&jpeg_info);
2831 Relinquish resources.
2833 jpeg_destroy_compress(&jpeg_info);
2834 memory_info=RelinquishVirtualMemory(memory_info);
2835 (void) CloseBlob(image);