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 % https://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/memory-private.h"
70 #include "MagickCore/module.h"
71 #include "MagickCore/monitor.h"
72 #include "MagickCore/monitor-private.h"
73 #include "MagickCore/option.h"
74 #include "MagickCore/option-private.h"
75 #include "MagickCore/pixel-accessor.h"
76 #include "MagickCore/profile.h"
77 #include "MagickCore/property.h"
78 #include "MagickCore/quantum-private.h"
79 #include "MagickCore/resource_.h"
80 #include "MagickCore/semaphore.h"
81 #include "MagickCore/splay-tree.h"
82 #include "MagickCore/static.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/token.h"
86 #include "MagickCore/utility.h"
87 #include "MagickCore/xml-tree.h"
88 #include "MagickCore/xml-tree-private.h"
90 #if defined(MAGICKCORE_JPEG_DELEGATE)
91 #define JPEG_INTERNAL_OPTIONS
92 #if defined(__MINGW32__)
93 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
103 #define ICC_MARKER (JPEG_APP0+2)
104 #define ICC_PROFILE "ICC_PROFILE"
105 #define IPTC_MARKER (JPEG_APP0+13)
106 #define XML_MARKER (JPEG_APP0+1)
107 #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
177 Forward declarations.
179 #if defined(MAGICKCORE_JPEG_DELEGATE)
180 static MagickBooleanType
181 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 % IsJPEG() returns MagickTrue if the image format type, identified by the
196 % magick string, is JPEG.
198 % The format of the IsJPEG method is:
200 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
202 % A description of each parameter follows:
204 % o magick: compare image format pattern against these bytes.
206 % o length: Specifies the length of the magick string.
209 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
213 if (memcmp(magick,"\377\330\377",3) == 0)
218 #if defined(MAGICKCORE_JPEG_DELEGATE)
220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 % R e a d J P E G I m a g e %
228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
231 % the memory necessary for the new Image structure and returns a pointer to
234 % The format of the ReadJPEGImage method is:
236 % Image *ReadJPEGImage(const ImageInfo *image_info,
237 % ExceptionInfo *exception)
239 % A description of each parameter follows:
241 % o image_info: the image info.
243 % o exception: return any errors or warnings in this structure.
247 static boolean FillInputBuffer(j_decompress_ptr cinfo)
252 source=(SourceManager *) cinfo->src;
253 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
254 MaxBufferExtent,source->buffer);
255 if (source->manager.bytes_in_buffer == 0)
257 if (source->start_of_blob != FALSE)
258 ERREXIT(cinfo,JERR_INPUT_EMPTY);
259 WARNMS(cinfo,JWRN_JPEG_EOF);
260 source->buffer[0]=(JOCTET) 0xff;
261 source->buffer[1]=(JOCTET) JPEG_EOI;
262 source->manager.bytes_in_buffer=2;
264 source->manager.next_input_byte=source->buffer;
265 source->start_of_blob=FALSE;
269 static int GetCharacter(j_decompress_ptr jpeg_info)
271 if (jpeg_info->src->bytes_in_buffer == 0)
272 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
273 jpeg_info->src->bytes_in_buffer--;
274 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
277 static void InitializeSource(j_decompress_ptr cinfo)
282 source=(SourceManager *) cinfo->src;
283 source->start_of_blob=TRUE;
286 static MagickBooleanType IsITUFaxImage(const Image *image)
294 profile=GetImageProfile(image,"8bim");
295 if (profile == (const StringInfo *) NULL)
297 if (GetStringInfoLength(profile) < 5)
299 datum=GetStringInfoDatum(profile);
300 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
301 (datum[3] == 0x41) && (datum[4] == 0x58))
306 static void JPEGErrorHandler(j_common_ptr jpeg_info)
309 message[JMSG_LENGTH_MAX];
321 error_manager=(ErrorManager *) jpeg_info->client_data;
322 image=error_manager->image;
323 exception=error_manager->exception;
324 (jpeg_info->err->format_message)(jpeg_info,message);
325 if (image->debug != MagickFalse)
326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
327 "[%s] JPEG Trace: \"%s\"",image->filename,message);
328 if (error_manager->finished != MagickFalse)
329 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
330 (char *) message,"`%s'",image->filename);
332 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
333 (char *) message,"`%s'",image->filename);
334 longjmp(error_manager->error_recovery,1);
337 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
339 #define JPEGExcessiveWarnings 1000
342 message[JMSG_LENGTH_MAX];
354 error_manager=(ErrorManager *) jpeg_info->client_data;
355 exception=error_manager->exception;
356 image=error_manager->image;
360 Process warning message.
362 (jpeg_info->err->format_message)(jpeg_info,message);
363 if (jpeg_info->err->num_warnings++ < JPEGExcessiveWarnings)
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++)
432 c=GetCharacter(jpeg_info);
435 *p++=(unsigned char) c;
438 error_manager->profile=NULL;
439 p=GetStringInfoDatum(comment);
440 (void) SetImageProperty(image,"comment",(const char *) p,exception);
441 comment=DestroyStringInfo(comment);
445 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
465 register unsigned char
478 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
479 length+=(size_t) GetCharacter(jpeg_info);
484 if (GetCharacter(jpeg_info) == EOF)
488 for (i=0; i < 12; i++)
489 magick[i]=(char) GetCharacter(jpeg_info);
490 if (LocaleCompare(magick,ICC_PROFILE) != 0)
493 Not a ICC profile, return.
495 for (i=0; i < (ssize_t) (length-12); i++)
496 if (GetCharacter(jpeg_info) == EOF)
500 (void) GetCharacter(jpeg_info); /* id */
501 (void) GetCharacter(jpeg_info); /* markers */
503 error_manager=(ErrorManager *) jpeg_info->client_data;
504 exception=error_manager->exception;
505 image=error_manager->image;
506 profile=BlobToStringInfo((const void *) NULL,length);
507 if (profile == (StringInfo *) NULL)
509 (void) ThrowMagickException(exception,GetMagickModule(),
510 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
513 error_manager->profile=profile;
514 p=GetStringInfoDatum(profile);
515 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
520 c=GetCharacter(jpeg_info);
523 *p++=(unsigned char) c;
525 error_manager->profile=NULL;
526 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
527 if (icc_profile != (StringInfo *) NULL)
529 ConcatenateStringInfo(icc_profile,profile);
530 profile=DestroyStringInfo(profile);
534 status=SetImageProfile(image,"icc",profile,exception);
535 profile=DestroyStringInfo(profile);
536 if (status == MagickFalse)
538 (void) ThrowMagickException(exception,GetMagickModule(),
539 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
543 if (image->debug != MagickFalse)
544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
545 "Profile: ICC, %.20g bytes",(double) length);
549 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
552 magick[MagickPathExtent];
569 register unsigned char
580 Determine length of binary data stored here.
582 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
583 length+=(size_t) GetCharacter(jpeg_info);
588 if (GetCharacter(jpeg_info) == EOF)
593 Validate that this was written as a Photoshop resource format slug.
595 for (i=0; i < 10; i++)
596 magick[i]=(char) GetCharacter(jpeg_info);
601 if (LocaleCompare(magick,"Photoshop ") != 0)
604 Not a IPTC profile, return.
606 for (i=0; i < (ssize_t) length; i++)
607 if (GetCharacter(jpeg_info) == EOF)
612 Remove the version number.
614 for (i=0; i < 4; i++)
615 if (GetCharacter(jpeg_info) == EOF)
620 error_manager=(ErrorManager *) jpeg_info->client_data;
621 exception=error_manager->exception;
622 image=error_manager->image;
623 profile=BlobToStringInfo((const void *) NULL,length);
624 if (profile == (StringInfo *) NULL)
626 (void) ThrowMagickException(exception,GetMagickModule(),
627 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
630 error_manager->profile=profile;
631 p=GetStringInfoDatum(profile);
632 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
637 c=GetCharacter(jpeg_info);
640 *p++=(unsigned char) c;
642 error_manager->profile=NULL;
643 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
644 if (iptc_profile != (StringInfo *) NULL)
646 ConcatenateStringInfo(iptc_profile,profile);
647 profile=DestroyStringInfo(profile);
651 status=SetImageProfile(image,"8bim",profile,exception);
652 profile=DestroyStringInfo(profile);
653 if (status == MagickFalse)
655 (void) ThrowMagickException(exception,GetMagickModule(),
656 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
660 if (image->debug != MagickFalse)
661 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
662 "Profile: iptc, %.20g bytes",(double) length);
666 static boolean ReadProfile(j_decompress_ptr jpeg_info)
669 name[MagickPathExtent];
692 register unsigned char
702 Read generic profile.
704 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
705 length+=(size_t) GetCharacter(jpeg_info);
709 marker=jpeg_info->unread_marker-JPEG_APP0;
710 (void) FormatLocaleString(name,MagickPathExtent,"APP%d",marker);
711 error_manager=(ErrorManager *) jpeg_info->client_data;
712 exception=error_manager->exception;
713 image=error_manager->image;
714 profile=BlobToStringInfo((const void *) NULL,length);
715 if (profile == (StringInfo *) NULL)
717 (void) ThrowMagickException(exception,GetMagickModule(),
718 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
721 error_manager->profile=profile;
722 p=GetStringInfoDatum(profile);
723 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
728 c=GetCharacter(jpeg_info);
731 *p++=(unsigned char) c;
733 error_manager->profile=NULL;
736 p=GetStringInfoDatum(profile);
737 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
738 (void) CopyMagickString(name,"exif",MagickPathExtent);
739 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
745 Extract namespace from XMP profile.
747 p=GetStringInfoDatum(profile);
748 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
754 if (j < (ssize_t) GetStringInfoLength(profile))
755 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
756 (void) CopyMagickString(name,"xmp",MagickPathExtent);
759 previous_profile=GetImageProfile(image,name);
760 if (previous_profile != (const StringInfo *) NULL)
765 profile_length=GetStringInfoLength(profile);
766 SetStringInfoLength(profile,GetStringInfoLength(profile)+
767 GetStringInfoLength(previous_profile));
768 (void) memmove(GetStringInfoDatum(profile)+
769 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
771 (void) memcpy(GetStringInfoDatum(profile),
772 GetStringInfoDatum(previous_profile),
773 GetStringInfoLength(previous_profile));
775 status=SetImageProfile(image,name,profile,exception);
776 profile=DestroyStringInfo(profile);
777 if (status == MagickFalse)
779 (void) ThrowMagickException(exception,GetMagickModule(),
780 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
783 if (image->debug != MagickFalse)
784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
785 "Profile: %s, %.20g bytes",name,(double) length);
789 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
794 if (number_bytes <= 0)
796 source=(SourceManager *) cinfo->src;
797 while (number_bytes > (long) source->manager.bytes_in_buffer)
799 number_bytes-=(long) source->manager.bytes_in_buffer;
800 (void) FillInputBuffer(cinfo);
802 source->manager.next_input_byte+=number_bytes;
803 source->manager.bytes_in_buffer-=number_bytes;
806 static void TerminateSource(j_decompress_ptr cinfo)
811 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
816 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
817 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
818 source=(SourceManager *) cinfo->src;
819 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
820 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
821 source=(SourceManager *) cinfo->src;
822 source->manager.init_source=InitializeSource;
823 source->manager.fill_input_buffer=FillInputBuffer;
824 source->manager.skip_input_data=SkipInputData;
825 source->manager.resync_to_restart=jpeg_resync_to_restart;
826 source->manager.term_source=TerminateSource;
827 source->manager.bytes_in_buffer=0;
828 source->manager.next_input_byte=NULL;
832 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
835 image->quality=UndefinedCompressionQuality;
836 #if defined(D_PROGRESSIVE_SUPPORTED)
837 if (image->compression == LosslessJPEGCompression)
840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
841 "Quality: 100 (lossless)");
855 Determine the JPEG compression quality from the quantization tables.
858 for (i=0; i < NUM_QUANT_TBLS; i++)
860 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
861 for (j=0; j < DCTSIZE2; j++)
862 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
864 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
865 (jpeg_info->quant_tbl_ptrs[1] != NULL))
870 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
871 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
872 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
873 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
874 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
875 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
876 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
877 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
878 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
879 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
884 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
885 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
886 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
887 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
888 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
889 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
890 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
891 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
892 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
893 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
894 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
898 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
899 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
900 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
901 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
902 for (i=0; i < 100; i++)
904 if ((qvalue < hash[i]) && (sum < sums[i]))
906 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
907 image->quality=(size_t) i+1;
908 if (image->debug != MagickFalse)
909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
910 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
911 (sum <= sums[i]) ? "exact" : "approximate");
916 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
921 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
922 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
923 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
924 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
925 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
926 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
927 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
928 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
929 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
930 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
935 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
936 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
937 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
938 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
939 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
940 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
941 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
942 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
943 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
944 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
945 667, 592, 518, 441, 369, 292, 221, 151, 86,
949 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
950 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
951 for (i=0; i < 100; i++)
953 if ((qvalue < hash[i]) && (sum < sums[i]))
955 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
956 image->quality=(size_t)i+1;
957 if (image->debug != MagickFalse)
958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
959 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
960 (sum <= sums[i]) ? "exact" : "approximate");
967 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
970 sampling_factor[MagickPathExtent];
972 switch (jpeg_info->out_color_space)
976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
977 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
978 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
979 jpeg_info->comp_info[0].v_samp_factor,
980 jpeg_info->comp_info[1].h_samp_factor,
981 jpeg_info->comp_info[1].v_samp_factor,
982 jpeg_info->comp_info[2].h_samp_factor,
983 jpeg_info->comp_info[2].v_samp_factor,
984 jpeg_info->comp_info[3].h_samp_factor,
985 jpeg_info->comp_info[3].v_samp_factor);
990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
991 "Colorspace: GRAYSCALE");
992 (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d",
993 jpeg_info->comp_info[0].h_samp_factor,
994 jpeg_info->comp_info[0].v_samp_factor);
999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
1000 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1001 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
1002 jpeg_info->comp_info[0].v_samp_factor,
1003 jpeg_info->comp_info[1].h_samp_factor,
1004 jpeg_info->comp_info[1].v_samp_factor,
1005 jpeg_info->comp_info[2].h_samp_factor,
1006 jpeg_info->comp_info[2].v_samp_factor);
1011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
1012 jpeg_info->out_color_space);
1013 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1014 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
1015 jpeg_info->comp_info[0].v_samp_factor,
1016 jpeg_info->comp_info[1].h_samp_factor,
1017 jpeg_info->comp_info[1].v_samp_factor,
1018 jpeg_info->comp_info[2].h_samp_factor,
1019 jpeg_info->comp_info[2].v_samp_factor,
1020 jpeg_info->comp_info[3].h_samp_factor,
1021 jpeg_info->comp_info[3].v_samp_factor);
1025 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
1027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
1031 static Image *ReadJPEGImage(const ImageInfo *image_info,
1032 ExceptionInfo *exception)
1035 value[MagickPathExtent];
1047 *volatile jpeg_pixels;
1068 struct jpeg_decompress_struct
1071 struct jpeg_error_mgr
1086 assert(image_info != (const ImageInfo *) NULL);
1087 assert(image_info->signature == MagickCoreSignature);
1088 if (image_info->debug != MagickFalse)
1089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1090 image_info->filename);
1091 assert(exception != (ExceptionInfo *) NULL);
1092 assert(exception->signature == MagickCoreSignature);
1093 debug=IsEventLogging();
1095 image=AcquireImage(image_info,exception);
1096 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1097 if (status == MagickFalse)
1099 image=DestroyImageList(image);
1100 return((Image *) NULL);
1103 Verify that file size large enough to contain a JPEG datastream.
1105 if (GetBlobSize(image) < 107)
1106 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
1108 Initialize JPEG parameters.
1110 (void) memset(&error_manager,0,sizeof(error_manager));
1111 (void) memset(&jpeg_info,0,sizeof(jpeg_info));
1112 (void) memset(&jpeg_error,0,sizeof(jpeg_error));
1113 jpeg_info.err=jpeg_std_error(&jpeg_error);
1114 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1115 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1116 memory_info=(MemoryInfo *) NULL;
1117 error_manager.exception=exception;
1118 error_manager.image=image;
1119 if (setjmp(error_manager.error_recovery) != 0)
1121 jpeg_destroy_decompress(&jpeg_info);
1122 if (error_manager.profile != (StringInfo *) NULL)
1123 error_manager.profile=DestroyStringInfo(error_manager.profile);
1124 (void) CloseBlob(image);
1125 number_pixels=(MagickSizeType) image->columns*image->rows;
1126 if (number_pixels != 0)
1127 return(GetFirstImageInList(image));
1128 return(DestroyImage(image));
1130 jpeg_info.client_data=(void *) &error_manager;
1131 jpeg_create_decompress(&jpeg_info);
1132 if (GetMaxMemoryRequest() != ~0UL)
1133 jpeg_info.mem->max_memory_to_use=(long) GetMaxMemoryRequest();
1134 JPEGSourceManager(&jpeg_info,image);
1135 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1136 option=GetImageOption(image_info,"profile:skip");
1137 if (IsOptionMember("ICC",option) == MagickFalse)
1138 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1139 if (IsOptionMember("IPTC",option) == MagickFalse)
1140 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1141 for (i=1; i < 16; i++)
1142 if ((i != 2) && (i != 13) && (i != 14))
1143 if (IsOptionMember("APP",option) == MagickFalse)
1144 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1145 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1146 if ((image_info->colorspace == YCbCrColorspace) ||
1147 (image_info->colorspace == Rec601YCbCrColorspace) ||
1148 (image_info->colorspace == Rec709YCbCrColorspace))
1149 jpeg_info.out_color_space=JCS_YCbCr;
1151 Set image resolution.
1154 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1155 (jpeg_info.Y_density != 1))
1157 image->resolution.x=(double) jpeg_info.X_density;
1158 image->resolution.y=(double) jpeg_info.Y_density;
1159 units=(size_t) jpeg_info.density_unit;
1162 image->units=PixelsPerInchResolution;
1164 image->units=PixelsPerCentimeterResolution;
1165 number_pixels=(MagickSizeType) image->columns*image->rows;
1166 option=GetImageOption(image_info,"jpeg:size");
1167 if ((option != (const char *) NULL) &&
1168 (jpeg_info.out_color_space != JCS_YCbCr))
1182 flags=ParseGeometry(option,&geometry_info);
1183 if ((flags & SigmaValue) == 0)
1184 geometry_info.sigma=geometry_info.rho;
1185 jpeg_calc_output_dimensions(&jpeg_info);
1186 image->magick_columns=jpeg_info.output_width;
1187 image->magick_rows=jpeg_info.output_height;
1189 if (geometry_info.rho != 0.0)
1190 scale_factor=jpeg_info.output_width/geometry_info.rho;
1191 if ((geometry_info.sigma != 0.0) &&
1192 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1193 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1194 jpeg_info.scale_num=1U;
1195 jpeg_info.scale_denom=(unsigned int) scale_factor;
1196 jpeg_calc_output_dimensions(&jpeg_info);
1197 if (image->debug != MagickFalse)
1198 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1199 "Scale factor: %.20g",(double) scale_factor);
1201 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1202 #if defined(D_LOSSLESS_SUPPORTED)
1203 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1204 JPEGInterlace : NoInterlace;
1205 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1206 LosslessJPEGCompression : JPEGCompression;
1207 if (jpeg_info.data_precision > 8)
1208 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1209 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1211 if (jpeg_info.data_precision == 16)
1212 jpeg_info.data_precision=12;
1214 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1216 image->compression=JPEGCompression;
1219 image->compression=JPEGCompression;
1220 image->interlace=JPEGInterlace;
1222 option=GetImageOption(image_info,"jpeg:colors");
1223 if (option != (const char *) NULL)
1226 Let the JPEG library quantize the image.
1228 jpeg_info.quantize_colors=TRUE;
1229 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1231 option=GetImageOption(image_info,"jpeg:block-smoothing");
1232 if (option != (const char *) NULL)
1233 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1235 jpeg_info.dct_method=JDCT_FLOAT;
1236 option=GetImageOption(image_info,"jpeg:dct-method");
1237 if (option != (const char *) NULL)
1243 if (LocaleCompare(option,"default") == 0)
1244 jpeg_info.dct_method=JDCT_DEFAULT;
1250 if (LocaleCompare(option,"fastest") == 0)
1251 jpeg_info.dct_method=JDCT_FASTEST;
1252 if (LocaleCompare(option,"float") == 0)
1253 jpeg_info.dct_method=JDCT_FLOAT;
1259 if (LocaleCompare(option,"ifast") == 0)
1260 jpeg_info.dct_method=JDCT_IFAST;
1261 if (LocaleCompare(option,"islow") == 0)
1262 jpeg_info.dct_method=JDCT_ISLOW;
1266 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1267 if (option != (const char *) NULL)
1268 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1270 jpeg_calc_output_dimensions(&jpeg_info);
1271 image->columns=jpeg_info.output_width;
1272 image->rows=jpeg_info.output_height;
1273 image->depth=(size_t) jpeg_info.data_precision;
1274 switch (jpeg_info.out_color_space)
1279 (void) SetImageColorspace(image,sRGBColorspace,exception);
1284 (void) SetImageColorspace(image,GRAYColorspace,exception);
1289 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1294 (void) SetImageColorspace(image,CMYKColorspace,exception);
1298 if (IsITUFaxImage(image) != MagickFalse)
1300 (void) SetImageColorspace(image,LabColorspace,exception);
1301 jpeg_info.out_color_space=JCS_YCbCr;
1303 option=GetImageOption(image_info,"jpeg:colors");
1304 if (option != (const char *) NULL)
1305 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception) == MagickFalse)
1307 jpeg_destroy_decompress(&jpeg_info);
1308 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1310 if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0))
1315 colors=(size_t) GetQuantumRange(image->depth)+1;
1316 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1318 jpeg_destroy_decompress(&jpeg_info);
1319 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1322 if (image->debug != MagickFalse)
1324 if (image->interlace != NoInterlace)
1325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1326 "Interlace: progressive");
1328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1329 "Interlace: nonprogressive");
1330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1331 (int) jpeg_info.data_precision);
1332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1333 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1335 JPEGSetImageQuality(&jpeg_info,image);
1336 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1337 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
1338 jpeg_info.out_color_space);
1339 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1340 if (image_info->ping != MagickFalse)
1342 jpeg_destroy_decompress(&jpeg_info);
1343 (void) CloseBlob(image);
1344 return(GetFirstImageInList(image));
1346 status=SetImageExtent(image,image->columns,image->rows,exception);
1347 if (status == MagickFalse)
1349 jpeg_destroy_decompress(&jpeg_info);
1350 return(DestroyImageList(image));
1352 (void) jpeg_start_decompress(&jpeg_info);
1353 if ((jpeg_info.output_components != 1) &&
1354 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1356 jpeg_destroy_decompress(&jpeg_info);
1357 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1359 memory_info=AcquireVirtualMemory((size_t) image->columns,
1360 jpeg_info.output_components*sizeof(*jpeg_pixels));
1361 if (memory_info == (MemoryInfo *) NULL)
1363 jpeg_destroy_decompress(&jpeg_info);
1364 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1366 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1367 (void) memset(jpeg_pixels,0,image->columns*
1368 jpeg_info.output_components*sizeof(*jpeg_pixels));
1370 Convert JPEG pixels to pixel packets.
1372 if (setjmp(error_manager.error_recovery) != 0)
1374 if (memory_info != (MemoryInfo *) NULL)
1375 memory_info=RelinquishVirtualMemory(memory_info);
1376 jpeg_destroy_decompress(&jpeg_info);
1377 (void) CloseBlob(image);
1378 number_pixels=(MagickSizeType) image->columns*image->rows;
1379 if (number_pixels != 0)
1380 return(GetFirstImageInList(image));
1381 return(DestroyImage(image));
1383 if (jpeg_info.quantize_colors != 0)
1385 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1386 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1387 for (i=0; i < (ssize_t) image->colors; i++)
1389 image->colormap[i].red=(double) ScaleCharToQuantum(
1390 jpeg_info.colormap[0][i]);
1391 image->colormap[i].green=image->colormap[i].red;
1392 image->colormap[i].blue=image->colormap[i].red;
1393 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1396 for (i=0; i < (ssize_t) image->colors; i++)
1398 image->colormap[i].red=(double) ScaleCharToQuantum(
1399 jpeg_info.colormap[0][i]);
1400 image->colormap[i].green=(double) ScaleCharToQuantum(
1401 jpeg_info.colormap[1][i]);
1402 image->colormap[i].blue=(double) ScaleCharToQuantum(
1403 jpeg_info.colormap[2][i]);
1404 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1407 scanline[0]=(JSAMPROW) jpeg_pixels;
1408 for (y=0; y < (ssize_t) image->rows; y++)
1416 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1418 (void) ThrowMagickException(exception,GetMagickModule(),
1419 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1423 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1424 if (q == (Quantum *) NULL)
1426 if (jpeg_info.data_precision > 8)
1431 scale=65535/(unsigned short) GetQuantumRange((size_t)
1432 jpeg_info.data_precision);
1433 if (jpeg_info.output_components == 1)
1434 for (x=0; x < (ssize_t) image->columns; x++)
1439 pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1440 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1441 SetPixelIndex(image,index,q);
1442 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1444 q+=GetPixelChannels(image);
1447 if (image->colorspace != CMYKColorspace)
1448 for (x=0; x < (ssize_t) image->columns; x++)
1450 SetPixelRed(image,ScaleShortToQuantum(
1451 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1452 SetPixelGreen(image,ScaleShortToQuantum(
1453 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1454 SetPixelBlue(image,ScaleShortToQuantum(
1455 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1456 SetPixelAlpha(image,OpaqueAlpha,q);
1457 q+=GetPixelChannels(image);
1460 for (x=0; x < (ssize_t) image->columns; x++)
1462 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1463 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1464 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1465 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1466 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1467 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1468 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1469 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1470 SetPixelAlpha(image,OpaqueAlpha,q);
1471 q+=GetPixelChannels(image);
1475 if (jpeg_info.output_components == 1)
1476 for (x=0; x < (ssize_t) image->columns; x++)
1481 pixel=(ssize_t) GETJSAMPLE(*p);
1482 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1483 SetPixelIndex(image,index,q);
1484 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1486 q+=GetPixelChannels(image);
1489 if (image->colorspace != CMYKColorspace)
1490 for (x=0; x < (ssize_t) image->columns; x++)
1492 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1493 GETJSAMPLE(*p++)),q);
1494 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1495 GETJSAMPLE(*p++)),q);
1496 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1497 GETJSAMPLE(*p++)),q);
1498 SetPixelAlpha(image,OpaqueAlpha,q);
1499 q+=GetPixelChannels(image);
1502 for (x=0; x < (ssize_t) image->columns; x++)
1504 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1505 (unsigned char) GETJSAMPLE(*p++)),q);
1506 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1507 (unsigned char) GETJSAMPLE(*p++)),q);
1508 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1509 (unsigned char) GETJSAMPLE(*p++)),q);
1510 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1511 (unsigned char) GETJSAMPLE(*p++)),q);
1512 SetPixelAlpha(image,OpaqueAlpha,q);
1513 q+=GetPixelChannels(image);
1515 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1517 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1519 if (status == MagickFalse)
1521 jpeg_abort_decompress(&jpeg_info);
1525 if (status != MagickFalse)
1527 error_manager.finished=MagickTrue;
1528 if (setjmp(error_manager.error_recovery) == 0)
1529 (void) jpeg_finish_decompress(&jpeg_info);
1532 Free jpeg resources.
1534 jpeg_destroy_decompress(&jpeg_info);
1535 memory_info=RelinquishVirtualMemory(memory_info);
1536 (void) CloseBlob(image);
1537 return(GetFirstImageInList(image));
1542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546 % R e g i s t e r J P E G I m a g e %
1550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 % RegisterJPEGImage() adds properties for the JPEG image format to
1553 % the list of supported formats. The properties include the image format
1554 % tag, a method to read and/or write the format, whether the format
1555 % supports the saving of more than one frame to the same file or blob,
1556 % whether the format supports native in-memory I/O, and a brief
1557 % description of the format.
1559 % The format of the RegisterJPEGImage method is:
1561 % size_t RegisterJPEGImage(void)
1564 ModuleExport size_t RegisterJPEGImage(void)
1566 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1569 version[MagickPathExtent];
1575 #if defined(JPEG_LIB_VERSION)
1576 (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION);
1578 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1579 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1580 entry->flags^=CoderDecoderThreadSupportFlag;
1582 #if defined(MAGICKCORE_JPEG_DELEGATE)
1583 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1584 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1586 entry->magick=(IsImageFormatHandler *) IsJPEG;
1587 entry->flags|=CoderDecoderSeekableStreamFlag;
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 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1595 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1596 entry->flags^=CoderDecoderThreadSupportFlag;
1598 #if defined(MAGICKCORE_JPEG_DELEGATE)
1599 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1600 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1602 entry->magick=(IsImageFormatHandler *) IsJPEG;
1603 entry->flags|=CoderDecoderSeekableStreamFlag;
1604 entry->flags^=CoderAdjoinFlag;
1605 if (*version != '\0')
1606 entry->version=ConstantString(version);
1607 entry->mime_type=ConstantString("image/jpeg");
1608 (void) RegisterMagickInfo(entry);
1609 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1610 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1611 entry->flags^=CoderDecoderThreadSupportFlag;
1613 #if defined(MAGICKCORE_JPEG_DELEGATE)
1614 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1615 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1617 entry->flags|=CoderDecoderSeekableStreamFlag;
1618 entry->flags^=CoderAdjoinFlag;
1619 entry->flags^=CoderUseExtensionFlag;
1620 if (*version != '\0')
1621 entry->version=ConstantString(version);
1622 entry->mime_type=ConstantString("image/jpeg");
1623 (void) RegisterMagickInfo(entry);
1624 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1625 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1626 entry->flags^=CoderDecoderThreadSupportFlag;
1628 #if defined(MAGICKCORE_JPEG_DELEGATE)
1629 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1630 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1632 entry->flags|=CoderDecoderSeekableStreamFlag;
1633 entry->flags^=CoderAdjoinFlag;
1634 entry->flags^=CoderUseExtensionFlag;
1635 if (*version != '\0')
1636 entry->version=ConstantString(version);
1637 entry->mime_type=ConstantString("image/jpeg");
1638 (void) RegisterMagickInfo(entry);
1639 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1640 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1641 entry->flags^=CoderDecoderThreadSupportFlag;
1643 #if defined(MAGICKCORE_JPEG_DELEGATE)
1644 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1645 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1647 entry->flags|=CoderDecoderSeekableStreamFlag;
1648 entry->flags^=CoderAdjoinFlag;
1649 entry->flags^=CoderUseExtensionFlag;
1650 if (*version != '\0')
1651 entry->version=ConstantString(version);
1652 entry->mime_type=ConstantString("image/jpeg");
1653 (void) RegisterMagickInfo(entry);
1654 return(MagickImageCoderSignature);
1658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1662 % U n r e g i s t e r J P E G I m a g e %
1666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668 % UnregisterJPEGImage() removes format registrations made by the
1669 % JPEG module from the list of supported formats.
1671 % The format of the UnregisterJPEGImage method is:
1673 % UnregisterJPEGImage(void)
1676 ModuleExport void UnregisterJPEGImage(void)
1678 (void) UnregisterMagickInfo("PJPG");
1679 (void) UnregisterMagickInfo("JPS");
1680 (void) UnregisterMagickInfo("JPG");
1681 (void) UnregisterMagickInfo("JPEG");
1682 (void) UnregisterMagickInfo("JPE");
1685 #if defined(MAGICKCORE_JPEG_DELEGATE)
1687 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691 % W r i t e J P E G I m a g e %
1695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697 % WriteJPEGImage() writes a JPEG image file and returns it. It
1698 % allocates the memory necessary for the new Image structure and returns a
1699 % pointer to the new image.
1701 % The format of the WriteJPEGImage method is:
1703 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1704 % Image *image,ExceptionInfo *exception)
1706 % A description of each parameter follows:
1708 % o image_info: the image info.
1710 % o jpeg_image: The image.
1712 % o exception: return any errors or warnings in this structure.
1716 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1718 assert(table != (QuantizationTable *) NULL);
1719 if (table->slot != (char *) NULL)
1720 table->slot=DestroyString(table->slot);
1721 if (table->description != (char *) NULL)
1722 table->description=DestroyString(table->description);
1723 if (table->levels != (unsigned int *) NULL)
1724 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1725 table=(QuantizationTable *) RelinquishMagickMemory(table);
1729 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1734 destination=(DestinationManager *) cinfo->dest;
1735 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1736 MaxBufferExtent,destination->buffer);
1737 if (destination->manager.free_in_buffer != MaxBufferExtent)
1738 ERREXIT(cinfo,JERR_FILE_WRITE);
1739 destination->manager.next_output_byte=destination->buffer;
1743 static QuantizationTable *GetQuantizationTable(const char *filename,
1744 const char *slot,ExceptionInfo *exception)
1772 *quantization_tables,
1775 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1776 "Loading quantization tables \"%s\" ...",filename);
1777 table=(QuantizationTable *) NULL;
1778 xml=FileToString(filename,~0UL,exception);
1779 if (xml == (char *) NULL)
1781 quantization_tables=NewXMLTree(xml,exception);
1782 if (quantization_tables == (XMLTreeInfo *) NULL)
1784 xml=DestroyString(xml);
1787 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1788 table_iterator != (XMLTreeInfo *) NULL;
1789 table_iterator=GetNextXMLTreeTag(table_iterator))
1791 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1792 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1794 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1795 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1798 if (table_iterator == (XMLTreeInfo *) NULL)
1800 xml=DestroyString(xml);
1803 description=GetXMLTreeChild(table_iterator,"description");
1804 if (description == (XMLTreeInfo *) NULL)
1806 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1807 "XmlMissingElement","<description>, slot \"%s\"",slot);
1808 quantization_tables=DestroyXMLTree(quantization_tables);
1809 xml=DestroyString(xml);
1812 levels=GetXMLTreeChild(table_iterator,"levels");
1813 if (levels == (XMLTreeInfo *) NULL)
1815 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1816 "XmlMissingElement","<levels>, slot \"%s\"",slot);
1817 quantization_tables=DestroyXMLTree(quantization_tables);
1818 xml=DestroyString(xml);
1821 table=(QuantizationTable *) AcquireCriticalMemory(sizeof(*table));
1822 table->slot=(char *) NULL;
1823 table->description=(char *) NULL;
1824 table->levels=(unsigned int *) NULL;
1825 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1826 if (attribute != (char *) NULL)
1827 table->slot=ConstantString(attribute);
1828 content=GetXMLTreeContent(description);
1829 if (content != (char *) NULL)
1830 table->description=ConstantString(content);
1831 attribute=GetXMLTreeAttribute(levels,"width");
1832 if (attribute == (char *) NULL)
1834 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1835 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1836 quantization_tables=DestroyXMLTree(quantization_tables);
1837 table=DestroyQuantizationTable(table);
1838 xml=DestroyString(xml);
1841 table->width=StringToUnsignedLong(attribute);
1842 if (table->width == 0)
1844 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1845 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1846 quantization_tables=DestroyXMLTree(quantization_tables);
1847 table=DestroyQuantizationTable(table);
1848 xml=DestroyString(xml);
1851 attribute=GetXMLTreeAttribute(levels,"height");
1852 if (attribute == (char *) NULL)
1854 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1855 "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1856 quantization_tables=DestroyXMLTree(quantization_tables);
1857 table=DestroyQuantizationTable(table);
1858 xml=DestroyString(xml);
1861 table->height=StringToUnsignedLong(attribute);
1862 if (table->height == 0)
1864 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1865 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1866 quantization_tables=DestroyXMLTree(quantization_tables);
1867 table=DestroyQuantizationTable(table);
1868 xml=DestroyString(xml);
1871 attribute=GetXMLTreeAttribute(levels,"divisor");
1872 if (attribute == (char *) NULL)
1874 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1875 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1876 quantization_tables=DestroyXMLTree(quantization_tables);
1877 table=DestroyQuantizationTable(table);
1878 xml=DestroyString(xml);
1881 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1882 if (table->divisor == 0.0)
1884 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1885 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1886 quantization_tables=DestroyXMLTree(quantization_tables);
1887 table=DestroyQuantizationTable(table);
1888 xml=DestroyString(xml);
1891 content=GetXMLTreeContent(levels);
1892 if (content == (char *) NULL)
1894 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1895 "XmlMissingContent","<levels>, table \"%s\"",slot);
1896 quantization_tables=DestroyXMLTree(quantization_tables);
1897 table=DestroyQuantizationTable(table);
1898 xml=DestroyString(xml);
1901 length=(size_t) table->width*table->height;
1904 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1905 sizeof(*table->levels));
1906 if (table->levels == (unsigned int *) NULL)
1907 ThrowFatalException(ResourceLimitFatalError,
1908 "UnableToAcquireQuantizationTable");
1909 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1911 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1912 table->divisor+0.5);
1913 while (isspace((int) ((unsigned char) *p)) != 0)
1919 value=InterpretLocaleValue(content,&p);
1923 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1924 "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1925 quantization_tables=DestroyXMLTree(quantization_tables);
1926 table=DestroyQuantizationTable(table);
1927 xml=DestroyString(xml);
1930 for (j=i; j < 64; j++)
1931 table->levels[j]=table->levels[j-1];
1932 quantization_tables=DestroyXMLTree(quantization_tables);
1933 xml=DestroyString(xml);
1937 static void InitializeDestination(j_compress_ptr cinfo)
1942 destination=(DestinationManager *) cinfo->dest;
1943 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1944 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1945 destination->manager.next_output_byte=destination->buffer;
1946 destination->manager.free_in_buffer=MaxBufferExtent;
1949 static void TerminateDestination(j_compress_ptr cinfo)
1954 destination=(DestinationManager *) cinfo->dest;
1955 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1960 count=WriteBlob(destination->image,MaxBufferExtent-
1961 destination->manager.free_in_buffer,destination->buffer);
1962 if (count != (ssize_t)
1963 (MaxBufferExtent-destination->manager.free_in_buffer))
1964 ERREXIT(cinfo,JERR_FILE_WRITE);
1968 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1969 ExceptionInfo *exception)
1991 Save image profile as a APP marker.
1994 custom_profile=AcquireStringInfo(65535L);
1995 ResetImageProfileIterator(image);
1996 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1998 profile=GetImageProfile(image,name);
1999 if (LocaleCompare(name,"EXIF") == 0)
2001 length=GetStringInfoLength(profile);
2002 if (length > 65533L)
2004 (void) ThrowMagickException(exception,GetMagickModule(),
2005 CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
2009 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
2010 (unsigned int) length);
2012 if (LocaleCompare(name,"ICC") == 0)
2014 register unsigned char
2017 tag_length=strlen(ICC_PROFILE);
2018 p=GetStringInfoDatum(custom_profile);
2019 (void) memcpy(p,ICC_PROFILE,tag_length);
2021 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
2023 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
2024 p[12]=(unsigned char) ((i/65519L)+1);
2025 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
2026 (void) memcpy(p+tag_length+3,GetStringInfoDatum(profile)+i,
2028 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
2029 custom_profile),(unsigned int) (length+tag_length+3));
2032 if (((LocaleCompare(name,"IPTC") == 0) ||
2033 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
2035 register unsigned char
2042 p=GetStringInfoDatum(custom_profile);
2043 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
2045 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
2046 roundup=(size_t) (length & 0x01);
2047 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
2049 (void) memcpy(p,"Photoshop 3.0 ",14);
2054 (void) memcpy(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2056 p[24]=(unsigned char) (length >> 8);
2057 p[25]=(unsigned char) (length & 0xff);
2060 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2062 p[length+tag_length]='\0';
2063 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2064 custom_profile),(unsigned int) (length+tag_length+roundup));
2067 if (LocaleCompare(name,"XMP") == 0)
2073 Add namespace to XMP profile.
2075 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2076 if (xmp_profile != (StringInfo *) NULL)
2078 if (profile != (StringInfo *) NULL)
2079 ConcatenateStringInfo(xmp_profile,profile);
2080 GetStringInfoDatum(xmp_profile)[28]='\0';
2081 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2083 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2084 jpeg_write_marker(jpeg_info,XML_MARKER,
2085 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2087 xmp_profile=DestroyStringInfo(xmp_profile);
2090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2091 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2092 name=GetNextImageProfile(image);
2094 custom_profile=DestroyStringInfo(custom_profile);
2097 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2102 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2103 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2104 destination=(DestinationManager *) cinfo->dest;
2105 destination->manager.init_destination=InitializeDestination;
2106 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2107 destination->manager.term_destination=TerminateDestination;
2108 destination->image=image;
2111 static char **SamplingFactorToList(const char *text)
2125 if (text == (char *) NULL)
2126 return((char **) NULL);
2128 Convert string to an ASCII list.
2130 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2132 if (textlist == (char **) NULL)
2133 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2135 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2137 for (q=(char *) p; *q != '\0'; q++)
2140 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2141 sizeof(*textlist[i]));
2142 if (textlist[i] == (char *) NULL)
2143 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2144 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2151 for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2152 textlist[i]=ConstantString("1x1");
2156 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2157 Image *image,ExceptionInfo *exception)
2168 *volatile volatile_image;
2175 *volatile jpeg_pixels;
2195 struct jpeg_compress_struct
2198 struct jpeg_error_mgr
2207 assert(image_info != (const ImageInfo *) NULL);
2208 assert(image_info->signature == MagickCoreSignature);
2209 assert(image != (Image *) NULL);
2210 assert(image->signature == MagickCoreSignature);
2211 if (image->debug != MagickFalse)
2212 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2213 assert(exception != (ExceptionInfo *) NULL);
2214 assert(exception->signature == MagickCoreSignature);
2215 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2216 (image->next != (Image *) NULL))
2217 image=AppendImages(image,MagickFalse,exception);
2218 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2219 if (status == MagickFalse)
2222 Initialize JPEG parameters.
2224 (void) memset(&error_manager,0,sizeof(error_manager));
2225 (void) memset(&jpeg_info,0,sizeof(jpeg_info));
2226 (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2227 volatile_image=image;
2228 jpeg_info.client_data=(void *) volatile_image;
2229 jpeg_info.err=jpeg_std_error(&jpeg_error);
2230 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2231 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2232 error_manager.exception=exception;
2233 error_manager.image=volatile_image;
2234 memory_info=(MemoryInfo *) NULL;
2235 if (setjmp(error_manager.error_recovery) != 0)
2237 jpeg_destroy_compress(&jpeg_info);
2238 (void) CloseBlob(volatile_image);
2239 return(MagickFalse);
2241 jpeg_info.client_data=(void *) &error_manager;
2242 jpeg_create_compress(&jpeg_info);
2243 JPEGDestinationManager(&jpeg_info,image);
2244 if ((image->columns != (unsigned int) image->columns) ||
2245 (image->rows != (unsigned int) image->rows))
2246 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2247 jpeg_info.image_width=(unsigned int) image->columns;
2248 jpeg_info.image_height=(unsigned int) image->rows;
2249 jpeg_info.input_components=3;
2250 jpeg_info.data_precision=8;
2251 jpeg_info.in_color_space=JCS_RGB;
2252 switch (image->colorspace)
2254 case CMYKColorspace:
2256 jpeg_info.input_components=4;
2257 jpeg_info.in_color_space=JCS_CMYK;
2260 case YCbCrColorspace:
2261 case Rec601YCbCrColorspace:
2262 case Rec709YCbCrColorspace:
2264 jpeg_info.in_color_space=JCS_YCbCr;
2267 case LinearGRAYColorspace:
2268 case GRAYColorspace:
2270 if (image_info->type == TrueColorType)
2272 jpeg_info.input_components=1;
2273 jpeg_info.in_color_space=JCS_GRAYSCALE;
2278 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2279 if (image_info->type == TrueColorType)
2281 if (SetImageGray(image,exception) != MagickFalse)
2283 jpeg_info.input_components=1;
2284 jpeg_info.in_color_space=JCS_GRAYSCALE;
2289 jpeg_set_defaults(&jpeg_info);
2290 if (jpeg_info.in_color_space == JCS_CMYK)
2291 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2292 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2293 jpeg_info.data_precision=8;
2295 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2296 if (image->debug != MagickFalse)
2297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2298 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2299 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2302 Set image resolution.
2304 jpeg_info.write_JFIF_header=TRUE;
2305 jpeg_info.X_density=(UINT16) image->resolution.x;
2306 jpeg_info.Y_density=(UINT16) image->resolution.y;
2308 Set image resolution units.
2310 if (image->units == PixelsPerInchResolution)
2311 jpeg_info.density_unit=(UINT8) 1;
2312 if (image->units == PixelsPerCentimeterResolution)
2313 jpeg_info.density_unit=(UINT8) 2;
2315 jpeg_info.dct_method=JDCT_FLOAT;
2316 option=GetImageOption(image_info,"jpeg:dct-method");
2317 if (option != (const char *) NULL)
2323 if (LocaleCompare(option,"default") == 0)
2324 jpeg_info.dct_method=JDCT_DEFAULT;
2330 if (LocaleCompare(option,"fastest") == 0)
2331 jpeg_info.dct_method=JDCT_FASTEST;
2332 if (LocaleCompare(option,"float") == 0)
2333 jpeg_info.dct_method=JDCT_FLOAT;
2339 if (LocaleCompare(option,"ifast") == 0)
2340 jpeg_info.dct_method=JDCT_IFAST;
2341 if (LocaleCompare(option,"islow") == 0)
2342 jpeg_info.dct_method=JDCT_ISLOW;
2346 option=GetImageOption(image_info,"jpeg:optimize-coding");
2347 if (option != (const char *) NULL)
2348 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2355 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2356 image->rows*sizeof(JSAMPLE);
2357 if (length == (MagickSizeType) ((size_t) length))
2360 Perform optimization only if available memory resources permit it.
2362 status=AcquireMagickResource(MemoryResource,length);
2363 if (status != MagickFalse)
2364 RelinquishMagickResource(MemoryResource,length);
2365 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2368 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2369 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2370 (image_info->interlace != NoInterlace))
2372 if (image->debug != MagickFalse)
2373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2374 "Interlace: progressive");
2375 jpeg_simple_progression(&jpeg_info);
2378 if (image->debug != MagickFalse)
2379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2380 "Interlace: non-progressive");
2382 if (image->debug != MagickFalse)
2383 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2384 "Interlace: nonprogressive");
2387 if ((image_info->compression != LosslessJPEGCompression) &&
2388 (image->quality <= 100))
2390 if (image->quality != UndefinedCompressionQuality)
2391 quality=(int) image->quality;
2392 if (image->debug != MagickFalse)
2393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2394 (double) image->quality);
2398 #if !defined(C_LOSSLESS_SUPPORTED)
2400 if (image->debug != MagickFalse)
2401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2403 if (image->quality < 100)
2404 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2405 "LosslessToLossyJPEGConversion","`%s'",image->filename);
2412 predictor=image->quality/100; /* range 1-7 */
2413 point_transform=image->quality % 20; /* range 0-15 */
2414 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2415 if (image->debug != MagickFalse)
2417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2418 "Compression: lossless");
2419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2420 "Predictor: %d",predictor);
2421 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2422 "Point Transform: %d",point_transform);
2427 option=GetImageOption(image_info,"jpeg:extent");
2428 if (option != (const char *) NULL)
2436 extent_info=CloneImageInfo(image_info);
2437 extent_info->blob=NULL;
2438 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2439 if (jpeg_image != (Image *) NULL)
2449 Search for compression quality that does not exceed image extent.
2451 extent_info->quality=0;
2452 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2453 (void) DeleteImageOption(extent_info,"jpeg:extent");
2454 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2455 maximum=image_info->quality;
2458 for (minimum=2; minimum < maximum; )
2460 (void) AcquireUniqueFilename(jpeg_image->filename);
2461 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2462 status=WriteJPEGImage(extent_info,jpeg_image,exception);
2463 if (GetBlobSize(jpeg_image) <= extent)
2464 minimum=jpeg_image->quality+1;
2466 maximum=jpeg_image->quality-1;
2467 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2469 quality=(int) minimum-1;
2470 jpeg_image=DestroyImage(jpeg_image);
2472 extent_info=DestroyImageInfo(extent_info);
2474 jpeg_set_quality(&jpeg_info,quality,TRUE);
2475 #if (JPEG_LIB_VERSION >= 70)
2476 option=GetImageOption(image_info,"quality");
2477 if (option != (const char *) NULL)
2486 Set quality scaling for luminance and chrominance separately.
2488 flags=ParseGeometry(option,&geometry_info);
2489 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2491 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2492 (geometry_info.rho+0.5));
2493 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2494 (geometry_info.sigma+0.5));
2495 jpeg_default_qtables(&jpeg_info,TRUE);
2499 colorspace=jpeg_info.in_color_space;
2500 value=GetImageOption(image_info,"jpeg:colorspace");
2501 if (value == (char *) NULL)
2502 value=GetImageProperty(image,"jpeg:colorspace",exception);
2503 if (value != (char *) NULL)
2504 colorspace=StringToInteger(value);
2505 sampling_factor=(const char *) NULL;
2506 if (colorspace == jpeg_info.in_color_space)
2508 value=GetImageOption(image_info,"jpeg:sampling-factor");
2509 if (value == (char *) NULL)
2510 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2511 if (value != (char *) NULL)
2513 sampling_factor=value;
2514 if (image->debug != MagickFalse)
2515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2516 " Input sampling-factors=%s",sampling_factor);
2519 value=GetImageOption(image_info,"jpeg:sampling-factor");
2520 if (image_info->sampling_factor != (char *) NULL)
2521 sampling_factor=image_info->sampling_factor;
2522 if (sampling_factor == (const char *) NULL)
2525 for (i=0; i < MAX_COMPONENTS; i++)
2527 jpeg_info.comp_info[i].h_samp_factor=1;
2528 jpeg_info.comp_info[i].v_samp_factor=1;
2543 Set sampling factor.
2546 factors=SamplingFactorToList(sampling_factor);
2547 if (factors != (char **) NULL)
2549 for (i=0; i < MAX_COMPONENTS; i++)
2551 if (factors[i] == (char *) NULL)
2553 flags=ParseGeometry(factors[i],&geometry_info);
2554 if ((flags & SigmaValue) == 0)
2555 geometry_info.sigma=geometry_info.rho;
2556 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2557 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2558 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2560 factors=(char **) RelinquishMagickMemory(factors);
2562 for ( ; i < MAX_COMPONENTS; i++)
2564 jpeg_info.comp_info[i].h_samp_factor=1;
2565 jpeg_info.comp_info[i].v_samp_factor=1;
2568 option=GetImageOption(image_info,"jpeg:q-table");
2569 if (option != (const char *) NULL)
2575 Custom quantization tables.
2577 table=GetQuantizationTable(option,"0",exception);
2578 if (table != (QuantizationTable *) NULL)
2580 for (i=0; i < MAX_COMPONENTS; i++)
2581 jpeg_info.comp_info[i].quant_tbl_no=0;
2582 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2583 jpeg_quality_scaling(quality),0);
2584 table=DestroyQuantizationTable(table);
2586 table=GetQuantizationTable(option,"1",exception);
2587 if (table != (QuantizationTable *) NULL)
2589 for (i=1; i < MAX_COMPONENTS; i++)
2590 jpeg_info.comp_info[i].quant_tbl_no=1;
2591 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2592 jpeg_quality_scaling(quality),0);
2593 table=DestroyQuantizationTable(table);
2595 table=GetQuantizationTable(option,"2",exception);
2596 if (table != (QuantizationTable *) NULL)
2598 for (i=2; i < MAX_COMPONENTS; i++)
2599 jpeg_info.comp_info[i].quant_tbl_no=2;
2600 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2601 jpeg_quality_scaling(quality),0);
2602 table=DestroyQuantizationTable(table);
2604 table=GetQuantizationTable(option,"3",exception);
2605 if (table != (QuantizationTable *) NULL)
2607 for (i=3; i < MAX_COMPONENTS; i++)
2608 jpeg_info.comp_info[i].quant_tbl_no=3;
2609 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2610 jpeg_quality_scaling(quality),0);
2611 table=DestroyQuantizationTable(table);
2614 jpeg_start_compress(&jpeg_info,TRUE);
2615 if (image->debug != MagickFalse)
2617 if (image->storage_class == PseudoClass)
2618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2619 "Storage class: PseudoClass");
2621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2622 "Storage class: DirectClass");
2623 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2624 (double) image->depth);
2625 if (image->colors != 0)
2626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2627 "Number of colors: %.20g",(double) image->colors);
2629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2630 "Number of colors: unspecified");
2631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2632 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2633 switch (image->colorspace)
2635 case CMYKColorspace:
2637 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2638 "Storage class: DirectClass");
2639 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2640 "Colorspace: CMYK");
2643 case YCbCrColorspace:
2644 case Rec601YCbCrColorspace:
2645 case Rec709YCbCrColorspace:
2647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2648 "Colorspace: YCbCr");
2654 switch (image->colorspace)
2656 case CMYKColorspace:
2658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2659 "Colorspace: CMYK");
2660 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2661 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2662 jpeg_info.comp_info[0].h_samp_factor,
2663 jpeg_info.comp_info[0].v_samp_factor,
2664 jpeg_info.comp_info[1].h_samp_factor,
2665 jpeg_info.comp_info[1].v_samp_factor,
2666 jpeg_info.comp_info[2].h_samp_factor,
2667 jpeg_info.comp_info[2].v_samp_factor,
2668 jpeg_info.comp_info[3].h_samp_factor,
2669 jpeg_info.comp_info[3].v_samp_factor);
2672 case GRAYColorspace:
2674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2675 "Colorspace: GRAY");
2676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2677 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2678 jpeg_info.comp_info[0].v_samp_factor);
2681 case sRGBColorspace:
2684 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2685 "Image colorspace is RGB");
2686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2687 "Sampling factors: %dx%d,%dx%d,%dx%d",
2688 jpeg_info.comp_info[0].h_samp_factor,
2689 jpeg_info.comp_info[0].v_samp_factor,
2690 jpeg_info.comp_info[1].h_samp_factor,
2691 jpeg_info.comp_info[1].v_samp_factor,
2692 jpeg_info.comp_info[2].h_samp_factor,
2693 jpeg_info.comp_info[2].v_samp_factor);
2696 case YCbCrColorspace:
2697 case Rec601YCbCrColorspace:
2698 case Rec709YCbCrColorspace:
2700 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2701 "Colorspace: YCbCr");
2702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2703 "Sampling factors: %dx%d,%dx%d,%dx%d",
2704 jpeg_info.comp_info[0].h_samp_factor,
2705 jpeg_info.comp_info[0].v_samp_factor,
2706 jpeg_info.comp_info[1].h_samp_factor,
2707 jpeg_info.comp_info[1].v_samp_factor,
2708 jpeg_info.comp_info[2].h_samp_factor,
2709 jpeg_info.comp_info[2].v_samp_factor);
2714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2717 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2718 jpeg_info.comp_info[0].h_samp_factor,
2719 jpeg_info.comp_info[0].v_samp_factor,
2720 jpeg_info.comp_info[1].h_samp_factor,
2721 jpeg_info.comp_info[1].v_samp_factor,
2722 jpeg_info.comp_info[2].h_samp_factor,
2723 jpeg_info.comp_info[2].v_samp_factor,
2724 jpeg_info.comp_info[3].h_samp_factor,
2725 jpeg_info.comp_info[3].v_samp_factor);
2731 Write JPEG profiles.
2733 value=GetImageProperty(image,"comment",exception);
2734 if (value != (char *) NULL)
2735 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2736 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2737 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2738 if (image->profiles != (void *) NULL)
2739 WriteProfile(&jpeg_info,image,exception);
2741 Convert MIFF to JPEG raster pixels.
2743 memory_info=AcquireVirtualMemory((size_t) image->columns,
2744 jpeg_info.input_components*sizeof(*jpeg_pixels));
2745 if (memory_info == (MemoryInfo *) NULL)
2746 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2747 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2748 if (setjmp(error_manager.error_recovery) != 0)
2750 jpeg_destroy_compress(&jpeg_info);
2751 if (memory_info != (MemoryInfo *) NULL)
2752 memory_info=RelinquishVirtualMemory(memory_info);
2753 (void) CloseBlob(image);
2754 return(MagickFalse);
2756 scanline[0]=(JSAMPROW) jpeg_pixels;
2757 scale=65535/(unsigned short) GetQuantumRange((size_t)
2758 jpeg_info.data_precision);
2761 if (jpeg_info.data_precision <= 8)
2763 if ((jpeg_info.in_color_space == JCS_RGB) ||
2764 (jpeg_info.in_color_space == JCS_YCbCr))
2765 for (y=0; y < (ssize_t) image->rows; y++)
2767 register const Quantum
2773 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2774 if (p == (const Quantum *) NULL)
2777 for (x=0; x < (ssize_t) image->columns; x++)
2779 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2780 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2781 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2782 p+=GetPixelChannels(image);
2784 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2785 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2787 if (status == MagickFalse)
2791 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2792 for (y=0; y < (ssize_t) image->rows; y++)
2794 register const Quantum
2800 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2801 if (p == (const Quantum *) NULL)
2804 for (x=0; x < (ssize_t) image->columns; x++)
2806 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2808 p+=GetPixelChannels(image);
2810 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2811 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2813 if (status == MagickFalse)
2817 for (y=0; y < (ssize_t) image->rows; y++)
2819 register const Quantum
2825 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2826 if (p == (const Quantum *) NULL)
2829 for (x=0; x < (ssize_t) image->columns; x++)
2832 Convert DirectClass packets to contiguous CMYK scanlines.
2834 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2835 GetPixelCyan(image,p))));
2836 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2837 GetPixelMagenta(image,p))));
2838 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2839 GetPixelYellow(image,p))));
2840 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2841 GetPixelBlack(image,p))));
2842 p+=GetPixelChannels(image);
2844 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2845 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2847 if (status == MagickFalse)
2852 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2853 for (y=0; y < (ssize_t) image->rows; y++)
2855 register const Quantum
2861 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2862 if (p == (const Quantum *) NULL)
2865 for (x=0; x < (ssize_t) image->columns; x++)
2867 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2869 p+=GetPixelChannels(image);
2871 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2872 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2874 if (status == MagickFalse)
2878 if ((jpeg_info.in_color_space == JCS_RGB) ||
2879 (jpeg_info.in_color_space == JCS_YCbCr))
2880 for (y=0; y < (ssize_t) image->rows; y++)
2882 register const Quantum
2888 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2889 if (p == (const Quantum *) NULL)
2892 for (x=0; x < (ssize_t) image->columns; x++)
2894 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2895 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2896 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2897 p+=GetPixelChannels(image);
2899 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2900 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2902 if (status == MagickFalse)
2906 for (y=0; y < (ssize_t) image->rows; y++)
2908 register const Quantum
2914 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2915 if (p == (const Quantum *) NULL)
2918 for (x=0; x < (ssize_t) image->columns; x++)
2921 Convert DirectClass packets to contiguous CMYK scanlines.
2923 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2925 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2927 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2929 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2931 p+=GetPixelChannels(image);
2933 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2934 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2936 if (status == MagickFalse)
2939 if (y == (ssize_t) image->rows)
2940 jpeg_finish_compress(&jpeg_info);
2942 Relinquish resources.
2944 jpeg_destroy_compress(&jpeg_info);
2945 memory_info=RelinquishVirtualMemory(memory_info);
2946 (void) CloseBlob(image);