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 % https://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/option-private.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/splay-tree.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/string_.h"
83 #include "MagickCore/string-private.h"
84 #include "MagickCore/token.h"
85 #include "MagickCore/utility.h"
86 #include "MagickCore/xml-tree.h"
87 #include "MagickCore/xml-tree-private.h"
89 #if defined(MAGICKCORE_JPEG_DELEGATE)
90 #define JPEG_INTERNAL_OPTIONS
91 #if defined(__MINGW32__) || defined(__MINGW64__)
92 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
102 #define ICC_MARKER (JPEG_APP0+2)
103 #define ICC_PROFILE "ICC_PROFILE"
104 #define IPTC_MARKER (JPEG_APP0+13)
105 #define XML_MARKER (JPEG_APP0+1)
106 #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
176 Forward declarations.
178 #if defined(MAGICKCORE_JPEG_DELEGATE)
179 static MagickBooleanType
180 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 % IsJPEG() returns MagickTrue if the image format type, identified by the
195 % magick string, is JPEG.
197 % The format of the IsJPEG method is:
199 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
201 % A description of each parameter follows:
203 % o magick: compare image format pattern against these bytes.
205 % o length: Specifies the length of the magick string.
208 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
212 if (memcmp(magick,"\377\330\377",3) == 0)
217 #if defined(MAGICKCORE_JPEG_DELEGATE)
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % R e a d J P E G I m a g e %
227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
230 % the memory necessary for the new Image structure and returns a pointer to
233 % The format of the ReadJPEGImage method is:
235 % Image *ReadJPEGImage(const ImageInfo *image_info,
236 % ExceptionInfo *exception)
238 % A description of each parameter follows:
240 % o image_info: the image info.
242 % o exception: return any errors or warnings in this structure.
246 static boolean FillInputBuffer(j_decompress_ptr cinfo)
251 source=(SourceManager *) cinfo->src;
252 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
253 MaxBufferExtent,source->buffer);
254 if (source->manager.bytes_in_buffer == 0)
256 if (source->start_of_blob != FALSE)
257 ERREXIT(cinfo,JERR_INPUT_EMPTY);
258 WARNMS(cinfo,JWRN_JPEG_EOF);
259 source->buffer[0]=(JOCTET) 0xff;
260 source->buffer[1]=(JOCTET) JPEG_EOI;
261 source->manager.bytes_in_buffer=2;
263 source->manager.next_input_byte=source->buffer;
264 source->start_of_blob=FALSE;
268 static int GetCharacter(j_decompress_ptr jpeg_info)
270 if (jpeg_info->src->bytes_in_buffer == 0)
271 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
272 jpeg_info->src->bytes_in_buffer--;
273 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
276 static void InitializeSource(j_decompress_ptr cinfo)
281 source=(SourceManager *) cinfo->src;
282 source->start_of_blob=TRUE;
285 static MagickBooleanType IsITUFaxImage(const Image *image)
293 profile=GetImageProfile(image,"8bim");
294 if (profile == (const StringInfo *) NULL)
296 if (GetStringInfoLength(profile) < 5)
298 datum=GetStringInfoDatum(profile);
299 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
300 (datum[3] == 0x41) && (datum[4] == 0x58))
305 static void JPEGErrorHandler(j_common_ptr jpeg_info)
308 message[JMSG_LENGTH_MAX];
320 error_manager=(ErrorManager *) jpeg_info->client_data;
321 image=error_manager->image;
322 exception=error_manager->exception;
323 (jpeg_info->err->format_message)(jpeg_info,message);
324 if (image->debug != MagickFalse)
325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
326 "[%s] JPEG Trace: \"%s\"",image->filename,message);
327 if (error_manager->finished != MagickFalse)
328 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
329 (char *) message,"`%s'",image->filename);
331 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
332 (char *) message,"`%s'",image->filename);
333 longjmp(error_manager->error_recovery,1);
336 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
338 #define JPEGExcessiveWarnings 1000
341 message[JMSG_LENGTH_MAX];
353 error_manager=(ErrorManager *) jpeg_info->client_data;
354 exception=error_manager->exception;
355 image=error_manager->image;
359 Process warning message.
361 (jpeg_info->err->format_message)(jpeg_info,message);
362 if (jpeg_info->err->num_warnings++ < JPEGExcessiveWarnings)
363 ThrowBinaryException(CorruptImageWarning,(char *) message,
367 if ((image->debug != MagickFalse) &&
368 (level >= jpeg_info->err->trace_level))
371 Process trace message.
373 (jpeg_info->err->format_message)(jpeg_info,message);
374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
375 "[%s] JPEG Trace: \"%s\"",image->filename,message);
380 static boolean ReadComment(j_decompress_ptr jpeg_info)
391 register unsigned char
404 Determine length of comment.
406 error_manager=(ErrorManager *) jpeg_info->client_data;
407 exception=error_manager->exception;
408 image=error_manager->image;
409 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
410 length+=GetCharacter(jpeg_info);
414 comment=BlobToStringInfo((const void *) NULL,length);
415 if (comment == (StringInfo *) NULL)
417 (void) ThrowMagickException(exception,GetMagickModule(),
418 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
424 error_manager->profile=comment;
425 p=GetStringInfoDatum(comment);
426 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
427 *p++=(unsigned char) GetCharacter(jpeg_info);
429 error_manager->profile=NULL;
430 p=GetStringInfoDatum(comment);
431 (void) SetImageProperty(image,"comment",(const char *) p,exception);
432 comment=DestroyStringInfo(comment);
436 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
456 register unsigned char
469 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
470 length+=(size_t) GetCharacter(jpeg_info);
475 (void) GetCharacter(jpeg_info);
478 for (i=0; i < 12; i++)
479 magick[i]=(char) GetCharacter(jpeg_info);
480 if (LocaleCompare(magick,ICC_PROFILE) != 0)
483 Not a ICC profile, return.
485 for (i=0; i < (ssize_t) (length-12); i++)
486 (void) GetCharacter(jpeg_info);
489 (void) GetCharacter(jpeg_info); /* id */
490 (void) GetCharacter(jpeg_info); /* markers */
492 error_manager=(ErrorManager *) jpeg_info->client_data;
493 exception=error_manager->exception;
494 image=error_manager->image;
495 profile=BlobToStringInfo((const void *) NULL,length);
496 if (profile == (StringInfo *) NULL)
498 (void) ThrowMagickException(exception,GetMagickModule(),
499 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
502 error_manager->profile=profile;
503 p=GetStringInfoDatum(profile);
504 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
505 *p++=(unsigned char) GetCharacter(jpeg_info);
506 error_manager->profile=NULL;
507 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
508 if (icc_profile != (StringInfo *) NULL)
510 ConcatenateStringInfo(icc_profile,profile);
511 profile=DestroyStringInfo(profile);
515 status=SetImageProfile(image,"icc",profile,exception);
516 profile=DestroyStringInfo(profile);
517 if (status == MagickFalse)
519 (void) ThrowMagickException(exception,GetMagickModule(),
520 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
524 if (image->debug != MagickFalse)
525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
526 "Profile: ICC, %.20g bytes",(double) length);
530 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
533 magick[MagickPathExtent];
550 register unsigned char
561 Determine length of binary data stored here.
563 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
564 length+=(size_t) GetCharacter(jpeg_info);
569 (void) GetCharacter(jpeg_info);
573 Validate that this was written as a Photoshop resource format slug.
575 for (i=0; i < 10; i++)
576 magick[i]=(char) GetCharacter(jpeg_info);
581 if (LocaleCompare(magick,"Photoshop ") != 0)
584 Not a IPTC profile, return.
586 for (i=0; i < (ssize_t) length; i++)
587 (void) GetCharacter(jpeg_info);
591 Remove the version number.
593 for (i=0; i < 4; i++)
594 (void) GetCharacter(jpeg_info);
598 error_manager=(ErrorManager *) jpeg_info->client_data;
599 exception=error_manager->exception;
600 image=error_manager->image;
601 profile=BlobToStringInfo((const void *) NULL,length);
602 if (profile == (StringInfo *) NULL)
604 (void) ThrowMagickException(exception,GetMagickModule(),
605 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
608 error_manager->profile=profile;
609 p=GetStringInfoDatum(profile);
610 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
611 *p++=(unsigned char) GetCharacter(jpeg_info);
612 error_manager->profile=NULL;
613 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
614 if (iptc_profile != (StringInfo *) NULL)
616 ConcatenateStringInfo(iptc_profile,profile);
617 profile=DestroyStringInfo(profile);
621 status=SetImageProfile(image,"8bim",profile,exception);
622 profile=DestroyStringInfo(profile);
623 if (status == MagickFalse)
625 (void) ThrowMagickException(exception,GetMagickModule(),
626 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
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)
639 name[MagickPathExtent];
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,MagickPathExtent,"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",MagickPathExtent);
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",MagickPathExtent);
721 previous_profile=GetImageProfile(image,name);
722 if (previous_profile != (const StringInfo *) NULL)
727 profile_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,
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[MagickPathExtent];
934 switch (jpeg_info->out_color_space)
938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
939 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
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,MagickPathExtent,"%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,MagickPathExtent,
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,MagickPathExtent,
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[MagickPathExtent];
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 == MagickCoreSignature);
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 == MagickCoreSignature);
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 Verify that file size large enough to contain a JPEG datastream
1066 if using a seekable blob
1068 if (IsBlobSeekable(image) && GetBlobSize(image) < 107)
1069 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
1072 Initialize JPEG parameters.
1074 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1075 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1076 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1077 jpeg_info.err=jpeg_std_error(&jpeg_error);
1078 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1079 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1080 memory_info=(MemoryInfo *) NULL;
1081 error_manager.exception=exception;
1082 error_manager.image=image;
1083 if (setjmp(error_manager.error_recovery) != 0)
1085 jpeg_destroy_decompress(&jpeg_info);
1086 if (error_manager.profile != (StringInfo *) NULL)
1087 error_manager.profile=DestroyStringInfo(error_manager.profile);
1088 (void) CloseBlob(image);
1089 number_pixels=(MagickSizeType) image->columns*image->rows;
1090 if (number_pixels != 0)
1091 return(GetFirstImageInList(image));
1092 return(DestroyImage(image));
1094 jpeg_info.client_data=(void *) &error_manager;
1095 jpeg_create_decompress(&jpeg_info);
1096 JPEGSourceManager(&jpeg_info,image);
1097 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1098 option=GetImageOption(image_info,"profile:skip");
1099 if (IsOptionMember("ICC",option) == MagickFalse)
1100 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1101 if (IsOptionMember("IPTC",option) == MagickFalse)
1102 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1103 for (i=1; i < 16; i++)
1104 if ((i != 2) && (i != 13) && (i != 14))
1105 if (IsOptionMember("APP",option) == MagickFalse)
1106 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1107 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1108 if ((image_info->colorspace == YCbCrColorspace) ||
1109 (image_info->colorspace == Rec601YCbCrColorspace) ||
1110 (image_info->colorspace == Rec709YCbCrColorspace))
1111 jpeg_info.out_color_space=JCS_YCbCr;
1113 Set image resolution.
1116 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1117 (jpeg_info.Y_density != 1))
1119 image->resolution.x=(double) jpeg_info.X_density;
1120 image->resolution.y=(double) jpeg_info.Y_density;
1121 units=(size_t) jpeg_info.density_unit;
1124 image->units=PixelsPerInchResolution;
1126 image->units=PixelsPerCentimeterResolution;
1127 number_pixels=(MagickSizeType) image->columns*image->rows;
1128 option=GetImageOption(image_info,"jpeg:size");
1129 if ((option != (const char *) NULL) &&
1130 (jpeg_info.out_color_space != JCS_YCbCr))
1144 flags=ParseGeometry(option,&geometry_info);
1145 if ((flags & SigmaValue) == 0)
1146 geometry_info.sigma=geometry_info.rho;
1147 jpeg_calc_output_dimensions(&jpeg_info);
1148 image->magick_columns=jpeg_info.output_width;
1149 image->magick_rows=jpeg_info.output_height;
1151 if (geometry_info.rho != 0.0)
1152 scale_factor=jpeg_info.output_width/geometry_info.rho;
1153 if ((geometry_info.sigma != 0.0) &&
1154 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1155 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1156 jpeg_info.scale_num=1U;
1157 jpeg_info.scale_denom=(unsigned int) scale_factor;
1158 jpeg_calc_output_dimensions(&jpeg_info);
1159 if (image->debug != MagickFalse)
1160 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1161 "Scale factor: %.20g",(double) scale_factor);
1163 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1164 #if defined(D_LOSSLESS_SUPPORTED)
1165 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1166 JPEGInterlace : NoInterlace;
1167 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1168 LosslessJPEGCompression : JPEGCompression;
1169 if (jpeg_info.data_precision > 8)
1170 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1171 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1173 if (jpeg_info.data_precision == 16)
1174 jpeg_info.data_precision=12;
1176 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1178 image->compression=JPEGCompression;
1181 image->compression=JPEGCompression;
1182 image->interlace=JPEGInterlace;
1184 option=GetImageOption(image_info,"jpeg:colors");
1185 if (option != (const char *) NULL)
1188 Let the JPEG library quantize the image.
1190 jpeg_info.quantize_colors=TRUE;
1191 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1193 option=GetImageOption(image_info,"jpeg:block-smoothing");
1194 if (option != (const char *) NULL)
1195 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1197 jpeg_info.dct_method=JDCT_FLOAT;
1198 option=GetImageOption(image_info,"jpeg:dct-method");
1199 if (option != (const char *) NULL)
1205 if (LocaleCompare(option,"default") == 0)
1206 jpeg_info.dct_method=JDCT_DEFAULT;
1212 if (LocaleCompare(option,"fastest") == 0)
1213 jpeg_info.dct_method=JDCT_FASTEST;
1214 if (LocaleCompare(option,"float") == 0)
1215 jpeg_info.dct_method=JDCT_FLOAT;
1221 if (LocaleCompare(option,"ifast") == 0)
1222 jpeg_info.dct_method=JDCT_IFAST;
1223 if (LocaleCompare(option,"islow") == 0)
1224 jpeg_info.dct_method=JDCT_ISLOW;
1228 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1229 if (option != (const char *) NULL)
1230 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1232 (void) jpeg_start_decompress(&jpeg_info);
1233 image->columns=jpeg_info.output_width;
1234 image->rows=jpeg_info.output_height;
1235 image->depth=(size_t) jpeg_info.data_precision;
1236 switch (jpeg_info.out_color_space)
1241 (void) SetImageColorspace(image,sRGBColorspace,exception);
1246 (void) SetImageColorspace(image,GRAYColorspace,exception);
1251 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1256 (void) SetImageColorspace(image,CMYKColorspace,exception);
1260 if (IsITUFaxImage(image) != MagickFalse)
1262 (void) SetImageColorspace(image,LabColorspace,exception);
1263 jpeg_info.out_color_space=JCS_YCbCr;
1265 option=GetImageOption(image_info,"jpeg:colors");
1266 if (option != (const char *) NULL)
1267 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1269 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1270 if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0))
1275 colors=(size_t) GetQuantumRange(image->depth)+1;
1276 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1277 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1279 if (image->debug != MagickFalse)
1281 if (image->interlace != NoInterlace)
1282 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1283 "Interlace: progressive");
1285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1286 "Interlace: nonprogressive");
1287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1288 (int) jpeg_info.data_precision);
1289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1290 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1292 JPEGSetImageQuality(&jpeg_info,image);
1293 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1294 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
1295 jpeg_info.out_color_space);
1296 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1297 if (image_info->ping != MagickFalse)
1299 jpeg_destroy_decompress(&jpeg_info);
1300 (void) CloseBlob(image);
1301 return(GetFirstImageInList(image));
1303 status=SetImageExtent(image,image->columns,image->rows,exception);
1304 if (status == MagickFalse)
1306 jpeg_destroy_decompress(&jpeg_info);
1307 return(DestroyImageList(image));
1309 if ((jpeg_info.output_components != 1) &&
1310 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1312 jpeg_destroy_decompress(&jpeg_info);
1313 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1315 memory_info=AcquireVirtualMemory((size_t) image->columns,
1316 jpeg_info.output_components*sizeof(*jpeg_pixels));
1317 if (memory_info == (MemoryInfo *) NULL)
1319 jpeg_destroy_decompress(&jpeg_info);
1320 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1322 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1324 Convert JPEG pixels to pixel packets.
1326 if (setjmp(error_manager.error_recovery) != 0)
1328 if (memory_info != (MemoryInfo *) NULL)
1329 memory_info=RelinquishVirtualMemory(memory_info);
1330 jpeg_destroy_decompress(&jpeg_info);
1331 (void) CloseBlob(image);
1332 number_pixels=(MagickSizeType) image->columns*image->rows;
1333 if (number_pixels != 0)
1334 return(GetFirstImageInList(image));
1335 return(DestroyImage(image));
1337 if (jpeg_info.quantize_colors != 0)
1339 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1340 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1341 for (i=0; i < (ssize_t) image->colors; i++)
1343 image->colormap[i].red=(double) ScaleCharToQuantum(
1344 jpeg_info.colormap[0][i]);
1345 image->colormap[i].green=image->colormap[i].red;
1346 image->colormap[i].blue=image->colormap[i].red;
1347 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1350 for (i=0; i < (ssize_t) image->colors; i++)
1352 image->colormap[i].red=(double) ScaleCharToQuantum(
1353 jpeg_info.colormap[0][i]);
1354 image->colormap[i].green=(double) ScaleCharToQuantum(
1355 jpeg_info.colormap[1][i]);
1356 image->colormap[i].blue=(double) ScaleCharToQuantum(
1357 jpeg_info.colormap[2][i]);
1358 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1361 scanline[0]=(JSAMPROW) jpeg_pixels;
1362 for (y=0; y < (ssize_t) image->rows; y++)
1370 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1372 (void) ThrowMagickException(exception,GetMagickModule(),
1373 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1377 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1378 if (q == (Quantum *) NULL)
1380 if (jpeg_info.data_precision > 8)
1385 scale=65535/(unsigned short) GetQuantumRange((size_t)
1386 jpeg_info.data_precision);
1387 if (jpeg_info.output_components == 1)
1388 for (x=0; x < (ssize_t) image->columns; x++)
1393 pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1394 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1395 SetPixelIndex(image,index,q);
1396 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1398 q+=GetPixelChannels(image);
1401 if (image->colorspace != CMYKColorspace)
1402 for (x=0; x < (ssize_t) image->columns; x++)
1404 SetPixelRed(image,ScaleShortToQuantum(
1405 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1406 SetPixelGreen(image,ScaleShortToQuantum(
1407 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1408 SetPixelBlue(image,ScaleShortToQuantum(
1409 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1410 SetPixelAlpha(image,OpaqueAlpha,q);
1411 q+=GetPixelChannels(image);
1414 for (x=0; x < (ssize_t) image->columns; x++)
1416 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1417 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1418 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1419 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1420 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1421 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1422 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1423 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1424 SetPixelAlpha(image,OpaqueAlpha,q);
1425 q+=GetPixelChannels(image);
1429 if (jpeg_info.output_components == 1)
1430 for (x=0; x < (ssize_t) image->columns; x++)
1432 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) GETJSAMPLE(*p),
1434 SetPixelIndex(image,index,q);
1435 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1437 q+=GetPixelChannels(image);
1440 if (image->colorspace != CMYKColorspace)
1441 for (x=0; x < (ssize_t) image->columns; x++)
1443 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1444 GETJSAMPLE(*p++)),q);
1445 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1446 GETJSAMPLE(*p++)),q);
1447 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1448 GETJSAMPLE(*p++)),q);
1449 SetPixelAlpha(image,OpaqueAlpha,q);
1450 q+=GetPixelChannels(image);
1453 for (x=0; x < (ssize_t) image->columns; x++)
1455 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1456 (unsigned char) GETJSAMPLE(*p++)),q);
1457 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1458 (unsigned char) GETJSAMPLE(*p++)),q);
1459 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1460 (unsigned char) GETJSAMPLE(*p++)),q);
1461 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1462 (unsigned char) GETJSAMPLE(*p++)),q);
1463 SetPixelAlpha(image,OpaqueAlpha,q);
1464 q+=GetPixelChannels(image);
1466 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1468 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1470 if (status == MagickFalse)
1472 jpeg_abort_decompress(&jpeg_info);
1476 if (status != MagickFalse)
1478 error_manager.finished=MagickTrue;
1479 if (setjmp(error_manager.error_recovery) == 0)
1480 (void) jpeg_finish_decompress(&jpeg_info);
1483 Free jpeg resources.
1485 jpeg_destroy_decompress(&jpeg_info);
1486 memory_info=RelinquishVirtualMemory(memory_info);
1487 (void) CloseBlob(image);
1488 return(GetFirstImageInList(image));
1493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1497 % R e g i s t e r J P E G I m a g e %
1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503 % RegisterJPEGImage() adds properties for the JPEG image format to
1504 % the list of supported formats. The properties include the image format
1505 % tag, a method to read and/or write the format, whether the format
1506 % supports the saving of more than one frame to the same file or blob,
1507 % whether the format supports native in-memory I/O, and a brief
1508 % description of the format.
1510 % The format of the RegisterJPEGImage method is:
1512 % size_t RegisterJPEGImage(void)
1515 ModuleExport size_t RegisterJPEGImage(void)
1517 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1520 version[MagickPathExtent];
1526 #if defined(JPEG_LIB_VERSION)
1527 (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION);
1529 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1530 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1531 entry->flags^=CoderDecoderThreadSupportFlag;
1533 #if defined(MAGICKCORE_JPEG_DELEGATE)
1534 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1535 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1537 entry->magick=(IsImageFormatHandler *) IsJPEG;
1538 entry->flags^=CoderAdjoinFlag;
1539 entry->flags^=CoderUseExtensionFlag;
1540 if (*version != '\0')
1541 entry->version=ConstantString(version);
1542 entry->mime_type=ConstantString("image/jpeg");
1543 (void) RegisterMagickInfo(entry);
1544 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1545 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1546 entry->flags^=CoderDecoderThreadSupportFlag;
1548 #if defined(MAGICKCORE_JPEG_DELEGATE)
1549 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1550 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1552 entry->magick=(IsImageFormatHandler *) IsJPEG;
1553 entry->flags^=CoderAdjoinFlag;
1554 if (*version != '\0')
1555 entry->version=ConstantString(version);
1556 entry->mime_type=ConstantString("image/jpeg");
1557 (void) RegisterMagickInfo(entry);
1558 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1559 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1560 entry->flags^=CoderDecoderThreadSupportFlag;
1562 #if defined(MAGICKCORE_JPEG_DELEGATE)
1563 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1564 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1566 entry->flags^=CoderAdjoinFlag;
1567 entry->flags^=CoderUseExtensionFlag;
1568 if (*version != '\0')
1569 entry->version=ConstantString(version);
1570 entry->mime_type=ConstantString("image/jpeg");
1571 (void) RegisterMagickInfo(entry);
1572 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1573 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1574 entry->flags^=CoderDecoderThreadSupportFlag;
1576 #if defined(MAGICKCORE_JPEG_DELEGATE)
1577 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1578 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1580 entry->flags^=CoderAdjoinFlag;
1581 entry->flags^=CoderUseExtensionFlag;
1582 if (*version != '\0')
1583 entry->version=ConstantString(version);
1584 entry->mime_type=ConstantString("image/jpeg");
1585 (void) RegisterMagickInfo(entry);
1586 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1587 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1588 entry->flags^=CoderDecoderThreadSupportFlag;
1590 #if defined(MAGICKCORE_JPEG_DELEGATE)
1591 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1592 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1594 entry->flags^=CoderAdjoinFlag;
1595 entry->flags^=CoderUseExtensionFlag;
1596 if (*version != '\0')
1597 entry->version=ConstantString(version);
1598 entry->mime_type=ConstantString("image/jpeg");
1599 (void) RegisterMagickInfo(entry);
1600 return(MagickImageCoderSignature);
1604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608 % U n r e g i s t e r J P E G I m a g e %
1612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1614 % UnregisterJPEGImage() removes format registrations made by the
1615 % JPEG module from the list of supported formats.
1617 % The format of the UnregisterJPEGImage method is:
1619 % UnregisterJPEGImage(void)
1622 ModuleExport void UnregisterJPEGImage(void)
1624 (void) UnregisterMagickInfo("PJPG");
1625 (void) UnregisterMagickInfo("JPS");
1626 (void) UnregisterMagickInfo("JPG");
1627 (void) UnregisterMagickInfo("JPEG");
1628 (void) UnregisterMagickInfo("JPE");
1631 #if defined(MAGICKCORE_JPEG_DELEGATE)
1633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637 % W r i t e J P E G I m a g e %
1641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1643 % WriteJPEGImage() writes a JPEG image file and returns it. It
1644 % allocates the memory necessary for the new Image structure and returns a
1645 % pointer to the new image.
1647 % The format of the WriteJPEGImage method is:
1649 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1650 % Image *image,ExceptionInfo *exception)
1652 % A description of each parameter follows:
1654 % o image_info: the image info.
1656 % o jpeg_image: The image.
1658 % o exception: return any errors or warnings in this structure.
1662 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1664 assert(table != (QuantizationTable *) NULL);
1665 if (table->slot != (char *) NULL)
1666 table->slot=DestroyString(table->slot);
1667 if (table->description != (char *) NULL)
1668 table->description=DestroyString(table->description);
1669 if (table->levels != (unsigned int *) NULL)
1670 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1671 table=(QuantizationTable *) RelinquishMagickMemory(table);
1675 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1680 destination=(DestinationManager *) cinfo->dest;
1681 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1682 MaxBufferExtent,destination->buffer);
1683 if (destination->manager.free_in_buffer != MaxBufferExtent)
1684 ERREXIT(cinfo,JERR_FILE_WRITE);
1685 destination->manager.next_output_byte=destination->buffer;
1689 static QuantizationTable *GetQuantizationTable(const char *filename,
1690 const char *slot,ExceptionInfo *exception)
1718 *quantization_tables,
1721 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1722 "Loading quantization tables \"%s\" ...",filename);
1723 table=(QuantizationTable *) NULL;
1724 xml=FileToString(filename,~0UL,exception);
1725 if (xml == (char *) NULL)
1727 quantization_tables=NewXMLTree(xml,exception);
1728 if (quantization_tables == (XMLTreeInfo *) NULL)
1730 xml=DestroyString(xml);
1733 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1734 table_iterator != (XMLTreeInfo *) NULL;
1735 table_iterator=GetNextXMLTreeTag(table_iterator))
1737 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1738 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1740 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1741 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1744 if (table_iterator == (XMLTreeInfo *) NULL)
1746 xml=DestroyString(xml);
1749 description=GetXMLTreeChild(table_iterator,"description");
1750 if (description == (XMLTreeInfo *) NULL)
1752 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1753 "XmlMissingElement","<description>, slot \"%s\"",slot);
1754 quantization_tables=DestroyXMLTree(quantization_tables);
1755 xml=DestroyString(xml);
1758 levels=GetXMLTreeChild(table_iterator,"levels");
1759 if (levels == (XMLTreeInfo *) NULL)
1761 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1762 "XmlMissingElement","<levels>, slot \"%s\"",slot);
1763 quantization_tables=DestroyXMLTree(quantization_tables);
1764 xml=DestroyString(xml);
1767 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1768 if (table == (QuantizationTable *) NULL)
1769 ThrowFatalException(ResourceLimitFatalError,
1770 "UnableToAcquireQuantizationTable");
1771 table->slot=(char *) NULL;
1772 table->description=(char *) NULL;
1773 table->levels=(unsigned int *) NULL;
1774 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1775 if (attribute != (char *) NULL)
1776 table->slot=ConstantString(attribute);
1777 content=GetXMLTreeContent(description);
1778 if (content != (char *) NULL)
1779 table->description=ConstantString(content);
1780 attribute=GetXMLTreeAttribute(levels,"width");
1781 if (attribute == (char *) NULL)
1783 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1784 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1785 quantization_tables=DestroyXMLTree(quantization_tables);
1786 table=DestroyQuantizationTable(table);
1787 xml=DestroyString(xml);
1790 table->width=StringToUnsignedLong(attribute);
1791 if (table->width == 0)
1793 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1794 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1795 quantization_tables=DestroyXMLTree(quantization_tables);
1796 table=DestroyQuantizationTable(table);
1797 xml=DestroyString(xml);
1800 attribute=GetXMLTreeAttribute(levels,"height");
1801 if (attribute == (char *) NULL)
1803 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1804 "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1805 quantization_tables=DestroyXMLTree(quantization_tables);
1806 table=DestroyQuantizationTable(table);
1807 xml=DestroyString(xml);
1810 table->height=StringToUnsignedLong(attribute);
1811 if (table->height == 0)
1813 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1814 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1815 quantization_tables=DestroyXMLTree(quantization_tables);
1816 table=DestroyQuantizationTable(table);
1817 xml=DestroyString(xml);
1820 attribute=GetXMLTreeAttribute(levels,"divisor");
1821 if (attribute == (char *) NULL)
1823 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1824 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1825 quantization_tables=DestroyXMLTree(quantization_tables);
1826 table=DestroyQuantizationTable(table);
1827 xml=DestroyString(xml);
1830 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1831 if (table->divisor == 0.0)
1833 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1834 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1835 quantization_tables=DestroyXMLTree(quantization_tables);
1836 table=DestroyQuantizationTable(table);
1837 xml=DestroyString(xml);
1840 content=GetXMLTreeContent(levels);
1841 if (content == (char *) NULL)
1843 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1844 "XmlMissingContent","<levels>, table \"%s\"",slot);
1845 quantization_tables=DestroyXMLTree(quantization_tables);
1846 table=DestroyQuantizationTable(table);
1847 xml=DestroyString(xml);
1850 length=(size_t) table->width*table->height;
1853 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1854 sizeof(*table->levels));
1855 if (table->levels == (unsigned int *) NULL)
1856 ThrowFatalException(ResourceLimitFatalError,
1857 "UnableToAcquireQuantizationTable");
1858 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1860 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1861 table->divisor+0.5);
1862 while (isspace((int) ((unsigned char) *p)) != 0)
1868 value=InterpretLocaleValue(content,&p);
1872 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1873 "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1874 quantization_tables=DestroyXMLTree(quantization_tables);
1875 table=DestroyQuantizationTable(table);
1876 xml=DestroyString(xml);
1879 for (j=i; j < 64; j++)
1880 table->levels[j]=table->levels[j-1];
1881 quantization_tables=DestroyXMLTree(quantization_tables);
1882 xml=DestroyString(xml);
1886 static void InitializeDestination(j_compress_ptr cinfo)
1891 destination=(DestinationManager *) cinfo->dest;
1892 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1893 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1894 destination->manager.next_output_byte=destination->buffer;
1895 destination->manager.free_in_buffer=MaxBufferExtent;
1898 static void TerminateDestination(j_compress_ptr cinfo)
1903 destination=(DestinationManager *) cinfo->dest;
1904 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1909 count=WriteBlob(destination->image,MaxBufferExtent-
1910 destination->manager.free_in_buffer,destination->buffer);
1911 if (count != (ssize_t)
1912 (MaxBufferExtent-destination->manager.free_in_buffer))
1913 ERREXIT(cinfo,JERR_FILE_WRITE);
1917 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1918 ExceptionInfo *exception)
1940 Save image profile as a APP marker.
1943 custom_profile=AcquireStringInfo(65535L);
1944 ResetImageProfileIterator(image);
1945 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1947 profile=GetImageProfile(image,name);
1948 if (LocaleCompare(name,"EXIF") == 0)
1950 length=GetStringInfoLength(profile);
1951 if (length > 65533L)
1953 (void) ThrowMagickException(exception,GetMagickModule(),
1954 CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
1958 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
1959 (unsigned int) length);
1961 if (LocaleCompare(name,"ICC") == 0)
1963 register unsigned char
1966 tag_length=strlen(ICC_PROFILE);
1967 p=GetStringInfoDatum(custom_profile);
1968 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1970 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1972 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1973 p[12]=(unsigned char) ((i/65519L)+1);
1974 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1975 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1977 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1978 custom_profile),(unsigned int) (length+tag_length+3));
1981 if (((LocaleCompare(name,"IPTC") == 0) ||
1982 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1984 register unsigned char
1991 p=GetStringInfoDatum(custom_profile);
1992 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1994 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1995 roundup=(size_t) (length & 0x01);
1996 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1998 (void) memcpy(p,"Photoshop 3.0 ",14);
2003 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2005 p[24]=(unsigned char) (length >> 8);
2006 p[25]=(unsigned char) (length & 0xff);
2009 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2011 p[length+tag_length]='\0';
2012 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2013 custom_profile),(unsigned int) (length+tag_length+roundup));
2016 if (LocaleCompare(name,"XMP") == 0)
2022 Add namespace to XMP profile.
2024 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2025 if (xmp_profile != (StringInfo *) NULL)
2027 if (profile != (StringInfo *) NULL)
2028 ConcatenateStringInfo(xmp_profile,profile);
2029 GetStringInfoDatum(xmp_profile)[28]='\0';
2030 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2032 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2033 jpeg_write_marker(jpeg_info,XML_MARKER,
2034 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2036 xmp_profile=DestroyStringInfo(xmp_profile);
2039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2040 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2041 name=GetNextImageProfile(image);
2043 custom_profile=DestroyStringInfo(custom_profile);
2046 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2051 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2052 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2053 destination=(DestinationManager *) cinfo->dest;
2054 destination->manager.init_destination=InitializeDestination;
2055 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2056 destination->manager.term_destination=TerminateDestination;
2057 destination->image=image;
2060 static char **SamplingFactorToList(const char *text)
2074 if (text == (char *) NULL)
2075 return((char **) NULL);
2077 Convert string to an ASCII list.
2079 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2081 if (textlist == (char **) NULL)
2082 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2084 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2086 for (q=(char *) p; *q != '\0'; q++)
2089 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2090 sizeof(*textlist[i]));
2091 if (textlist[i] == (char *) NULL)
2092 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2093 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2100 for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2101 textlist[i]=ConstantString("1x1");
2105 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2106 Image *image,ExceptionInfo *exception)
2117 *volatile volatile_image;
2124 *volatile jpeg_pixels;
2144 struct jpeg_compress_struct
2147 struct jpeg_error_mgr
2156 assert(image_info != (const ImageInfo *) NULL);
2157 assert(image_info->signature == MagickCoreSignature);
2158 assert(image != (Image *) NULL);
2159 assert(image->signature == MagickCoreSignature);
2160 if (image->debug != MagickFalse)
2161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2162 assert(exception != (ExceptionInfo *) NULL);
2163 assert(exception->signature == MagickCoreSignature);
2164 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2165 (image->next != (Image *) NULL))
2166 image=AppendImages(image,MagickFalse,exception);
2167 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2168 if (status == MagickFalse)
2171 Initialize JPEG parameters.
2173 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2174 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2175 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2176 volatile_image=image;
2177 jpeg_info.client_data=(void *) volatile_image;
2178 jpeg_info.err=jpeg_std_error(&jpeg_error);
2179 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2180 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2181 error_manager.exception=exception;
2182 error_manager.image=volatile_image;
2183 memory_info=(MemoryInfo *) NULL;
2184 if (setjmp(error_manager.error_recovery) != 0)
2186 jpeg_destroy_compress(&jpeg_info);
2187 (void) CloseBlob(volatile_image);
2188 return(MagickFalse);
2190 jpeg_info.client_data=(void *) &error_manager;
2191 jpeg_create_compress(&jpeg_info);
2192 JPEGDestinationManager(&jpeg_info,image);
2193 if ((image->columns != (unsigned int) image->columns) ||
2194 (image->rows != (unsigned int) image->rows))
2195 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2196 jpeg_info.image_width=(unsigned int) image->columns;
2197 jpeg_info.image_height=(unsigned int) image->rows;
2198 jpeg_info.input_components=3;
2199 jpeg_info.data_precision=8;
2200 jpeg_info.in_color_space=JCS_RGB;
2201 switch (image->colorspace)
2203 case CMYKColorspace:
2205 jpeg_info.input_components=4;
2206 jpeg_info.in_color_space=JCS_CMYK;
2209 case YCbCrColorspace:
2210 case Rec601YCbCrColorspace:
2211 case Rec709YCbCrColorspace:
2213 jpeg_info.in_color_space=JCS_YCbCr;
2216 case GRAYColorspace:
2218 if (image_info->type == TrueColorType)
2220 jpeg_info.input_components=1;
2221 jpeg_info.in_color_space=JCS_GRAYSCALE;
2226 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2227 if (image_info->type == TrueColorType)
2229 if (SetImageGray(image,exception) != MagickFalse)
2231 jpeg_info.input_components=1;
2232 jpeg_info.in_color_space=JCS_GRAYSCALE;
2237 jpeg_set_defaults(&jpeg_info);
2238 if (jpeg_info.in_color_space == JCS_CMYK)
2239 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2240 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2241 jpeg_info.data_precision=8;
2243 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2244 if (image->debug != MagickFalse)
2245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2246 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2247 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2250 Set image resolution.
2252 jpeg_info.write_JFIF_header=TRUE;
2253 jpeg_info.X_density=(UINT16) image->resolution.x;
2254 jpeg_info.Y_density=(UINT16) image->resolution.y;
2256 Set image resolution units.
2258 if (image->units == PixelsPerInchResolution)
2259 jpeg_info.density_unit=(UINT8) 1;
2260 if (image->units == PixelsPerCentimeterResolution)
2261 jpeg_info.density_unit=(UINT8) 2;
2263 jpeg_info.dct_method=JDCT_FLOAT;
2264 option=GetImageOption(image_info,"jpeg:dct-method");
2265 if (option != (const char *) NULL)
2271 if (LocaleCompare(option,"default") == 0)
2272 jpeg_info.dct_method=JDCT_DEFAULT;
2278 if (LocaleCompare(option,"fastest") == 0)
2279 jpeg_info.dct_method=JDCT_FASTEST;
2280 if (LocaleCompare(option,"float") == 0)
2281 jpeg_info.dct_method=JDCT_FLOAT;
2287 if (LocaleCompare(option,"ifast") == 0)
2288 jpeg_info.dct_method=JDCT_IFAST;
2289 if (LocaleCompare(option,"islow") == 0)
2290 jpeg_info.dct_method=JDCT_ISLOW;
2294 option=GetImageOption(image_info,"jpeg:optimize-coding");
2295 if (option != (const char *) NULL)
2296 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2303 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2304 image->rows*sizeof(JSAMPLE);
2305 if (length == (MagickSizeType) ((size_t) length))
2308 Perform optimization only if available memory resources permit it.
2310 status=AcquireMagickResource(MemoryResource,length);
2311 RelinquishMagickResource(MemoryResource,length);
2312 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2315 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2316 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2317 (image_info->interlace != NoInterlace))
2319 if (image->debug != MagickFalse)
2320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2321 "Interlace: progressive");
2322 jpeg_simple_progression(&jpeg_info);
2325 if (image->debug != MagickFalse)
2326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2327 "Interlace: non-progressive");
2329 if (image->debug != MagickFalse)
2330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2331 "Interlace: nonprogressive");
2334 if ((image_info->compression != LosslessJPEGCompression) &&
2335 (image->quality <= 100))
2337 if (image->quality != UndefinedCompressionQuality)
2338 quality=(int) image->quality;
2339 if (image->debug != MagickFalse)
2340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2341 (double) image->quality);
2345 #if !defined(C_LOSSLESS_SUPPORTED)
2347 if (image->debug != MagickFalse)
2348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2350 if (image->quality < 100)
2351 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2352 "LosslessToLossyJPEGConversion","`%s'",image->filename);
2359 predictor=image->quality/100; /* range 1-7 */
2360 point_transform=image->quality % 20; /* range 0-15 */
2361 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2362 if (image->debug != MagickFalse)
2364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2365 "Compression: lossless");
2366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2367 "Predictor: %d",predictor);
2368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2369 "Point Transform: %d",point_transform);
2374 option=GetImageOption(image_info,"jpeg:extent");
2375 if (option != (const char *) NULL)
2383 extent_info=CloneImageInfo(image_info);
2384 extent_info->blob=NULL;
2385 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2386 if (jpeg_image != (Image *) NULL)
2396 Search for compression quality that does not exceed image extent.
2398 extent_info->quality=0;
2399 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2400 (void) DeleteImageOption(extent_info,"jpeg:extent");
2401 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2402 maximum=image_info->quality;
2405 for (minimum=2; minimum < maximum; )
2407 (void) AcquireUniqueFilename(jpeg_image->filename);
2408 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2409 status=WriteJPEGImage(extent_info,jpeg_image,exception);
2410 if (GetBlobSize(jpeg_image) <= extent)
2411 minimum=jpeg_image->quality+1;
2413 maximum=jpeg_image->quality-1;
2414 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2416 quality=(int) minimum-1;
2417 jpeg_image=DestroyImage(jpeg_image);
2419 extent_info=DestroyImageInfo(extent_info);
2421 jpeg_set_quality(&jpeg_info,quality,TRUE);
2422 #if (JPEG_LIB_VERSION >= 70)
2423 option=GetImageOption(image_info,"quality");
2424 if (option != (const char *) NULL)
2433 Set quality scaling for luminance and chrominance separately.
2435 flags=ParseGeometry(option,&geometry_info);
2436 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2438 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2439 (geometry_info.rho+0.5));
2440 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2441 (geometry_info.sigma+0.5));
2442 jpeg_default_qtables(&jpeg_info,TRUE);
2446 colorspace=jpeg_info.in_color_space;
2447 value=GetImageOption(image_info,"jpeg:colorspace");
2448 if (value == (char *) NULL)
2449 value=GetImageProperty(image,"jpeg:colorspace",exception);
2450 if (value != (char *) NULL)
2451 colorspace=StringToInteger(value);
2452 sampling_factor=(const char *) NULL;
2453 if (colorspace == jpeg_info.in_color_space)
2455 value=GetImageOption(image_info,"jpeg:sampling-factor");
2456 if (value == (char *) NULL)
2457 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2458 if (value != (char *) NULL)
2460 sampling_factor=value;
2461 if (image->debug != MagickFalse)
2462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2463 " Input sampling-factors=%s",sampling_factor);
2466 value=GetImageOption(image_info,"jpeg:sampling-factor");
2467 if (image_info->sampling_factor != (char *) NULL)
2468 sampling_factor=image_info->sampling_factor;
2469 if (sampling_factor == (const char *) NULL)
2472 for (i=0; i < MAX_COMPONENTS; i++)
2474 jpeg_info.comp_info[i].h_samp_factor=1;
2475 jpeg_info.comp_info[i].v_samp_factor=1;
2490 Set sampling factor.
2493 factors=SamplingFactorToList(sampling_factor);
2494 if (factors != (char **) NULL)
2496 for (i=0; i < MAX_COMPONENTS; i++)
2498 if (factors[i] == (char *) NULL)
2500 flags=ParseGeometry(factors[i],&geometry_info);
2501 if ((flags & SigmaValue) == 0)
2502 geometry_info.sigma=geometry_info.rho;
2503 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2504 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2505 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2507 factors=(char **) RelinquishMagickMemory(factors);
2509 for ( ; i < MAX_COMPONENTS; i++)
2511 jpeg_info.comp_info[i].h_samp_factor=1;
2512 jpeg_info.comp_info[i].v_samp_factor=1;
2515 option=GetImageOption(image_info,"jpeg:q-table");
2516 if (option != (const char *) NULL)
2522 Custom quantization tables.
2524 table=GetQuantizationTable(option,"0",exception);
2525 if (table != (QuantizationTable *) NULL)
2527 for (i=0; i < MAX_COMPONENTS; i++)
2528 jpeg_info.comp_info[i].quant_tbl_no=0;
2529 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2530 jpeg_quality_scaling(quality),0);
2531 table=DestroyQuantizationTable(table);
2533 table=GetQuantizationTable(option,"1",exception);
2534 if (table != (QuantizationTable *) NULL)
2536 for (i=1; i < MAX_COMPONENTS; i++)
2537 jpeg_info.comp_info[i].quant_tbl_no=1;
2538 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2539 jpeg_quality_scaling(quality),0);
2540 table=DestroyQuantizationTable(table);
2542 table=GetQuantizationTable(option,"2",exception);
2543 if (table != (QuantizationTable *) NULL)
2545 for (i=2; i < MAX_COMPONENTS; i++)
2546 jpeg_info.comp_info[i].quant_tbl_no=2;
2547 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2548 jpeg_quality_scaling(quality),0);
2549 table=DestroyQuantizationTable(table);
2551 table=GetQuantizationTable(option,"3",exception);
2552 if (table != (QuantizationTable *) NULL)
2554 for (i=3; i < MAX_COMPONENTS; i++)
2555 jpeg_info.comp_info[i].quant_tbl_no=3;
2556 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2557 jpeg_quality_scaling(quality),0);
2558 table=DestroyQuantizationTable(table);
2561 jpeg_start_compress(&jpeg_info,TRUE);
2562 if (image->debug != MagickFalse)
2564 if (image->storage_class == PseudoClass)
2565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2566 "Storage class: PseudoClass");
2568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2569 "Storage class: DirectClass");
2570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2571 (double) image->depth);
2572 if (image->colors != 0)
2573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2574 "Number of colors: %.20g",(double) image->colors);
2576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2577 "Number of colors: unspecified");
2578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2579 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2580 switch (image->colorspace)
2582 case CMYKColorspace:
2584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2585 "Storage class: DirectClass");
2586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2587 "Colorspace: CMYK");
2590 case YCbCrColorspace:
2591 case Rec601YCbCrColorspace:
2592 case Rec709YCbCrColorspace:
2594 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2595 "Colorspace: YCbCr");
2601 switch (image->colorspace)
2603 case CMYKColorspace:
2605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2606 "Colorspace: CMYK");
2607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2608 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2609 jpeg_info.comp_info[0].h_samp_factor,
2610 jpeg_info.comp_info[0].v_samp_factor,
2611 jpeg_info.comp_info[1].h_samp_factor,
2612 jpeg_info.comp_info[1].v_samp_factor,
2613 jpeg_info.comp_info[2].h_samp_factor,
2614 jpeg_info.comp_info[2].v_samp_factor,
2615 jpeg_info.comp_info[3].h_samp_factor,
2616 jpeg_info.comp_info[3].v_samp_factor);
2619 case GRAYColorspace:
2621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2622 "Colorspace: GRAY");
2623 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2624 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2625 jpeg_info.comp_info[0].v_samp_factor);
2628 case sRGBColorspace:
2631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2632 "Image colorspace is RGB");
2633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2634 "Sampling factors: %dx%d,%dx%d,%dx%d",
2635 jpeg_info.comp_info[0].h_samp_factor,
2636 jpeg_info.comp_info[0].v_samp_factor,
2637 jpeg_info.comp_info[1].h_samp_factor,
2638 jpeg_info.comp_info[1].v_samp_factor,
2639 jpeg_info.comp_info[2].h_samp_factor,
2640 jpeg_info.comp_info[2].v_samp_factor);
2643 case YCbCrColorspace:
2644 case Rec601YCbCrColorspace:
2645 case Rec709YCbCrColorspace:
2647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2648 "Colorspace: YCbCr");
2649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2650 "Sampling factors: %dx%d,%dx%d,%dx%d",
2651 jpeg_info.comp_info[0].h_samp_factor,
2652 jpeg_info.comp_info[0].v_samp_factor,
2653 jpeg_info.comp_info[1].h_samp_factor,
2654 jpeg_info.comp_info[1].v_samp_factor,
2655 jpeg_info.comp_info[2].h_samp_factor,
2656 jpeg_info.comp_info[2].v_samp_factor);
2661 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2663 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2664 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2665 jpeg_info.comp_info[0].h_samp_factor,
2666 jpeg_info.comp_info[0].v_samp_factor,
2667 jpeg_info.comp_info[1].h_samp_factor,
2668 jpeg_info.comp_info[1].v_samp_factor,
2669 jpeg_info.comp_info[2].h_samp_factor,
2670 jpeg_info.comp_info[2].v_samp_factor,
2671 jpeg_info.comp_info[3].h_samp_factor,
2672 jpeg_info.comp_info[3].v_samp_factor);
2678 Write JPEG profiles.
2680 value=GetImageProperty(image,"comment",exception);
2681 if (value != (char *) NULL)
2682 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2683 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2684 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2685 if (image->profiles != (void *) NULL)
2686 WriteProfile(&jpeg_info,image,exception);
2688 Convert MIFF to JPEG raster pixels.
2690 memory_info=AcquireVirtualMemory((size_t) image->columns,
2691 jpeg_info.input_components*sizeof(*jpeg_pixels));
2692 if (memory_info == (MemoryInfo *) NULL)
2693 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2694 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2695 if (setjmp(error_manager.error_recovery) != 0)
2697 jpeg_destroy_compress(&jpeg_info);
2698 if (memory_info != (MemoryInfo *) NULL)
2699 memory_info=RelinquishVirtualMemory(memory_info);
2700 (void) CloseBlob(image);
2701 return(MagickFalse);
2703 scanline[0]=(JSAMPROW) jpeg_pixels;
2704 scale=65535/(unsigned short) GetQuantumRange((size_t)
2705 jpeg_info.data_precision);
2708 if (jpeg_info.data_precision <= 8)
2710 if ((jpeg_info.in_color_space == JCS_RGB) ||
2711 (jpeg_info.in_color_space == JCS_YCbCr))
2712 for (y=0; y < (ssize_t) image->rows; y++)
2714 register const Quantum
2720 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2721 if (p == (const Quantum *) NULL)
2724 for (x=0; x < (ssize_t) image->columns; x++)
2726 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2727 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2728 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2729 p+=GetPixelChannels(image);
2731 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2732 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2734 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) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
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 for (y=0; y < (ssize_t) image->rows; y++)
2766 register const Quantum
2772 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2773 if (p == (const Quantum *) NULL)
2776 for (x=0; x < (ssize_t) image->columns; x++)
2779 Convert DirectClass packets to contiguous CMYK scanlines.
2781 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2782 GetPixelCyan(image,p))));
2783 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2784 GetPixelMagenta(image,p))));
2785 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2786 GetPixelYellow(image,p))));
2787 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2788 GetPixelBlack(image,p))));
2789 p+=GetPixelChannels(image);
2791 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2792 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2794 if (status == MagickFalse)
2799 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2800 for (y=0; y < (ssize_t) image->rows; y++)
2802 register const Quantum
2808 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2809 if (p == (const Quantum *) NULL)
2812 for (x=0; x < (ssize_t) image->columns; x++)
2814 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2816 p+=GetPixelChannels(image);
2818 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2819 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2821 if (status == MagickFalse)
2825 if ((jpeg_info.in_color_space == JCS_RGB) ||
2826 (jpeg_info.in_color_space == JCS_YCbCr))
2827 for (y=0; y < (ssize_t) image->rows; y++)
2829 register const Quantum
2835 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2836 if (p == (const Quantum *) NULL)
2839 for (x=0; x < (ssize_t) image->columns; x++)
2841 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2842 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2843 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2844 p+=GetPixelChannels(image);
2846 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2847 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2849 if (status == MagickFalse)
2853 for (y=0; y < (ssize_t) image->rows; y++)
2855 register const Quantum
2861 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2862 if (p == (const Quantum *) NULL)
2865 for (x=0; x < (ssize_t) image->columns; x++)
2868 Convert DirectClass packets to contiguous CMYK scanlines.
2870 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2872 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2874 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2876 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2878 p+=GetPixelChannels(image);
2880 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2881 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2883 if (status == MagickFalse)
2886 if (y == (ssize_t) image->rows)
2887 jpeg_finish_compress(&jpeg_info);
2889 Relinquish resources.
2891 jpeg_destroy_compress(&jpeg_info);
2892 memory_info=RelinquishVirtualMemory(memory_info);
2893 (void) CloseBlob(image);