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)
1306 jpeg_destroy_decompress(&jpeg_info);
1307 return(DestroyImageList(image));
1309 if ((jpeg_info.output_components != 1) &&
1310 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1312 jpeg_destroy_decompress(&jpeg_info);
1313 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1315 memory_info=AcquireVirtualMemory((size_t) image->columns,
1316 jpeg_info.output_components*sizeof(*jpeg_pixels));
1317 if (memory_info == (MemoryInfo *) NULL)
1319 jpeg_destroy_decompress(&jpeg_info);
1320 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1322 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1324 Convert JPEG pixels to pixel packets.
1326 if (setjmp(error_manager.error_recovery) != 0)
1328 if (memory_info != (MemoryInfo *) NULL)
1329 memory_info=RelinquishVirtualMemory(memory_info);
1330 jpeg_destroy_decompress(&jpeg_info);
1331 (void) CloseBlob(image);
1332 number_pixels=(MagickSizeType) image->columns*image->rows;
1333 if (number_pixels != 0)
1334 return(GetFirstImageInList(image));
1335 return(DestroyImage(image));
1337 if (jpeg_info.quantize_colors != MagickFalse)
1339 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1340 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
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=image->colormap[i].red;
1346 image->colormap[i].blue=image->colormap[i].red;
1347 image->colormap[i].alpha=OpaqueAlpha;
1350 for (i=0; i < (ssize_t) image->colors; i++)
1352 image->colormap[i].red=(double) ScaleCharToQuantum(
1353 jpeg_info.colormap[0][i]);
1354 image->colormap[i].green=(double) ScaleCharToQuantum(
1355 jpeg_info.colormap[1][i]);
1356 image->colormap[i].blue=(double) ScaleCharToQuantum(
1357 jpeg_info.colormap[2][i]);
1358 image->colormap[i].alpha=OpaqueAlpha;
1361 scanline[0]=(JSAMPROW) jpeg_pixels;
1362 for (y=0; y < (ssize_t) image->rows; y++)
1370 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1372 (void) ThrowMagickException(exception,GetMagickModule(),
1373 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1377 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1378 if (q == (Quantum *) NULL)
1380 if (jpeg_info.data_precision > 8)
1385 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1386 if (jpeg_info.output_components == 1)
1387 for (x=0; x < (ssize_t) image->columns; x++)
1392 pixel=(size_t) (scale*GETJSAMPLE(*p));
1393 index=ConstrainColormapIndex(image,pixel,exception);
1394 SetPixelIndex(image,index,q);
1395 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1397 q+=GetPixelChannels(image);
1400 if (image->colorspace != CMYKColorspace)
1401 for (x=0; x < (ssize_t) image->columns; x++)
1403 SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1405 SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1407 SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1409 SetPixelAlpha(image,OpaqueAlpha,q);
1410 q+=GetPixelChannels(image);
1413 for (x=0; x < (ssize_t) image->columns; x++)
1415 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(scale*
1416 GETJSAMPLE(*p++)),q);
1417 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(scale*
1418 GETJSAMPLE(*p++)),q);
1419 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(scale*
1420 GETJSAMPLE(*p++)),q);
1421 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(scale*
1422 GETJSAMPLE(*p++)),q);
1423 SetPixelAlpha(image,OpaqueAlpha,q);
1424 q+=GetPixelChannels(image);
1428 if (jpeg_info.output_components == 1)
1429 for (x=0; x < (ssize_t) image->columns; x++)
1431 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1432 SetPixelIndex(image,index,q);
1433 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1435 q+=GetPixelChannels(image);
1438 if (image->colorspace != CMYKColorspace)
1439 for (x=0; x < (ssize_t) image->columns; x++)
1441 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1442 GETJSAMPLE(*p++)),q);
1443 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1444 GETJSAMPLE(*p++)),q);
1445 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1446 GETJSAMPLE(*p++)),q);
1447 SetPixelAlpha(image,OpaqueAlpha,q);
1448 q+=GetPixelChannels(image);
1451 for (x=0; x < (ssize_t) image->columns; x++)
1453 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1454 (unsigned char) GETJSAMPLE(*p++)),q);
1455 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1456 (unsigned char) GETJSAMPLE(*p++)),q);
1457 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1458 (unsigned char) GETJSAMPLE(*p++)),q);
1459 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1460 (unsigned char) GETJSAMPLE(*p++)),q);
1461 SetPixelAlpha(image,OpaqueAlpha,q);
1462 q+=GetPixelChannels(image);
1464 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1466 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1468 if (status == MagickFalse)
1470 jpeg_abort_decompress(&jpeg_info);
1474 if (status != MagickFalse)
1476 error_manager.finished=MagickTrue;
1477 if (setjmp(error_manager.error_recovery) == 0)
1478 (void) jpeg_finish_decompress(&jpeg_info);
1481 Free jpeg resources.
1483 jpeg_destroy_decompress(&jpeg_info);
1484 memory_info=RelinquishVirtualMemory(memory_info);
1485 (void) CloseBlob(image);
1486 return(GetFirstImageInList(image));
1492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 % R e g i s t e r J P E G I m a g e %
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502 % RegisterJPEGImage() adds properties for the JPEG image format to
1503 % the list of supported formats. The properties include the image format
1504 % tag, a method to read and/or write the format, whether the format
1505 % supports the saving of more than one frame to the same file or blob,
1506 % whether the format supports native in-memory I/O, and a brief
1507 % description of the format.
1509 % The format of the RegisterJPEGImage method is:
1511 % size_t RegisterJPEGImage(void)
1514 ModuleExport size_t RegisterJPEGImage(void)
1517 version[MaxTextExtent];
1523 description[] = "Joint Photographic Experts Group JFIF format";
1526 #if defined(JPEG_LIB_VERSION)
1527 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1529 entry=SetMagickInfo("JPE");
1530 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1531 entry->thread_support=NoThreadSupport;
1533 #if defined(MAGICKCORE_JPEG_DELEGATE)
1534 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1535 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1537 entry->magick=(IsImageFormatHandler *) IsJPEG;
1538 entry->flags^=CoderAdjoinFlag;
1539 entry->flags^=CoderUseExtensionFlag;
1540 entry->description=ConstantString(description);
1541 if (*version != '\0')
1542 entry->version=ConstantString(version);
1543 entry->mime_type=ConstantString("image/jpeg");
1544 entry->module=ConstantString("JPEG");
1545 (void) RegisterMagickInfo(entry);
1546 entry=SetMagickInfo("JPEG");
1547 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1548 entry->thread_support=NoThreadSupport;
1550 #if defined(MAGICKCORE_JPEG_DELEGATE)
1551 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1552 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1554 entry->magick=(IsImageFormatHandler *) IsJPEG;
1555 entry->flags^=CoderAdjoinFlag;
1556 entry->description=ConstantString(description);
1557 if (*version != '\0')
1558 entry->version=ConstantString(version);
1559 entry->mime_type=ConstantString("image/jpeg");
1560 entry->module=ConstantString("JPEG");
1561 (void) RegisterMagickInfo(entry);
1562 entry=SetMagickInfo("JPG");
1563 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1564 entry->thread_support=NoThreadSupport;
1566 #if defined(MAGICKCORE_JPEG_DELEGATE)
1567 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1568 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1570 entry->flags^=CoderAdjoinFlag;
1571 entry->flags^=CoderUseExtensionFlag;
1572 entry->description=ConstantString(description);
1573 if (*version != '\0')
1574 entry->version=ConstantString(version);
1575 entry->mime_type=ConstantString("image/jpeg");
1576 entry->module=ConstantString("JPEG");
1577 (void) RegisterMagickInfo(entry);
1578 entry=SetMagickInfo("JPS");
1579 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1580 entry->thread_support=NoThreadSupport;
1582 #if defined(MAGICKCORE_JPEG_DELEGATE)
1583 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1584 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1586 entry->flags^=CoderAdjoinFlag;
1587 entry->flags^=CoderUseExtensionFlag;
1588 entry->description=ConstantString(description);
1589 if (*version != '\0')
1590 entry->version=ConstantString(version);
1591 entry->mime_type=ConstantString("image/jpeg");
1592 entry->module=ConstantString("JPEG");
1593 (void) RegisterMagickInfo(entry);
1594 entry=SetMagickInfo("PJPEG");
1595 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1596 entry->thread_support=NoThreadSupport;
1598 #if defined(MAGICKCORE_JPEG_DELEGATE)
1599 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1600 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1602 entry->flags^=CoderAdjoinFlag;
1603 entry->flags^=CoderUseExtensionFlag;
1604 entry->description=ConstantString(description);
1605 if (*version != '\0')
1606 entry->version=ConstantString(version);
1607 entry->mime_type=ConstantString("image/jpeg");
1608 entry->module=ConstantString("JPEG");
1609 (void) RegisterMagickInfo(entry);
1610 return(MagickImageCoderSignature);
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 % U n r e g i s t e r J P E G I m a g e %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % UnregisterJPEGImage() removes format registrations made by the
1626 % JPEG module from the list of supported formats.
1628 % The format of the UnregisterJPEGImage method is:
1630 % UnregisterJPEGImage(void)
1633 ModuleExport void UnregisterJPEGImage(void)
1635 (void) UnregisterMagickInfo("PJPG");
1636 (void) UnregisterMagickInfo("JPS");
1637 (void) UnregisterMagickInfo("JPG");
1638 (void) UnregisterMagickInfo("JPEG");
1639 (void) UnregisterMagickInfo("JPE");
1643 #if defined(MAGICKCORE_JPEG_DELEGATE)
1645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1649 % W r i t e J P E G I m a g e %
1653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1655 % WriteJPEGImage() writes a JPEG image file and returns it. It
1656 % allocates the memory necessary for the new Image structure and returns a
1657 % pointer to the new image.
1659 % The format of the WriteJPEGImage method is:
1661 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1662 % Image *image,ExceptionInfo *exception)
1664 % A description of each parameter follows:
1666 % o image_info: the image info.
1668 % o jpeg_image: The image.
1670 % o exception: return any errors or warnings in this structure.
1674 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1676 assert(table != (QuantizationTable *) NULL);
1677 if (table->slot != (char *) NULL)
1678 table->slot=DestroyString(table->slot);
1679 if (table->description != (char *) NULL)
1680 table->description=DestroyString(table->description);
1681 if (table->levels != (unsigned int *) NULL)
1682 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1683 table=(QuantizationTable *) RelinquishMagickMemory(table);
1687 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1692 destination=(DestinationManager *) cinfo->dest;
1693 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1694 MaxBufferExtent,destination->buffer);
1695 if (destination->manager.free_in_buffer != MaxBufferExtent)
1696 ERREXIT(cinfo,JERR_FILE_WRITE);
1697 destination->manager.next_output_byte=destination->buffer;
1701 static QuantizationTable *GetQuantizationTable(const char *filename,
1702 const char *slot,ExceptionInfo *exception)
1730 *quantization_tables,
1733 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1734 "Loading quantization tables \"%s\" ...",filename);
1735 table=(QuantizationTable *) NULL;
1736 xml=FileToString(filename,~0UL,exception);
1737 if (xml == (char *) NULL)
1739 quantization_tables=NewXMLTree(xml,exception);
1740 if (quantization_tables == (XMLTreeInfo *) NULL)
1742 xml=DestroyString(xml);
1745 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1746 table_iterator != (XMLTreeInfo *) NULL;
1747 table_iterator=GetNextXMLTreeTag(table_iterator))
1749 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1750 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1752 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1753 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1756 if (table_iterator == (XMLTreeInfo *) NULL)
1758 xml=DestroyString(xml);
1761 description=GetXMLTreeChild(table_iterator,"description");
1762 if (description == (XMLTreeInfo *) NULL)
1764 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1765 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1766 quantization_tables=DestroyXMLTree(quantization_tables);
1767 xml=DestroyString(xml);
1770 levels=GetXMLTreeChild(table_iterator,"levels");
1771 if (levels == (XMLTreeInfo *) NULL)
1773 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1774 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1775 quantization_tables=DestroyXMLTree(quantization_tables);
1776 xml=DestroyString(xml);
1779 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1780 if (table == (QuantizationTable *) NULL)
1781 ThrowFatalException(ResourceLimitFatalError,
1782 "UnableToAcquireQuantizationTable");
1783 table->slot=(char *) NULL;
1784 table->description=(char *) NULL;
1785 table->levels=(unsigned int *) NULL;
1786 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1787 if (attribute != (char *) NULL)
1788 table->slot=ConstantString(attribute);
1789 content=GetXMLTreeContent(description);
1790 if (content != (char *) NULL)
1791 table->description=ConstantString(content);
1792 attribute=GetXMLTreeAttribute(levels,"width");
1793 if (attribute == (char *) NULL)
1795 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1796 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1797 quantization_tables=DestroyXMLTree(quantization_tables);
1798 table=DestroyQuantizationTable(table);
1799 xml=DestroyString(xml);
1802 table->width=StringToUnsignedLong(attribute);
1803 if (table->width == 0)
1805 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1806 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1807 quantization_tables=DestroyXMLTree(quantization_tables);
1808 table=DestroyQuantizationTable(table);
1809 xml=DestroyString(xml);
1812 attribute=GetXMLTreeAttribute(levels,"height");
1813 if (attribute == (char *) NULL)
1815 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1816 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1817 quantization_tables=DestroyXMLTree(quantization_tables);
1818 table=DestroyQuantizationTable(table);
1819 xml=DestroyString(xml);
1822 table->height=StringToUnsignedLong(attribute);
1823 if (table->height == 0)
1825 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1826 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1827 quantization_tables=DestroyXMLTree(quantization_tables);
1828 table=DestroyQuantizationTable(table);
1829 xml=DestroyString(xml);
1832 attribute=GetXMLTreeAttribute(levels,"divisor");
1833 if (attribute == (char *) NULL)
1835 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1836 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1837 quantization_tables=DestroyXMLTree(quantization_tables);
1838 table=DestroyQuantizationTable(table);
1839 xml=DestroyString(xml);
1842 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1843 if (table->divisor == 0.0)
1845 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1846 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1847 quantization_tables=DestroyXMLTree(quantization_tables);
1848 table=DestroyQuantizationTable(table);
1849 xml=DestroyString(xml);
1852 content=GetXMLTreeContent(levels);
1853 if (content == (char *) NULL)
1855 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1856 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1857 quantization_tables=DestroyXMLTree(quantization_tables);
1858 table=DestroyQuantizationTable(table);
1859 xml=DestroyString(xml);
1862 length=(size_t) table->width*table->height;
1865 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1866 sizeof(*table->levels));
1867 if (table->levels == (unsigned int *) NULL)
1868 ThrowFatalException(ResourceLimitFatalError,
1869 "UnableToAcquireQuantizationTable");
1870 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1872 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1873 table->divisor+0.5);
1874 while (isspace((int) ((unsigned char) *p)) != 0)
1880 value=InterpretLocaleValue(content,&p);
1884 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1885 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1886 quantization_tables=DestroyXMLTree(quantization_tables);
1887 table=DestroyQuantizationTable(table);
1888 xml=DestroyString(xml);
1891 for (j=i; j < 64; j++)
1892 table->levels[j]=table->levels[j-1];
1893 quantization_tables=DestroyXMLTree(quantization_tables);
1894 xml=DestroyString(xml);
1898 static void InitializeDestination(j_compress_ptr cinfo)
1903 destination=(DestinationManager *) cinfo->dest;
1904 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1905 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1906 destination->manager.next_output_byte=destination->buffer;
1907 destination->manager.free_in_buffer=MaxBufferExtent;
1910 static void TerminateDestination(j_compress_ptr cinfo)
1915 destination=(DestinationManager *) cinfo->dest;
1916 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1921 count=WriteBlob(destination->image,MaxBufferExtent-
1922 destination->manager.free_in_buffer,destination->buffer);
1923 if (count != (ssize_t)
1924 (MaxBufferExtent-destination->manager.free_in_buffer))
1925 ERREXIT(cinfo,JERR_FILE_WRITE);
1929 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1951 Save image profile as a APP marker.
1954 custom_profile=AcquireStringInfo(65535L);
1955 ResetImageProfileIterator(image);
1956 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1958 register unsigned char
1961 profile=GetImageProfile(image,name);
1962 p=GetStringInfoDatum(custom_profile);
1963 if (LocaleCompare(name,"EXIF") == 0)
1964 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1966 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1967 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1968 (unsigned int) length);
1970 if (LocaleCompare(name,"ICC") == 0)
1972 register unsigned char
1975 tag_length=strlen(ICC_PROFILE);
1976 p=GetStringInfoDatum(custom_profile);
1977 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1979 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1981 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1982 p[12]=(unsigned char) ((i/65519L)+1);
1983 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1984 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1986 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1987 custom_profile),(unsigned int) (length+tag_length+3));
1990 if (((LocaleCompare(name,"IPTC") == 0) ||
1991 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1997 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1999 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
2000 roundup=(size_t) (length & 0x01);
2001 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
2003 (void) memcpy(p,"Photoshop 3.0 ",14);
2008 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2010 p[24]=(unsigned char) (length >> 8);
2011 p[25]=(unsigned char) (length & 0xff);
2014 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2016 p[length+tag_length]='\0';
2017 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2018 custom_profile),(unsigned int) (length+tag_length+roundup));
2021 if (LocaleCompare(name,"XMP") == 0)
2027 Add namespace to XMP profile.
2029 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2030 if (xmp_profile != (StringInfo *) NULL)
2032 if (profile != (StringInfo *) NULL)
2033 ConcatenateStringInfo(xmp_profile,profile);
2034 GetStringInfoDatum(xmp_profile)[28]='\0';
2035 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2037 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2038 jpeg_write_marker(jpeg_info,XML_MARKER,
2039 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2041 xmp_profile=DestroyStringInfo(xmp_profile);
2044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2045 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2046 name=GetNextImageProfile(image);
2048 custom_profile=DestroyStringInfo(custom_profile);
2051 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2056 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2057 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2058 destination=(DestinationManager *) cinfo->dest;
2059 destination->manager.init_destination=InitializeDestination;
2060 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2061 destination->manager.term_destination=TerminateDestination;
2062 destination->image=image;
2065 static char **SamplingFactorToList(const char *text)
2082 if (text == (char *) NULL)
2083 return((char **) NULL);
2085 Convert string to an ASCII list.
2088 for (p=text; *p != '\0'; p++)
2091 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2093 if (textlist == (char **) NULL)
2094 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2096 for (i=0; i < (ssize_t) lines; i++)
2098 for (q=(char *) p; *q != '\0'; q++)
2101 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2102 sizeof(*textlist[i]));
2103 if (textlist[i] == (char *) NULL)
2104 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2105 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2110 textlist[i]=(char *) NULL;
2114 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2115 Image *image,ExceptionInfo *exception)
2130 *volatile jpeg_pixels;
2150 struct jpeg_compress_struct
2153 struct jpeg_error_mgr
2162 assert(image_info != (const ImageInfo *) NULL);
2163 assert(image_info->signature == MagickSignature);
2164 assert(image != (Image *) NULL);
2165 assert(image->signature == MagickSignature);
2166 if (image->debug != MagickFalse)
2167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2168 assert(exception != (ExceptionInfo *) NULL);
2169 assert(exception->signature == MagickSignature);
2170 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2171 (image->next != (Image *) NULL))
2172 image=AppendImages(image,MagickFalse,exception);
2173 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2174 if (status == MagickFalse)
2177 Initialize JPEG parameters.
2179 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2180 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2181 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2182 jpeg_info.client_data=(void *) image;
2183 jpeg_info.err=jpeg_std_error(&jpeg_error);
2184 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2185 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2186 error_manager.exception=exception;
2187 error_manager.image=image;
2188 memory_info=(MemoryInfo *) NULL;
2189 if (setjmp(error_manager.error_recovery) != 0)
2191 jpeg_destroy_compress(&jpeg_info);
2192 (void) CloseBlob(image);
2193 return(MagickFalse);
2195 jpeg_info.client_data=(void *) &error_manager;
2196 jpeg_create_compress(&jpeg_info);
2197 JPEGDestinationManager(&jpeg_info,image);
2198 if ((image->columns != (unsigned int) image->columns) ||
2199 (image->rows != (unsigned int) image->rows))
2200 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2201 jpeg_info.image_width=(unsigned int) image->columns;
2202 jpeg_info.image_height=(unsigned int) image->rows;
2203 jpeg_info.input_components=3;
2204 jpeg_info.data_precision=8;
2205 jpeg_info.in_color_space=JCS_RGB;
2206 switch (image->colorspace)
2208 case CMYKColorspace:
2210 jpeg_info.input_components=4;
2211 jpeg_info.in_color_space=JCS_CMYK;
2214 case YCbCrColorspace:
2215 case Rec601YCbCrColorspace:
2216 case Rec709YCbCrColorspace:
2218 jpeg_info.in_color_space=JCS_YCbCr;
2221 case GRAYColorspace:
2223 if (image_info->type == TrueColorType)
2225 jpeg_info.input_components=1;
2226 jpeg_info.in_color_space=JCS_GRAYSCALE;
2231 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2232 if (image_info->type == TrueColorType)
2234 if (SetImageGray(image,exception) != MagickFalse)
2236 jpeg_info.input_components=1;
2237 jpeg_info.in_color_space=JCS_GRAYSCALE;
2242 jpeg_set_defaults(&jpeg_info);
2243 if (jpeg_info.in_color_space == JCS_CMYK)
2244 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2245 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2246 jpeg_info.data_precision=8;
2248 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2249 jpeg_info.density_unit=1;
2250 if (image->debug != MagickFalse)
2251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2252 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2253 floor(image->resolution.y+0.5));
2254 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2257 Set image resolution.
2259 jpeg_info.write_JFIF_header=TRUE;
2260 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2261 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2263 Set image resolution units.
2265 jpeg_info.density_unit=(UINT8) 0;
2266 if (image->units == PixelsPerInchResolution)
2267 jpeg_info.density_unit=(UINT8) 1;
2268 if (image->units == PixelsPerCentimeterResolution)
2269 jpeg_info.density_unit=(UINT8) 2;
2271 jpeg_info.dct_method=JDCT_FLOAT;
2272 option=GetImageOption(image_info,"jpeg:dct-method");
2273 if (option != (const char *) NULL)
2279 if (LocaleCompare(option,"default") == 0)
2280 jpeg_info.dct_method=JDCT_DEFAULT;
2286 if (LocaleCompare(option,"fastest") == 0)
2287 jpeg_info.dct_method=JDCT_FASTEST;
2288 if (LocaleCompare(option,"float") == 0)
2289 jpeg_info.dct_method=JDCT_FLOAT;
2295 if (LocaleCompare(option,"ifast") == 0)
2296 jpeg_info.dct_method=JDCT_IFAST;
2297 if (LocaleCompare(option,"islow") == 0)
2298 jpeg_info.dct_method=JDCT_ISLOW;
2302 option=GetImageOption(image_info,"jpeg:optimize-coding");
2303 if (option != (const char *) NULL)
2304 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2311 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2312 image->rows*sizeof(JSAMPLE);
2313 if (length == (MagickSizeType) ((size_t) length))
2316 Perform optimization only if available memory resources permit it.
2318 status=AcquireMagickResource(MemoryResource,length);
2319 RelinquishMagickResource(MemoryResource,length);
2320 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2323 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2324 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2325 (image_info->interlace != NoInterlace))
2327 if (image->debug != MagickFalse)
2328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2329 "Interlace: progressive");
2330 jpeg_simple_progression(&jpeg_info);
2333 if (image->debug != MagickFalse)
2334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2335 "Interlace: non-progressive");
2337 if (image->debug != MagickFalse)
2338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2339 "Interlace: nonprogressive");
2342 if ((image_info->compression != LosslessJPEGCompression) &&
2343 (image->quality <= 100))
2345 if (image->quality != UndefinedCompressionQuality)
2346 quality=(int) image->quality;
2347 if (image->debug != MagickFalse)
2348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2349 (double) image->quality);
2353 #if !defined(C_LOSSLESS_SUPPORTED)
2355 if (image->debug != MagickFalse)
2356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2358 if (image->quality < 100)
2359 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2360 "LosslessToLossyJPEGConversion",image->filename);
2367 predictor=image->quality/100; /* range 1-7 */
2368 point_transform=image->quality % 20; /* range 0-15 */
2369 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2370 if (image->debug != MagickFalse)
2372 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2373 "Compression: lossless");
2374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2375 "Predictor: %d",predictor);
2376 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2377 "Point Transform: %d",point_transform);
2382 option=GetImageOption(image_info,"jpeg:extent");
2383 if (option != (const char *) NULL)
2391 jpeg_info=CloneImageInfo(image_info);
2392 jpeg_info->blob=NULL;
2393 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2394 if (jpeg_image != (Image *) NULL)
2404 Search for compression quality that does not exceed image extent.
2406 jpeg_info->quality=0;
2407 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2408 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2409 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2410 maximum=image->quality;
2413 for (minimum=2; minimum < maximum; )
2415 (void) AcquireUniqueFilename(jpeg_image->filename);
2416 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2417 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2418 if (GetBlobSize(jpeg_image) <= extent)
2419 minimum=jpeg_image->quality+1;
2421 maximum=jpeg_image->quality-1;
2422 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2424 quality=(int) minimum-1;
2425 jpeg_image=DestroyImage(jpeg_image);
2427 jpeg_info=DestroyImageInfo(jpeg_info);
2429 jpeg_set_quality(&jpeg_info,quality,TRUE);
2430 #if (JPEG_LIB_VERSION >= 70)
2431 option=GetImageOption(image_info,"quality");
2432 if (option != (const char *) NULL)
2441 Set quality scaling for luminance and chrominance separately.
2443 flags=ParseGeometry(option,&geometry_info);
2444 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2446 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2447 (geometry_info.rho+0.5));
2448 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2449 (geometry_info.sigma+0.5));
2450 jpeg_default_qtables(&jpeg_info,TRUE);
2454 colorspace=jpeg_info.in_color_space;
2455 value=GetImageOption(image_info,"jpeg:colorspace");
2456 if (value == (char *) NULL)
2457 value=GetImageProperty(image,"jpeg:colorspace",exception);
2458 if (value != (char *) NULL)
2459 colorspace=StringToInteger(value);
2460 sampling_factor=(const char *) NULL;
2461 if (colorspace == jpeg_info.in_color_space)
2463 value=GetImageOption(image_info,"jpeg:sampling-factor");
2464 if (value == (char *) NULL)
2465 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2466 if (value != (char *) NULL)
2468 sampling_factor=value;
2469 if (image->debug != MagickFalse)
2470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2471 " Input sampling-factors=%s",sampling_factor);
2474 value=GetImageOption(image_info,"jpeg:sampling-factor");
2475 if (image_info->sampling_factor != (char *) NULL)
2476 sampling_factor=image_info->sampling_factor;
2477 if (sampling_factor == (const char *) NULL)
2480 for (i=0; i < MAX_COMPONENTS; i++)
2482 jpeg_info.comp_info[i].h_samp_factor=1;
2483 jpeg_info.comp_info[i].v_samp_factor=1;
2498 Set sampling factor.
2501 factors=SamplingFactorToList(sampling_factor);
2502 if (factors != (char **) NULL)
2504 for (i=0; i < MAX_COMPONENTS; i++)
2506 if (factors[i] == (char *) NULL)
2508 flags=ParseGeometry(factors[i],&geometry_info);
2509 if ((flags & SigmaValue) == 0)
2510 geometry_info.sigma=geometry_info.rho;
2511 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2512 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2513 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2515 factors=(char **) RelinquishMagickMemory(factors);
2517 for ( ; i < MAX_COMPONENTS; i++)
2519 jpeg_info.comp_info[i].h_samp_factor=1;
2520 jpeg_info.comp_info[i].v_samp_factor=1;
2523 option=GetImageOption(image_info,"jpeg:q-table");
2524 if (option != (const char *) NULL)
2530 Custom quantization tables.
2532 table=GetQuantizationTable(option,"0",exception);
2533 if (table != (QuantizationTable *) NULL)
2535 for (i=0; i < MAX_COMPONENTS; i++)
2536 jpeg_info.comp_info[i].quant_tbl_no=0;
2537 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2538 jpeg_quality_scaling(quality),0);
2539 table=DestroyQuantizationTable(table);
2541 table=GetQuantizationTable(option,"1",exception);
2542 if (table != (QuantizationTable *) NULL)
2544 for (i=1; i < MAX_COMPONENTS; i++)
2545 jpeg_info.comp_info[i].quant_tbl_no=1;
2546 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2547 jpeg_quality_scaling(quality),0);
2548 table=DestroyQuantizationTable(table);
2550 table=GetQuantizationTable(option,"2",exception);
2551 if (table != (QuantizationTable *) NULL)
2553 for (i=2; i < MAX_COMPONENTS; i++)
2554 jpeg_info.comp_info[i].quant_tbl_no=2;
2555 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2556 jpeg_quality_scaling(quality),0);
2557 table=DestroyQuantizationTable(table);
2559 table=GetQuantizationTable(option,"3",exception);
2560 if (table != (QuantizationTable *) NULL)
2562 for (i=3; i < MAX_COMPONENTS; i++)
2563 jpeg_info.comp_info[i].quant_tbl_no=3;
2564 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2565 jpeg_quality_scaling(quality),0);
2566 table=DestroyQuantizationTable(table);
2569 jpeg_start_compress(&jpeg_info,TRUE);
2570 if (image->debug != MagickFalse)
2572 if (image->storage_class == PseudoClass)
2573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2574 "Storage class: PseudoClass");
2576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2577 "Storage class: DirectClass");
2578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2579 (double) image->depth);
2580 if (image->colors != 0)
2581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2582 "Number of colors: %.20g",(double) image->colors);
2584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2585 "Number of colors: unspecified");
2586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2587 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2588 switch (image->colorspace)
2590 case CMYKColorspace:
2592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2593 "Storage class: DirectClass");
2594 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2595 "Colorspace: CMYK");
2598 case YCbCrColorspace:
2599 case Rec601YCbCrColorspace:
2600 case Rec709YCbCrColorspace:
2602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2603 "Colorspace: YCbCr");
2609 switch (image->colorspace)
2611 case CMYKColorspace:
2613 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2614 "Colorspace: CMYK");
2615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2616 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2617 jpeg_info.comp_info[0].h_samp_factor,
2618 jpeg_info.comp_info[0].v_samp_factor,
2619 jpeg_info.comp_info[1].h_samp_factor,
2620 jpeg_info.comp_info[1].v_samp_factor,
2621 jpeg_info.comp_info[2].h_samp_factor,
2622 jpeg_info.comp_info[2].v_samp_factor,
2623 jpeg_info.comp_info[3].h_samp_factor,
2624 jpeg_info.comp_info[3].v_samp_factor);
2627 case GRAYColorspace:
2629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2630 "Colorspace: GRAY");
2631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2632 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2633 jpeg_info.comp_info[0].v_samp_factor);
2636 case sRGBColorspace:
2639 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2640 "Image colorspace is RGB");
2641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2642 "Sampling factors: %dx%d,%dx%d,%dx%d",
2643 jpeg_info.comp_info[0].h_samp_factor,
2644 jpeg_info.comp_info[0].v_samp_factor,
2645 jpeg_info.comp_info[1].h_samp_factor,
2646 jpeg_info.comp_info[1].v_samp_factor,
2647 jpeg_info.comp_info[2].h_samp_factor,
2648 jpeg_info.comp_info[2].v_samp_factor);
2651 case YCbCrColorspace:
2652 case Rec601YCbCrColorspace:
2653 case Rec709YCbCrColorspace:
2655 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2656 "Colorspace: YCbCr");
2657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2658 "Sampling factors: %dx%d,%dx%d,%dx%d",
2659 jpeg_info.comp_info[0].h_samp_factor,
2660 jpeg_info.comp_info[0].v_samp_factor,
2661 jpeg_info.comp_info[1].h_samp_factor,
2662 jpeg_info.comp_info[1].v_samp_factor,
2663 jpeg_info.comp_info[2].h_samp_factor,
2664 jpeg_info.comp_info[2].v_samp_factor);
2669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2672 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2673 jpeg_info.comp_info[0].h_samp_factor,
2674 jpeg_info.comp_info[0].v_samp_factor,
2675 jpeg_info.comp_info[1].h_samp_factor,
2676 jpeg_info.comp_info[1].v_samp_factor,
2677 jpeg_info.comp_info[2].h_samp_factor,
2678 jpeg_info.comp_info[2].v_samp_factor,
2679 jpeg_info.comp_info[3].h_samp_factor,
2680 jpeg_info.comp_info[3].v_samp_factor);
2686 Write JPEG profiles.
2688 value=GetImageProperty(image,"comment",exception);
2689 if (value != (char *) NULL)
2690 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2691 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2692 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2693 if (image->profiles != (void *) NULL)
2694 WriteProfile(&jpeg_info,image);
2696 Convert MIFF to JPEG raster pixels.
2698 memory_info=AcquireVirtualMemory((size_t) image->columns,
2699 jpeg_info.input_components*sizeof(*jpeg_pixels));
2700 if (memory_info == (MemoryInfo *) NULL)
2701 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2702 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2703 if (setjmp(error_manager.error_recovery) != 0)
2705 jpeg_destroy_compress(&jpeg_info);
2706 if (memory_info != (MemoryInfo *) NULL)
2707 memory_info=RelinquishVirtualMemory(memory_info);
2708 (void) CloseBlob(image);
2709 return(MagickFalse);
2711 scanline[0]=(JSAMPROW) jpeg_pixels;
2712 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2715 if (jpeg_info.data_precision <= 8)
2717 if ((jpeg_info.in_color_space == JCS_RGB) ||
2718 (jpeg_info.in_color_space == JCS_YCbCr))
2719 for (y=0; y < (ssize_t) image->rows; y++)
2721 register const Quantum
2727 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2728 if (p == (const Quantum *) NULL)
2731 for (x=0; x < (ssize_t) image->columns; x++)
2733 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2734 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2735 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2736 p+=GetPixelChannels(image);
2738 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2739 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2741 if (status == MagickFalse)
2745 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2746 for (y=0; y < (ssize_t) image->rows; y++)
2748 register const Quantum
2754 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2755 if (p == (const Quantum *) NULL)
2758 for (x=0; x < (ssize_t) image->columns; x++)
2760 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2762 p+=GetPixelChannels(image);
2764 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2765 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2767 if (status == MagickFalse)
2771 for (y=0; y < (ssize_t) image->rows; y++)
2773 register const Quantum
2779 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2780 if (p == (const Quantum *) NULL)
2783 for (x=0; x < (ssize_t) image->columns; x++)
2786 Convert DirectClass packets to contiguous CMYK scanlines.
2788 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2789 GetPixelCyan(image,p))));
2790 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2791 GetPixelMagenta(image,p))));
2792 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2793 GetPixelYellow(image,p))));
2794 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2795 GetPixelBlack(image,p))));
2796 p+=GetPixelChannels(image);
2798 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2799 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2801 if (status == MagickFalse)
2806 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2807 for (y=0; y < (ssize_t) image->rows; y++)
2809 register const Quantum
2815 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2816 if (p == (const Quantum *) NULL)
2819 for (x=0; x < (ssize_t) image->columns; x++)
2821 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2823 p+=GetPixelChannels(image);
2825 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2826 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2828 if (status == MagickFalse)
2832 if ((jpeg_info.in_color_space == JCS_RGB) ||
2833 (jpeg_info.in_color_space == JCS_YCbCr))
2834 for (y=0; y < (ssize_t) image->rows; y++)
2836 register const Quantum
2842 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2843 if (p == (const Quantum *) NULL)
2846 for (x=0; x < (ssize_t) image->columns; x++)
2848 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2849 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2850 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2851 p+=GetPixelChannels(image);
2853 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2854 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2856 if (status == MagickFalse)
2860 for (y=0; y < (ssize_t) image->rows; y++)
2862 register const Quantum
2868 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2869 if (p == (const Quantum *) NULL)
2872 for (x=0; x < (ssize_t) image->columns; x++)
2875 Convert DirectClass packets to contiguous CMYK scanlines.
2877 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2879 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2881 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2883 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2885 p+=GetPixelChannels(image);
2887 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2888 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2890 if (status == MagickFalse)
2893 if (y == (ssize_t) image->rows)
2894 jpeg_finish_compress(&jpeg_info);
2896 Relinquish resources.
2898 jpeg_destroy_compress(&jpeg_info);
2899 memory_info=RelinquishVirtualMemory(memory_info);
2900 (void) CloseBlob(image);