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/pixel-accessor.h"
74 #include "MagickCore/profile.h"
75 #include "MagickCore/property.h"
76 #include "MagickCore/quantum-private.h"
77 #include "MagickCore/resource_.h"
78 #include "MagickCore/splay-tree.h"
79 #include "MagickCore/static.h"
80 #include "MagickCore/string_.h"
81 #include "MagickCore/string-private.h"
82 #include "MagickCore/token.h"
83 #include "MagickCore/utility.h"
84 #include "MagickCore/xml-tree.h"
85 #include "MagickCore/xml-tree-private.h"
87 #if defined(MAGICKCORE_JPEG_DELEGATE)
88 #define JPEG_INTERNAL_OPTIONS
89 #if defined(__MINGW32__) || defined(__MINGW64__)
90 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
101 #define ICC_MARKER (JPEG_APP0+2)
102 #define ICC_PROFILE "ICC_PROFILE"
103 #define IPTC_MARKER (JPEG_APP0+13)
104 #define XML_MARKER (JPEG_APP0+1)
105 #define MaxBufferExtent 16384
109 Typedef declarations.
111 #if defined(MAGICKCORE_JPEG_DELEGATE)
112 typedef struct _DestinationManager
114 struct jpeg_destination_mgr
122 } DestinationManager;
124 typedef struct _ErrorManager
142 typedef struct _SourceManager
144 struct jpeg_source_mgr
158 typedef struct _QuantizationTable
177 Forward declarations.
179 #if defined(MAGICKCORE_JPEG_DELEGATE)
180 static MagickBooleanType
181 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 % IsJPEG() returns MagickTrue if the image format type, identified by the
197 % magick string, is JPEG.
199 % The format of the IsJPEG method is:
201 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
203 % A description of each parameter follows:
205 % o magick: compare image format pattern against these bytes.
207 % o length: Specifies the length of the magick string.
210 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
214 if (memcmp(magick,"\377\330\377",3) == 0)
220 #if defined(MAGICKCORE_JPEG_DELEGATE)
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226 % R e a d J P E G I m a g e %
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
233 % the memory necessary for the new Image structure and returns a pointer to
236 % The format of the ReadJPEGImage method is:
238 % Image *ReadJPEGImage(const ImageInfo *image_info,
239 % ExceptionInfo *exception)
241 % A description of each parameter follows:
243 % o image_info: the image info.
245 % o exception: return any errors or warnings in this structure.
249 static boolean FillInputBuffer(j_decompress_ptr cinfo)
254 source=(SourceManager *) cinfo->src;
255 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
256 MaxBufferExtent,source->buffer);
257 if (source->manager.bytes_in_buffer == 0)
259 if (source->start_of_blob != FALSE)
260 ERREXIT(cinfo,JERR_INPUT_EMPTY);
261 WARNMS(cinfo,JWRN_JPEG_EOF);
262 source->buffer[0]=(JOCTET) 0xff;
263 source->buffer[1]=(JOCTET) JPEG_EOI;
264 source->manager.bytes_in_buffer=2;
266 source->manager.next_input_byte=source->buffer;
267 source->start_of_blob=FALSE;
271 static int GetCharacter(j_decompress_ptr jpeg_info)
273 if (jpeg_info->src->bytes_in_buffer == 0)
274 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
275 jpeg_info->src->bytes_in_buffer--;
276 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
279 static void InitializeSource(j_decompress_ptr cinfo)
284 source=(SourceManager *) cinfo->src;
285 source->start_of_blob=TRUE;
288 static MagickBooleanType IsITUFaxImage(const Image *image)
296 profile=GetImageProfile(image,"8bim");
297 if (profile == (const StringInfo *) NULL)
299 if (GetStringInfoLength(profile) < 5)
301 datum=GetStringInfoDatum(profile);
302 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
303 (datum[3] == 0x41) && (datum[4] == 0x58))
308 static void JPEGErrorHandler(j_common_ptr jpeg_info)
311 message[JMSG_LENGTH_MAX];
323 error_manager=(ErrorManager *) jpeg_info->client_data;
324 image=error_manager->image;
325 exception=error_manager->exception;
326 (jpeg_info->err->format_message)(jpeg_info,message);
327 if (image->debug != MagickFalse)
328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
329 "[%s] JPEG Trace: \"%s\"",image->filename,message);
330 if (error_manager->finished != MagickFalse)
331 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
332 (char *) message,"`%s'",image->filename);
334 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
335 (char *) message,"`%s'",image->filename);
336 longjmp(error_manager->error_recovery,1);
339 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
341 #define JPEGExcessiveWarnings 1000
344 message[JMSG_LENGTH_MAX];
356 error_manager=(ErrorManager *) jpeg_info->client_data;
357 exception=error_manager->exception;
358 image=error_manager->image;
362 Process warning message.
364 (jpeg_info->err->format_message)(jpeg_info,message);
365 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
366 JPEGErrorHandler(jpeg_info);
367 ThrowBinaryException(CorruptImageWarning,(char *) message,
371 if ((image->debug != MagickFalse) &&
372 (level >= jpeg_info->err->trace_level))
375 Process trace message.
377 (jpeg_info->err->format_message)(jpeg_info,message);
378 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
379 "[%s] JPEG Trace: \"%s\"",image->filename,message);
384 static boolean ReadComment(j_decompress_ptr jpeg_info)
395 register unsigned char
408 Determine length of comment.
410 error_manager=(ErrorManager *) jpeg_info->client_data;
411 exception=error_manager->exception;
412 image=error_manager->image;
413 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
414 length+=GetCharacter(jpeg_info);
418 comment=BlobToStringInfo((const void *) NULL,length);
419 if (comment == (StringInfo *) NULL)
420 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
425 error_manager->profile=comment;
426 p=GetStringInfoDatum(comment);
427 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
428 *p++=(unsigned char) GetCharacter(jpeg_info);
430 error_manager->profile=NULL;
431 p=GetStringInfoDatum(comment);
432 (void) SetImageProperty(image,"comment",(const char *) p,exception);
433 comment=DestroyStringInfo(comment);
437 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
457 register unsigned char
470 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
471 length+=(size_t) GetCharacter(jpeg_info);
476 (void) GetCharacter(jpeg_info);
479 for (i=0; i < 12; i++)
480 magick[i]=(char) GetCharacter(jpeg_info);
481 if (LocaleCompare(magick,ICC_PROFILE) != 0)
484 Not a ICC profile, return.
486 for (i=0; i < (ssize_t) (length-12); i++)
487 (void) GetCharacter(jpeg_info);
490 (void) GetCharacter(jpeg_info); /* id */
491 (void) GetCharacter(jpeg_info); /* markers */
493 error_manager=(ErrorManager *) jpeg_info->client_data;
494 exception=error_manager->exception;
495 image=error_manager->image;
496 profile=BlobToStringInfo((const void *) NULL,length);
497 if (profile == (StringInfo *) NULL)
498 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
500 error_manager->profile=profile;
501 p=GetStringInfoDatum(profile);
502 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
503 *p++=(unsigned char) GetCharacter(jpeg_info);
504 error_manager->profile=NULL;
505 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
506 if (icc_profile != (StringInfo *) NULL)
508 ConcatenateStringInfo(icc_profile,profile);
509 profile=DestroyStringInfo(profile);
513 status=SetImageProfile(image,"icc",profile,exception);
514 profile=DestroyStringInfo(profile);
515 if (status == MagickFalse)
516 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
519 if (image->debug != MagickFalse)
520 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
521 "Profile: ICC, %.20g bytes",(double) length);
525 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
528 magick[MaxTextExtent];
545 register unsigned char
556 Determine length of binary data stored here.
558 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
559 length+=(size_t) GetCharacter(jpeg_info);
564 (void) GetCharacter(jpeg_info);
568 Validate that this was written as a Photoshop resource format slug.
570 for (i=0; i < 10; i++)
571 magick[i]=(char) GetCharacter(jpeg_info);
576 if (LocaleCompare(magick,"Photoshop ") != 0)
579 Not a IPTC profile, return.
581 for (i=0; i < (ssize_t) length; i++)
582 (void) GetCharacter(jpeg_info);
586 Remove the version number.
588 for (i=0; i < 4; i++)
589 (void) GetCharacter(jpeg_info);
595 error_manager=(ErrorManager *) jpeg_info->client_data;
596 exception=error_manager->exception;
597 image=error_manager->image;
598 profile=BlobToStringInfo((const void *) NULL,length);
599 if (profile == (StringInfo *) NULL)
600 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
602 error_manager->profile=profile;
603 p=GetStringInfoDatum(profile);
604 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
605 *p++=(unsigned char) GetCharacter(jpeg_info);
606 error_manager->profile=NULL;
607 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
608 if (iptc_profile != (StringInfo *) NULL)
610 ConcatenateStringInfo(iptc_profile,profile);
611 profile=DestroyStringInfo(profile);
615 status=SetImageProfile(image,"8bim",profile,exception);
616 profile=DestroyStringInfo(profile);
617 if (status == MagickFalse)
618 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
621 if (image->debug != MagickFalse)
622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
623 "Profile: iptc, %.20g bytes",(double) length);
627 static boolean ReadProfile(j_decompress_ptr jpeg_info)
653 register unsigned char
663 Read generic profile.
665 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
666 length+=(size_t) GetCharacter(jpeg_info);
670 marker=jpeg_info->unread_marker-JPEG_APP0;
671 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
672 error_manager=(ErrorManager *) jpeg_info->client_data;
673 exception=error_manager->exception;
674 image=error_manager->image;
675 profile=BlobToStringInfo((const void *) NULL,length);
676 if (profile == (StringInfo *) NULL)
677 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
679 error_manager->profile=profile;
680 p=GetStringInfoDatum(profile);
681 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
682 *p++=(unsigned char) GetCharacter(jpeg_info);
683 error_manager->profile=NULL;
686 p=GetStringInfoDatum(profile);
687 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
688 (void) CopyMagickString(name,"exif",MaxTextExtent);
689 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
695 Extract namespace from XMP profile.
697 p=GetStringInfoDatum(profile);
698 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
704 if (j < (ssize_t) GetStringInfoLength(profile))
705 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
706 (void) CopyMagickString(name,"xmp",MaxTextExtent);
709 previous_profile=GetImageProfile(image,name);
710 if (previous_profile != (const StringInfo *) NULL)
715 length=GetStringInfoLength(profile);
716 SetStringInfoLength(profile,GetStringInfoLength(profile)+
717 GetStringInfoLength(previous_profile));
718 (void) memmove(GetStringInfoDatum(profile)+
719 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
721 (void) memcpy(GetStringInfoDatum(profile),
722 GetStringInfoDatum(previous_profile),
723 GetStringInfoLength(previous_profile));
725 status=SetImageProfile(image,name,profile,exception);
726 profile=DestroyStringInfo(profile);
727 if (status == MagickFalse)
728 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
730 if (image->debug != MagickFalse)
731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
732 "Profile: %s, %.20g bytes",name,(double) length);
736 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
741 if (number_bytes <= 0)
743 source=(SourceManager *) cinfo->src;
744 while (number_bytes > (long) source->manager.bytes_in_buffer)
746 number_bytes-=(long) source->manager.bytes_in_buffer;
747 (void) FillInputBuffer(cinfo);
749 source->manager.next_input_byte+=number_bytes;
750 source->manager.bytes_in_buffer-=number_bytes;
753 static void TerminateSource(j_decompress_ptr cinfo)
758 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
763 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
764 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
765 source=(SourceManager *) cinfo->src;
766 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
767 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
768 source=(SourceManager *) cinfo->src;
769 source->manager.init_source=InitializeSource;
770 source->manager.fill_input_buffer=FillInputBuffer;
771 source->manager.skip_input_data=SkipInputData;
772 source->manager.resync_to_restart=jpeg_resync_to_restart;
773 source->manager.term_source=TerminateSource;
774 source->manager.bytes_in_buffer=0;
775 source->manager.next_input_byte=NULL;
779 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
780 Image *image, ExceptionInfo *exception)
782 image->quality=UndefinedCompressionQuality;
783 #if defined(D_PROGRESSIVE_SUPPORTED)
784 if (image->compression == LosslessJPEGCompression)
787 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
788 "Quality: 100 (lossless)");
802 Determine the JPEG compression quality from the quantization tables.
805 for (i=0; i < NUM_QUANT_TBLS; i++)
807 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
808 for (j=0; j < DCTSIZE2; j++)
809 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
811 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
812 (jpeg_info->quant_tbl_ptrs[1] != NULL))
817 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
818 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
819 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
820 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
821 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
822 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
823 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
824 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
825 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
826 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
831 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
832 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
833 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
834 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
835 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
836 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
837 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
838 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
839 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
840 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
841 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
845 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
846 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
847 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
848 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
849 for (i=0; i < 100; i++)
851 if ((qvalue < hash[i]) && (sum < sums[i]))
853 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
854 image->quality=(size_t) i+1;
855 if (image->debug != MagickFalse)
856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
857 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
858 (sum <= sums[i]) ? "exact" : "approximate");
863 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
868 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
869 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
870 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
871 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
872 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
873 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
874 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
875 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
876 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
877 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
882 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
883 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
884 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
885 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
886 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
887 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
888 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
889 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
890 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
891 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
892 667, 592, 518, 441, 369, 292, 221, 151, 86,
896 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
897 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
898 for (i=0; i < 100; i++)
900 if ((qvalue < hash[i]) && (sum < sums[i]))
902 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
903 image->quality=(size_t)i+1;
904 if (image->debug != MagickFalse)
905 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
906 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
907 (sum <= sums[i]) ? "exact" : "approximate");
914 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
917 sampling_factor[MaxTextExtent];
919 switch (jpeg_info->out_color_space)
923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
924 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
925 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
926 jpeg_info->comp_info[0].v_samp_factor,
927 jpeg_info->comp_info[1].h_samp_factor,
928 jpeg_info->comp_info[1].v_samp_factor,
929 jpeg_info->comp_info[2].h_samp_factor,
930 jpeg_info->comp_info[2].v_samp_factor,
931 jpeg_info->comp_info[3].h_samp_factor,
932 jpeg_info->comp_info[3].v_samp_factor);
937 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
938 "Colorspace: GRAYSCALE");
939 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
940 jpeg_info->comp_info[0].h_samp_factor,
941 jpeg_info->comp_info[0].v_samp_factor);
946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
947 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
948 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
949 jpeg_info->comp_info[0].v_samp_factor,
950 jpeg_info->comp_info[1].h_samp_factor,
951 jpeg_info->comp_info[1].v_samp_factor,
952 jpeg_info->comp_info[2].h_samp_factor,
953 jpeg_info->comp_info[2].v_samp_factor);
958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
959 jpeg_info->out_color_space);
960 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
961 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
962 jpeg_info->comp_info[0].v_samp_factor,
963 jpeg_info->comp_info[1].h_samp_factor,
964 jpeg_info->comp_info[1].v_samp_factor,
965 jpeg_info->comp_info[2].h_samp_factor,
966 jpeg_info->comp_info[2].v_samp_factor,
967 jpeg_info->comp_info[3].h_samp_factor,
968 jpeg_info->comp_info[3].v_samp_factor);
972 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
978 static Image *ReadJPEGImage(const ImageInfo *image_info,
979 ExceptionInfo *exception)
982 value[MaxTextExtent];
994 *volatile jpeg_pixels;
1015 struct jpeg_decompress_struct
1018 struct jpeg_error_mgr
1034 assert(image_info != (const ImageInfo *) NULL);
1035 assert(image_info->signature == MagickSignature);
1036 if (image_info->debug != MagickFalse)
1037 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1038 image_info->filename);
1039 assert(exception != (ExceptionInfo *) NULL);
1040 assert(exception->signature == MagickSignature);
1041 debug=IsEventLogging();
1043 image=AcquireImage(image_info,exception);
1044 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1045 if (status == MagickFalse)
1047 image=DestroyImageList(image);
1048 return((Image *) NULL);
1051 Initialize JPEG parameters.
1053 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1054 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1055 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1056 jpeg_info.err=jpeg_std_error(&jpeg_error);
1057 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1058 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1059 memory_info=(MemoryInfo *) NULL;
1060 error_manager.exception=exception;
1061 error_manager.image=image;
1062 if (setjmp(error_manager.error_recovery) != 0)
1064 jpeg_destroy_decompress(&jpeg_info);
1065 if (error_manager.profile != (StringInfo *) NULL)
1066 error_manager.profile=DestroyStringInfo(error_manager.profile);
1067 (void) CloseBlob(image);
1068 number_pixels=(MagickSizeType) image->columns*image->rows;
1069 if (number_pixels != 0)
1070 return(GetFirstImageInList(image));
1071 return(DestroyImage(image));
1073 jpeg_info.client_data=(void *) &error_manager;
1074 jpeg_create_decompress(&jpeg_info);
1075 JPEGSourceManager(&jpeg_info,image);
1076 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1077 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1078 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1079 for (i=1; i < 16; i++)
1080 if ((i != 2) && (i != 13) && (i != 14))
1081 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1082 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1083 if ((image_info->colorspace == YCbCrColorspace) ||
1084 (image_info->colorspace == Rec601YCbCrColorspace) ||
1085 (image_info->colorspace == Rec709YCbCrColorspace))
1086 jpeg_info.out_color_space=JCS_YCbCr;
1088 Set image resolution.
1091 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1092 (jpeg_info.Y_density != 1))
1094 image->resolution.x=(double) jpeg_info.X_density;
1095 image->resolution.y=(double) jpeg_info.Y_density;
1096 units=(size_t) jpeg_info.density_unit;
1099 image->units=PixelsPerInchResolution;
1101 image->units=PixelsPerCentimeterResolution;
1102 number_pixels=(MagickSizeType) image->columns*image->rows;
1103 option=GetImageOption(image_info,"jpeg:size");
1104 if (option != (const char *) NULL)
1118 flags=ParseGeometry(option,&geometry_info);
1119 if ((flags & SigmaValue) == 0)
1120 geometry_info.sigma=geometry_info.rho;
1121 jpeg_calc_output_dimensions(&jpeg_info);
1122 image->magick_columns=jpeg_info.output_width;
1123 image->magick_rows=jpeg_info.output_height;
1125 if (geometry_info.rho != 0.0)
1126 scale_factor=jpeg_info.output_width/geometry_info.rho;
1127 if ((geometry_info.sigma != 0.0) &&
1128 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1129 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1130 jpeg_info.scale_num=1U;
1131 jpeg_info.scale_denom=(unsigned int) scale_factor;
1132 jpeg_calc_output_dimensions(&jpeg_info);
1133 if (image->debug != MagickFalse)
1134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1135 "Scale factor: %.20g",(double) scale_factor);
1137 precision=(size_t) jpeg_info.data_precision;
1138 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1139 #if defined(D_LOSSLESS_SUPPORTED)
1140 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1141 JPEGInterlace : NoInterlace;
1142 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1143 LosslessJPEGCompression : JPEGCompression;
1144 if (jpeg_info.data_precision > 8)
1145 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1146 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1148 if (jpeg_info.data_precision == 16)
1149 jpeg_info.data_precision=12;
1151 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1153 image->compression=JPEGCompression;
1156 image->compression=JPEGCompression;
1157 image->interlace=JPEGInterlace;
1159 option=GetImageOption(image_info,"jpeg:colors");
1160 if (option != (const char *) NULL)
1163 Let the JPEG library quantize the image.
1165 jpeg_info.quantize_colors=MagickTrue;
1166 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1168 option=GetImageOption(image_info,"jpeg:block-smoothing");
1169 if (option != (const char *) NULL)
1170 jpeg_info.do_block_smoothing=IsStringTrue(option);
1171 jpeg_info.dct_method=JDCT_FLOAT;
1172 option=GetImageOption(image_info,"jpeg:dct-method");
1173 if (option != (const char *) NULL)
1179 if (LocaleCompare(option,"default") == 0)
1180 jpeg_info.dct_method=JDCT_DEFAULT;
1186 if (LocaleCompare(option,"fastest") == 0)
1187 jpeg_info.dct_method=JDCT_FASTEST;
1188 if (LocaleCompare(option,"float") == 0)
1189 jpeg_info.dct_method=JDCT_FLOAT;
1195 if (LocaleCompare(option,"ifast") == 0)
1196 jpeg_info.dct_method=JDCT_IFAST;
1197 if (LocaleCompare(option,"islow") == 0)
1198 jpeg_info.dct_method=JDCT_ISLOW;
1202 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1203 if (option != (const char *) NULL)
1204 jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1205 (void) jpeg_start_decompress(&jpeg_info);
1206 image->columns=jpeg_info.output_width;
1207 image->rows=jpeg_info.output_height;
1208 image->depth=(size_t) jpeg_info.data_precision;
1209 switch (jpeg_info.out_color_space)
1214 (void) SetImageColorspace(image,sRGBColorspace,exception);
1219 (void) SetImageColorspace(image,GRAYColorspace,exception);
1224 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1229 (void) SetImageColorspace(image,CMYKColorspace,exception);
1233 if (IsITUFaxImage(image) != MagickFalse)
1235 (void) SetImageColorspace(image,LabColorspace,exception);
1236 jpeg_info.out_color_space=JCS_YCbCr;
1238 option=GetImageOption(image_info,"jpeg:colors");
1239 if (option != (const char *) NULL)
1240 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1242 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1243 if ((jpeg_info.output_components == 1) &&
1244 (jpeg_info.quantize_colors == MagickFalse))
1249 colors=(size_t) GetQuantumRange(image->depth)+1;
1250 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1251 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1253 if (image->debug != MagickFalse)
1255 if (image->interlace != NoInterlace)
1256 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1257 "Interlace: progressive");
1259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1260 "Interlace: nonprogressive");
1261 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1262 (int) jpeg_info.data_precision);
1263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1264 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1266 JPEGSetImageQuality(&jpeg_info,image,exception);
1267 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1268 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1269 jpeg_info.out_color_space);
1270 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1271 if (image_info->ping != MagickFalse)
1273 jpeg_destroy_decompress(&jpeg_info);
1274 (void) CloseBlob(image);
1275 return(GetFirstImageInList(image));
1277 memory_info=AcquireVirtualMemory((size_t) image->columns,
1278 jpeg_info.output_components*sizeof(*jpeg_pixels));
1279 if (memory_info == (MemoryInfo *) NULL)
1281 jpeg_destroy_decompress(&jpeg_info);
1282 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1284 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1286 Convert JPEG pixels to pixel packets.
1288 if (setjmp(error_manager.error_recovery) != 0)
1290 if (memory_info != (MemoryInfo *) NULL)
1291 memory_info=RelinquishVirtualMemory(memory_info);
1292 jpeg_destroy_decompress(&jpeg_info);
1293 (void) CloseBlob(image);
1294 number_pixels=(MagickSizeType) image->columns*image->rows;
1295 if (number_pixels != 0)
1296 return(GetFirstImageInList(image));
1297 return(DestroyImage(image));
1299 if (jpeg_info.quantize_colors != MagickFalse)
1301 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1302 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1303 for (i=0; i < (ssize_t) image->colors; i++)
1305 image->colormap[i].red=(double) ScaleCharToQuantum(
1306 jpeg_info.colormap[0][i]);
1307 image->colormap[i].green=image->colormap[i].red;
1308 image->colormap[i].blue=image->colormap[i].red;
1309 image->colormap[i].alpha=OpaqueAlpha;
1312 for (i=0; i < (ssize_t) image->colors; i++)
1314 image->colormap[i].red=(double) ScaleCharToQuantum(
1315 jpeg_info.colormap[0][i]);
1316 image->colormap[i].green=(double) ScaleCharToQuantum(
1317 jpeg_info.colormap[1][i]);
1318 image->colormap[i].blue=(double) ScaleCharToQuantum(
1319 jpeg_info.colormap[2][i]);
1320 image->colormap[i].alpha=OpaqueAlpha;
1323 scanline[0]=(JSAMPROW) jpeg_pixels;
1324 for (y=0; y < (ssize_t) image->rows; y++)
1332 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1334 (void) ThrowMagickException(exception,GetMagickModule(),
1335 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1339 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1340 if (q == (Quantum *) NULL)
1342 if (jpeg_info.data_precision > 8)
1344 if (jpeg_info.output_components == 1)
1345 for (x=0; x < (ssize_t) image->columns; x++)
1350 if (precision != 16)
1351 pixel=(size_t) GETJSAMPLE(*p);
1353 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1354 index=ConstrainColormapIndex(image,pixel,exception);
1355 SetPixelIndex(image,index,q);
1356 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1358 q+=GetPixelChannels(image);
1361 if (image->colorspace != CMYKColorspace)
1362 for (x=0; x < (ssize_t) image->columns; x++)
1364 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1365 (GETJSAMPLE(*p++) << 4)),q);
1366 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1367 (GETJSAMPLE(*p++) << 4)),q);
1368 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1369 (GETJSAMPLE(*p++) << 4)),q);
1370 SetPixelAlpha(image,OpaqueAlpha,q);
1371 q+=GetPixelChannels(image);
1374 for (x=0; x < (ssize_t) image->columns; x++)
1376 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1377 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1378 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1379 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1380 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1381 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1382 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1383 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1384 SetPixelAlpha(image,OpaqueAlpha,q);
1385 q+=GetPixelChannels(image);
1389 if (jpeg_info.output_components == 1)
1390 for (x=0; x < (ssize_t) image->columns; x++)
1392 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1393 SetPixelIndex(image,index,q);
1394 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1396 q+=GetPixelChannels(image);
1399 if (image->colorspace != CMYKColorspace)
1400 for (x=0; x < (ssize_t) image->columns; x++)
1402 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1403 GETJSAMPLE(*p++)),q);
1404 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1405 GETJSAMPLE(*p++)),q);
1406 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1407 GETJSAMPLE(*p++)),q);
1408 SetPixelAlpha(image,OpaqueAlpha,q);
1409 q+=GetPixelChannels(image);
1412 for (x=0; x < (ssize_t) image->columns; x++)
1414 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1415 (unsigned char) GETJSAMPLE(*p++)),q);
1416 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1417 (unsigned char) GETJSAMPLE(*p++)),q);
1418 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1419 (unsigned char) GETJSAMPLE(*p++)),q);
1420 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1421 (unsigned char) GETJSAMPLE(*p++)),q);
1422 SetPixelAlpha(image,OpaqueAlpha,q);
1423 q+=GetPixelChannels(image);
1425 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1427 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1429 if (status == MagickFalse)
1431 jpeg_abort_decompress(&jpeg_info);
1435 if (status != MagickFalse)
1437 error_manager.finished=MagickTrue;
1438 if (setjmp(error_manager.error_recovery) == 0)
1439 (void) jpeg_finish_decompress(&jpeg_info);
1442 Free jpeg resources.
1444 jpeg_destroy_decompress(&jpeg_info);
1445 memory_info=RelinquishVirtualMemory(memory_info);
1446 (void) CloseBlob(image);
1447 return(GetFirstImageInList(image));
1453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 % R e g i s t e r J P E G I m a g e %
1461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463 % RegisterJPEGImage() adds properties for the JPEG image format to
1464 % the list of supported formats. The properties include the image format
1465 % tag, a method to read and/or write the format, whether the format
1466 % supports the saving of more than one frame to the same file or blob,
1467 % whether the format supports native in-memory I/O, and a brief
1468 % description of the format.
1470 % The format of the RegisterJPEGImage method is:
1472 % size_t RegisterJPEGImage(void)
1475 ModuleExport size_t RegisterJPEGImage(void)
1478 version[MaxTextExtent];
1484 description[] = "Joint Photographic Experts Group JFIF format";
1487 #if defined(JPEG_LIB_VERSION)
1488 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1490 entry=SetMagickInfo("JPEG");
1491 entry->thread_support=NoThreadSupport;
1492 #if defined(MAGICKCORE_JPEG_DELEGATE)
1493 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1494 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1496 entry->magick=(IsImageFormatHandler *) IsJPEG;
1497 entry->adjoin=MagickFalse;
1498 entry->description=ConstantString(description);
1499 if (*version != '\0')
1500 entry->version=ConstantString(version);
1501 entry->mime_type=ConstantString("image/jpeg");
1502 entry->module=ConstantString("JPEG");
1503 (void) RegisterMagickInfo(entry);
1504 entry=SetMagickInfo("JPG");
1505 entry->thread_support=NoThreadSupport;
1506 #if defined(MAGICKCORE_JPEG_DELEGATE)
1507 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1508 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1510 entry->adjoin=MagickFalse;
1511 entry->description=ConstantString(description);
1512 if (*version != '\0')
1513 entry->version=ConstantString(version);
1514 entry->mime_type=ConstantString("image/jpeg");
1515 entry->module=ConstantString("JPEG");
1516 (void) RegisterMagickInfo(entry);
1517 entry=SetMagickInfo("PJPEG");
1518 entry->thread_support=NoThreadSupport;
1519 #if defined(MAGICKCORE_JPEG_DELEGATE)
1520 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1521 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1523 entry->adjoin=MagickFalse;
1524 entry->description=ConstantString(description);
1525 if (*version != '\0')
1526 entry->version=ConstantString(version);
1527 entry->mime_type=ConstantString("image/jpeg");
1528 entry->module=ConstantString("JPEG");
1529 (void) RegisterMagickInfo(entry);
1530 return(MagickImageCoderSignature);
1535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1539 % U n r e g i s t e r J P E G I m a g e %
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545 % UnregisterJPEGImage() removes format registrations made by the
1546 % JPEG module from the list of supported formats.
1548 % The format of the UnregisterJPEGImage method is:
1550 % UnregisterJPEGImage(void)
1553 ModuleExport void UnregisterJPEGImage(void)
1555 (void) UnregisterMagickInfo("PJPG");
1556 (void) UnregisterMagickInfo("JPEG");
1557 (void) UnregisterMagickInfo("JPG");
1561 #if defined(MAGICKCORE_JPEG_DELEGATE)
1563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567 % W r i t e J P E G I m a g e %
1571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573 % WriteJPEGImage() writes a JPEG image file and returns it. It
1574 % allocates the memory necessary for the new Image structure and returns a
1575 % pointer to the new image.
1577 % The format of the WriteJPEGImage method is:
1579 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1580 % Image *image,ExceptionInfo *exception)
1582 % A description of each parameter follows:
1584 % o image_info: the image info.
1586 % o jpeg_image: The image.
1588 % o exception: return any errors or warnings in this structure.
1592 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1594 assert(table != (QuantizationTable *) NULL);
1595 if (table->slot != (char *) NULL)
1596 table->slot=DestroyString(table->slot);
1597 if (table->description != (char *) NULL)
1598 table->description=DestroyString(table->description);
1599 if (table->levels != (unsigned int *) NULL)
1600 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1601 table=(QuantizationTable *) RelinquishMagickMemory(table);
1605 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1610 destination=(DestinationManager *) cinfo->dest;
1611 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1612 MaxBufferExtent,destination->buffer);
1613 if (destination->manager.free_in_buffer != MaxBufferExtent)
1614 ERREXIT(cinfo,JERR_FILE_WRITE);
1615 destination->manager.next_output_byte=destination->buffer;
1619 static QuantizationTable *GetQuantizationTable(const char *filename,
1620 const char *slot,ExceptionInfo *exception)
1648 *quantization_tables,
1651 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1652 "Loading quantization tables \"%s\" ...",filename);
1653 table=(QuantizationTable *) NULL;
1654 xml=FileToString(filename,~0UL,exception);
1655 if (xml == (char *) NULL)
1657 quantization_tables=NewXMLTree(xml,exception);
1658 if (quantization_tables == (XMLTreeInfo *) NULL)
1660 xml=DestroyString(xml);
1663 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1664 table_iterator != (XMLTreeInfo *) NULL;
1665 table_iterator=GetNextXMLTreeTag(table_iterator))
1667 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1668 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1670 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1671 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1674 if (table_iterator == (XMLTreeInfo *) NULL)
1676 xml=DestroyString(xml);
1679 description=GetXMLTreeChild(table_iterator,"description");
1680 if (description == (XMLTreeInfo *) NULL)
1682 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1683 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1684 quantization_tables=DestroyXMLTree(quantization_tables);
1685 xml=DestroyString(xml);
1688 levels=GetXMLTreeChild(table_iterator,"levels");
1689 if (levels == (XMLTreeInfo *) NULL)
1691 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1692 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1693 quantization_tables=DestroyXMLTree(quantization_tables);
1694 xml=DestroyString(xml);
1697 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1698 if (table == (QuantizationTable *) NULL)
1699 ThrowFatalException(ResourceLimitFatalError,
1700 "UnableToAcquireQuantizationTable");
1701 table->slot=(char *) NULL;
1702 table->description=(char *) NULL;
1703 table->levels=(unsigned int *) NULL;
1704 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1705 if (attribute != (char *) NULL)
1706 table->slot=ConstantString(attribute);
1707 content=GetXMLTreeContent(description);
1708 if (content != (char *) NULL)
1709 table->description=ConstantString(content);
1710 attribute=GetXMLTreeAttribute(levels,"width");
1711 if (attribute == (char *) NULL)
1713 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1714 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1715 quantization_tables=DestroyXMLTree(quantization_tables);
1716 table=DestroyQuantizationTable(table);
1717 xml=DestroyString(xml);
1720 table->width=StringToUnsignedLong(attribute);
1721 if (table->width == 0)
1723 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1724 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1725 quantization_tables=DestroyXMLTree(quantization_tables);
1726 table=DestroyQuantizationTable(table);
1727 xml=DestroyString(xml);
1730 attribute=GetXMLTreeAttribute(levels,"height");
1731 if (attribute == (char *) NULL)
1733 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1734 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1735 quantization_tables=DestroyXMLTree(quantization_tables);
1736 table=DestroyQuantizationTable(table);
1737 xml=DestroyString(xml);
1740 table->height=StringToUnsignedLong(attribute);
1741 if (table->height == 0)
1743 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1744 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1745 quantization_tables=DestroyXMLTree(quantization_tables);
1746 table=DestroyQuantizationTable(table);
1747 xml=DestroyString(xml);
1750 attribute=GetXMLTreeAttribute(levels,"divisor");
1751 if (attribute == (char *) NULL)
1753 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1754 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1755 quantization_tables=DestroyXMLTree(quantization_tables);
1756 table=DestroyQuantizationTable(table);
1757 xml=DestroyString(xml);
1760 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1761 if (table->divisor == 0.0)
1763 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1764 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1765 quantization_tables=DestroyXMLTree(quantization_tables);
1766 table=DestroyQuantizationTable(table);
1767 xml=DestroyString(xml);
1770 content=GetXMLTreeContent(levels);
1771 if (content == (char *) NULL)
1773 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1774 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1775 quantization_tables=DestroyXMLTree(quantization_tables);
1776 table=DestroyQuantizationTable(table);
1777 xml=DestroyString(xml);
1780 length=(size_t) table->width*table->height;
1783 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1784 sizeof(*table->levels));
1785 if (table->levels == (unsigned int *) NULL)
1786 ThrowFatalException(ResourceLimitFatalError,
1787 "UnableToAcquireQuantizationTable");
1788 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1790 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1791 table->divisor+0.5);
1792 while (isspace((int) ((unsigned char) *p)) != 0)
1798 value=InterpretLocaleValue(content,&p);
1802 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1803 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1804 quantization_tables=DestroyXMLTree(quantization_tables);
1805 table=DestroyQuantizationTable(table);
1806 xml=DestroyString(xml);
1809 for (j=i; j < 64; j++)
1810 table->levels[j]=table->levels[j-1];
1811 quantization_tables=DestroyXMLTree(quantization_tables);
1812 xml=DestroyString(xml);
1816 static void InitializeDestination(j_compress_ptr cinfo)
1821 destination=(DestinationManager *) cinfo->dest;
1822 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1823 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1824 destination->manager.next_output_byte=destination->buffer;
1825 destination->manager.free_in_buffer=MaxBufferExtent;
1828 static inline size_t MagickMin(const size_t x,const size_t y)
1835 static void TerminateDestination(j_compress_ptr cinfo)
1840 destination=(DestinationManager *) cinfo->dest;
1841 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1846 count=WriteBlob(destination->image,MaxBufferExtent-
1847 destination->manager.free_in_buffer,destination->buffer);
1848 if (count != (ssize_t)
1849 (MaxBufferExtent-destination->manager.free_in_buffer))
1850 ERREXIT(cinfo,JERR_FILE_WRITE);
1854 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1876 Save image profile as a APP marker.
1879 custom_profile=AcquireStringInfo(65535L);
1880 ResetImageProfileIterator(image);
1881 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1883 register unsigned char
1886 profile=GetImageProfile(image,name);
1887 p=GetStringInfoDatum(custom_profile);
1888 if (LocaleCompare(name,"EXIF") == 0)
1889 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1891 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1892 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1893 (unsigned int) length);
1895 if (LocaleCompare(name,"ICC") == 0)
1897 register unsigned char
1900 tag_length=strlen(ICC_PROFILE);
1901 p=GetStringInfoDatum(custom_profile);
1902 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1904 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1906 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1907 p[12]=(unsigned char) ((i/65519L)+1);
1908 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1909 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1911 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1912 custom_profile),(unsigned int) (length+tag_length+3));
1915 if (((LocaleCompare(name,"IPTC") == 0) ||
1916 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1922 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1924 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1925 roundup=(size_t) (length & 0x01);
1926 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1928 (void) memcpy(p,"Photoshop 3.0 ",14);
1933 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1935 p[24]=(unsigned char) (length >> 8);
1936 p[25]=(unsigned char) (length & 0xff);
1939 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1941 p[length+tag_length]='\0';
1942 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1943 custom_profile),(unsigned int) (length+tag_length+roundup));
1946 if (LocaleCompare(name,"XMP") == 0)
1952 Add namespace to XMP profile.
1954 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1955 ConcatenateStringInfo(xmp_profile,profile);
1956 GetStringInfoDatum(xmp_profile)[28]='\0';
1957 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1959 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1960 jpeg_write_marker(jpeg_info,XML_MARKER,
1961 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1963 xmp_profile=DestroyStringInfo(xmp_profile);
1965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1966 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1967 name=GetNextImageProfile(image);
1969 custom_profile=DestroyStringInfo(custom_profile);
1972 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1977 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1978 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1979 destination=(DestinationManager *) cinfo->dest;
1980 destination->manager.init_destination=InitializeDestination;
1981 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1982 destination->manager.term_destination=TerminateDestination;
1983 destination->image=image;
1986 static char **SamplingFactorToList(const char *text)
2003 if (text == (char *) NULL)
2004 return((char **) NULL);
2006 Convert string to an ASCII list.
2009 for (p=text; *p != '\0'; p++)
2012 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2014 if (textlist == (char **) NULL)
2015 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2017 for (i=0; i < (ssize_t) lines; i++)
2019 for (q=(char *) p; *q != '\0'; q++)
2022 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2023 sizeof(*textlist[i]));
2024 if (textlist[i] == (char *) NULL)
2025 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2026 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2031 textlist[i]=(char *) NULL;
2035 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2036 Image *image,ExceptionInfo *exception)
2051 *volatile jpeg_pixels;
2071 struct jpeg_compress_struct
2074 struct jpeg_error_mgr
2080 assert(image_info != (const ImageInfo *) NULL);
2081 assert(image_info->signature == MagickSignature);
2082 assert(image != (Image *) NULL);
2083 assert(image->signature == MagickSignature);
2084 if (image->debug != MagickFalse)
2085 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2086 assert(exception != (ExceptionInfo *) NULL);
2087 assert(exception->signature == MagickSignature);
2088 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2089 if (status == MagickFalse)
2092 Initialize JPEG parameters.
2094 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2095 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2096 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2097 jpeg_info.client_data=(void *) image;
2098 jpeg_info.err=jpeg_std_error(&jpeg_error);
2099 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2100 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2101 error_manager.exception=exception;
2102 error_manager.image=image;
2103 memory_info=(MemoryInfo *) NULL;
2104 if (setjmp(error_manager.error_recovery) != 0)
2106 jpeg_destroy_compress(&jpeg_info);
2107 (void) CloseBlob(image);
2108 return(MagickFalse);
2110 jpeg_info.client_data=(void *) &error_manager;
2111 jpeg_create_compress(&jpeg_info);
2112 JPEGDestinationManager(&jpeg_info,image);
2113 if ((image->columns != (unsigned int) image->columns) ||
2114 (image->rows != (unsigned int) image->rows))
2115 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2116 jpeg_info.image_width=(unsigned int) image->columns;
2117 jpeg_info.image_height=(unsigned int) image->rows;
2118 jpeg_info.input_components=3;
2119 jpeg_info.data_precision=8;
2120 jpeg_info.in_color_space=JCS_RGB;
2121 switch (image->colorspace)
2123 case CMYKColorspace:
2125 jpeg_info.input_components=4;
2126 jpeg_info.in_color_space=JCS_CMYK;
2129 case YCbCrColorspace:
2130 case Rec601YCbCrColorspace:
2131 case Rec709YCbCrColorspace:
2133 jpeg_info.in_color_space=JCS_YCbCr;
2136 case GRAYColorspace:
2138 jpeg_info.input_components=1;
2139 jpeg_info.in_color_space=JCS_GRAYSCALE;
2144 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2145 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2149 if ((image_info->type != TrueColorType) &&
2150 (IsImageGray(image,exception) != MagickFalse))
2152 jpeg_info.input_components=1;
2153 jpeg_info.in_color_space=JCS_GRAYSCALE;
2155 jpeg_set_defaults(&jpeg_info);
2156 if (jpeg_info.in_color_space == JCS_CMYK)
2157 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2158 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2159 jpeg_info.data_precision=8;
2161 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2162 jpeg_info.density_unit=(UINT8) 1;
2163 if (image->debug != MagickFalse)
2164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2165 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2166 floor(image->resolution.y+0.5));
2167 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2170 Set image resolution.
2172 jpeg_info.write_JFIF_header=MagickTrue;
2173 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2174 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2176 Set image resolution units.
2178 jpeg_info.density_unit=(UINT8) 0;
2179 if (image->units == PixelsPerInchResolution)
2180 jpeg_info.density_unit=(UINT8) 1;
2181 if (image->units == PixelsPerCentimeterResolution)
2182 jpeg_info.density_unit=(UINT8) 2;
2184 jpeg_info.dct_method=JDCT_FLOAT;
2185 option=GetImageOption(image_info,"jpeg:dct-method");
2186 if (option != (const char *) NULL)
2192 if (LocaleCompare(option,"default") == 0)
2193 jpeg_info.dct_method=JDCT_DEFAULT;
2199 if (LocaleCompare(option,"fastest") == 0)
2200 jpeg_info.dct_method=JDCT_FASTEST;
2201 if (LocaleCompare(option,"float") == 0)
2202 jpeg_info.dct_method=JDCT_FLOAT;
2208 if (LocaleCompare(option,"ifast") == 0)
2209 jpeg_info.dct_method=JDCT_IFAST;
2210 if (LocaleCompare(option,"islow") == 0)
2211 jpeg_info.dct_method=JDCT_ISLOW;
2215 option=GetImageOption(image_info,"jpeg:optimize-coding");
2216 if (option != (const char *) NULL)
2217 jpeg_info.optimize_coding=IsStringTrue(option);
2223 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2224 image->rows*sizeof(JSAMPLE);
2225 if (length == (MagickSizeType) ((size_t) length))
2228 Perform optimization only if available memory resources permit it.
2230 status=AcquireMagickResource(MemoryResource,length);
2231 RelinquishMagickResource(MemoryResource,length);
2232 jpeg_info.optimize_coding=status;
2235 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2236 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2237 (image_info->interlace != NoInterlace))
2239 if (image->debug != MagickFalse)
2240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2241 "Interlace: progressive");
2242 jpeg_simple_progression(&jpeg_info);
2245 if (image->debug != MagickFalse)
2246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2247 "Interlace: non-progressive");
2249 if (image->debug != MagickFalse)
2250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2251 "Interlace: nonprogressive");
2254 option=GetImageOption(image_info,"jpeg:extent");
2255 if (option != (const char *) NULL)
2263 jpeg_info=CloneImageInfo(image_info);
2264 jpeg_info->blob=NULL;
2265 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2266 if (jpeg_image != (Image *) NULL)
2276 Search for compression quality that does not exceed image extent.
2278 jpeg_info->quality=0;
2279 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2280 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2281 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2282 (void) AcquireUniqueFilename(jpeg_image->filename);
2284 for (minimum=2; minimum < maximum; )
2286 jpeg_info->quality=minimum+(maximum-minimum+1)/2;
2287 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2288 if (GetBlobSize(jpeg_image) <= extent)
2289 minimum=jpeg_info->quality+1;
2291 maximum=jpeg_info->quality-1;
2293 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2295 jpeg_image=DestroyImage(jpeg_image);
2297 jpeg_info=DestroyImageInfo(jpeg_info);
2299 if ((image_info->compression != LosslessJPEGCompression) &&
2300 (image->quality <= 100))
2302 if (image->quality != UndefinedCompressionQuality)
2303 quality=(int) image->quality;
2304 if (image->debug != MagickFalse)
2305 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2306 (double) image->quality);
2310 #if !defined(C_LOSSLESS_SUPPORTED)
2312 if (image->debug != MagickFalse)
2313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2315 if (image->quality < 100)
2316 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2317 "LosslessToLossyJPEGConversion",image->filename);
2324 predictor=image->quality/100; /* range 1-7 */
2325 point_transform=image->quality % 20; /* range 0-15 */
2326 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2327 if (image->debug != MagickFalse)
2329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2330 "Compression: lossless");
2331 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2332 "Predictor: %d",predictor);
2333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2334 "Point Transform: %d",point_transform);
2339 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2340 #if (JPEG_LIB_VERSION >= 70)
2341 option=GetImageOption(image_info,"quality");
2342 if (option != (const char *) NULL)
2351 Set quality scaling for luminance and chrominance separately.
2353 flags=ParseGeometry(option,&geometry_info);
2354 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2356 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2357 (geometry_info.rho+0.5));
2358 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2359 (geometry_info.sigma+0.5));
2360 jpeg_default_qtables(&jpeg_info,MagickTrue);
2364 colorspace=jpeg_info.in_color_space;
2365 value=GetImageOption(image_info,"jpeg:colorspace");
2366 if (value == (char *) NULL)
2367 value=GetImageProperty(image,"jpeg:colorspace",exception);
2368 if (value != (char *) NULL)
2369 colorspace=StringToInteger(value);
2370 sampling_factor=(const char *) NULL;
2371 if (colorspace == jpeg_info.in_color_space)
2373 value=GetImageOption(image_info,"jpeg:sampling-factor");
2374 if (value == (char *) NULL)
2375 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2376 if (value != (char *) NULL)
2378 sampling_factor=value;
2379 if (image->debug != MagickFalse)
2380 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2381 " Input sampling-factors=%s",sampling_factor);
2384 value=GetImageOption(image_info,"jpeg:sampling-factor");
2385 if (image_info->sampling_factor != (char *) NULL)
2386 sampling_factor=image_info->sampling_factor;
2387 if (sampling_factor == (const char *) NULL)
2389 if (image->quality >= 90)
2390 for (i=0; i < MAX_COMPONENTS; i++)
2392 jpeg_info.comp_info[i].h_samp_factor=1;
2393 jpeg_info.comp_info[i].v_samp_factor=1;
2408 Set sampling factor.
2411 factors=SamplingFactorToList(sampling_factor);
2412 if (factors != (char **) NULL)
2414 for (i=0; i < MAX_COMPONENTS; i++)
2416 if (factors[i] == (char *) NULL)
2418 flags=ParseGeometry(factors[i],&geometry_info);
2419 if ((flags & SigmaValue) == 0)
2420 geometry_info.sigma=geometry_info.rho;
2421 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2422 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2423 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2425 factors=(char **) RelinquishMagickMemory(factors);
2427 for ( ; i < MAX_COMPONENTS; i++)
2429 jpeg_info.comp_info[i].h_samp_factor=1;
2430 jpeg_info.comp_info[i].v_samp_factor=1;
2433 option=GetImageOption(image_info,"jpeg:q-table");
2434 if (option != (const char *) NULL)
2440 Custom quantization tables.
2442 table=GetQuantizationTable(option,"0",exception);
2443 if (table != (QuantizationTable *) NULL)
2445 for (i=0; i < MAX_COMPONENTS; i++)
2446 jpeg_info.comp_info[i].quant_tbl_no=0;
2447 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2448 jpeg_quality_scaling(quality),0);
2449 table=DestroyQuantizationTable(table);
2451 table=GetQuantizationTable(option,"1",exception);
2452 if (table != (QuantizationTable *) NULL)
2454 for (i=1; i < MAX_COMPONENTS; i++)
2455 jpeg_info.comp_info[i].quant_tbl_no=1;
2456 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2457 jpeg_quality_scaling(quality),0);
2458 table=DestroyQuantizationTable(table);
2460 table=GetQuantizationTable(option,"2",exception);
2461 if (table != (QuantizationTable *) NULL)
2463 for (i=2; i < MAX_COMPONENTS; i++)
2464 jpeg_info.comp_info[i].quant_tbl_no=2;
2465 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2466 jpeg_quality_scaling(quality),0);
2467 table=DestroyQuantizationTable(table);
2469 table=GetQuantizationTable(option,"3",exception);
2470 if (table != (QuantizationTable *) NULL)
2472 for (i=3; i < MAX_COMPONENTS; i++)
2473 jpeg_info.comp_info[i].quant_tbl_no=3;
2474 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2475 jpeg_quality_scaling(quality),0);
2476 table=DestroyQuantizationTable(table);
2479 jpeg_start_compress(&jpeg_info,MagickTrue);
2480 if (image->debug != MagickFalse)
2482 if (image->storage_class == PseudoClass)
2483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2484 "Storage class: PseudoClass");
2486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2487 "Storage class: DirectClass");
2488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2489 (double) image->depth);
2490 if (image->colors != 0)
2491 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2492 "Number of colors: %.20g",(double) image->colors);
2494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2495 "Number of colors: unspecified");
2496 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2497 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2498 switch (image->colorspace)
2500 case CMYKColorspace:
2502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2503 "Storage class: DirectClass");
2504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2505 "Colorspace: CMYK");
2508 case YCbCrColorspace:
2509 case Rec601YCbCrColorspace:
2510 case Rec709YCbCrColorspace:
2512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2513 "Colorspace: YCbCr");
2519 switch (image->colorspace)
2521 case CMYKColorspace:
2523 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2524 "Colorspace: CMYK");
2525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2526 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2527 jpeg_info.comp_info[0].h_samp_factor,
2528 jpeg_info.comp_info[0].v_samp_factor,
2529 jpeg_info.comp_info[1].h_samp_factor,
2530 jpeg_info.comp_info[1].v_samp_factor,
2531 jpeg_info.comp_info[2].h_samp_factor,
2532 jpeg_info.comp_info[2].v_samp_factor,
2533 jpeg_info.comp_info[3].h_samp_factor,
2534 jpeg_info.comp_info[3].v_samp_factor);
2537 case GRAYColorspace:
2539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2540 "Colorspace: GRAY");
2541 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2542 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2543 jpeg_info.comp_info[0].v_samp_factor);
2546 case sRGBColorspace:
2549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2550 "Image colorspace is RGB");
2551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2552 "Sampling factors: %dx%d,%dx%d,%dx%d",
2553 jpeg_info.comp_info[0].h_samp_factor,
2554 jpeg_info.comp_info[0].v_samp_factor,
2555 jpeg_info.comp_info[1].h_samp_factor,
2556 jpeg_info.comp_info[1].v_samp_factor,
2557 jpeg_info.comp_info[2].h_samp_factor,
2558 jpeg_info.comp_info[2].v_samp_factor);
2561 case YCbCrColorspace:
2562 case Rec601YCbCrColorspace:
2563 case Rec709YCbCrColorspace:
2565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2566 "Colorspace: YCbCr");
2567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2568 "Sampling factors: %dx%d,%dx%d,%dx%d",
2569 jpeg_info.comp_info[0].h_samp_factor,
2570 jpeg_info.comp_info[0].v_samp_factor,
2571 jpeg_info.comp_info[1].h_samp_factor,
2572 jpeg_info.comp_info[1].v_samp_factor,
2573 jpeg_info.comp_info[2].h_samp_factor,
2574 jpeg_info.comp_info[2].v_samp_factor);
2579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2582 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2583 jpeg_info.comp_info[0].h_samp_factor,
2584 jpeg_info.comp_info[0].v_samp_factor,
2585 jpeg_info.comp_info[1].h_samp_factor,
2586 jpeg_info.comp_info[1].v_samp_factor,
2587 jpeg_info.comp_info[2].h_samp_factor,
2588 jpeg_info.comp_info[2].v_samp_factor,
2589 jpeg_info.comp_info[3].h_samp_factor,
2590 jpeg_info.comp_info[3].v_samp_factor);
2596 Write JPEG profiles.
2598 value=GetImageProperty(image,"comment",exception);
2599 if (value != (char *) NULL)
2600 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2601 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2602 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2603 if (image->profiles != (void *) NULL)
2604 WriteProfile(&jpeg_info,image);
2606 Convert MIFF to JPEG raster pixels.
2608 memory_info=AcquireVirtualMemory((size_t) image->columns,
2609 jpeg_info.input_components*sizeof(*jpeg_pixels));
2610 if (memory_info == (MemoryInfo *) NULL)
2611 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2612 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2613 if (setjmp(error_manager.error_recovery) != 0)
2615 jpeg_destroy_compress(&jpeg_info);
2616 if (memory_info != (MemoryInfo *) NULL)
2617 memory_info=RelinquishVirtualMemory(memory_info);
2618 (void) CloseBlob(image);
2619 return(MagickFalse);
2621 scanline[0]=(JSAMPROW) jpeg_pixels;
2622 if (jpeg_info.data_precision <= 8)
2624 if ((jpeg_info.in_color_space == JCS_RGB) ||
2625 (jpeg_info.in_color_space == JCS_YCbCr))
2626 for (y=0; y < (ssize_t) image->rows; y++)
2628 register const Quantum
2634 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2635 if (p == (const Quantum *) NULL)
2638 for (x=0; x < (ssize_t) image->columns; x++)
2640 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2641 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2642 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2643 p+=GetPixelChannels(image);
2645 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2646 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2648 if (status == MagickFalse)
2652 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2653 for (y=0; y < (ssize_t) image->rows; y++)
2655 register const Quantum
2661 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2662 if (p == (const Quantum *) NULL)
2665 for (x=0; x < (ssize_t) image->columns; x++)
2667 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2669 p+=GetPixelChannels(image);
2671 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2672 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2674 if (status == MagickFalse)
2678 for (y=0; y < (ssize_t) image->rows; y++)
2680 register const Quantum
2686 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2687 if (p == (const Quantum *) NULL)
2690 for (x=0; x < (ssize_t) image->columns; x++)
2693 Convert DirectClass packets to contiguous CMYK scanlines.
2695 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2696 GetPixelCyan(image,p))));
2697 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2698 GetPixelMagenta(image,p))));
2699 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2700 GetPixelYellow(image,p))));
2701 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2702 GetPixelBlack(image,p))));
2703 p+=GetPixelChannels(image);
2705 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2706 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2708 if (status == MagickFalse)
2713 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2714 for (y=0; y < (ssize_t) image->rows; y++)
2716 register const Quantum
2722 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2723 if (p == (const Quantum *) NULL)
2726 for (x=0; x < (ssize_t) image->columns; x++)
2728 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(
2730 p+=GetPixelChannels(image);
2732 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2733 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2735 if (status == MagickFalse)
2739 if ((jpeg_info.in_color_space == JCS_RGB) ||
2740 (jpeg_info.in_color_space == JCS_YCbCr))
2741 for (y=0; y < (ssize_t) image->rows; y++)
2743 register const Quantum
2749 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2750 if (p == (const Quantum *) NULL)
2753 for (x=0; x < (ssize_t) image->columns; x++)
2755 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2756 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2757 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2758 p+=GetPixelChannels(image);
2760 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2761 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2763 if (status == MagickFalse)
2767 for (y=0; y < (ssize_t) image->rows; y++)
2769 register const Quantum
2775 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2776 if (p == (const Quantum *) NULL)
2779 for (x=0; x < (ssize_t) image->columns; x++)
2782 Convert DirectClass packets to contiguous CMYK scanlines.
2784 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2785 GetPixelRed(image,p)) >> 4));
2786 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2787 GetPixelGreen(image,p)) >> 4));
2788 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2789 GetPixelBlue(image,p)) >> 4));
2790 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2791 GetPixelBlack(image,p)) >> 4));
2792 p+=GetPixelChannels(image);
2794 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2795 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2797 if (status == MagickFalse)
2800 if (y == (ssize_t) image->rows)
2801 jpeg_finish_compress(&jpeg_info);
2803 Relinquish resources.
2805 jpeg_destroy_compress(&jpeg_info);
2806 memory_info=RelinquishVirtualMemory(memory_info);
2807 (void) CloseBlob(image);