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)
421 (void) ThrowMagickException(exception,GetMagickModule(),
422 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
428 error_manager->profile=comment;
429 p=GetStringInfoDatum(comment);
430 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
431 *p++=(unsigned char) GetCharacter(jpeg_info);
433 error_manager->profile=NULL;
434 p=GetStringInfoDatum(comment);
435 (void) SetImageProperty(image,"comment",(const char *) p,exception);
436 comment=DestroyStringInfo(comment);
440 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
460 register unsigned char
473 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
474 length+=(size_t) GetCharacter(jpeg_info);
479 (void) GetCharacter(jpeg_info);
482 for (i=0; i < 12; i++)
483 magick[i]=(char) GetCharacter(jpeg_info);
484 if (LocaleCompare(magick,ICC_PROFILE) != 0)
487 Not a ICC profile, return.
489 for (i=0; i < (ssize_t) (length-12); i++)
490 (void) GetCharacter(jpeg_info);
493 (void) GetCharacter(jpeg_info); /* id */
494 (void) GetCharacter(jpeg_info); /* markers */
496 error_manager=(ErrorManager *) jpeg_info->client_data;
497 exception=error_manager->exception;
498 image=error_manager->image;
499 profile=BlobToStringInfo((const void *) NULL,length);
500 if (profile == (StringInfo *) NULL)
502 (void) ThrowMagickException(exception,GetMagickModule(),
503 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
506 error_manager->profile=profile;
507 p=GetStringInfoDatum(profile);
508 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
509 *p++=(unsigned char) GetCharacter(jpeg_info);
510 error_manager->profile=NULL;
511 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
512 if (icc_profile != (StringInfo *) NULL)
514 ConcatenateStringInfo(icc_profile,profile);
515 profile=DestroyStringInfo(profile);
519 status=SetImageProfile(image,"icc",profile,exception);
520 profile=DestroyStringInfo(profile);
521 if (status == MagickFalse)
522 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
525 if (image->debug != MagickFalse)
526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
527 "Profile: ICC, %.20g bytes",(double) length);
531 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
534 magick[MaxTextExtent];
551 register unsigned char
562 Determine length of binary data stored here.
564 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
565 length+=(size_t) GetCharacter(jpeg_info);
570 (void) GetCharacter(jpeg_info);
574 Validate that this was written as a Photoshop resource format slug.
576 for (i=0; i < 10; i++)
577 magick[i]=(char) GetCharacter(jpeg_info);
582 if (LocaleCompare(magick,"Photoshop ") != 0)
585 Not a IPTC profile, return.
587 for (i=0; i < (ssize_t) length; i++)
588 (void) GetCharacter(jpeg_info);
592 Remove the version number.
594 for (i=0; i < 4; i++)
595 (void) GetCharacter(jpeg_info);
601 error_manager=(ErrorManager *) jpeg_info->client_data;
602 exception=error_manager->exception;
603 image=error_manager->image;
604 profile=BlobToStringInfo((const void *) NULL,length);
605 if (profile == (StringInfo *) NULL)
607 (void) ThrowMagickException(exception,GetMagickModule(),
608 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
611 error_manager->profile=profile;
612 p=GetStringInfoDatum(profile);
613 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
614 *p++=(unsigned char) GetCharacter(jpeg_info);
615 error_manager->profile=NULL;
616 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
617 if (iptc_profile != (StringInfo *) NULL)
619 ConcatenateStringInfo(iptc_profile,profile);
620 profile=DestroyStringInfo(profile);
624 status=SetImageProfile(image,"8bim",profile,exception);
625 profile=DestroyStringInfo(profile);
626 if (status == MagickFalse)
627 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
630 if (image->debug != MagickFalse)
631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
632 "Profile: iptc, %.20g bytes",(double) length);
636 static boolean ReadProfile(j_decompress_ptr jpeg_info)
662 register unsigned char
672 Read generic profile.
674 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
675 length+=(size_t) GetCharacter(jpeg_info);
679 marker=jpeg_info->unread_marker-JPEG_APP0;
680 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
681 error_manager=(ErrorManager *) jpeg_info->client_data;
682 exception=error_manager->exception;
683 image=error_manager->image;
684 profile=BlobToStringInfo((const void *) NULL,length);
685 if (profile == (StringInfo *) NULL)
687 (void) ThrowMagickException(exception,GetMagickModule(),
688 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
691 error_manager->profile=profile;
692 p=GetStringInfoDatum(profile);
693 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
694 *p++=(unsigned char) GetCharacter(jpeg_info);
695 error_manager->profile=NULL;
698 p=GetStringInfoDatum(profile);
699 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
700 (void) CopyMagickString(name,"exif",MaxTextExtent);
701 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
707 Extract namespace from XMP profile.
709 p=GetStringInfoDatum(profile);
710 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
716 if (j < (ssize_t) GetStringInfoLength(profile))
717 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
718 (void) CopyMagickString(name,"xmp",MaxTextExtent);
721 previous_profile=GetImageProfile(image,name);
722 if (previous_profile != (const StringInfo *) NULL)
727 length=GetStringInfoLength(profile);
728 SetStringInfoLength(profile,GetStringInfoLength(profile)+
729 GetStringInfoLength(previous_profile));
730 (void) memmove(GetStringInfoDatum(profile)+
731 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
733 (void) memcpy(GetStringInfoDatum(profile),
734 GetStringInfoDatum(previous_profile),
735 GetStringInfoLength(previous_profile));
737 status=SetImageProfile(image,name,profile,exception);
738 profile=DestroyStringInfo(profile);
739 if (status == MagickFalse)
741 (void) ThrowMagickException(exception,GetMagickModule(),
742 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
745 if (image->debug != MagickFalse)
746 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
747 "Profile: %s, %.20g bytes",name,(double) length);
751 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
756 if (number_bytes <= 0)
758 source=(SourceManager *) cinfo->src;
759 while (number_bytes > (long) source->manager.bytes_in_buffer)
761 number_bytes-=(long) source->manager.bytes_in_buffer;
762 (void) FillInputBuffer(cinfo);
764 source->manager.next_input_byte+=number_bytes;
765 source->manager.bytes_in_buffer-=number_bytes;
768 static void TerminateSource(j_decompress_ptr cinfo)
773 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
778 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
779 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
780 source=(SourceManager *) cinfo->src;
781 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
782 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
783 source=(SourceManager *) cinfo->src;
784 source->manager.init_source=InitializeSource;
785 source->manager.fill_input_buffer=FillInputBuffer;
786 source->manager.skip_input_data=SkipInputData;
787 source->manager.resync_to_restart=jpeg_resync_to_restart;
788 source->manager.term_source=TerminateSource;
789 source->manager.bytes_in_buffer=0;
790 source->manager.next_input_byte=NULL;
794 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
795 Image *image, ExceptionInfo *exception)
797 image->quality=UndefinedCompressionQuality;
798 #if defined(D_PROGRESSIVE_SUPPORTED)
799 if (image->compression == LosslessJPEGCompression)
802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
803 "Quality: 100 (lossless)");
817 Determine the JPEG compression quality from the quantization tables.
820 for (i=0; i < NUM_QUANT_TBLS; i++)
822 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
823 for (j=0; j < DCTSIZE2; j++)
824 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
826 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
827 (jpeg_info->quant_tbl_ptrs[1] != NULL))
832 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
833 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
834 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
835 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
836 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
837 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
838 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
839 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
840 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
841 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
846 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
847 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
848 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
849 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
850 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
851 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
852 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
853 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
854 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
855 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
856 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
860 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
861 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
862 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
863 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
864 for (i=0; i < 100; i++)
866 if ((qvalue < hash[i]) && (sum < sums[i]))
868 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
869 image->quality=(size_t) i+1;
870 if (image->debug != MagickFalse)
871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
872 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
873 (sum <= sums[i]) ? "exact" : "approximate");
878 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
883 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
884 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
885 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
886 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
887 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
888 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
889 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
890 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
891 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
892 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
897 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
898 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
899 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
900 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
901 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
902 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
903 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
904 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
905 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
906 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
907 667, 592, 518, 441, 369, 292, 221, 151, 86,
911 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
912 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
913 for (i=0; i < 100; i++)
915 if ((qvalue < hash[i]) && (sum < sums[i]))
917 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
918 image->quality=(size_t)i+1;
919 if (image->debug != MagickFalse)
920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
921 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
922 (sum <= sums[i]) ? "exact" : "approximate");
929 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
932 sampling_factor[MaxTextExtent];
934 switch (jpeg_info->out_color_space)
938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
939 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
940 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
941 jpeg_info->comp_info[0].v_samp_factor,
942 jpeg_info->comp_info[1].h_samp_factor,
943 jpeg_info->comp_info[1].v_samp_factor,
944 jpeg_info->comp_info[2].h_samp_factor,
945 jpeg_info->comp_info[2].v_samp_factor,
946 jpeg_info->comp_info[3].h_samp_factor,
947 jpeg_info->comp_info[3].v_samp_factor);
952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
953 "Colorspace: GRAYSCALE");
954 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
955 jpeg_info->comp_info[0].h_samp_factor,
956 jpeg_info->comp_info[0].v_samp_factor);
961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
962 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
963 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
964 jpeg_info->comp_info[0].v_samp_factor,
965 jpeg_info->comp_info[1].h_samp_factor,
966 jpeg_info->comp_info[1].v_samp_factor,
967 jpeg_info->comp_info[2].h_samp_factor,
968 jpeg_info->comp_info[2].v_samp_factor);
973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
974 jpeg_info->out_color_space);
975 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
976 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
977 jpeg_info->comp_info[0].v_samp_factor,
978 jpeg_info->comp_info[1].h_samp_factor,
979 jpeg_info->comp_info[1].v_samp_factor,
980 jpeg_info->comp_info[2].h_samp_factor,
981 jpeg_info->comp_info[2].v_samp_factor,
982 jpeg_info->comp_info[3].h_samp_factor,
983 jpeg_info->comp_info[3].v_samp_factor);
987 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
993 static Image *ReadJPEGImage(const ImageInfo *image_info,
994 ExceptionInfo *exception)
997 value[MaxTextExtent];
1009 *volatile jpeg_pixels;
1030 struct jpeg_decompress_struct
1033 struct jpeg_error_mgr
1048 assert(image_info != (const ImageInfo *) NULL);
1049 assert(image_info->signature == MagickSignature);
1050 if (image_info->debug != MagickFalse)
1051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1052 image_info->filename);
1053 assert(exception != (ExceptionInfo *) NULL);
1054 assert(exception->signature == MagickSignature);
1055 debug=IsEventLogging();
1057 image=AcquireImage(image_info,exception);
1058 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1059 if (status == MagickFalse)
1061 image=DestroyImageList(image);
1062 return((Image *) NULL);
1065 Initialize JPEG parameters.
1067 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1068 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1069 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1070 jpeg_info.err=jpeg_std_error(&jpeg_error);
1071 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1072 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1073 memory_info=(MemoryInfo *) NULL;
1074 error_manager.exception=exception;
1075 error_manager.image=image;
1076 if (setjmp(error_manager.error_recovery) != 0)
1078 jpeg_destroy_decompress(&jpeg_info);
1079 if (error_manager.profile != (StringInfo *) NULL)
1080 error_manager.profile=DestroyStringInfo(error_manager.profile);
1081 (void) CloseBlob(image);
1082 number_pixels=(MagickSizeType) image->columns*image->rows;
1083 if (number_pixels != 0)
1084 return(GetFirstImageInList(image));
1085 return(DestroyImage(image));
1087 jpeg_info.client_data=(void *) &error_manager;
1088 jpeg_create_decompress(&jpeg_info);
1089 JPEGSourceManager(&jpeg_info,image);
1090 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1091 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1092 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1093 for (i=1; i < 16; i++)
1094 if ((i != 2) && (i != 13) && (i != 14))
1095 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1096 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1097 if ((image_info->colorspace == YCbCrColorspace) ||
1098 (image_info->colorspace == Rec601YCbCrColorspace) ||
1099 (image_info->colorspace == Rec709YCbCrColorspace))
1100 jpeg_info.out_color_space=JCS_YCbCr;
1102 Set image resolution.
1105 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1106 (jpeg_info.Y_density != 1))
1108 image->resolution.x=(double) jpeg_info.X_density;
1109 image->resolution.y=(double) jpeg_info.Y_density;
1110 units=(size_t) jpeg_info.density_unit;
1113 image->units=PixelsPerInchResolution;
1115 image->units=PixelsPerCentimeterResolution;
1116 number_pixels=(MagickSizeType) image->columns*image->rows;
1117 option=GetImageOption(image_info,"jpeg:size");
1118 if (option != (const char *) NULL)
1132 flags=ParseGeometry(option,&geometry_info);
1133 if ((flags & SigmaValue) == 0)
1134 geometry_info.sigma=geometry_info.rho;
1135 jpeg_calc_output_dimensions(&jpeg_info);
1136 image->magick_columns=jpeg_info.output_width;
1137 image->magick_rows=jpeg_info.output_height;
1139 if (geometry_info.rho != 0.0)
1140 scale_factor=jpeg_info.output_width/geometry_info.rho;
1141 if ((geometry_info.sigma != 0.0) &&
1142 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1143 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1144 jpeg_info.scale_num=1U;
1145 jpeg_info.scale_denom=(unsigned int) scale_factor;
1146 jpeg_calc_output_dimensions(&jpeg_info);
1147 if (image->debug != MagickFalse)
1148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1149 "Scale factor: %.20g",(double) scale_factor);
1151 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1152 #if defined(D_LOSSLESS_SUPPORTED)
1153 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1154 JPEGInterlace : NoInterlace;
1155 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1156 LosslessJPEGCompression : JPEGCompression;
1157 if (jpeg_info.data_precision > 8)
1158 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1159 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1161 if (jpeg_info.data_precision == 16)
1162 jpeg_info.data_precision=12;
1164 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1166 image->compression=JPEGCompression;
1169 image->compression=JPEGCompression;
1170 image->interlace=JPEGInterlace;
1172 option=GetImageOption(image_info,"jpeg:colors");
1173 if (option != (const char *) NULL)
1176 Let the JPEG library quantize the image.
1178 jpeg_info.quantize_colors=TRUE;
1179 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1181 option=GetImageOption(image_info,"jpeg:block-smoothing");
1182 if (option != (const char *) NULL)
1183 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1185 jpeg_info.dct_method=JDCT_FLOAT;
1186 option=GetImageOption(image_info,"jpeg:dct-method");
1187 if (option != (const char *) NULL)
1193 if (LocaleCompare(option,"default") == 0)
1194 jpeg_info.dct_method=JDCT_DEFAULT;
1200 if (LocaleCompare(option,"fastest") == 0)
1201 jpeg_info.dct_method=JDCT_FASTEST;
1202 if (LocaleCompare(option,"float") == 0)
1203 jpeg_info.dct_method=JDCT_FLOAT;
1209 if (LocaleCompare(option,"ifast") == 0)
1210 jpeg_info.dct_method=JDCT_IFAST;
1211 if (LocaleCompare(option,"islow") == 0)
1212 jpeg_info.dct_method=JDCT_ISLOW;
1216 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1217 if (option != (const char *) NULL)
1218 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1220 (void) jpeg_start_decompress(&jpeg_info);
1221 image->columns=jpeg_info.output_width;
1222 image->rows=jpeg_info.output_height;
1223 image->depth=(size_t) jpeg_info.data_precision;
1224 switch (jpeg_info.out_color_space)
1229 (void) SetImageColorspace(image,sRGBColorspace,exception);
1234 (void) SetImageColorspace(image,GRAYColorspace,exception);
1239 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1244 (void) SetImageColorspace(image,CMYKColorspace,exception);
1248 if (IsITUFaxImage(image) != MagickFalse)
1250 (void) SetImageColorspace(image,LabColorspace,exception);
1251 jpeg_info.out_color_space=JCS_YCbCr;
1253 option=GetImageOption(image_info,"jpeg:colors");
1254 if (option != (const char *) NULL)
1255 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1257 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1258 if ((jpeg_info.output_components == 1) &&
1259 (jpeg_info.quantize_colors == MagickFalse))
1264 colors=(size_t) GetQuantumRange(image->depth)+1;
1265 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1266 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1268 if (image->debug != MagickFalse)
1270 if (image->interlace != NoInterlace)
1271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1272 "Interlace: progressive");
1274 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1275 "Interlace: nonprogressive");
1276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1277 (int) jpeg_info.data_precision);
1278 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1279 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1281 JPEGSetImageQuality(&jpeg_info,image,exception);
1282 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1283 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1284 jpeg_info.out_color_space);
1285 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1286 if (image_info->ping != MagickFalse)
1288 jpeg_destroy_decompress(&jpeg_info);
1289 (void) CloseBlob(image);
1290 return(GetFirstImageInList(image));
1292 memory_info=AcquireVirtualMemory((size_t) image->columns,
1293 jpeg_info.output_components*sizeof(*jpeg_pixels));
1294 if (memory_info == (MemoryInfo *) NULL)
1296 jpeg_destroy_decompress(&jpeg_info);
1297 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1299 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1301 Convert JPEG pixels to pixel packets.
1303 if (setjmp(error_manager.error_recovery) != 0)
1305 if (memory_info != (MemoryInfo *) NULL)
1306 memory_info=RelinquishVirtualMemory(memory_info);
1307 jpeg_destroy_decompress(&jpeg_info);
1308 (void) CloseBlob(image);
1309 number_pixels=(MagickSizeType) image->columns*image->rows;
1310 if (number_pixels != 0)
1311 return(GetFirstImageInList(image));
1312 return(DestroyImage(image));
1314 if (jpeg_info.quantize_colors != MagickFalse)
1316 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1317 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1318 for (i=0; i < (ssize_t) image->colors; i++)
1320 image->colormap[i].red=(double) ScaleCharToQuantum(
1321 jpeg_info.colormap[0][i]);
1322 image->colormap[i].green=image->colormap[i].red;
1323 image->colormap[i].blue=image->colormap[i].red;
1324 image->colormap[i].alpha=OpaqueAlpha;
1327 for (i=0; i < (ssize_t) image->colors; i++)
1329 image->colormap[i].red=(double) ScaleCharToQuantum(
1330 jpeg_info.colormap[0][i]);
1331 image->colormap[i].green=(double) ScaleCharToQuantum(
1332 jpeg_info.colormap[1][i]);
1333 image->colormap[i].blue=(double) ScaleCharToQuantum(
1334 jpeg_info.colormap[2][i]);
1335 image->colormap[i].alpha=OpaqueAlpha;
1338 scanline[0]=(JSAMPROW) jpeg_pixels;
1339 for (y=0; y < (ssize_t) image->rows; y++)
1347 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1349 (void) ThrowMagickException(exception,GetMagickModule(),
1350 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1354 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1355 if (q == (Quantum *) NULL)
1357 if (jpeg_info.data_precision > 8)
1362 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1363 if (jpeg_info.output_components == 1)
1364 for (x=0; x < (ssize_t) image->columns; x++)
1369 pixel=(size_t) (scale*GETJSAMPLE(*p));
1370 index=ConstrainColormapIndex(image,pixel,exception);
1371 SetPixelIndex(image,index,q);
1372 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1374 q+=GetPixelChannels(image);
1377 if (image->colorspace != CMYKColorspace)
1378 for (x=0; x < (ssize_t) image->columns; x++)
1380 SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1382 SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1384 SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
1386 SetPixelAlpha(image,OpaqueAlpha,q);
1387 q+=GetPixelChannels(image);
1390 for (x=0; x < (ssize_t) image->columns; x++)
1392 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(scale*
1393 GETJSAMPLE(*p++)),q);
1394 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(scale*
1395 GETJSAMPLE(*p++)),q);
1396 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(scale*
1397 GETJSAMPLE(*p++)),q);
1398 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(scale*
1399 GETJSAMPLE(*p++)),q);
1400 SetPixelAlpha(image,OpaqueAlpha,q);
1401 q+=GetPixelChannels(image);
1405 if (jpeg_info.output_components == 1)
1406 for (x=0; x < (ssize_t) image->columns; x++)
1408 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1409 SetPixelIndex(image,index,q);
1410 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1412 q+=GetPixelChannels(image);
1415 if (image->colorspace != CMYKColorspace)
1416 for (x=0; x < (ssize_t) image->columns; x++)
1418 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1419 GETJSAMPLE(*p++)),q);
1420 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1421 GETJSAMPLE(*p++)),q);
1422 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1423 GETJSAMPLE(*p++)),q);
1424 SetPixelAlpha(image,OpaqueAlpha,q);
1425 q+=GetPixelChannels(image);
1428 for (x=0; x < (ssize_t) image->columns; x++)
1430 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1431 (unsigned char) GETJSAMPLE(*p++)),q);
1432 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1433 (unsigned char) GETJSAMPLE(*p++)),q);
1434 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1435 (unsigned char) GETJSAMPLE(*p++)),q);
1436 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1437 (unsigned char) GETJSAMPLE(*p++)),q);
1438 SetPixelAlpha(image,OpaqueAlpha,q);
1439 q+=GetPixelChannels(image);
1441 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1443 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1445 if (status == MagickFalse)
1447 jpeg_abort_decompress(&jpeg_info);
1451 if (status != MagickFalse)
1453 error_manager.finished=MagickTrue;
1454 if (setjmp(error_manager.error_recovery) == 0)
1455 (void) jpeg_finish_decompress(&jpeg_info);
1458 Free jpeg resources.
1460 jpeg_destroy_decompress(&jpeg_info);
1461 memory_info=RelinquishVirtualMemory(memory_info);
1462 (void) CloseBlob(image);
1463 return(GetFirstImageInList(image));
1469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473 % R e g i s t e r J P E G I m a g e %
1477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1479 % RegisterJPEGImage() adds properties for the JPEG image format to
1480 % the list of supported formats. The properties include the image format
1481 % tag, a method to read and/or write the format, whether the format
1482 % supports the saving of more than one frame to the same file or blob,
1483 % whether the format supports native in-memory I/O, and a brief
1484 % description of the format.
1486 % The format of the RegisterJPEGImage method is:
1488 % size_t RegisterJPEGImage(void)
1491 ModuleExport size_t RegisterJPEGImage(void)
1494 version[MaxTextExtent];
1500 description[] = "Joint Photographic Experts Group JFIF format";
1503 #if defined(JPEG_LIB_VERSION)
1504 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1506 entry=SetMagickInfo("JPEG");
1507 entry->thread_support=NoThreadSupport;
1508 #if defined(MAGICKCORE_JPEG_DELEGATE)
1509 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1510 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1512 entry->magick=(IsImageFormatHandler *) IsJPEG;
1513 entry->adjoin=MagickFalse;
1514 entry->description=ConstantString(description);
1515 if (*version != '\0')
1516 entry->version=ConstantString(version);
1517 entry->mime_type=ConstantString("image/jpeg");
1518 entry->module=ConstantString("JPEG");
1519 (void) RegisterMagickInfo(entry);
1520 entry=SetMagickInfo("JPG");
1521 entry->thread_support=NoThreadSupport;
1522 #if defined(MAGICKCORE_JPEG_DELEGATE)
1523 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1524 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1526 entry->adjoin=MagickFalse;
1527 entry->description=ConstantString(description);
1528 if (*version != '\0')
1529 entry->version=ConstantString(version);
1530 entry->mime_type=ConstantString("image/jpeg");
1531 entry->module=ConstantString("JPEG");
1532 (void) RegisterMagickInfo(entry);
1533 entry=SetMagickInfo("PJPEG");
1534 entry->thread_support=NoThreadSupport;
1535 #if defined(MAGICKCORE_JPEG_DELEGATE)
1536 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1537 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1539 entry->adjoin=MagickFalse;
1540 entry->description=ConstantString(description);
1541 if (*version != '\0')
1542 entry->version=ConstantString(version);
1543 entry->mime_type=ConstantString("image/jpeg");
1544 entry->module=ConstantString("JPEG");
1545 (void) RegisterMagickInfo(entry);
1546 return(MagickImageCoderSignature);
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 % U n r e g i s t e r J P E G I m a g e %
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1561 % UnregisterJPEGImage() removes format registrations made by the
1562 % JPEG module from the list of supported formats.
1564 % The format of the UnregisterJPEGImage method is:
1566 % UnregisterJPEGImage(void)
1569 ModuleExport void UnregisterJPEGImage(void)
1571 (void) UnregisterMagickInfo("PJPG");
1572 (void) UnregisterMagickInfo("JPEG");
1573 (void) UnregisterMagickInfo("JPG");
1577 #if defined(MAGICKCORE_JPEG_DELEGATE)
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 % W r i t e J P E G I m a g e %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % WriteJPEGImage() writes a JPEG image file and returns it. It
1590 % allocates the memory necessary for the new Image structure and returns a
1591 % pointer to the new image.
1593 % The format of the WriteJPEGImage method is:
1595 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1596 % Image *image,ExceptionInfo *exception)
1598 % A description of each parameter follows:
1600 % o image_info: the image info.
1602 % o jpeg_image: The image.
1604 % o exception: return any errors or warnings in this structure.
1608 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1610 assert(table != (QuantizationTable *) NULL);
1611 if (table->slot != (char *) NULL)
1612 table->slot=DestroyString(table->slot);
1613 if (table->description != (char *) NULL)
1614 table->description=DestroyString(table->description);
1615 if (table->levels != (unsigned int *) NULL)
1616 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1617 table=(QuantizationTable *) RelinquishMagickMemory(table);
1621 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1626 destination=(DestinationManager *) cinfo->dest;
1627 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1628 MaxBufferExtent,destination->buffer);
1629 if (destination->manager.free_in_buffer != MaxBufferExtent)
1630 ERREXIT(cinfo,JERR_FILE_WRITE);
1631 destination->manager.next_output_byte=destination->buffer;
1635 static QuantizationTable *GetQuantizationTable(const char *filename,
1636 const char *slot,ExceptionInfo *exception)
1664 *quantization_tables,
1667 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1668 "Loading quantization tables \"%s\" ...",filename);
1669 table=(QuantizationTable *) NULL;
1670 xml=FileToString(filename,~0UL,exception);
1671 if (xml == (char *) NULL)
1673 quantization_tables=NewXMLTree(xml,exception);
1674 if (quantization_tables == (XMLTreeInfo *) NULL)
1676 xml=DestroyString(xml);
1679 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1680 table_iterator != (XMLTreeInfo *) NULL;
1681 table_iterator=GetNextXMLTreeTag(table_iterator))
1683 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1684 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1686 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1687 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1690 if (table_iterator == (XMLTreeInfo *) NULL)
1692 xml=DestroyString(xml);
1695 description=GetXMLTreeChild(table_iterator,"description");
1696 if (description == (XMLTreeInfo *) NULL)
1698 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1699 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1700 quantization_tables=DestroyXMLTree(quantization_tables);
1701 xml=DestroyString(xml);
1704 levels=GetXMLTreeChild(table_iterator,"levels");
1705 if (levels == (XMLTreeInfo *) NULL)
1707 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1708 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1709 quantization_tables=DestroyXMLTree(quantization_tables);
1710 xml=DestroyString(xml);
1713 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1714 if (table == (QuantizationTable *) NULL)
1715 ThrowFatalException(ResourceLimitFatalError,
1716 "UnableToAcquireQuantizationTable");
1717 table->slot=(char *) NULL;
1718 table->description=(char *) NULL;
1719 table->levels=(unsigned int *) NULL;
1720 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1721 if (attribute != (char *) NULL)
1722 table->slot=ConstantString(attribute);
1723 content=GetXMLTreeContent(description);
1724 if (content != (char *) NULL)
1725 table->description=ConstantString(content);
1726 attribute=GetXMLTreeAttribute(levels,"width");
1727 if (attribute == (char *) NULL)
1729 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1730 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1731 quantization_tables=DestroyXMLTree(quantization_tables);
1732 table=DestroyQuantizationTable(table);
1733 xml=DestroyString(xml);
1736 table->width=StringToUnsignedLong(attribute);
1737 if (table->width == 0)
1739 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1740 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1741 quantization_tables=DestroyXMLTree(quantization_tables);
1742 table=DestroyQuantizationTable(table);
1743 xml=DestroyString(xml);
1746 attribute=GetXMLTreeAttribute(levels,"height");
1747 if (attribute == (char *) NULL)
1749 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1750 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1751 quantization_tables=DestroyXMLTree(quantization_tables);
1752 table=DestroyQuantizationTable(table);
1753 xml=DestroyString(xml);
1756 table->height=StringToUnsignedLong(attribute);
1757 if (table->height == 0)
1759 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1760 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1761 quantization_tables=DestroyXMLTree(quantization_tables);
1762 table=DestroyQuantizationTable(table);
1763 xml=DestroyString(xml);
1766 attribute=GetXMLTreeAttribute(levels,"divisor");
1767 if (attribute == (char *) NULL)
1769 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1770 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1771 quantization_tables=DestroyXMLTree(quantization_tables);
1772 table=DestroyQuantizationTable(table);
1773 xml=DestroyString(xml);
1776 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1777 if (table->divisor == 0.0)
1779 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1780 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1781 quantization_tables=DestroyXMLTree(quantization_tables);
1782 table=DestroyQuantizationTable(table);
1783 xml=DestroyString(xml);
1786 content=GetXMLTreeContent(levels);
1787 if (content == (char *) NULL)
1789 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1790 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1791 quantization_tables=DestroyXMLTree(quantization_tables);
1792 table=DestroyQuantizationTable(table);
1793 xml=DestroyString(xml);
1796 length=(size_t) table->width*table->height;
1799 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1800 sizeof(*table->levels));
1801 if (table->levels == (unsigned int *) NULL)
1802 ThrowFatalException(ResourceLimitFatalError,
1803 "UnableToAcquireQuantizationTable");
1804 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1806 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1807 table->divisor+0.5);
1808 while (isspace((int) ((unsigned char) *p)) != 0)
1814 value=InterpretLocaleValue(content,&p);
1818 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1819 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1820 quantization_tables=DestroyXMLTree(quantization_tables);
1821 table=DestroyQuantizationTable(table);
1822 xml=DestroyString(xml);
1825 for (j=i; j < 64; j++)
1826 table->levels[j]=table->levels[j-1];
1827 quantization_tables=DestroyXMLTree(quantization_tables);
1828 xml=DestroyString(xml);
1832 static void InitializeDestination(j_compress_ptr cinfo)
1837 destination=(DestinationManager *) cinfo->dest;
1838 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1839 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1840 destination->manager.next_output_byte=destination->buffer;
1841 destination->manager.free_in_buffer=MaxBufferExtent;
1844 static inline size_t MagickMin(const size_t x,const size_t y)
1851 static void TerminateDestination(j_compress_ptr cinfo)
1856 destination=(DestinationManager *) cinfo->dest;
1857 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1862 count=WriteBlob(destination->image,MaxBufferExtent-
1863 destination->manager.free_in_buffer,destination->buffer);
1864 if (count != (ssize_t)
1865 (MaxBufferExtent-destination->manager.free_in_buffer))
1866 ERREXIT(cinfo,JERR_FILE_WRITE);
1870 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1892 Save image profile as a APP marker.
1895 custom_profile=AcquireStringInfo(65535L);
1896 ResetImageProfileIterator(image);
1897 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1899 register unsigned char
1902 profile=GetImageProfile(image,name);
1903 p=GetStringInfoDatum(custom_profile);
1904 if (LocaleCompare(name,"EXIF") == 0)
1905 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1907 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1908 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1909 (unsigned int) length);
1911 if (LocaleCompare(name,"ICC") == 0)
1913 register unsigned char
1916 tag_length=strlen(ICC_PROFILE);
1917 p=GetStringInfoDatum(custom_profile);
1918 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1920 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1922 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1923 p[12]=(unsigned char) ((i/65519L)+1);
1924 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1925 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1927 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1928 custom_profile),(unsigned int) (length+tag_length+3));
1931 if (((LocaleCompare(name,"IPTC") == 0) ||
1932 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1938 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1940 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1941 roundup=(size_t) (length & 0x01);
1942 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1944 (void) memcpy(p,"Photoshop 3.0 ",14);
1949 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1951 p[24]=(unsigned char) (length >> 8);
1952 p[25]=(unsigned char) (length & 0xff);
1955 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1957 p[length+tag_length]='\0';
1958 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1959 custom_profile),(unsigned int) (length+tag_length+roundup));
1962 if (LocaleCompare(name,"XMP") == 0)
1968 Add namespace to XMP profile.
1970 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1971 ConcatenateStringInfo(xmp_profile,profile);
1972 GetStringInfoDatum(xmp_profile)[28]='\0';
1973 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1975 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1976 jpeg_write_marker(jpeg_info,XML_MARKER,
1977 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1979 xmp_profile=DestroyStringInfo(xmp_profile);
1981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1982 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1983 name=GetNextImageProfile(image);
1985 custom_profile=DestroyStringInfo(custom_profile);
1988 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1993 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1994 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1995 destination=(DestinationManager *) cinfo->dest;
1996 destination->manager.init_destination=InitializeDestination;
1997 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1998 destination->manager.term_destination=TerminateDestination;
1999 destination->image=image;
2002 static char **SamplingFactorToList(const char *text)
2019 if (text == (char *) NULL)
2020 return((char **) NULL);
2022 Convert string to an ASCII list.
2025 for (p=text; *p != '\0'; p++)
2028 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2030 if (textlist == (char **) NULL)
2031 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2033 for (i=0; i < (ssize_t) lines; i++)
2035 for (q=(char *) p; *q != '\0'; q++)
2038 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2039 sizeof(*textlist[i]));
2040 if (textlist[i] == (char *) NULL)
2041 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2042 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2047 textlist[i]=(char *) NULL;
2051 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2052 Image *image,ExceptionInfo *exception)
2067 *volatile jpeg_pixels;
2087 struct jpeg_compress_struct
2090 struct jpeg_error_mgr
2099 assert(image_info != (const ImageInfo *) NULL);
2100 assert(image_info->signature == MagickSignature);
2101 assert(image != (Image *) NULL);
2102 assert(image->signature == MagickSignature);
2103 if (image->debug != MagickFalse)
2104 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2105 assert(exception != (ExceptionInfo *) NULL);
2106 assert(exception->signature == MagickSignature);
2107 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2108 if (status == MagickFalse)
2111 Initialize JPEG parameters.
2113 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2114 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2115 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2116 jpeg_info.client_data=(void *) image;
2117 jpeg_info.err=jpeg_std_error(&jpeg_error);
2118 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2119 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2120 error_manager.exception=exception;
2121 error_manager.image=image;
2122 memory_info=(MemoryInfo *) NULL;
2123 if (setjmp(error_manager.error_recovery) != 0)
2125 jpeg_destroy_compress(&jpeg_info);
2126 (void) CloseBlob(image);
2127 return(MagickFalse);
2129 jpeg_info.client_data=(void *) &error_manager;
2130 jpeg_create_compress(&jpeg_info);
2131 JPEGDestinationManager(&jpeg_info,image);
2132 if ((image->columns != (unsigned int) image->columns) ||
2133 (image->rows != (unsigned int) image->rows))
2134 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2135 jpeg_info.image_width=(unsigned int) image->columns;
2136 jpeg_info.image_height=(unsigned int) image->rows;
2137 jpeg_info.input_components=3;
2138 jpeg_info.data_precision=8;
2139 jpeg_info.in_color_space=JCS_RGB;
2140 switch (image->colorspace)
2142 case CMYKColorspace:
2144 jpeg_info.input_components=4;
2145 jpeg_info.in_color_space=JCS_CMYK;
2148 case YCbCrColorspace:
2149 case Rec601YCbCrColorspace:
2150 case Rec709YCbCrColorspace:
2152 jpeg_info.in_color_space=JCS_YCbCr;
2155 case GRAYColorspace:
2157 if (image_info->type == TrueColorType)
2159 jpeg_info.input_components=1;
2160 jpeg_info.in_color_space=JCS_GRAYSCALE;
2165 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2166 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2167 if (image_info->type == TrueColorType)
2169 if (IsImageGray(image,exception) != MagickFalse)
2171 jpeg_info.input_components=1;
2172 jpeg_info.in_color_space=JCS_GRAYSCALE;
2177 jpeg_set_defaults(&jpeg_info);
2178 if (jpeg_info.in_color_space == JCS_CMYK)
2179 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2180 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2181 jpeg_info.data_precision=8;
2183 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2184 jpeg_info.density_unit=(UINT8) 1;
2185 if (image->debug != MagickFalse)
2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2188 floor(image->resolution.y+0.5));
2189 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2192 Set image resolution.
2194 jpeg_info.write_JFIF_header=TRUE;
2195 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2196 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2198 Set image resolution units.
2200 jpeg_info.density_unit=(UINT8) 0;
2201 if (image->units == PixelsPerInchResolution)
2202 jpeg_info.density_unit=(UINT8) 1;
2203 if (image->units == PixelsPerCentimeterResolution)
2204 jpeg_info.density_unit=(UINT8) 2;
2206 jpeg_info.dct_method=JDCT_FLOAT;
2207 option=GetImageOption(image_info,"jpeg:dct-method");
2208 if (option != (const char *) NULL)
2214 if (LocaleCompare(option,"default") == 0)
2215 jpeg_info.dct_method=JDCT_DEFAULT;
2221 if (LocaleCompare(option,"fastest") == 0)
2222 jpeg_info.dct_method=JDCT_FASTEST;
2223 if (LocaleCompare(option,"float") == 0)
2224 jpeg_info.dct_method=JDCT_FLOAT;
2230 if (LocaleCompare(option,"ifast") == 0)
2231 jpeg_info.dct_method=JDCT_IFAST;
2232 if (LocaleCompare(option,"islow") == 0)
2233 jpeg_info.dct_method=JDCT_ISLOW;
2237 option=GetImageOption(image_info,"jpeg:optimize-coding");
2238 if (option != (const char *) NULL)
2239 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : FALSE;
2245 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2246 image->rows*sizeof(JSAMPLE);
2247 if (length == (MagickSizeType) ((size_t) length))
2250 Perform optimization only if available memory resources permit it.
2252 status=AcquireMagickResource(MemoryResource,length);
2253 RelinquishMagickResource(MemoryResource,length);
2254 jpeg_info.optimize_coding=status;
2257 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2258 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2259 (image_info->interlace != NoInterlace))
2261 if (image->debug != MagickFalse)
2262 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2263 "Interlace: progressive");
2264 jpeg_simple_progression(&jpeg_info);
2267 if (image->debug != MagickFalse)
2268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2269 "Interlace: non-progressive");
2271 if (image->debug != MagickFalse)
2272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2273 "Interlace: nonprogressive");
2276 option=GetImageOption(image_info,"jpeg:extent");
2277 if (option != (const char *) NULL)
2285 jpeg_info=CloneImageInfo(image_info);
2286 jpeg_info->blob=NULL;
2287 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2288 if (jpeg_image != (Image *) NULL)
2298 Search for compression quality that does not exceed image extent.
2300 jpeg_info->quality=0;
2301 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2302 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2303 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2304 (void) AcquireUniqueFilename(jpeg_image->filename);
2306 for (minimum=2; minimum < maximum; )
2308 jpeg_info->quality=minimum+(maximum-minimum+1)/2;
2309 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2310 if (GetBlobSize(jpeg_image) <= extent)
2311 minimum=jpeg_info->quality+1;
2313 maximum=jpeg_info->quality-1;
2315 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2317 jpeg_image=DestroyImage(jpeg_image);
2319 jpeg_info=DestroyImageInfo(jpeg_info);
2321 if ((image_info->compression != LosslessJPEGCompression) &&
2322 (image->quality <= 100))
2324 if (image->quality != UndefinedCompressionQuality)
2325 quality=(int) image->quality;
2326 if (image->debug != MagickFalse)
2327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2328 (double) image->quality);
2332 #if !defined(C_LOSSLESS_SUPPORTED)
2334 if (image->debug != MagickFalse)
2335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2337 if (image->quality < 100)
2338 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2339 "LosslessToLossyJPEGConversion",image->filename);
2346 predictor=image->quality/100; /* range 1-7 */
2347 point_transform=image->quality % 20; /* range 0-15 */
2348 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2349 if (image->debug != MagickFalse)
2351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2352 "Compression: lossless");
2353 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2354 "Predictor: %d",predictor);
2355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2356 "Point Transform: %d",point_transform);
2361 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2362 #if (JPEG_LIB_VERSION >= 70)
2363 option=GetImageOption(image_info,"quality");
2364 if (option != (const char *) NULL)
2373 Set quality scaling for luminance and chrominance separately.
2375 flags=ParseGeometry(option,&geometry_info);
2376 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2378 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2379 (geometry_info.rho+0.5));
2380 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2381 (geometry_info.sigma+0.5));
2382 jpeg_default_qtables(&jpeg_info,MagickTrue);
2386 colorspace=jpeg_info.in_color_space;
2387 value=GetImageOption(image_info,"jpeg:colorspace");
2388 if (value == (char *) NULL)
2389 value=GetImageProperty(image,"jpeg:colorspace",exception);
2390 if (value != (char *) NULL)
2391 colorspace=StringToInteger(value);
2392 sampling_factor=(const char *) NULL;
2393 if (colorspace == jpeg_info.in_color_space)
2395 value=GetImageOption(image_info,"jpeg:sampling-factor");
2396 if (value == (char *) NULL)
2397 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2398 if (value != (char *) NULL)
2400 sampling_factor=value;
2401 if (image->debug != MagickFalse)
2402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2403 " Input sampling-factors=%s",sampling_factor);
2406 value=GetImageOption(image_info,"jpeg:sampling-factor");
2407 if (image_info->sampling_factor != (char *) NULL)
2408 sampling_factor=image_info->sampling_factor;
2409 if (sampling_factor == (const char *) NULL)
2411 if (image->quality >= 90)
2412 for (i=0; i < MAX_COMPONENTS; i++)
2414 jpeg_info.comp_info[i].h_samp_factor=1;
2415 jpeg_info.comp_info[i].v_samp_factor=1;
2430 Set sampling factor.
2433 factors=SamplingFactorToList(sampling_factor);
2434 if (factors != (char **) NULL)
2436 for (i=0; i < MAX_COMPONENTS; i++)
2438 if (factors[i] == (char *) NULL)
2440 flags=ParseGeometry(factors[i],&geometry_info);
2441 if ((flags & SigmaValue) == 0)
2442 geometry_info.sigma=geometry_info.rho;
2443 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2444 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2445 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2447 factors=(char **) RelinquishMagickMemory(factors);
2449 for ( ; i < MAX_COMPONENTS; i++)
2451 jpeg_info.comp_info[i].h_samp_factor=1;
2452 jpeg_info.comp_info[i].v_samp_factor=1;
2455 option=GetImageOption(image_info,"jpeg:q-table");
2456 if (option != (const char *) NULL)
2462 Custom quantization tables.
2464 table=GetQuantizationTable(option,"0",exception);
2465 if (table != (QuantizationTable *) NULL)
2467 for (i=0; i < MAX_COMPONENTS; i++)
2468 jpeg_info.comp_info[i].quant_tbl_no=0;
2469 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2470 jpeg_quality_scaling(quality),0);
2471 table=DestroyQuantizationTable(table);
2473 table=GetQuantizationTable(option,"1",exception);
2474 if (table != (QuantizationTable *) NULL)
2476 for (i=1; i < MAX_COMPONENTS; i++)
2477 jpeg_info.comp_info[i].quant_tbl_no=1;
2478 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2479 jpeg_quality_scaling(quality),0);
2480 table=DestroyQuantizationTable(table);
2482 table=GetQuantizationTable(option,"2",exception);
2483 if (table != (QuantizationTable *) NULL)
2485 for (i=2; i < MAX_COMPONENTS; i++)
2486 jpeg_info.comp_info[i].quant_tbl_no=2;
2487 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2488 jpeg_quality_scaling(quality),0);
2489 table=DestroyQuantizationTable(table);
2491 table=GetQuantizationTable(option,"3",exception);
2492 if (table != (QuantizationTable *) NULL)
2494 for (i=3; i < MAX_COMPONENTS; i++)
2495 jpeg_info.comp_info[i].quant_tbl_no=3;
2496 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2497 jpeg_quality_scaling(quality),0);
2498 table=DestroyQuantizationTable(table);
2501 jpeg_start_compress(&jpeg_info,MagickTrue);
2502 if (image->debug != MagickFalse)
2504 if (image->storage_class == PseudoClass)
2505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2506 "Storage class: PseudoClass");
2508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2509 "Storage class: DirectClass");
2510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2511 (double) image->depth);
2512 if (image->colors != 0)
2513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2514 "Number of colors: %.20g",(double) image->colors);
2516 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2517 "Number of colors: unspecified");
2518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2519 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2520 switch (image->colorspace)
2522 case CMYKColorspace:
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525 "Storage class: DirectClass");
2526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2527 "Colorspace: CMYK");
2530 case YCbCrColorspace:
2531 case Rec601YCbCrColorspace:
2532 case Rec709YCbCrColorspace:
2534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2535 "Colorspace: YCbCr");
2541 switch (image->colorspace)
2543 case CMYKColorspace:
2545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2546 "Colorspace: CMYK");
2547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2548 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2549 jpeg_info.comp_info[0].h_samp_factor,
2550 jpeg_info.comp_info[0].v_samp_factor,
2551 jpeg_info.comp_info[1].h_samp_factor,
2552 jpeg_info.comp_info[1].v_samp_factor,
2553 jpeg_info.comp_info[2].h_samp_factor,
2554 jpeg_info.comp_info[2].v_samp_factor,
2555 jpeg_info.comp_info[3].h_samp_factor,
2556 jpeg_info.comp_info[3].v_samp_factor);
2559 case GRAYColorspace:
2561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2562 "Colorspace: GRAY");
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2564 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2565 jpeg_info.comp_info[0].v_samp_factor);
2568 case sRGBColorspace:
2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2572 "Image colorspace is RGB");
2573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2574 "Sampling factors: %dx%d,%dx%d,%dx%d",
2575 jpeg_info.comp_info[0].h_samp_factor,
2576 jpeg_info.comp_info[0].v_samp_factor,
2577 jpeg_info.comp_info[1].h_samp_factor,
2578 jpeg_info.comp_info[1].v_samp_factor,
2579 jpeg_info.comp_info[2].h_samp_factor,
2580 jpeg_info.comp_info[2].v_samp_factor);
2583 case YCbCrColorspace:
2584 case Rec601YCbCrColorspace:
2585 case Rec709YCbCrColorspace:
2587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2588 "Colorspace: YCbCr");
2589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2590 "Sampling factors: %dx%d,%dx%d,%dx%d",
2591 jpeg_info.comp_info[0].h_samp_factor,
2592 jpeg_info.comp_info[0].v_samp_factor,
2593 jpeg_info.comp_info[1].h_samp_factor,
2594 jpeg_info.comp_info[1].v_samp_factor,
2595 jpeg_info.comp_info[2].h_samp_factor,
2596 jpeg_info.comp_info[2].v_samp_factor);
2601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2604 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2605 jpeg_info.comp_info[0].h_samp_factor,
2606 jpeg_info.comp_info[0].v_samp_factor,
2607 jpeg_info.comp_info[1].h_samp_factor,
2608 jpeg_info.comp_info[1].v_samp_factor,
2609 jpeg_info.comp_info[2].h_samp_factor,
2610 jpeg_info.comp_info[2].v_samp_factor,
2611 jpeg_info.comp_info[3].h_samp_factor,
2612 jpeg_info.comp_info[3].v_samp_factor);
2618 Write JPEG profiles.
2620 value=GetImageProperty(image,"comment",exception);
2621 if (value != (char *) NULL)
2622 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2623 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2624 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2625 if (image->profiles != (void *) NULL)
2626 WriteProfile(&jpeg_info,image);
2628 Convert MIFF to JPEG raster pixels.
2630 memory_info=AcquireVirtualMemory((size_t) image->columns,
2631 jpeg_info.input_components*sizeof(*jpeg_pixels));
2632 if (memory_info == (MemoryInfo *) NULL)
2633 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2634 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2635 if (setjmp(error_manager.error_recovery) != 0)
2637 jpeg_destroy_compress(&jpeg_info);
2638 if (memory_info != (MemoryInfo *) NULL)
2639 memory_info=RelinquishVirtualMemory(memory_info);
2640 (void) CloseBlob(image);
2641 return(MagickFalse);
2643 scanline[0]=(JSAMPROW) jpeg_pixels;
2644 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2647 if (jpeg_info.data_precision <= 8)
2649 if ((jpeg_info.in_color_space == JCS_RGB) ||
2650 (jpeg_info.in_color_space == JCS_YCbCr))
2651 for (y=0; y < (ssize_t) image->rows; y++)
2653 register const Quantum
2659 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2660 if (p == (const Quantum *) NULL)
2663 for (x=0; x < (ssize_t) image->columns; x++)
2665 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2666 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2667 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2668 p+=GetPixelChannels(image);
2670 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2671 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2673 if (status == MagickFalse)
2677 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
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++)
2692 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2694 p+=GetPixelChannels(image);
2696 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2697 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2699 if (status == MagickFalse)
2703 for (y=0; y < (ssize_t) image->rows; y++)
2705 register const Quantum
2711 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2712 if (p == (const Quantum *) NULL)
2715 for (x=0; x < (ssize_t) image->columns; x++)
2718 Convert DirectClass packets to contiguous CMYK scanlines.
2720 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2721 GetPixelCyan(image,p))));
2722 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2723 GetPixelMagenta(image,p))));
2724 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2725 GetPixelYellow(image,p))));
2726 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2727 GetPixelBlack(image,p))));
2728 p+=GetPixelChannels(image);
2730 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2731 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2733 if (status == MagickFalse)
2738 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2739 for (y=0; y < (ssize_t) image->rows; y++)
2741 register const Quantum
2747 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2748 if (p == (const Quantum *) NULL)
2751 for (x=0; x < (ssize_t) image->columns; x++)
2753 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2755 p+=GetPixelChannels(image);
2757 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2758 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2760 if (status == MagickFalse)
2764 if ((jpeg_info.in_color_space == JCS_RGB) ||
2765 (jpeg_info.in_color_space == JCS_YCbCr))
2766 for (y=0; y < (ssize_t) image->rows; y++)
2768 register const Quantum
2774 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2775 if (p == (const Quantum *) NULL)
2778 for (x=0; x < (ssize_t) image->columns; x++)
2780 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2781 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2782 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2783 p+=GetPixelChannels(image);
2785 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2786 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2788 if (status == MagickFalse)
2792 for (y=0; y < (ssize_t) image->rows; y++)
2794 register const Quantum
2800 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2801 if (p == (const Quantum *) NULL)
2804 for (x=0; x < (ssize_t) image->columns; x++)
2807 Convert DirectClass packets to contiguous CMYK scanlines.
2809 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2811 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2813 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2815 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2817 p+=GetPixelChannels(image);
2819 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2820 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2822 if (status == MagickFalse)
2825 if (y == (ssize_t) image->rows)
2826 jpeg_finish_compress(&jpeg_info);
2828 Relinquish resources.
2830 jpeg_destroy_compress(&jpeg_info);
2831 memory_info=RelinquishVirtualMemory(memory_info);
2832 (void) CloseBlob(image);