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.
46 #include "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/token.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/xml-tree.h"
83 #include "MagickCore/xml-tree-private.h"
85 #if defined(MAGICKCORE_JPEG_DELEGATE)
86 #define JPEG_INTERNAL_OPTIONS
87 #if defined(__MINGW32__) || defined(__MINGW64__)
88 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
98 #define ICC_MARKER (JPEG_APP0+2)
99 #define ICC_PROFILE "ICC_PROFILE"
100 #define IPTC_MARKER (JPEG_APP0+13)
101 #define XML_MARKER (JPEG_APP0+1)
102 #define MaxBufferExtent 16384
105 Typedef declarations.
107 #if defined(MAGICKCORE_JPEG_DELEGATE)
108 typedef struct _DestinationManager
110 struct jpeg_destination_mgr
118 } DestinationManager;
120 typedef struct _ErrorManager
138 typedef struct _SourceManager
140 struct jpeg_source_mgr
154 typedef struct _QuantizationTable
172 Forward declarations.
174 #if defined(MAGICKCORE_JPEG_DELEGATE)
175 static MagickBooleanType
176 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190 % IsJPEG() returns MagickTrue if the image format type, identified by the
191 % magick string, is JPEG.
193 % The format of the IsJPEG method is:
195 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
197 % A description of each parameter follows:
199 % o magick: compare image format pattern against these bytes.
201 % o length: Specifies the length of the magick string.
204 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
208 if (memcmp(magick,"\377\330\377",3) == 0)
213 #if defined(MAGICKCORE_JPEG_DELEGATE)
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 % R e a d J P E G I m a g e %
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
226 % the memory necessary for the new Image structure and returns a pointer to
229 % The format of the ReadJPEGImage method is:
231 % Image *ReadJPEGImage(const ImageInfo *image_info,
232 % ExceptionInfo *exception)
234 % A description of each parameter follows:
236 % o image_info: the image info.
238 % o exception: return any errors or warnings in this structure.
242 static boolean FillInputBuffer(j_decompress_ptr cinfo)
247 source=(SourceManager *) cinfo->src;
248 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
249 MaxBufferExtent,source->buffer);
250 if (source->manager.bytes_in_buffer == 0)
252 if (source->start_of_blob != FALSE)
253 ERREXIT(cinfo,JERR_INPUT_EMPTY);
254 WARNMS(cinfo,JWRN_JPEG_EOF);
255 source->buffer[0]=(JOCTET) 0xff;
256 source->buffer[1]=(JOCTET) JPEG_EOI;
257 source->manager.bytes_in_buffer=2;
259 source->manager.next_input_byte=source->buffer;
260 source->start_of_blob=FALSE;
264 static int GetCharacter(j_decompress_ptr jpeg_info)
266 if (jpeg_info->src->bytes_in_buffer == 0)
267 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
268 jpeg_info->src->bytes_in_buffer--;
269 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
272 static void InitializeSource(j_decompress_ptr cinfo)
277 source=(SourceManager *) cinfo->src;
278 source->start_of_blob=TRUE;
281 static MagickBooleanType IsITUFaxImage(const Image *image)
289 profile=GetImageProfile(image,"8bim");
290 if (profile == (const StringInfo *) NULL)
292 if (GetStringInfoLength(profile) < 5)
294 datum=GetStringInfoDatum(profile);
295 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
296 (datum[3] == 0x41) && (datum[4] == 0x58))
301 static void JPEGErrorHandler(j_common_ptr jpeg_info)
304 message[JMSG_LENGTH_MAX];
316 error_manager=(ErrorManager *) jpeg_info->client_data;
317 image=error_manager->image;
318 exception=error_manager->exception;
319 (jpeg_info->err->format_message)(jpeg_info,message);
320 if (image->debug != MagickFalse)
321 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
322 "[%s] JPEG Trace: \"%s\"",image->filename,message);
323 if (error_manager->finished != MagickFalse)
324 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
325 (char *) message,"`%s'",image->filename);
327 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
328 (char *) message,"`%s'",image->filename);
329 longjmp(error_manager->error_recovery,1);
332 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
334 #define JPEGExcessiveWarnings 1000
337 message[JMSG_LENGTH_MAX];
349 error_manager=(ErrorManager *) jpeg_info->client_data;
350 exception=error_manager->exception;
351 image=error_manager->image;
355 Process warning message.
357 (jpeg_info->err->format_message)(jpeg_info,message);
358 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
359 JPEGErrorHandler(jpeg_info);
360 ThrowBinaryException(CorruptImageWarning,(char *) message,
364 if ((image->debug != MagickFalse) &&
365 (level >= jpeg_info->err->trace_level))
368 Process trace message.
370 (jpeg_info->err->format_message)(jpeg_info,message);
371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
372 "[%s] JPEG Trace: \"%s\"",image->filename,message);
377 static boolean ReadComment(j_decompress_ptr jpeg_info)
388 register unsigned char
401 Determine length of comment.
403 error_manager=(ErrorManager *) jpeg_info->client_data;
404 exception=error_manager->exception;
405 image=error_manager->image;
406 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
407 length+=GetCharacter(jpeg_info);
411 comment=BlobToStringInfo((const void *) NULL,length);
412 if (comment == (StringInfo *) NULL)
413 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
418 error_manager->profile=comment;
419 p=GetStringInfoDatum(comment);
420 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
421 *p++=(unsigned char) GetCharacter(jpeg_info);
423 error_manager->profile=NULL;
424 p=GetStringInfoDatum(comment);
425 (void) SetImageProperty(image,"comment",(const char *) p,exception);
426 comment=DestroyStringInfo(comment);
430 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
450 register unsigned char
463 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
464 length+=(size_t) GetCharacter(jpeg_info);
469 (void) GetCharacter(jpeg_info);
472 for (i=0; i < 12; i++)
473 magick[i]=(char) GetCharacter(jpeg_info);
474 if (LocaleCompare(magick,ICC_PROFILE) != 0)
477 Not a ICC profile, return.
479 for (i=0; i < (ssize_t) (length-12); i++)
480 (void) GetCharacter(jpeg_info);
483 (void) GetCharacter(jpeg_info); /* id */
484 (void) GetCharacter(jpeg_info); /* markers */
486 error_manager=(ErrorManager *) jpeg_info->client_data;
487 exception=error_manager->exception;
488 image=error_manager->image;
489 profile=BlobToStringInfo((const void *) NULL,length);
490 if (profile == (StringInfo *) NULL)
491 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
493 error_manager->profile=profile;
494 p=GetStringInfoDatum(profile);
495 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
496 *p++=(unsigned char) GetCharacter(jpeg_info);
497 error_manager->profile=NULL;
498 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
499 if (icc_profile != (StringInfo *) NULL)
501 ConcatenateStringInfo(icc_profile,profile);
502 profile=DestroyStringInfo(profile);
506 status=SetImageProfile(image,"icc",profile,exception);
507 profile=DestroyStringInfo(profile);
508 if (status == MagickFalse)
509 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
512 if (image->debug != MagickFalse)
513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
514 "Profile: ICC, %.20g bytes",(double) length);
518 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
521 magick[MaxTextExtent];
538 register unsigned char
549 Determine length of binary data stored here.
551 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
552 length+=(size_t) GetCharacter(jpeg_info);
557 (void) GetCharacter(jpeg_info);
561 Validate that this was written as a Photoshop resource format slug.
563 for (i=0; i < 10; i++)
564 magick[i]=(char) GetCharacter(jpeg_info);
569 if (LocaleCompare(magick,"Photoshop ") != 0)
572 Not a IPTC profile, return.
574 for (i=0; i < (ssize_t) length; i++)
575 (void) GetCharacter(jpeg_info);
579 Remove the version number.
581 for (i=0; i < 4; i++)
582 (void) GetCharacter(jpeg_info);
588 error_manager=(ErrorManager *) jpeg_info->client_data;
589 exception=error_manager->exception;
590 image=error_manager->image;
591 profile=BlobToStringInfo((const void *) NULL,length);
592 if (profile == (StringInfo *) NULL)
593 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
595 error_manager->profile=profile;
596 p=GetStringInfoDatum(profile);
597 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
598 *p++=(unsigned char) GetCharacter(jpeg_info);
599 error_manager->profile=NULL;
600 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
601 if (iptc_profile != (StringInfo *) NULL)
603 ConcatenateStringInfo(iptc_profile,profile);
604 profile=DestroyStringInfo(profile);
608 status=SetImageProfile(image,"8bim",profile,exception);
609 profile=DestroyStringInfo(profile);
610 if (status == MagickFalse)
611 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
614 if (image->debug != MagickFalse)
615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
616 "Profile: iptc, %.20g bytes",(double) length);
620 static boolean ReadProfile(j_decompress_ptr jpeg_info)
646 register unsigned char
656 Read generic profile.
658 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
659 length+=(size_t) GetCharacter(jpeg_info);
663 marker=jpeg_info->unread_marker-JPEG_APP0;
664 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
665 error_manager=(ErrorManager *) jpeg_info->client_data;
666 exception=error_manager->exception;
667 image=error_manager->image;
668 profile=BlobToStringInfo((const void *) NULL,length);
669 if (profile == (StringInfo *) NULL)
670 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
672 error_manager->profile=profile;
673 p=GetStringInfoDatum(profile);
674 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
675 *p++=(unsigned char) GetCharacter(jpeg_info);
676 error_manager->profile=NULL;
679 p=GetStringInfoDatum(profile);
680 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
681 (void) CopyMagickString(name,"exif",MaxTextExtent);
682 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
688 Extract namespace from XMP profile.
690 p=GetStringInfoDatum(profile);
691 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
697 if (j < (ssize_t) GetStringInfoLength(profile))
698 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
699 (void) CopyMagickString(name,"xmp",MaxTextExtent);
702 previous_profile=GetImageProfile(image,name);
703 if (previous_profile != (const StringInfo *) NULL)
708 length=GetStringInfoLength(profile);
709 SetStringInfoLength(profile,GetStringInfoLength(profile)+
710 GetStringInfoLength(previous_profile));
711 (void) memmove(GetStringInfoDatum(profile)+
712 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
714 (void) memcpy(GetStringInfoDatum(profile),
715 GetStringInfoDatum(previous_profile),
716 GetStringInfoLength(previous_profile));
718 status=SetImageProfile(image,name,profile,exception);
719 profile=DestroyStringInfo(profile);
720 if (status == MagickFalse)
721 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
723 if (image->debug != MagickFalse)
724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
725 "Profile: %s, %.20g bytes",name,(double) length);
729 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
734 if (number_bytes <= 0)
736 source=(SourceManager *) cinfo->src;
737 while (number_bytes > (long) source->manager.bytes_in_buffer)
739 number_bytes-=(long) source->manager.bytes_in_buffer;
740 (void) FillInputBuffer(cinfo);
742 source->manager.next_input_byte+=number_bytes;
743 source->manager.bytes_in_buffer-=number_bytes;
746 static void TerminateSource(j_decompress_ptr cinfo)
751 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
756 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
757 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
758 source=(SourceManager *) cinfo->src;
759 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
760 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
761 source=(SourceManager *) cinfo->src;
762 source->manager.init_source=InitializeSource;
763 source->manager.fill_input_buffer=FillInputBuffer;
764 source->manager.skip_input_data=SkipInputData;
765 source->manager.resync_to_restart=jpeg_resync_to_restart;
766 source->manager.term_source=TerminateSource;
767 source->manager.bytes_in_buffer=0;
768 source->manager.next_input_byte=NULL;
772 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
775 image->quality=UndefinedCompressionQuality;
776 #if defined(D_PROGRESSIVE_SUPPORTED)
777 if (image->compression == LosslessJPEGCompression)
780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
781 "Quality: 100 (lossless)");
795 Determine the JPEG compression quality from the quantization tables.
798 for (i=0; i < NUM_QUANT_TBLS; i++)
800 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
801 for (j=0; j < DCTSIZE2; j++)
802 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
804 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
805 (jpeg_info->quant_tbl_ptrs[1] != NULL))
810 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
811 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
812 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
813 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
814 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
815 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
816 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
817 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
818 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
819 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
824 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
825 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
826 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
827 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
828 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
829 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
830 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
831 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
832 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
833 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
834 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
838 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
839 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
840 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
841 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
842 for (i=0; i < 100; i++)
844 if ((qvalue < hash[i]) && (sum < sums[i]))
846 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
847 image->quality=(size_t) i+1;
848 if (image->debug != MagickFalse)
849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
850 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
851 (sum <= sums[i]) ? "exact" : "approximate");
856 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
861 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
862 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
863 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
864 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
865 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
866 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
867 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
868 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
869 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
870 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
875 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
876 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
877 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
878 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
879 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
880 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
881 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
882 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
883 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
884 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
885 667, 592, 518, 441, 369, 292, 221, 151, 86,
889 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
890 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
891 for (i=0; i < 100; i++)
893 if ((qvalue < hash[i]) && (sum < sums[i]))
895 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
896 image->quality=(size_t) i+1;
897 if (image->debug != MagickFalse)
898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
899 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
900 (sum <= sums[i]) ? "exact" : "approximate");
907 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
910 sampling_factor[MaxTextExtent];
912 switch (jpeg_info->out_color_space)
916 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
917 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
918 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
919 jpeg_info->comp_info[0].v_samp_factor,
920 jpeg_info->comp_info[1].h_samp_factor,
921 jpeg_info->comp_info[1].v_samp_factor,
922 jpeg_info->comp_info[2].h_samp_factor,
923 jpeg_info->comp_info[2].v_samp_factor,
924 jpeg_info->comp_info[3].h_samp_factor,
925 jpeg_info->comp_info[3].v_samp_factor);
930 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
931 "Colorspace: GRAYSCALE");
932 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
933 jpeg_info->comp_info[0].h_samp_factor,
934 jpeg_info->comp_info[0].v_samp_factor);
939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
940 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
941 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
942 jpeg_info->comp_info[0].v_samp_factor,
943 jpeg_info->comp_info[1].h_samp_factor,
944 jpeg_info->comp_info[1].v_samp_factor,
945 jpeg_info->comp_info[2].h_samp_factor,
946 jpeg_info->comp_info[2].v_samp_factor);
951 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
952 jpeg_info->out_color_space);
953 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
954 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
955 jpeg_info->comp_info[0].v_samp_factor,
956 jpeg_info->comp_info[1].h_samp_factor,
957 jpeg_info->comp_info[1].v_samp_factor,
958 jpeg_info->comp_info[2].h_samp_factor,
959 jpeg_info->comp_info[2].v_samp_factor,
960 jpeg_info->comp_info[3].h_samp_factor,
961 jpeg_info->comp_info[3].v_samp_factor);
965 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
967 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
971 static Image *ReadJPEGImage(const ImageInfo *image_info,
972 ExceptionInfo *exception)
975 value[MaxTextExtent];
987 *volatile jpeg_pixels;
1005 struct jpeg_decompress_struct
1008 struct jpeg_error_mgr
1024 assert(image_info != (const ImageInfo *) NULL);
1025 assert(image_info->signature == MagickSignature);
1026 if (image_info->debug != MagickFalse)
1027 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1028 image_info->filename);
1029 assert(exception != (ExceptionInfo *) NULL);
1030 assert(exception->signature == MagickSignature);
1031 debug=IsEventLogging();
1033 image=AcquireImage(image_info,exception);
1034 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1035 if (status == MagickFalse)
1037 image=DestroyImageList(image);
1038 return((Image *) NULL);
1041 Initialize JPEG parameters.
1043 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1044 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1045 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1046 jpeg_info.err=jpeg_std_error(&jpeg_error);
1047 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1048 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1049 jpeg_pixels=(JSAMPLE *) NULL;
1050 error_manager.exception=exception;
1051 error_manager.image=image;
1052 if (setjmp(error_manager.error_recovery) != 0)
1054 jpeg_destroy_decompress(&jpeg_info);
1055 if (error_manager.profile != (StringInfo *) NULL)
1056 error_manager.profile=DestroyStringInfo(error_manager.profile);
1057 (void) CloseBlob(image);
1058 number_pixels=(MagickSizeType) image->columns*image->rows;
1059 if (number_pixels != 0)
1060 return(GetFirstImageInList(image));
1061 return(DestroyImage(image));
1063 jpeg_info.client_data=(void *) &error_manager;
1064 jpeg_create_decompress(&jpeg_info);
1065 JPEGSourceManager(&jpeg_info,image);
1066 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1067 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1068 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1069 for (i=1; i < 16; i++)
1070 if ((i != 2) && (i != 13) && (i != 14))
1071 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1072 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1073 if ((image_info->colorspace == YCbCrColorspace) ||
1074 (image_info->colorspace == Rec601YCbCrColorspace) ||
1075 (image_info->colorspace == Rec709YCbCrColorspace))
1076 jpeg_info.out_color_space=JCS_YCbCr;
1078 Set image resolution.
1081 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1082 (jpeg_info.Y_density != 1))
1084 image->resolution.x=(double) jpeg_info.X_density;
1085 image->resolution.y=(double) jpeg_info.Y_density;
1086 units=(size_t) jpeg_info.density_unit;
1089 image->units=PixelsPerInchResolution;
1091 image->units=PixelsPerCentimeterResolution;
1092 number_pixels=(MagickSizeType) image->columns*image->rows;
1093 option=GetImageOption(image_info,"jpeg:size");
1094 if (option != (const char *) NULL)
1108 flags=ParseGeometry(option,&geometry_info);
1109 if ((flags & SigmaValue) == 0)
1110 geometry_info.sigma=geometry_info.rho;
1111 jpeg_calc_output_dimensions(&jpeg_info);
1112 image->magick_columns=jpeg_info.output_width;
1113 image->magick_rows=jpeg_info.output_height;
1115 if (geometry_info.rho != 0.0)
1116 scale_factor=jpeg_info.output_width/geometry_info.rho;
1117 if ((geometry_info.sigma != 0.0) &&
1118 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1119 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1120 jpeg_info.scale_num=1U;
1121 jpeg_info.scale_denom=(unsigned int) scale_factor;
1122 jpeg_calc_output_dimensions(&jpeg_info);
1123 if (image->debug != MagickFalse)
1124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1125 "Scale factor: %.20g",(double) scale_factor);
1127 precision=(size_t) jpeg_info.data_precision;
1128 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1129 #if defined(D_LOSSLESS_SUPPORTED)
1130 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1131 JPEGInterlace : NoInterlace;
1132 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1133 LosslessJPEGCompression : JPEGCompression;
1134 if (jpeg_info.data_precision > 8)
1135 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1136 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1138 if (jpeg_info.data_precision == 16)
1139 jpeg_info.data_precision=12;
1141 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1143 image->compression=JPEGCompression;
1146 image->compression=JPEGCompression;
1147 image->interlace=JPEGInterlace;
1149 option=GetImageOption(image_info,"jpeg:colors");
1150 if (option != (const char *) NULL)
1153 Let the JPEG library quantize the image.
1155 jpeg_info.quantize_colors=MagickTrue;
1156 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1158 option=GetImageOption(image_info,"jpeg:block-smoothing");
1159 jpeg_info.do_block_smoothing=IsStringTrue(option);
1160 jpeg_info.dct_method=JDCT_FLOAT;
1161 option=GetImageOption(image_info,"jpeg:dct-method");
1162 if (option != (const char *) NULL)
1168 if (LocaleCompare(option,"default") == 0)
1169 jpeg_info.dct_method=JDCT_DEFAULT;
1175 if (LocaleCompare(option,"fastest") == 0)
1176 jpeg_info.dct_method=JDCT_FASTEST;
1177 if (LocaleCompare(option,"float") == 0)
1178 jpeg_info.dct_method=JDCT_FLOAT;
1184 if (LocaleCompare(option,"ifast") == 0)
1185 jpeg_info.dct_method=JDCT_IFAST;
1186 if (LocaleCompare(option,"islow") == 0)
1187 jpeg_info.dct_method=JDCT_ISLOW;
1191 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1192 jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1193 (void) jpeg_start_decompress(&jpeg_info);
1194 image->columns=jpeg_info.output_width;
1195 image->rows=jpeg_info.output_height;
1196 image->depth=(size_t) jpeg_info.data_precision;
1197 switch (jpeg_info.out_color_space)
1202 (void) SetImageColorspace(image,sRGBColorspace,exception);
1207 (void) SetImageColorspace(image,GRAYColorspace,exception);
1212 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1217 (void) SetImageColorspace(image,CMYKColorspace,exception);
1221 if (IsITUFaxImage(image) != MagickFalse)
1223 (void) SetImageColorspace(image,LabColorspace,exception);
1224 jpeg_info.out_color_space=JCS_YCbCr;
1226 option=GetImageOption(image_info,"jpeg:colors");
1227 if (option != (const char *) NULL)
1228 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1230 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1231 if ((jpeg_info.output_components == 1) &&
1232 (jpeg_info.quantize_colors == MagickFalse))
1237 colors=(size_t) GetQuantumRange(image->depth)+1;
1238 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1239 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1241 if (image->debug != MagickFalse)
1243 if (image->interlace != NoInterlace)
1244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1245 "Interlace: progressive");
1247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1248 "Interlace: nonprogressive");
1249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1250 (int) jpeg_info.data_precision);
1251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1252 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1254 JPEGSetImageQuality(&jpeg_info,image);
1255 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1256 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1257 jpeg_info.out_color_space);
1258 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1259 if (image_info->ping != MagickFalse)
1261 jpeg_destroy_decompress(&jpeg_info);
1262 (void) CloseBlob(image);
1263 return(GetFirstImageInList(image));
1265 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1266 jpeg_info.output_components*sizeof(JSAMPLE));
1267 if (jpeg_pixels == (JSAMPLE *) NULL)
1268 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1270 Convert JPEG pixels to pixel packets.
1272 if (setjmp(error_manager.error_recovery) != 0)
1274 if (jpeg_pixels != (JSAMPLE *) NULL)
1275 jpeg_pixels=(JSAMPLE *) RelinquishMagickMemory(jpeg_pixels);
1276 jpeg_destroy_decompress(&jpeg_info);
1277 (void) CloseBlob(image);
1278 number_pixels=(MagickSizeType) image->columns*image->rows;
1279 if (number_pixels != 0)
1280 return(GetFirstImageInList(image));
1281 return(DestroyImage(image));
1283 if (jpeg_info.quantize_colors != MagickFalse)
1285 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1286 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1287 for (i=0; i < (ssize_t) image->colors; i++)
1289 image->colormap[i].red=(double) ScaleCharToQuantum(
1290 jpeg_info.colormap[0][i]);
1291 image->colormap[i].green=image->colormap[i].red;
1292 image->colormap[i].blue=image->colormap[i].red;
1293 image->colormap[i].alpha=OpaqueAlpha;
1296 for (i=0; i < (ssize_t) image->colors; i++)
1298 image->colormap[i].red=(double) ScaleCharToQuantum(
1299 jpeg_info.colormap[0][i]);
1300 image->colormap[i].green=(double) ScaleCharToQuantum(
1301 jpeg_info.colormap[1][i]);
1302 image->colormap[i].blue=(double) ScaleCharToQuantum(
1303 jpeg_info.colormap[2][i]);
1304 image->colormap[i].alpha=OpaqueAlpha;
1307 scanline[0]=(JSAMPROW) jpeg_pixels;
1308 for (y=0; y < (ssize_t) image->rows; y++)
1316 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1318 (void) ThrowMagickException(exception,GetMagickModule(),
1319 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1323 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1324 if (q == (Quantum *) NULL)
1326 if (jpeg_info.data_precision > 8)
1328 if (jpeg_info.output_components == 1)
1329 for (x=0; x < (ssize_t) image->columns; x++)
1334 if (precision != 16)
1335 pixel=(size_t) GETJSAMPLE(*p);
1337 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1338 index=ConstrainColormapIndex(image,pixel,exception);
1339 SetPixelIndex(image,index,q);
1340 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1342 q+=GetPixelChannels(image);
1345 if (image->colorspace != CMYKColorspace)
1346 for (x=0; x < (ssize_t) image->columns; x++)
1348 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1349 (GETJSAMPLE(*p++) << 4)),q);
1350 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1351 (GETJSAMPLE(*p++) << 4)),q);
1352 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1353 (GETJSAMPLE(*p++) << 4)),q);
1354 SetPixelAlpha(image,OpaqueAlpha,q);
1355 q+=GetPixelChannels(image);
1358 for (x=0; x < (ssize_t) image->columns; x++)
1360 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1361 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1362 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1363 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1364 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1365 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1366 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1367 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1368 SetPixelAlpha(image,OpaqueAlpha,q);
1369 q+=GetPixelChannels(image);
1373 if (jpeg_info.output_components == 1)
1374 for (x=0; x < (ssize_t) image->columns; x++)
1376 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1377 SetPixelIndex(image,index,q);
1378 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1380 q+=GetPixelChannels(image);
1383 if (image->colorspace != CMYKColorspace)
1384 for (x=0; x < (ssize_t) image->columns; x++)
1386 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1387 GETJSAMPLE(*p++)),q);
1388 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1389 GETJSAMPLE(*p++)),q);
1390 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1391 GETJSAMPLE(*p++)),q);
1392 SetPixelAlpha(image,OpaqueAlpha,q);
1393 q+=GetPixelChannels(image);
1396 for (x=0; x < (ssize_t) image->columns; x++)
1398 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1399 (unsigned char) GETJSAMPLE(*p++)),q);
1400 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1401 (unsigned char) GETJSAMPLE(*p++)),q);
1402 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1403 (unsigned char) GETJSAMPLE(*p++)),q);
1404 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1405 (unsigned char) GETJSAMPLE(*p++)),q);
1406 SetPixelAlpha(image,OpaqueAlpha,q);
1407 q+=GetPixelChannels(image);
1409 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1411 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1413 if (status == MagickFalse)
1415 jpeg_abort_decompress(&jpeg_info);
1419 if (status != MagickFalse)
1421 error_manager.finished=MagickTrue;
1422 if (setjmp(error_manager.error_recovery) == 0)
1423 (void) jpeg_finish_decompress(&jpeg_info);
1426 Free jpeg resources.
1428 jpeg_destroy_decompress(&jpeg_info);
1429 jpeg_pixels=(JSAMPLE *) RelinquishMagickMemory(jpeg_pixels);
1430 (void) CloseBlob(image);
1431 return(GetFirstImageInList(image));
1436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % R e g i s t e r J P E G I m a g e %
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446 % RegisterJPEGImage() adds properties for the JPEG image format to
1447 % the list of supported formats. The properties include the image format
1448 % tag, a method to read and/or write the format, whether the format
1449 % supports the saving of more than one frame to the same file or blob,
1450 % whether the format supports native in-memory I/O, and a brief
1451 % description of the format.
1453 % The format of the RegisterJPEGImage method is:
1455 % size_t RegisterJPEGImage(void)
1458 ModuleExport size_t RegisterJPEGImage(void)
1461 version[MaxTextExtent];
1467 description[] = "Joint Photographic Experts Group JFIF format";
1470 #if defined(JPEG_LIB_VERSION)
1471 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1473 entry=SetMagickInfo("JPEG");
1474 entry->thread_support=NoThreadSupport;
1475 #if defined(MAGICKCORE_JPEG_DELEGATE)
1476 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1477 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1479 entry->magick=(IsImageFormatHandler *) IsJPEG;
1480 entry->adjoin=MagickFalse;
1481 entry->description=ConstantString(description);
1482 if (*version != '\0')
1483 entry->version=ConstantString(version);
1484 entry->module=ConstantString("JPEG");
1485 (void) RegisterMagickInfo(entry);
1486 entry=SetMagickInfo("JPG");
1487 entry->thread_support=NoThreadSupport;
1488 #if defined(MAGICKCORE_JPEG_DELEGATE)
1489 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1490 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1492 entry->adjoin=MagickFalse;
1493 entry->description=ConstantString(description);
1494 if (*version != '\0')
1495 entry->version=ConstantString(version);
1496 entry->module=ConstantString("JPEG");
1497 (void) RegisterMagickInfo(entry);
1498 entry=SetMagickInfo("PJPEG");
1499 entry->thread_support=NoThreadSupport;
1500 #if defined(MAGICKCORE_JPEG_DELEGATE)
1501 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1502 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1504 entry->adjoin=MagickFalse;
1505 entry->description=ConstantString(description);
1506 if (*version != '\0')
1507 entry->version=ConstantString(version);
1508 entry->module=ConstantString("JPEG");
1509 (void) RegisterMagickInfo(entry);
1510 return(MagickImageCoderSignature);
1514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518 % U n r e g i s t e r J P E G I m a g e %
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524 % UnregisterJPEGImage() removes format registrations made by the
1525 % JPEG module from the list of supported formats.
1527 % The format of the UnregisterJPEGImage method is:
1529 % UnregisterJPEGImage(void)
1532 ModuleExport void UnregisterJPEGImage(void)
1534 (void) UnregisterMagickInfo("PJPG");
1535 (void) UnregisterMagickInfo("JPEG");
1536 (void) UnregisterMagickInfo("JPG");
1539 #if defined(MAGICKCORE_JPEG_DELEGATE)
1541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545 % W r i t e J P E G I m a g e %
1549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1551 % WriteJPEGImage() writes a JPEG image file and returns it. It
1552 % allocates the memory necessary for the new Image structure and returns a
1553 % pointer to the new image.
1555 % The format of the WriteJPEGImage method is:
1557 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1558 % Image *image,ExceptionInfo *exception)
1560 % A description of each parameter follows:
1562 % o image_info: the image info.
1564 % o jpeg_image: The image.
1566 % o exception: return any errors or warnings in this structure.
1570 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1572 assert(table != (QuantizationTable *) NULL);
1573 if (table->slot != (char *) NULL)
1574 table->slot=DestroyString(table->slot);
1575 if (table->description != (char *) NULL)
1576 table->description=DestroyString(table->description);
1577 if (table->levels != (unsigned int *) NULL)
1578 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1579 table=(QuantizationTable *) RelinquishMagickMemory(table);
1583 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1588 destination=(DestinationManager *) cinfo->dest;
1589 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1590 MaxBufferExtent,destination->buffer);
1591 if (destination->manager.free_in_buffer != MaxBufferExtent)
1592 ERREXIT(cinfo,JERR_FILE_WRITE);
1593 destination->manager.next_output_byte=destination->buffer;
1597 static QuantizationTable *GetQuantizationTable(const char *filename,
1598 const char *slot,ExceptionInfo *exception)
1626 *quantization_tables,
1629 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1630 "Loading quantization tables \"%s\" ...",filename);
1631 table=(QuantizationTable *) NULL;
1632 xml=FileToString(filename,~0,exception);
1633 if (xml == (char *) NULL)
1635 quantization_tables=NewXMLTree(xml,exception);
1636 if (quantization_tables == (XMLTreeInfo *) NULL)
1638 xml=DestroyString(xml);
1641 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1642 table_iterator != (XMLTreeInfo *) NULL;
1643 table_iterator=GetNextXMLTreeTag(table_iterator))
1645 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1646 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1648 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1649 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1652 if (table_iterator == (XMLTreeInfo *) NULL)
1654 xml=DestroyString(xml);
1657 description=GetXMLTreeChild(table_iterator,"description");
1658 if (description == (XMLTreeInfo *) NULL)
1660 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1661 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1662 quantization_tables=DestroyXMLTree(quantization_tables);
1663 xml=DestroyString(xml);
1666 levels=GetXMLTreeChild(table_iterator,"levels");
1667 if (levels == (XMLTreeInfo *) NULL)
1669 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1670 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1671 quantization_tables=DestroyXMLTree(quantization_tables);
1672 xml=DestroyString(xml);
1675 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1676 if (table == (QuantizationTable *) NULL)
1677 ThrowFatalException(ResourceLimitFatalError,
1678 "UnableToAcquireQuantizationTable");
1679 table->slot=(char *) NULL;
1680 table->description=(char *) NULL;
1681 table->levels=(unsigned int *) NULL;
1682 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1683 if (attribute != (char *) NULL)
1684 table->slot=ConstantString(attribute);
1685 content=GetXMLTreeContent(description);
1686 if (content != (char *) NULL)
1687 table->description=ConstantString(content);
1688 attribute=GetXMLTreeAttribute(levels,"width");
1689 if (attribute == (char *) NULL)
1691 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1692 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1693 quantization_tables=DestroyXMLTree(quantization_tables);
1694 table=DestroyQuantizationTable(table);
1695 xml=DestroyString(xml);
1698 table->width=StringToUnsignedLong(attribute);
1699 if (table->width == 0)
1701 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1702 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1703 quantization_tables=DestroyXMLTree(quantization_tables);
1704 table=DestroyQuantizationTable(table);
1705 xml=DestroyString(xml);
1708 attribute=GetXMLTreeAttribute(levels,"height");
1709 if (attribute == (char *) NULL)
1711 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1712 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1713 quantization_tables=DestroyXMLTree(quantization_tables);
1714 table=DestroyQuantizationTable(table);
1715 xml=DestroyString(xml);
1718 table->height=StringToUnsignedLong(attribute);
1719 if (table->height == 0)
1721 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1722 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1723 quantization_tables=DestroyXMLTree(quantization_tables);
1724 table=DestroyQuantizationTable(table);
1725 xml=DestroyString(xml);
1728 attribute=GetXMLTreeAttribute(levels,"divisor");
1729 if (attribute == (char *) NULL)
1731 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1732 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1733 quantization_tables=DestroyXMLTree(quantization_tables);
1734 table=DestroyQuantizationTable(table);
1735 xml=DestroyString(xml);
1738 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1739 if (table->divisor == 0.0)
1741 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1742 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1743 quantization_tables=DestroyXMLTree(quantization_tables);
1744 table=DestroyQuantizationTable(table);
1745 xml=DestroyString(xml);
1748 content=GetXMLTreeContent(levels);
1749 if (content == (char *) NULL)
1751 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1752 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1753 quantization_tables=DestroyXMLTree(quantization_tables);
1754 table=DestroyQuantizationTable(table);
1755 xml=DestroyString(xml);
1758 length=(size_t) table->width*table->height;
1761 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1762 sizeof(*table->levels));
1763 if (table->levels == (unsigned int *) NULL)
1764 ThrowFatalException(ResourceLimitFatalError,
1765 "UnableToAcquireQuantizationTable");
1766 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1768 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1769 table->divisor+0.5);
1770 while (isspace((int) ((unsigned char) *p)) != 0)
1776 value=InterpretLocaleValue(content,&p);
1780 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1781 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1782 quantization_tables=DestroyXMLTree(quantization_tables);
1783 table=DestroyQuantizationTable(table);
1784 xml=DestroyString(xml);
1787 for (j=i; j < 64; j++)
1788 table->levels[j]=table->levels[j-1];
1789 quantization_tables=DestroyXMLTree(quantization_tables);
1790 xml=DestroyString(xml);
1794 static void InitializeDestination(j_compress_ptr cinfo)
1799 destination=(DestinationManager *) cinfo->dest;
1800 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1801 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1802 destination->manager.next_output_byte=destination->buffer;
1803 destination->manager.free_in_buffer=MaxBufferExtent;
1806 static inline size_t MagickMin(const size_t x,const size_t y)
1813 static void TerminateDestination(j_compress_ptr cinfo)
1818 destination=(DestinationManager *) cinfo->dest;
1819 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1824 count=WriteBlob(destination->image,MaxBufferExtent-
1825 destination->manager.free_in_buffer,destination->buffer);
1826 if (count != (ssize_t)
1827 (MaxBufferExtent-destination->manager.free_in_buffer))
1828 ERREXIT(cinfo,JERR_FILE_WRITE);
1832 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1854 Save image profile as a APP marker.
1857 custom_profile=AcquireStringInfo(65535L);
1858 ResetImageProfileIterator(image);
1859 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1861 register unsigned char
1864 profile=GetImageProfile(image,name);
1865 p=GetStringInfoDatum(custom_profile);
1866 if (LocaleCompare(name,"EXIF") == 0)
1867 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1869 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1870 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1871 (unsigned int) length);
1873 if (LocaleCompare(name,"ICC") == 0)
1875 register unsigned char
1879 p=GetStringInfoDatum(custom_profile);
1880 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1881 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1883 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1884 p[12]=(unsigned char) ((i/65519L)+1);
1885 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1886 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1888 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1889 custom_profile),(unsigned int) (length+tag_length));
1892 if (((LocaleCompare(name,"IPTC") == 0) ||
1893 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1899 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1901 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1902 roundup=(size_t) (length & 0x01);
1903 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1905 (void) memcpy(p,"Photoshop 3.0 ",14);
1910 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1912 p[24]=(unsigned char) (length >> 8);
1913 p[25]=(unsigned char) (length & 0xff);
1916 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1918 p[length+tag_length]='\0';
1919 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1920 custom_profile),(unsigned int) (length+tag_length+roundup));
1923 if (LocaleCompare(name,"XMP") == 0)
1929 Add namespace to XMP profile.
1931 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1932 ConcatenateStringInfo(xmp_profile,profile);
1933 GetStringInfoDatum(xmp_profile)[28]='\0';
1934 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1936 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1937 jpeg_write_marker(jpeg_info,XML_MARKER,
1938 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1940 xmp_profile=DestroyStringInfo(xmp_profile);
1942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1943 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1944 name=GetNextImageProfile(image);
1946 custom_profile=DestroyStringInfo(custom_profile);
1949 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1954 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1955 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1956 destination=(DestinationManager *) cinfo->dest;
1957 destination->manager.init_destination=InitializeDestination;
1958 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1959 destination->manager.term_destination=TerminateDestination;
1960 destination->image=image;
1963 static char **SamplingFactorToList(const char *text)
1980 if (text == (char *) NULL)
1981 return((char **) NULL);
1983 Convert string to an ASCII list.
1986 for (p=text; *p != '\0'; p++)
1989 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1991 if (textlist == (char **) NULL)
1992 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1994 for (i=0; i < (ssize_t) lines; i++)
1996 for (q=(char *) p; *q != '\0'; q++)
1999 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2000 sizeof(*textlist[i]));
2001 if (textlist[i] == (char *) NULL)
2002 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2003 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2008 textlist[i]=(char *) NULL;
2012 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2013 Image *image,ExceptionInfo *exception)
2027 *volatile jpeg_pixels;
2044 struct jpeg_compress_struct
2047 struct jpeg_error_mgr
2053 assert(image_info != (const ImageInfo *) NULL);
2054 assert(image_info->signature == MagickSignature);
2055 assert(image != (Image *) NULL);
2056 assert(image->signature == MagickSignature);
2057 if (image->debug != MagickFalse)
2058 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2059 assert(exception != (ExceptionInfo *) NULL);
2060 assert(exception->signature == MagickSignature);
2061 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2062 if (status == MagickFalse)
2065 Initialize JPEG parameters.
2067 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2068 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2069 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2070 jpeg_info.client_data=(void *) image;
2071 jpeg_info.err=jpeg_std_error(&jpeg_error);
2072 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2073 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2074 error_manager.exception=exception;
2075 error_manager.image=image;
2076 jpeg_pixels=(JSAMPLE *) NULL;
2077 if (setjmp(error_manager.error_recovery) != 0)
2079 jpeg_destroy_compress(&jpeg_info);
2080 (void) CloseBlob(image);
2081 return(MagickFalse);
2083 jpeg_info.client_data=(void *) &error_manager;
2084 jpeg_create_compress(&jpeg_info);
2085 JPEGDestinationManager(&jpeg_info,image);
2086 if ((image->columns != (unsigned int) image->columns) ||
2087 (image->rows != (unsigned int) image->rows))
2088 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2089 jpeg_info.image_width=(unsigned int) image->columns;
2090 jpeg_info.image_height=(unsigned int) image->rows;
2091 jpeg_info.input_components=3;
2092 jpeg_info.data_precision=8;
2093 jpeg_info.in_color_space=JCS_RGB;
2094 switch (image->colorspace)
2096 case CMYKColorspace:
2098 jpeg_info.input_components=4;
2099 jpeg_info.in_color_space=JCS_CMYK;
2102 case YCbCrColorspace:
2103 case Rec601YCbCrColorspace:
2104 case Rec709YCbCrColorspace:
2106 jpeg_info.in_color_space=JCS_YCbCr;
2109 case GRAYColorspace:
2110 case Rec601LumaColorspace:
2111 case Rec709LumaColorspace:
2113 jpeg_info.input_components=1;
2114 jpeg_info.in_color_space=JCS_GRAYSCALE;
2119 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2120 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2124 if ((image_info->type != TrueColorType) &&
2125 (IsImageGray(image,exception) != MagickFalse))
2127 jpeg_info.input_components=1;
2128 jpeg_info.in_color_space=JCS_GRAYSCALE;
2130 jpeg_set_defaults(&jpeg_info);
2131 if (jpeg_info.in_color_space == JCS_CMYK)
2132 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2133 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2134 jpeg_info.data_precision=8;
2136 if (sizeof(JSAMPLE) > 1)
2137 jpeg_info.data_precision=12;
2138 jpeg_info.density_unit=(UINT8) 1;
2139 if (image->debug != MagickFalse)
2140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2141 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2142 floor(image->resolution.y+0.5));
2143 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2146 Set image resolution.
2148 jpeg_info.write_JFIF_header=MagickTrue;
2149 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2150 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2151 if (image->units == PixelsPerInchResolution)
2152 jpeg_info.density_unit=(UINT8) 1;
2153 if (image->units == PixelsPerCentimeterResolution)
2154 jpeg_info.density_unit=(UINT8) 2;
2156 jpeg_info.dct_method=JDCT_FLOAT;
2157 option=GetImageOption(image_info,"jpeg:dct-method");
2158 if (option != (const char *) NULL)
2164 if (LocaleCompare(option,"default") == 0)
2165 jpeg_info.dct_method=JDCT_DEFAULT;
2171 if (LocaleCompare(option,"fastest") == 0)
2172 jpeg_info.dct_method=JDCT_FASTEST;
2173 if (LocaleCompare(option,"float") == 0)
2174 jpeg_info.dct_method=JDCT_FLOAT;
2180 if (LocaleCompare(option,"ifast") == 0)
2181 jpeg_info.dct_method=JDCT_IFAST;
2182 if (LocaleCompare(option,"islow") == 0)
2183 jpeg_info.dct_method=JDCT_ISLOW;
2187 option=GetImageOption(image_info,"jpeg:optimize-coding");
2188 if (option != (const char *) NULL)
2189 jpeg_info.optimize_coding=IsStringTrue(option);
2195 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2196 image->rows*sizeof(JSAMPLE);
2197 if (length == (MagickSizeType) ((size_t) length))
2200 Perform optimization only if available memory resources permit it.
2202 status=AcquireMagickResource(MemoryResource,length);
2203 RelinquishMagickResource(MemoryResource,length);
2204 jpeg_info.optimize_coding=status;
2207 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2208 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2209 (image_info->interlace != NoInterlace))
2211 if (image->debug != MagickFalse)
2212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2213 "Interlace: progressive");
2214 jpeg_simple_progression(&jpeg_info);
2217 if (image->debug != MagickFalse)
2218 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2219 "Interlace: non-progressive");
2221 if (image->debug != MagickFalse)
2222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2223 "Interlace: nonprogressive");
2225 option=GetImageOption(image_info,"jpeg:extent");
2226 if (option != (const char *) NULL)
2234 jpeg_info=CloneImageInfo(image_info);
2235 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2236 if (jpeg_image != (Image *) NULL)
2246 Search for compression quality that does not exceed image extent.
2248 jpeg_info->quality=0;
2249 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2250 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2251 (void) AcquireUniqueFilename(jpeg_image->filename);
2253 for (minimum=0; minimum != maximum; )
2255 jpeg_image->quality=minimum+(maximum-minimum)/2;
2256 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2257 if (GetBlobSize(jpeg_image) <= extent)
2258 minimum=jpeg_image->quality+1;
2260 maximum=jpeg_image->quality-1;
2262 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2263 image->quality=minimum-1;
2264 jpeg_image=DestroyImage(jpeg_image);
2266 jpeg_info=DestroyImageInfo(jpeg_info);
2269 if ((image_info->compression != LosslessJPEGCompression) &&
2270 (image->quality <= 100))
2272 if (image->quality != UndefinedCompressionQuality)
2273 quality=(int) image->quality;
2274 if (image->debug != MagickFalse)
2275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2276 (double) image->quality);
2280 #if !defined(C_LOSSLESS_SUPPORTED)
2282 if (image->debug != MagickFalse)
2283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2285 if (image->quality < 100)
2286 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2287 "LosslessToLossyJPEGConversion",image->filename);
2294 predictor=image->quality/100; /* range 1-7 */
2295 point_transform=image->quality % 20; /* range 0-15 */
2296 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2297 if (image->debug != MagickFalse)
2299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2300 "Compression: lossless");
2301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2302 "Predictor: %d",predictor);
2303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2304 "Point Transform: %d",point_transform);
2309 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2310 #if (JPEG_LIB_VERSION >= 70)
2311 option=GetImageOption(image_info,"quality");
2312 if (option != (const char *) NULL)
2321 Set quality scaling for luminance and chrominance separately.
2323 flags=ParseGeometry(option,&geometry_info);
2324 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2326 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2327 (geometry_info.rho+0.5));
2328 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2329 (geometry_info.sigma+0.5));
2330 jpeg_default_qtables(&jpeg_info,MagickTrue);
2334 sampling_factor=(const char *) NULL;
2335 value=GetImageOption(image_info,"jpeg:sampling-factor");
2336 if (value == (char *) NULL)
2337 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2338 if (value != (char *) NULL)
2340 sampling_factor=value;
2341 if (image->debug != MagickFalse)
2342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2343 " Input sampling-factors=%s",sampling_factor);
2345 if (image_info->sampling_factor != (char *) NULL)
2346 sampling_factor=image_info->sampling_factor;
2347 if (sampling_factor == (const char *) NULL)
2349 if (image->quality >= 90)
2350 for (i=0; i < MAX_COMPONENTS; i++)
2352 jpeg_info.comp_info[i].h_samp_factor=1;
2353 jpeg_info.comp_info[i].v_samp_factor=1;
2368 Set sampling factor.
2371 factors=SamplingFactorToList(sampling_factor);
2372 if (factors != (char **) NULL)
2374 for (i=0; i < MAX_COMPONENTS; i++)
2376 if (factors[i] == (char *) NULL)
2378 flags=ParseGeometry(factors[i],&geometry_info);
2379 if ((flags & SigmaValue) == 0)
2380 geometry_info.sigma=geometry_info.rho;
2381 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2382 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2383 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2385 factors=(char **) RelinquishMagickMemory(factors);
2387 for ( ; i < MAX_COMPONENTS; i++)
2389 jpeg_info.comp_info[i].h_samp_factor=1;
2390 jpeg_info.comp_info[i].v_samp_factor=1;
2393 if (jpeg_info.input_components == 1)
2394 for (i=0; i < MAX_COMPONENTS; i++)
2396 jpeg_info.comp_info[i].h_samp_factor=1;
2397 jpeg_info.comp_info[i].v_samp_factor=1;
2399 option=GetImageOption(image_info,"jpeg:q-table");
2400 if (option != (const char *) NULL)
2406 Custom quantization tables.
2408 table=GetQuantizationTable(option,"0",exception);
2409 if (table != (QuantizationTable *) NULL)
2411 jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2413 table=DestroyQuantizationTable(table);
2415 table=GetQuantizationTable(option,"1",exception);
2416 if (table != (QuantizationTable *) NULL)
2418 jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2420 table=DestroyQuantizationTable(table);
2422 table=GetQuantizationTable(option,"2",exception);
2423 if (table != (QuantizationTable *) NULL)
2425 jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2427 table=DestroyQuantizationTable(table);
2429 table=GetQuantizationTable(option,"3",exception);
2430 if (table != (QuantizationTable *) NULL)
2432 jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2434 table=DestroyQuantizationTable(table);
2437 jpeg_start_compress(&jpeg_info,MagickTrue);
2438 if (image->debug != MagickFalse)
2440 if (image->storage_class == PseudoClass)
2441 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2442 "Storage class: PseudoClass");
2444 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2445 "Storage class: DirectClass");
2446 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2447 (double) image->depth);
2448 if (image->colors != 0)
2449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2450 "Number of colors: %.20g",(double) image->colors);
2452 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2453 "Number of colors: unspecified");
2454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2455 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2456 switch (image->colorspace)
2458 case CMYKColorspace:
2460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2461 "Storage class: DirectClass");
2462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2463 "Colorspace: CMYK");
2466 case YCbCrColorspace:
2467 case Rec601YCbCrColorspace:
2468 case Rec709YCbCrColorspace:
2470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2471 "Colorspace: YCbCr");
2477 switch (image->colorspace)
2479 case CMYKColorspace:
2481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2482 "Colorspace: CMYK");
2483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2484 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2485 jpeg_info.comp_info[0].h_samp_factor,
2486 jpeg_info.comp_info[0].v_samp_factor,
2487 jpeg_info.comp_info[1].h_samp_factor,
2488 jpeg_info.comp_info[1].v_samp_factor,
2489 jpeg_info.comp_info[2].h_samp_factor,
2490 jpeg_info.comp_info[2].v_samp_factor,
2491 jpeg_info.comp_info[3].h_samp_factor,
2492 jpeg_info.comp_info[3].v_samp_factor);
2495 case GRAYColorspace:
2496 case Rec601LumaColorspace:
2497 case Rec709LumaColorspace:
2499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2500 "Colorspace: GRAY");
2501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2502 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2503 jpeg_info.comp_info[0].v_samp_factor);
2508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2509 "Image colorspace is RGB");
2510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2511 "Sampling factors: %dx%d,%dx%d,%dx%d",
2512 jpeg_info.comp_info[0].h_samp_factor,
2513 jpeg_info.comp_info[0].v_samp_factor,
2514 jpeg_info.comp_info[1].h_samp_factor,
2515 jpeg_info.comp_info[1].v_samp_factor,
2516 jpeg_info.comp_info[2].h_samp_factor,
2517 jpeg_info.comp_info[2].v_samp_factor);
2520 case YCbCrColorspace:
2521 case Rec601YCbCrColorspace:
2522 case Rec709YCbCrColorspace:
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525 "Colorspace: YCbCr");
2526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2527 "Sampling factors: %dx%d,%dx%d,%dx%d",
2528 jpeg_info.comp_info[0].h_samp_factor,
2529 jpeg_info.comp_info[0].v_samp_factor,
2530 jpeg_info.comp_info[1].h_samp_factor,
2531 jpeg_info.comp_info[1].v_samp_factor,
2532 jpeg_info.comp_info[2].h_samp_factor,
2533 jpeg_info.comp_info[2].v_samp_factor);
2538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2541 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2542 jpeg_info.comp_info[0].h_samp_factor,
2543 jpeg_info.comp_info[0].v_samp_factor,
2544 jpeg_info.comp_info[1].h_samp_factor,
2545 jpeg_info.comp_info[1].v_samp_factor,
2546 jpeg_info.comp_info[2].h_samp_factor,
2547 jpeg_info.comp_info[2].v_samp_factor,
2548 jpeg_info.comp_info[3].h_samp_factor,
2549 jpeg_info.comp_info[3].v_samp_factor);
2555 Write JPEG profiles.
2557 value=GetImageProperty(image,"comment",exception);
2558 if (value != (char *) NULL)
2559 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2560 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2561 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2562 if (image->profiles != (void *) NULL)
2563 WriteProfile(&jpeg_info,image);
2565 Convert MIFF to JPEG raster pixels.
2567 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2568 jpeg_info.input_components*sizeof(*jpeg_pixels));
2569 if (jpeg_pixels == (JSAMPLE *) NULL)
2570 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2571 if (setjmp(error_manager.error_recovery) != 0)
2573 jpeg_destroy_compress(&jpeg_info);
2574 if (jpeg_pixels != (JSAMPLE *) NULL)
2575 jpeg_pixels=(JSAMPLE *) RelinquishMagickMemory(jpeg_pixels);
2576 (void) CloseBlob(image);
2577 return(MagickFalse);
2579 scanline[0]=(JSAMPROW) jpeg_pixels;
2580 if (jpeg_info.data_precision <= 8)
2582 if ((jpeg_info.in_color_space == JCS_RGB) ||
2583 (jpeg_info.in_color_space == JCS_YCbCr))
2584 for (y=0; y < (ssize_t) image->rows; y++)
2586 register const Quantum
2592 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2593 if (p == (const Quantum *) NULL)
2596 for (x=0; x < (ssize_t) image->columns; x++)
2598 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2599 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2600 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2601 p+=GetPixelChannels(image);
2603 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2604 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2606 if (status == MagickFalse)
2610 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2611 for (y=0; y < (ssize_t) image->rows; y++)
2613 register const Quantum
2619 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2620 if (p == (const Quantum *) NULL)
2623 for (x=0; x < (ssize_t) image->columns; x++)
2625 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2626 p+=GetPixelChannels(image);
2628 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2629 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2631 if (status == MagickFalse)
2635 for (y=0; y < (ssize_t) image->rows; y++)
2637 register const Quantum
2643 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2644 if (p == (const Quantum *) NULL)
2647 for (x=0; x < (ssize_t) image->columns; x++)
2650 Convert DirectClass packets to contiguous CMYK scanlines.
2652 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2653 GetPixelCyan(image,p))));
2654 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2655 GetPixelMagenta(image,p))));
2656 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2657 GetPixelYellow(image,p))));
2658 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2659 GetPixelBlack(image,p))));
2660 p+=GetPixelChannels(image);
2662 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2663 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2665 if (status == MagickFalse)
2670 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2671 for (y=0; y < (ssize_t) image->rows; y++)
2673 register const Quantum
2679 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2680 if (p == (const Quantum *) NULL)
2683 for (x=0; x < (ssize_t) image->columns; x++)
2685 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >> 4);
2686 p+=GetPixelChannels(image);
2688 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2689 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2691 if (status == MagickFalse)
2695 if ((jpeg_info.in_color_space == JCS_RGB) ||
2696 (jpeg_info.in_color_space == JCS_YCbCr))
2697 for (y=0; y < (ssize_t) image->rows; y++)
2699 register const Quantum
2705 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2706 if (p == (const Quantum *) NULL)
2709 for (x=0; x < (ssize_t) image->columns; x++)
2711 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2712 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2713 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2714 p+=GetPixelChannels(image);
2716 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2717 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2719 if (status == MagickFalse)
2723 for (y=0; y < (ssize_t) image->rows; y++)
2725 register const Quantum
2731 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2732 if (p == (const Quantum *) NULL)
2735 for (x=0; x < (ssize_t) image->columns; x++)
2738 Convert DirectClass packets to contiguous CMYK scanlines.
2740 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2741 GetPixelRed(image,p)) >> 4));
2742 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2743 GetPixelGreen(image,p)) >> 4));
2744 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2745 GetPixelBlue(image,p)) >> 4));
2746 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2747 GetPixelBlack(image,p)) >> 4));
2748 p+=GetPixelChannels(image);
2750 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2751 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2753 if (status == MagickFalse)
2756 if (y == (ssize_t) image->rows)
2757 jpeg_finish_compress(&jpeg_info);
2759 Relinquish resources.
2761 jpeg_destroy_compress(&jpeg_info);
2762 jpeg_pixels=(JSAMPLE *) RelinquishMagickMemory(jpeg_pixels);
2763 (void) CloseBlob(image);