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 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 option=GetImageOption(image_info,"profile:skip");
1092 if (IsOptionMember("ICC",option) == MagickFalse)
1093 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1094 if (IsOptionMember("IPTC",option) == MagickFalse)
1095 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1096 for (i=1; i < 16; i++)
1097 if ((i != 2) && (i != 13) && (i != 14))
1098 if (IsOptionMember("APP",option) == MagickFalse)
1099 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1100 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1101 if ((image_info->colorspace == YCbCrColorspace) ||
1102 (image_info->colorspace == Rec601YCbCrColorspace) ||
1103 (image_info->colorspace == Rec709YCbCrColorspace))
1104 jpeg_info.out_color_space=JCS_YCbCr;
1106 Set image resolution.
1109 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1110 (jpeg_info.Y_density != 1))
1112 image->resolution.x=(double) jpeg_info.X_density;
1113 image->resolution.y=(double) jpeg_info.Y_density;
1114 units=(size_t) jpeg_info.density_unit;
1117 image->units=PixelsPerInchResolution;
1119 image->units=PixelsPerCentimeterResolution;
1120 number_pixels=(MagickSizeType) image->columns*image->rows;
1121 option=GetImageOption(image_info,"jpeg:size");
1122 if ((option != (const char *) NULL) &&
1123 (jpeg_info.out_color_space != JCS_YCbCr))
1137 flags=ParseGeometry(option,&geometry_info);
1138 if ((flags & SigmaValue) == 0)
1139 geometry_info.sigma=geometry_info.rho;
1140 jpeg_calc_output_dimensions(&jpeg_info);
1141 image->magick_columns=jpeg_info.output_width;
1142 image->magick_rows=jpeg_info.output_height;
1144 if (geometry_info.rho != 0.0)
1145 scale_factor=jpeg_info.output_width/geometry_info.rho;
1146 if ((geometry_info.sigma != 0.0) &&
1147 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1148 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1149 jpeg_info.scale_num=1U;
1150 jpeg_info.scale_denom=(unsigned int) scale_factor;
1151 jpeg_calc_output_dimensions(&jpeg_info);
1152 if (image->debug != MagickFalse)
1153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1154 "Scale factor: %.20g",(double) scale_factor);
1156 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1157 #if defined(D_LOSSLESS_SUPPORTED)
1158 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1159 JPEGInterlace : NoInterlace;
1160 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1161 LosslessJPEGCompression : JPEGCompression;
1162 if (jpeg_info.data_precision > 8)
1163 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1164 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1166 if (jpeg_info.data_precision == 16)
1167 jpeg_info.data_precision=12;
1169 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1171 image->compression=JPEGCompression;
1174 image->compression=JPEGCompression;
1175 image->interlace=JPEGInterlace;
1177 option=GetImageOption(image_info,"jpeg:colors");
1178 if (option != (const char *) NULL)
1181 Let the JPEG library quantize the image.
1183 jpeg_info.quantize_colors=TRUE;
1184 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1186 option=GetImageOption(image_info,"jpeg:block-smoothing");
1187 if (option != (const char *) NULL)
1188 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1190 jpeg_info.dct_method=JDCT_FLOAT;
1191 option=GetImageOption(image_info,"jpeg:dct-method");
1192 if (option != (const char *) NULL)
1198 if (LocaleCompare(option,"default") == 0)
1199 jpeg_info.dct_method=JDCT_DEFAULT;
1205 if (LocaleCompare(option,"fastest") == 0)
1206 jpeg_info.dct_method=JDCT_FASTEST;
1207 if (LocaleCompare(option,"float") == 0)
1208 jpeg_info.dct_method=JDCT_FLOAT;
1214 if (LocaleCompare(option,"ifast") == 0)
1215 jpeg_info.dct_method=JDCT_IFAST;
1216 if (LocaleCompare(option,"islow") == 0)
1217 jpeg_info.dct_method=JDCT_ISLOW;
1221 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1222 if (option != (const char *) NULL)
1223 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1225 (void) jpeg_start_decompress(&jpeg_info);
1226 image->columns=jpeg_info.output_width;
1227 image->rows=jpeg_info.output_height;
1228 image->depth=(size_t) jpeg_info.data_precision;
1229 switch (jpeg_info.out_color_space)
1234 (void) SetImageColorspace(image,sRGBColorspace,exception);
1239 (void) SetImageColorspace(image,GRAYColorspace,exception);
1244 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1249 (void) SetImageColorspace(image,CMYKColorspace,exception);
1253 if (IsITUFaxImage(image) != MagickFalse)
1255 (void) SetImageColorspace(image,LabColorspace,exception);
1256 jpeg_info.out_color_space=JCS_YCbCr;
1258 option=GetImageOption(image_info,"jpeg:colors");
1259 if (option != (const char *) NULL)
1260 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1262 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1263 if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0))
1268 colors=(size_t) GetQuantumRange(image->depth)+1;
1269 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1270 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1272 if (image->debug != MagickFalse)
1274 if (image->interlace != NoInterlace)
1275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1276 "Interlace: progressive");
1278 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1279 "Interlace: nonprogressive");
1280 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1281 (int) jpeg_info.data_precision);
1282 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1283 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1285 JPEGSetImageQuality(&jpeg_info,image);
1286 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1287 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
1288 jpeg_info.out_color_space);
1289 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1290 if (image_info->ping != MagickFalse)
1292 jpeg_destroy_decompress(&jpeg_info);
1293 (void) CloseBlob(image);
1294 return(GetFirstImageInList(image));
1296 status=SetImageExtent(image,image->columns,image->rows,exception);
1297 if (status == MagickFalse)
1299 jpeg_destroy_decompress(&jpeg_info);
1300 return(DestroyImageList(image));
1302 if ((jpeg_info.output_components != 1) &&
1303 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1305 jpeg_destroy_decompress(&jpeg_info);
1306 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1308 memory_info=AcquireVirtualMemory((size_t) image->columns,
1309 jpeg_info.output_components*sizeof(*jpeg_pixels));
1310 if (memory_info == (MemoryInfo *) NULL)
1312 jpeg_destroy_decompress(&jpeg_info);
1313 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1315 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1317 Convert JPEG pixels to pixel packets.
1319 if (setjmp(error_manager.error_recovery) != 0)
1321 if (memory_info != (MemoryInfo *) NULL)
1322 memory_info=RelinquishVirtualMemory(memory_info);
1323 jpeg_destroy_decompress(&jpeg_info);
1324 (void) CloseBlob(image);
1325 number_pixels=(MagickSizeType) image->columns*image->rows;
1326 if (number_pixels != 0)
1327 return(GetFirstImageInList(image));
1328 return(DestroyImage(image));
1330 if (jpeg_info.quantize_colors != 0)
1332 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1333 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1334 for (i=0; i < (ssize_t) image->colors; i++)
1336 image->colormap[i].red=(double) ScaleCharToQuantum(
1337 jpeg_info.colormap[0][i]);
1338 image->colormap[i].green=image->colormap[i].red;
1339 image->colormap[i].blue=image->colormap[i].red;
1340 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1343 for (i=0; i < (ssize_t) image->colors; i++)
1345 image->colormap[i].red=(double) ScaleCharToQuantum(
1346 jpeg_info.colormap[0][i]);
1347 image->colormap[i].green=(double) ScaleCharToQuantum(
1348 jpeg_info.colormap[1][i]);
1349 image->colormap[i].blue=(double) ScaleCharToQuantum(
1350 jpeg_info.colormap[2][i]);
1351 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1354 scanline[0]=(JSAMPROW) jpeg_pixels;
1355 for (y=0; y < (ssize_t) image->rows; y++)
1363 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1365 (void) ThrowMagickException(exception,GetMagickModule(),
1366 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1370 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1371 if (q == (Quantum *) NULL)
1373 if (jpeg_info.data_precision > 8)
1378 scale=65535/(unsigned short) GetQuantumRange((size_t)
1379 jpeg_info.data_precision);
1380 if (jpeg_info.output_components == 1)
1381 for (x=0; x < (ssize_t) image->columns; x++)
1386 pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1387 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1388 SetPixelIndex(image,index,q);
1389 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1391 q+=GetPixelChannels(image);
1394 if (image->colorspace != CMYKColorspace)
1395 for (x=0; x < (ssize_t) image->columns; x++)
1397 SetPixelRed(image,ScaleShortToQuantum(
1398 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1399 SetPixelGreen(image,ScaleShortToQuantum(
1400 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1401 SetPixelBlue(image,ScaleShortToQuantum(
1402 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1403 SetPixelAlpha(image,OpaqueAlpha,q);
1404 q+=GetPixelChannels(image);
1407 for (x=0; x < (ssize_t) image->columns; x++)
1409 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1410 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1411 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1412 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1413 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1414 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1415 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1416 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1417 SetPixelAlpha(image,OpaqueAlpha,q);
1418 q+=GetPixelChannels(image);
1422 if (jpeg_info.output_components == 1)
1423 for (x=0; x < (ssize_t) image->columns; x++)
1425 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) GETJSAMPLE(*p),
1427 SetPixelIndex(image,index,q);
1428 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1430 q+=GetPixelChannels(image);
1433 if (image->colorspace != CMYKColorspace)
1434 for (x=0; x < (ssize_t) image->columns; x++)
1436 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1437 GETJSAMPLE(*p++)),q);
1438 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1439 GETJSAMPLE(*p++)),q);
1440 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1441 GETJSAMPLE(*p++)),q);
1442 SetPixelAlpha(image,OpaqueAlpha,q);
1443 q+=GetPixelChannels(image);
1446 for (x=0; x < (ssize_t) image->columns; x++)
1448 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1449 (unsigned char) GETJSAMPLE(*p++)),q);
1450 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1451 (unsigned char) GETJSAMPLE(*p++)),q);
1452 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1453 (unsigned char) GETJSAMPLE(*p++)),q);
1454 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1455 (unsigned char) GETJSAMPLE(*p++)),q);
1456 SetPixelAlpha(image,OpaqueAlpha,q);
1457 q+=GetPixelChannels(image);
1459 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1461 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1463 if (status == MagickFalse)
1465 jpeg_abort_decompress(&jpeg_info);
1469 if (status != MagickFalse)
1471 error_manager.finished=MagickTrue;
1472 if (setjmp(error_manager.error_recovery) == 0)
1473 (void) jpeg_finish_decompress(&jpeg_info);
1476 Free jpeg resources.
1478 jpeg_destroy_decompress(&jpeg_info);
1479 memory_info=RelinquishVirtualMemory(memory_info);
1480 (void) CloseBlob(image);
1481 return(GetFirstImageInList(image));
1486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490 % R e g i s t e r J P E G I m a g e %
1494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 % RegisterJPEGImage() adds properties for the JPEG image format to
1497 % the list of supported formats. The properties include the image format
1498 % tag, a method to read and/or write the format, whether the format
1499 % supports the saving of more than one frame to the same file or blob,
1500 % whether the format supports native in-memory I/O, and a brief
1501 % description of the format.
1503 % The format of the RegisterJPEGImage method is:
1505 % size_t RegisterJPEGImage(void)
1508 ModuleExport size_t RegisterJPEGImage(void)
1510 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1513 version[MagickPathExtent];
1519 #if defined(JPEG_LIB_VERSION)
1520 (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION);
1522 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1523 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1524 entry->flags^=CoderDecoderThreadSupportFlag;
1526 #if defined(MAGICKCORE_JPEG_DELEGATE)
1527 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1528 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1530 entry->magick=(IsImageFormatHandler *) IsJPEG;
1531 entry->flags^=CoderAdjoinFlag;
1532 entry->flags^=CoderUseExtensionFlag;
1533 if (*version != '\0')
1534 entry->version=ConstantString(version);
1535 entry->mime_type=ConstantString("image/jpeg");
1536 (void) RegisterMagickInfo(entry);
1537 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1538 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1539 entry->flags^=CoderDecoderThreadSupportFlag;
1541 #if defined(MAGICKCORE_JPEG_DELEGATE)
1542 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1543 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1545 entry->magick=(IsImageFormatHandler *) IsJPEG;
1546 entry->flags^=CoderAdjoinFlag;
1547 if (*version != '\0')
1548 entry->version=ConstantString(version);
1549 entry->mime_type=ConstantString("image/jpeg");
1550 (void) RegisterMagickInfo(entry);
1551 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1552 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1553 entry->flags^=CoderDecoderThreadSupportFlag;
1555 #if defined(MAGICKCORE_JPEG_DELEGATE)
1556 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1557 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1559 entry->flags^=CoderAdjoinFlag;
1560 entry->flags^=CoderUseExtensionFlag;
1561 if (*version != '\0')
1562 entry->version=ConstantString(version);
1563 entry->mime_type=ConstantString("image/jpeg");
1564 (void) RegisterMagickInfo(entry);
1565 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1566 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1567 entry->flags^=CoderDecoderThreadSupportFlag;
1569 #if defined(MAGICKCORE_JPEG_DELEGATE)
1570 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1571 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1573 entry->flags^=CoderAdjoinFlag;
1574 entry->flags^=CoderUseExtensionFlag;
1575 if (*version != '\0')
1576 entry->version=ConstantString(version);
1577 entry->mime_type=ConstantString("image/jpeg");
1578 (void) RegisterMagickInfo(entry);
1579 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1580 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1581 entry->flags^=CoderDecoderThreadSupportFlag;
1583 #if defined(MAGICKCORE_JPEG_DELEGATE)
1584 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1585 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1587 entry->flags^=CoderAdjoinFlag;
1588 entry->flags^=CoderUseExtensionFlag;
1589 if (*version != '\0')
1590 entry->version=ConstantString(version);
1591 entry->mime_type=ConstantString("image/jpeg");
1592 (void) RegisterMagickInfo(entry);
1593 return(MagickImageCoderSignature);
1597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % U n r e g i s t e r J P E G I m a g e %
1605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607 % UnregisterJPEGImage() removes format registrations made by the
1608 % JPEG module from the list of supported formats.
1610 % The format of the UnregisterJPEGImage method is:
1612 % UnregisterJPEGImage(void)
1615 ModuleExport void UnregisterJPEGImage(void)
1617 (void) UnregisterMagickInfo("PJPG");
1618 (void) UnregisterMagickInfo("JPS");
1619 (void) UnregisterMagickInfo("JPG");
1620 (void) UnregisterMagickInfo("JPEG");
1621 (void) UnregisterMagickInfo("JPE");
1624 #if defined(MAGICKCORE_JPEG_DELEGATE)
1626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630 % W r i t e J P E G I m a g e %
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 % WriteJPEGImage() writes a JPEG image file and returns it. It
1637 % allocates the memory necessary for the new Image structure and returns a
1638 % pointer to the new image.
1640 % The format of the WriteJPEGImage method is:
1642 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1643 % Image *image,ExceptionInfo *exception)
1645 % A description of each parameter follows:
1647 % o image_info: the image info.
1649 % o jpeg_image: The image.
1651 % o exception: return any errors or warnings in this structure.
1655 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1657 assert(table != (QuantizationTable *) NULL);
1658 if (table->slot != (char *) NULL)
1659 table->slot=DestroyString(table->slot);
1660 if (table->description != (char *) NULL)
1661 table->description=DestroyString(table->description);
1662 if (table->levels != (unsigned int *) NULL)
1663 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1664 table=(QuantizationTable *) RelinquishMagickMemory(table);
1668 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1673 destination=(DestinationManager *) cinfo->dest;
1674 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1675 MaxBufferExtent,destination->buffer);
1676 if (destination->manager.free_in_buffer != MaxBufferExtent)
1677 ERREXIT(cinfo,JERR_FILE_WRITE);
1678 destination->manager.next_output_byte=destination->buffer;
1682 static QuantizationTable *GetQuantizationTable(const char *filename,
1683 const char *slot,ExceptionInfo *exception)
1711 *quantization_tables,
1714 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1715 "Loading quantization tables \"%s\" ...",filename);
1716 table=(QuantizationTable *) NULL;
1717 xml=FileToString(filename,~0UL,exception);
1718 if (xml == (char *) NULL)
1720 quantization_tables=NewXMLTree(xml,exception);
1721 if (quantization_tables == (XMLTreeInfo *) NULL)
1723 xml=DestroyString(xml);
1726 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1727 table_iterator != (XMLTreeInfo *) NULL;
1728 table_iterator=GetNextXMLTreeTag(table_iterator))
1730 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1731 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1733 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1734 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1737 if (table_iterator == (XMLTreeInfo *) NULL)
1739 xml=DestroyString(xml);
1742 description=GetXMLTreeChild(table_iterator,"description");
1743 if (description == (XMLTreeInfo *) NULL)
1745 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1746 "XmlMissingElement","<description>, slot \"%s\"",slot);
1747 quantization_tables=DestroyXMLTree(quantization_tables);
1748 xml=DestroyString(xml);
1751 levels=GetXMLTreeChild(table_iterator,"levels");
1752 if (levels == (XMLTreeInfo *) NULL)
1754 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1755 "XmlMissingElement","<levels>, slot \"%s\"",slot);
1756 quantization_tables=DestroyXMLTree(quantization_tables);
1757 xml=DestroyString(xml);
1760 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1761 if (table == (QuantizationTable *) NULL)
1762 ThrowFatalException(ResourceLimitFatalError,
1763 "UnableToAcquireQuantizationTable");
1764 table->slot=(char *) NULL;
1765 table->description=(char *) NULL;
1766 table->levels=(unsigned int *) NULL;
1767 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1768 if (attribute != (char *) NULL)
1769 table->slot=ConstantString(attribute);
1770 content=GetXMLTreeContent(description);
1771 if (content != (char *) NULL)
1772 table->description=ConstantString(content);
1773 attribute=GetXMLTreeAttribute(levels,"width");
1774 if (attribute == (char *) NULL)
1776 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1777 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1778 quantization_tables=DestroyXMLTree(quantization_tables);
1779 table=DestroyQuantizationTable(table);
1780 xml=DestroyString(xml);
1783 table->width=StringToUnsignedLong(attribute);
1784 if (table->width == 0)
1786 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1787 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1788 quantization_tables=DestroyXMLTree(quantization_tables);
1789 table=DestroyQuantizationTable(table);
1790 xml=DestroyString(xml);
1793 attribute=GetXMLTreeAttribute(levels,"height");
1794 if (attribute == (char *) NULL)
1796 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1797 "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1798 quantization_tables=DestroyXMLTree(quantization_tables);
1799 table=DestroyQuantizationTable(table);
1800 xml=DestroyString(xml);
1803 table->height=StringToUnsignedLong(attribute);
1804 if (table->height == 0)
1806 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1807 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1808 quantization_tables=DestroyXMLTree(quantization_tables);
1809 table=DestroyQuantizationTable(table);
1810 xml=DestroyString(xml);
1813 attribute=GetXMLTreeAttribute(levels,"divisor");
1814 if (attribute == (char *) NULL)
1816 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1817 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1818 quantization_tables=DestroyXMLTree(quantization_tables);
1819 table=DestroyQuantizationTable(table);
1820 xml=DestroyString(xml);
1823 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1824 if (table->divisor == 0.0)
1826 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1827 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1828 quantization_tables=DestroyXMLTree(quantization_tables);
1829 table=DestroyQuantizationTable(table);
1830 xml=DestroyString(xml);
1833 content=GetXMLTreeContent(levels);
1834 if (content == (char *) NULL)
1836 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1837 "XmlMissingContent","<levels>, table \"%s\"",slot);
1838 quantization_tables=DestroyXMLTree(quantization_tables);
1839 table=DestroyQuantizationTable(table);
1840 xml=DestroyString(xml);
1843 length=(size_t) table->width*table->height;
1846 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1847 sizeof(*table->levels));
1848 if (table->levels == (unsigned int *) NULL)
1849 ThrowFatalException(ResourceLimitFatalError,
1850 "UnableToAcquireQuantizationTable");
1851 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1853 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1854 table->divisor+0.5);
1855 while (isspace((int) ((unsigned char) *p)) != 0)
1861 value=InterpretLocaleValue(content,&p);
1865 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1866 "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1867 quantization_tables=DestroyXMLTree(quantization_tables);
1868 table=DestroyQuantizationTable(table);
1869 xml=DestroyString(xml);
1872 for (j=i; j < 64; j++)
1873 table->levels[j]=table->levels[j-1];
1874 quantization_tables=DestroyXMLTree(quantization_tables);
1875 xml=DestroyString(xml);
1879 static void InitializeDestination(j_compress_ptr cinfo)
1884 destination=(DestinationManager *) cinfo->dest;
1885 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1886 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1887 destination->manager.next_output_byte=destination->buffer;
1888 destination->manager.free_in_buffer=MaxBufferExtent;
1891 static void TerminateDestination(j_compress_ptr cinfo)
1896 destination=(DestinationManager *) cinfo->dest;
1897 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1902 count=WriteBlob(destination->image,MaxBufferExtent-
1903 destination->manager.free_in_buffer,destination->buffer);
1904 if (count != (ssize_t)
1905 (MaxBufferExtent-destination->manager.free_in_buffer))
1906 ERREXIT(cinfo,JERR_FILE_WRITE);
1910 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1911 ExceptionInfo *exception)
1933 Save image profile as a APP marker.
1936 custom_profile=AcquireStringInfo(65535L);
1937 ResetImageProfileIterator(image);
1938 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1940 profile=GetImageProfile(image,name);
1941 if (LocaleCompare(name,"EXIF") == 0)
1943 length=GetStringInfoLength(profile);
1944 if (length > 65533L)
1946 (void) ThrowMagickException(exception,GetMagickModule(),
1947 CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
1951 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
1952 (unsigned int) length);
1954 if (LocaleCompare(name,"ICC") == 0)
1956 register unsigned char
1959 tag_length=strlen(ICC_PROFILE);
1960 p=GetStringInfoDatum(custom_profile);
1961 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1963 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1965 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1966 p[12]=(unsigned char) ((i/65519L)+1);
1967 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1968 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1970 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1971 custom_profile),(unsigned int) (length+tag_length+3));
1974 if (((LocaleCompare(name,"IPTC") == 0) ||
1975 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1977 register unsigned char
1984 p=GetStringInfoDatum(custom_profile);
1985 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1987 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1988 roundup=(size_t) (length & 0x01);
1989 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1991 (void) memcpy(p,"Photoshop 3.0 ",14);
1996 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1998 p[24]=(unsigned char) (length >> 8);
1999 p[25]=(unsigned char) (length & 0xff);
2002 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2004 p[length+tag_length]='\0';
2005 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2006 custom_profile),(unsigned int) (length+tag_length+roundup));
2009 if (LocaleCompare(name,"XMP") == 0)
2015 Add namespace to XMP profile.
2017 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2018 if (xmp_profile != (StringInfo *) NULL)
2020 if (profile != (StringInfo *) NULL)
2021 ConcatenateStringInfo(xmp_profile,profile);
2022 GetStringInfoDatum(xmp_profile)[28]='\0';
2023 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2025 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2026 jpeg_write_marker(jpeg_info,XML_MARKER,
2027 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2029 xmp_profile=DestroyStringInfo(xmp_profile);
2032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2033 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2034 name=GetNextImageProfile(image);
2036 custom_profile=DestroyStringInfo(custom_profile);
2039 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2044 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2045 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2046 destination=(DestinationManager *) cinfo->dest;
2047 destination->manager.init_destination=InitializeDestination;
2048 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2049 destination->manager.term_destination=TerminateDestination;
2050 destination->image=image;
2053 static char **SamplingFactorToList(const char *text)
2067 if (text == (char *) NULL)
2068 return((char **) NULL);
2070 Convert string to an ASCII list.
2072 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2074 if (textlist == (char **) NULL)
2075 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2077 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2079 for (q=(char *) p; *q != '\0'; q++)
2082 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2083 sizeof(*textlist[i]));
2084 if (textlist[i] == (char *) NULL)
2085 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2086 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2093 for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2094 textlist[i]=ConstantString("1x1");
2098 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2099 Image *image,ExceptionInfo *exception)
2110 *volatile volatile_image;
2117 *volatile jpeg_pixels;
2137 struct jpeg_compress_struct
2140 struct jpeg_error_mgr
2149 assert(image_info != (const ImageInfo *) NULL);
2150 assert(image_info->signature == MagickCoreSignature);
2151 assert(image != (Image *) NULL);
2152 assert(image->signature == MagickCoreSignature);
2153 if (image->debug != MagickFalse)
2154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2155 assert(exception != (ExceptionInfo *) NULL);
2156 assert(exception->signature == MagickCoreSignature);
2157 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2158 (image->next != (Image *) NULL))
2159 image=AppendImages(image,MagickFalse,exception);
2160 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2161 if (status == MagickFalse)
2164 Initialize JPEG parameters.
2166 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2167 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2168 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2169 volatile_image=image;
2170 jpeg_info.client_data=(void *) volatile_image;
2171 jpeg_info.err=jpeg_std_error(&jpeg_error);
2172 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2173 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2174 error_manager.exception=exception;
2175 error_manager.image=volatile_image;
2176 memory_info=(MemoryInfo *) NULL;
2177 if (setjmp(error_manager.error_recovery) != 0)
2179 jpeg_destroy_compress(&jpeg_info);
2180 (void) CloseBlob(volatile_image);
2181 return(MagickFalse);
2183 jpeg_info.client_data=(void *) &error_manager;
2184 jpeg_create_compress(&jpeg_info);
2185 JPEGDestinationManager(&jpeg_info,image);
2186 if ((image->columns != (unsigned int) image->columns) ||
2187 (image->rows != (unsigned int) image->rows))
2188 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2189 jpeg_info.image_width=(unsigned int) image->columns;
2190 jpeg_info.image_height=(unsigned int) image->rows;
2191 jpeg_info.input_components=3;
2192 jpeg_info.data_precision=8;
2193 jpeg_info.in_color_space=JCS_RGB;
2194 switch (image->colorspace)
2196 case CMYKColorspace:
2198 jpeg_info.input_components=4;
2199 jpeg_info.in_color_space=JCS_CMYK;
2202 case YCbCrColorspace:
2203 case Rec601YCbCrColorspace:
2204 case Rec709YCbCrColorspace:
2206 jpeg_info.in_color_space=JCS_YCbCr;
2209 case GRAYColorspace:
2211 if (image_info->type == TrueColorType)
2213 jpeg_info.input_components=1;
2214 jpeg_info.in_color_space=JCS_GRAYSCALE;
2219 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2220 if (image_info->type == TrueColorType)
2222 if (SetImageGray(image,exception) != MagickFalse)
2224 jpeg_info.input_components=1;
2225 jpeg_info.in_color_space=JCS_GRAYSCALE;
2230 jpeg_set_defaults(&jpeg_info);
2231 if (jpeg_info.in_color_space == JCS_CMYK)
2232 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2233 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2234 jpeg_info.data_precision=8;
2236 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2237 if (image->debug != MagickFalse)
2238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2239 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2240 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2243 Set image resolution.
2245 jpeg_info.write_JFIF_header=TRUE;
2246 jpeg_info.X_density=(UINT16) image->resolution.x;
2247 jpeg_info.Y_density=(UINT16) image->resolution.y;
2249 Set image resolution units.
2251 if (image->units == PixelsPerInchResolution)
2252 jpeg_info.density_unit=(UINT8) 1;
2253 if (image->units == PixelsPerCentimeterResolution)
2254 jpeg_info.density_unit=(UINT8) 2;
2256 jpeg_info.dct_method=JDCT_FLOAT;
2257 option=GetImageOption(image_info,"jpeg:dct-method");
2258 if (option != (const char *) NULL)
2264 if (LocaleCompare(option,"default") == 0)
2265 jpeg_info.dct_method=JDCT_DEFAULT;
2271 if (LocaleCompare(option,"fastest") == 0)
2272 jpeg_info.dct_method=JDCT_FASTEST;
2273 if (LocaleCompare(option,"float") == 0)
2274 jpeg_info.dct_method=JDCT_FLOAT;
2280 if (LocaleCompare(option,"ifast") == 0)
2281 jpeg_info.dct_method=JDCT_IFAST;
2282 if (LocaleCompare(option,"islow") == 0)
2283 jpeg_info.dct_method=JDCT_ISLOW;
2287 option=GetImageOption(image_info,"jpeg:optimize-coding");
2288 if (option != (const char *) NULL)
2289 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2296 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2297 image->rows*sizeof(JSAMPLE);
2298 if (length == (MagickSizeType) ((size_t) length))
2301 Perform optimization only if available memory resources permit it.
2303 status=AcquireMagickResource(MemoryResource,length);
2304 RelinquishMagickResource(MemoryResource,length);
2305 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2308 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2309 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2310 (image_info->interlace != NoInterlace))
2312 if (image->debug != MagickFalse)
2313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2314 "Interlace: progressive");
2315 jpeg_simple_progression(&jpeg_info);
2318 if (image->debug != MagickFalse)
2319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2320 "Interlace: non-progressive");
2322 if (image->debug != MagickFalse)
2323 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2324 "Interlace: nonprogressive");
2327 if ((image_info->compression != LosslessJPEGCompression) &&
2328 (image->quality <= 100))
2330 if (image->quality != UndefinedCompressionQuality)
2331 quality=(int) image->quality;
2332 if (image->debug != MagickFalse)
2333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2334 (double) image->quality);
2338 #if !defined(C_LOSSLESS_SUPPORTED)
2340 if (image->debug != MagickFalse)
2341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2343 if (image->quality < 100)
2344 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2345 "LosslessToLossyJPEGConversion","`%s'",image->filename);
2352 predictor=image->quality/100; /* range 1-7 */
2353 point_transform=image->quality % 20; /* range 0-15 */
2354 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2355 if (image->debug != MagickFalse)
2357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2358 "Compression: lossless");
2359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2360 "Predictor: %d",predictor);
2361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2362 "Point Transform: %d",point_transform);
2367 option=GetImageOption(image_info,"jpeg:extent");
2368 if (option != (const char *) NULL)
2376 extent_info=CloneImageInfo(image_info);
2377 extent_info->blob=NULL;
2378 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2379 if (jpeg_image != (Image *) NULL)
2389 Search for compression quality that does not exceed image extent.
2391 extent_info->quality=0;
2392 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2393 (void) DeleteImageOption(extent_info,"jpeg:extent");
2394 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2395 maximum=image_info->quality;
2398 for (minimum=2; minimum < maximum; )
2400 (void) AcquireUniqueFilename(jpeg_image->filename);
2401 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2402 status=WriteJPEGImage(extent_info,jpeg_image,exception);
2403 if (GetBlobSize(jpeg_image) <= extent)
2404 minimum=jpeg_image->quality+1;
2406 maximum=jpeg_image->quality-1;
2407 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2409 quality=(int) minimum-1;
2410 jpeg_image=DestroyImage(jpeg_image);
2412 extent_info=DestroyImageInfo(extent_info);
2414 jpeg_set_quality(&jpeg_info,quality,TRUE);
2415 #if (JPEG_LIB_VERSION >= 70)
2416 option=GetImageOption(image_info,"quality");
2417 if (option != (const char *) NULL)
2426 Set quality scaling for luminance and chrominance separately.
2428 flags=ParseGeometry(option,&geometry_info);
2429 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2431 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2432 (geometry_info.rho+0.5));
2433 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2434 (geometry_info.sigma+0.5));
2435 jpeg_default_qtables(&jpeg_info,TRUE);
2439 colorspace=jpeg_info.in_color_space;
2440 value=GetImageOption(image_info,"jpeg:colorspace");
2441 if (value == (char *) NULL)
2442 value=GetImageProperty(image,"jpeg:colorspace",exception);
2443 if (value != (char *) NULL)
2444 colorspace=StringToInteger(value);
2445 sampling_factor=(const char *) NULL;
2446 if (colorspace == jpeg_info.in_color_space)
2448 value=GetImageOption(image_info,"jpeg:sampling-factor");
2449 if (value == (char *) NULL)
2450 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2451 if (value != (char *) NULL)
2453 sampling_factor=value;
2454 if (image->debug != MagickFalse)
2455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2456 " Input sampling-factors=%s",sampling_factor);
2459 value=GetImageOption(image_info,"jpeg:sampling-factor");
2460 if (image_info->sampling_factor != (char *) NULL)
2461 sampling_factor=image_info->sampling_factor;
2462 if (sampling_factor == (const char *) NULL)
2465 for (i=0; i < MAX_COMPONENTS; i++)
2467 jpeg_info.comp_info[i].h_samp_factor=1;
2468 jpeg_info.comp_info[i].v_samp_factor=1;
2483 Set sampling factor.
2486 factors=SamplingFactorToList(sampling_factor);
2487 if (factors != (char **) NULL)
2489 for (i=0; i < MAX_COMPONENTS; i++)
2491 if (factors[i] == (char *) NULL)
2493 flags=ParseGeometry(factors[i],&geometry_info);
2494 if ((flags & SigmaValue) == 0)
2495 geometry_info.sigma=geometry_info.rho;
2496 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2497 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2498 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2500 factors=(char **) RelinquishMagickMemory(factors);
2502 for ( ; i < MAX_COMPONENTS; i++)
2504 jpeg_info.comp_info[i].h_samp_factor=1;
2505 jpeg_info.comp_info[i].v_samp_factor=1;
2508 option=GetImageOption(image_info,"jpeg:q-table");
2509 if (option != (const char *) NULL)
2515 Custom quantization tables.
2517 table=GetQuantizationTable(option,"0",exception);
2518 if (table != (QuantizationTable *) NULL)
2520 for (i=0; i < MAX_COMPONENTS; i++)
2521 jpeg_info.comp_info[i].quant_tbl_no=0;
2522 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2523 jpeg_quality_scaling(quality),0);
2524 table=DestroyQuantizationTable(table);
2526 table=GetQuantizationTable(option,"1",exception);
2527 if (table != (QuantizationTable *) NULL)
2529 for (i=1; i < MAX_COMPONENTS; i++)
2530 jpeg_info.comp_info[i].quant_tbl_no=1;
2531 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2532 jpeg_quality_scaling(quality),0);
2533 table=DestroyQuantizationTable(table);
2535 table=GetQuantizationTable(option,"2",exception);
2536 if (table != (QuantizationTable *) NULL)
2538 for (i=2; i < MAX_COMPONENTS; i++)
2539 jpeg_info.comp_info[i].quant_tbl_no=2;
2540 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2541 jpeg_quality_scaling(quality),0);
2542 table=DestroyQuantizationTable(table);
2544 table=GetQuantizationTable(option,"3",exception);
2545 if (table != (QuantizationTable *) NULL)
2547 for (i=3; i < MAX_COMPONENTS; i++)
2548 jpeg_info.comp_info[i].quant_tbl_no=3;
2549 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2550 jpeg_quality_scaling(quality),0);
2551 table=DestroyQuantizationTable(table);
2554 jpeg_start_compress(&jpeg_info,TRUE);
2555 if (image->debug != MagickFalse)
2557 if (image->storage_class == PseudoClass)
2558 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2559 "Storage class: PseudoClass");
2561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2562 "Storage class: DirectClass");
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2564 (double) image->depth);
2565 if (image->colors != 0)
2566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2567 "Number of colors: %.20g",(double) image->colors);
2569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2570 "Number of colors: unspecified");
2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2572 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2573 switch (image->colorspace)
2575 case CMYKColorspace:
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2578 "Storage class: DirectClass");
2579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2580 "Colorspace: CMYK");
2583 case YCbCrColorspace:
2584 case Rec601YCbCrColorspace:
2585 case Rec709YCbCrColorspace:
2587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2588 "Colorspace: YCbCr");
2594 switch (image->colorspace)
2596 case CMYKColorspace:
2598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2599 "Colorspace: CMYK");
2600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2601 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2602 jpeg_info.comp_info[0].h_samp_factor,
2603 jpeg_info.comp_info[0].v_samp_factor,
2604 jpeg_info.comp_info[1].h_samp_factor,
2605 jpeg_info.comp_info[1].v_samp_factor,
2606 jpeg_info.comp_info[2].h_samp_factor,
2607 jpeg_info.comp_info[2].v_samp_factor,
2608 jpeg_info.comp_info[3].h_samp_factor,
2609 jpeg_info.comp_info[3].v_samp_factor);
2612 case GRAYColorspace:
2614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2615 "Colorspace: GRAY");
2616 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2617 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2618 jpeg_info.comp_info[0].v_samp_factor);
2621 case sRGBColorspace:
2624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2625 "Image colorspace is RGB");
2626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2627 "Sampling factors: %dx%d,%dx%d,%dx%d",
2628 jpeg_info.comp_info[0].h_samp_factor,
2629 jpeg_info.comp_info[0].v_samp_factor,
2630 jpeg_info.comp_info[1].h_samp_factor,
2631 jpeg_info.comp_info[1].v_samp_factor,
2632 jpeg_info.comp_info[2].h_samp_factor,
2633 jpeg_info.comp_info[2].v_samp_factor);
2636 case YCbCrColorspace:
2637 case Rec601YCbCrColorspace:
2638 case Rec709YCbCrColorspace:
2640 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2641 "Colorspace: YCbCr");
2642 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2643 "Sampling factors: %dx%d,%dx%d,%dx%d",
2644 jpeg_info.comp_info[0].h_samp_factor,
2645 jpeg_info.comp_info[0].v_samp_factor,
2646 jpeg_info.comp_info[1].h_samp_factor,
2647 jpeg_info.comp_info[1].v_samp_factor,
2648 jpeg_info.comp_info[2].h_samp_factor,
2649 jpeg_info.comp_info[2].v_samp_factor);
2654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2657 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2658 jpeg_info.comp_info[0].h_samp_factor,
2659 jpeg_info.comp_info[0].v_samp_factor,
2660 jpeg_info.comp_info[1].h_samp_factor,
2661 jpeg_info.comp_info[1].v_samp_factor,
2662 jpeg_info.comp_info[2].h_samp_factor,
2663 jpeg_info.comp_info[2].v_samp_factor,
2664 jpeg_info.comp_info[3].h_samp_factor,
2665 jpeg_info.comp_info[3].v_samp_factor);
2671 Write JPEG profiles.
2673 value=GetImageProperty(image,"comment",exception);
2674 if (value != (char *) NULL)
2675 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2676 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2677 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2678 if (image->profiles != (void *) NULL)
2679 WriteProfile(&jpeg_info,image,exception);
2681 Convert MIFF to JPEG raster pixels.
2683 memory_info=AcquireVirtualMemory((size_t) image->columns,
2684 jpeg_info.input_components*sizeof(*jpeg_pixels));
2685 if (memory_info == (MemoryInfo *) NULL)
2686 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2687 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2688 if (setjmp(error_manager.error_recovery) != 0)
2690 jpeg_destroy_compress(&jpeg_info);
2691 if (memory_info != (MemoryInfo *) NULL)
2692 memory_info=RelinquishVirtualMemory(memory_info);
2693 (void) CloseBlob(image);
2694 return(MagickFalse);
2696 scanline[0]=(JSAMPROW) jpeg_pixels;
2697 scale=65535/(unsigned short) GetQuantumRange((size_t)
2698 jpeg_info.data_precision);
2701 if (jpeg_info.data_precision <= 8)
2703 if ((jpeg_info.in_color_space == JCS_RGB) ||
2704 (jpeg_info.in_color_space == JCS_YCbCr))
2705 for (y=0; y < (ssize_t) image->rows; y++)
2707 register const Quantum
2713 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2714 if (p == (const Quantum *) NULL)
2717 for (x=0; x < (ssize_t) image->columns; x++)
2719 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2720 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2721 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2722 p+=GetPixelChannels(image);
2724 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2725 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2727 if (status == MagickFalse)
2731 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2732 for (y=0; y < (ssize_t) image->rows; y++)
2734 register const Quantum
2740 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2741 if (p == (const Quantum *) NULL)
2744 for (x=0; x < (ssize_t) image->columns; x++)
2746 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2748 p+=GetPixelChannels(image);
2750 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2751 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2753 if (status == MagickFalse)
2757 for (y=0; y < (ssize_t) image->rows; y++)
2759 register const Quantum
2765 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2766 if (p == (const Quantum *) NULL)
2769 for (x=0; x < (ssize_t) image->columns; x++)
2772 Convert DirectClass packets to contiguous CMYK scanlines.
2774 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2775 GetPixelCyan(image,p))));
2776 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2777 GetPixelMagenta(image,p))));
2778 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2779 GetPixelYellow(image,p))));
2780 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2781 GetPixelBlack(image,p))));
2782 p+=GetPixelChannels(image);
2784 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2785 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2787 if (status == MagickFalse)
2792 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2793 for (y=0; y < (ssize_t) image->rows; y++)
2795 register const Quantum
2801 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2802 if (p == (const Quantum *) NULL)
2805 for (x=0; x < (ssize_t) image->columns; x++)
2807 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2809 p+=GetPixelChannels(image);
2811 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2812 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2814 if (status == MagickFalse)
2818 if ((jpeg_info.in_color_space == JCS_RGB) ||
2819 (jpeg_info.in_color_space == JCS_YCbCr))
2820 for (y=0; y < (ssize_t) image->rows; y++)
2822 register const Quantum
2828 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2829 if (p == (const Quantum *) NULL)
2832 for (x=0; x < (ssize_t) image->columns; x++)
2834 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2835 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2836 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2837 p+=GetPixelChannels(image);
2839 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2840 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2842 if (status == MagickFalse)
2846 for (y=0; y < (ssize_t) image->rows; y++)
2848 register const Quantum
2854 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2855 if (p == (const Quantum *) NULL)
2858 for (x=0; x < (ssize_t) image->columns; x++)
2861 Convert DirectClass packets to contiguous CMYK scanlines.
2863 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2865 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2867 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2869 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2871 p+=GetPixelChannels(image);
2873 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2874 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2876 if (status == MagickFalse)
2879 if (y == (ssize_t) image->rows)
2880 jpeg_finish_compress(&jpeg_info);
2882 Relinquish resources.
2884 jpeg_destroy_compress(&jpeg_info);
2885 memory_info=RelinquishVirtualMemory(memory_info);
2886 (void) CloseBlob(image);