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
1033 assert(image_info != (const ImageInfo *) NULL);
1034 assert(image_info->signature == MagickSignature);
1035 if (image_info->debug != MagickFalse)
1036 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1037 image_info->filename);
1038 assert(exception != (ExceptionInfo *) NULL);
1039 assert(exception->signature == MagickSignature);
1040 debug=IsEventLogging();
1042 image=AcquireImage(image_info,exception);
1043 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1044 if (status == MagickFalse)
1046 image=DestroyImageList(image);
1047 return((Image *) NULL);
1050 Initialize JPEG parameters.
1052 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1053 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1054 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1055 jpeg_info.err=jpeg_std_error(&jpeg_error);
1056 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1057 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1058 memory_info=(MemoryInfo *) NULL;
1059 error_manager.exception=exception;
1060 error_manager.image=image;
1061 if (setjmp(error_manager.error_recovery) != 0)
1063 jpeg_destroy_decompress(&jpeg_info);
1064 if (error_manager.profile != (StringInfo *) NULL)
1065 error_manager.profile=DestroyStringInfo(error_manager.profile);
1066 (void) CloseBlob(image);
1067 number_pixels=(MagickSizeType) image->columns*image->rows;
1068 if (number_pixels != 0)
1069 return(GetFirstImageInList(image));
1070 return(DestroyImage(image));
1072 jpeg_info.client_data=(void *) &error_manager;
1073 jpeg_create_decompress(&jpeg_info);
1074 JPEGSourceManager(&jpeg_info,image);
1075 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1076 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1077 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1078 for (i=1; i < 16; i++)
1079 if ((i != 2) && (i != 13) && (i != 14))
1080 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1081 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1082 if ((image_info->colorspace == YCbCrColorspace) ||
1083 (image_info->colorspace == Rec601YCbCrColorspace) ||
1084 (image_info->colorspace == Rec709YCbCrColorspace))
1085 jpeg_info.out_color_space=JCS_YCbCr;
1087 Set image resolution.
1090 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1091 (jpeg_info.Y_density != 1))
1093 image->resolution.x=(double) jpeg_info.X_density;
1094 image->resolution.y=(double) jpeg_info.Y_density;
1095 units=(size_t) jpeg_info.density_unit;
1098 image->units=PixelsPerInchResolution;
1100 image->units=PixelsPerCentimeterResolution;
1101 number_pixels=(MagickSizeType) image->columns*image->rows;
1102 option=GetImageOption(image_info,"jpeg:size");
1103 if (option != (const char *) NULL)
1117 flags=ParseGeometry(option,&geometry_info);
1118 if ((flags & SigmaValue) == 0)
1119 geometry_info.sigma=geometry_info.rho;
1120 jpeg_calc_output_dimensions(&jpeg_info);
1121 image->magick_columns=jpeg_info.output_width;
1122 image->magick_rows=jpeg_info.output_height;
1124 if (geometry_info.rho != 0.0)
1125 scale_factor=jpeg_info.output_width/geometry_info.rho;
1126 if ((geometry_info.sigma != 0.0) &&
1127 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1128 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1129 jpeg_info.scale_num=1U;
1130 jpeg_info.scale_denom=(unsigned int) scale_factor;
1131 jpeg_calc_output_dimensions(&jpeg_info);
1132 if (image->debug != MagickFalse)
1133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1134 "Scale factor: %.20g",(double) scale_factor);
1136 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1137 #if defined(D_LOSSLESS_SUPPORTED)
1138 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1139 JPEGInterlace : NoInterlace;
1140 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1141 LosslessJPEGCompression : JPEGCompression;
1142 if (jpeg_info.data_precision > 8)
1143 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1144 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1146 if (jpeg_info.data_precision == 16)
1147 jpeg_info.data_precision=12;
1149 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1151 image->compression=JPEGCompression;
1154 image->compression=JPEGCompression;
1155 image->interlace=JPEGInterlace;
1157 option=GetImageOption(image_info,"jpeg:colors");
1158 if (option != (const char *) NULL)
1161 Let the JPEG library quantize the image.
1163 jpeg_info.quantize_colors=MagickTrue;
1164 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1166 option=GetImageOption(image_info,"jpeg:block-smoothing");
1167 if (option != (const char *) NULL)
1168 jpeg_info.do_block_smoothing=IsStringTrue(option);
1169 jpeg_info.dct_method=JDCT_FLOAT;
1170 option=GetImageOption(image_info,"jpeg:dct-method");
1171 if (option != (const char *) NULL)
1177 if (LocaleCompare(option,"default") == 0)
1178 jpeg_info.dct_method=JDCT_DEFAULT;
1184 if (LocaleCompare(option,"fastest") == 0)
1185 jpeg_info.dct_method=JDCT_FASTEST;
1186 if (LocaleCompare(option,"float") == 0)
1187 jpeg_info.dct_method=JDCT_FLOAT;
1193 if (LocaleCompare(option,"ifast") == 0)
1194 jpeg_info.dct_method=JDCT_IFAST;
1195 if (LocaleCompare(option,"islow") == 0)
1196 jpeg_info.dct_method=JDCT_ISLOW;
1200 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1201 if (option != (const char *) NULL)
1202 jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1203 (void) jpeg_start_decompress(&jpeg_info);
1204 image->columns=jpeg_info.output_width;
1205 image->rows=jpeg_info.output_height;
1206 image->depth=(size_t) jpeg_info.data_precision;
1207 switch (jpeg_info.out_color_space)
1212 (void) SetImageColorspace(image,sRGBColorspace,exception);
1217 (void) SetImageColorspace(image,GRAYColorspace,exception);
1222 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1227 (void) SetImageColorspace(image,CMYKColorspace,exception);
1231 if (IsITUFaxImage(image) != MagickFalse)
1233 (void) SetImageColorspace(image,LabColorspace,exception);
1234 jpeg_info.out_color_space=JCS_YCbCr;
1236 option=GetImageOption(image_info,"jpeg:colors");
1237 if (option != (const char *) NULL)
1238 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1240 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1241 if ((jpeg_info.output_components == 1) &&
1242 (jpeg_info.quantize_colors == MagickFalse))
1247 colors=(size_t) GetQuantumRange(image->depth)+1;
1248 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1249 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1251 if (image->debug != MagickFalse)
1253 if (image->interlace != NoInterlace)
1254 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1255 "Interlace: progressive");
1257 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1258 "Interlace: nonprogressive");
1259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1260 (int) jpeg_info.data_precision);
1261 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1262 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1264 JPEGSetImageQuality(&jpeg_info,image,exception);
1265 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1266 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1267 jpeg_info.out_color_space);
1268 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1269 if (image_info->ping != MagickFalse)
1271 jpeg_destroy_decompress(&jpeg_info);
1272 (void) CloseBlob(image);
1273 return(GetFirstImageInList(image));
1275 memory_info=AcquireVirtualMemory((size_t) image->columns,
1276 jpeg_info.output_components*sizeof(*jpeg_pixels));
1277 if (memory_info == (MemoryInfo *) NULL)
1279 jpeg_destroy_decompress(&jpeg_info);
1280 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1282 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1284 Convert JPEG pixels to pixel packets.
1286 if (setjmp(error_manager.error_recovery) != 0)
1288 if (memory_info != (MemoryInfo *) NULL)
1289 memory_info=RelinquishVirtualMemory(memory_info);
1290 jpeg_destroy_decompress(&jpeg_info);
1291 (void) CloseBlob(image);
1292 number_pixels=(MagickSizeType) image->columns*image->rows;
1293 if (number_pixels != 0)
1294 return(GetFirstImageInList(image));
1295 return(DestroyImage(image));
1297 if (jpeg_info.quantize_colors != MagickFalse)
1299 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1300 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1301 for (i=0; i < (ssize_t) image->colors; i++)
1303 image->colormap[i].red=(double) ScaleCharToQuantum(
1304 jpeg_info.colormap[0][i]);
1305 image->colormap[i].green=image->colormap[i].red;
1306 image->colormap[i].blue=image->colormap[i].red;
1307 image->colormap[i].alpha=OpaqueAlpha;
1310 for (i=0; i < (ssize_t) image->colors; i++)
1312 image->colormap[i].red=(double) ScaleCharToQuantum(
1313 jpeg_info.colormap[0][i]);
1314 image->colormap[i].green=(double) ScaleCharToQuantum(
1315 jpeg_info.colormap[1][i]);
1316 image->colormap[i].blue=(double) ScaleCharToQuantum(
1317 jpeg_info.colormap[2][i]);
1318 image->colormap[i].alpha=OpaqueAlpha;
1321 scanline[0]=(JSAMPROW) jpeg_pixels;
1322 for (y=0; y < (ssize_t) image->rows; y++)
1330 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1332 (void) ThrowMagickException(exception,GetMagickModule(),
1333 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1337 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1338 if (q == (Quantum *) NULL)
1340 if (jpeg_info.data_precision > 8)
1345 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1346 if (jpeg_info.output_components == 1)
1347 for (x=0; x < (ssize_t) image->columns; x++)
1352 pixel=(size_t) (scale*GETJSAMPLE(*p));
1353 index=ConstrainColormapIndex(image,pixel,exception);
1354 SetPixelIndex(image,index,q);
1355 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1357 q+=GetPixelChannels(image);
1360 if (image->colorspace != CMYKColorspace)
1361 for (x=0; x < (ssize_t) image->columns; x++)
1363 SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1364 SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1365 SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1366 SetPixelAlpha(image,OpaqueAlpha,q);
1367 q+=GetPixelChannels(image);
1370 for (x=0; x < (ssize_t) image->columns; x++)
1372 SetPixelCyan(image,QuantumRange-
1373 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1374 SetPixelMagenta(image,QuantumRange-
1375 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1376 SetPixelYellow(image,QuantumRange-
1377 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1378 SetPixelBlack(image,QuantumRange-
1379 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1380 SetPixelAlpha(image,OpaqueAlpha,q);
1381 q+=GetPixelChannels(image);
1385 if (jpeg_info.output_components == 1)
1386 for (x=0; x < (ssize_t) image->columns; x++)
1388 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1389 SetPixelIndex(image,index,q);
1390 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1392 q+=GetPixelChannels(image);
1395 if (image->colorspace != CMYKColorspace)
1396 for (x=0; x < (ssize_t) image->columns; x++)
1398 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1399 GETJSAMPLE(*p++)),q);
1400 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1401 GETJSAMPLE(*p++)),q);
1402 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1403 GETJSAMPLE(*p++)),q);
1404 SetPixelAlpha(image,OpaqueAlpha,q);
1405 q+=GetPixelChannels(image);
1408 for (x=0; x < (ssize_t) image->columns; x++)
1410 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1411 (unsigned char) GETJSAMPLE(*p++)),q);
1412 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1413 (unsigned char) GETJSAMPLE(*p++)),q);
1414 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1415 (unsigned char) GETJSAMPLE(*p++)),q);
1416 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1417 (unsigned char) GETJSAMPLE(*p++)),q);
1418 SetPixelAlpha(image,OpaqueAlpha,q);
1419 q+=GetPixelChannels(image);
1421 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1423 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1425 if (status == MagickFalse)
1427 jpeg_abort_decompress(&jpeg_info);
1431 if (status != MagickFalse)
1433 error_manager.finished=MagickTrue;
1434 if (setjmp(error_manager.error_recovery) == 0)
1435 (void) jpeg_finish_decompress(&jpeg_info);
1438 Free jpeg resources.
1440 jpeg_destroy_decompress(&jpeg_info);
1441 memory_info=RelinquishVirtualMemory(memory_info);
1442 (void) CloseBlob(image);
1443 return(GetFirstImageInList(image));
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 % R e g i s t e r J P E G I m a g e %
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459 % RegisterJPEGImage() adds properties for the JPEG image format to
1460 % the list of supported formats. The properties include the image format
1461 % tag, a method to read and/or write the format, whether the format
1462 % supports the saving of more than one frame to the same file or blob,
1463 % whether the format supports native in-memory I/O, and a brief
1464 % description of the format.
1466 % The format of the RegisterJPEGImage method is:
1468 % size_t RegisterJPEGImage(void)
1471 ModuleExport size_t RegisterJPEGImage(void)
1474 version[MaxTextExtent];
1480 description[] = "Joint Photographic Experts Group JFIF format";
1483 #if defined(JPEG_LIB_VERSION)
1484 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1486 entry=SetMagickInfo("JPEG");
1487 entry->thread_support=NoThreadSupport;
1488 #if defined(MAGICKCORE_JPEG_DELEGATE)
1489 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1490 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1492 entry->magick=(IsImageFormatHandler *) IsJPEG;
1493 entry->adjoin=MagickFalse;
1494 entry->description=ConstantString(description);
1495 if (*version != '\0')
1496 entry->version=ConstantString(version);
1497 entry->mime_type=ConstantString("image/jpeg");
1498 entry->module=ConstantString("JPEG");
1499 (void) RegisterMagickInfo(entry);
1500 entry=SetMagickInfo("JPG");
1501 entry->thread_support=NoThreadSupport;
1502 #if defined(MAGICKCORE_JPEG_DELEGATE)
1503 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1504 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1506 entry->adjoin=MagickFalse;
1507 entry->description=ConstantString(description);
1508 if (*version != '\0')
1509 entry->version=ConstantString(version);
1510 entry->mime_type=ConstantString("image/jpeg");
1511 entry->module=ConstantString("JPEG");
1512 (void) RegisterMagickInfo(entry);
1513 entry=SetMagickInfo("PJPEG");
1514 entry->thread_support=NoThreadSupport;
1515 #if defined(MAGICKCORE_JPEG_DELEGATE)
1516 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1517 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1519 entry->adjoin=MagickFalse;
1520 entry->description=ConstantString(description);
1521 if (*version != '\0')
1522 entry->version=ConstantString(version);
1523 entry->mime_type=ConstantString("image/jpeg");
1524 entry->module=ConstantString("JPEG");
1525 (void) RegisterMagickInfo(entry);
1526 return(MagickImageCoderSignature);
1531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535 % U n r e g i s t e r J P E G I m a g e %
1539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541 % UnregisterJPEGImage() removes format registrations made by the
1542 % JPEG module from the list of supported formats.
1544 % The format of the UnregisterJPEGImage method is:
1546 % UnregisterJPEGImage(void)
1549 ModuleExport void UnregisterJPEGImage(void)
1551 (void) UnregisterMagickInfo("PJPG");
1552 (void) UnregisterMagickInfo("JPEG");
1553 (void) UnregisterMagickInfo("JPG");
1557 #if defined(MAGICKCORE_JPEG_DELEGATE)
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1563 % W r i t e J P E G I m a g e %
1567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1569 % WriteJPEGImage() writes a JPEG image file and returns it. It
1570 % allocates the memory necessary for the new Image structure and returns a
1571 % pointer to the new image.
1573 % The format of the WriteJPEGImage method is:
1575 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1576 % Image *image,ExceptionInfo *exception)
1578 % A description of each parameter follows:
1580 % o image_info: the image info.
1582 % o jpeg_image: The image.
1584 % o exception: return any errors or warnings in this structure.
1588 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1590 assert(table != (QuantizationTable *) NULL);
1591 if (table->slot != (char *) NULL)
1592 table->slot=DestroyString(table->slot);
1593 if (table->description != (char *) NULL)
1594 table->description=DestroyString(table->description);
1595 if (table->levels != (unsigned int *) NULL)
1596 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1597 table=(QuantizationTable *) RelinquishMagickMemory(table);
1601 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1606 destination=(DestinationManager *) cinfo->dest;
1607 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1608 MaxBufferExtent,destination->buffer);
1609 if (destination->manager.free_in_buffer != MaxBufferExtent)
1610 ERREXIT(cinfo,JERR_FILE_WRITE);
1611 destination->manager.next_output_byte=destination->buffer;
1615 static QuantizationTable *GetQuantizationTable(const char *filename,
1616 const char *slot,ExceptionInfo *exception)
1644 *quantization_tables,
1647 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1648 "Loading quantization tables \"%s\" ...",filename);
1649 table=(QuantizationTable *) NULL;
1650 xml=FileToString(filename,~0UL,exception);
1651 if (xml == (char *) NULL)
1653 quantization_tables=NewXMLTree(xml,exception);
1654 if (quantization_tables == (XMLTreeInfo *) NULL)
1656 xml=DestroyString(xml);
1659 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1660 table_iterator != (XMLTreeInfo *) NULL;
1661 table_iterator=GetNextXMLTreeTag(table_iterator))
1663 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1664 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1666 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1667 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1670 if (table_iterator == (XMLTreeInfo *) NULL)
1672 xml=DestroyString(xml);
1675 description=GetXMLTreeChild(table_iterator,"description");
1676 if (description == (XMLTreeInfo *) NULL)
1678 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1679 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1680 quantization_tables=DestroyXMLTree(quantization_tables);
1681 xml=DestroyString(xml);
1684 levels=GetXMLTreeChild(table_iterator,"levels");
1685 if (levels == (XMLTreeInfo *) NULL)
1687 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1688 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1689 quantization_tables=DestroyXMLTree(quantization_tables);
1690 xml=DestroyString(xml);
1693 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1694 if (table == (QuantizationTable *) NULL)
1695 ThrowFatalException(ResourceLimitFatalError,
1696 "UnableToAcquireQuantizationTable");
1697 table->slot=(char *) NULL;
1698 table->description=(char *) NULL;
1699 table->levels=(unsigned int *) NULL;
1700 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1701 if (attribute != (char *) NULL)
1702 table->slot=ConstantString(attribute);
1703 content=GetXMLTreeContent(description);
1704 if (content != (char *) NULL)
1705 table->description=ConstantString(content);
1706 attribute=GetXMLTreeAttribute(levels,"width");
1707 if (attribute == (char *) NULL)
1709 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1710 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1711 quantization_tables=DestroyXMLTree(quantization_tables);
1712 table=DestroyQuantizationTable(table);
1713 xml=DestroyString(xml);
1716 table->width=StringToUnsignedLong(attribute);
1717 if (table->width == 0)
1719 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1720 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1721 quantization_tables=DestroyXMLTree(quantization_tables);
1722 table=DestroyQuantizationTable(table);
1723 xml=DestroyString(xml);
1726 attribute=GetXMLTreeAttribute(levels,"height");
1727 if (attribute == (char *) NULL)
1729 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1730 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1731 quantization_tables=DestroyXMLTree(quantization_tables);
1732 table=DestroyQuantizationTable(table);
1733 xml=DestroyString(xml);
1736 table->height=StringToUnsignedLong(attribute);
1737 if (table->height == 0)
1739 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1740 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1741 quantization_tables=DestroyXMLTree(quantization_tables);
1742 table=DestroyQuantizationTable(table);
1743 xml=DestroyString(xml);
1746 attribute=GetXMLTreeAttribute(levels,"divisor");
1747 if (attribute == (char *) NULL)
1749 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1750 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1751 quantization_tables=DestroyXMLTree(quantization_tables);
1752 table=DestroyQuantizationTable(table);
1753 xml=DestroyString(xml);
1756 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1757 if (table->divisor == 0.0)
1759 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1760 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1761 quantization_tables=DestroyXMLTree(quantization_tables);
1762 table=DestroyQuantizationTable(table);
1763 xml=DestroyString(xml);
1766 content=GetXMLTreeContent(levels);
1767 if (content == (char *) NULL)
1769 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1770 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1771 quantization_tables=DestroyXMLTree(quantization_tables);
1772 table=DestroyQuantizationTable(table);
1773 xml=DestroyString(xml);
1776 length=(size_t) table->width*table->height;
1779 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1780 sizeof(*table->levels));
1781 if (table->levels == (unsigned int *) NULL)
1782 ThrowFatalException(ResourceLimitFatalError,
1783 "UnableToAcquireQuantizationTable");
1784 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1786 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1787 table->divisor+0.5);
1788 while (isspace((int) ((unsigned char) *p)) != 0)
1794 value=InterpretLocaleValue(content,&p);
1798 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1799 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1800 quantization_tables=DestroyXMLTree(quantization_tables);
1801 table=DestroyQuantizationTable(table);
1802 xml=DestroyString(xml);
1805 for (j=i; j < 64; j++)
1806 table->levels[j]=table->levels[j-1];
1807 quantization_tables=DestroyXMLTree(quantization_tables);
1808 xml=DestroyString(xml);
1812 static void InitializeDestination(j_compress_ptr cinfo)
1817 destination=(DestinationManager *) cinfo->dest;
1818 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1819 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1820 destination->manager.next_output_byte=destination->buffer;
1821 destination->manager.free_in_buffer=MaxBufferExtent;
1824 static inline size_t MagickMin(const size_t x,const size_t y)
1831 static void TerminateDestination(j_compress_ptr cinfo)
1836 destination=(DestinationManager *) cinfo->dest;
1837 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1842 count=WriteBlob(destination->image,MaxBufferExtent-
1843 destination->manager.free_in_buffer,destination->buffer);
1844 if (count != (ssize_t)
1845 (MaxBufferExtent-destination->manager.free_in_buffer))
1846 ERREXIT(cinfo,JERR_FILE_WRITE);
1850 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1872 Save image profile as a APP marker.
1875 custom_profile=AcquireStringInfo(65535L);
1876 ResetImageProfileIterator(image);
1877 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1879 register unsigned char
1882 profile=GetImageProfile(image,name);
1883 p=GetStringInfoDatum(custom_profile);
1884 if (LocaleCompare(name,"EXIF") == 0)
1885 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1887 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1888 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1889 (unsigned int) length);
1891 if (LocaleCompare(name,"ICC") == 0)
1893 register unsigned char
1896 tag_length=strlen(ICC_PROFILE);
1897 p=GetStringInfoDatum(custom_profile);
1898 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1900 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1902 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1903 p[12]=(unsigned char) ((i/65519L)+1);
1904 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1905 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1907 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1908 custom_profile),(unsigned int) (length+tag_length+3));
1911 if (((LocaleCompare(name,"IPTC") == 0) ||
1912 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1918 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1920 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1921 roundup=(size_t) (length & 0x01);
1922 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1924 (void) memcpy(p,"Photoshop 3.0 ",14);
1929 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1931 p[24]=(unsigned char) (length >> 8);
1932 p[25]=(unsigned char) (length & 0xff);
1935 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1937 p[length+tag_length]='\0';
1938 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1939 custom_profile),(unsigned int) (length+tag_length+roundup));
1942 if (LocaleCompare(name,"XMP") == 0)
1948 Add namespace to XMP profile.
1950 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1951 ConcatenateStringInfo(xmp_profile,profile);
1952 GetStringInfoDatum(xmp_profile)[28]='\0';
1953 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1955 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1956 jpeg_write_marker(jpeg_info,XML_MARKER,
1957 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1959 xmp_profile=DestroyStringInfo(xmp_profile);
1961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1963 name=GetNextImageProfile(image);
1965 custom_profile=DestroyStringInfo(custom_profile);
1968 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1973 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1974 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1975 destination=(DestinationManager *) cinfo->dest;
1976 destination->manager.init_destination=InitializeDestination;
1977 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1978 destination->manager.term_destination=TerminateDestination;
1979 destination->image=image;
1982 static char **SamplingFactorToList(const char *text)
1999 if (text == (char *) NULL)
2000 return((char **) NULL);
2002 Convert string to an ASCII list.
2005 for (p=text; *p != '\0'; p++)
2008 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2010 if (textlist == (char **) NULL)
2011 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2013 for (i=0; i < (ssize_t) lines; i++)
2015 for (q=(char *) p; *q != '\0'; q++)
2018 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2019 sizeof(*textlist[i]));
2020 if (textlist[i] == (char *) NULL)
2021 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2022 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2027 textlist[i]=(char *) NULL;
2031 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2032 Image *image,ExceptionInfo *exception)
2047 *volatile jpeg_pixels;
2067 struct jpeg_compress_struct
2070 struct jpeg_error_mgr
2079 assert(image_info != (const ImageInfo *) NULL);
2080 assert(image_info->signature == MagickSignature);
2081 assert(image != (Image *) NULL);
2082 assert(image->signature == MagickSignature);
2083 if (image->debug != MagickFalse)
2084 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2085 assert(exception != (ExceptionInfo *) NULL);
2086 assert(exception->signature == MagickSignature);
2087 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2088 if (status == MagickFalse)
2091 Initialize JPEG parameters.
2093 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2094 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2095 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2096 jpeg_info.client_data=(void *) image;
2097 jpeg_info.err=jpeg_std_error(&jpeg_error);
2098 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2099 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2100 error_manager.exception=exception;
2101 error_manager.image=image;
2102 memory_info=(MemoryInfo *) NULL;
2103 if (setjmp(error_manager.error_recovery) != 0)
2105 jpeg_destroy_compress(&jpeg_info);
2106 (void) CloseBlob(image);
2107 return(MagickFalse);
2109 jpeg_info.client_data=(void *) &error_manager;
2110 jpeg_create_compress(&jpeg_info);
2111 JPEGDestinationManager(&jpeg_info,image);
2112 if ((image->columns != (unsigned int) image->columns) ||
2113 (image->rows != (unsigned int) image->rows))
2114 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2115 jpeg_info.image_width=(unsigned int) image->columns;
2116 jpeg_info.image_height=(unsigned int) image->rows;
2117 jpeg_info.input_components=3;
2118 jpeg_info.data_precision=8;
2119 jpeg_info.in_color_space=JCS_RGB;
2120 switch (image->colorspace)
2122 case CMYKColorspace:
2124 jpeg_info.input_components=4;
2125 jpeg_info.in_color_space=JCS_CMYK;
2128 case YCbCrColorspace:
2129 case Rec601YCbCrColorspace:
2130 case Rec709YCbCrColorspace:
2132 jpeg_info.in_color_space=JCS_YCbCr;
2135 case GRAYColorspace:
2137 jpeg_info.input_components=1;
2138 jpeg_info.in_color_space=JCS_GRAYSCALE;
2143 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2144 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2148 if ((image_info->type != TrueColorType) &&
2149 (IsImageGray(image,exception) != MagickFalse))
2151 jpeg_info.input_components=1;
2152 jpeg_info.in_color_space=JCS_GRAYSCALE;
2154 jpeg_set_defaults(&jpeg_info);
2155 if (jpeg_info.in_color_space == JCS_CMYK)
2156 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2157 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2158 jpeg_info.data_precision=8;
2160 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2161 jpeg_info.density_unit=(UINT8) 1;
2162 if (image->debug != MagickFalse)
2163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2164 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2165 floor(image->resolution.y+0.5));
2166 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2169 Set image resolution.
2171 jpeg_info.write_JFIF_header=MagickTrue;
2172 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2173 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2175 Set image resolution units.
2177 jpeg_info.density_unit=(UINT8) 0;
2178 if (image->units == PixelsPerInchResolution)
2179 jpeg_info.density_unit=(UINT8) 1;
2180 if (image->units == PixelsPerCentimeterResolution)
2181 jpeg_info.density_unit=(UINT8) 2;
2183 jpeg_info.dct_method=JDCT_FLOAT;
2184 option=GetImageOption(image_info,"jpeg:dct-method");
2185 if (option != (const char *) NULL)
2191 if (LocaleCompare(option,"default") == 0)
2192 jpeg_info.dct_method=JDCT_DEFAULT;
2198 if (LocaleCompare(option,"fastest") == 0)
2199 jpeg_info.dct_method=JDCT_FASTEST;
2200 if (LocaleCompare(option,"float") == 0)
2201 jpeg_info.dct_method=JDCT_FLOAT;
2207 if (LocaleCompare(option,"ifast") == 0)
2208 jpeg_info.dct_method=JDCT_IFAST;
2209 if (LocaleCompare(option,"islow") == 0)
2210 jpeg_info.dct_method=JDCT_ISLOW;
2214 option=GetImageOption(image_info,"jpeg:optimize-coding");
2215 if (option != (const char *) NULL)
2216 jpeg_info.optimize_coding=IsStringTrue(option);
2222 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2223 image->rows*sizeof(JSAMPLE);
2224 if (length == (MagickSizeType) ((size_t) length))
2227 Perform optimization only if available memory resources permit it.
2229 status=AcquireMagickResource(MemoryResource,length);
2230 RelinquishMagickResource(MemoryResource,length);
2231 jpeg_info.optimize_coding=status;
2234 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2235 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2236 (image_info->interlace != NoInterlace))
2238 if (image->debug != MagickFalse)
2239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2240 "Interlace: progressive");
2241 jpeg_simple_progression(&jpeg_info);
2244 if (image->debug != MagickFalse)
2245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2246 "Interlace: non-progressive");
2248 if (image->debug != MagickFalse)
2249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2250 "Interlace: nonprogressive");
2253 option=GetImageOption(image_info,"jpeg:extent");
2254 if (option != (const char *) NULL)
2262 jpeg_info=CloneImageInfo(image_info);
2263 jpeg_info->blob=NULL;
2264 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2265 if (jpeg_image != (Image *) NULL)
2275 Search for compression quality that does not exceed image extent.
2277 jpeg_info->quality=0;
2278 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2279 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2280 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2281 (void) AcquireUniqueFilename(jpeg_image->filename);
2283 for (minimum=2; minimum < maximum; )
2285 jpeg_info->quality=minimum+(maximum-minimum+1)/2;
2286 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2287 if (GetBlobSize(jpeg_image) <= extent)
2288 minimum=jpeg_info->quality+1;
2290 maximum=jpeg_info->quality-1;
2292 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2294 jpeg_image=DestroyImage(jpeg_image);
2296 jpeg_info=DestroyImageInfo(jpeg_info);
2298 if ((image_info->compression != LosslessJPEGCompression) &&
2299 (image->quality <= 100))
2301 if (image->quality != UndefinedCompressionQuality)
2302 quality=(int) image->quality;
2303 if (image->debug != MagickFalse)
2304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2305 (double) image->quality);
2309 #if !defined(C_LOSSLESS_SUPPORTED)
2311 if (image->debug != MagickFalse)
2312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2314 if (image->quality < 100)
2315 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2316 "LosslessToLossyJPEGConversion",image->filename);
2323 predictor=image->quality/100; /* range 1-7 */
2324 point_transform=image->quality % 20; /* range 0-15 */
2325 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2326 if (image->debug != MagickFalse)
2328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2329 "Compression: lossless");
2330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2331 "Predictor: %d",predictor);
2332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2333 "Point Transform: %d",point_transform);
2338 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2339 #if (JPEG_LIB_VERSION >= 70)
2340 option=GetImageOption(image_info,"quality");
2341 if (option != (const char *) NULL)
2350 Set quality scaling for luminance and chrominance separately.
2352 flags=ParseGeometry(option,&geometry_info);
2353 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2355 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2356 (geometry_info.rho+0.5));
2357 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2358 (geometry_info.sigma+0.5));
2359 jpeg_default_qtables(&jpeg_info,MagickTrue);
2363 colorspace=jpeg_info.in_color_space;
2364 value=GetImageOption(image_info,"jpeg:colorspace");
2365 if (value == (char *) NULL)
2366 value=GetImageProperty(image,"jpeg:colorspace",exception);
2367 if (value != (char *) NULL)
2368 colorspace=StringToInteger(value);
2369 sampling_factor=(const char *) NULL;
2370 if (colorspace == jpeg_info.in_color_space)
2372 value=GetImageOption(image_info,"jpeg:sampling-factor");
2373 if (value == (char *) NULL)
2374 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2375 if (value != (char *) NULL)
2377 sampling_factor=value;
2378 if (image->debug != MagickFalse)
2379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2380 " Input sampling-factors=%s",sampling_factor);
2383 value=GetImageOption(image_info,"jpeg:sampling-factor");
2384 if (image_info->sampling_factor != (char *) NULL)
2385 sampling_factor=image_info->sampling_factor;
2386 if (sampling_factor == (const char *) NULL)
2388 if (image->quality >= 90)
2389 for (i=0; i < MAX_COMPONENTS; i++)
2391 jpeg_info.comp_info[i].h_samp_factor=1;
2392 jpeg_info.comp_info[i].v_samp_factor=1;
2407 Set sampling factor.
2410 factors=SamplingFactorToList(sampling_factor);
2411 if (factors != (char **) NULL)
2413 for (i=0; i < MAX_COMPONENTS; i++)
2415 if (factors[i] == (char *) NULL)
2417 flags=ParseGeometry(factors[i],&geometry_info);
2418 if ((flags & SigmaValue) == 0)
2419 geometry_info.sigma=geometry_info.rho;
2420 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2421 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2422 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2424 factors=(char **) RelinquishMagickMemory(factors);
2426 for ( ; i < MAX_COMPONENTS; i++)
2428 jpeg_info.comp_info[i].h_samp_factor=1;
2429 jpeg_info.comp_info[i].v_samp_factor=1;
2432 option=GetImageOption(image_info,"jpeg:q-table");
2433 if (option != (const char *) NULL)
2439 Custom quantization tables.
2441 table=GetQuantizationTable(option,"0",exception);
2442 if (table != (QuantizationTable *) NULL)
2444 for (i=0; i < MAX_COMPONENTS; i++)
2445 jpeg_info.comp_info[i].quant_tbl_no=0;
2446 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2447 jpeg_quality_scaling(quality),0);
2448 table=DestroyQuantizationTable(table);
2450 table=GetQuantizationTable(option,"1",exception);
2451 if (table != (QuantizationTable *) NULL)
2453 for (i=1; i < MAX_COMPONENTS; i++)
2454 jpeg_info.comp_info[i].quant_tbl_no=1;
2455 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2456 jpeg_quality_scaling(quality),0);
2457 table=DestroyQuantizationTable(table);
2459 table=GetQuantizationTable(option,"2",exception);
2460 if (table != (QuantizationTable *) NULL)
2462 for (i=2; i < MAX_COMPONENTS; i++)
2463 jpeg_info.comp_info[i].quant_tbl_no=2;
2464 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2465 jpeg_quality_scaling(quality),0);
2466 table=DestroyQuantizationTable(table);
2468 table=GetQuantizationTable(option,"3",exception);
2469 if (table != (QuantizationTable *) NULL)
2471 for (i=3; i < MAX_COMPONENTS; i++)
2472 jpeg_info.comp_info[i].quant_tbl_no=3;
2473 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2474 jpeg_quality_scaling(quality),0);
2475 table=DestroyQuantizationTable(table);
2478 jpeg_start_compress(&jpeg_info,MagickTrue);
2479 if (image->debug != MagickFalse)
2481 if (image->storage_class == PseudoClass)
2482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2483 "Storage class: PseudoClass");
2485 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2486 "Storage class: DirectClass");
2487 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2488 (double) image->depth);
2489 if (image->colors != 0)
2490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2491 "Number of colors: %.20g",(double) image->colors);
2493 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2494 "Number of colors: unspecified");
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2497 switch (image->colorspace)
2499 case CMYKColorspace:
2501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2502 "Storage class: DirectClass");
2503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2504 "Colorspace: CMYK");
2507 case YCbCrColorspace:
2508 case Rec601YCbCrColorspace:
2509 case Rec709YCbCrColorspace:
2511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2512 "Colorspace: YCbCr");
2518 switch (image->colorspace)
2520 case CMYKColorspace:
2522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2523 "Colorspace: CMYK");
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2526 jpeg_info.comp_info[0].h_samp_factor,
2527 jpeg_info.comp_info[0].v_samp_factor,
2528 jpeg_info.comp_info[1].h_samp_factor,
2529 jpeg_info.comp_info[1].v_samp_factor,
2530 jpeg_info.comp_info[2].h_samp_factor,
2531 jpeg_info.comp_info[2].v_samp_factor,
2532 jpeg_info.comp_info[3].h_samp_factor,
2533 jpeg_info.comp_info[3].v_samp_factor);
2536 case GRAYColorspace:
2538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2539 "Colorspace: GRAY");
2540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2541 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2542 jpeg_info.comp_info[0].v_samp_factor);
2545 case sRGBColorspace:
2548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549 "Image colorspace is RGB");
2550 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2551 "Sampling factors: %dx%d,%dx%d,%dx%d",
2552 jpeg_info.comp_info[0].h_samp_factor,
2553 jpeg_info.comp_info[0].v_samp_factor,
2554 jpeg_info.comp_info[1].h_samp_factor,
2555 jpeg_info.comp_info[1].v_samp_factor,
2556 jpeg_info.comp_info[2].h_samp_factor,
2557 jpeg_info.comp_info[2].v_samp_factor);
2560 case YCbCrColorspace:
2561 case Rec601YCbCrColorspace:
2562 case Rec709YCbCrColorspace:
2564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2565 "Colorspace: YCbCr");
2566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2567 "Sampling factors: %dx%d,%dx%d,%dx%d",
2568 jpeg_info.comp_info[0].h_samp_factor,
2569 jpeg_info.comp_info[0].v_samp_factor,
2570 jpeg_info.comp_info[1].h_samp_factor,
2571 jpeg_info.comp_info[1].v_samp_factor,
2572 jpeg_info.comp_info[2].h_samp_factor,
2573 jpeg_info.comp_info[2].v_samp_factor);
2578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2581 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2582 jpeg_info.comp_info[0].h_samp_factor,
2583 jpeg_info.comp_info[0].v_samp_factor,
2584 jpeg_info.comp_info[1].h_samp_factor,
2585 jpeg_info.comp_info[1].v_samp_factor,
2586 jpeg_info.comp_info[2].h_samp_factor,
2587 jpeg_info.comp_info[2].v_samp_factor,
2588 jpeg_info.comp_info[3].h_samp_factor,
2589 jpeg_info.comp_info[3].v_samp_factor);
2595 Write JPEG profiles.
2597 value=GetImageProperty(image,"comment",exception);
2598 if (value != (char *) NULL)
2599 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2600 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2601 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2602 if (image->profiles != (void *) NULL)
2603 WriteProfile(&jpeg_info,image);
2605 Convert MIFF to JPEG raster pixels.
2607 memory_info=AcquireVirtualMemory((size_t) image->columns,
2608 jpeg_info.input_components*sizeof(*jpeg_pixels));
2609 if (memory_info == (MemoryInfo *) NULL)
2610 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2611 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2612 if (setjmp(error_manager.error_recovery) != 0)
2614 jpeg_destroy_compress(&jpeg_info);
2615 if (memory_info != (MemoryInfo *) NULL)
2616 memory_info=RelinquishVirtualMemory(memory_info);
2617 (void) CloseBlob(image);
2618 return(MagickFalse);
2620 scanline[0]=(JSAMPROW) jpeg_pixels;
2621 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
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))/scale);
2756 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2757 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
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) (ScaleQuantumToShort(QuantumRange-
2785 GetPixelRed(image,p))/scale);
2786 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-
2787 GetPixelGreen(image,p))/scale);
2788 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-
2789 GetPixelBlue(image,p))/scale);
2790 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-
2791 GetPixelBlack(image,p))/scale);
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);