2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
47 #include "MagickCore/studio.h"
48 #include "MagickCore/artifact.h"
49 #include "MagickCore/attribute.h"
50 #include "MagickCore/blob.h"
51 #include "MagickCore/blob-private.h"
52 #include "MagickCore/cache.h"
53 #include "MagickCore/color.h"
54 #include "MagickCore/colormap-private.h"
55 #include "MagickCore/color-private.h"
56 #include "MagickCore/colormap.h"
57 #include "MagickCore/colorspace.h"
58 #include "MagickCore/colorspace-private.h"
59 #include "MagickCore/constitute.h"
60 #include "MagickCore/exception.h"
61 #include "MagickCore/exception-private.h"
62 #include "MagickCore/geometry.h"
63 #include "MagickCore/image.h"
64 #include "MagickCore/image-private.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/magick.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/option-private.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/splay-tree.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/string_.h"
83 #include "MagickCore/string-private.h"
84 #include "MagickCore/token.h"
85 #include "MagickCore/utility.h"
86 #include "MagickCore/xml-tree.h"
87 #include "MagickCore/xml-tree-private.h"
89 #if defined(MAGICKCORE_JPEG_DELEGATE)
90 #define JPEG_INTERNAL_OPTIONS
91 #if defined(__MINGW32__) || defined(__MINGW64__)
92 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
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
111 Typedef declarations.
113 #if defined(MAGICKCORE_JPEG_DELEGATE)
114 typedef struct _DestinationManager
116 struct jpeg_destination_mgr
124 } DestinationManager;
126 typedef struct _ErrorManager
144 typedef struct _SourceManager
146 struct jpeg_source_mgr
160 typedef struct _QuantizationTable
179 Forward declarations.
181 #if defined(MAGICKCORE_JPEG_DELEGATE)
182 static MagickBooleanType
183 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % IsJPEG() returns MagickTrue if the image format type, identified by the
199 % magick string, is JPEG.
201 % The format of the IsJPEG method is:
203 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
205 % A description of each parameter follows:
207 % o magick: compare image format pattern against these bytes.
209 % o length: Specifies the length of the magick string.
212 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
216 if (memcmp(magick,"\377\330\377",3) == 0)
222 #if defined(MAGICKCORE_JPEG_DELEGATE)
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228 % R e a d J P E G I m a g e %
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
235 % the memory necessary for the new Image structure and returns a pointer to
238 % The format of the ReadJPEGImage method is:
240 % Image *ReadJPEGImage(const ImageInfo *image_info,
241 % ExceptionInfo *exception)
243 % A description of each parameter follows:
245 % o image_info: the image info.
247 % o exception: return any errors or warnings in this structure.
251 static boolean FillInputBuffer(j_decompress_ptr cinfo)
256 source=(SourceManager *) cinfo->src;
257 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
258 MaxBufferExtent,source->buffer);
259 if (source->manager.bytes_in_buffer == 0)
261 if (source->start_of_blob != FALSE)
262 ERREXIT(cinfo,JERR_INPUT_EMPTY);
263 WARNMS(cinfo,JWRN_JPEG_EOF);
264 source->buffer[0]=(JOCTET) 0xff;
265 source->buffer[1]=(JOCTET) JPEG_EOI;
266 source->manager.bytes_in_buffer=2;
268 source->manager.next_input_byte=source->buffer;
269 source->start_of_blob=FALSE;
273 static int GetCharacter(j_decompress_ptr jpeg_info)
275 if (jpeg_info->src->bytes_in_buffer == 0)
276 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
277 jpeg_info->src->bytes_in_buffer--;
278 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
281 static void InitializeSource(j_decompress_ptr cinfo)
286 source=(SourceManager *) cinfo->src;
287 source->start_of_blob=TRUE;
290 static MagickBooleanType IsITUFaxImage(const Image *image)
298 profile=GetImageProfile(image,"8bim");
299 if (profile == (const StringInfo *) NULL)
301 if (GetStringInfoLength(profile) < 5)
303 datum=GetStringInfoDatum(profile);
304 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
305 (datum[3] == 0x41) && (datum[4] == 0x58))
310 static void JPEGErrorHandler(j_common_ptr jpeg_info)
313 message[JMSG_LENGTH_MAX];
325 error_manager=(ErrorManager *) jpeg_info->client_data;
326 image=error_manager->image;
327 exception=error_manager->exception;
328 (jpeg_info->err->format_message)(jpeg_info,message);
329 if (image->debug != MagickFalse)
330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
331 "[%s] JPEG Trace: \"%s\"",image->filename,message);
332 if (error_manager->finished != MagickFalse)
333 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
334 (char *) message,"`%s'",image->filename);
336 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
337 (char *) message,"`%s'",image->filename);
338 longjmp(error_manager->error_recovery,1);
341 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
343 #define JPEGExcessiveWarnings 1000
346 message[JMSG_LENGTH_MAX];
358 error_manager=(ErrorManager *) jpeg_info->client_data;
359 exception=error_manager->exception;
360 image=error_manager->image;
364 Process warning message.
366 (jpeg_info->err->format_message)(jpeg_info,message);
367 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
368 JPEGErrorHandler(jpeg_info);
369 ThrowBinaryException(CorruptImageWarning,(char *) message,
373 if ((image->debug != MagickFalse) &&
374 (level >= jpeg_info->err->trace_level))
377 Process trace message.
379 (jpeg_info->err->format_message)(jpeg_info,message);
380 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
381 "[%s] JPEG Trace: \"%s\"",image->filename,message);
386 static boolean ReadComment(j_decompress_ptr jpeg_info)
397 register unsigned char
410 Determine length of comment.
412 error_manager=(ErrorManager *) jpeg_info->client_data;
413 exception=error_manager->exception;
414 image=error_manager->image;
415 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
416 length+=GetCharacter(jpeg_info);
420 comment=BlobToStringInfo((const void *) NULL,length);
421 if (comment == (StringInfo *) NULL)
423 (void) ThrowMagickException(exception,GetMagickModule(),
424 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
430 error_manager->profile=comment;
431 p=GetStringInfoDatum(comment);
432 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
433 *p++=(unsigned char) GetCharacter(jpeg_info);
435 error_manager->profile=NULL;
436 p=GetStringInfoDatum(comment);
437 (void) SetImageProperty(image,"comment",(const char *) p,exception);
438 comment=DestroyStringInfo(comment);
442 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
462 register unsigned char
475 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
476 length+=(size_t) GetCharacter(jpeg_info);
481 (void) GetCharacter(jpeg_info);
484 for (i=0; i < 12; i++)
485 magick[i]=(char) GetCharacter(jpeg_info);
486 if (LocaleCompare(magick,ICC_PROFILE) != 0)
489 Not a ICC profile, return.
491 for (i=0; i < (ssize_t) (length-12); i++)
492 (void) GetCharacter(jpeg_info);
495 (void) GetCharacter(jpeg_info); /* id */
496 (void) GetCharacter(jpeg_info); /* markers */
498 error_manager=(ErrorManager *) jpeg_info->client_data;
499 exception=error_manager->exception;
500 image=error_manager->image;
501 profile=BlobToStringInfo((const void *) NULL,length);
502 if (profile == (StringInfo *) NULL)
504 (void) ThrowMagickException(exception,GetMagickModule(),
505 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
508 error_manager->profile=profile;
509 p=GetStringInfoDatum(profile);
510 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
511 *p++=(unsigned char) GetCharacter(jpeg_info);
512 error_manager->profile=NULL;
513 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
514 if (icc_profile != (StringInfo *) NULL)
516 ConcatenateStringInfo(icc_profile,profile);
517 profile=DestroyStringInfo(profile);
521 status=SetImageProfile(image,"icc",profile,exception);
522 profile=DestroyStringInfo(profile);
523 if (status == MagickFalse)
525 (void) ThrowMagickException(exception,GetMagickModule(),
526 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
530 if (image->debug != MagickFalse)
531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
532 "Profile: ICC, %.20g bytes",(double) length);
536 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
539 magick[MaxTextExtent];
556 register unsigned char
567 Determine length of binary data stored here.
569 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
570 length+=(size_t) GetCharacter(jpeg_info);
575 (void) GetCharacter(jpeg_info);
579 Validate that this was written as a Photoshop resource format slug.
581 for (i=0; i < 10; i++)
582 magick[i]=(char) GetCharacter(jpeg_info);
587 if (LocaleCompare(magick,"Photoshop ") != 0)
590 Not a IPTC profile, return.
592 for (i=0; i < (ssize_t) length; i++)
593 (void) GetCharacter(jpeg_info);
597 Remove the version number.
599 for (i=0; i < 4; i++)
600 (void) GetCharacter(jpeg_info);
604 error_manager=(ErrorManager *) jpeg_info->client_data;
605 exception=error_manager->exception;
606 image=error_manager->image;
607 profile=BlobToStringInfo((const void *) NULL,length);
608 if (profile == (StringInfo *) NULL)
610 (void) ThrowMagickException(exception,GetMagickModule(),
611 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
614 error_manager->profile=profile;
615 p=GetStringInfoDatum(profile);
616 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
617 *p++=(unsigned char) GetCharacter(jpeg_info);
618 error_manager->profile=NULL;
619 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
620 if (iptc_profile != (StringInfo *) NULL)
622 ConcatenateStringInfo(iptc_profile,profile);
623 profile=DestroyStringInfo(profile);
627 status=SetImageProfile(image,"8bim",profile,exception);
628 profile=DestroyStringInfo(profile);
629 if (status == MagickFalse)
631 (void) ThrowMagickException(exception,GetMagickModule(),
632 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
636 if (image->debug != MagickFalse)
637 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
638 "Profile: iptc, %.20g bytes",(double) length);
642 static boolean ReadProfile(j_decompress_ptr jpeg_info)
668 register unsigned char
678 Read generic profile.
680 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
681 length+=(size_t) GetCharacter(jpeg_info);
685 marker=jpeg_info->unread_marker-JPEG_APP0;
686 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
687 error_manager=(ErrorManager *) jpeg_info->client_data;
688 exception=error_manager->exception;
689 image=error_manager->image;
690 profile=BlobToStringInfo((const void *) NULL,length);
691 if (profile == (StringInfo *) NULL)
693 (void) ThrowMagickException(exception,GetMagickModule(),
694 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
697 error_manager->profile=profile;
698 p=GetStringInfoDatum(profile);
699 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
700 *p++=(unsigned char) GetCharacter(jpeg_info);
701 error_manager->profile=NULL;
704 p=GetStringInfoDatum(profile);
705 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
706 (void) CopyMagickString(name,"exif",MaxTextExtent);
707 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
713 Extract namespace from XMP profile.
715 p=GetStringInfoDatum(profile);
716 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
722 if (j < (ssize_t) GetStringInfoLength(profile))
723 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
724 (void) CopyMagickString(name,"xmp",MaxTextExtent);
727 previous_profile=GetImageProfile(image,name);
728 if (previous_profile != (const StringInfo *) NULL)
733 length=GetStringInfoLength(profile);
734 SetStringInfoLength(profile,GetStringInfoLength(profile)+
735 GetStringInfoLength(previous_profile));
736 (void) memmove(GetStringInfoDatum(profile)+
737 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
739 (void) memcpy(GetStringInfoDatum(profile),
740 GetStringInfoDatum(previous_profile),
741 GetStringInfoLength(previous_profile));
743 status=SetImageProfile(image,name,profile,exception);
744 profile=DestroyStringInfo(profile);
745 if (status == MagickFalse)
747 (void) ThrowMagickException(exception,GetMagickModule(),
748 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
751 if (image->debug != MagickFalse)
752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
753 "Profile: %s, %.20g bytes",name,(double) length);
757 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
762 if (number_bytes <= 0)
764 source=(SourceManager *) cinfo->src;
765 while (number_bytes > (long) source->manager.bytes_in_buffer)
767 number_bytes-=(long) source->manager.bytes_in_buffer;
768 (void) FillInputBuffer(cinfo);
770 source->manager.next_input_byte+=number_bytes;
771 source->manager.bytes_in_buffer-=number_bytes;
774 static void TerminateSource(j_decompress_ptr cinfo)
779 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
784 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
785 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
786 source=(SourceManager *) cinfo->src;
787 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
788 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
789 source=(SourceManager *) cinfo->src;
790 source->manager.init_source=InitializeSource;
791 source->manager.fill_input_buffer=FillInputBuffer;
792 source->manager.skip_input_data=SkipInputData;
793 source->manager.resync_to_restart=jpeg_resync_to_restart;
794 source->manager.term_source=TerminateSource;
795 source->manager.bytes_in_buffer=0;
796 source->manager.next_input_byte=NULL;
800 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
801 Image *image, ExceptionInfo *exception)
803 image->quality=UndefinedCompressionQuality;
804 #if defined(D_PROGRESSIVE_SUPPORTED)
805 if (image->compression == LosslessJPEGCompression)
808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
809 "Quality: 100 (lossless)");
823 Determine the JPEG compression quality from the quantization tables.
826 for (i=0; i < NUM_QUANT_TBLS; i++)
828 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
829 for (j=0; j < DCTSIZE2; j++)
830 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
832 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
833 (jpeg_info->quant_tbl_ptrs[1] != NULL))
838 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
839 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
840 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
841 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
842 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
843 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
844 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
845 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
846 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
847 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
852 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
853 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
854 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
855 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
856 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
857 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
858 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
859 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
860 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
861 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
862 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
866 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
867 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
868 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
869 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
870 for (i=0; i < 100; i++)
872 if ((qvalue < hash[i]) && (sum < sums[i]))
874 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
875 image->quality=(size_t) i+1;
876 if (image->debug != MagickFalse)
877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
878 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
879 (sum <= sums[i]) ? "exact" : "approximate");
884 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
889 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
890 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
891 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
892 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
893 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
894 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
895 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
896 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
897 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
898 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
903 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
904 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
905 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
906 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
907 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
908 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
909 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
910 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
911 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
912 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
913 667, 592, 518, 441, 369, 292, 221, 151, 86,
917 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
918 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
919 for (i=0; i < 100; i++)
921 if ((qvalue < hash[i]) && (sum < sums[i]))
923 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
924 image->quality=(size_t)i+1;
925 if (image->debug != MagickFalse)
926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
927 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
928 (sum <= sums[i]) ? "exact" : "approximate");
935 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
938 sampling_factor[MaxTextExtent];
940 switch (jpeg_info->out_color_space)
944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
945 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
946 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
947 jpeg_info->comp_info[0].v_samp_factor,
948 jpeg_info->comp_info[1].h_samp_factor,
949 jpeg_info->comp_info[1].v_samp_factor,
950 jpeg_info->comp_info[2].h_samp_factor,
951 jpeg_info->comp_info[2].v_samp_factor,
952 jpeg_info->comp_info[3].h_samp_factor,
953 jpeg_info->comp_info[3].v_samp_factor);
958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
959 "Colorspace: GRAYSCALE");
960 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
961 jpeg_info->comp_info[0].h_samp_factor,
962 jpeg_info->comp_info[0].v_samp_factor);
967 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
968 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
969 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
970 jpeg_info->comp_info[0].v_samp_factor,
971 jpeg_info->comp_info[1].h_samp_factor,
972 jpeg_info->comp_info[1].v_samp_factor,
973 jpeg_info->comp_info[2].h_samp_factor,
974 jpeg_info->comp_info[2].v_samp_factor);
979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
980 jpeg_info->out_color_space);
981 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
982 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
983 jpeg_info->comp_info[0].v_samp_factor,
984 jpeg_info->comp_info[1].h_samp_factor,
985 jpeg_info->comp_info[1].v_samp_factor,
986 jpeg_info->comp_info[2].h_samp_factor,
987 jpeg_info->comp_info[2].v_samp_factor,
988 jpeg_info->comp_info[3].h_samp_factor,
989 jpeg_info->comp_info[3].v_samp_factor);
993 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
999 static Image *ReadJPEGImage(const ImageInfo *image_info,
1000 ExceptionInfo *exception)
1003 value[MaxTextExtent];
1015 *volatile jpeg_pixels;
1036 struct jpeg_decompress_struct
1039 struct jpeg_error_mgr
1054 assert(image_info != (const ImageInfo *) NULL);
1055 assert(image_info->signature == MagickSignature);
1056 if (image_info->debug != MagickFalse)
1057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1058 image_info->filename);
1059 assert(exception != (ExceptionInfo *) NULL);
1060 assert(exception->signature == MagickSignature);
1061 debug=IsEventLogging();
1063 image=AcquireImage(image_info,exception);
1064 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1065 if (status == MagickFalse)
1067 image=DestroyImageList(image);
1068 return((Image *) NULL);
1071 Initialize JPEG parameters.
1073 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1074 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1075 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1076 jpeg_info.err=jpeg_std_error(&jpeg_error);
1077 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1078 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1079 memory_info=(MemoryInfo *) NULL;
1080 error_manager.exception=exception;
1081 error_manager.image=image;
1082 if (setjmp(error_manager.error_recovery) != 0)
1084 jpeg_destroy_decompress(&jpeg_info);
1085 if (error_manager.profile != (StringInfo *) NULL)
1086 error_manager.profile=DestroyStringInfo(error_manager.profile);
1087 (void) CloseBlob(image);
1088 number_pixels=(MagickSizeType) image->columns*image->rows;
1089 if (number_pixels != 0)
1090 return(GetFirstImageInList(image));
1091 return(DestroyImage(image));
1093 jpeg_info.client_data=(void *) &error_manager;
1094 jpeg_create_decompress(&jpeg_info);
1095 JPEGSourceManager(&jpeg_info,image);
1096 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1097 option=GetImageOption(image_info,"profile:skip");
1098 if (IsOptionMember("ICC",option) == MagickFalse)
1099 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1100 if (IsOptionMember("IPTC",option) == MagickFalse)
1101 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1102 for (i=1; i < 16; i++)
1103 if ((i != 2) && (i != 13) && (i != 14))
1104 if (IsOptionMember("APP",option) == MagickFalse)
1105 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1106 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1107 if ((image_info->colorspace == YCbCrColorspace) ||
1108 (image_info->colorspace == Rec601YCbCrColorspace) ||
1109 (image_info->colorspace == Rec709YCbCrColorspace))
1110 jpeg_info.out_color_space=JCS_YCbCr;
1112 Set image resolution.
1115 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1116 (jpeg_info.Y_density != 1))
1118 image->resolution.x=(double) jpeg_info.X_density;
1119 image->resolution.y=(double) jpeg_info.Y_density;
1120 units=(size_t) jpeg_info.density_unit;
1123 image->units=PixelsPerInchResolution;
1125 image->units=PixelsPerCentimeterResolution;
1126 number_pixels=(MagickSizeType) image->columns*image->rows;
1127 option=GetImageOption(image_info,"jpeg:size");
1128 if ((option != (const char *) NULL) &&
1129 (jpeg_info.out_color_space != JCS_YCbCr))
1143 flags=ParseGeometry(option,&geometry_info);
1144 if ((flags & SigmaValue) == 0)
1145 geometry_info.sigma=geometry_info.rho;
1146 jpeg_calc_output_dimensions(&jpeg_info);
1147 image->magick_columns=jpeg_info.output_width;
1148 image->magick_rows=jpeg_info.output_height;
1150 if (geometry_info.rho != 0.0)
1151 scale_factor=jpeg_info.output_width/geometry_info.rho;
1152 if ((geometry_info.sigma != 0.0) &&
1153 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1154 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1155 jpeg_info.scale_num=1U;
1156 jpeg_info.scale_denom=(unsigned int) scale_factor;
1157 jpeg_calc_output_dimensions(&jpeg_info);
1158 if (image->debug != MagickFalse)
1159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1160 "Scale factor: %.20g",(double) scale_factor);
1162 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1163 #if defined(D_LOSSLESS_SUPPORTED)
1164 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1165 JPEGInterlace : NoInterlace;
1166 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1167 LosslessJPEGCompression : JPEGCompression;
1168 if (jpeg_info.data_precision > 8)
1169 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1170 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1172 if (jpeg_info.data_precision == 16)
1173 jpeg_info.data_precision=12;
1175 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1177 image->compression=JPEGCompression;
1180 image->compression=JPEGCompression;
1181 image->interlace=JPEGInterlace;
1183 option=GetImageOption(image_info,"jpeg:colors");
1184 if (option != (const char *) NULL)
1187 Let the JPEG library quantize the image.
1189 jpeg_info.quantize_colors=TRUE;
1190 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1192 option=GetImageOption(image_info,"jpeg:block-smoothing");
1193 if (option != (const char *) NULL)
1194 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1196 jpeg_info.dct_method=JDCT_FLOAT;
1197 option=GetImageOption(image_info,"jpeg:dct-method");
1198 if (option != (const char *) NULL)
1204 if (LocaleCompare(option,"default") == 0)
1205 jpeg_info.dct_method=JDCT_DEFAULT;
1211 if (LocaleCompare(option,"fastest") == 0)
1212 jpeg_info.dct_method=JDCT_FASTEST;
1213 if (LocaleCompare(option,"float") == 0)
1214 jpeg_info.dct_method=JDCT_FLOAT;
1220 if (LocaleCompare(option,"ifast") == 0)
1221 jpeg_info.dct_method=JDCT_IFAST;
1222 if (LocaleCompare(option,"islow") == 0)
1223 jpeg_info.dct_method=JDCT_ISLOW;
1227 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1228 if (option != (const char *) NULL)
1229 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1231 (void) jpeg_start_decompress(&jpeg_info);
1232 image->columns=jpeg_info.output_width;
1233 image->rows=jpeg_info.output_height;
1234 image->depth=(size_t) jpeg_info.data_precision;
1235 switch (jpeg_info.out_color_space)
1240 (void) SetImageColorspace(image,sRGBColorspace,exception);
1245 (void) SetImageColorspace(image,GRAYColorspace,exception);
1250 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1255 (void) SetImageColorspace(image,CMYKColorspace,exception);
1259 if (IsITUFaxImage(image) != MagickFalse)
1261 (void) SetImageColorspace(image,LabColorspace,exception);
1262 jpeg_info.out_color_space=JCS_YCbCr;
1264 option=GetImageOption(image_info,"jpeg:colors");
1265 if (option != (const char *) NULL)
1266 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1268 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1269 if ((jpeg_info.output_components == 1) &&
1270 (jpeg_info.quantize_colors == MagickFalse))
1275 colors=(size_t) GetQuantumRange(image->depth)+1;
1276 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1277 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1279 if (image->debug != MagickFalse)
1281 if (image->interlace != NoInterlace)
1282 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1283 "Interlace: progressive");
1285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1286 "Interlace: nonprogressive");
1287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1288 (int) jpeg_info.data_precision);
1289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1290 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1292 JPEGSetImageQuality(&jpeg_info,image,exception);
1293 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1294 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1295 jpeg_info.out_color_space);
1296 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1297 if (image_info->ping != MagickFalse)
1299 jpeg_destroy_decompress(&jpeg_info);
1300 (void) CloseBlob(image);
1301 return(GetFirstImageInList(image));
1303 status=SetImageExtent(image,image->columns,image->rows,exception);
1304 if (status == MagickFalse)
1305 return(DestroyImageList(image));
1306 memory_info=AcquireVirtualMemory((size_t) image->columns,
1307 jpeg_info.output_components*sizeof(*jpeg_pixels));
1308 if (memory_info == (MemoryInfo *) NULL)
1310 jpeg_destroy_decompress(&jpeg_info);
1311 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1313 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1315 Convert JPEG pixels to pixel packets.
1317 if (setjmp(error_manager.error_recovery) != 0)
1319 if (memory_info != (MemoryInfo *) NULL)
1320 memory_info=RelinquishVirtualMemory(memory_info);
1321 jpeg_destroy_decompress(&jpeg_info);
1322 (void) CloseBlob(image);
1323 number_pixels=(MagickSizeType) image->columns*image->rows;
1324 if (number_pixels != 0)
1325 return(GetFirstImageInList(image));
1326 return(DestroyImage(image));
1328 if (jpeg_info.quantize_colors != MagickFalse)
1330 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1331 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1332 for (i=0; i < (ssize_t) image->colors; i++)
1334 image->colormap[i].red=(double) ScaleCharToQuantum(
1335 jpeg_info.colormap[0][i]);
1336 image->colormap[i].green=image->colormap[i].red;
1337 image->colormap[i].blue=image->colormap[i].red;
1338 image->colormap[i].alpha=OpaqueAlpha;
1341 for (i=0; i < (ssize_t) image->colors; i++)
1343 image->colormap[i].red=(double) ScaleCharToQuantum(
1344 jpeg_info.colormap[0][i]);
1345 image->colormap[i].green=(double) ScaleCharToQuantum(
1346 jpeg_info.colormap[1][i]);
1347 image->colormap[i].blue=(double) ScaleCharToQuantum(
1348 jpeg_info.colormap[2][i]);
1349 image->colormap[i].alpha=OpaqueAlpha;
1352 scanline[0]=(JSAMPROW) jpeg_pixels;
1353 for (y=0; y < (ssize_t) image->rows; y++)
1361 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1363 (void) ThrowMagickException(exception,GetMagickModule(),
1364 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1368 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1369 if (q == (Quantum *) NULL)
1371 if (jpeg_info.data_precision > 8)
1376 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1377 if (jpeg_info.output_components == 1)
1378 for (x=0; x < (ssize_t) image->columns; x++)
1383 pixel=(size_t) (scale*GETJSAMPLE(*p));
1384 index=ConstrainColormapIndex(image,pixel,exception);
1385 SetPixelIndex(image,index,q);
1386 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1388 q+=GetPixelChannels(image);
1391 if (image->colorspace != CMYKColorspace)
1392 for (x=0; x < (ssize_t) image->columns; x++)
1394 SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1396 SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1398 SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1400 SetPixelAlpha(image,OpaqueAlpha,q);
1401 q+=GetPixelChannels(image);
1404 for (x=0; x < (ssize_t) image->columns; x++)
1406 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(scale*
1407 GETJSAMPLE(*p++)),q);
1408 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(scale*
1409 GETJSAMPLE(*p++)),q);
1410 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(scale*
1411 GETJSAMPLE(*p++)),q);
1412 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(scale*
1413 GETJSAMPLE(*p++)),q);
1414 SetPixelAlpha(image,OpaqueAlpha,q);
1415 q+=GetPixelChannels(image);
1419 if (jpeg_info.output_components == 1)
1420 for (x=0; x < (ssize_t) image->columns; x++)
1422 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1423 SetPixelIndex(image,index,q);
1424 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1426 q+=GetPixelChannels(image);
1429 if (image->colorspace != CMYKColorspace)
1430 for (x=0; x < (ssize_t) image->columns; x++)
1432 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1433 GETJSAMPLE(*p++)),q);
1434 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1435 GETJSAMPLE(*p++)),q);
1436 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1437 GETJSAMPLE(*p++)),q);
1438 SetPixelAlpha(image,OpaqueAlpha,q);
1439 q+=GetPixelChannels(image);
1442 for (x=0; x < (ssize_t) image->columns; x++)
1444 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1445 (unsigned char) GETJSAMPLE(*p++)),q);
1446 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1447 (unsigned char) GETJSAMPLE(*p++)),q);
1448 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1449 (unsigned char) GETJSAMPLE(*p++)),q);
1450 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1451 (unsigned char) GETJSAMPLE(*p++)),q);
1452 SetPixelAlpha(image,OpaqueAlpha,q);
1453 q+=GetPixelChannels(image);
1455 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1457 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1459 if (status == MagickFalse)
1461 jpeg_abort_decompress(&jpeg_info);
1465 if (status != MagickFalse)
1467 error_manager.finished=MagickTrue;
1468 if (setjmp(error_manager.error_recovery) == 0)
1469 (void) jpeg_finish_decompress(&jpeg_info);
1472 Free jpeg resources.
1474 jpeg_destroy_decompress(&jpeg_info);
1475 memory_info=RelinquishVirtualMemory(memory_info);
1476 (void) CloseBlob(image);
1477 return(GetFirstImageInList(image));
1483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487 % R e g i s t e r J P E G I m a g e %
1491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1493 % RegisterJPEGImage() adds properties for the JPEG image format to
1494 % the list of supported formats. The properties include the image format
1495 % tag, a method to read and/or write the format, whether the format
1496 % supports the saving of more than one frame to the same file or blob,
1497 % whether the format supports native in-memory I/O, and a brief
1498 % description of the format.
1500 % The format of the RegisterJPEGImage method is:
1502 % size_t RegisterJPEGImage(void)
1505 ModuleExport size_t RegisterJPEGImage(void)
1508 version[MaxTextExtent];
1514 description[] = "Joint Photographic Experts Group JFIF format";
1517 #if defined(JPEG_LIB_VERSION)
1518 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1520 entry=SetMagickInfo("JPE");
1521 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1522 entry->thread_support=NoThreadSupport;
1524 #if defined(MAGICKCORE_JPEG_DELEGATE)
1525 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1526 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1528 entry->magick=(IsImageFormatHandler *) IsJPEG;
1529 entry->adjoin=MagickFalse;
1530 entry->description=ConstantString(description);
1531 if (*version != '\0')
1532 entry->version=ConstantString(version);
1533 entry->mime_type=ConstantString("image/jpeg");
1534 entry->module=ConstantString("JPEG");
1535 (void) RegisterMagickInfo(entry);
1536 entry=SetMagickInfo("JPEG");
1537 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1538 entry->thread_support=NoThreadSupport;
1540 #if defined(MAGICKCORE_JPEG_DELEGATE)
1541 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1542 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1544 entry->magick=(IsImageFormatHandler *) IsJPEG;
1545 entry->adjoin=MagickFalse;
1546 entry->description=ConstantString(description);
1547 if (*version != '\0')
1548 entry->version=ConstantString(version);
1549 entry->mime_type=ConstantString("image/jpeg");
1550 entry->module=ConstantString("JPEG");
1551 (void) RegisterMagickInfo(entry);
1552 entry=SetMagickInfo("JPG");
1553 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1554 entry->thread_support=NoThreadSupport;
1556 #if defined(MAGICKCORE_JPEG_DELEGATE)
1557 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1558 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1560 entry->adjoin=MagickFalse;
1561 entry->description=ConstantString(description);
1562 if (*version != '\0')
1563 entry->version=ConstantString(version);
1564 entry->mime_type=ConstantString("image/jpeg");
1565 entry->module=ConstantString("JPEG");
1566 (void) RegisterMagickInfo(entry);
1567 entry=SetMagickInfo("JPS");
1568 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1569 entry->thread_support=NoThreadSupport;
1571 #if defined(MAGICKCORE_JPEG_DELEGATE)
1572 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1573 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1575 entry->adjoin=MagickFalse;
1576 entry->description=ConstantString(description);
1577 if (*version != '\0')
1578 entry->version=ConstantString(version);
1579 entry->mime_type=ConstantString("image/jpeg");
1580 entry->module=ConstantString("JPEG Stereoscopic");
1581 (void) RegisterMagickInfo(entry);
1582 entry=SetMagickInfo("PJPEG");
1583 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1584 entry->thread_support=NoThreadSupport;
1586 #if defined(MAGICKCORE_JPEG_DELEGATE)
1587 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1588 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1590 entry->adjoin=MagickFalse;
1591 entry->description=ConstantString(description);
1592 if (*version != '\0')
1593 entry->version=ConstantString(version);
1594 entry->mime_type=ConstantString("image/jpeg");
1595 entry->module=ConstantString("JPEG");
1596 (void) RegisterMagickInfo(entry);
1597 return(MagickImageCoderSignature);
1602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1606 % U n r e g i s t e r J P E G I m a g e %
1610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1612 % UnregisterJPEGImage() removes format registrations made by the
1613 % JPEG module from the list of supported formats.
1615 % The format of the UnregisterJPEGImage method is:
1617 % UnregisterJPEGImage(void)
1620 ModuleExport void UnregisterJPEGImage(void)
1622 (void) UnregisterMagickInfo("PJPG");
1623 (void) UnregisterMagickInfo("JPS");
1624 (void) UnregisterMagickInfo("JPG");
1625 (void) UnregisterMagickInfo("JPEG");
1626 (void) UnregisterMagickInfo("JPE");
1630 #if defined(MAGICKCORE_JPEG_DELEGATE)
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 % W r i t e J P E G I m a g e %
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642 % WriteJPEGImage() writes a JPEG image file and returns it. It
1643 % allocates the memory necessary for the new Image structure and returns a
1644 % pointer to the new image.
1646 % The format of the WriteJPEGImage method is:
1648 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1649 % Image *image,ExceptionInfo *exception)
1651 % A description of each parameter follows:
1653 % o image_info: the image info.
1655 % o jpeg_image: The image.
1657 % o exception: return any errors or warnings in this structure.
1661 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1663 assert(table != (QuantizationTable *) NULL);
1664 if (table->slot != (char *) NULL)
1665 table->slot=DestroyString(table->slot);
1666 if (table->description != (char *) NULL)
1667 table->description=DestroyString(table->description);
1668 if (table->levels != (unsigned int *) NULL)
1669 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1670 table=(QuantizationTable *) RelinquishMagickMemory(table);
1674 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1679 destination=(DestinationManager *) cinfo->dest;
1680 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1681 MaxBufferExtent,destination->buffer);
1682 if (destination->manager.free_in_buffer != MaxBufferExtent)
1683 ERREXIT(cinfo,JERR_FILE_WRITE);
1684 destination->manager.next_output_byte=destination->buffer;
1688 static QuantizationTable *GetQuantizationTable(const char *filename,
1689 const char *slot,ExceptionInfo *exception)
1717 *quantization_tables,
1720 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1721 "Loading quantization tables \"%s\" ...",filename);
1722 table=(QuantizationTable *) NULL;
1723 xml=FileToString(filename,~0UL,exception);
1724 if (xml == (char *) NULL)
1726 quantization_tables=NewXMLTree(xml,exception);
1727 if (quantization_tables == (XMLTreeInfo *) NULL)
1729 xml=DestroyString(xml);
1732 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1733 table_iterator != (XMLTreeInfo *) NULL;
1734 table_iterator=GetNextXMLTreeTag(table_iterator))
1736 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1737 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1739 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1740 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1743 if (table_iterator == (XMLTreeInfo *) NULL)
1745 xml=DestroyString(xml);
1748 description=GetXMLTreeChild(table_iterator,"description");
1749 if (description == (XMLTreeInfo *) NULL)
1751 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1752 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1753 quantization_tables=DestroyXMLTree(quantization_tables);
1754 xml=DestroyString(xml);
1757 levels=GetXMLTreeChild(table_iterator,"levels");
1758 if (levels == (XMLTreeInfo *) NULL)
1760 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1761 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1762 quantization_tables=DestroyXMLTree(quantization_tables);
1763 xml=DestroyString(xml);
1766 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1767 if (table == (QuantizationTable *) NULL)
1768 ThrowFatalException(ResourceLimitFatalError,
1769 "UnableToAcquireQuantizationTable");
1770 table->slot=(char *) NULL;
1771 table->description=(char *) NULL;
1772 table->levels=(unsigned int *) NULL;
1773 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1774 if (attribute != (char *) NULL)
1775 table->slot=ConstantString(attribute);
1776 content=GetXMLTreeContent(description);
1777 if (content != (char *) NULL)
1778 table->description=ConstantString(content);
1779 attribute=GetXMLTreeAttribute(levels,"width");
1780 if (attribute == (char *) NULL)
1782 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1783 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1784 quantization_tables=DestroyXMLTree(quantization_tables);
1785 table=DestroyQuantizationTable(table);
1786 xml=DestroyString(xml);
1789 table->width=StringToUnsignedLong(attribute);
1790 if (table->width == 0)
1792 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1793 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1794 quantization_tables=DestroyXMLTree(quantization_tables);
1795 table=DestroyQuantizationTable(table);
1796 xml=DestroyString(xml);
1799 attribute=GetXMLTreeAttribute(levels,"height");
1800 if (attribute == (char *) NULL)
1802 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1803 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1804 quantization_tables=DestroyXMLTree(quantization_tables);
1805 table=DestroyQuantizationTable(table);
1806 xml=DestroyString(xml);
1809 table->height=StringToUnsignedLong(attribute);
1810 if (table->height == 0)
1812 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1813 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1814 quantization_tables=DestroyXMLTree(quantization_tables);
1815 table=DestroyQuantizationTable(table);
1816 xml=DestroyString(xml);
1819 attribute=GetXMLTreeAttribute(levels,"divisor");
1820 if (attribute == (char *) NULL)
1822 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1823 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1824 quantization_tables=DestroyXMLTree(quantization_tables);
1825 table=DestroyQuantizationTable(table);
1826 xml=DestroyString(xml);
1829 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1830 if (table->divisor == 0.0)
1832 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1833 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1834 quantization_tables=DestroyXMLTree(quantization_tables);
1835 table=DestroyQuantizationTable(table);
1836 xml=DestroyString(xml);
1839 content=GetXMLTreeContent(levels);
1840 if (content == (char *) NULL)
1842 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1843 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1844 quantization_tables=DestroyXMLTree(quantization_tables);
1845 table=DestroyQuantizationTable(table);
1846 xml=DestroyString(xml);
1849 length=(size_t) table->width*table->height;
1852 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1853 sizeof(*table->levels));
1854 if (table->levels == (unsigned int *) NULL)
1855 ThrowFatalException(ResourceLimitFatalError,
1856 "UnableToAcquireQuantizationTable");
1857 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1859 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1860 table->divisor+0.5);
1861 while (isspace((int) ((unsigned char) *p)) != 0)
1867 value=InterpretLocaleValue(content,&p);
1871 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1872 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1873 quantization_tables=DestroyXMLTree(quantization_tables);
1874 table=DestroyQuantizationTable(table);
1875 xml=DestroyString(xml);
1878 for (j=i; j < 64; j++)
1879 table->levels[j]=table->levels[j-1];
1880 quantization_tables=DestroyXMLTree(quantization_tables);
1881 xml=DestroyString(xml);
1885 static void InitializeDestination(j_compress_ptr cinfo)
1890 destination=(DestinationManager *) cinfo->dest;
1891 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1892 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1893 destination->manager.next_output_byte=destination->buffer;
1894 destination->manager.free_in_buffer=MaxBufferExtent;
1897 static void TerminateDestination(j_compress_ptr cinfo)
1902 destination=(DestinationManager *) cinfo->dest;
1903 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1908 count=WriteBlob(destination->image,MaxBufferExtent-
1909 destination->manager.free_in_buffer,destination->buffer);
1910 if (count != (ssize_t)
1911 (MaxBufferExtent-destination->manager.free_in_buffer))
1912 ERREXIT(cinfo,JERR_FILE_WRITE);
1916 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1938 Save image profile as a APP marker.
1941 custom_profile=AcquireStringInfo(65535L);
1942 ResetImageProfileIterator(image);
1943 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1945 register unsigned char
1948 profile=GetImageProfile(image,name);
1949 p=GetStringInfoDatum(custom_profile);
1950 if (LocaleCompare(name,"EXIF") == 0)
1951 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1953 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1954 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1955 (unsigned int) length);
1957 if (LocaleCompare(name,"ICC") == 0)
1959 register unsigned char
1962 tag_length=strlen(ICC_PROFILE);
1963 p=GetStringInfoDatum(custom_profile);
1964 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1966 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1968 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1969 p[12]=(unsigned char) ((i/65519L)+1);
1970 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1971 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1973 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1974 custom_profile),(unsigned int) (length+tag_length+3));
1977 if (((LocaleCompare(name,"IPTC") == 0) ||
1978 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1984 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1986 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1987 roundup=(size_t) (length & 0x01);
1988 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1990 (void) memcpy(p,"Photoshop 3.0 ",14);
1995 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1997 p[24]=(unsigned char) (length >> 8);
1998 p[25]=(unsigned char) (length & 0xff);
2001 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2003 p[length+tag_length]='\0';
2004 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2005 custom_profile),(unsigned int) (length+tag_length+roundup));
2008 if (LocaleCompare(name,"XMP") == 0)
2014 Add namespace to XMP profile.
2016 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2017 if (xmp_profile != (StringInfo *) NULL)
2019 if (profile != (StringInfo *) NULL)
2020 ConcatenateStringInfo(xmp_profile,profile);
2021 GetStringInfoDatum(xmp_profile)[28]='\0';
2022 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2024 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2025 jpeg_write_marker(jpeg_info,XML_MARKER,
2026 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2028 xmp_profile=DestroyStringInfo(xmp_profile);
2031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2032 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2033 name=GetNextImageProfile(image);
2035 custom_profile=DestroyStringInfo(custom_profile);
2038 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2043 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2044 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2045 destination=(DestinationManager *) cinfo->dest;
2046 destination->manager.init_destination=InitializeDestination;
2047 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2048 destination->manager.term_destination=TerminateDestination;
2049 destination->image=image;
2052 static char **SamplingFactorToList(const char *text)
2069 if (text == (char *) NULL)
2070 return((char **) NULL);
2072 Convert string to an ASCII list.
2075 for (p=text; *p != '\0'; p++)
2078 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2080 if (textlist == (char **) NULL)
2081 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2083 for (i=0; i < (ssize_t) lines; i++)
2085 for (q=(char *) p; *q != '\0'; q++)
2088 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2089 sizeof(*textlist[i]));
2090 if (textlist[i] == (char *) NULL)
2091 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2092 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2097 textlist[i]=(char *) NULL;
2101 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2102 Image *image,ExceptionInfo *exception)
2117 *volatile jpeg_pixels;
2137 struct jpeg_compress_struct
2140 struct jpeg_error_mgr
2149 assert(image_info != (const ImageInfo *) NULL);
2150 assert(image_info->signature == MagickSignature);
2151 assert(image != (Image *) NULL);
2152 assert(image->signature == MagickSignature);
2153 if (image->debug != MagickFalse)
2154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2155 assert(exception != (ExceptionInfo *) NULL);
2156 assert(exception->signature == MagickSignature);
2157 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2158 (image->next != (Image *) NULL))
2159 image=AppendImages(image,MagickFalse,exception);
2160 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2161 if (status == MagickFalse)
2164 Initialize JPEG parameters.
2166 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2167 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2168 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2169 jpeg_info.client_data=(void *) image;
2170 jpeg_info.err=jpeg_std_error(&jpeg_error);
2171 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2172 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2173 error_manager.exception=exception;
2174 error_manager.image=image;
2175 memory_info=(MemoryInfo *) NULL;
2176 if (setjmp(error_manager.error_recovery) != 0)
2178 jpeg_destroy_compress(&jpeg_info);
2179 (void) CloseBlob(image);
2180 return(MagickFalse);
2182 jpeg_info.client_data=(void *) &error_manager;
2183 jpeg_create_compress(&jpeg_info);
2184 JPEGDestinationManager(&jpeg_info,image);
2185 if ((image->columns != (unsigned int) image->columns) ||
2186 (image->rows != (unsigned int) image->rows))
2187 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2188 jpeg_info.image_width=(unsigned int) image->columns;
2189 jpeg_info.image_height=(unsigned int) image->rows;
2190 jpeg_info.input_components=3;
2191 jpeg_info.data_precision=8;
2192 jpeg_info.in_color_space=JCS_RGB;
2193 switch (image->colorspace)
2195 case CMYKColorspace:
2197 jpeg_info.input_components=4;
2198 jpeg_info.in_color_space=JCS_CMYK;
2201 case YCbCrColorspace:
2202 case Rec601YCbCrColorspace:
2203 case Rec709YCbCrColorspace:
2205 jpeg_info.in_color_space=JCS_YCbCr;
2208 case GRAYColorspace:
2210 if (image_info->type == TrueColorType)
2212 jpeg_info.input_components=1;
2213 jpeg_info.in_color_space=JCS_GRAYSCALE;
2218 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2219 if (image_info->type == TrueColorType)
2221 if (IsImageGray(image,exception) != MagickFalse)
2223 jpeg_info.input_components=1;
2224 jpeg_info.in_color_space=JCS_GRAYSCALE;
2229 jpeg_set_defaults(&jpeg_info);
2230 if (jpeg_info.in_color_space == JCS_CMYK)
2231 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2232 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2233 jpeg_info.data_precision=8;
2235 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2236 jpeg_info.density_unit=1;
2237 if (image->debug != MagickFalse)
2238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2239 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2240 floor(image->resolution.y+0.5));
2241 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2244 Set image resolution.
2246 jpeg_info.write_JFIF_header=TRUE;
2247 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2248 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2250 Set image resolution units.
2252 jpeg_info.density_unit=(UINT8) 0;
2253 if (image->units == PixelsPerInchResolution)
2254 jpeg_info.density_unit=(UINT8) 1;
2255 if (image->units == PixelsPerCentimeterResolution)
2256 jpeg_info.density_unit=(UINT8) 2;
2258 jpeg_info.dct_method=JDCT_FLOAT;
2259 option=GetImageOption(image_info,"jpeg:dct-method");
2260 if (option != (const char *) NULL)
2266 if (LocaleCompare(option,"default") == 0)
2267 jpeg_info.dct_method=JDCT_DEFAULT;
2273 if (LocaleCompare(option,"fastest") == 0)
2274 jpeg_info.dct_method=JDCT_FASTEST;
2275 if (LocaleCompare(option,"float") == 0)
2276 jpeg_info.dct_method=JDCT_FLOAT;
2282 if (LocaleCompare(option,"ifast") == 0)
2283 jpeg_info.dct_method=JDCT_IFAST;
2284 if (LocaleCompare(option,"islow") == 0)
2285 jpeg_info.dct_method=JDCT_ISLOW;
2289 option=GetImageOption(image_info,"jpeg:optimize-coding");
2290 if (option != (const char *) NULL)
2291 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2298 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2299 image->rows*sizeof(JSAMPLE);
2300 if (length == (MagickSizeType) ((size_t) length))
2303 Perform optimization only if available memory resources permit it.
2305 status=AcquireMagickResource(MemoryResource,length);
2306 RelinquishMagickResource(MemoryResource,length);
2307 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2310 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2311 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2312 (image_info->interlace != NoInterlace))
2314 if (image->debug != MagickFalse)
2315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2316 "Interlace: progressive");
2317 jpeg_simple_progression(&jpeg_info);
2320 if (image->debug != MagickFalse)
2321 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2322 "Interlace: non-progressive");
2324 if (image->debug != MagickFalse)
2325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2326 "Interlace: nonprogressive");
2329 if ((image_info->compression != LosslessJPEGCompression) &&
2330 (image->quality <= 100))
2332 if (image->quality != UndefinedCompressionQuality)
2333 quality=(int) image->quality;
2334 if (image->debug != MagickFalse)
2335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2336 (double) image->quality);
2340 #if !defined(C_LOSSLESS_SUPPORTED)
2342 if (image->debug != MagickFalse)
2343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2345 if (image->quality < 100)
2346 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2347 "LosslessToLossyJPEGConversion",image->filename);
2354 predictor=image->quality/100; /* range 1-7 */
2355 point_transform=image->quality % 20; /* range 0-15 */
2356 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2357 if (image->debug != MagickFalse)
2359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2360 "Compression: lossless");
2361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2362 "Predictor: %d",predictor);
2363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2364 "Point Transform: %d",point_transform);
2369 option=GetImageOption(image_info,"jpeg:extent");
2370 if (option != (const char *) NULL)
2378 jpeg_info=CloneImageInfo(image_info);
2379 jpeg_info->blob=NULL;
2380 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2381 if (jpeg_image != (Image *) NULL)
2391 Search for compression quality that does not exceed image extent.
2393 jpeg_info->quality=0;
2394 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2395 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2396 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2398 for (minimum=2; minimum < maximum; )
2400 (void) AcquireUniqueFilename(jpeg_image->filename);
2401 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2402 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2403 if (GetBlobSize(jpeg_image) <= extent)
2404 minimum=jpeg_image->quality+1;
2406 maximum=jpeg_image->quality-1;
2407 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2409 quality=(int)minimum-1;
2410 jpeg_image=DestroyImage(jpeg_image);
2412 jpeg_info=DestroyImageInfo(jpeg_info);
2414 jpeg_set_quality(&jpeg_info,quality,TRUE);
2415 #if (JPEG_LIB_VERSION >= 70)
2416 option=GetImageOption(image_info,"quality");
2417 if (option != (const char *) NULL)
2426 Set quality scaling for luminance and chrominance separately.
2428 flags=ParseGeometry(option,&geometry_info);
2429 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2431 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2432 (geometry_info.rho+0.5));
2433 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2434 (geometry_info.sigma+0.5));
2435 jpeg_default_qtables(&jpeg_info,TRUE);
2439 colorspace=jpeg_info.in_color_space;
2440 value=GetImageOption(image_info,"jpeg:colorspace");
2441 if (value == (char *) NULL)
2442 value=GetImageProperty(image,"jpeg:colorspace",exception);
2443 if (value != (char *) NULL)
2444 colorspace=StringToInteger(value);
2445 sampling_factor=(const char *) NULL;
2446 if (colorspace == jpeg_info.in_color_space)
2448 value=GetImageOption(image_info,"jpeg:sampling-factor");
2449 if (value == (char *) NULL)
2450 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2451 if (value != (char *) NULL)
2453 sampling_factor=value;
2454 if (image->debug != MagickFalse)
2455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2456 " Input sampling-factors=%s",sampling_factor);
2459 value=GetImageOption(image_info,"jpeg:sampling-factor");
2460 if (image_info->sampling_factor != (char *) NULL)
2461 sampling_factor=image_info->sampling_factor;
2462 if (sampling_factor == (const char *) NULL)
2464 if (image->quality >= 90)
2465 for (i=0; i < MAX_COMPONENTS; i++)
2467 jpeg_info.comp_info[i].h_samp_factor=1;
2468 jpeg_info.comp_info[i].v_samp_factor=1;
2483 Set sampling factor.
2486 factors=SamplingFactorToList(sampling_factor);
2487 if (factors != (char **) NULL)
2489 for (i=0; i < MAX_COMPONENTS; i++)
2491 if (factors[i] == (char *) NULL)
2493 flags=ParseGeometry(factors[i],&geometry_info);
2494 if ((flags & SigmaValue) == 0)
2495 geometry_info.sigma=geometry_info.rho;
2496 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2497 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2498 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2500 factors=(char **) RelinquishMagickMemory(factors);
2502 for ( ; i < MAX_COMPONENTS; i++)
2504 jpeg_info.comp_info[i].h_samp_factor=1;
2505 jpeg_info.comp_info[i].v_samp_factor=1;
2508 option=GetImageOption(image_info,"jpeg:q-table");
2509 if (option != (const char *) NULL)
2515 Custom quantization tables.
2517 table=GetQuantizationTable(option,"0",exception);
2518 if (table != (QuantizationTable *) NULL)
2520 for (i=0; i < MAX_COMPONENTS; i++)
2521 jpeg_info.comp_info[i].quant_tbl_no=0;
2522 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2523 jpeg_quality_scaling(quality),0);
2524 table=DestroyQuantizationTable(table);
2526 table=GetQuantizationTable(option,"1",exception);
2527 if (table != (QuantizationTable *) NULL)
2529 for (i=1; i < MAX_COMPONENTS; i++)
2530 jpeg_info.comp_info[i].quant_tbl_no=1;
2531 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2532 jpeg_quality_scaling(quality),0);
2533 table=DestroyQuantizationTable(table);
2535 table=GetQuantizationTable(option,"2",exception);
2536 if (table != (QuantizationTable *) NULL)
2538 for (i=2; i < MAX_COMPONENTS; i++)
2539 jpeg_info.comp_info[i].quant_tbl_no=2;
2540 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2541 jpeg_quality_scaling(quality),0);
2542 table=DestroyQuantizationTable(table);
2544 table=GetQuantizationTable(option,"3",exception);
2545 if (table != (QuantizationTable *) NULL)
2547 for (i=3; i < MAX_COMPONENTS; i++)
2548 jpeg_info.comp_info[i].quant_tbl_no=3;
2549 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2550 jpeg_quality_scaling(quality),0);
2551 table=DestroyQuantizationTable(table);
2554 jpeg_start_compress(&jpeg_info,TRUE);
2555 if (image->debug != MagickFalse)
2557 if (image->storage_class == PseudoClass)
2558 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2559 "Storage class: PseudoClass");
2561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2562 "Storage class: DirectClass");
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2564 (double) image->depth);
2565 if (image->colors != 0)
2566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2567 "Number of colors: %.20g",(double) image->colors);
2569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2570 "Number of colors: unspecified");
2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2572 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2573 switch (image->colorspace)
2575 case CMYKColorspace:
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2578 "Storage class: DirectClass");
2579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2580 "Colorspace: CMYK");
2583 case YCbCrColorspace:
2584 case Rec601YCbCrColorspace:
2585 case Rec709YCbCrColorspace:
2587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2588 "Colorspace: YCbCr");
2594 switch (image->colorspace)
2596 case CMYKColorspace:
2598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2599 "Colorspace: CMYK");
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2601 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2602 jpeg_info.comp_info[0].h_samp_factor,
2603 jpeg_info.comp_info[0].v_samp_factor,
2604 jpeg_info.comp_info[1].h_samp_factor,
2605 jpeg_info.comp_info[1].v_samp_factor,
2606 jpeg_info.comp_info[2].h_samp_factor,
2607 jpeg_info.comp_info[2].v_samp_factor,
2608 jpeg_info.comp_info[3].h_samp_factor,
2609 jpeg_info.comp_info[3].v_samp_factor);
2612 case GRAYColorspace:
2614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2615 "Colorspace: GRAY");
2616 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2617 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2618 jpeg_info.comp_info[0].v_samp_factor);
2621 case sRGBColorspace:
2624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2625 "Image colorspace is RGB");
2626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2627 "Sampling factors: %dx%d,%dx%d,%dx%d",
2628 jpeg_info.comp_info[0].h_samp_factor,
2629 jpeg_info.comp_info[0].v_samp_factor,
2630 jpeg_info.comp_info[1].h_samp_factor,
2631 jpeg_info.comp_info[1].v_samp_factor,
2632 jpeg_info.comp_info[2].h_samp_factor,
2633 jpeg_info.comp_info[2].v_samp_factor);
2636 case YCbCrColorspace:
2637 case Rec601YCbCrColorspace:
2638 case Rec709YCbCrColorspace:
2640 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2641 "Colorspace: YCbCr");
2642 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2643 "Sampling factors: %dx%d,%dx%d,%dx%d",
2644 jpeg_info.comp_info[0].h_samp_factor,
2645 jpeg_info.comp_info[0].v_samp_factor,
2646 jpeg_info.comp_info[1].h_samp_factor,
2647 jpeg_info.comp_info[1].v_samp_factor,
2648 jpeg_info.comp_info[2].h_samp_factor,
2649 jpeg_info.comp_info[2].v_samp_factor);
2654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2657 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2658 jpeg_info.comp_info[0].h_samp_factor,
2659 jpeg_info.comp_info[0].v_samp_factor,
2660 jpeg_info.comp_info[1].h_samp_factor,
2661 jpeg_info.comp_info[1].v_samp_factor,
2662 jpeg_info.comp_info[2].h_samp_factor,
2663 jpeg_info.comp_info[2].v_samp_factor,
2664 jpeg_info.comp_info[3].h_samp_factor,
2665 jpeg_info.comp_info[3].v_samp_factor);
2671 Write JPEG profiles.
2673 value=GetImageProperty(image,"comment",exception);
2674 if (value != (char *) NULL)
2675 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2676 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2677 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2678 if (image->profiles != (void *) NULL)
2679 WriteProfile(&jpeg_info,image);
2681 Convert MIFF to JPEG raster pixels.
2683 memory_info=AcquireVirtualMemory((size_t) image->columns,
2684 jpeg_info.input_components*sizeof(*jpeg_pixels));
2685 if (memory_info == (MemoryInfo *) NULL)
2686 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2687 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2688 if (setjmp(error_manager.error_recovery) != 0)
2690 jpeg_destroy_compress(&jpeg_info);
2691 if (memory_info != (MemoryInfo *) NULL)
2692 memory_info=RelinquishVirtualMemory(memory_info);
2693 (void) CloseBlob(image);
2694 return(MagickFalse);
2696 scanline[0]=(JSAMPROW) jpeg_pixels;
2697 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2700 if (jpeg_info.data_precision <= 8)
2702 if ((jpeg_info.in_color_space == JCS_RGB) ||
2703 (jpeg_info.in_color_space == JCS_YCbCr))
2704 for (y=0; y < (ssize_t) image->rows; y++)
2706 register const Quantum
2712 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2713 if (p == (const Quantum *) NULL)
2716 for (x=0; x < (ssize_t) image->columns; x++)
2718 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2719 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2720 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2721 p+=GetPixelChannels(image);
2723 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2724 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2726 if (status == MagickFalse)
2730 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2731 for (y=0; y < (ssize_t) image->rows; y++)
2733 register const Quantum
2739 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2740 if (p == (const Quantum *) NULL)
2743 for (x=0; x < (ssize_t) image->columns; x++)
2745 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2747 p+=GetPixelChannels(image);
2749 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2750 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2752 if (status == MagickFalse)
2756 for (y=0; y < (ssize_t) image->rows; y++)
2758 register const Quantum
2764 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2765 if (p == (const Quantum *) NULL)
2768 for (x=0; x < (ssize_t) image->columns; x++)
2771 Convert DirectClass packets to contiguous CMYK scanlines.
2773 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2774 GetPixelCyan(image,p))));
2775 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2776 GetPixelMagenta(image,p))));
2777 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2778 GetPixelYellow(image,p))));
2779 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2780 GetPixelBlack(image,p))));
2781 p+=GetPixelChannels(image);
2783 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2784 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2786 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) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
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 if ((jpeg_info.in_color_space == JCS_RGB) ||
2818 (jpeg_info.in_color_space == JCS_YCbCr))
2819 for (y=0; y < (ssize_t) image->rows; y++)
2821 register const Quantum
2827 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2828 if (p == (const Quantum *) NULL)
2831 for (x=0; x < (ssize_t) image->columns; x++)
2833 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2834 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2835 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2836 p+=GetPixelChannels(image);
2838 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2839 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2841 if (status == MagickFalse)
2845 for (y=0; y < (ssize_t) image->rows; y++)
2847 register const Quantum
2853 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2854 if (p == (const Quantum *) NULL)
2857 for (x=0; x < (ssize_t) image->columns; x++)
2860 Convert DirectClass packets to contiguous CMYK scanlines.
2862 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2864 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2866 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2868 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2870 p+=GetPixelChannels(image);
2872 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2873 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2875 if (status == MagickFalse)
2878 if (y == (ssize_t) image->rows)
2879 jpeg_finish_compress(&jpeg_info);
2881 Relinquish resources.
2883 jpeg_destroy_compress(&jpeg_info);
2884 memory_info=RelinquishVirtualMemory(memory_info);
2885 (void) CloseBlob(image);