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/option-private.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/splay-tree.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/string_.h"
83 #include "MagickCore/string-private.h"
84 #include "MagickCore/token.h"
85 #include "MagickCore/utility.h"
86 #include "MagickCore/xml-tree.h"
87 #include "MagickCore/xml-tree-private.h"
89 #if defined(MAGICKCORE_JPEG_DELEGATE)
90 #define JPEG_INTERNAL_OPTIONS
91 #if defined(__MINGW32__) || defined(__MINGW64__)
92 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
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
109 Typedef declarations.
111 #if defined(MAGICKCORE_JPEG_DELEGATE)
112 typedef struct _DestinationManager
114 struct jpeg_destination_mgr
122 } DestinationManager;
124 typedef struct _ErrorManager
142 typedef struct _SourceManager
144 struct jpeg_source_mgr
158 typedef struct _QuantizationTable
176 Forward declarations.
178 #if defined(MAGICKCORE_JPEG_DELEGATE)
179 static MagickBooleanType
180 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 % IsJPEG() returns MagickTrue if the image format type, identified by the
195 % magick string, is JPEG.
197 % The format of the IsJPEG method is:
199 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
201 % A description of each parameter follows:
203 % o magick: compare image format pattern against these bytes.
205 % o length: Specifies the length of the magick string.
208 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
212 if (memcmp(magick,"\377\330\377",3) == 0)
217 #if defined(MAGICKCORE_JPEG_DELEGATE)
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % R e a d J P E G I m a g e %
227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
230 % the memory necessary for the new Image structure and returns a pointer to
233 % The format of the ReadJPEGImage method is:
235 % Image *ReadJPEGImage(const ImageInfo *image_info,
236 % ExceptionInfo *exception)
238 % A description of each parameter follows:
240 % o image_info: the image info.
242 % o exception: return any errors or warnings in this structure.
246 static boolean FillInputBuffer(j_decompress_ptr cinfo)
251 source=(SourceManager *) cinfo->src;
252 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
253 MaxBufferExtent,source->buffer);
254 if (source->manager.bytes_in_buffer == 0)
256 if (source->start_of_blob != FALSE)
257 ERREXIT(cinfo,JERR_INPUT_EMPTY);
258 WARNMS(cinfo,JWRN_JPEG_EOF);
259 source->buffer[0]=(JOCTET) 0xff;
260 source->buffer[1]=(JOCTET) JPEG_EOI;
261 source->manager.bytes_in_buffer=2;
263 source->manager.next_input_byte=source->buffer;
264 source->start_of_blob=FALSE;
268 static int GetCharacter(j_decompress_ptr jpeg_info)
270 if (jpeg_info->src->bytes_in_buffer == 0)
271 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
272 jpeg_info->src->bytes_in_buffer--;
273 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
276 static void InitializeSource(j_decompress_ptr cinfo)
281 source=(SourceManager *) cinfo->src;
282 source->start_of_blob=TRUE;
285 static MagickBooleanType IsITUFaxImage(const Image *image)
293 profile=GetImageProfile(image,"8bim");
294 if (profile == (const StringInfo *) NULL)
296 if (GetStringInfoLength(profile) < 5)
298 datum=GetStringInfoDatum(profile);
299 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
300 (datum[3] == 0x41) && (datum[4] == 0x58))
305 static void JPEGErrorHandler(j_common_ptr jpeg_info)
308 message[JMSG_LENGTH_MAX];
320 error_manager=(ErrorManager *) jpeg_info->client_data;
321 image=error_manager->image;
322 exception=error_manager->exception;
323 (jpeg_info->err->format_message)(jpeg_info,message);
324 if (image->debug != MagickFalse)
325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
326 "[%s] JPEG Trace: \"%s\"",image->filename,message);
327 if (error_manager->finished != MagickFalse)
328 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
329 (char *) message,"`%s'",image->filename);
331 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
332 (char *) message,"`%s'",image->filename);
333 longjmp(error_manager->error_recovery,1);
336 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
338 #define JPEGExcessiveWarnings 1000
341 message[JMSG_LENGTH_MAX];
353 error_manager=(ErrorManager *) jpeg_info->client_data;
354 exception=error_manager->exception;
355 image=error_manager->image;
359 Process warning message.
361 (jpeg_info->err->format_message)(jpeg_info,message);
362 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
363 JPEGErrorHandler(jpeg_info);
364 ThrowBinaryException(CorruptImageWarning,(char *) message,
368 if ((image->debug != MagickFalse) &&
369 (level >= jpeg_info->err->trace_level))
372 Process trace message.
374 (jpeg_info->err->format_message)(jpeg_info,message);
375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
376 "[%s] JPEG Trace: \"%s\"",image->filename,message);
381 static boolean ReadComment(j_decompress_ptr jpeg_info)
392 register unsigned char
405 Determine length of comment.
407 error_manager=(ErrorManager *) jpeg_info->client_data;
408 exception=error_manager->exception;
409 image=error_manager->image;
410 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
411 length+=GetCharacter(jpeg_info);
415 comment=BlobToStringInfo((const void *) NULL,length);
416 if (comment == (StringInfo *) NULL)
418 (void) ThrowMagickException(exception,GetMagickModule(),
419 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
425 error_manager->profile=comment;
426 p=GetStringInfoDatum(comment);
427 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
428 *p++=(unsigned char) GetCharacter(jpeg_info);
430 error_manager->profile=NULL;
431 p=GetStringInfoDatum(comment);
432 (void) SetImageProperty(image,"comment",(const char *) p,exception);
433 comment=DestroyStringInfo(comment);
437 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
457 register unsigned char
470 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
471 length+=(size_t) GetCharacter(jpeg_info);
476 (void) GetCharacter(jpeg_info);
479 for (i=0; i < 12; i++)
480 magick[i]=(char) GetCharacter(jpeg_info);
481 if (LocaleCompare(magick,ICC_PROFILE) != 0)
484 Not a ICC profile, return.
486 for (i=0; i < (ssize_t) (length-12); i++)
487 (void) GetCharacter(jpeg_info);
490 (void) GetCharacter(jpeg_info); /* id */
491 (void) GetCharacter(jpeg_info); /* markers */
493 error_manager=(ErrorManager *) jpeg_info->client_data;
494 exception=error_manager->exception;
495 image=error_manager->image;
496 profile=BlobToStringInfo((const void *) NULL,length);
497 if (profile == (StringInfo *) NULL)
499 (void) ThrowMagickException(exception,GetMagickModule(),
500 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
503 error_manager->profile=profile;
504 p=GetStringInfoDatum(profile);
505 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
506 *p++=(unsigned char) GetCharacter(jpeg_info);
507 error_manager->profile=NULL;
508 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
509 if (icc_profile != (StringInfo *) NULL)
511 ConcatenateStringInfo(icc_profile,profile);
512 profile=DestroyStringInfo(profile);
516 status=SetImageProfile(image,"icc",profile,exception);
517 profile=DestroyStringInfo(profile);
518 if (status == MagickFalse)
520 (void) ThrowMagickException(exception,GetMagickModule(),
521 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
525 if (image->debug != MagickFalse)
526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
527 "Profile: ICC, %.20g bytes",(double) length);
531 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
534 magick[MagickPathExtent];
551 register unsigned char
562 Determine length of binary data stored here.
564 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
565 length+=(size_t) GetCharacter(jpeg_info);
570 (void) GetCharacter(jpeg_info);
574 Validate that this was written as a Photoshop resource format slug.
576 for (i=0; i < 10; i++)
577 magick[i]=(char) GetCharacter(jpeg_info);
582 if (LocaleCompare(magick,"Photoshop ") != 0)
585 Not a IPTC profile, return.
587 for (i=0; i < (ssize_t) length; i++)
588 (void) GetCharacter(jpeg_info);
592 Remove the version number.
594 for (i=0; i < 4; i++)
595 (void) GetCharacter(jpeg_info);
599 error_manager=(ErrorManager *) jpeg_info->client_data;
600 exception=error_manager->exception;
601 image=error_manager->image;
602 profile=BlobToStringInfo((const void *) NULL,length);
603 if (profile == (StringInfo *) NULL)
605 (void) ThrowMagickException(exception,GetMagickModule(),
606 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
609 error_manager->profile=profile;
610 p=GetStringInfoDatum(profile);
611 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
612 *p++=(unsigned char) GetCharacter(jpeg_info);
613 error_manager->profile=NULL;
614 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
615 if (iptc_profile != (StringInfo *) NULL)
617 ConcatenateStringInfo(iptc_profile,profile);
618 profile=DestroyStringInfo(profile);
622 status=SetImageProfile(image,"8bim",profile,exception);
623 profile=DestroyStringInfo(profile);
624 if (status == MagickFalse)
626 (void) ThrowMagickException(exception,GetMagickModule(),
627 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
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)
640 name[MagickPathExtent];
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,MagickPathExtent,"APP%d",marker);
682 error_manager=(ErrorManager *) jpeg_info->client_data;
683 exception=error_manager->exception;
684 image=error_manager->image;
685 profile=BlobToStringInfo((const void *) NULL,length);
686 if (profile == (StringInfo *) NULL)
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",MagickPathExtent);
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",MagickPathExtent);
722 previous_profile=GetImageProfile(image,name);
723 if (previous_profile != (const StringInfo *) NULL)
728 profile_length=GetStringInfoLength(profile);
729 SetStringInfoLength(profile,GetStringInfoLength(profile)+
730 GetStringInfoLength(previous_profile));
731 (void) memmove(GetStringInfoDatum(profile)+
732 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
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,
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[MagickPathExtent];
935 switch (jpeg_info->out_color_space)
939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
940 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
941 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
942 jpeg_info->comp_info[0].v_samp_factor,
943 jpeg_info->comp_info[1].h_samp_factor,
944 jpeg_info->comp_info[1].v_samp_factor,
945 jpeg_info->comp_info[2].h_samp_factor,
946 jpeg_info->comp_info[2].v_samp_factor,
947 jpeg_info->comp_info[3].h_samp_factor,
948 jpeg_info->comp_info[3].v_samp_factor);
953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
954 "Colorspace: GRAYSCALE");
955 (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d",
956 jpeg_info->comp_info[0].h_samp_factor,
957 jpeg_info->comp_info[0].v_samp_factor);
962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
963 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
964 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
965 jpeg_info->comp_info[0].v_samp_factor,
966 jpeg_info->comp_info[1].h_samp_factor,
967 jpeg_info->comp_info[1].v_samp_factor,
968 jpeg_info->comp_info[2].h_samp_factor,
969 jpeg_info->comp_info[2].v_samp_factor);
974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
975 jpeg_info->out_color_space);
976 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
977 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
978 jpeg_info->comp_info[0].v_samp_factor,
979 jpeg_info->comp_info[1].h_samp_factor,
980 jpeg_info->comp_info[1].v_samp_factor,
981 jpeg_info->comp_info[2].h_samp_factor,
982 jpeg_info->comp_info[2].v_samp_factor,
983 jpeg_info->comp_info[3].h_samp_factor,
984 jpeg_info->comp_info[3].v_samp_factor);
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[MagickPathExtent];
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 == MagickCoreSignature);
1051 if (image_info->debug != MagickFalse)
1052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1053 image_info->filename);
1054 assert(exception != (ExceptionInfo *) NULL);
1055 assert(exception->signature == MagickCoreSignature);
1056 debug=IsEventLogging();
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 option=GetImageOption(image_info,"profile:skip");
1093 if (IsOptionMember("ICC",option) == MagickFalse)
1094 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1095 if (IsOptionMember("IPTC",option) == MagickFalse)
1096 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1097 for (i=1; i < 16; i++)
1098 if ((i != 2) && (i != 13) && (i != 14))
1099 if (IsOptionMember("APP",option) == MagickFalse)
1100 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1101 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1102 if ((image_info->colorspace == YCbCrColorspace) ||
1103 (image_info->colorspace == Rec601YCbCrColorspace) ||
1104 (image_info->colorspace == Rec709YCbCrColorspace))
1105 jpeg_info.out_color_space=JCS_YCbCr;
1107 Set image resolution.
1110 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1111 (jpeg_info.Y_density != 1))
1113 image->resolution.x=(double) jpeg_info.X_density;
1114 image->resolution.y=(double) jpeg_info.Y_density;
1115 units=(size_t) jpeg_info.density_unit;
1118 image->units=PixelsPerInchResolution;
1120 image->units=PixelsPerCentimeterResolution;
1121 number_pixels=(MagickSizeType) image->columns*image->rows;
1122 option=GetImageOption(image_info,"jpeg:size");
1123 if ((option != (const char *) NULL) &&
1124 (jpeg_info.out_color_space != JCS_YCbCr))
1138 flags=ParseGeometry(option,&geometry_info);
1139 if ((flags & SigmaValue) == 0)
1140 geometry_info.sigma=geometry_info.rho;
1141 jpeg_calc_output_dimensions(&jpeg_info);
1142 image->magick_columns=jpeg_info.output_width;
1143 image->magick_rows=jpeg_info.output_height;
1145 if (geometry_info.rho != 0.0)
1146 scale_factor=jpeg_info.output_width/geometry_info.rho;
1147 if ((geometry_info.sigma != 0.0) &&
1148 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1149 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1150 jpeg_info.scale_num=1U;
1151 jpeg_info.scale_denom=(unsigned int) scale_factor;
1152 jpeg_calc_output_dimensions(&jpeg_info);
1153 if (image->debug != MagickFalse)
1154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1155 "Scale factor: %.20g",(double) scale_factor);
1157 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1158 #if defined(D_LOSSLESS_SUPPORTED)
1159 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1160 JPEGInterlace : NoInterlace;
1161 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1162 LosslessJPEGCompression : JPEGCompression;
1163 if (jpeg_info.data_precision > 8)
1164 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1165 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1167 if (jpeg_info.data_precision == 16)
1168 jpeg_info.data_precision=12;
1170 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1172 image->compression=JPEGCompression;
1175 image->compression=JPEGCompression;
1176 image->interlace=JPEGInterlace;
1178 option=GetImageOption(image_info,"jpeg:colors");
1179 if (option != (const char *) NULL)
1182 Let the JPEG library quantize the image.
1184 jpeg_info.quantize_colors=TRUE;
1185 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1187 option=GetImageOption(image_info,"jpeg:block-smoothing");
1188 if (option != (const char *) NULL)
1189 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1191 jpeg_info.dct_method=JDCT_FLOAT;
1192 option=GetImageOption(image_info,"jpeg:dct-method");
1193 if (option != (const char *) NULL)
1199 if (LocaleCompare(option,"default") == 0)
1200 jpeg_info.dct_method=JDCT_DEFAULT;
1206 if (LocaleCompare(option,"fastest") == 0)
1207 jpeg_info.dct_method=JDCT_FASTEST;
1208 if (LocaleCompare(option,"float") == 0)
1209 jpeg_info.dct_method=JDCT_FLOAT;
1215 if (LocaleCompare(option,"ifast") == 0)
1216 jpeg_info.dct_method=JDCT_IFAST;
1217 if (LocaleCompare(option,"islow") == 0)
1218 jpeg_info.dct_method=JDCT_ISLOW;
1222 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1223 if (option != (const char *) NULL)
1224 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1226 (void) jpeg_start_decompress(&jpeg_info);
1227 image->columns=jpeg_info.output_width;
1228 image->rows=jpeg_info.output_height;
1229 image->depth=(size_t) jpeg_info.data_precision;
1230 switch (jpeg_info.out_color_space)
1235 (void) SetImageColorspace(image,sRGBColorspace,exception);
1240 (void) SetImageColorspace(image,GRAYColorspace,exception);
1245 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1250 (void) SetImageColorspace(image,CMYKColorspace,exception);
1254 if (IsITUFaxImage(image) != MagickFalse)
1256 (void) SetImageColorspace(image,LabColorspace,exception);
1257 jpeg_info.out_color_space=JCS_YCbCr;
1259 option=GetImageOption(image_info,"jpeg:colors");
1260 if (option != (const char *) NULL)
1261 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1263 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1264 if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0))
1269 colors=(size_t) GetQuantumRange(image->depth)+1;
1270 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1271 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1273 if (image->debug != MagickFalse)
1275 if (image->interlace != NoInterlace)
1276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1277 "Interlace: progressive");
1279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1280 "Interlace: nonprogressive");
1281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1282 (int) jpeg_info.data_precision);
1283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1284 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1286 JPEGSetImageQuality(&jpeg_info,image);
1287 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1288 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
1289 jpeg_info.out_color_space);
1290 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1291 if (image_info->ping != MagickFalse)
1293 jpeg_destroy_decompress(&jpeg_info);
1294 (void) CloseBlob(image);
1295 return(GetFirstImageInList(image));
1297 status=SetImageExtent(image,image->columns,image->rows,exception);
1298 if (status == MagickFalse)
1300 jpeg_destroy_decompress(&jpeg_info);
1301 return(DestroyImageList(image));
1303 if ((jpeg_info.output_components != 1) &&
1304 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1306 jpeg_destroy_decompress(&jpeg_info);
1307 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1309 memory_info=AcquireVirtualMemory((size_t) image->columns,
1310 jpeg_info.output_components*sizeof(*jpeg_pixels));
1311 if (memory_info == (MemoryInfo *) NULL)
1313 jpeg_destroy_decompress(&jpeg_info);
1314 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1316 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1318 Convert JPEG pixels to pixel packets.
1320 if (setjmp(error_manager.error_recovery) != 0)
1322 if (memory_info != (MemoryInfo *) NULL)
1323 memory_info=RelinquishVirtualMemory(memory_info);
1324 jpeg_destroy_decompress(&jpeg_info);
1325 (void) CloseBlob(image);
1326 number_pixels=(MagickSizeType) image->columns*image->rows;
1327 if (number_pixels != 0)
1328 return(GetFirstImageInList(image));
1329 return(DestroyImage(image));
1331 if (jpeg_info.quantize_colors != 0)
1333 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1334 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1335 for (i=0; i < (ssize_t) image->colors; i++)
1337 image->colormap[i].red=(double) ScaleCharToQuantum(
1338 jpeg_info.colormap[0][i]);
1339 image->colormap[i].green=image->colormap[i].red;
1340 image->colormap[i].blue=image->colormap[i].red;
1341 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1344 for (i=0; i < (ssize_t) image->colors; i++)
1346 image->colormap[i].red=(double) ScaleCharToQuantum(
1347 jpeg_info.colormap[0][i]);
1348 image->colormap[i].green=(double) ScaleCharToQuantum(
1349 jpeg_info.colormap[1][i]);
1350 image->colormap[i].blue=(double) ScaleCharToQuantum(
1351 jpeg_info.colormap[2][i]);
1352 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1355 scanline[0]=(JSAMPROW) jpeg_pixels;
1356 for (y=0; y < (ssize_t) image->rows; y++)
1364 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1366 (void) ThrowMagickException(exception,GetMagickModule(),
1367 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1371 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1372 if (q == (Quantum *) NULL)
1374 if (jpeg_info.data_precision > 8)
1379 scale=65535/(unsigned short) GetQuantumRange((size_t)
1380 jpeg_info.data_precision);
1381 if (jpeg_info.output_components == 1)
1382 for (x=0; x < (ssize_t) image->columns; x++)
1387 pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1388 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1389 SetPixelIndex(image,index,q);
1390 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1392 q+=GetPixelChannels(image);
1395 if (image->colorspace != CMYKColorspace)
1396 for (x=0; x < (ssize_t) image->columns; x++)
1398 SetPixelRed(image,ScaleShortToQuantum(
1399 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1400 SetPixelGreen(image,ScaleShortToQuantum(
1401 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1402 SetPixelBlue(image,ScaleShortToQuantum(
1403 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1404 SetPixelAlpha(image,OpaqueAlpha,q);
1405 q+=GetPixelChannels(image);
1408 for (x=0; x < (ssize_t) image->columns; x++)
1410 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1411 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1412 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1413 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1414 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1415 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1416 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1417 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1418 SetPixelAlpha(image,OpaqueAlpha,q);
1419 q+=GetPixelChannels(image);
1423 if (jpeg_info.output_components == 1)
1424 for (x=0; x < (ssize_t) image->columns; x++)
1426 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) GETJSAMPLE(*p),
1428 SetPixelIndex(image,index,q);
1429 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1431 q+=GetPixelChannels(image);
1434 if (image->colorspace != CMYKColorspace)
1435 for (x=0; x < (ssize_t) image->columns; x++)
1437 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1438 GETJSAMPLE(*p++)),q);
1439 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1440 GETJSAMPLE(*p++)),q);
1441 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1442 GETJSAMPLE(*p++)),q);
1443 SetPixelAlpha(image,OpaqueAlpha,q);
1444 q+=GetPixelChannels(image);
1447 for (x=0; x < (ssize_t) image->columns; x++)
1449 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1450 (unsigned char) GETJSAMPLE(*p++)),q);
1451 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1452 (unsigned char) GETJSAMPLE(*p++)),q);
1453 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1454 (unsigned char) GETJSAMPLE(*p++)),q);
1455 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1456 (unsigned char) GETJSAMPLE(*p++)),q);
1457 SetPixelAlpha(image,OpaqueAlpha,q);
1458 q+=GetPixelChannels(image);
1460 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1462 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1464 if (status == MagickFalse)
1466 jpeg_abort_decompress(&jpeg_info);
1470 if (status != MagickFalse)
1472 error_manager.finished=MagickTrue;
1473 if (setjmp(error_manager.error_recovery) == 0)
1474 (void) jpeg_finish_decompress(&jpeg_info);
1477 Free jpeg resources.
1479 jpeg_destroy_decompress(&jpeg_info);
1480 memory_info=RelinquishVirtualMemory(memory_info);
1481 (void) CloseBlob(image);
1482 return(GetFirstImageInList(image));
1487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1491 % R e g i s t e r J P E G I m a g e %
1495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1497 % RegisterJPEGImage() adds properties for the JPEG image format to
1498 % the list of supported formats. The properties include the image format
1499 % tag, a method to read and/or write the format, whether the format
1500 % supports the saving of more than one frame to the same file or blob,
1501 % whether the format supports native in-memory I/O, and a brief
1502 % description of the format.
1504 % The format of the RegisterJPEGImage method is:
1506 % size_t RegisterJPEGImage(void)
1509 ModuleExport size_t RegisterJPEGImage(void)
1511 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1514 version[MagickPathExtent];
1520 #if defined(JPEG_LIB_VERSION)
1521 (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION);
1523 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1524 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1525 entry->flags^=CoderDecoderThreadSupportFlag;
1527 #if defined(MAGICKCORE_JPEG_DELEGATE)
1528 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1529 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1531 entry->magick=(IsImageFormatHandler *) IsJPEG;
1532 entry->flags^=CoderAdjoinFlag;
1533 entry->flags^=CoderUseExtensionFlag;
1534 if (*version != '\0')
1535 entry->version=ConstantString(version);
1536 entry->mime_type=ConstantString("image/jpeg");
1537 (void) RegisterMagickInfo(entry);
1538 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1539 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1540 entry->flags^=CoderDecoderThreadSupportFlag;
1542 #if defined(MAGICKCORE_JPEG_DELEGATE)
1543 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1544 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1546 entry->magick=(IsImageFormatHandler *) IsJPEG;
1547 entry->flags^=CoderAdjoinFlag;
1548 if (*version != '\0')
1549 entry->version=ConstantString(version);
1550 entry->mime_type=ConstantString("image/jpeg");
1551 (void) RegisterMagickInfo(entry);
1552 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1553 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1554 entry->flags^=CoderDecoderThreadSupportFlag;
1556 #if defined(MAGICKCORE_JPEG_DELEGATE)
1557 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1558 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1560 entry->flags^=CoderAdjoinFlag;
1561 entry->flags^=CoderUseExtensionFlag;
1562 if (*version != '\0')
1563 entry->version=ConstantString(version);
1564 entry->mime_type=ConstantString("image/jpeg");
1565 (void) RegisterMagickInfo(entry);
1566 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1567 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1568 entry->flags^=CoderDecoderThreadSupportFlag;
1570 #if defined(MAGICKCORE_JPEG_DELEGATE)
1571 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1572 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1574 entry->flags^=CoderAdjoinFlag;
1575 entry->flags^=CoderUseExtensionFlag;
1576 if (*version != '\0')
1577 entry->version=ConstantString(version);
1578 entry->mime_type=ConstantString("image/jpeg");
1579 (void) RegisterMagickInfo(entry);
1580 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1581 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1582 entry->flags^=CoderDecoderThreadSupportFlag;
1584 #if defined(MAGICKCORE_JPEG_DELEGATE)
1585 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1586 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1588 entry->flags^=CoderAdjoinFlag;
1589 entry->flags^=CoderUseExtensionFlag;
1590 if (*version != '\0')
1591 entry->version=ConstantString(version);
1592 entry->mime_type=ConstantString("image/jpeg");
1593 (void) RegisterMagickInfo(entry);
1594 return(MagickImageCoderSignature);
1598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % U n r e g i s t e r J P E G I m a g e %
1606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608 % UnregisterJPEGImage() removes format registrations made by the
1609 % JPEG module from the list of supported formats.
1611 % The format of the UnregisterJPEGImage method is:
1613 % UnregisterJPEGImage(void)
1616 ModuleExport void UnregisterJPEGImage(void)
1618 (void) UnregisterMagickInfo("PJPG");
1619 (void) UnregisterMagickInfo("JPS");
1620 (void) UnregisterMagickInfo("JPG");
1621 (void) UnregisterMagickInfo("JPEG");
1622 (void) UnregisterMagickInfo("JPE");
1625 #if defined(MAGICKCORE_JPEG_DELEGATE)
1627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 % W r i t e J P E G I m a g e %
1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637 % WriteJPEGImage() writes a JPEG image file and returns it. It
1638 % allocates the memory necessary for the new Image structure and returns a
1639 % pointer to the new image.
1641 % The format of the WriteJPEGImage method is:
1643 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1644 % Image *image,ExceptionInfo *exception)
1646 % A description of each parameter follows:
1648 % o image_info: the image info.
1650 % o jpeg_image: The image.
1652 % o exception: return any errors or warnings in this structure.
1656 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1658 assert(table != (QuantizationTable *) NULL);
1659 if (table->slot != (char *) NULL)
1660 table->slot=DestroyString(table->slot);
1661 if (table->description != (char *) NULL)
1662 table->description=DestroyString(table->description);
1663 if (table->levels != (unsigned int *) NULL)
1664 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1665 table=(QuantizationTable *) RelinquishMagickMemory(table);
1669 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1674 destination=(DestinationManager *) cinfo->dest;
1675 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1676 MaxBufferExtent,destination->buffer);
1677 if (destination->manager.free_in_buffer != MaxBufferExtent)
1678 ERREXIT(cinfo,JERR_FILE_WRITE);
1679 destination->manager.next_output_byte=destination->buffer;
1683 static QuantizationTable *GetQuantizationTable(const char *filename,
1684 const char *slot,ExceptionInfo *exception)
1712 *quantization_tables,
1715 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1716 "Loading quantization tables \"%s\" ...",filename);
1717 table=(QuantizationTable *) NULL;
1718 xml=FileToString(filename,~0UL,exception);
1719 if (xml == (char *) NULL)
1721 quantization_tables=NewXMLTree(xml,exception);
1722 if (quantization_tables == (XMLTreeInfo *) NULL)
1724 xml=DestroyString(xml);
1727 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1728 table_iterator != (XMLTreeInfo *) NULL;
1729 table_iterator=GetNextXMLTreeTag(table_iterator))
1731 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1732 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1734 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1735 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1738 if (table_iterator == (XMLTreeInfo *) NULL)
1740 xml=DestroyString(xml);
1743 description=GetXMLTreeChild(table_iterator,"description");
1744 if (description == (XMLTreeInfo *) NULL)
1746 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1747 "XmlMissingElement","<description>, slot \"%s\"",slot);
1748 quantization_tables=DestroyXMLTree(quantization_tables);
1749 xml=DestroyString(xml);
1752 levels=GetXMLTreeChild(table_iterator,"levels");
1753 if (levels == (XMLTreeInfo *) NULL)
1755 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1756 "XmlMissingElement","<levels>, slot \"%s\"",slot);
1757 quantization_tables=DestroyXMLTree(quantization_tables);
1758 xml=DestroyString(xml);
1761 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1762 if (table == (QuantizationTable *) NULL)
1763 ThrowFatalException(ResourceLimitFatalError,
1764 "UnableToAcquireQuantizationTable");
1765 table->slot=(char *) NULL;
1766 table->description=(char *) NULL;
1767 table->levels=(unsigned int *) NULL;
1768 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1769 if (attribute != (char *) NULL)
1770 table->slot=ConstantString(attribute);
1771 content=GetXMLTreeContent(description);
1772 if (content != (char *) NULL)
1773 table->description=ConstantString(content);
1774 attribute=GetXMLTreeAttribute(levels,"width");
1775 if (attribute == (char *) NULL)
1777 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1778 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1779 quantization_tables=DestroyXMLTree(quantization_tables);
1780 table=DestroyQuantizationTable(table);
1781 xml=DestroyString(xml);
1784 table->width=StringToUnsignedLong(attribute);
1785 if (table->width == 0)
1787 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1788 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1789 quantization_tables=DestroyXMLTree(quantization_tables);
1790 table=DestroyQuantizationTable(table);
1791 xml=DestroyString(xml);
1794 attribute=GetXMLTreeAttribute(levels,"height");
1795 if (attribute == (char *) NULL)
1797 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1798 "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1799 quantization_tables=DestroyXMLTree(quantization_tables);
1800 table=DestroyQuantizationTable(table);
1801 xml=DestroyString(xml);
1804 table->height=StringToUnsignedLong(attribute);
1805 if (table->height == 0)
1807 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1808 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1809 quantization_tables=DestroyXMLTree(quantization_tables);
1810 table=DestroyQuantizationTable(table);
1811 xml=DestroyString(xml);
1814 attribute=GetXMLTreeAttribute(levels,"divisor");
1815 if (attribute == (char *) NULL)
1817 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1818 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1819 quantization_tables=DestroyXMLTree(quantization_tables);
1820 table=DestroyQuantizationTable(table);
1821 xml=DestroyString(xml);
1824 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1825 if (table->divisor == 0.0)
1827 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1828 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1829 quantization_tables=DestroyXMLTree(quantization_tables);
1830 table=DestroyQuantizationTable(table);
1831 xml=DestroyString(xml);
1834 content=GetXMLTreeContent(levels);
1835 if (content == (char *) NULL)
1837 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1838 "XmlMissingContent","<levels>, table \"%s\"",slot);
1839 quantization_tables=DestroyXMLTree(quantization_tables);
1840 table=DestroyQuantizationTable(table);
1841 xml=DestroyString(xml);
1844 length=(size_t) table->width*table->height;
1847 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1848 sizeof(*table->levels));
1849 if (table->levels == (unsigned int *) NULL)
1850 ThrowFatalException(ResourceLimitFatalError,
1851 "UnableToAcquireQuantizationTable");
1852 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1854 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1855 table->divisor+0.5);
1856 while (isspace((int) ((unsigned char) *p)) != 0)
1862 value=InterpretLocaleValue(content,&p);
1866 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1867 "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1868 quantization_tables=DestroyXMLTree(quantization_tables);
1869 table=DestroyQuantizationTable(table);
1870 xml=DestroyString(xml);
1873 for (j=i; j < 64; j++)
1874 table->levels[j]=table->levels[j-1];
1875 quantization_tables=DestroyXMLTree(quantization_tables);
1876 xml=DestroyString(xml);
1880 static void InitializeDestination(j_compress_ptr cinfo)
1885 destination=(DestinationManager *) cinfo->dest;
1886 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1887 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1888 destination->manager.next_output_byte=destination->buffer;
1889 destination->manager.free_in_buffer=MaxBufferExtent;
1892 static void TerminateDestination(j_compress_ptr cinfo)
1897 destination=(DestinationManager *) cinfo->dest;
1898 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1903 count=WriteBlob(destination->image,MaxBufferExtent-
1904 destination->manager.free_in_buffer,destination->buffer);
1905 if (count != (ssize_t)
1906 (MaxBufferExtent-destination->manager.free_in_buffer))
1907 ERREXIT(cinfo,JERR_FILE_WRITE);
1911 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1912 ExceptionInfo *exception)
1934 Save image profile as a APP marker.
1937 custom_profile=AcquireStringInfo(65535L);
1938 ResetImageProfileIterator(image);
1939 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1941 profile=GetImageProfile(image,name);
1942 if (LocaleCompare(name,"EXIF") == 0)
1944 length=GetStringInfoLength(profile);
1945 if (length > 65533L)
1947 (void) ThrowMagickException(exception,GetMagickModule(),
1948 CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
1952 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
1953 (unsigned int) length);
1955 if (LocaleCompare(name,"ICC") == 0)
1957 register unsigned char
1960 tag_length=strlen(ICC_PROFILE);
1961 p=GetStringInfoDatum(custom_profile);
1962 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1964 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1966 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1967 p[12]=(unsigned char) ((i/65519L)+1);
1968 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1969 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1971 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1972 custom_profile),(unsigned int) (length+tag_length+3));
1975 if (((LocaleCompare(name,"IPTC") == 0) ||
1976 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1978 register unsigned char
1985 p=GetStringInfoDatum(custom_profile);
1986 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1988 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1989 roundup=(size_t) (length & 0x01);
1990 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1992 (void) memcpy(p,"Photoshop 3.0 ",14);
1997 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1999 p[24]=(unsigned char) (length >> 8);
2000 p[25]=(unsigned char) (length & 0xff);
2003 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2005 p[length+tag_length]='\0';
2006 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2007 custom_profile),(unsigned int) (length+tag_length+roundup));
2010 if (LocaleCompare(name,"XMP") == 0)
2016 Add namespace to XMP profile.
2018 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2019 if (xmp_profile != (StringInfo *) NULL)
2021 if (profile != (StringInfo *) NULL)
2022 ConcatenateStringInfo(xmp_profile,profile);
2023 GetStringInfoDatum(xmp_profile)[28]='\0';
2024 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2026 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2027 jpeg_write_marker(jpeg_info,XML_MARKER,
2028 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2030 xmp_profile=DestroyStringInfo(xmp_profile);
2033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2034 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2035 name=GetNextImageProfile(image);
2037 custom_profile=DestroyStringInfo(custom_profile);
2040 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2045 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2046 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2047 destination=(DestinationManager *) cinfo->dest;
2048 destination->manager.init_destination=InitializeDestination;
2049 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2050 destination->manager.term_destination=TerminateDestination;
2051 destination->image=image;
2054 static char **SamplingFactorToList(const char *text)
2068 if (text == (char *) NULL)
2069 return((char **) NULL);
2071 Convert string to an ASCII list.
2073 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2075 if (textlist == (char **) NULL)
2076 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2078 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2080 for (q=(char *) p; *q != '\0'; q++)
2083 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2084 sizeof(*textlist[i]));
2085 if (textlist[i] == (char *) NULL)
2086 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2087 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2094 for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2095 textlist[i]=ConstantString("1x1");
2099 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2100 Image *image,ExceptionInfo *exception)
2111 *volatile volatile_image;
2118 *volatile jpeg_pixels;
2138 struct jpeg_compress_struct
2141 struct jpeg_error_mgr
2150 assert(image_info != (const ImageInfo *) NULL);
2151 assert(image_info->signature == MagickCoreSignature);
2152 assert(image != (Image *) NULL);
2153 assert(image->signature == MagickCoreSignature);
2154 if (image->debug != MagickFalse)
2155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2156 assert(exception != (ExceptionInfo *) NULL);
2157 assert(exception->signature == MagickCoreSignature);
2158 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2159 (image->next != (Image *) NULL))
2160 image=AppendImages(image,MagickFalse,exception);
2161 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2162 if (status == MagickFalse)
2165 Initialize JPEG parameters.
2167 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2168 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2169 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2170 volatile_image=image;
2171 jpeg_info.client_data=(void *) volatile_image;
2172 jpeg_info.err=jpeg_std_error(&jpeg_error);
2173 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2174 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2175 error_manager.exception=exception;
2176 error_manager.image=volatile_image;
2177 memory_info=(MemoryInfo *) NULL;
2178 if (setjmp(error_manager.error_recovery) != 0)
2180 jpeg_destroy_compress(&jpeg_info);
2181 (void) CloseBlob(volatile_image);
2182 return(MagickFalse);
2184 jpeg_info.client_data=(void *) &error_manager;
2185 jpeg_create_compress(&jpeg_info);
2186 JPEGDestinationManager(&jpeg_info,image);
2187 if ((image->columns != (unsigned int) image->columns) ||
2188 (image->rows != (unsigned int) image->rows))
2189 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2190 jpeg_info.image_width=(unsigned int) image->columns;
2191 jpeg_info.image_height=(unsigned int) image->rows;
2192 jpeg_info.input_components=3;
2193 jpeg_info.data_precision=8;
2194 jpeg_info.in_color_space=JCS_RGB;
2195 switch (image->colorspace)
2197 case CMYKColorspace:
2199 jpeg_info.input_components=4;
2200 jpeg_info.in_color_space=JCS_CMYK;
2203 case YCbCrColorspace:
2204 case Rec601YCbCrColorspace:
2205 case Rec709YCbCrColorspace:
2207 jpeg_info.in_color_space=JCS_YCbCr;
2210 case GRAYColorspace:
2212 if (image_info->type == TrueColorType)
2214 jpeg_info.input_components=1;
2215 jpeg_info.in_color_space=JCS_GRAYSCALE;
2220 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2221 if (image_info->type == TrueColorType)
2223 if (SetImageGray(image,exception) != MagickFalse)
2225 jpeg_info.input_components=1;
2226 jpeg_info.in_color_space=JCS_GRAYSCALE;
2231 jpeg_set_defaults(&jpeg_info);
2232 if (jpeg_info.in_color_space == JCS_CMYK)
2233 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2234 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2235 jpeg_info.data_precision=8;
2237 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2238 if (image->debug != MagickFalse)
2239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2240 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2241 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2244 Set image resolution.
2246 jpeg_info.write_JFIF_header=TRUE;
2247 jpeg_info.X_density=(UINT16) image->resolution.x;
2248 jpeg_info.Y_density=(UINT16) image->resolution.y;
2250 Set image resolution units.
2252 if (image->units == PixelsPerInchResolution)
2253 jpeg_info.density_unit=(UINT8) 1;
2254 if (image->units == PixelsPerCentimeterResolution)
2255 jpeg_info.density_unit=(UINT8) 2;
2257 jpeg_info.dct_method=JDCT_FLOAT;
2258 option=GetImageOption(image_info,"jpeg:dct-method");
2259 if (option != (const char *) NULL)
2265 if (LocaleCompare(option,"default") == 0)
2266 jpeg_info.dct_method=JDCT_DEFAULT;
2272 if (LocaleCompare(option,"fastest") == 0)
2273 jpeg_info.dct_method=JDCT_FASTEST;
2274 if (LocaleCompare(option,"float") == 0)
2275 jpeg_info.dct_method=JDCT_FLOAT;
2281 if (LocaleCompare(option,"ifast") == 0)
2282 jpeg_info.dct_method=JDCT_IFAST;
2283 if (LocaleCompare(option,"islow") == 0)
2284 jpeg_info.dct_method=JDCT_ISLOW;
2288 option=GetImageOption(image_info,"jpeg:optimize-coding");
2289 if (option != (const char *) NULL)
2290 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2297 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2298 image->rows*sizeof(JSAMPLE);
2299 if (length == (MagickSizeType) ((size_t) length))
2302 Perform optimization only if available memory resources permit it.
2304 status=AcquireMagickResource(MemoryResource,length);
2305 RelinquishMagickResource(MemoryResource,length);
2306 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2309 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2310 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2311 (image_info->interlace != NoInterlace))
2313 if (image->debug != MagickFalse)
2314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2315 "Interlace: progressive");
2316 jpeg_simple_progression(&jpeg_info);
2319 if (image->debug != MagickFalse)
2320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2321 "Interlace: non-progressive");
2323 if (image->debug != MagickFalse)
2324 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2325 "Interlace: nonprogressive");
2328 if ((image_info->compression != LosslessJPEGCompression) &&
2329 (image->quality <= 100))
2331 if (image->quality != UndefinedCompressionQuality)
2332 quality=(int) image->quality;
2333 if (image->debug != MagickFalse)
2334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2335 (double) image->quality);
2339 #if !defined(C_LOSSLESS_SUPPORTED)
2341 if (image->debug != MagickFalse)
2342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2344 if (image->quality < 100)
2345 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2346 "LosslessToLossyJPEGConversion","`%s'",image->filename);
2353 predictor=image->quality/100; /* range 1-7 */
2354 point_transform=image->quality % 20; /* range 0-15 */
2355 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2356 if (image->debug != MagickFalse)
2358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2359 "Compression: lossless");
2360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2361 "Predictor: %d",predictor);
2362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2363 "Point Transform: %d",point_transform);
2368 option=GetImageOption(image_info,"jpeg:extent");
2369 if (option != (const char *) NULL)
2377 extent_info=CloneImageInfo(image_info);
2378 extent_info->blob=NULL;
2379 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2380 if (jpeg_image != (Image *) NULL)
2390 Search for compression quality that does not exceed image extent.
2392 extent_info->quality=0;
2393 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2394 (void) DeleteImageOption(extent_info,"jpeg:extent");
2395 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2396 maximum=image_info->quality;
2399 for (minimum=2; minimum < maximum; )
2401 (void) AcquireUniqueFilename(jpeg_image->filename);
2402 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2403 status=WriteJPEGImage(extent_info,jpeg_image,exception);
2404 if (GetBlobSize(jpeg_image) <= extent)
2405 minimum=jpeg_image->quality+1;
2407 maximum=jpeg_image->quality-1;
2408 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2410 quality=(int) minimum-1;
2411 jpeg_image=DestroyImage(jpeg_image);
2413 extent_info=DestroyImageInfo(extent_info);
2415 jpeg_set_quality(&jpeg_info,quality,TRUE);
2416 #if (JPEG_LIB_VERSION >= 70)
2417 option=GetImageOption(image_info,"quality");
2418 if (option != (const char *) NULL)
2427 Set quality scaling for luminance and chrominance separately.
2429 flags=ParseGeometry(option,&geometry_info);
2430 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2432 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2433 (geometry_info.rho+0.5));
2434 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2435 (geometry_info.sigma+0.5));
2436 jpeg_default_qtables(&jpeg_info,TRUE);
2440 colorspace=jpeg_info.in_color_space;
2441 value=GetImageOption(image_info,"jpeg:colorspace");
2442 if (value == (char *) NULL)
2443 value=GetImageProperty(image,"jpeg:colorspace",exception);
2444 if (value != (char *) NULL)
2445 colorspace=StringToInteger(value);
2446 sampling_factor=(const char *) NULL;
2447 if (colorspace == jpeg_info.in_color_space)
2449 value=GetImageOption(image_info,"jpeg:sampling-factor");
2450 if (value == (char *) NULL)
2451 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2452 if (value != (char *) NULL)
2454 sampling_factor=value;
2455 if (image->debug != MagickFalse)
2456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2457 " Input sampling-factors=%s",sampling_factor);
2460 value=GetImageOption(image_info,"jpeg:sampling-factor");
2461 if (image_info->sampling_factor != (char *) NULL)
2462 sampling_factor=image_info->sampling_factor;
2463 if (sampling_factor == (const char *) NULL)
2466 for (i=0; i < MAX_COMPONENTS; i++)
2468 jpeg_info.comp_info[i].h_samp_factor=1;
2469 jpeg_info.comp_info[i].v_samp_factor=1;
2484 Set sampling factor.
2487 factors=SamplingFactorToList(sampling_factor);
2488 if (factors != (char **) NULL)
2490 for (i=0; i < MAX_COMPONENTS; i++)
2492 if (factors[i] == (char *) NULL)
2494 flags=ParseGeometry(factors[i],&geometry_info);
2495 if ((flags & SigmaValue) == 0)
2496 geometry_info.sigma=geometry_info.rho;
2497 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2498 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2499 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2501 factors=(char **) RelinquishMagickMemory(factors);
2503 for ( ; i < MAX_COMPONENTS; i++)
2505 jpeg_info.comp_info[i].h_samp_factor=1;
2506 jpeg_info.comp_info[i].v_samp_factor=1;
2509 option=GetImageOption(image_info,"jpeg:q-table");
2510 if (option != (const char *) NULL)
2516 Custom quantization tables.
2518 table=GetQuantizationTable(option,"0",exception);
2519 if (table != (QuantizationTable *) NULL)
2521 for (i=0; i < MAX_COMPONENTS; i++)
2522 jpeg_info.comp_info[i].quant_tbl_no=0;
2523 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2524 jpeg_quality_scaling(quality),0);
2525 table=DestroyQuantizationTable(table);
2527 table=GetQuantizationTable(option,"1",exception);
2528 if (table != (QuantizationTable *) NULL)
2530 for (i=1; i < MAX_COMPONENTS; i++)
2531 jpeg_info.comp_info[i].quant_tbl_no=1;
2532 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2533 jpeg_quality_scaling(quality),0);
2534 table=DestroyQuantizationTable(table);
2536 table=GetQuantizationTable(option,"2",exception);
2537 if (table != (QuantizationTable *) NULL)
2539 for (i=2; i < MAX_COMPONENTS; i++)
2540 jpeg_info.comp_info[i].quant_tbl_no=2;
2541 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2542 jpeg_quality_scaling(quality),0);
2543 table=DestroyQuantizationTable(table);
2545 table=GetQuantizationTable(option,"3",exception);
2546 if (table != (QuantizationTable *) NULL)
2548 for (i=3; i < MAX_COMPONENTS; i++)
2549 jpeg_info.comp_info[i].quant_tbl_no=3;
2550 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2551 jpeg_quality_scaling(quality),0);
2552 table=DestroyQuantizationTable(table);
2555 jpeg_start_compress(&jpeg_info,TRUE);
2556 if (image->debug != MagickFalse)
2558 if (image->storage_class == PseudoClass)
2559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2560 "Storage class: PseudoClass");
2562 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2563 "Storage class: DirectClass");
2564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2565 (double) image->depth);
2566 if (image->colors != 0)
2567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2568 "Number of colors: %.20g",(double) image->colors);
2570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2571 "Number of colors: unspecified");
2572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2573 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2574 switch (image->colorspace)
2576 case CMYKColorspace:
2578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2579 "Storage class: DirectClass");
2580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2581 "Colorspace: CMYK");
2584 case YCbCrColorspace:
2585 case Rec601YCbCrColorspace:
2586 case Rec709YCbCrColorspace:
2588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2589 "Colorspace: YCbCr");
2595 switch (image->colorspace)
2597 case CMYKColorspace:
2599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2600 "Colorspace: CMYK");
2601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2602 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2603 jpeg_info.comp_info[0].h_samp_factor,
2604 jpeg_info.comp_info[0].v_samp_factor,
2605 jpeg_info.comp_info[1].h_samp_factor,
2606 jpeg_info.comp_info[1].v_samp_factor,
2607 jpeg_info.comp_info[2].h_samp_factor,
2608 jpeg_info.comp_info[2].v_samp_factor,
2609 jpeg_info.comp_info[3].h_samp_factor,
2610 jpeg_info.comp_info[3].v_samp_factor);
2613 case GRAYColorspace:
2615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2616 "Colorspace: GRAY");
2617 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2618 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2619 jpeg_info.comp_info[0].v_samp_factor);
2622 case sRGBColorspace:
2625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2626 "Image colorspace is RGB");
2627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2628 "Sampling factors: %dx%d,%dx%d,%dx%d",
2629 jpeg_info.comp_info[0].h_samp_factor,
2630 jpeg_info.comp_info[0].v_samp_factor,
2631 jpeg_info.comp_info[1].h_samp_factor,
2632 jpeg_info.comp_info[1].v_samp_factor,
2633 jpeg_info.comp_info[2].h_samp_factor,
2634 jpeg_info.comp_info[2].v_samp_factor);
2637 case YCbCrColorspace:
2638 case Rec601YCbCrColorspace:
2639 case Rec709YCbCrColorspace:
2641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2642 "Colorspace: YCbCr");
2643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2644 "Sampling factors: %dx%d,%dx%d,%dx%d",
2645 jpeg_info.comp_info[0].h_samp_factor,
2646 jpeg_info.comp_info[0].v_samp_factor,
2647 jpeg_info.comp_info[1].h_samp_factor,
2648 jpeg_info.comp_info[1].v_samp_factor,
2649 jpeg_info.comp_info[2].h_samp_factor,
2650 jpeg_info.comp_info[2].v_samp_factor);
2655 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2658 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2659 jpeg_info.comp_info[0].h_samp_factor,
2660 jpeg_info.comp_info[0].v_samp_factor,
2661 jpeg_info.comp_info[1].h_samp_factor,
2662 jpeg_info.comp_info[1].v_samp_factor,
2663 jpeg_info.comp_info[2].h_samp_factor,
2664 jpeg_info.comp_info[2].v_samp_factor,
2665 jpeg_info.comp_info[3].h_samp_factor,
2666 jpeg_info.comp_info[3].v_samp_factor);
2672 Write JPEG profiles.
2674 value=GetImageProperty(image,"comment",exception);
2675 if (value != (char *) NULL)
2676 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2677 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2678 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2679 if (image->profiles != (void *) NULL)
2680 WriteProfile(&jpeg_info,image,exception);
2682 Convert MIFF to JPEG raster pixels.
2684 memory_info=AcquireVirtualMemory((size_t) image->columns,
2685 jpeg_info.input_components*sizeof(*jpeg_pixels));
2686 if (memory_info == (MemoryInfo *) NULL)
2687 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2688 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2689 if (setjmp(error_manager.error_recovery) != 0)
2691 jpeg_destroy_compress(&jpeg_info);
2692 if (memory_info != (MemoryInfo *) NULL)
2693 memory_info=RelinquishVirtualMemory(memory_info);
2694 (void) CloseBlob(image);
2695 return(MagickFalse);
2697 scanline[0]=(JSAMPROW) jpeg_pixels;
2698 scale=65535/(unsigned short) GetQuantumRange((size_t)
2699 jpeg_info.data_precision);
2702 if (jpeg_info.data_precision <= 8)
2704 if ((jpeg_info.in_color_space == JCS_RGB) ||
2705 (jpeg_info.in_color_space == JCS_YCbCr))
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++)
2720 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2721 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2722 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2723 p+=GetPixelChannels(image);
2725 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2726 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2728 if (status == MagickFalse)
2732 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2733 for (y=0; y < (ssize_t) image->rows; y++)
2735 register const Quantum
2741 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2742 if (p == (const Quantum *) NULL)
2745 for (x=0; x < (ssize_t) image->columns; x++)
2747 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2749 p+=GetPixelChannels(image);
2751 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2752 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2754 if (status == MagickFalse)
2758 for (y=0; y < (ssize_t) image->rows; y++)
2760 register const Quantum
2766 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2767 if (p == (const Quantum *) NULL)
2770 for (x=0; x < (ssize_t) image->columns; x++)
2773 Convert DirectClass packets to contiguous CMYK scanlines.
2775 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2776 GetPixelCyan(image,p))));
2777 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2778 GetPixelMagenta(image,p))));
2779 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2780 GetPixelYellow(image,p))));
2781 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2782 GetPixelBlack(image,p))));
2783 p+=GetPixelChannels(image);
2785 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2786 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2788 if (status == MagickFalse)
2793 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2794 for (y=0; y < (ssize_t) image->rows; y++)
2796 register const Quantum
2802 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2803 if (p == (const Quantum *) NULL)
2806 for (x=0; x < (ssize_t) image->columns; x++)
2808 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2810 p+=GetPixelChannels(image);
2812 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2813 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2815 if (status == MagickFalse)
2819 if ((jpeg_info.in_color_space == JCS_RGB) ||
2820 (jpeg_info.in_color_space == JCS_YCbCr))
2821 for (y=0; y < (ssize_t) image->rows; y++)
2823 register const Quantum
2829 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2830 if (p == (const Quantum *) NULL)
2833 for (x=0; x < (ssize_t) image->columns; x++)
2835 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2836 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2837 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2838 p+=GetPixelChannels(image);
2840 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2841 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2843 if (status == MagickFalse)
2847 for (y=0; y < (ssize_t) image->rows; y++)
2849 register const Quantum
2855 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2856 if (p == (const Quantum *) NULL)
2859 for (x=0; x < (ssize_t) image->columns; x++)
2862 Convert DirectClass packets to contiguous CMYK scanlines.
2864 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2866 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2868 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2870 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2872 p+=GetPixelChannels(image);
2874 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2875 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2877 if (status == MagickFalse)
2880 if (y == (ssize_t) image->rows)
2881 jpeg_finish_compress(&jpeg_info);
2883 Relinquish resources.
2885 jpeg_destroy_compress(&jpeg_info);
2886 memory_info=RelinquishVirtualMemory(memory_info);
2887 (void) CloseBlob(image);