2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2009 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/monitor.h"
65 #include "magick/monitor-private.h"
66 #include "magick/option.h"
67 #include "magick/profile.h"
68 #include "magick/property.h"
69 #include "magick/quantum-private.h"
70 #include "magick/resource_.h"
71 #include "magick/splay-tree.h"
72 #include "magick/static.h"
73 #include "magick/string_.h"
74 #include "magick/module.h"
75 #include "magick/utility.h"
77 #if defined(MAGICKCORE_JPEG_DELEGATE)
78 #define JPEG_INTERNAL_OPTIONS
79 #if defined(__MINGW32__)
80 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
90 #define ICC_MARKER (JPEG_APP0+2)
91 #define ICC_PROFILE "ICC_PROFILE"
92 #define IPTC_MARKER (JPEG_APP0+13)
93 #define XML_MARKER (JPEG_APP0+1)
94 #define MaxBufferExtent 8192
99 #if defined(MAGICKCORE_JPEG_DELEGATE)
100 typedef struct _DestinationManager
102 struct jpeg_destination_mgr
110 } DestinationManager;
112 typedef struct _ErrorManager
121 typedef struct _SourceManager
123 struct jpeg_source_mgr
138 Forward declarations.
140 #if defined(MAGICKCORE_JPEG_DELEGATE)
141 static MagickBooleanType
142 WriteJPEGImage(const ImageInfo *,Image *);
146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 % IsJPEG() returns MagickTrue if the image format type, identified by the
157 % magick string, is JPEG.
159 % The format of the IsJPEG method is:
161 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
163 % A description of each parameter follows:
165 % o magick: compare image format pattern against these bytes.
167 % o length: Specifies the length of the magick string.
170 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
174 if (memcmp(magick,"\377\330\377",3) == 0)
179 #if defined(MAGICKCORE_JPEG_DELEGATE)
181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 % R e a d J P E G I m a g e %
189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
192 % the memory necessary for the new Image structure and returns a pointer to
195 % The format of the ReadJPEGImage method is:
197 % Image *ReadJPEGImage(const ImageInfo *image_info,
198 % ExceptionInfo *exception)
200 % A description of each parameter follows:
202 % o image_info: the image info.
204 % o exception: return any errors or warnings in this structure.
208 static MagickBooleanType EmitMessage(j_common_ptr jpeg_info,int level)
211 message[JMSG_LENGTH_MAX];
219 (jpeg_info->err->format_message)(jpeg_info,message);
220 error_manager=(ErrorManager *) jpeg_info->client_data;
221 image=error_manager->image;
224 if ((jpeg_info->err->num_warnings == 0) ||
225 (jpeg_info->err->trace_level >= 3))
226 ThrowBinaryException(CorruptImageWarning,(char *) message,
228 jpeg_info->err->num_warnings++;
231 if (jpeg_info->err->trace_level >= level)
232 ThrowBinaryException(CoderError,(char *) message,image->filename);
236 static boolean FillInputBuffer(j_decompress_ptr cinfo)
241 source=(SourceManager *) cinfo->src;
242 source->manager.bytes_in_buffer=(size_t)
243 ReadBlob(source->image,MaxBufferExtent,source->buffer);
244 if (source->manager.bytes_in_buffer == 0)
246 if (source->start_of_blob != 0)
247 ERREXIT(cinfo,JERR_INPUT_EMPTY);
248 WARNMS(cinfo,JWRN_JPEG_EOF);
249 source->buffer[0]=(JOCTET) 0xff;
250 source->buffer[1]=(JOCTET) JPEG_EOI;
251 source->manager.bytes_in_buffer=2;
253 source->manager.next_input_byte=source->buffer;
254 source->start_of_blob=FALSE;
258 static int GetCharacter(j_decompress_ptr jpeg_info)
260 if (jpeg_info->src->bytes_in_buffer == 0)
261 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
262 jpeg_info->src->bytes_in_buffer--;
263 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
266 static void InitializeSource(j_decompress_ptr cinfo)
271 source=(SourceManager *) cinfo->src;
272 source->start_of_blob=TRUE;
275 static MagickBooleanType IsITUFaxImage(const Image *image)
283 profile=GetImageProfile(image,"8bim");
284 if (profile == (const StringInfo *) NULL)
286 if (GetStringInfoLength(profile) < 5)
288 datum=GetStringInfoDatum(profile);
289 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
290 (datum[3] == 0x41) && (datum[4] == 0x58))
295 static void JPEGErrorHandler(j_common_ptr jpeg_info)
300 (void) EmitMessage(jpeg_info,0);
301 error_manager=(ErrorManager *) jpeg_info->client_data;
302 longjmp(error_manager->error_recovery,1);
305 static boolean ReadComment(j_decompress_ptr jpeg_info)
326 Determine length of comment.
328 error_manager=(ErrorManager *) jpeg_info->client_data;
329 image=error_manager->image;
330 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
331 length+=GetCharacter(jpeg_info);
335 comment=(char *) NULL;
336 if (~length >= MaxTextExtent)
337 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
339 if (comment == (char *) NULL)
340 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
346 for (p=comment; i-- >= 0; p++)
347 *p=(char) GetCharacter(jpeg_info);
349 (void) SetImageProperty(image,"comment",comment);
350 comment=DestroyString(comment);
354 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
371 register unsigned char
384 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
385 length+=(size_t) GetCharacter(jpeg_info);
390 (void) GetCharacter(jpeg_info);
393 for (i=0; i < 12; i++)
394 magick[i]=(char) GetCharacter(jpeg_info);
395 if (LocaleCompare(magick,ICC_PROFILE) != 0)
398 Not a ICC profile, return.
400 for (i=0; i < (long) (length-12); i++)
401 (void) GetCharacter(jpeg_info);
404 (void) GetCharacter(jpeg_info); /* id */
405 (void) GetCharacter(jpeg_info); /* markers */
407 error_manager=(ErrorManager *) jpeg_info->client_data;
408 image=error_manager->image;
409 profile=AcquireStringInfo(length);
410 if (profile == (StringInfo *) NULL)
411 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
413 p=GetStringInfoDatum(profile);
414 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
415 *p++=(unsigned char) GetCharacter(jpeg_info);
416 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
417 if (icc_profile != (StringInfo *) NULL)
419 ConcatenateStringInfo(icc_profile,profile);
420 profile=DestroyStringInfo(profile);
424 status=SetImageProfile(image,"icc",profile);
425 profile=DestroyStringInfo(profile);
426 if (status == MagickFalse)
427 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
432 "Profile: ICC, %lu bytes",(unsigned long) length);
436 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
439 magick[MaxTextExtent];
453 register unsigned char
464 Determine length of binary data stored here.
466 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
467 length+=(size_t) GetCharacter(jpeg_info);
472 (void) GetCharacter(jpeg_info);
476 Validate that this was written as a Photoshop resource format slug.
478 for (i=0; i < 10; i++)
479 magick[i]=(char) GetCharacter(jpeg_info);
484 if (LocaleCompare(magick,"Photoshop ") != 0)
487 Not a IPTC profile, return.
489 for (i=0; i < (long) length; i++)
490 (void) GetCharacter(jpeg_info);
494 Remove the version number.
496 for (i=0; i < 4; i++)
497 (void) GetCharacter(jpeg_info);
503 error_manager=(ErrorManager *) jpeg_info->client_data;
504 image=error_manager->image;
505 profile=AcquireStringInfo(length);
506 if (profile == (StringInfo *) NULL)
507 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
509 p=GetStringInfoDatum(profile);
510 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
511 *p++=(unsigned char) GetCharacter(jpeg_info);
512 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
513 if (iptc_profile != (StringInfo *) NULL)
515 ConcatenateStringInfo(iptc_profile,profile);
516 profile=DestroyStringInfo(profile);
520 status=SetImageProfile(image,"8bim",profile);
521 profile=DestroyStringInfo(profile);
522 if (status == MagickFalse)
523 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
526 if (image->debug != MagickFalse)
527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
528 "Profile: iptc, %lu bytes",(unsigned long) length);
532 static boolean ReadProfile(j_decompress_ptr jpeg_info)
552 register unsigned char
562 Read generic profile.
564 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
565 length+=(size_t) GetCharacter(jpeg_info);
569 marker=jpeg_info->unread_marker-JPEG_APP0;
570 (void) FormatMagickString(name,MaxTextExtent,"APP%d",marker);
571 error_manager=(ErrorManager *) jpeg_info->client_data;
572 image=error_manager->image;
573 profile=AcquireStringInfo(length);
574 if (profile == (StringInfo *) NULL)
575 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
577 p=GetStringInfoDatum(profile);
578 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
579 *p++=(unsigned char) GetCharacter(jpeg_info);
582 p=GetStringInfoDatum(profile);
583 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
584 (void) CopyMagickString(name,"exif",MaxTextExtent);
585 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
591 Extract namespace from XMP profile.
593 p=GetStringInfoDatum(profile);
594 for (j=0; j < (long) GetStringInfoLength(profile); j++)
600 if (j < (long) GetStringInfoLength(profile))
601 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
602 (void) CopyMagickString(name,"xmp",MaxTextExtent);
605 status=SetImageProfile(image,name,profile);
606 profile=DestroyStringInfo(profile);
607 if (status == MagickFalse)
608 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
610 if (image->debug != MagickFalse)
611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
612 "Profile: %s, %lu bytes",name,(unsigned long) length);
616 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
621 if (number_bytes <= 0)
623 source=(SourceManager *) cinfo->src;
624 while (number_bytes > (long) source->manager.bytes_in_buffer)
626 number_bytes-=(long) source->manager.bytes_in_buffer;
627 (void) FillInputBuffer(cinfo);
629 source->manager.next_input_byte+=(size_t) number_bytes;
630 source->manager.bytes_in_buffer-=(size_t) number_bytes;
633 static void TerminateSource(j_decompress_ptr cinfo)
638 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
643 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
644 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
645 source=(SourceManager *) cinfo->src;
646 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
647 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
648 source=(SourceManager *) cinfo->src;
649 source->manager.init_source=InitializeSource;
650 source->manager.fill_input_buffer=FillInputBuffer;
651 source->manager.skip_input_data=SkipInputData;
652 source->manager.resync_to_restart=jpeg_resync_to_restart;
653 source->manager.term_source=TerminateSource;
654 source->manager.bytes_in_buffer=0;
655 source->manager.next_input_byte=NULL;
659 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
662 image->quality=UndefinedCompressionQuality;
663 #if defined(D_PROGRESSIVE_SUPPORTED)
664 if (image->compression == LosslessJPEGCompression)
667 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
668 "Quality: 100 (lossless)");
682 Determine the JPEG compression quality from the quantization tables.
685 for (i=0; i < NUM_QUANT_TBLS; i++)
687 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
688 for (j=0; j < DCTSIZE2; j++)
689 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
691 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
692 (jpeg_info->quant_tbl_ptrs[1] != NULL))
697 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
698 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
699 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
700 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
701 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
702 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
703 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
704 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
705 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
706 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
711 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
712 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
713 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
714 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
715 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
716 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
717 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
718 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
719 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
720 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
721 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
725 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
726 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
727 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
728 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
729 for (i=0; i < 100; i++)
731 if ((qvalue < hash[i]) && (sum < sums[i]))
733 if ((qvalue <= hash[i]) && (sum <= sums[i]))
734 image->quality=(unsigned long) i+1;
735 if (image->debug != MagickFalse)
737 if (image->quality != UndefinedCompressionQuality)
738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
739 "Quality: %ld",image->quality);
741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
742 "Quality: %ld (approximate)",i+1);
748 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
753 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
754 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
755 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
756 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
757 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
758 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
759 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
760 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
761 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
762 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
767 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
768 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
769 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
770 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
771 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
772 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
773 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
774 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
775 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
776 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
777 667, 592, 518, 441, 369, 292, 221, 151, 86,
781 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
782 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
783 for (i=0; i < 100; i++)
785 if ((qvalue < hash[i]) && (sum < sums[i]))
787 image->quality=(unsigned long) i+1;
788 if (image->debug != MagickFalse)
790 if ((qvalue > hash[i]) || (sum > sums[i]))
791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
792 "Quality: %ld (approximate)",i+1);
794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
803 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
806 sampling_factor[MaxTextExtent];
808 switch (jpeg_info->out_color_space)
812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
813 (void) FormatMagickString(sampling_factor,MaxTextExtent,
814 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
815 jpeg_info->comp_info[0].v_samp_factor,
816 jpeg_info->comp_info[1].h_samp_factor,
817 jpeg_info->comp_info[1].v_samp_factor,
818 jpeg_info->comp_info[2].h_samp_factor,
819 jpeg_info->comp_info[2].v_samp_factor,
820 jpeg_info->comp_info[3].h_samp_factor,
821 jpeg_info->comp_info[3].v_samp_factor);
826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
827 "Colorspace: GRAYSCALE");
828 (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
829 jpeg_info->comp_info[0].h_samp_factor,
830 jpeg_info->comp_info[0].v_samp_factor);
835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
836 (void) FormatMagickString(sampling_factor,MaxTextExtent,
837 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
838 jpeg_info->comp_info[0].v_samp_factor,
839 jpeg_info->comp_info[1].h_samp_factor,
840 jpeg_info->comp_info[1].v_samp_factor,
841 jpeg_info->comp_info[2].h_samp_factor,
842 jpeg_info->comp_info[2].v_samp_factor);
847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
848 jpeg_info->out_color_space);
849 (void) FormatMagickString(sampling_factor,MaxTextExtent,
850 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
851 jpeg_info->comp_info[0].v_samp_factor,
852 jpeg_info->comp_info[1].h_samp_factor,
853 jpeg_info->comp_info[1].v_samp_factor,
854 jpeg_info->comp_info[2].h_samp_factor,
855 jpeg_info->comp_info[2].v_samp_factor,
856 jpeg_info->comp_info[3].h_samp_factor,
857 jpeg_info->comp_info[3].v_samp_factor);
861 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
863 "Sampling Factors: %s",sampling_factor);
866 static Image *ReadJPEGImage(const ImageInfo *image_info,
867 ExceptionInfo *exception)
870 value[MaxTextExtent];
903 struct jpeg_decompress_struct
906 struct jpeg_error_mgr
919 assert(image_info != (const ImageInfo *) NULL);
920 assert(image_info->signature == MagickSignature);
921 if (image_info->debug != MagickFalse)
922 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
923 image_info->filename);
924 assert(exception != (ExceptionInfo *) NULL);
925 assert(exception->signature == MagickSignature);
926 debug=IsEventLogging();
927 image=AcquireImage(image_info);
928 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
929 if (status == MagickFalse)
931 image=DestroyImageList(image);
932 return((Image *) NULL);
935 Initialize JPEG parameters.
937 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
938 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
939 jpeg_info.err=jpeg_std_error(&jpeg_error);
940 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
941 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
942 jpeg_pixels=(JSAMPLE *) NULL;
943 error_manager.image=image;
944 if (setjmp(error_manager.error_recovery) != 0)
946 jpeg_destroy_decompress(&jpeg_info);
947 (void) CloseBlob(image);
948 number_pixels=(MagickSizeType) image->columns*image->rows;
949 if (number_pixels != 0)
950 return(GetFirstImageInList(image));
951 InheritException(exception,&image->exception);
952 return(DestroyImage(image));
954 jpeg_info.client_data=(void *) &error_manager;
955 jpeg_create_decompress(&jpeg_info);
956 JPEGSourceManager(&jpeg_info,image);
957 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
958 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
959 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
960 for (i=1; i < 16; i++)
961 if ((i != 2) && (i != 13) && (i != 14))
962 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
963 i=jpeg_read_header(&jpeg_info,MagickTrue);
964 if ((image_info->colorspace == YCbCrColorspace) ||
965 (image_info->colorspace == Rec601YCbCrColorspace) ||
966 (image_info->colorspace == Rec709YCbCrColorspace))
967 jpeg_info.out_color_space=JCS_YCbCr;
968 if (IsITUFaxImage(image) != MagickFalse)
970 image->colorspace=LabColorspace;
971 jpeg_info.out_color_space=JCS_YCbCr;
974 if (jpeg_info.out_color_space == JCS_CMYK)
975 image->colorspace=CMYKColorspace;
977 Set image resolution.
980 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
981 (jpeg_info.Y_density != 1))
983 image->x_resolution=(double) jpeg_info.X_density;
984 image->y_resolution=(double) jpeg_info.Y_density;
985 units=(unsigned long) jpeg_info.density_unit;
988 image->units=PixelsPerInchResolution;
990 image->units=PixelsPerCentimeterResolution;
991 number_pixels=(MagickSizeType) image->columns*image->rows;
992 option=GetImageOption(image_info,"jpeg:size");
993 if (option != (const char *) NULL)
1007 flags=ParseGeometry(option,&geometry_info);
1008 if ((flags & SigmaValue) == 0)
1009 geometry_info.sigma=geometry_info.rho;
1010 jpeg_calc_output_dimensions(&jpeg_info);
1011 image->magick_columns=jpeg_info.output_width;
1012 image->magick_rows=jpeg_info.output_height;
1014 if (geometry_info.rho != 0.0)
1015 scale_factor=jpeg_info.output_width/geometry_info.rho;
1016 if ((geometry_info.sigma != 0.0) &&
1017 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1018 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1019 jpeg_info.scale_num=1U;
1020 jpeg_info.scale_denom=(unsigned int) scale_factor;
1021 jpeg_calc_output_dimensions(&jpeg_info);
1022 if (image->debug != MagickFalse)
1023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Scale factor: %ld",
1024 (long) scale_factor);
1026 precision=(unsigned long) jpeg_info.data_precision;
1027 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1028 #if defined(D_LOSSLESS_SUPPORTED)
1029 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1030 JPEGInterlace : NoInterlace;
1031 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1032 LosslessJPEGCompression : JPEGCompression;
1033 if (jpeg_info.data_precision > 8)
1034 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1035 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1037 if (jpeg_info.data_precision == 16)
1038 jpeg_info.data_precision=12;
1040 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1042 image->compression=JPEGCompression;
1045 image->compression=JPEGCompression;
1046 image->interlace=JPEGInterlace;
1048 if ((image_info->colors > 8) && (image_info->colors <= 256))
1051 Let the JPEG library quantize for us.
1053 jpeg_info.quantize_colors=MagickTrue;
1054 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1056 option=GetImageOption(image_info,"jpeg:block-smoothing");
1057 if (option != (const char *) NULL)
1059 jpeg_info.do_block_smoothing=MagickFalse;
1060 if (IsMagickTrue(option) != MagickFalse)
1061 jpeg_info.do_block_smoothing=MagickTrue;
1063 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1064 if (option != (const char *) NULL)
1066 jpeg_info.do_fancy_upsampling=MagickFalse;
1067 if (IsMagickTrue(option) != MagickFalse)
1068 jpeg_info.do_fancy_upsampling=MagickTrue;
1070 (void) jpeg_start_decompress(&jpeg_info);
1071 image->columns=jpeg_info.output_width;
1072 image->rows=jpeg_info.output_height;
1073 image->depth=(unsigned long) jpeg_info.data_precision;
1074 if (jpeg_info.out_color_space == JCS_YCbCr)
1075 image->colorspace=YCbCrColorspace;
1076 if (jpeg_info.out_color_space == JCS_CMYK)
1077 image->colorspace=CMYKColorspace;
1078 if ((image_info->colors != 0) && (image_info->colors <= 256))
1079 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1080 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1081 if ((jpeg_info.output_components == 1) &&
1082 (jpeg_info.quantize_colors == MagickFalse))
1087 colors=(unsigned long) GetQuantumRange(image->depth)+1;
1088 if (AcquireImageColormap(image,colors) == MagickFalse)
1089 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1091 if (image->debug != MagickFalse)
1093 if (image->interlace != NoInterlace)
1094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1095 "Interlace: progressive");
1097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1098 "Interlace: nonprogressive");
1099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1100 (int) jpeg_info.data_precision);
1101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1102 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1104 JPEGSetImageQuality(&jpeg_info,image);
1105 JPEGSetImageSamplingFactor(&jpeg_info,image);
1106 (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
1107 jpeg_info.out_color_space);
1108 (void) SetImageProperty(image,"jpeg:colorspace",value);
1109 if (image_info->ping != MagickFalse)
1111 jpeg_destroy_decompress(&jpeg_info);
1112 (void) CloseBlob(image);
1113 return(GetFirstImageInList(image));
1115 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1116 jpeg_info.output_components*sizeof(JSAMPLE));
1117 if (jpeg_pixels == (JSAMPLE *) NULL)
1118 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1120 Convert JPEG pixels to pixel packets.
1122 if (setjmp(error_manager.error_recovery) != 0)
1124 if (jpeg_pixels != (unsigned char *) NULL)
1125 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1126 jpeg_destroy_decompress(&jpeg_info);
1127 (void) CloseBlob(image);
1128 number_pixels=(MagickSizeType) image->columns*image->rows;
1129 if (number_pixels != 0)
1130 return(GetFirstImageInList(image));
1131 return(DestroyImage(image));
1133 if (jpeg_info.quantize_colors != MagickFalse)
1135 image->colors=(unsigned long) jpeg_info.actual_number_of_colors;
1136 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1137 for (i=0; i < (long) image->colors; i++)
1139 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1140 image->colormap[i].green=image->colormap[i].red;
1141 image->colormap[i].blue=image->colormap[i].red;
1142 image->colormap[i].opacity=OpaqueOpacity;
1145 for (i=0; i < (long) image->colors; i++)
1147 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1148 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1149 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1150 image->colormap[i].opacity=OpaqueOpacity;
1153 scanline[0]=(JSAMPROW) jpeg_pixels;
1154 for (y=0; y < (long) image->rows; y++)
1156 register IndexPacket
1162 register PixelPacket
1165 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1167 (void) ThrowMagickException(exception,GetMagickModule(),
1168 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1172 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1173 if (q == (PixelPacket *) NULL)
1175 indexes=GetAuthenticIndexQueue(image);
1176 if (jpeg_info.data_precision > 8)
1178 if (jpeg_info.output_components == 1)
1179 for (x=0; x < (long) image->columns; x++)
1184 if (precision != 16)
1185 pixel=(unsigned long) GETJSAMPLE(*p);
1187 pixel=(unsigned long) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1188 jindex=ConstrainColormapIndex(image,pixel);
1190 *q++=image->colormap[(int) jindex];
1194 if (image->colorspace != CMYKColorspace)
1195 for (x=0; x < (long) image->columns; x++)
1197 q->red=ScaleShortToQuantum((unsigned char)
1198 (GETJSAMPLE(*p++) << 4));
1199 q->green=ScaleShortToQuantum((unsigned char)
1200 (GETJSAMPLE(*p++) << 4));
1201 q->blue=ScaleShortToQuantum((unsigned char)
1202 (GETJSAMPLE(*p++) << 4));
1203 q->opacity=OpaqueOpacity;
1207 for (x=0; x < (long) image->columns; x++)
1209 q->red=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1210 (GETJSAMPLE(*p++) << 4));
1211 q->green=(Quantum) QuantumRange-ScaleShortToQuantum(
1212 (unsigned char) (GETJSAMPLE(*p++) << 4));
1213 q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1214 (GETJSAMPLE(*p++) << 4));
1215 q->opacity=OpaqueOpacity;
1216 indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
1217 (unsigned char) (GETJSAMPLE(*p++) << 4));
1222 if (jpeg_info.output_components == 1)
1223 for (x=0; x < (long) image->columns; x++)
1225 jindex=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
1226 indexes[x]=(IndexPacket) jindex;
1227 *q++=image->colormap[(int) jindex];
1231 if (image->colorspace != CMYKColorspace)
1232 for (x=0; x < (long) image->columns; x++)
1234 q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1235 q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1236 q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1237 q->opacity=OpaqueOpacity;
1241 for (x=0; x < (long) image->columns; x++)
1243 q->red=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1245 q->green=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1247 q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1249 q->opacity=OpaqueOpacity;
1250 indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
1251 (unsigned char) GETJSAMPLE(*p++));
1254 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1256 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
1260 Free jpeg resources.
1262 (void) jpeg_finish_decompress(&jpeg_info);
1263 jpeg_destroy_decompress(&jpeg_info);
1264 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1265 (void) CloseBlob(image);
1266 return(GetFirstImageInList(image));
1271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1275 % R e g i s t e r J P E G I m a g e %
1279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281 % RegisterJPEGImage() adds properties for the JPEG image format to
1282 % the list of supported formats. The properties include the image format
1283 % tag, a method to read and/or write the format, whether the format
1284 % supports the saving of more than one frame to the same file or blob,
1285 % whether the format supports native in-memory I/O, and a brief
1286 % description of the format.
1288 % The format of the RegisterJPEGImage method is:
1290 % unsigned long RegisterJPEGImage(void)
1293 ModuleExport unsigned long RegisterJPEGImage(void)
1296 version[MaxTextExtent];
1302 description[] = "Joint Photographic Experts Group JFIF format";
1305 #if defined(JPEG_LIB_VERSION)
1306 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1308 entry=SetMagickInfo("JPEG");
1309 entry->thread_support=NoThreadSupport;
1310 #if defined(MAGICKCORE_JPEG_DELEGATE)
1311 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1312 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1314 entry->magick=(IsImageFormatHandler *) IsJPEG;
1315 entry->adjoin=MagickFalse;
1316 entry->description=ConstantString(description);
1317 if (*version != '\0')
1318 entry->version=ConstantString(version);
1319 entry->module=ConstantString("JPEG");
1320 (void) RegisterMagickInfo(entry);
1321 entry=SetMagickInfo("JPG");
1322 entry->thread_support=NoThreadSupport;
1323 #if defined(MAGICKCORE_JPEG_DELEGATE)
1324 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1325 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1327 entry->adjoin=MagickFalse;
1328 entry->description=ConstantString(description);
1329 if (*version != '\0')
1330 entry->version=ConstantString(version);
1331 entry->module=ConstantString("JPEG");
1332 (void) RegisterMagickInfo(entry);
1333 entry=SetMagickInfo("PJPEG");
1334 entry->thread_support=NoThreadSupport;
1335 #if defined(MAGICKCORE_JPEG_DELEGATE)
1336 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1337 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1339 entry->adjoin=MagickFalse;
1340 entry->description=ConstantString(description);
1341 if (*version != '\0')
1342 entry->version=ConstantString(version);
1343 entry->module=ConstantString("JPEG");
1344 (void) RegisterMagickInfo(entry);
1345 return(MagickImageCoderSignature);
1349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 % U n r e g i s t e r J P E G I m a g e %
1357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 % UnregisterJPEGImage() removes format registrations made by the
1360 % JPEG module from the list of supported formats.
1362 % The format of the UnregisterJPEGImage method is:
1364 % UnregisterJPEGImage(void)
1367 ModuleExport void UnregisterJPEGImage(void)
1369 (void) UnregisterMagickInfo("PJPG");
1370 (void) UnregisterMagickInfo("JPEG");
1371 (void) UnregisterMagickInfo("JPG");
1374 #if defined(MAGICKCORE_JPEG_DELEGATE)
1376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380 % W r i t e J P E G I m a g e %
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 % WriteJPEGImage() writes a JPEG image file and returns it. It
1387 % allocates the memory necessary for the new Image structure and returns a
1388 % pointer to the new image.
1390 % The format of the WriteJPEGImage method is:
1392 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,Image *image)
1394 % A description of each parameter follows:
1396 % o image_info: the image info.
1398 % o jpeg_image: The image.
1403 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1408 destination=(DestinationManager *) cinfo->dest;
1409 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1410 MaxBufferExtent,destination->buffer);
1411 if (destination->manager.free_in_buffer != MaxBufferExtent)
1412 ERREXIT(cinfo,JERR_FILE_WRITE);
1413 destination->manager.next_output_byte=destination->buffer;
1417 static void InitializeDestination(j_compress_ptr cinfo)
1422 destination=(DestinationManager *) cinfo->dest;
1423 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1424 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1425 destination->manager.next_output_byte=destination->buffer;
1426 destination->manager.free_in_buffer=MaxBufferExtent;
1429 static inline size_t MagickMin(const size_t x,const size_t y)
1436 static void TerminateDestination(j_compress_ptr cinfo)
1441 destination=(DestinationManager *) cinfo->dest;
1442 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1447 count=WriteBlob(destination->image,MaxBufferExtent-
1448 destination->manager.free_in_buffer,destination->buffer);
1449 if (count != (ssize_t)
1450 (MaxBufferExtent-destination->manager.free_in_buffer))
1451 ERREXIT(cinfo,JERR_FILE_WRITE);
1455 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1479 Save image profile as a APP marker.
1482 custom_profile=AcquireStringInfo(65535L);
1483 ResetImageProfileIterator(image);
1484 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1486 profile=GetImageProfile(image,name);
1487 if (LocaleCompare(name,"EXIF") == 0)
1488 for (i=0; i < (long) GetStringInfoLength(profile); i+=65533L)
1490 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1491 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1492 (unsigned int) length);
1494 if (LocaleCompare(name,"ICC") == 0)
1496 register unsigned char
1500 p=GetStringInfoDatum(custom_profile);
1501 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1502 for (i=0; i < (long) GetStringInfoLength(profile); i+=65519L)
1504 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1505 p=GetStringInfoDatum(custom_profile);
1506 p[12]=(unsigned char) ((i/65519L)+1);
1507 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1508 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1510 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1511 custom_profile),(unsigned int) (length+tag_length));
1514 if (((LocaleCompare(name,"IPTC") == 0) ||
1515 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1517 register unsigned char
1524 p=GetStringInfoDatum(custom_profile);
1525 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1527 (void) CopyMagickMemory(p,"Photoshop 3.0\0",14);
1532 (void) CopyMagickMemory(p,"Photoshop 3.0\08BIM\04\04\0\0\0\0",24);
1534 p[24]=(unsigned char) (GetStringInfoLength(profile) >> 8);
1535 p[25]=(unsigned char) (GetStringInfoLength(profile) & 0xff);
1538 for (i=0; i < (long) GetStringInfoLength(profile); i+=65500L)
1540 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1541 roundup=(unsigned long) (length & 0x01);
1542 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1545 p[length+tag_length]='\0';
1546 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1547 custom_profile),(unsigned int) (length+tag_length+roundup));
1550 if (LocaleCompare(name,"XMP") == 0)
1556 Add namespace to XMP profile.
1558 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1559 ConcatenateStringInfo(xmp_profile,profile);
1560 GetStringInfoDatum(xmp_profile)[28]='\0';
1561 for (i=0; i < (long) GetStringInfoLength(xmp_profile); i+=65533L)
1563 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1564 jpeg_write_marker(jpeg_info,XML_MARKER,
1565 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1567 xmp_profile=DestroyStringInfo(xmp_profile);
1569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s profile: %lu bytes",
1570 name,(unsigned long) GetStringInfoLength(profile));
1571 name=GetNextImageProfile(image);
1573 custom_profile=DestroyStringInfo(custom_profile);
1576 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1581 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1582 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1583 destination=(DestinationManager *) cinfo->dest;
1584 destination->manager.init_destination=InitializeDestination;
1585 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1586 destination->manager.term_destination=TerminateDestination;
1587 destination->image=image;
1590 static char **SamplingFactorToList(const char *text)
1607 if (text == (char *) NULL)
1608 return((char **) NULL);
1610 Convert string to an ASCII list.
1613 for (p=text; *p != '\0'; p++)
1616 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1618 if (textlist == (char **) NULL)
1619 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1621 for (i=0; i < (long) lines; i++)
1623 for (q=(char *) p; *q != '\0'; q++)
1626 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1627 sizeof(*textlist[i]));
1628 if (textlist[i] == (char *) NULL)
1629 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1630 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1635 textlist[i]=(char *) NULL;
1639 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1668 struct jpeg_compress_struct
1671 struct jpeg_error_mgr
1677 assert(image_info != (const ImageInfo *) NULL);
1678 assert(image_info->signature == MagickSignature);
1679 assert(image != (Image *) NULL);
1680 assert(image->signature == MagickSignature);
1681 if (image->debug != MagickFalse)
1682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1683 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1684 if (status == MagickFalse)
1687 Initialize JPEG parameters.
1689 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1690 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1691 jpeg_info.client_data=(void *) image;
1692 jpeg_info.err=jpeg_std_error(&jpeg_error);
1693 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
1694 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1695 error_manager.image=image;
1696 jpeg_pixels=(JSAMPLE *) NULL;
1697 if (setjmp(error_manager.error_recovery) != 0)
1699 jpeg_destroy_compress(&jpeg_info);
1700 (void) CloseBlob(image);
1701 return(MagickFalse);
1703 jpeg_info.client_data=(void *) &error_manager;
1704 jpeg_create_compress(&jpeg_info);
1705 JPEGDestinationManager(&jpeg_info,image);
1706 if ((image->columns != (unsigned int) image->columns) ||
1707 (image->rows != (unsigned int) image->rows))
1708 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1709 jpeg_info.image_width=(unsigned int) image->columns;
1710 jpeg_info.image_height=(unsigned int) image->rows;
1711 jpeg_info.input_components=3;
1712 jpeg_info.data_precision=8;
1713 jpeg_info.in_color_space=JCS_RGB;
1714 switch (image->colorspace)
1716 case CMYKColorspace:
1718 jpeg_info.input_components=4;
1719 jpeg_info.in_color_space=JCS_CMYK;
1722 case YCbCrColorspace:
1723 case Rec601YCbCrColorspace:
1724 case Rec709YCbCrColorspace:
1726 jpeg_info.in_color_space=JCS_YCbCr;
1729 case GRAYColorspace:
1730 case Rec601LumaColorspace:
1731 case Rec709LumaColorspace:
1733 jpeg_info.input_components=1;
1734 jpeg_info.in_color_space=JCS_GRAYSCALE;
1740 if ((image_info->type != TrueColorType) &&
1741 (IsGrayImage(image,&image->exception) != MagickFalse))
1743 jpeg_info.input_components=1;
1744 jpeg_info.in_color_space=JCS_GRAYSCALE;
1746 jpeg_set_defaults(&jpeg_info);
1747 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1748 jpeg_info.data_precision=8;
1750 if (sizeof(JSAMPLE) > 1)
1751 jpeg_info.data_precision=12;
1752 jpeg_info.density_unit=(UINT8) 1;
1753 if (image->debug != MagickFalse)
1754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1755 "Image resolution: %ld,%ld",(long) (image->x_resolution+0.5),
1756 (long) (image->y_resolution+0.5));
1757 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1760 Set image resolution.
1762 jpeg_info.write_JFIF_header=MagickTrue;
1763 jpeg_info.X_density=(UINT16) image->x_resolution;
1764 jpeg_info.Y_density=(UINT16) image->y_resolution;
1765 if (image->units == PixelsPerInchResolution)
1766 jpeg_info.density_unit=(UINT8) 1;
1767 if (image->units == PixelsPerCentimeterResolution)
1768 jpeg_info.density_unit=(UINT8) 2;
1770 option=GetImageOption(image_info,"jpeg:dct-method");
1771 if (option != (const char *) NULL)
1777 if (LocaleCompare(option,"default") == 0)
1778 jpeg_info.dct_method=JDCT_DEFAULT;
1784 if (LocaleCompare(option,"fastest") == 0)
1785 jpeg_info.dct_method=JDCT_FASTEST;
1786 if (LocaleCompare(option,"float") == 0)
1787 jpeg_info.dct_method=JDCT_FLOAT;
1793 if (LocaleCompare(option,"ifast") == 0)
1794 jpeg_info.dct_method=JDCT_IFAST;
1795 if (LocaleCompare(option,"islow") == 0)
1796 jpeg_info.dct_method=JDCT_ISLOW;
1800 option=GetImageOption(image_info,"jpeg:optimize-coding");
1801 if (option != (const char *) NULL)
1803 jpeg_info.optimize_coding=MagickFalse;
1804 if (IsMagickTrue(option) != MagickFalse)
1805 jpeg_info.optimize_coding=MagickTrue;
1812 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1813 image->rows*sizeof(JSAMPLE);
1814 if (length == (MagickSizeType) ((size_t) length))
1817 Perform optimization only if available memory resources permit it.
1819 status=AcquireMagickResource(MemoryResource,length);
1820 if (status != MagickFalse)
1821 jpeg_info.optimize_coding=MagickTrue;
1822 RelinquishMagickResource(MemoryResource,length);
1825 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1826 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1827 (image_info->interlace != NoInterlace))
1829 if (image->debug != MagickFalse)
1830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1831 "Interlace: progressive");
1832 jpeg_simple_progression(&jpeg_info);
1835 if (image->debug != MagickFalse)
1836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1837 "Interlace: non-progressive");
1839 if (image->debug != MagickFalse)
1840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1841 "Interlace: nonprogressive");
1843 option=GetImageOption(image_info,"jpeg:extent");
1844 if (option != (const char *) NULL)
1852 jpeg_info=CloneImageInfo(image_info);
1853 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1854 if (jpeg_image != (Image *) NULL)
1864 Search for compression quality that does not exceed image extent.
1866 jpeg_info->quality=0;
1867 extent=(MagickSizeType) StringToDouble(option,100.0);
1868 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1869 (void) AcquireUniqueFilename(jpeg_image->filename);
1871 for (max=100; (max-min) > 1; )
1873 jpeg_image->quality=min+(max-min)/2;
1874 status=WriteJPEGImage(jpeg_info,jpeg_image);
1875 if (GetBlobSize(jpeg_image) < extent)
1876 min=jpeg_image->quality+1;
1878 max=jpeg_image->quality-1;
1880 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1882 jpeg_image=DestroyImage(jpeg_image);
1884 jpeg_info=DestroyImageInfo(jpeg_info);
1886 if ((image_info->compression != LosslessJPEGCompression) &&
1887 (image->quality <= 100))
1889 if (image->quality == UndefinedCompressionQuality)
1890 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1892 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1893 if (image->debug != MagickFalse)
1894 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
1899 #if !defined(C_LOSSLESS_SUPPORTED)
1900 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1901 if (image->debug != MagickFalse)
1902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1904 if (image->quality < 100)
1905 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1906 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1913 predictor=image->quality/100; /* range 1-7 */
1914 point_transform=image->quality % 20; /* range 0-15 */
1915 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1916 if (image->debug != MagickFalse)
1918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1919 "Compression: lossless");
1920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1921 "Predictor: %d",predictor);
1922 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1923 "Point Transform: %d",point_transform);
1928 sampling_factor=(const char *) NULL;
1929 value=GetImageProperty(image,"jpeg:sampling-factor");
1930 if (value != (char *) NULL)
1932 sampling_factor=value;
1933 if (image->debug != MagickFalse)
1934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1935 " Input sampling-factors=%s",sampling_factor);
1937 if (image_info->sampling_factor != (char *) NULL)
1938 sampling_factor=image_info->sampling_factor;
1939 if (sampling_factor == (const char *) NULL)
1941 if (image->quality >= 90)
1942 for (i=0; i < MAX_COMPONENTS; i++)
1944 jpeg_info.comp_info[i].h_samp_factor=1;
1945 jpeg_info.comp_info[i].v_samp_factor=1;
1960 Set sampling factor.
1963 factors=SamplingFactorToList(sampling_factor);
1964 if (factors != (char **) NULL)
1966 for (i=0; i < MAX_COMPONENTS; i++)
1968 if (factors[i] == (char *) NULL)
1970 flags=ParseGeometry(factors[i],&geometry_info);
1971 if ((flags & SigmaValue) == 0)
1972 geometry_info.sigma=geometry_info.rho;
1973 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
1974 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
1975 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
1977 factors=(char **) RelinquishMagickMemory(factors);
1979 for ( ; i < MAX_COMPONENTS; i++)
1981 jpeg_info.comp_info[i].h_samp_factor=1;
1982 jpeg_info.comp_info[i].v_samp_factor=1;
1985 if (jpeg_info.input_components == 1)
1986 for (i=0; i < MAX_COMPONENTS; i++)
1988 jpeg_info.comp_info[i].h_samp_factor=1;
1989 jpeg_info.comp_info[i].v_samp_factor=1;
1991 jpeg_start_compress(&jpeg_info,MagickTrue);
1992 if (image->debug != MagickFalse)
1994 if (image->storage_class == PseudoClass)
1995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1996 "Storage class: PseudoClass");
1998 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1999 "Storage class: DirectClass");
2000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %lu",
2002 if (image->colors != 0)
2003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2004 "Number of colors: %lu",image->colors);
2006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2007 "Number of colors: unspecified");
2008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2009 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2010 switch (image->colorspace)
2012 case CMYKColorspace:
2014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2015 "Storage class: DirectClass");
2016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2017 "Colorspace: CMYK");
2020 case YCbCrColorspace:
2021 case Rec601YCbCrColorspace:
2022 case Rec709YCbCrColorspace:
2024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2025 "Colorspace: YCbCr");
2031 switch (image->colorspace)
2033 case CMYKColorspace:
2035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2036 "Colorspace: CMYK");
2037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2038 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2039 jpeg_info.comp_info[0].h_samp_factor,
2040 jpeg_info.comp_info[0].v_samp_factor,
2041 jpeg_info.comp_info[1].h_samp_factor,
2042 jpeg_info.comp_info[1].v_samp_factor,
2043 jpeg_info.comp_info[2].h_samp_factor,
2044 jpeg_info.comp_info[2].v_samp_factor,
2045 jpeg_info.comp_info[3].h_samp_factor,
2046 jpeg_info.comp_info[3].v_samp_factor);
2049 case GRAYColorspace:
2050 case Rec601LumaColorspace:
2051 case Rec709LumaColorspace:
2053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2054 "Colorspace: GRAY");
2055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2056 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2057 jpeg_info.comp_info[0].v_samp_factor);
2062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2063 "Image colorspace is RGB");
2064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2065 "Sampling factors: %dx%d,%dx%d,%dx%d",
2066 jpeg_info.comp_info[0].h_samp_factor,
2067 jpeg_info.comp_info[0].v_samp_factor,
2068 jpeg_info.comp_info[1].h_samp_factor,
2069 jpeg_info.comp_info[1].v_samp_factor,
2070 jpeg_info.comp_info[2].h_samp_factor,
2071 jpeg_info.comp_info[2].v_samp_factor);
2074 case YCbCrColorspace:
2075 case Rec601YCbCrColorspace:
2076 case Rec709YCbCrColorspace:
2078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2079 "Colorspace: YCbCr");
2080 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2081 "Sampling factors: %dx%d,%dx%d,%dx%d",
2082 jpeg_info.comp_info[0].h_samp_factor,
2083 jpeg_info.comp_info[0].v_samp_factor,
2084 jpeg_info.comp_info[1].h_samp_factor,
2085 jpeg_info.comp_info[1].v_samp_factor,
2086 jpeg_info.comp_info[2].h_samp_factor,
2087 jpeg_info.comp_info[2].v_samp_factor);
2092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2095 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2096 jpeg_info.comp_info[0].h_samp_factor,
2097 jpeg_info.comp_info[0].v_samp_factor,
2098 jpeg_info.comp_info[1].h_samp_factor,
2099 jpeg_info.comp_info[1].v_samp_factor,
2100 jpeg_info.comp_info[2].h_samp_factor,
2101 jpeg_info.comp_info[2].v_samp_factor,
2102 jpeg_info.comp_info[3].h_samp_factor,
2103 jpeg_info.comp_info[3].v_samp_factor);
2109 Write JPEG profiles.
2111 value=GetImageProperty(image,"comment");
2112 if (value != (char *) NULL)
2113 for (i=0; i < (long) strlen(value); i+=65533L)
2114 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2115 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2116 if (image->profiles != (void *) NULL)
2117 WriteProfile(&jpeg_info,image);
2119 Convert MIFF to JPEG raster pixels.
2121 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2122 jpeg_info.input_components*sizeof(*jpeg_pixels));
2123 if (jpeg_pixels == (JSAMPLE *) NULL)
2124 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2125 if (setjmp(error_manager.error_recovery) != 0)
2127 jpeg_destroy_compress(&jpeg_info);
2128 if (jpeg_pixels != (unsigned char *) NULL)
2129 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2130 (void) CloseBlob(image);
2131 return(MagickFalse);
2133 scanline[0]=(JSAMPROW) jpeg_pixels;
2134 if (jpeg_info.data_precision > 8)
2136 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2137 for (y=0; y < (long) image->rows; y++)
2139 register const PixelPacket
2145 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2146 if (p == (const PixelPacket *) NULL)
2149 for (x=0; x < (long) image->columns; x++)
2151 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2155 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2156 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2160 if ((jpeg_info.in_color_space == JCS_RGB) ||
2161 (jpeg_info.in_color_space == JCS_YCbCr))
2162 for (y=0; y < (long) image->rows; y++)
2164 register const PixelPacket
2170 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2171 if (p == (const PixelPacket *) NULL)
2174 for (x=0; x < (long) image->columns; x++)
2176 *q++=(JSAMPLE) (ScaleQuantumToShort(p->red) >> 4);
2177 *q++=(JSAMPLE) (ScaleQuantumToShort(p->green) >> 4);
2178 *q++=(JSAMPLE) (ScaleQuantumToShort(p->blue) >> 4);
2181 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2182 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2183 if (status == MagickFalse)
2187 for (y=0; y < (long) image->rows; y++)
2189 register const IndexPacket
2192 register const PixelPacket
2198 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2199 if (p == (const PixelPacket *) NULL)
2202 indexes=GetVirtualIndexQueue(image);
2203 for (x=0; x < (long) image->columns; x++)
2206 Convert DirectClass packets to contiguous CMYK scanlines.
2208 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->red) >> 4));
2209 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->green) >> 4));
2210 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->blue) >> 4));
2211 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
2214 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2215 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2216 if (status == MagickFalse)
2221 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2222 for (y=0; y < (long) image->rows; y++)
2224 register const PixelPacket
2230 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2231 if (p == (const PixelPacket *) NULL)
2234 for (x=0; x < (long) image->columns; x++)
2236 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2239 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2240 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2244 if ((jpeg_info.in_color_space == JCS_RGB) ||
2245 (jpeg_info.in_color_space == JCS_YCbCr))
2246 for (y=0; y < (long) image->rows; y++)
2248 register const PixelPacket
2254 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2255 if (p == (const PixelPacket *) NULL)
2258 for (x=0; x < (long) image->columns; x++)
2260 *q++=(JSAMPLE) ScaleQuantumToChar(p->red);
2261 *q++=(JSAMPLE) ScaleQuantumToChar(p->green);
2262 *q++=(JSAMPLE) ScaleQuantumToChar(p->blue);
2265 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2266 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2270 for (y=0; y < (long) image->rows; y++)
2272 register const IndexPacket
2275 register const PixelPacket
2281 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2282 if (p == (const PixelPacket *) NULL)
2285 indexes=GetVirtualIndexQueue(image);
2286 for (x=0; x < (long) image->columns; x++)
2289 Convert DirectClass packets to contiguous CMYK scanlines.
2291 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2293 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2295 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2297 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2301 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2302 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2305 if (y == (long) image->rows)
2306 jpeg_finish_compress(&jpeg_info);
2308 Relinquish resources.
2310 jpeg_destroy_compress(&jpeg_info);
2311 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2312 (void) CloseBlob(image);