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 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2166 if (image_info->type == TrueColorType)
2168 if (IsImageGray(image,exception) != MagickFalse)
2170 jpeg_info.input_components=1;
2171 jpeg_info.in_color_space=JCS_GRAYSCALE;
2176 jpeg_set_defaults(&jpeg_info);
2177 if (jpeg_info.in_color_space == JCS_CMYK)
2178 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2179 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2180 jpeg_info.data_precision=8;
2182 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2183 jpeg_info.density_unit=(UINT8) 1;
2184 if (image->debug != MagickFalse)
2185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2186 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2187 floor(image->resolution.y+0.5));
2188 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2191 Set image resolution.
2193 jpeg_info.write_JFIF_header=TRUE;
2194 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2195 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2197 Set image resolution units.
2199 jpeg_info.density_unit=(UINT8) 0;
2200 if (image->units == PixelsPerInchResolution)
2201 jpeg_info.density_unit=(UINT8) 1;
2202 if (image->units == PixelsPerCentimeterResolution)
2203 jpeg_info.density_unit=(UINT8) 2;
2205 jpeg_info.dct_method=JDCT_FLOAT;
2206 option=GetImageOption(image_info,"jpeg:dct-method");
2207 if (option != (const char *) NULL)
2213 if (LocaleCompare(option,"default") == 0)
2214 jpeg_info.dct_method=JDCT_DEFAULT;
2220 if (LocaleCompare(option,"fastest") == 0)
2221 jpeg_info.dct_method=JDCT_FASTEST;
2222 if (LocaleCompare(option,"float") == 0)
2223 jpeg_info.dct_method=JDCT_FLOAT;
2229 if (LocaleCompare(option,"ifast") == 0)
2230 jpeg_info.dct_method=JDCT_IFAST;
2231 if (LocaleCompare(option,"islow") == 0)
2232 jpeg_info.dct_method=JDCT_ISLOW;
2236 option=GetImageOption(image_info,"jpeg:optimize-coding");
2237 if (option != (const char *) NULL)
2238 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : FALSE;
2244 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2245 image->rows*sizeof(JSAMPLE);
2246 if (length == (MagickSizeType) ((size_t) length))
2249 Perform optimization only if available memory resources permit it.
2251 status=AcquireMagickResource(MemoryResource,length);
2252 RelinquishMagickResource(MemoryResource,length);
2253 jpeg_info.optimize_coding=status;
2256 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2257 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2258 (image_info->interlace != NoInterlace))
2260 if (image->debug != MagickFalse)
2261 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2262 "Interlace: progressive");
2263 jpeg_simple_progression(&jpeg_info);
2266 if (image->debug != MagickFalse)
2267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2268 "Interlace: non-progressive");
2270 if (image->debug != MagickFalse)
2271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2272 "Interlace: nonprogressive");
2275 option=GetImageOption(image_info,"jpeg:extent");
2276 if (option != (const char *) NULL)
2284 jpeg_info=CloneImageInfo(image_info);
2285 jpeg_info->blob=NULL;
2286 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2287 if (jpeg_image != (Image *) NULL)
2297 Search for compression quality that does not exceed image extent.
2299 jpeg_info->quality=0;
2300 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2301 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2302 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2303 (void) AcquireUniqueFilename(jpeg_image->filename);
2305 for (minimum=2; minimum < maximum; )
2307 jpeg_info->quality=minimum+(maximum-minimum+1)/2;
2308 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2309 if (GetBlobSize(jpeg_image) <= extent)
2310 minimum=jpeg_info->quality+1;
2312 maximum=jpeg_info->quality-1;
2314 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2316 jpeg_image=DestroyImage(jpeg_image);
2318 jpeg_info=DestroyImageInfo(jpeg_info);
2320 if ((image_info->compression != LosslessJPEGCompression) &&
2321 (image->quality <= 100))
2323 if (image->quality != UndefinedCompressionQuality)
2324 quality=(int) image->quality;
2325 if (image->debug != MagickFalse)
2326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2327 (double) image->quality);
2331 #if !defined(C_LOSSLESS_SUPPORTED)
2333 if (image->debug != MagickFalse)
2334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2336 if (image->quality < 100)
2337 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2338 "LosslessToLossyJPEGConversion",image->filename);
2345 predictor=image->quality/100; /* range 1-7 */
2346 point_transform=image->quality % 20; /* range 0-15 */
2347 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2348 if (image->debug != MagickFalse)
2350 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2351 "Compression: lossless");
2352 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2353 "Predictor: %d",predictor);
2354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2355 "Point Transform: %d",point_transform);
2360 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2361 #if (JPEG_LIB_VERSION >= 70)
2362 option=GetImageOption(image_info,"quality");
2363 if (option != (const char *) NULL)
2372 Set quality scaling for luminance and chrominance separately.
2374 flags=ParseGeometry(option,&geometry_info);
2375 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2377 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2378 (geometry_info.rho+0.5));
2379 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2380 (geometry_info.sigma+0.5));
2381 jpeg_default_qtables(&jpeg_info,MagickTrue);
2385 colorspace=jpeg_info.in_color_space;
2386 value=GetImageOption(image_info,"jpeg:colorspace");
2387 if (value == (char *) NULL)
2388 value=GetImageProperty(image,"jpeg:colorspace",exception);
2389 if (value != (char *) NULL)
2390 colorspace=StringToInteger(value);
2391 sampling_factor=(const char *) NULL;
2392 if (colorspace == jpeg_info.in_color_space)
2394 value=GetImageOption(image_info,"jpeg:sampling-factor");
2395 if (value == (char *) NULL)
2396 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2397 if (value != (char *) NULL)
2399 sampling_factor=value;
2400 if (image->debug != MagickFalse)
2401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2402 " Input sampling-factors=%s",sampling_factor);
2405 value=GetImageOption(image_info,"jpeg:sampling-factor");
2406 if (image_info->sampling_factor != (char *) NULL)
2407 sampling_factor=image_info->sampling_factor;
2408 if (sampling_factor == (const char *) NULL)
2410 if (image->quality >= 90)
2411 for (i=0; i < MAX_COMPONENTS; i++)
2413 jpeg_info.comp_info[i].h_samp_factor=1;
2414 jpeg_info.comp_info[i].v_samp_factor=1;
2429 Set sampling factor.
2432 factors=SamplingFactorToList(sampling_factor);
2433 if (factors != (char **) NULL)
2435 for (i=0; i < MAX_COMPONENTS; i++)
2437 if (factors[i] == (char *) NULL)
2439 flags=ParseGeometry(factors[i],&geometry_info);
2440 if ((flags & SigmaValue) == 0)
2441 geometry_info.sigma=geometry_info.rho;
2442 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2443 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2444 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2446 factors=(char **) RelinquishMagickMemory(factors);
2448 for ( ; i < MAX_COMPONENTS; i++)
2450 jpeg_info.comp_info[i].h_samp_factor=1;
2451 jpeg_info.comp_info[i].v_samp_factor=1;
2454 option=GetImageOption(image_info,"jpeg:q-table");
2455 if (option != (const char *) NULL)
2461 Custom quantization tables.
2463 table=GetQuantizationTable(option,"0",exception);
2464 if (table != (QuantizationTable *) NULL)
2466 for (i=0; i < MAX_COMPONENTS; i++)
2467 jpeg_info.comp_info[i].quant_tbl_no=0;
2468 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2469 jpeg_quality_scaling(quality),0);
2470 table=DestroyQuantizationTable(table);
2472 table=GetQuantizationTable(option,"1",exception);
2473 if (table != (QuantizationTable *) NULL)
2475 for (i=1; i < MAX_COMPONENTS; i++)
2476 jpeg_info.comp_info[i].quant_tbl_no=1;
2477 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2478 jpeg_quality_scaling(quality),0);
2479 table=DestroyQuantizationTable(table);
2481 table=GetQuantizationTable(option,"2",exception);
2482 if (table != (QuantizationTable *) NULL)
2484 for (i=2; i < MAX_COMPONENTS; i++)
2485 jpeg_info.comp_info[i].quant_tbl_no=2;
2486 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2487 jpeg_quality_scaling(quality),0);
2488 table=DestroyQuantizationTable(table);
2490 table=GetQuantizationTable(option,"3",exception);
2491 if (table != (QuantizationTable *) NULL)
2493 for (i=3; i < MAX_COMPONENTS; i++)
2494 jpeg_info.comp_info[i].quant_tbl_no=3;
2495 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2496 jpeg_quality_scaling(quality),0);
2497 table=DestroyQuantizationTable(table);
2500 jpeg_start_compress(&jpeg_info,MagickTrue);
2501 if (image->debug != MagickFalse)
2503 if (image->storage_class == PseudoClass)
2504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2505 "Storage class: PseudoClass");
2507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2508 "Storage class: DirectClass");
2509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2510 (double) image->depth);
2511 if (image->colors != 0)
2512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2513 "Number of colors: %.20g",(double) image->colors);
2515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2516 "Number of colors: unspecified");
2517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2518 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2519 switch (image->colorspace)
2521 case CMYKColorspace:
2523 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2524 "Storage class: DirectClass");
2525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2526 "Colorspace: CMYK");
2529 case YCbCrColorspace:
2530 case Rec601YCbCrColorspace:
2531 case Rec709YCbCrColorspace:
2533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2534 "Colorspace: YCbCr");
2540 switch (image->colorspace)
2542 case CMYKColorspace:
2544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2545 "Colorspace: CMYK");
2546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2547 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2548 jpeg_info.comp_info[0].h_samp_factor,
2549 jpeg_info.comp_info[0].v_samp_factor,
2550 jpeg_info.comp_info[1].h_samp_factor,
2551 jpeg_info.comp_info[1].v_samp_factor,
2552 jpeg_info.comp_info[2].h_samp_factor,
2553 jpeg_info.comp_info[2].v_samp_factor,
2554 jpeg_info.comp_info[3].h_samp_factor,
2555 jpeg_info.comp_info[3].v_samp_factor);
2558 case GRAYColorspace:
2560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2561 "Colorspace: GRAY");
2562 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2563 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2564 jpeg_info.comp_info[0].v_samp_factor);
2567 case sRGBColorspace:
2570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2571 "Image colorspace is RGB");
2572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2573 "Sampling factors: %dx%d,%dx%d,%dx%d",
2574 jpeg_info.comp_info[0].h_samp_factor,
2575 jpeg_info.comp_info[0].v_samp_factor,
2576 jpeg_info.comp_info[1].h_samp_factor,
2577 jpeg_info.comp_info[1].v_samp_factor,
2578 jpeg_info.comp_info[2].h_samp_factor,
2579 jpeg_info.comp_info[2].v_samp_factor);
2582 case YCbCrColorspace:
2583 case Rec601YCbCrColorspace:
2584 case Rec709YCbCrColorspace:
2586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2587 "Colorspace: YCbCr");
2588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2589 "Sampling factors: %dx%d,%dx%d,%dx%d",
2590 jpeg_info.comp_info[0].h_samp_factor,
2591 jpeg_info.comp_info[0].v_samp_factor,
2592 jpeg_info.comp_info[1].h_samp_factor,
2593 jpeg_info.comp_info[1].v_samp_factor,
2594 jpeg_info.comp_info[2].h_samp_factor,
2595 jpeg_info.comp_info[2].v_samp_factor);
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2603 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2604 jpeg_info.comp_info[0].h_samp_factor,
2605 jpeg_info.comp_info[0].v_samp_factor,
2606 jpeg_info.comp_info[1].h_samp_factor,
2607 jpeg_info.comp_info[1].v_samp_factor,
2608 jpeg_info.comp_info[2].h_samp_factor,
2609 jpeg_info.comp_info[2].v_samp_factor,
2610 jpeg_info.comp_info[3].h_samp_factor,
2611 jpeg_info.comp_info[3].v_samp_factor);
2617 Write JPEG profiles.
2619 value=GetImageProperty(image,"comment",exception);
2620 if (value != (char *) NULL)
2621 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2622 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2623 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2624 if (image->profiles != (void *) NULL)
2625 WriteProfile(&jpeg_info,image);
2627 Convert MIFF to JPEG raster pixels.
2629 memory_info=AcquireVirtualMemory((size_t) image->columns,
2630 jpeg_info.input_components*sizeof(*jpeg_pixels));
2631 if (memory_info == (MemoryInfo *) NULL)
2632 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2633 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2634 if (setjmp(error_manager.error_recovery) != 0)
2636 jpeg_destroy_compress(&jpeg_info);
2637 if (memory_info != (MemoryInfo *) NULL)
2638 memory_info=RelinquishVirtualMemory(memory_info);
2639 (void) CloseBlob(image);
2640 return(MagickFalse);
2642 scanline[0]=(JSAMPROW) jpeg_pixels;
2643 scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2646 if (jpeg_info.data_precision <= 8)
2648 if ((jpeg_info.in_color_space == JCS_RGB) ||
2649 (jpeg_info.in_color_space == JCS_YCbCr))
2650 for (y=0; y < (ssize_t) image->rows; y++)
2652 register const Quantum
2658 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2659 if (p == (const Quantum *) NULL)
2662 for (x=0; x < (ssize_t) image->columns; x++)
2664 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2665 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2666 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2667 p+=GetPixelChannels(image);
2669 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2670 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2672 if (status == MagickFalse)
2676 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2677 for (y=0; y < (ssize_t) image->rows; y++)
2679 register const Quantum
2685 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2686 if (p == (const Quantum *) NULL)
2689 for (x=0; x < (ssize_t) image->columns; x++)
2691 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2693 p+=GetPixelChannels(image);
2695 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2696 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2698 if (status == MagickFalse)
2702 for (y=0; y < (ssize_t) image->rows; y++)
2704 register const Quantum
2710 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2711 if (p == (const Quantum *) NULL)
2714 for (x=0; x < (ssize_t) image->columns; x++)
2717 Convert DirectClass packets to contiguous CMYK scanlines.
2719 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2720 GetPixelCyan(image,p))));
2721 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2722 GetPixelMagenta(image,p))));
2723 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2724 GetPixelYellow(image,p))));
2725 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2726 GetPixelBlack(image,p))));
2727 p+=GetPixelChannels(image);
2729 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2730 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2732 if (status == MagickFalse)
2737 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2738 for (y=0; y < (ssize_t) image->rows; y++)
2740 register const Quantum
2746 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2747 if (p == (const Quantum *) NULL)
2750 for (x=0; x < (ssize_t) image->columns; x++)
2752 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2754 p+=GetPixelChannels(image);
2756 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2757 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2759 if (status == MagickFalse)
2763 if ((jpeg_info.in_color_space == JCS_RGB) ||
2764 (jpeg_info.in_color_space == JCS_YCbCr))
2765 for (y=0; y < (ssize_t) image->rows; y++)
2767 register const Quantum
2773 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2774 if (p == (const Quantum *) NULL)
2777 for (x=0; x < (ssize_t) image->columns; x++)
2779 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2780 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2781 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2782 p+=GetPixelChannels(image);
2784 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2785 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2787 if (status == MagickFalse)
2791 for (y=0; y < (ssize_t) image->rows; y++)
2793 register const Quantum
2799 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2800 if (p == (const Quantum *) NULL)
2803 for (x=0; x < (ssize_t) image->columns; x++)
2806 Convert DirectClass packets to contiguous CMYK scanlines.
2808 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2810 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2812 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2814 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2816 p+=GetPixelChannels(image);
2818 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2819 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2821 if (status == MagickFalse)
2824 if (y == (ssize_t) image->rows)
2825 jpeg_finish_compress(&jpeg_info);
2827 Relinquish resources.
2829 jpeg_destroy_compress(&jpeg_info);
2830 memory_info=RelinquishVirtualMemory(memory_info);
2831 (void) CloseBlob(image);