2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
46 #include "magick/studio.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/color.h"
51 #include "magick/colormap-private.h"
52 #include "magick/color-private.h"
53 #include "magick/colorspace.h"
54 #include "magick/constitute.h"
55 #include "magick/exception.h"
56 #include "magick/exception-private.h"
57 #include "magick/geometry.h"
58 #include "magick/image.h"
59 #include "magick/image-private.h"
60 #include "magick/list.h"
61 #include "magick/log.h"
62 #include "magick/magick.h"
63 #include "magick/memory_.h"
64 #include "magick/module.h"
65 #include "magick/monitor.h"
66 #include "magick/monitor-private.h"
67 #include "magick/option.h"
68 #include "magick/profile.h"
69 #include "magick/property.h"
70 #include "magick/quantum-private.h"
71 #include "magick/resource_.h"
72 #include "magick/splay-tree.h"
73 #include "magick/static.h"
74 #include "magick/string_.h"
75 #include "magick/string-private.h"
76 #include "magick/utility.h"
78 #if defined(MAGICKCORE_JPEG_DELEGATE)
79 #define JPEG_INTERNAL_OPTIONS
80 #if defined(__MINGW32__)
81 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
91 #define ICC_MARKER (JPEG_APP0+2)
92 #define ICC_PROFILE "ICC_PROFILE"
93 #define IPTC_MARKER (JPEG_APP0+13)
94 #define XML_MARKER (JPEG_APP0+1)
95 #define MaxBufferExtent 8192
100 #if defined(MAGICKCORE_JPEG_DELEGATE)
101 typedef struct _DestinationManager
103 struct jpeg_destination_mgr
111 } DestinationManager;
113 typedef struct _ErrorManager
122 typedef struct _SourceManager
124 struct jpeg_source_mgr
139 Forward declarations.
141 #if defined(MAGICKCORE_JPEG_DELEGATE)
142 static MagickBooleanType
143 WriteJPEGImage(const ImageInfo *,Image *);
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 % IsJPEG() returns MagickTrue if the image format type, identified by the
158 % magick string, is JPEG.
160 % The format of the IsJPEG method is:
162 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
164 % A description of each parameter follows:
166 % o magick: compare image format pattern against these bytes.
168 % o length: Specifies the length of the magick string.
171 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
175 if (memcmp(magick,"\377\330\377",3) == 0)
180 #if defined(MAGICKCORE_JPEG_DELEGATE)
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 % R e a d J P E G I m a g e %
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
193 % the memory necessary for the new Image structure and returns a pointer to
196 % The format of the ReadJPEGImage method is:
198 % Image *ReadJPEGImage(const ImageInfo *image_info,
199 % ExceptionInfo *exception)
201 % A description of each parameter follows:
203 % o image_info: the image info.
205 % o exception: return any errors or warnings in this structure.
209 static MagickBooleanType EmitMessage(j_common_ptr jpeg_info,int level)
212 message[JMSG_LENGTH_MAX];
220 (jpeg_info->err->format_message)(jpeg_info,message);
221 error_manager=(ErrorManager *) jpeg_info->client_data;
222 image=error_manager->image;
225 if ((jpeg_info->err->num_warnings == 0) ||
226 (jpeg_info->err->trace_level >= 3))
227 ThrowBinaryException(CorruptImageWarning,(char *) message,
229 jpeg_info->err->num_warnings++;
232 if (jpeg_info->err->trace_level >= level)
233 ThrowBinaryException(CoderError,(char *) message,image->filename);
237 static boolean FillInputBuffer(j_decompress_ptr cinfo)
242 source=(SourceManager *) cinfo->src;
243 source->manager.bytes_in_buffer=(size_t)
244 ReadBlob(source->image,MaxBufferExtent,source->buffer);
245 if (source->manager.bytes_in_buffer == 0)
247 if (source->start_of_blob != 0)
248 ERREXIT(cinfo,JERR_INPUT_EMPTY);
249 WARNMS(cinfo,JWRN_JPEG_EOF);
250 source->buffer[0]=(JOCTET) 0xff;
251 source->buffer[1]=(JOCTET) JPEG_EOI;
252 source->manager.bytes_in_buffer=2;
254 source->manager.next_input_byte=source->buffer;
255 source->start_of_blob=FALSE;
259 static int GetCharacter(j_decompress_ptr jpeg_info)
261 if (jpeg_info->src->bytes_in_buffer == 0)
262 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
263 jpeg_info->src->bytes_in_buffer--;
264 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
267 static void InitializeSource(j_decompress_ptr cinfo)
272 source=(SourceManager *) cinfo->src;
273 source->start_of_blob=TRUE;
276 static MagickBooleanType IsITUFaxImage(const Image *image)
284 profile=GetImageProfile(image,"8bim");
285 if (profile == (const StringInfo *) NULL)
287 if (GetStringInfoLength(profile) < 5)
289 datum=GetStringInfoDatum(profile);
290 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
291 (datum[3] == 0x41) && (datum[4] == 0x58))
296 static void JPEGErrorHandler(j_common_ptr jpeg_info)
301 (void) EmitMessage(jpeg_info,0);
302 error_manager=(ErrorManager *) jpeg_info->client_data;
303 longjmp(error_manager->error_recovery,1);
306 static boolean ReadComment(j_decompress_ptr jpeg_info)
327 Determine length of comment.
329 error_manager=(ErrorManager *) jpeg_info->client_data;
330 image=error_manager->image;
331 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
332 length+=GetCharacter(jpeg_info);
336 comment=(char *) NULL;
337 if (~length >= MaxTextExtent)
338 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
340 if (comment == (char *) NULL)
341 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
347 for (p=comment; i-- >= 0; p++)
348 *p=(char) GetCharacter(jpeg_info);
350 (void) SetImageProperty(image,"comment",comment);
351 comment=DestroyString(comment);
355 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
372 register unsigned char
385 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
386 length+=(size_t) GetCharacter(jpeg_info);
391 (void) GetCharacter(jpeg_info);
394 for (i=0; i < 12; i++)
395 magick[i]=(char) GetCharacter(jpeg_info);
396 if (LocaleCompare(magick,ICC_PROFILE) != 0)
399 Not a ICC profile, return.
401 for (i=0; i < (long) (length-12); i++)
402 (void) GetCharacter(jpeg_info);
405 (void) GetCharacter(jpeg_info); /* id */
406 (void) GetCharacter(jpeg_info); /* markers */
408 error_manager=(ErrorManager *) jpeg_info->client_data;
409 image=error_manager->image;
410 profile=AcquireStringInfo(length);
411 if (profile == (StringInfo *) NULL)
412 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
414 p=GetStringInfoDatum(profile);
415 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
416 *p++=(unsigned char) GetCharacter(jpeg_info);
417 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
418 if (icc_profile != (StringInfo *) NULL)
420 ConcatenateStringInfo(icc_profile,profile);
421 profile=DestroyStringInfo(profile);
425 status=SetImageProfile(image,"icc",profile);
426 profile=DestroyStringInfo(profile);
427 if (status == MagickFalse)
428 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
431 if (image->debug != MagickFalse)
432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
433 "Profile: ICC, %lu bytes",(unsigned long) length);
437 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
440 magick[MaxTextExtent];
454 register unsigned char
465 Determine length of binary data stored here.
467 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
468 length+=(size_t) GetCharacter(jpeg_info);
473 (void) GetCharacter(jpeg_info);
477 Validate that this was written as a Photoshop resource format slug.
479 for (i=0; i < 10; i++)
480 magick[i]=(char) GetCharacter(jpeg_info);
485 if (LocaleCompare(magick,"Photoshop ") != 0)
488 Not a IPTC profile, return.
490 for (i=0; i < (long) length; i++)
491 (void) GetCharacter(jpeg_info);
495 Remove the version number.
497 for (i=0; i < 4; i++)
498 (void) GetCharacter(jpeg_info);
504 error_manager=(ErrorManager *) jpeg_info->client_data;
505 image=error_manager->image;
506 profile=AcquireStringInfo(length);
507 if (profile == (StringInfo *) NULL)
508 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
510 p=GetStringInfoDatum(profile);
511 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
512 *p++=(unsigned char) GetCharacter(jpeg_info);
513 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
514 if (iptc_profile != (StringInfo *) NULL)
516 ConcatenateStringInfo(iptc_profile,profile);
517 profile=DestroyStringInfo(profile);
521 status=SetImageProfile(image,"8bim",profile);
522 profile=DestroyStringInfo(profile);
523 if (status == MagickFalse)
524 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
527 if (image->debug != MagickFalse)
528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
529 "Profile: iptc, %lu bytes",(unsigned long) length);
533 static boolean ReadProfile(j_decompress_ptr jpeg_info)
553 register unsigned char
563 Read generic profile.
565 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
566 length+=(size_t) GetCharacter(jpeg_info);
570 marker=jpeg_info->unread_marker-JPEG_APP0;
571 (void) FormatMagickString(name,MaxTextExtent,"APP%d",marker);
572 error_manager=(ErrorManager *) jpeg_info->client_data;
573 image=error_manager->image;
574 profile=AcquireStringInfo(length);
575 if (profile == (StringInfo *) NULL)
576 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
578 p=GetStringInfoDatum(profile);
579 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
580 *p++=(unsigned char) GetCharacter(jpeg_info);
583 p=GetStringInfoDatum(profile);
584 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
585 (void) CopyMagickString(name,"exif",MaxTextExtent);
586 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
592 Extract namespace from XMP profile.
594 p=GetStringInfoDatum(profile);
595 for (j=0; j < (long) GetStringInfoLength(profile); j++)
601 if (j < (long) GetStringInfoLength(profile))
602 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
603 (void) CopyMagickString(name,"xmp",MaxTextExtent);
606 status=SetImageProfile(image,name,profile);
607 profile=DestroyStringInfo(profile);
608 if (status == MagickFalse)
609 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
611 if (image->debug != MagickFalse)
612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
613 "Profile: %s, %lu bytes",name,(unsigned long) length);
617 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
622 if (number_bytes <= 0)
624 source=(SourceManager *) cinfo->src;
625 while (number_bytes > (long) source->manager.bytes_in_buffer)
627 number_bytes-=(long) source->manager.bytes_in_buffer;
628 (void) FillInputBuffer(cinfo);
630 source->manager.next_input_byte+=(size_t) number_bytes;
631 source->manager.bytes_in_buffer-=(size_t) number_bytes;
634 static void TerminateSource(j_decompress_ptr cinfo)
639 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
644 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
645 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
646 source=(SourceManager *) cinfo->src;
647 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
648 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
649 source=(SourceManager *) cinfo->src;
650 source->manager.init_source=InitializeSource;
651 source->manager.fill_input_buffer=FillInputBuffer;
652 source->manager.skip_input_data=SkipInputData;
653 source->manager.resync_to_restart=jpeg_resync_to_restart;
654 source->manager.term_source=TerminateSource;
655 source->manager.bytes_in_buffer=0;
656 source->manager.next_input_byte=NULL;
660 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
663 image->quality=UndefinedCompressionQuality;
664 #if defined(D_PROGRESSIVE_SUPPORTED)
665 if (image->compression == LosslessJPEGCompression)
668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
669 "Quality: 100 (lossless)");
683 Determine the JPEG compression quality from the quantization tables.
686 for (i=0; i < NUM_QUANT_TBLS; i++)
688 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
689 for (j=0; j < DCTSIZE2; j++)
690 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
692 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
693 (jpeg_info->quant_tbl_ptrs[1] != NULL))
698 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
699 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
700 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
701 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
702 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
703 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
704 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
705 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
706 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
707 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
712 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
713 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
714 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
715 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
716 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
717 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
718 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
719 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
720 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
721 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
722 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
726 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
727 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
728 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
729 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
730 for (i=0; i < 100; i++)
732 if ((qvalue < hash[i]) && (sum < sums[i]))
734 if ((qvalue <= hash[i]) && (sum <= sums[i]))
735 image->quality=(unsigned long) i+1;
736 if (image->debug != MagickFalse)
738 if (image->quality != UndefinedCompressionQuality)
739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
740 "Quality: %ld",image->quality);
742 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
743 "Quality: %ld (approximate)",i+1);
749 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
754 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
755 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
756 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
757 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
758 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
759 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
760 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
761 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
762 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
763 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
768 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
769 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
770 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
771 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
772 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
773 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
774 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
775 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
776 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
777 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
778 667, 592, 518, 441, 369, 292, 221, 151, 86,
782 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
783 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
784 for (i=0; i < 100; i++)
786 if ((qvalue < hash[i]) && (sum < sums[i]))
788 image->quality=(unsigned long) i+1;
789 if (image->debug != MagickFalse)
791 if ((qvalue > hash[i]) || (sum > sums[i]))
792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
793 "Quality: %ld (approximate)",i+1);
795 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
804 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
807 sampling_factor[MaxTextExtent];
809 switch (jpeg_info->out_color_space)
813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
814 (void) FormatMagickString(sampling_factor,MaxTextExtent,
815 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
816 jpeg_info->comp_info[0].v_samp_factor,
817 jpeg_info->comp_info[1].h_samp_factor,
818 jpeg_info->comp_info[1].v_samp_factor,
819 jpeg_info->comp_info[2].h_samp_factor,
820 jpeg_info->comp_info[2].v_samp_factor,
821 jpeg_info->comp_info[3].h_samp_factor,
822 jpeg_info->comp_info[3].v_samp_factor);
827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
828 "Colorspace: GRAYSCALE");
829 (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
830 jpeg_info->comp_info[0].h_samp_factor,
831 jpeg_info->comp_info[0].v_samp_factor);
836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
837 (void) FormatMagickString(sampling_factor,MaxTextExtent,
838 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
839 jpeg_info->comp_info[0].v_samp_factor,
840 jpeg_info->comp_info[1].h_samp_factor,
841 jpeg_info->comp_info[1].v_samp_factor,
842 jpeg_info->comp_info[2].h_samp_factor,
843 jpeg_info->comp_info[2].v_samp_factor);
848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
849 jpeg_info->out_color_space);
850 (void) FormatMagickString(sampling_factor,MaxTextExtent,
851 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
852 jpeg_info->comp_info[0].v_samp_factor,
853 jpeg_info->comp_info[1].h_samp_factor,
854 jpeg_info->comp_info[1].v_samp_factor,
855 jpeg_info->comp_info[2].h_samp_factor,
856 jpeg_info->comp_info[2].v_samp_factor,
857 jpeg_info->comp_info[3].h_samp_factor,
858 jpeg_info->comp_info[3].v_samp_factor);
862 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
864 "Sampling Factors: %s",sampling_factor);
867 static Image *ReadJPEGImage(const ImageInfo *image_info,
868 ExceptionInfo *exception)
871 value[MaxTextExtent];
904 struct jpeg_decompress_struct
907 struct jpeg_error_mgr
920 assert(image_info != (const ImageInfo *) NULL);
921 assert(image_info->signature == MagickSignature);
922 if (image_info->debug != MagickFalse)
923 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
924 image_info->filename);
925 assert(exception != (ExceptionInfo *) NULL);
926 assert(exception->signature == MagickSignature);
927 debug=IsEventLogging();
928 image=AcquireImage(image_info);
929 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
930 if (status == MagickFalse)
932 image=DestroyImageList(image);
933 return((Image *) NULL);
936 Initialize JPEG parameters.
938 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
939 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
940 jpeg_info.err=jpeg_std_error(&jpeg_error);
941 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
942 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
943 jpeg_pixels=(JSAMPLE *) NULL;
944 error_manager.image=image;
945 if (setjmp(error_manager.error_recovery) != 0)
947 jpeg_destroy_decompress(&jpeg_info);
948 (void) CloseBlob(image);
949 number_pixels=(MagickSizeType) image->columns*image->rows;
950 if (number_pixels != 0)
951 return(GetFirstImageInList(image));
952 InheritException(exception,&image->exception);
953 return(DestroyImage(image));
955 jpeg_info.client_data=(void *) &error_manager;
956 jpeg_create_decompress(&jpeg_info);
957 JPEGSourceManager(&jpeg_info,image);
958 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
959 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
960 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
961 for (i=1; i < 16; i++)
962 if ((i != 2) && (i != 13) && (i != 14))
963 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
964 i=jpeg_read_header(&jpeg_info,MagickTrue);
965 if ((image_info->colorspace == YCbCrColorspace) ||
966 (image_info->colorspace == Rec601YCbCrColorspace) ||
967 (image_info->colorspace == Rec709YCbCrColorspace))
968 jpeg_info.out_color_space=JCS_YCbCr;
969 if (IsITUFaxImage(image) != MagickFalse)
971 image->colorspace=LabColorspace;
972 jpeg_info.out_color_space=JCS_YCbCr;
975 if (jpeg_info.out_color_space == JCS_CMYK)
976 image->colorspace=CMYKColorspace;
978 Set image resolution.
981 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
982 (jpeg_info.Y_density != 1))
984 image->x_resolution=(double) jpeg_info.X_density;
985 image->y_resolution=(double) jpeg_info.Y_density;
986 units=(unsigned long) jpeg_info.density_unit;
989 image->units=PixelsPerInchResolution;
991 image->units=PixelsPerCentimeterResolution;
992 number_pixels=(MagickSizeType) image->columns*image->rows;
993 option=GetImageOption(image_info,"jpeg:size");
994 if (option != (const char *) NULL)
1008 flags=ParseGeometry(option,&geometry_info);
1009 if ((flags & SigmaValue) == 0)
1010 geometry_info.sigma=geometry_info.rho;
1011 jpeg_calc_output_dimensions(&jpeg_info);
1012 image->magick_columns=jpeg_info.output_width;
1013 image->magick_rows=jpeg_info.output_height;
1015 if (geometry_info.rho != 0.0)
1016 scale_factor=jpeg_info.output_width/geometry_info.rho;
1017 if ((geometry_info.sigma != 0.0) &&
1018 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1019 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1020 jpeg_info.scale_num=1U;
1021 jpeg_info.scale_denom=(unsigned int) scale_factor;
1022 jpeg_calc_output_dimensions(&jpeg_info);
1023 if (image->debug != MagickFalse)
1024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Scale factor: %ld",
1025 (long) scale_factor);
1027 precision=(unsigned long) jpeg_info.data_precision;
1028 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1029 #if defined(D_LOSSLESS_SUPPORTED)
1030 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1031 JPEGInterlace : NoInterlace;
1032 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1033 LosslessJPEGCompression : JPEGCompression;
1034 if (jpeg_info.data_precision > 8)
1035 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1036 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1038 if (jpeg_info.data_precision == 16)
1039 jpeg_info.data_precision=12;
1041 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1043 image->compression=JPEGCompression;
1046 image->compression=JPEGCompression;
1047 image->interlace=JPEGInterlace;
1049 if ((image_info->colors > 8) && (image_info->colors <= 256))
1052 Let the JPEG library quantize for us.
1054 jpeg_info.quantize_colors=MagickTrue;
1055 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1057 option=GetImageOption(image_info,"jpeg:block-smoothing");
1058 if (option != (const char *) NULL)
1060 jpeg_info.do_block_smoothing=MagickFalse;
1061 if (IsMagickTrue(option) != MagickFalse)
1062 jpeg_info.do_block_smoothing=MagickTrue;
1064 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1065 if (option != (const char *) NULL)
1067 jpeg_info.do_fancy_upsampling=MagickFalse;
1068 if (IsMagickTrue(option) != MagickFalse)
1069 jpeg_info.do_fancy_upsampling=MagickTrue;
1071 (void) jpeg_start_decompress(&jpeg_info);
1072 image->columns=jpeg_info.output_width;
1073 image->rows=jpeg_info.output_height;
1074 image->depth=(unsigned long) jpeg_info.data_precision;
1075 if (jpeg_info.out_color_space == JCS_YCbCr)
1076 image->colorspace=YCbCrColorspace;
1077 if (jpeg_info.out_color_space == JCS_CMYK)
1078 image->colorspace=CMYKColorspace;
1079 if ((image_info->colors != 0) && (image_info->colors <= 256))
1080 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1081 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1082 if ((jpeg_info.output_components == 1) &&
1083 (jpeg_info.quantize_colors == MagickFalse))
1088 colors=(unsigned long) GetQuantumRange(image->depth)+1;
1089 if (AcquireImageColormap(image,colors) == MagickFalse)
1090 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1092 if (image->debug != MagickFalse)
1094 if (image->interlace != NoInterlace)
1095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1096 "Interlace: progressive");
1098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1099 "Interlace: nonprogressive");
1100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1101 (int) jpeg_info.data_precision);
1102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1103 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1105 JPEGSetImageQuality(&jpeg_info,image);
1106 JPEGSetImageSamplingFactor(&jpeg_info,image);
1107 (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
1108 jpeg_info.out_color_space);
1109 (void) SetImageProperty(image,"jpeg:colorspace",value);
1110 if (image_info->ping != MagickFalse)
1112 jpeg_destroy_decompress(&jpeg_info);
1113 (void) CloseBlob(image);
1114 return(GetFirstImageInList(image));
1116 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1117 jpeg_info.output_components*sizeof(JSAMPLE));
1118 if (jpeg_pixels == (JSAMPLE *) NULL)
1119 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1121 Convert JPEG pixels to pixel packets.
1123 if (setjmp(error_manager.error_recovery) != 0)
1125 if (jpeg_pixels != (unsigned char *) NULL)
1126 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1127 jpeg_destroy_decompress(&jpeg_info);
1128 (void) CloseBlob(image);
1129 number_pixels=(MagickSizeType) image->columns*image->rows;
1130 if (number_pixels != 0)
1131 return(GetFirstImageInList(image));
1132 return(DestroyImage(image));
1134 if (jpeg_info.quantize_colors != MagickFalse)
1136 image->colors=(unsigned long) jpeg_info.actual_number_of_colors;
1137 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1138 for (i=0; i < (long) image->colors; i++)
1140 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1141 image->colormap[i].green=image->colormap[i].red;
1142 image->colormap[i].blue=image->colormap[i].red;
1143 image->colormap[i].opacity=OpaqueOpacity;
1146 for (i=0; i < (long) image->colors; i++)
1148 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1149 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1150 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1151 image->colormap[i].opacity=OpaqueOpacity;
1154 scanline[0]=(JSAMPROW) jpeg_pixels;
1155 for (y=0; y < (long) image->rows; y++)
1157 register IndexPacket
1163 register PixelPacket
1166 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1168 (void) ThrowMagickException(exception,GetMagickModule(),
1169 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1173 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1174 if (q == (PixelPacket *) NULL)
1176 indexes=GetAuthenticIndexQueue(image);
1177 if (jpeg_info.data_precision > 8)
1179 if (jpeg_info.output_components == 1)
1180 for (x=0; x < (long) image->columns; x++)
1185 if (precision != 16)
1186 pixel=(unsigned long) GETJSAMPLE(*p);
1188 pixel=(unsigned long) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1189 jindex=ConstrainColormapIndex(image,pixel);
1191 *q++=image->colormap[(int) jindex];
1195 if (image->colorspace != CMYKColorspace)
1196 for (x=0; x < (long) image->columns; x++)
1198 q->red=ScaleShortToQuantum((unsigned char)
1199 (GETJSAMPLE(*p++) << 4));
1200 q->green=ScaleShortToQuantum((unsigned char)
1201 (GETJSAMPLE(*p++) << 4));
1202 q->blue=ScaleShortToQuantum((unsigned char)
1203 (GETJSAMPLE(*p++) << 4));
1204 q->opacity=OpaqueOpacity;
1208 for (x=0; x < (long) image->columns; x++)
1210 q->red=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1211 (GETJSAMPLE(*p++) << 4));
1212 q->green=(Quantum) QuantumRange-ScaleShortToQuantum(
1213 (unsigned char) (GETJSAMPLE(*p++) << 4));
1214 q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1215 (GETJSAMPLE(*p++) << 4));
1216 q->opacity=OpaqueOpacity;
1217 indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
1218 (unsigned char) (GETJSAMPLE(*p++) << 4));
1223 if (jpeg_info.output_components == 1)
1224 for (x=0; x < (long) image->columns; x++)
1226 jindex=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
1227 indexes[x]=(IndexPacket) jindex;
1228 *q++=image->colormap[(int) jindex];
1232 if (image->colorspace != CMYKColorspace)
1233 for (x=0; x < (long) image->columns; x++)
1235 q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1236 q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1237 q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1238 q->opacity=OpaqueOpacity;
1242 for (x=0; x < (long) image->columns; x++)
1244 q->red=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1246 q->green=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1248 q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1250 q->opacity=OpaqueOpacity;
1251 indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
1252 (unsigned char) GETJSAMPLE(*p++));
1255 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1257 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
1261 Free jpeg resources.
1263 (void) jpeg_finish_decompress(&jpeg_info);
1264 jpeg_destroy_decompress(&jpeg_info);
1265 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1266 (void) CloseBlob(image);
1267 return(GetFirstImageInList(image));
1272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1276 % R e g i s t e r J P E G I m a g e %
1280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282 % RegisterJPEGImage() adds properties for the JPEG image format to
1283 % the list of supported formats. The properties include the image format
1284 % tag, a method to read and/or write the format, whether the format
1285 % supports the saving of more than one frame to the same file or blob,
1286 % whether the format supports native in-memory I/O, and a brief
1287 % description of the format.
1289 % The format of the RegisterJPEGImage method is:
1291 % unsigned long RegisterJPEGImage(void)
1294 ModuleExport unsigned long RegisterJPEGImage(void)
1297 version[MaxTextExtent];
1303 description[] = "Joint Photographic Experts Group JFIF format";
1306 #if defined(JPEG_LIB_VERSION)
1307 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1309 entry=SetMagickInfo("JPEG");
1310 entry->thread_support=NoThreadSupport;
1311 #if defined(MAGICKCORE_JPEG_DELEGATE)
1312 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1313 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1315 entry->magick=(IsImageFormatHandler *) IsJPEG;
1316 entry->adjoin=MagickFalse;
1317 entry->description=ConstantString(description);
1318 if (*version != '\0')
1319 entry->version=ConstantString(version);
1320 entry->module=ConstantString("JPEG");
1321 (void) RegisterMagickInfo(entry);
1322 entry=SetMagickInfo("JPG");
1323 entry->thread_support=NoThreadSupport;
1324 #if defined(MAGICKCORE_JPEG_DELEGATE)
1325 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1326 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1328 entry->adjoin=MagickFalse;
1329 entry->description=ConstantString(description);
1330 if (*version != '\0')
1331 entry->version=ConstantString(version);
1332 entry->module=ConstantString("JPEG");
1333 (void) RegisterMagickInfo(entry);
1334 entry=SetMagickInfo("PJPEG");
1335 entry->thread_support=NoThreadSupport;
1336 #if defined(MAGICKCORE_JPEG_DELEGATE)
1337 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1338 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1340 entry->adjoin=MagickFalse;
1341 entry->description=ConstantString(description);
1342 if (*version != '\0')
1343 entry->version=ConstantString(version);
1344 entry->module=ConstantString("JPEG");
1345 (void) RegisterMagickInfo(entry);
1346 return(MagickImageCoderSignature);
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % U n r e g i s t e r J P E G I m a g e %
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 % UnregisterJPEGImage() removes format registrations made by the
1361 % JPEG module from the list of supported formats.
1363 % The format of the UnregisterJPEGImage method is:
1365 % UnregisterJPEGImage(void)
1368 ModuleExport void UnregisterJPEGImage(void)
1370 (void) UnregisterMagickInfo("PJPG");
1371 (void) UnregisterMagickInfo("JPEG");
1372 (void) UnregisterMagickInfo("JPG");
1375 #if defined(MAGICKCORE_JPEG_DELEGATE)
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % W r i t e J P E G I m a g e %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % WriteJPEGImage() writes a JPEG image file and returns it. It
1388 % allocates the memory necessary for the new Image structure and returns a
1389 % pointer to the new image.
1391 % The format of the WriteJPEGImage method is:
1393 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,Image *image)
1395 % A description of each parameter follows:
1397 % o image_info: the image info.
1399 % o jpeg_image: The image.
1404 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1409 destination=(DestinationManager *) cinfo->dest;
1410 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1411 MaxBufferExtent,destination->buffer);
1412 if (destination->manager.free_in_buffer != MaxBufferExtent)
1413 ERREXIT(cinfo,JERR_FILE_WRITE);
1414 destination->manager.next_output_byte=destination->buffer;
1418 static void InitializeDestination(j_compress_ptr cinfo)
1423 destination=(DestinationManager *) cinfo->dest;
1424 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1425 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1426 destination->manager.next_output_byte=destination->buffer;
1427 destination->manager.free_in_buffer=MaxBufferExtent;
1430 static inline size_t MagickMin(const size_t x,const size_t y)
1437 static void TerminateDestination(j_compress_ptr cinfo)
1442 destination=(DestinationManager *) cinfo->dest;
1443 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1448 count=WriteBlob(destination->image,MaxBufferExtent-
1449 destination->manager.free_in_buffer,destination->buffer);
1450 if (count != (ssize_t)
1451 (MaxBufferExtent-destination->manager.free_in_buffer))
1452 ERREXIT(cinfo,JERR_FILE_WRITE);
1456 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1480 Save image profile as a APP marker.
1483 custom_profile=AcquireStringInfo(65535L);
1484 ResetImageProfileIterator(image);
1485 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1487 profile=GetImageProfile(image,name);
1488 if (LocaleCompare(name,"EXIF") == 0)
1489 for (i=0; i < (long) GetStringInfoLength(profile); i+=65533L)
1491 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1492 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1493 (unsigned int) length);
1495 if (LocaleCompare(name,"ICC") == 0)
1497 register unsigned char
1501 p=GetStringInfoDatum(custom_profile);
1502 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1503 for (i=0; i < (long) GetStringInfoLength(profile); i+=65519L)
1505 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1506 p=GetStringInfoDatum(custom_profile);
1507 p[12]=(unsigned char) ((i/65519L)+1);
1508 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1509 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1511 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1512 custom_profile),(unsigned int) (length+tag_length));
1515 if (((LocaleCompare(name,"IPTC") == 0) ||
1516 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1518 register unsigned char
1525 p=GetStringInfoDatum(custom_profile);
1526 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1528 (void) CopyMagickMemory(p,"Photoshop 3.0\0",14);
1533 (void) CopyMagickMemory(p,"Photoshop 3.0\08BIM\04\04\0\0\0\0",24);
1535 p[24]=(unsigned char) (GetStringInfoLength(profile) >> 8);
1536 p[25]=(unsigned char) (GetStringInfoLength(profile) & 0xff);
1539 for (i=0; i < (long) GetStringInfoLength(profile); i+=65500L)
1541 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1542 roundup=(unsigned long) (length & 0x01);
1543 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1546 p[length+tag_length]='\0';
1547 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1548 custom_profile),(unsigned int) (length+tag_length+roundup));
1551 if (LocaleCompare(name,"XMP") == 0)
1557 Add namespace to XMP profile.
1559 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1560 ConcatenateStringInfo(xmp_profile,profile);
1561 GetStringInfoDatum(xmp_profile)[28]='\0';
1562 for (i=0; i < (long) GetStringInfoLength(xmp_profile); i+=65533L)
1564 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1565 jpeg_write_marker(jpeg_info,XML_MARKER,
1566 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1568 xmp_profile=DestroyStringInfo(xmp_profile);
1570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s profile: %lu bytes",
1571 name,(unsigned long) GetStringInfoLength(profile));
1572 name=GetNextImageProfile(image);
1574 custom_profile=DestroyStringInfo(custom_profile);
1577 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1582 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1583 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1584 destination=(DestinationManager *) cinfo->dest;
1585 destination->manager.init_destination=InitializeDestination;
1586 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1587 destination->manager.term_destination=TerminateDestination;
1588 destination->image=image;
1591 static char **SamplingFactorToList(const char *text)
1608 if (text == (char *) NULL)
1609 return((char **) NULL);
1611 Convert string to an ASCII list.
1614 for (p=text; *p != '\0'; p++)
1617 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1619 if (textlist == (char **) NULL)
1620 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1622 for (i=0; i < (long) lines; i++)
1624 for (q=(char *) p; *q != '\0'; q++)
1627 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1628 sizeof(*textlist[i]));
1629 if (textlist[i] == (char *) NULL)
1630 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1631 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1636 textlist[i]=(char *) NULL;
1640 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1669 struct jpeg_compress_struct
1672 struct jpeg_error_mgr
1678 assert(image_info != (const ImageInfo *) NULL);
1679 assert(image_info->signature == MagickSignature);
1680 assert(image != (Image *) NULL);
1681 assert(image->signature == MagickSignature);
1682 if (image->debug != MagickFalse)
1683 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1684 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1685 if (status == MagickFalse)
1688 Initialize JPEG parameters.
1690 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1691 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1692 jpeg_info.client_data=(void *) image;
1693 jpeg_info.err=jpeg_std_error(&jpeg_error);
1694 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
1695 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1696 error_manager.image=image;
1697 jpeg_pixels=(JSAMPLE *) NULL;
1698 if (setjmp(error_manager.error_recovery) != 0)
1700 jpeg_destroy_compress(&jpeg_info);
1701 (void) CloseBlob(image);
1702 return(MagickFalse);
1704 jpeg_info.client_data=(void *) &error_manager;
1705 jpeg_create_compress(&jpeg_info);
1706 JPEGDestinationManager(&jpeg_info,image);
1707 if ((image->columns != (unsigned int) image->columns) ||
1708 (image->rows != (unsigned int) image->rows))
1709 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1710 jpeg_info.image_width=(unsigned int) image->columns;
1711 jpeg_info.image_height=(unsigned int) image->rows;
1712 jpeg_info.input_components=3;
1713 jpeg_info.data_precision=8;
1714 jpeg_info.in_color_space=JCS_RGB;
1715 switch (image->colorspace)
1717 case CMYKColorspace:
1719 jpeg_info.input_components=4;
1720 jpeg_info.in_color_space=JCS_CMYK;
1723 case YCbCrColorspace:
1724 case Rec601YCbCrColorspace:
1725 case Rec709YCbCrColorspace:
1727 jpeg_info.in_color_space=JCS_YCbCr;
1730 case GRAYColorspace:
1731 case Rec601LumaColorspace:
1732 case Rec709LumaColorspace:
1734 jpeg_info.input_components=1;
1735 jpeg_info.in_color_space=JCS_GRAYSCALE;
1741 if ((image_info->type != TrueColorType) &&
1742 (IsGrayImage(image,&image->exception) != MagickFalse))
1744 jpeg_info.input_components=1;
1745 jpeg_info.in_color_space=JCS_GRAYSCALE;
1747 jpeg_set_defaults(&jpeg_info);
1748 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1749 jpeg_info.data_precision=8;
1751 if (sizeof(JSAMPLE) > 1)
1752 jpeg_info.data_precision=12;
1753 jpeg_info.density_unit=(UINT8) 1;
1754 if (image->debug != MagickFalse)
1755 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1756 "Image resolution: %ld,%ld",(long) (image->x_resolution+0.5),
1757 (long) (image->y_resolution+0.5));
1758 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1761 Set image resolution.
1763 jpeg_info.write_JFIF_header=MagickTrue;
1764 jpeg_info.X_density=(UINT16) image->x_resolution;
1765 jpeg_info.Y_density=(UINT16) image->y_resolution;
1766 if (image->units == PixelsPerInchResolution)
1767 jpeg_info.density_unit=(UINT8) 1;
1768 if (image->units == PixelsPerCentimeterResolution)
1769 jpeg_info.density_unit=(UINT8) 2;
1771 option=GetImageOption(image_info,"jpeg:dct-method");
1772 if (option != (const char *) NULL)
1778 if (LocaleCompare(option,"default") == 0)
1779 jpeg_info.dct_method=JDCT_DEFAULT;
1785 if (LocaleCompare(option,"fastest") == 0)
1786 jpeg_info.dct_method=JDCT_FASTEST;
1787 if (LocaleCompare(option,"float") == 0)
1788 jpeg_info.dct_method=JDCT_FLOAT;
1794 if (LocaleCompare(option,"ifast") == 0)
1795 jpeg_info.dct_method=JDCT_IFAST;
1796 if (LocaleCompare(option,"islow") == 0)
1797 jpeg_info.dct_method=JDCT_ISLOW;
1801 option=GetImageOption(image_info,"jpeg:optimize-coding");
1802 if (option != (const char *) NULL)
1804 jpeg_info.optimize_coding=MagickFalse;
1805 if (IsMagickTrue(option) != MagickFalse)
1806 jpeg_info.optimize_coding=MagickTrue;
1813 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1814 image->rows*sizeof(JSAMPLE);
1815 if (length == (MagickSizeType) ((size_t) length))
1818 Perform optimization only if available memory resources permit it.
1820 status=AcquireMagickResource(MemoryResource,length);
1821 if (status != MagickFalse)
1822 jpeg_info.optimize_coding=MagickTrue;
1823 RelinquishMagickResource(MemoryResource,length);
1826 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1827 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1828 (image_info->interlace != NoInterlace))
1830 if (image->debug != MagickFalse)
1831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1832 "Interlace: progressive");
1833 jpeg_simple_progression(&jpeg_info);
1836 if (image->debug != MagickFalse)
1837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1838 "Interlace: non-progressive");
1840 if (image->debug != MagickFalse)
1841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1842 "Interlace: nonprogressive");
1844 option=GetImageOption(image_info,"jpeg:extent");
1845 if (option != (const char *) NULL)
1853 jpeg_info=CloneImageInfo(image_info);
1854 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1855 if (jpeg_image != (Image *) NULL)
1865 Search for compression quality that does not exceed image extent.
1867 jpeg_info->quality=0;
1868 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1869 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1870 (void) AcquireUniqueFilename(jpeg_image->filename);
1872 for (max=100; (max-min) > 1; )
1874 jpeg_image->quality=min+(max-min)/2;
1875 status=WriteJPEGImage(jpeg_info,jpeg_image);
1876 if (GetBlobSize(jpeg_image) < extent)
1877 min=jpeg_image->quality+1;
1879 max=jpeg_image->quality-1;
1881 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1883 jpeg_image=DestroyImage(jpeg_image);
1885 jpeg_info=DestroyImageInfo(jpeg_info);
1887 if ((image_info->compression != LosslessJPEGCompression) &&
1888 (image->quality <= 100))
1890 if (image->quality == UndefinedCompressionQuality)
1891 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1893 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1894 if (image->debug != MagickFalse)
1895 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
1900 #if !defined(C_LOSSLESS_SUPPORTED)
1901 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1902 if (image->debug != MagickFalse)
1903 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1905 if (image->quality < 100)
1906 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1907 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1914 predictor=image->quality/100; /* range 1-7 */
1915 point_transform=image->quality % 20; /* range 0-15 */
1916 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1917 if (image->debug != MagickFalse)
1919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1920 "Compression: lossless");
1921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1922 "Predictor: %d",predictor);
1923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1924 "Point Transform: %d",point_transform);
1929 sampling_factor=(const char *) NULL;
1930 value=GetImageProperty(image,"jpeg:sampling-factor");
1931 if (value != (char *) NULL)
1933 sampling_factor=value;
1934 if (image->debug != MagickFalse)
1935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1936 " Input sampling-factors=%s",sampling_factor);
1938 if (image_info->sampling_factor != (char *) NULL)
1939 sampling_factor=image_info->sampling_factor;
1940 if (sampling_factor == (const char *) NULL)
1942 if (image->quality >= 90)
1943 for (i=0; i < MAX_COMPONENTS; i++)
1945 jpeg_info.comp_info[i].h_samp_factor=1;
1946 jpeg_info.comp_info[i].v_samp_factor=1;
1961 Set sampling factor.
1964 factors=SamplingFactorToList(sampling_factor);
1965 if (factors != (char **) NULL)
1967 for (i=0; i < MAX_COMPONENTS; i++)
1969 if (factors[i] == (char *) NULL)
1971 flags=ParseGeometry(factors[i],&geometry_info);
1972 if ((flags & SigmaValue) == 0)
1973 geometry_info.sigma=geometry_info.rho;
1974 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
1975 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
1976 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
1978 factors=(char **) RelinquishMagickMemory(factors);
1980 for ( ; i < MAX_COMPONENTS; i++)
1982 jpeg_info.comp_info[i].h_samp_factor=1;
1983 jpeg_info.comp_info[i].v_samp_factor=1;
1986 if (jpeg_info.input_components == 1)
1987 for (i=0; i < MAX_COMPONENTS; i++)
1989 jpeg_info.comp_info[i].h_samp_factor=1;
1990 jpeg_info.comp_info[i].v_samp_factor=1;
1992 jpeg_start_compress(&jpeg_info,MagickTrue);
1993 if (image->debug != MagickFalse)
1995 if (image->storage_class == PseudoClass)
1996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1997 "Storage class: PseudoClass");
1999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2000 "Storage class: DirectClass");
2001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %lu",
2003 if (image->colors != 0)
2004 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2005 "Number of colors: %lu",image->colors);
2007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2008 "Number of colors: unspecified");
2009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2010 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2011 switch (image->colorspace)
2013 case CMYKColorspace:
2015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2016 "Storage class: DirectClass");
2017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2018 "Colorspace: CMYK");
2021 case YCbCrColorspace:
2022 case Rec601YCbCrColorspace:
2023 case Rec709YCbCrColorspace:
2025 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2026 "Colorspace: YCbCr");
2032 switch (image->colorspace)
2034 case CMYKColorspace:
2036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2037 "Colorspace: CMYK");
2038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2039 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2040 jpeg_info.comp_info[0].h_samp_factor,
2041 jpeg_info.comp_info[0].v_samp_factor,
2042 jpeg_info.comp_info[1].h_samp_factor,
2043 jpeg_info.comp_info[1].v_samp_factor,
2044 jpeg_info.comp_info[2].h_samp_factor,
2045 jpeg_info.comp_info[2].v_samp_factor,
2046 jpeg_info.comp_info[3].h_samp_factor,
2047 jpeg_info.comp_info[3].v_samp_factor);
2050 case GRAYColorspace:
2051 case Rec601LumaColorspace:
2052 case Rec709LumaColorspace:
2054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2055 "Colorspace: GRAY");
2056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2057 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2058 jpeg_info.comp_info[0].v_samp_factor);
2063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2064 "Image colorspace is RGB");
2065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2066 "Sampling factors: %dx%d,%dx%d,%dx%d",
2067 jpeg_info.comp_info[0].h_samp_factor,
2068 jpeg_info.comp_info[0].v_samp_factor,
2069 jpeg_info.comp_info[1].h_samp_factor,
2070 jpeg_info.comp_info[1].v_samp_factor,
2071 jpeg_info.comp_info[2].h_samp_factor,
2072 jpeg_info.comp_info[2].v_samp_factor);
2075 case YCbCrColorspace:
2076 case Rec601YCbCrColorspace:
2077 case Rec709YCbCrColorspace:
2079 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2080 "Colorspace: YCbCr");
2081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2082 "Sampling factors: %dx%d,%dx%d,%dx%d",
2083 jpeg_info.comp_info[0].h_samp_factor,
2084 jpeg_info.comp_info[0].v_samp_factor,
2085 jpeg_info.comp_info[1].h_samp_factor,
2086 jpeg_info.comp_info[1].v_samp_factor,
2087 jpeg_info.comp_info[2].h_samp_factor,
2088 jpeg_info.comp_info[2].v_samp_factor);
2093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2096 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2097 jpeg_info.comp_info[0].h_samp_factor,
2098 jpeg_info.comp_info[0].v_samp_factor,
2099 jpeg_info.comp_info[1].h_samp_factor,
2100 jpeg_info.comp_info[1].v_samp_factor,
2101 jpeg_info.comp_info[2].h_samp_factor,
2102 jpeg_info.comp_info[2].v_samp_factor,
2103 jpeg_info.comp_info[3].h_samp_factor,
2104 jpeg_info.comp_info[3].v_samp_factor);
2110 Write JPEG profiles.
2112 value=GetImageProperty(image,"comment");
2113 if (value != (char *) NULL)
2114 for (i=0; i < (long) strlen(value); i+=65533L)
2115 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2116 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2117 if (image->profiles != (void *) NULL)
2118 WriteProfile(&jpeg_info,image);
2120 Convert MIFF to JPEG raster pixels.
2122 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2123 jpeg_info.input_components*sizeof(*jpeg_pixels));
2124 if (jpeg_pixels == (JSAMPLE *) NULL)
2125 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2126 if (setjmp(error_manager.error_recovery) != 0)
2128 jpeg_destroy_compress(&jpeg_info);
2129 if (jpeg_pixels != (unsigned char *) NULL)
2130 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2131 (void) CloseBlob(image);
2132 return(MagickFalse);
2134 scanline[0]=(JSAMPROW) jpeg_pixels;
2135 if (jpeg_info.data_precision > 8)
2137 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2138 for (y=0; y < (long) image->rows; y++)
2140 register const PixelPacket
2146 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2147 if (p == (const PixelPacket *) NULL)
2150 for (x=0; x < (long) image->columns; x++)
2152 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2156 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2157 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2161 if ((jpeg_info.in_color_space == JCS_RGB) ||
2162 (jpeg_info.in_color_space == JCS_YCbCr))
2163 for (y=0; y < (long) image->rows; y++)
2165 register const PixelPacket
2171 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2172 if (p == (const PixelPacket *) NULL)
2175 for (x=0; x < (long) image->columns; x++)
2177 *q++=(JSAMPLE) (ScaleQuantumToShort(p->red) >> 4);
2178 *q++=(JSAMPLE) (ScaleQuantumToShort(p->green) >> 4);
2179 *q++=(JSAMPLE) (ScaleQuantumToShort(p->blue) >> 4);
2182 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2183 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2184 if (status == MagickFalse)
2188 for (y=0; y < (long) image->rows; y++)
2190 register const IndexPacket
2193 register const PixelPacket
2199 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2200 if (p == (const PixelPacket *) NULL)
2203 indexes=GetVirtualIndexQueue(image);
2204 for (x=0; x < (long) image->columns; x++)
2207 Convert DirectClass packets to contiguous CMYK scanlines.
2209 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->red) >> 4));
2210 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->green) >> 4));
2211 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->blue) >> 4));
2212 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
2215 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2216 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2217 if (status == MagickFalse)
2222 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2223 for (y=0; y < (long) image->rows; y++)
2225 register const PixelPacket
2231 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2232 if (p == (const PixelPacket *) NULL)
2235 for (x=0; x < (long) image->columns; x++)
2237 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2240 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2241 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2245 if ((jpeg_info.in_color_space == JCS_RGB) ||
2246 (jpeg_info.in_color_space == JCS_YCbCr))
2247 for (y=0; y < (long) image->rows; y++)
2249 register const PixelPacket
2255 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2256 if (p == (const PixelPacket *) NULL)
2259 for (x=0; x < (long) image->columns; x++)
2261 *q++=(JSAMPLE) ScaleQuantumToChar(p->red);
2262 *q++=(JSAMPLE) ScaleQuantumToChar(p->green);
2263 *q++=(JSAMPLE) ScaleQuantumToChar(p->blue);
2266 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2267 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2271 for (y=0; y < (long) image->rows; y++)
2273 register const IndexPacket
2276 register const PixelPacket
2282 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2283 if (p == (const PixelPacket *) NULL)
2286 indexes=GetVirtualIndexQueue(image);
2287 for (x=0; x < (long) image->columns; x++)
2290 Convert DirectClass packets to contiguous CMYK scanlines.
2292 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2294 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2296 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2298 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2302 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2303 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2306 if (y == (long) image->rows)
2307 jpeg_finish_compress(&jpeg_info);
2309 Relinquish resources.
2311 jpeg_destroy_compress(&jpeg_info);
2312 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2313 (void) CloseBlob(image);