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 if (profile != (StringInfo *) NULL)
1975 ConcatenateStringInfo(xmp_profile,profile);
1976 GetStringInfoDatum(xmp_profile)[28]='\0';
1977 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1979 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1980 jpeg_write_marker(jpeg_info,XML_MARKER,
1981 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1983 xmp_profile=DestroyStringInfo(xmp_profile);
1986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1987 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1988 name=GetNextImageProfile(image);
1990 custom_profile=DestroyStringInfo(custom_profile);
1993 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1998 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1999 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2000 destination=(DestinationManager *) cinfo->dest;
2001 destination->manager.init_destination=InitializeDestination;
2002 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2003 destination->manager.term_destination=TerminateDestination;
2004 destination->image=image;
2007 static char **SamplingFactorToList(const char *text)
2024 if (text == (char *) NULL)
2025 return((char **) NULL);
2027 Convert string to an ASCII list.
2030 for (p=text; *p != '\0'; p++)
2033 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2035 if (textlist == (char **) NULL)
2036 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2038 for (i=0; i < (ssize_t) lines; i++)
2040 for (q=(char *) p; *q != '\0'; q++)
2043 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2044 sizeof(*textlist[i]));
2045 if (textlist[i] == (char *) NULL)
2046 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2047 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2052 textlist[i]=(char *) NULL;
2056 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2057 Image *image,ExceptionInfo *exception)
2072 *volatile jpeg_pixels;
2092 struct jpeg_compress_struct
2095 struct jpeg_error_mgr
2104 assert(image_info != (const ImageInfo *) NULL);
2105 assert(image_info->signature == MagickSignature);
2106 assert(image != (Image *) NULL);
2107 assert(image->signature == MagickSignature);
2108 if (image->debug != MagickFalse)
2109 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2110 assert(exception != (ExceptionInfo *) NULL);
2111 assert(exception->signature == MagickSignature);
2112 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2113 if (status == MagickFalse)
2116 Initialize JPEG parameters.
2118 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2119 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2120 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2121 jpeg_info.client_data=(void *) image;
2122 jpeg_info.err=jpeg_std_error(&jpeg_error);
2123 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2124 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2125 error_manager.exception=exception;
2126 error_manager.image=image;
2127 memory_info=(MemoryInfo *) NULL;
2128 if (setjmp(error_manager.error_recovery) != 0)
2130 jpeg_destroy_compress(&jpeg_info);
2131 (void) CloseBlob(image);
2132 return(MagickFalse);
2134 jpeg_info.client_data=(void *) &error_manager;
2135 jpeg_create_compress(&jpeg_info);
2136 JPEGDestinationManager(&jpeg_info,image);
2137 if ((image->columns != (unsigned int) image->columns) ||
2138 (image->rows != (unsigned int) image->rows))
2139 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2140 jpeg_info.image_width=(unsigned int) image->columns;
2141 jpeg_info.image_height=(unsigned int) image->rows;
2142 jpeg_info.input_components=3;
2143 jpeg_info.data_precision=8;
2144 jpeg_info.in_color_space=JCS_RGB;
2145 switch (image->colorspace)
2147 case CMYKColorspace:
2149 jpeg_info.input_components=4;
2150 jpeg_info.in_color_space=JCS_CMYK;
2153 case YCbCrColorspace:
2154 case Rec601YCbCrColorspace:
2155 case Rec709YCbCrColorspace:
2157 jpeg_info.in_color_space=JCS_YCbCr;
2160 case GRAYColorspace:
2162 if (image_info->type == TrueColorType)
2164 jpeg_info.input_components=1;
2165 jpeg_info.in_color_space=JCS_GRAYSCALE;
2170 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2171 if (image_info->type == TrueColorType)
2173 if (IsImageGray(image,exception) != MagickFalse)
2175 jpeg_info.input_components=1;
2176 jpeg_info.in_color_space=JCS_GRAYSCALE;
2181 jpeg_set_defaults(&jpeg_info);
2182 if (jpeg_info.in_color_space == JCS_CMYK)
2183 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2184 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2185 jpeg_info.data_precision=8;
2187 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2188 jpeg_info.density_unit=(UINT8) 1;
2189 if (image->debug != MagickFalse)
2190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2191 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2192 floor(image->resolution.y+0.5));
2193 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2196 Set image resolution.
2198 jpeg_info.write_JFIF_header=TRUE;
2199 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2200 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2202 Set image resolution units.
2204 jpeg_info.density_unit=(UINT8) 0;
2205 if (image->units == PixelsPerInchResolution)
2206 jpeg_info.density_unit=(UINT8) 1;
2207 if (image->units == PixelsPerCentimeterResolution)
2208 jpeg_info.density_unit=(UINT8) 2;
2210 jpeg_info.dct_method=JDCT_FLOAT;
2211 option=GetImageOption(image_info,"jpeg:dct-method");
2212 if (option != (const char *) NULL)
2218 if (LocaleCompare(option,"default") == 0)
2219 jpeg_info.dct_method=JDCT_DEFAULT;
2225 if (LocaleCompare(option,"fastest") == 0)
2226 jpeg_info.dct_method=JDCT_FASTEST;
2227 if (LocaleCompare(option,"float") == 0)
2228 jpeg_info.dct_method=JDCT_FLOAT;
2234 if (LocaleCompare(option,"ifast") == 0)
2235 jpeg_info.dct_method=JDCT_IFAST;
2236 if (LocaleCompare(option,"islow") == 0)
2237 jpeg_info.dct_method=JDCT_ISLOW;
2241 option=GetImageOption(image_info,"jpeg:optimize-coding");
2242 if (option != (const char *) NULL)
2243 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : FALSE;
2249 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2250 image->rows*sizeof(JSAMPLE);
2251 if (length == (MagickSizeType) ((size_t) length))
2254 Perform optimization only if available memory resources permit it.
2256 status=AcquireMagickResource(MemoryResource,length);
2257 RelinquishMagickResource(MemoryResource,length);
2258 jpeg_info.optimize_coding=status;
2261 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2262 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2263 (image_info->interlace != NoInterlace))
2265 if (image->debug != MagickFalse)
2266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2267 "Interlace: progressive");
2268 jpeg_simple_progression(&jpeg_info);
2271 if (image->debug != MagickFalse)
2272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2273 "Interlace: non-progressive");
2275 if (image->debug != MagickFalse)
2276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2277 "Interlace: nonprogressive");
2280 if ((image_info->compression != LosslessJPEGCompression) &&
2281 (image->quality <= 100))
2283 if (image->quality != UndefinedCompressionQuality)
2284 quality=(int) image->quality;
2285 if (image->debug != MagickFalse)
2286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2287 (double) image->quality);
2291 #if !defined(C_LOSSLESS_SUPPORTED)
2293 if (image->debug != MagickFalse)
2294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2296 if (image->quality < 100)
2297 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2298 "LosslessToLossyJPEGConversion",image->filename);
2305 predictor=image->quality/100; /* range 1-7 */
2306 point_transform=image->quality % 20; /* range 0-15 */
2307 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2308 if (image->debug != MagickFalse)
2310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2311 "Compression: lossless");
2312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2313 "Predictor: %d",predictor);
2314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2315 "Point Transform: %d",point_transform);
2320 option=GetImageOption(image_info,"jpeg:extent");
2321 if (option != (const char *) NULL)
2329 jpeg_info=CloneImageInfo(image_info);
2330 jpeg_info->blob=NULL;
2331 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2332 if (jpeg_image != (Image *) NULL)
2342 Search for compression quality that does not exceed image extent.
2344 jpeg_info->quality=0;
2345 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2346 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2347 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2349 for (minimum=2; minimum < maximum; )
2351 (void) AcquireUniqueFilename(jpeg_image->filename);
2352 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2353 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2354 if (GetBlobSize(jpeg_image) <= extent)
2355 minimum=jpeg_image->quality+1;
2357 maximum=jpeg_image->quality-1;
2358 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2361 jpeg_image=DestroyImage(jpeg_image);
2363 jpeg_info=DestroyImageInfo(jpeg_info);
2365 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2366 #if (JPEG_LIB_VERSION >= 70)
2367 option=GetImageOption(image_info,"quality");
2368 if (option != (const char *) NULL)
2377 Set quality scaling for luminance and chrominance separately.
2379 flags=ParseGeometry(option,&geometry_info);
2380 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2382 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2383 (geometry_info.rho+0.5));
2384 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2385 (geometry_info.sigma+0.5));
2386 jpeg_default_qtables(&jpeg_info,MagickTrue);
2390 colorspace=jpeg_info.in_color_space;
2391 value=GetImageOption(image_info,"jpeg:colorspace");
2392 if (value == (char *) NULL)
2393 value=GetImageProperty(image,"jpeg:colorspace",exception);
2394 if (value != (char *) NULL)
2395 colorspace=StringToInteger(value);
2396 sampling_factor=(const char *) NULL;
2397 if (colorspace == jpeg_info.in_color_space)
2399 value=GetImageOption(image_info,"jpeg:sampling-factor");
2400 if (value == (char *) NULL)
2401 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2402 if (value != (char *) NULL)
2404 sampling_factor=value;
2405 if (image->debug != MagickFalse)
2406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2407 " Input sampling-factors=%s",sampling_factor);
2410 value=GetImageOption(image_info,"jpeg:sampling-factor");
2411 if (image_info->sampling_factor != (char *) NULL)
2412 sampling_factor=image_info->sampling_factor;
2413 if (sampling_factor == (const char *) NULL)
2415 if (image->quality >= 90)
2416 for (i=0; i < MAX_COMPONENTS; i++)
2418 jpeg_info.comp_info[i].h_samp_factor=1;
2419 jpeg_info.comp_info[i].v_samp_factor=1;
2434 Set sampling factor.
2437 factors=SamplingFactorToList(sampling_factor);
2438 if (factors != (char **) NULL)
2440 for (i=0; i < MAX_COMPONENTS; i++)
2442 if (factors[i] == (char *) NULL)
2444 flags=ParseGeometry(factors[i],&geometry_info);
2445 if ((flags & SigmaValue) == 0)
2446 geometry_info.sigma=geometry_info.rho;
2447 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2448 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2449 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2451 factors=(char **) RelinquishMagickMemory(factors);
2453 for ( ; i < MAX_COMPONENTS; i++)
2455 jpeg_info.comp_info[i].h_samp_factor=1;
2456 jpeg_info.comp_info[i].v_samp_factor=1;
2459 option=GetImageOption(image_info,"jpeg:q-table");
2460 if (option != (const char *) NULL)
2466 Custom quantization tables.
2468 table=GetQuantizationTable(option,"0",exception);
2469 if (table != (QuantizationTable *) NULL)
2471 for (i=0; i < MAX_COMPONENTS; i++)
2472 jpeg_info.comp_info[i].quant_tbl_no=0;
2473 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2474 jpeg_quality_scaling(quality),0);
2475 table=DestroyQuantizationTable(table);
2477 table=GetQuantizationTable(option,"1",exception);
2478 if (table != (QuantizationTable *) NULL)
2480 for (i=1; i < MAX_COMPONENTS; i++)
2481 jpeg_info.comp_info[i].quant_tbl_no=1;
2482 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2483 jpeg_quality_scaling(quality),0);
2484 table=DestroyQuantizationTable(table);
2486 table=GetQuantizationTable(option,"2",exception);
2487 if (table != (QuantizationTable *) NULL)
2489 for (i=2; i < MAX_COMPONENTS; i++)
2490 jpeg_info.comp_info[i].quant_tbl_no=2;
2491 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2492 jpeg_quality_scaling(quality),0);
2493 table=DestroyQuantizationTable(table);
2495 table=GetQuantizationTable(option,"3",exception);
2496 if (table != (QuantizationTable *) NULL)
2498 for (i=3; i < MAX_COMPONENTS; i++)
2499 jpeg_info.comp_info[i].quant_tbl_no=3;
2500 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2501 jpeg_quality_scaling(quality),0);
2502 table=DestroyQuantizationTable(table);
2505 jpeg_start_compress(&jpeg_info,MagickTrue);
2506 if (image->debug != MagickFalse)
2508 if (image->storage_class == PseudoClass)
2509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2510 "Storage class: PseudoClass");
2512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2513 "Storage class: DirectClass");
2514 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2515 (double) image->depth);
2516 if (image->colors != 0)
2517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2518 "Number of colors: %.20g",(double) image->colors);
2520 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2521 "Number of colors: unspecified");
2522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2523 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2524 switch (image->colorspace)
2526 case CMYKColorspace:
2528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2529 "Storage class: DirectClass");
2530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2531 "Colorspace: CMYK");
2534 case YCbCrColorspace:
2535 case Rec601YCbCrColorspace:
2536 case Rec709YCbCrColorspace:
2538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2539 "Colorspace: YCbCr");
2545 switch (image->colorspace)
2547 case CMYKColorspace:
2549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2550 "Colorspace: CMYK");
2551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2552 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2553 jpeg_info.comp_info[0].h_samp_factor,
2554 jpeg_info.comp_info[0].v_samp_factor,
2555 jpeg_info.comp_info[1].h_samp_factor,
2556 jpeg_info.comp_info[1].v_samp_factor,
2557 jpeg_info.comp_info[2].h_samp_factor,
2558 jpeg_info.comp_info[2].v_samp_factor,
2559 jpeg_info.comp_info[3].h_samp_factor,
2560 jpeg_info.comp_info[3].v_samp_factor);
2563 case GRAYColorspace:
2565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2566 "Colorspace: GRAY");
2567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2568 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2569 jpeg_info.comp_info[0].v_samp_factor);
2572 case sRGBColorspace:
2575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2576 "Image colorspace is RGB");
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2578 "Sampling factors: %dx%d,%dx%d,%dx%d",
2579 jpeg_info.comp_info[0].h_samp_factor,
2580 jpeg_info.comp_info[0].v_samp_factor,
2581 jpeg_info.comp_info[1].h_samp_factor,
2582 jpeg_info.comp_info[1].v_samp_factor,
2583 jpeg_info.comp_info[2].h_samp_factor,
2584 jpeg_info.comp_info[2].v_samp_factor);
2587 case YCbCrColorspace:
2588 case Rec601YCbCrColorspace:
2589 case Rec709YCbCrColorspace:
2591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2592 "Colorspace: YCbCr");
2593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2594 "Sampling factors: %dx%d,%dx%d,%dx%d",
2595 jpeg_info.comp_info[0].h_samp_factor,
2596 jpeg_info.comp_info[0].v_samp_factor,
2597 jpeg_info.comp_info[1].h_samp_factor,
2598 jpeg_info.comp_info[1].v_samp_factor,
2599 jpeg_info.comp_info[2].h_samp_factor,
2600 jpeg_info.comp_info[2].v_samp_factor);
2605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2608 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2609 jpeg_info.comp_info[0].h_samp_factor,
2610 jpeg_info.comp_info[0].v_samp_factor,
2611 jpeg_info.comp_info[1].h_samp_factor,
2612 jpeg_info.comp_info[1].v_samp_factor,
2613 jpeg_info.comp_info[2].h_samp_factor,
2614 jpeg_info.comp_info[2].v_samp_factor,
2615 jpeg_info.comp_info[3].h_samp_factor,
2616 jpeg_info.comp_info[3].v_samp_factor);
2622 Write JPEG profiles.
2624 value=GetImageProperty(image,"comment",exception);
2625 if (value != (char *) NULL)
2626 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2627 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2628 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2629 if (image->profiles != (void *) NULL)
2630 WriteProfile(&jpeg_info,image);
2632 Convert MIFF to JPEG raster pixels.
2634 memory_info=AcquireVirtualMemory((size_t) image->columns,
2635 jpeg_info.input_components*sizeof(*jpeg_pixels));
2636 if (memory_info == (MemoryInfo *) NULL)
2637 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2638 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2639 if (setjmp(error_manager.error_recovery) != 0)
2641 jpeg_destroy_compress(&jpeg_info);
2642 if (memory_info != (MemoryInfo *) NULL)
2643 memory_info=RelinquishVirtualMemory(memory_info);
2644 (void) CloseBlob(image);
2645 return(MagickFalse);
2647 scanline[0]=(JSAMPROW) jpeg_pixels;
2648 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2651 if (jpeg_info.data_precision <= 8)
2653 if ((jpeg_info.in_color_space == JCS_RGB) ||
2654 (jpeg_info.in_color_space == JCS_YCbCr))
2655 for (y=0; y < (ssize_t) image->rows; y++)
2657 register const Quantum
2663 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2664 if (p == (const Quantum *) NULL)
2667 for (x=0; x < (ssize_t) image->columns; x++)
2669 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2670 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2671 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2672 p+=GetPixelChannels(image);
2674 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2675 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2677 if (status == MagickFalse)
2681 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2682 for (y=0; y < (ssize_t) image->rows; y++)
2684 register const Quantum
2690 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2691 if (p == (const Quantum *) NULL)
2694 for (x=0; x < (ssize_t) image->columns; x++)
2696 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2698 p+=GetPixelChannels(image);
2700 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2701 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2703 if (status == MagickFalse)
2707 for (y=0; y < (ssize_t) image->rows; y++)
2709 register const Quantum
2715 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2716 if (p == (const Quantum *) NULL)
2719 for (x=0; x < (ssize_t) image->columns; x++)
2722 Convert DirectClass packets to contiguous CMYK scanlines.
2724 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2725 GetPixelCyan(image,p))));
2726 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2727 GetPixelMagenta(image,p))));
2728 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2729 GetPixelYellow(image,p))));
2730 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2731 GetPixelBlack(image,p))));
2732 p+=GetPixelChannels(image);
2734 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2735 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2737 if (status == MagickFalse)
2742 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2743 for (y=0; y < (ssize_t) image->rows; y++)
2745 register const Quantum
2751 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2752 if (p == (const Quantum *) NULL)
2755 for (x=0; x < (ssize_t) image->columns; x++)
2757 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2759 p+=GetPixelChannels(image);
2761 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2762 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2764 if (status == MagickFalse)
2768 if ((jpeg_info.in_color_space == JCS_RGB) ||
2769 (jpeg_info.in_color_space == JCS_YCbCr))
2770 for (y=0; y < (ssize_t) image->rows; y++)
2772 register const Quantum
2778 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2779 if (p == (const Quantum *) NULL)
2782 for (x=0; x < (ssize_t) image->columns; x++)
2784 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2785 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2786 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2787 p+=GetPixelChannels(image);
2789 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2790 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2792 if (status == MagickFalse)
2796 for (y=0; y < (ssize_t) image->rows; y++)
2798 register const Quantum
2804 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2805 if (p == (const Quantum *) NULL)
2808 for (x=0; x < (ssize_t) image->columns; x++)
2811 Convert DirectClass packets to contiguous CMYK scanlines.
2813 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2815 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2817 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2819 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2821 p+=GetPixelChannels(image);
2823 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2824 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2826 if (status == MagickFalse)
2829 if (y == (ssize_t) image->rows)
2830 jpeg_finish_compress(&jpeg_info);
2832 Relinquish resources.
2834 jpeg_destroy_compress(&jpeg_info);
2835 memory_info=RelinquishVirtualMemory(memory_info);
2836 (void) CloseBlob(image);