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 defined(D_ARITH_CODING_SUPPORTED)
1341 if (jpeg_info.arith_code == TRUE)
1342 (void) SetImageProperty(image,"jpeg:coding","arithmetic",exception);
1344 if (image_info->ping != MagickFalse)
1346 jpeg_destroy_decompress(&jpeg_info);
1347 (void) CloseBlob(image);
1348 return(GetFirstImageInList(image));
1350 status=SetImageExtent(image,image->columns,image->rows,exception);
1351 if (status == MagickFalse)
1353 jpeg_destroy_decompress(&jpeg_info);
1354 return(DestroyImageList(image));
1356 (void) jpeg_start_decompress(&jpeg_info);
1357 if ((jpeg_info.output_components != 1) &&
1358 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1360 jpeg_destroy_decompress(&jpeg_info);
1361 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1363 memory_info=AcquireVirtualMemory((size_t) image->columns,
1364 jpeg_info.output_components*sizeof(*jpeg_pixels));
1365 if (memory_info == (MemoryInfo *) NULL)
1367 jpeg_destroy_decompress(&jpeg_info);
1368 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1370 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1371 (void) memset(jpeg_pixels,0,image->columns*
1372 jpeg_info.output_components*sizeof(*jpeg_pixels));
1374 Convert JPEG pixels to pixel packets.
1376 if (setjmp(error_manager.error_recovery) != 0)
1378 if (memory_info != (MemoryInfo *) NULL)
1379 memory_info=RelinquishVirtualMemory(memory_info);
1380 jpeg_destroy_decompress(&jpeg_info);
1381 (void) CloseBlob(image);
1382 number_pixels=(MagickSizeType) image->columns*image->rows;
1383 if (number_pixels != 0)
1384 return(GetFirstImageInList(image));
1385 return(DestroyImage(image));
1387 if (jpeg_info.quantize_colors != 0)
1389 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1390 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1391 for (i=0; i < (ssize_t) image->colors; i++)
1393 image->colormap[i].red=(double) ScaleCharToQuantum(
1394 jpeg_info.colormap[0][i]);
1395 image->colormap[i].green=image->colormap[i].red;
1396 image->colormap[i].blue=image->colormap[i].red;
1397 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1400 for (i=0; i < (ssize_t) image->colors; i++)
1402 image->colormap[i].red=(double) ScaleCharToQuantum(
1403 jpeg_info.colormap[0][i]);
1404 image->colormap[i].green=(double) ScaleCharToQuantum(
1405 jpeg_info.colormap[1][i]);
1406 image->colormap[i].blue=(double) ScaleCharToQuantum(
1407 jpeg_info.colormap[2][i]);
1408 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1411 scanline[0]=(JSAMPROW) jpeg_pixels;
1412 for (y=0; y < (ssize_t) image->rows; y++)
1420 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1422 (void) ThrowMagickException(exception,GetMagickModule(),
1423 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1427 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1428 if (q == (Quantum *) NULL)
1430 if (jpeg_info.data_precision > 8)
1435 scale=65535/(unsigned short) GetQuantumRange((size_t)
1436 jpeg_info.data_precision);
1437 if (jpeg_info.output_components == 1)
1438 for (x=0; x < (ssize_t) image->columns; x++)
1443 pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1444 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1445 SetPixelIndex(image,index,q);
1446 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1448 q+=GetPixelChannels(image);
1451 if (image->colorspace != CMYKColorspace)
1452 for (x=0; x < (ssize_t) image->columns; x++)
1454 SetPixelRed(image,ScaleShortToQuantum(
1455 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1456 SetPixelGreen(image,ScaleShortToQuantum(
1457 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1458 SetPixelBlue(image,ScaleShortToQuantum(
1459 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1460 SetPixelAlpha(image,OpaqueAlpha,q);
1461 q+=GetPixelChannels(image);
1464 for (x=0; x < (ssize_t) image->columns; x++)
1466 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1467 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1468 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1469 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1470 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1471 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1472 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1473 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1474 SetPixelAlpha(image,OpaqueAlpha,q);
1475 q+=GetPixelChannels(image);
1479 if (jpeg_info.output_components == 1)
1480 for (x=0; x < (ssize_t) image->columns; x++)
1485 pixel=(ssize_t) GETJSAMPLE(*p);
1486 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1487 SetPixelIndex(image,index,q);
1488 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1490 q+=GetPixelChannels(image);
1493 if (image->colorspace != CMYKColorspace)
1494 for (x=0; x < (ssize_t) image->columns; x++)
1496 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1497 GETJSAMPLE(*p++)),q);
1498 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1499 GETJSAMPLE(*p++)),q);
1500 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1501 GETJSAMPLE(*p++)),q);
1502 SetPixelAlpha(image,OpaqueAlpha,q);
1503 q+=GetPixelChannels(image);
1506 for (x=0; x < (ssize_t) image->columns; x++)
1508 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1509 (unsigned char) GETJSAMPLE(*p++)),q);
1510 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1511 (unsigned char) GETJSAMPLE(*p++)),q);
1512 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1513 (unsigned char) GETJSAMPLE(*p++)),q);
1514 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1515 (unsigned char) GETJSAMPLE(*p++)),q);
1516 SetPixelAlpha(image,OpaqueAlpha,q);
1517 q+=GetPixelChannels(image);
1519 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1521 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1523 if (status == MagickFalse)
1525 jpeg_abort_decompress(&jpeg_info);
1529 if (status != MagickFalse)
1531 error_manager.finished=MagickTrue;
1532 if (setjmp(error_manager.error_recovery) == 0)
1533 (void) jpeg_finish_decompress(&jpeg_info);
1536 Free jpeg resources.
1538 jpeg_destroy_decompress(&jpeg_info);
1539 memory_info=RelinquishVirtualMemory(memory_info);
1540 (void) CloseBlob(image);
1541 return(GetFirstImageInList(image));
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 % R e g i s t e r J P E G I m a g e %
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 % RegisterJPEGImage() adds properties for the JPEG image format to
1557 % the list of supported formats. The properties include the image format
1558 % tag, a method to read and/or write the format, whether the format
1559 % supports the saving of more than one frame to the same file or blob,
1560 % whether the format supports native in-memory I/O, and a brief
1561 % description of the format.
1563 % The format of the RegisterJPEGImage method is:
1565 % size_t RegisterJPEGImage(void)
1568 ModuleExport size_t RegisterJPEGImage(void)
1570 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1571 #define JPEGStringify(macro_or_string) JPEGStringifyArg(macro_or_string)
1572 #define JPEGStringifyArg(contents) #contents
1575 version[MagickPathExtent];
1581 #if defined(LIBJPEG_TURBO_VERSION)
1582 (void) CopyMagickString(version,"libjpeg-turbo " JPEGStringify(
1583 LIBJPEG_TURBO_VERSION),MagickPathExtent);
1584 #elif defined(JPEG_LIB_VERSION)
1585 (void) FormatLocaleString(version,MagickPathExtent,"libjpeg %d",
1588 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1589 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1590 entry->flags^=CoderDecoderThreadSupportFlag;
1592 #if defined(MAGICKCORE_JPEG_DELEGATE)
1593 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1594 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1596 entry->magick=(IsImageFormatHandler *) IsJPEG;
1597 entry->flags|=CoderDecoderSeekableStreamFlag;
1598 entry->flags^=CoderAdjoinFlag;
1599 entry->flags^=CoderUseExtensionFlag;
1600 if (*version != '\0')
1601 entry->version=ConstantString(version);
1602 entry->mime_type=ConstantString("image/jpeg");
1603 (void) RegisterMagickInfo(entry);
1604 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1605 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1606 entry->flags^=CoderDecoderThreadSupportFlag;
1608 #if defined(MAGICKCORE_JPEG_DELEGATE)
1609 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1610 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1612 entry->magick=(IsImageFormatHandler *) IsJPEG;
1613 entry->flags|=CoderDecoderSeekableStreamFlag;
1614 entry->flags^=CoderAdjoinFlag;
1615 if (*version != '\0')
1616 entry->version=ConstantString(version);
1617 entry->mime_type=ConstantString("image/jpeg");
1618 (void) RegisterMagickInfo(entry);
1619 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1620 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1621 entry->flags^=CoderDecoderThreadSupportFlag;
1623 #if defined(MAGICKCORE_JPEG_DELEGATE)
1624 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1625 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1627 entry->flags|=CoderDecoderSeekableStreamFlag;
1628 entry->flags^=CoderAdjoinFlag;
1629 entry->flags^=CoderUseExtensionFlag;
1630 if (*version != '\0')
1631 entry->version=ConstantString(version);
1632 entry->mime_type=ConstantString("image/jpeg");
1633 (void) RegisterMagickInfo(entry);
1634 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1635 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1636 entry->flags^=CoderDecoderThreadSupportFlag;
1638 #if defined(MAGICKCORE_JPEG_DELEGATE)
1639 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1640 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1642 entry->flags|=CoderDecoderSeekableStreamFlag;
1643 entry->flags^=CoderAdjoinFlag;
1644 entry->flags^=CoderUseExtensionFlag;
1645 if (*version != '\0')
1646 entry->version=ConstantString(version);
1647 entry->mime_type=ConstantString("image/jpeg");
1648 (void) RegisterMagickInfo(entry);
1649 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1650 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1651 entry->flags^=CoderDecoderThreadSupportFlag;
1653 #if defined(MAGICKCORE_JPEG_DELEGATE)
1654 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1655 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1657 entry->flags|=CoderDecoderSeekableStreamFlag;
1658 entry->flags^=CoderAdjoinFlag;
1659 entry->flags^=CoderUseExtensionFlag;
1660 if (*version != '\0')
1661 entry->version=ConstantString(version);
1662 entry->mime_type=ConstantString("image/jpeg");
1663 (void) RegisterMagickInfo(entry);
1664 return(MagickImageCoderSignature);
1668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 % U n r e g i s t e r J P E G I m a g e %
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678 % UnregisterJPEGImage() removes format registrations made by the
1679 % JPEG module from the list of supported formats.
1681 % The format of the UnregisterJPEGImage method is:
1683 % UnregisterJPEGImage(void)
1686 ModuleExport void UnregisterJPEGImage(void)
1688 (void) UnregisterMagickInfo("PJPG");
1689 (void) UnregisterMagickInfo("JPS");
1690 (void) UnregisterMagickInfo("JPG");
1691 (void) UnregisterMagickInfo("JPEG");
1692 (void) UnregisterMagickInfo("JPE");
1695 #if defined(MAGICKCORE_JPEG_DELEGATE)
1697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701 % W r i t e J P E G I m a g e %
1705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707 % WriteJPEGImage() writes a JPEG image file and returns it. It
1708 % allocates the memory necessary for the new Image structure and returns a
1709 % pointer to the new image.
1711 % The format of the WriteJPEGImage method is:
1713 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1714 % Image *image,ExceptionInfo *exception)
1716 % A description of each parameter follows:
1718 % o image_info: the image info.
1720 % o jpeg_image: The image.
1722 % o exception: return any errors or warnings in this structure.
1726 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1728 assert(table != (QuantizationTable *) NULL);
1729 if (table->slot != (char *) NULL)
1730 table->slot=DestroyString(table->slot);
1731 if (table->description != (char *) NULL)
1732 table->description=DestroyString(table->description);
1733 if (table->levels != (unsigned int *) NULL)
1734 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1735 table=(QuantizationTable *) RelinquishMagickMemory(table);
1739 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1744 destination=(DestinationManager *) cinfo->dest;
1745 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1746 MaxBufferExtent,destination->buffer);
1747 if (destination->manager.free_in_buffer != MaxBufferExtent)
1748 ERREXIT(cinfo,JERR_FILE_WRITE);
1749 destination->manager.next_output_byte=destination->buffer;
1753 static QuantizationTable *GetQuantizationTable(const char *filename,
1754 const char *slot,ExceptionInfo *exception)
1782 *quantization_tables,
1785 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1786 "Loading quantization tables \"%s\" ...",filename);
1787 table=(QuantizationTable *) NULL;
1788 xml=FileToString(filename,~0UL,exception);
1789 if (xml == (char *) NULL)
1791 quantization_tables=NewXMLTree(xml,exception);
1792 if (quantization_tables == (XMLTreeInfo *) NULL)
1794 xml=DestroyString(xml);
1797 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1798 table_iterator != (XMLTreeInfo *) NULL;
1799 table_iterator=GetNextXMLTreeTag(table_iterator))
1801 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1802 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1804 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1805 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1808 if (table_iterator == (XMLTreeInfo *) NULL)
1810 xml=DestroyString(xml);
1813 description=GetXMLTreeChild(table_iterator,"description");
1814 if (description == (XMLTreeInfo *) NULL)
1816 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1817 "XmlMissingElement","<description>, slot \"%s\"",slot);
1818 quantization_tables=DestroyXMLTree(quantization_tables);
1819 xml=DestroyString(xml);
1822 levels=GetXMLTreeChild(table_iterator,"levels");
1823 if (levels == (XMLTreeInfo *) NULL)
1825 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1826 "XmlMissingElement","<levels>, slot \"%s\"",slot);
1827 quantization_tables=DestroyXMLTree(quantization_tables);
1828 xml=DestroyString(xml);
1831 table=(QuantizationTable *) AcquireCriticalMemory(sizeof(*table));
1832 table->slot=(char *) NULL;
1833 table->description=(char *) NULL;
1834 table->levels=(unsigned int *) NULL;
1835 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1836 if (attribute != (char *) NULL)
1837 table->slot=ConstantString(attribute);
1838 content=GetXMLTreeContent(description);
1839 if (content != (char *) NULL)
1840 table->description=ConstantString(content);
1841 attribute=GetXMLTreeAttribute(levels,"width");
1842 if (attribute == (char *) NULL)
1844 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1845 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1846 quantization_tables=DestroyXMLTree(quantization_tables);
1847 table=DestroyQuantizationTable(table);
1848 xml=DestroyString(xml);
1851 table->width=StringToUnsignedLong(attribute);
1852 if (table->width == 0)
1854 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1855 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1856 quantization_tables=DestroyXMLTree(quantization_tables);
1857 table=DestroyQuantizationTable(table);
1858 xml=DestroyString(xml);
1861 attribute=GetXMLTreeAttribute(levels,"height");
1862 if (attribute == (char *) NULL)
1864 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1865 "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1866 quantization_tables=DestroyXMLTree(quantization_tables);
1867 table=DestroyQuantizationTable(table);
1868 xml=DestroyString(xml);
1871 table->height=StringToUnsignedLong(attribute);
1872 if (table->height == 0)
1874 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1875 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1876 quantization_tables=DestroyXMLTree(quantization_tables);
1877 table=DestroyQuantizationTable(table);
1878 xml=DestroyString(xml);
1881 attribute=GetXMLTreeAttribute(levels,"divisor");
1882 if (attribute == (char *) NULL)
1884 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1885 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1886 quantization_tables=DestroyXMLTree(quantization_tables);
1887 table=DestroyQuantizationTable(table);
1888 xml=DestroyString(xml);
1891 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1892 if (table->divisor == 0.0)
1894 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1895 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1896 quantization_tables=DestroyXMLTree(quantization_tables);
1897 table=DestroyQuantizationTable(table);
1898 xml=DestroyString(xml);
1901 content=GetXMLTreeContent(levels);
1902 if (content == (char *) NULL)
1904 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1905 "XmlMissingContent","<levels>, table \"%s\"",slot);
1906 quantization_tables=DestroyXMLTree(quantization_tables);
1907 table=DestroyQuantizationTable(table);
1908 xml=DestroyString(xml);
1911 length=(size_t) table->width*table->height;
1914 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1915 sizeof(*table->levels));
1916 if (table->levels == (unsigned int *) NULL)
1917 ThrowFatalException(ResourceLimitFatalError,
1918 "UnableToAcquireQuantizationTable");
1919 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1921 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1922 table->divisor+0.5);
1923 while (isspace((int) ((unsigned char) *p)) != 0)
1929 value=InterpretLocaleValue(content,&p);
1933 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1934 "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1935 quantization_tables=DestroyXMLTree(quantization_tables);
1936 table=DestroyQuantizationTable(table);
1937 xml=DestroyString(xml);
1940 for (j=i; j < 64; j++)
1941 table->levels[j]=table->levels[j-1];
1942 quantization_tables=DestroyXMLTree(quantization_tables);
1943 xml=DestroyString(xml);
1947 static void InitializeDestination(j_compress_ptr cinfo)
1952 destination=(DestinationManager *) cinfo->dest;
1953 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1954 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1955 destination->manager.next_output_byte=destination->buffer;
1956 destination->manager.free_in_buffer=MaxBufferExtent;
1959 static void TerminateDestination(j_compress_ptr cinfo)
1964 destination=(DestinationManager *) cinfo->dest;
1965 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1970 count=WriteBlob(destination->image,MaxBufferExtent-
1971 destination->manager.free_in_buffer,destination->buffer);
1972 if (count != (ssize_t)
1973 (MaxBufferExtent-destination->manager.free_in_buffer))
1974 ERREXIT(cinfo,JERR_FILE_WRITE);
1978 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1979 ExceptionInfo *exception)
2001 Save image profile as a APP marker.
2004 custom_profile=AcquireStringInfo(65535L);
2005 ResetImageProfileIterator(image);
2006 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2008 profile=GetImageProfile(image,name);
2009 if (LocaleCompare(name,"EXIF") == 0)
2011 length=GetStringInfoLength(profile);
2012 if (length > 65533L)
2014 (void) ThrowMagickException(exception,GetMagickModule(),
2015 CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
2019 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
2020 (unsigned int) length);
2022 if (LocaleCompare(name,"ICC") == 0)
2024 register unsigned char
2027 tag_length=strlen(ICC_PROFILE);
2028 p=GetStringInfoDatum(custom_profile);
2029 (void) memcpy(p,ICC_PROFILE,tag_length);
2031 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
2033 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
2034 p[12]=(unsigned char) ((i/65519L)+1);
2035 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
2036 (void) memcpy(p+tag_length+3,GetStringInfoDatum(profile)+i,
2038 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
2039 custom_profile),(unsigned int) (length+tag_length+3));
2042 if (((LocaleCompare(name,"IPTC") == 0) ||
2043 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
2045 register unsigned char
2052 p=GetStringInfoDatum(custom_profile);
2053 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
2055 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
2056 roundup=(size_t) (length & 0x01);
2057 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
2059 (void) memcpy(p,"Photoshop 3.0 ",14);
2064 (void) memcpy(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2066 p[24]=(unsigned char) (length >> 8);
2067 p[25]=(unsigned char) (length & 0xff);
2070 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2072 p[length+tag_length]='\0';
2073 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2074 custom_profile),(unsigned int) (length+tag_length+roundup));
2077 if (LocaleCompare(name,"XMP") == 0)
2083 Add namespace to XMP profile.
2085 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2086 if (xmp_profile != (StringInfo *) NULL)
2088 if (profile != (StringInfo *) NULL)
2089 ConcatenateStringInfo(xmp_profile,profile);
2090 GetStringInfoDatum(xmp_profile)[28]='\0';
2091 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2093 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2094 jpeg_write_marker(jpeg_info,XML_MARKER,
2095 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2097 xmp_profile=DestroyStringInfo(xmp_profile);
2100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2101 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2102 name=GetNextImageProfile(image);
2104 custom_profile=DestroyStringInfo(custom_profile);
2107 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2112 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2113 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2114 destination=(DestinationManager *) cinfo->dest;
2115 destination->manager.init_destination=InitializeDestination;
2116 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2117 destination->manager.term_destination=TerminateDestination;
2118 destination->image=image;
2121 static char **SamplingFactorToList(const char *text)
2135 if (text == (char *) NULL)
2136 return((char **) NULL);
2138 Convert string to an ASCII list.
2140 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2142 if (textlist == (char **) NULL)
2143 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2145 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2147 for (q=(char *) p; *q != '\0'; q++)
2150 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2151 sizeof(*textlist[i]));
2152 if (textlist[i] == (char *) NULL)
2153 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2154 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2161 for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2162 textlist[i]=ConstantString("1x1");
2166 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2167 Image *image,ExceptionInfo *exception)
2178 *volatile volatile_image;
2185 *volatile jpeg_pixels;
2205 struct jpeg_compress_struct
2208 struct jpeg_error_mgr
2217 assert(image_info != (const ImageInfo *) NULL);
2218 assert(image_info->signature == MagickCoreSignature);
2219 assert(image != (Image *) NULL);
2220 assert(image->signature == MagickCoreSignature);
2221 if (image->debug != MagickFalse)
2222 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2223 assert(exception != (ExceptionInfo *) NULL);
2224 assert(exception->signature == MagickCoreSignature);
2225 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2226 (image->next != (Image *) NULL))
2227 image=AppendImages(image,MagickFalse,exception);
2228 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2229 if (status == MagickFalse)
2232 Initialize JPEG parameters.
2234 (void) memset(&error_manager,0,sizeof(error_manager));
2235 (void) memset(&jpeg_info,0,sizeof(jpeg_info));
2236 (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2237 volatile_image=image;
2238 jpeg_info.client_data=(void *) volatile_image;
2239 jpeg_info.err=jpeg_std_error(&jpeg_error);
2240 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2241 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2242 error_manager.exception=exception;
2243 error_manager.image=volatile_image;
2244 memory_info=(MemoryInfo *) NULL;
2245 if (setjmp(error_manager.error_recovery) != 0)
2247 jpeg_destroy_compress(&jpeg_info);
2248 (void) CloseBlob(volatile_image);
2249 return(MagickFalse);
2251 jpeg_info.client_data=(void *) &error_manager;
2252 jpeg_create_compress(&jpeg_info);
2253 JPEGDestinationManager(&jpeg_info,image);
2254 if ((image->columns != (unsigned int) image->columns) ||
2255 (image->rows != (unsigned int) image->rows))
2256 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2257 jpeg_info.image_width=(unsigned int) image->columns;
2258 jpeg_info.image_height=(unsigned int) image->rows;
2259 jpeg_info.input_components=3;
2260 jpeg_info.data_precision=8;
2261 jpeg_info.in_color_space=JCS_RGB;
2262 switch (image->colorspace)
2264 case CMYKColorspace:
2266 jpeg_info.input_components=4;
2267 jpeg_info.in_color_space=JCS_CMYK;
2270 case YCbCrColorspace:
2271 case Rec601YCbCrColorspace:
2272 case Rec709YCbCrColorspace:
2274 jpeg_info.in_color_space=JCS_YCbCr;
2277 case LinearGRAYColorspace:
2278 case GRAYColorspace:
2280 if (image_info->type == TrueColorType)
2282 jpeg_info.input_components=1;
2283 jpeg_info.in_color_space=JCS_GRAYSCALE;
2288 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2289 if (image_info->type == TrueColorType)
2291 if (SetImageGray(image,exception) != MagickFalse)
2293 jpeg_info.input_components=1;
2294 jpeg_info.in_color_space=JCS_GRAYSCALE;
2299 jpeg_set_defaults(&jpeg_info);
2300 if (jpeg_info.in_color_space == JCS_CMYK)
2301 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2302 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2303 jpeg_info.data_precision=8;
2305 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2306 if (image->debug != MagickFalse)
2307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2308 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2309 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2312 Set image resolution.
2314 jpeg_info.write_JFIF_header=TRUE;
2315 jpeg_info.X_density=(UINT16) image->resolution.x;
2316 jpeg_info.Y_density=(UINT16) image->resolution.y;
2318 Set image resolution units.
2320 if (image->units == PixelsPerInchResolution)
2321 jpeg_info.density_unit=(UINT8) 1;
2322 if (image->units == PixelsPerCentimeterResolution)
2323 jpeg_info.density_unit=(UINT8) 2;
2325 jpeg_info.dct_method=JDCT_FLOAT;
2326 option=GetImageOption(image_info,"jpeg:dct-method");
2327 if (option != (const char *) NULL)
2333 if (LocaleCompare(option,"default") == 0)
2334 jpeg_info.dct_method=JDCT_DEFAULT;
2340 if (LocaleCompare(option,"fastest") == 0)
2341 jpeg_info.dct_method=JDCT_FASTEST;
2342 if (LocaleCompare(option,"float") == 0)
2343 jpeg_info.dct_method=JDCT_FLOAT;
2349 if (LocaleCompare(option,"ifast") == 0)
2350 jpeg_info.dct_method=JDCT_IFAST;
2351 if (LocaleCompare(option,"islow") == 0)
2352 jpeg_info.dct_method=JDCT_ISLOW;
2356 option=GetImageOption(image_info,"jpeg:optimize-coding");
2357 if (option != (const char *) NULL)
2358 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2365 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2366 image->rows*sizeof(JSAMPLE);
2367 if (length == (MagickSizeType) ((size_t) length))
2370 Perform optimization only if available memory resources permit it.
2372 status=AcquireMagickResource(MemoryResource,length);
2373 if (status != MagickFalse)
2374 RelinquishMagickResource(MemoryResource,length);
2375 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2378 #if defined(C_ARITH_CODING_SUPPORTED)
2379 option=GetImageOption(image_info,"jpeg:arithmetic-coding");
2380 if (IsStringTrue(option) != MagickFalse)
2382 jpeg_info.arith_code=TRUE;
2383 jpeg_info.optimize_coding=FALSE; // Not supported.
2386 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2387 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2388 (image_info->interlace != NoInterlace))
2390 if (image->debug != MagickFalse)
2391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2392 "Interlace: progressive");
2393 jpeg_simple_progression(&jpeg_info);
2396 if (image->debug != MagickFalse)
2397 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2398 "Interlace: non-progressive");
2400 if (image->debug != MagickFalse)
2401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2402 "Interlace: nonprogressive");
2405 if ((image_info->compression != LosslessJPEGCompression) &&
2406 (image->quality <= 100))
2408 if (image->quality != UndefinedCompressionQuality)
2409 quality=(int) image->quality;
2410 if (image->debug != MagickFalse)
2411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2412 (double) image->quality);
2416 #if !defined(C_LOSSLESS_SUPPORTED)
2418 if (image->debug != MagickFalse)
2419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2421 if (image->quality < 100)
2422 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2423 "LosslessToLossyJPEGConversion","`%s'",image->filename);
2430 predictor=image->quality/100; /* range 1-7 */
2431 point_transform=image->quality % 20; /* range 0-15 */
2432 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2433 if (image->debug != MagickFalse)
2435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2436 "Compression: lossless");
2437 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2438 "Predictor: %d",predictor);
2439 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2440 "Point Transform: %d",point_transform);
2445 option=GetImageOption(image_info,"jpeg:extent");
2446 if (option != (const char *) NULL)
2454 extent_info=CloneImageInfo(image_info);
2455 extent_info->blob=NULL;
2456 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2457 if (jpeg_image != (Image *) NULL)
2467 Search for compression quality that does not exceed image extent.
2469 extent_info->quality=0;
2470 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2471 (void) DeleteImageOption(extent_info,"jpeg:extent");
2472 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2473 maximum=image_info->quality;
2476 for (minimum=2; minimum < maximum; )
2478 (void) AcquireUniqueFilename(jpeg_image->filename);
2479 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2480 status=WriteJPEGImage(extent_info,jpeg_image,exception);
2481 if (GetBlobSize(jpeg_image) <= extent)
2482 minimum=jpeg_image->quality+1;
2484 maximum=jpeg_image->quality-1;
2485 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2487 quality=(int) minimum-1;
2488 jpeg_image=DestroyImage(jpeg_image);
2490 extent_info=DestroyImageInfo(extent_info);
2492 jpeg_set_quality(&jpeg_info,quality,TRUE);
2493 #if (JPEG_LIB_VERSION >= 70)
2494 option=GetImageOption(image_info,"quality");
2495 if (option != (const char *) NULL)
2504 Set quality scaling for luminance and chrominance separately.
2506 flags=ParseGeometry(option,&geometry_info);
2507 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2509 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2510 (geometry_info.rho+0.5));
2511 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2512 (geometry_info.sigma+0.5));
2513 jpeg_default_qtables(&jpeg_info,TRUE);
2517 colorspace=jpeg_info.in_color_space;
2518 value=GetImageOption(image_info,"jpeg:colorspace");
2519 if (value == (char *) NULL)
2520 value=GetImageProperty(image,"jpeg:colorspace",exception);
2521 if (value != (char *) NULL)
2522 colorspace=StringToInteger(value);
2523 sampling_factor=(const char *) NULL;
2524 if (colorspace == jpeg_info.in_color_space)
2526 value=GetImageOption(image_info,"jpeg:sampling-factor");
2527 if (value == (char *) NULL)
2528 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2529 if (value != (char *) NULL)
2531 sampling_factor=value;
2532 if (image->debug != MagickFalse)
2533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2534 " Input sampling-factors=%s",sampling_factor);
2537 value=GetImageOption(image_info,"jpeg:sampling-factor");
2538 if (image_info->sampling_factor != (char *) NULL)
2539 sampling_factor=image_info->sampling_factor;
2540 if (sampling_factor == (const char *) NULL)
2543 for (i=0; i < MAX_COMPONENTS; i++)
2545 jpeg_info.comp_info[i].h_samp_factor=1;
2546 jpeg_info.comp_info[i].v_samp_factor=1;
2561 Set sampling factor.
2564 factors=SamplingFactorToList(sampling_factor);
2565 if (factors != (char **) NULL)
2567 for (i=0; i < MAX_COMPONENTS; i++)
2569 if (factors[i] == (char *) NULL)
2571 flags=ParseGeometry(factors[i],&geometry_info);
2572 if ((flags & SigmaValue) == 0)
2573 geometry_info.sigma=geometry_info.rho;
2574 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2575 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2576 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2578 factors=(char **) RelinquishMagickMemory(factors);
2580 for ( ; i < MAX_COMPONENTS; i++)
2582 jpeg_info.comp_info[i].h_samp_factor=1;
2583 jpeg_info.comp_info[i].v_samp_factor=1;
2586 option=GetImageOption(image_info,"jpeg:q-table");
2587 if (option != (const char *) NULL)
2593 Custom quantization tables.
2595 table=GetQuantizationTable(option,"0",exception);
2596 if (table != (QuantizationTable *) NULL)
2598 for (i=0; i < MAX_COMPONENTS; i++)
2599 jpeg_info.comp_info[i].quant_tbl_no=0;
2600 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2601 jpeg_quality_scaling(quality),0);
2602 table=DestroyQuantizationTable(table);
2604 table=GetQuantizationTable(option,"1",exception);
2605 if (table != (QuantizationTable *) NULL)
2607 for (i=1; i < MAX_COMPONENTS; i++)
2608 jpeg_info.comp_info[i].quant_tbl_no=1;
2609 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2610 jpeg_quality_scaling(quality),0);
2611 table=DestroyQuantizationTable(table);
2613 table=GetQuantizationTable(option,"2",exception);
2614 if (table != (QuantizationTable *) NULL)
2616 for (i=2; i < MAX_COMPONENTS; i++)
2617 jpeg_info.comp_info[i].quant_tbl_no=2;
2618 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2619 jpeg_quality_scaling(quality),0);
2620 table=DestroyQuantizationTable(table);
2622 table=GetQuantizationTable(option,"3",exception);
2623 if (table != (QuantizationTable *) NULL)
2625 for (i=3; i < MAX_COMPONENTS; i++)
2626 jpeg_info.comp_info[i].quant_tbl_no=3;
2627 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2628 jpeg_quality_scaling(quality),0);
2629 table=DestroyQuantizationTable(table);
2632 jpeg_start_compress(&jpeg_info,TRUE);
2633 if (image->debug != MagickFalse)
2635 if (image->storage_class == PseudoClass)
2636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2637 "Storage class: PseudoClass");
2639 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2640 "Storage class: DirectClass");
2641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2642 (double) image->depth);
2643 if (image->colors != 0)
2644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2645 "Number of colors: %.20g",(double) image->colors);
2647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2648 "Number of colors: unspecified");
2649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2650 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2651 switch (image->colorspace)
2653 case CMYKColorspace:
2655 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2656 "Storage class: DirectClass");
2657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2658 "Colorspace: CMYK");
2661 case YCbCrColorspace:
2662 case Rec601YCbCrColorspace:
2663 case Rec709YCbCrColorspace:
2665 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2666 "Colorspace: YCbCr");
2672 switch (image->colorspace)
2674 case CMYKColorspace:
2676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2677 "Colorspace: CMYK");
2678 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2679 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2680 jpeg_info.comp_info[0].h_samp_factor,
2681 jpeg_info.comp_info[0].v_samp_factor,
2682 jpeg_info.comp_info[1].h_samp_factor,
2683 jpeg_info.comp_info[1].v_samp_factor,
2684 jpeg_info.comp_info[2].h_samp_factor,
2685 jpeg_info.comp_info[2].v_samp_factor,
2686 jpeg_info.comp_info[3].h_samp_factor,
2687 jpeg_info.comp_info[3].v_samp_factor);
2690 case GRAYColorspace:
2692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2693 "Colorspace: GRAY");
2694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2695 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2696 jpeg_info.comp_info[0].v_samp_factor);
2699 case sRGBColorspace:
2702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2703 "Image colorspace is RGB");
2704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2705 "Sampling factors: %dx%d,%dx%d,%dx%d",
2706 jpeg_info.comp_info[0].h_samp_factor,
2707 jpeg_info.comp_info[0].v_samp_factor,
2708 jpeg_info.comp_info[1].h_samp_factor,
2709 jpeg_info.comp_info[1].v_samp_factor,
2710 jpeg_info.comp_info[2].h_samp_factor,
2711 jpeg_info.comp_info[2].v_samp_factor);
2714 case YCbCrColorspace:
2715 case Rec601YCbCrColorspace:
2716 case Rec709YCbCrColorspace:
2718 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2719 "Colorspace: YCbCr");
2720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2721 "Sampling factors: %dx%d,%dx%d,%dx%d",
2722 jpeg_info.comp_info[0].h_samp_factor,
2723 jpeg_info.comp_info[0].v_samp_factor,
2724 jpeg_info.comp_info[1].h_samp_factor,
2725 jpeg_info.comp_info[1].v_samp_factor,
2726 jpeg_info.comp_info[2].h_samp_factor,
2727 jpeg_info.comp_info[2].v_samp_factor);
2732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2735 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2736 jpeg_info.comp_info[0].h_samp_factor,
2737 jpeg_info.comp_info[0].v_samp_factor,
2738 jpeg_info.comp_info[1].h_samp_factor,
2739 jpeg_info.comp_info[1].v_samp_factor,
2740 jpeg_info.comp_info[2].h_samp_factor,
2741 jpeg_info.comp_info[2].v_samp_factor,
2742 jpeg_info.comp_info[3].h_samp_factor,
2743 jpeg_info.comp_info[3].v_samp_factor);
2749 Write JPEG profiles.
2751 value=GetImageProperty(image,"comment",exception);
2752 if (value != (char *) NULL)
2753 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2754 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2755 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2756 if (image->profiles != (void *) NULL)
2757 WriteProfile(&jpeg_info,image,exception);
2759 Convert MIFF to JPEG raster pixels.
2761 memory_info=AcquireVirtualMemory((size_t) image->columns,
2762 jpeg_info.input_components*sizeof(*jpeg_pixels));
2763 if (memory_info == (MemoryInfo *) NULL)
2764 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2765 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2766 if (setjmp(error_manager.error_recovery) != 0)
2768 jpeg_destroy_compress(&jpeg_info);
2769 if (memory_info != (MemoryInfo *) NULL)
2770 memory_info=RelinquishVirtualMemory(memory_info);
2771 (void) CloseBlob(image);
2772 return(MagickFalse);
2774 scanline[0]=(JSAMPROW) jpeg_pixels;
2775 scale=65535/(unsigned short) GetQuantumRange((size_t)
2776 jpeg_info.data_precision);
2779 if (jpeg_info.data_precision <= 8)
2781 if ((jpeg_info.in_color_space == JCS_RGB) ||
2782 (jpeg_info.in_color_space == JCS_YCbCr))
2783 for (y=0; y < (ssize_t) image->rows; y++)
2785 register const Quantum
2791 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2792 if (p == (const Quantum *) NULL)
2795 for (x=0; x < (ssize_t) image->columns; x++)
2797 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2798 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2799 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2800 p+=GetPixelChannels(image);
2802 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2803 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2805 if (status == MagickFalse)
2809 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2810 for (y=0; y < (ssize_t) image->rows; y++)
2812 register const Quantum
2818 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2819 if (p == (const Quantum *) NULL)
2822 for (x=0; x < (ssize_t) image->columns; x++)
2824 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2826 p+=GetPixelChannels(image);
2828 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2829 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2831 if (status == MagickFalse)
2835 for (y=0; y < (ssize_t) image->rows; y++)
2837 register const Quantum
2843 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2844 if (p == (const Quantum *) NULL)
2847 for (x=0; x < (ssize_t) image->columns; x++)
2850 Convert DirectClass packets to contiguous CMYK scanlines.
2852 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2853 GetPixelCyan(image,p))));
2854 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2855 GetPixelMagenta(image,p))));
2856 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2857 GetPixelYellow(image,p))));
2858 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2859 GetPixelBlack(image,p))));
2860 p+=GetPixelChannels(image);
2862 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2863 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2865 if (status == MagickFalse)
2870 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2871 for (y=0; y < (ssize_t) image->rows; y++)
2873 register const Quantum
2879 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2880 if (p == (const Quantum *) NULL)
2883 for (x=0; x < (ssize_t) image->columns; x++)
2885 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2887 p+=GetPixelChannels(image);
2889 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2890 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2892 if (status == MagickFalse)
2896 if ((jpeg_info.in_color_space == JCS_RGB) ||
2897 (jpeg_info.in_color_space == JCS_YCbCr))
2898 for (y=0; y < (ssize_t) image->rows; y++)
2900 register const Quantum
2906 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2907 if (p == (const Quantum *) NULL)
2910 for (x=0; x < (ssize_t) image->columns; x++)
2912 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2913 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2914 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2915 p+=GetPixelChannels(image);
2917 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2918 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2920 if (status == MagickFalse)
2924 for (y=0; y < (ssize_t) image->rows; y++)
2926 register const Quantum
2932 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2933 if (p == (const Quantum *) NULL)
2936 for (x=0; x < (ssize_t) image->columns; x++)
2939 Convert DirectClass packets to contiguous CMYK scanlines.
2941 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2943 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2945 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2947 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2949 p+=GetPixelChannels(image);
2951 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2952 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2954 if (status == MagickFalse)
2957 if (y == (ssize_t) image->rows)
2958 jpeg_finish_compress(&jpeg_info);
2960 Relinquish resources.
2962 jpeg_destroy_compress(&jpeg_info);
2963 memory_info=RelinquishVirtualMemory(memory_info);
2964 (void) CloseBlob(image);