2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2012 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 "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/token.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/xml-tree.h"
83 #include "MagickCore/xml-tree-private.h"
85 #if defined(MAGICKCORE_JPEG_DELEGATE)
86 #define JPEG_INTERNAL_OPTIONS
87 #if defined(__MINGW32__)
88 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
89 typedef unsigned char boolean;
100 #define ICC_MARKER (JPEG_APP0+2)
101 #define ICC_PROFILE "ICC_PROFILE"
102 #define IPTC_MARKER (JPEG_APP0+13)
103 #define XML_MARKER (JPEG_APP0+1)
104 #define MaxBufferExtent 16384
107 Typedef declarations.
109 #if defined(MAGICKCORE_JPEG_DELEGATE)
110 typedef struct _DestinationManager
112 struct jpeg_destination_mgr
120 } DestinationManager;
122 typedef struct _ErrorManager
137 typedef struct _SourceManager
139 struct jpeg_source_mgr
153 typedef struct _QuantizationTable
171 Forward declarations.
173 #if defined(MAGICKCORE_JPEG_DELEGATE)
174 static MagickBooleanType
175 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 % IsJPEG() returns MagickTrue if the image format type, identified by the
190 % magick string, is JPEG.
192 % The format of the IsJPEG method is:
194 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
196 % A description of each parameter follows:
198 % o magick: compare image format pattern against these bytes.
200 % o length: Specifies the length of the magick string.
203 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
207 if (memcmp(magick,"\377\330\377",3) == 0)
212 #if defined(MAGICKCORE_JPEG_DELEGATE)
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218 % R e a d J P E G I m a g e %
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
225 % the memory necessary for the new Image structure and returns a pointer to
228 % The format of the ReadJPEGImage method is:
230 % Image *ReadJPEGImage(const ImageInfo *image_info,
231 % ExceptionInfo *exception)
233 % A description of each parameter follows:
235 % o image_info: the image info.
237 % o exception: return any errors or warnings in this structure.
241 static boolean FillInputBuffer(j_decompress_ptr cinfo)
246 source=(SourceManager *) cinfo->src;
247 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
248 MaxBufferExtent,source->buffer);
249 if (source->manager.bytes_in_buffer == 0)
251 if (source->start_of_blob != FALSE)
252 ERREXIT(cinfo,JERR_INPUT_EMPTY);
253 WARNMS(cinfo,JWRN_JPEG_EOF);
254 source->buffer[0]=(JOCTET) 0xff;
255 source->buffer[1]=(JOCTET) JPEG_EOI;
256 source->manager.bytes_in_buffer=2;
258 source->manager.next_input_byte=source->buffer;
259 source->start_of_blob=FALSE;
263 static int GetCharacter(j_decompress_ptr jpeg_info)
265 if (jpeg_info->src->bytes_in_buffer == 0)
266 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
267 jpeg_info->src->bytes_in_buffer--;
268 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
271 static void InitializeSource(j_decompress_ptr cinfo)
276 source=(SourceManager *) cinfo->src;
277 source->start_of_blob=TRUE;
280 static MagickBooleanType IsITUFaxImage(const Image *image)
288 profile=GetImageProfile(image,"8bim");
289 if (profile == (const StringInfo *) NULL)
291 if (GetStringInfoLength(profile) < 5)
293 datum=GetStringInfoDatum(profile);
294 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
295 (datum[3] == 0x41) && (datum[4] == 0x58))
300 static void JPEGErrorHandler(j_common_ptr jpeg_info)
303 message[JMSG_LENGTH_MAX];
315 error_manager=(ErrorManager *) jpeg_info->client_data;
316 image=error_manager->image;
317 exception=error_manager->exception;
318 (jpeg_info->err->format_message)(jpeg_info,message);
319 if (image->debug != MagickFalse)
320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
321 "[%s] JPEG Trace: \"%s\"",image->filename,message);
322 if (error_manager->finished != MagickFalse)
323 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
324 (char *) message,"`%s'",image->filename);
326 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
327 (char *) message,"`%s'",image->filename);
328 longjmp(error_manager->error_recovery,1);
331 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
333 #define JPEGExcessiveWarnings 1000
336 message[JMSG_LENGTH_MAX];
348 error_manager=(ErrorManager *) jpeg_info->client_data;
349 exception=error_manager->exception;
350 image=error_manager->image;
354 Process warning message.
356 (jpeg_info->err->format_message)(jpeg_info,message);
357 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
358 JPEGErrorHandler(jpeg_info);
359 ThrowBinaryException(CorruptImageWarning,(char *) message,
363 if ((image->debug != MagickFalse) &&
364 (level >= jpeg_info->err->trace_level))
367 Process trace message.
369 (jpeg_info->err->format_message)(jpeg_info,message);
370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
371 "[%s] JPEG Trace: \"%s\"",image->filename,message);
376 static boolean ReadComment(j_decompress_ptr jpeg_info)
400 Determine length of comment.
402 error_manager=(ErrorManager *) jpeg_info->client_data;
403 exception=error_manager->exception;
404 image=error_manager->image;
405 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
406 length+=GetCharacter(jpeg_info);
410 comment=(char *) NULL;
411 if (~length >= (MaxTextExtent-1))
412 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
414 if (comment == (char *) NULL)
415 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
420 i=(ssize_t) length-1;
421 for (p=comment; i-- >= 0; p++)
422 *p=(char) GetCharacter(jpeg_info);
424 (void) SetImageProperty(image,"comment",comment,exception);
425 comment=DestroyString(comment);
429 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
449 register unsigned char
462 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
463 length+=(size_t) GetCharacter(jpeg_info);
468 (void) GetCharacter(jpeg_info);
471 for (i=0; i < 12; i++)
472 magick[i]=(char) GetCharacter(jpeg_info);
473 if (LocaleCompare(magick,ICC_PROFILE) != 0)
476 Not a ICC profile, return.
478 for (i=0; i < (ssize_t) (length-12); i++)
479 (void) GetCharacter(jpeg_info);
482 (void) GetCharacter(jpeg_info); /* id */
483 (void) GetCharacter(jpeg_info); /* markers */
485 error_manager=(ErrorManager *) jpeg_info->client_data;
486 exception=error_manager->exception;
487 image=error_manager->image;
488 profile=BlobToStringInfo((const void *) NULL,length);
489 if (profile == (StringInfo *) NULL)
490 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
492 p=GetStringInfoDatum(profile);
493 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
494 *p++=(unsigned char) GetCharacter(jpeg_info);
495 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
496 if (icc_profile != (StringInfo *) NULL)
498 ConcatenateStringInfo(icc_profile,profile);
499 profile=DestroyStringInfo(profile);
503 status=SetImageProfile(image,"icc",profile,exception);
504 profile=DestroyStringInfo(profile);
505 if (status == MagickFalse)
506 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
509 if (image->debug != MagickFalse)
510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
511 "Profile: ICC, %.20g bytes",(double) length);
515 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
518 magick[MaxTextExtent];
535 register unsigned char
546 Determine length of binary data stored here.
548 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
549 length+=(size_t) GetCharacter(jpeg_info);
554 (void) GetCharacter(jpeg_info);
558 Validate that this was written as a Photoshop resource format slug.
560 for (i=0; i < 10; i++)
561 magick[i]=(char) GetCharacter(jpeg_info);
566 if (LocaleCompare(magick,"Photoshop ") != 0)
569 Not a IPTC profile, return.
571 for (i=0; i < (ssize_t) length; i++)
572 (void) GetCharacter(jpeg_info);
576 Remove the version number.
578 for (i=0; i < 4; i++)
579 (void) GetCharacter(jpeg_info);
585 error_manager=(ErrorManager *) jpeg_info->client_data;
586 exception=error_manager->exception;
587 image=error_manager->image;
588 profile=BlobToStringInfo((const void *) NULL,length);
589 if (profile == (StringInfo *) NULL)
590 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
592 p=GetStringInfoDatum(profile);
593 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
594 *p++=(unsigned char) GetCharacter(jpeg_info);
595 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
596 if (iptc_profile != (StringInfo *) NULL)
598 ConcatenateStringInfo(iptc_profile,profile);
599 profile=DestroyStringInfo(profile);
603 status=SetImageProfile(image,"8bim",profile,exception);
604 profile=DestroyStringInfo(profile);
605 if (status == MagickFalse)
606 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
609 if (image->debug != MagickFalse)
610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
611 "Profile: iptc, %.20g bytes",(double) length);
615 static boolean ReadProfile(j_decompress_ptr jpeg_info)
641 register unsigned char
651 Read generic profile.
653 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
654 length+=(size_t) GetCharacter(jpeg_info);
658 marker=jpeg_info->unread_marker-JPEG_APP0;
659 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
660 error_manager=(ErrorManager *) jpeg_info->client_data;
661 exception=error_manager->exception;
662 image=error_manager->image;
663 profile=BlobToStringInfo((const void *) NULL,length);
664 if (profile == (StringInfo *) NULL)
665 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
667 p=GetStringInfoDatum(profile);
668 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
669 *p++=(unsigned char) GetCharacter(jpeg_info);
672 p=GetStringInfoDatum(profile);
673 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
674 (void) CopyMagickString(name,"exif",MaxTextExtent);
675 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
681 Extract namespace from XMP profile.
683 p=GetStringInfoDatum(profile);
684 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
690 if (j < (ssize_t) GetStringInfoLength(profile))
691 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
692 (void) CopyMagickString(name,"xmp",MaxTextExtent);
695 previous_profile=GetImageProfile(image,name);
696 if (previous_profile != (const StringInfo *) NULL)
701 length=GetStringInfoLength(profile);
702 SetStringInfoLength(profile,GetStringInfoLength(profile)+
703 GetStringInfoLength(previous_profile));
704 (void) memmove(GetStringInfoDatum(profile)+
705 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
707 (void) memcpy(GetStringInfoDatum(profile),
708 GetStringInfoDatum(previous_profile),
709 GetStringInfoLength(previous_profile));
711 status=SetImageProfile(image,name,profile,exception);
712 profile=DestroyStringInfo(profile);
713 if (status == MagickFalse)
714 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
716 if (image->debug != MagickFalse)
717 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
718 "Profile: %s, %.20g bytes",name,(double) length);
722 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
727 if (number_bytes <= 0)
729 source=(SourceManager *) cinfo->src;
730 while (number_bytes > (long) source->manager.bytes_in_buffer)
732 number_bytes-=(long) source->manager.bytes_in_buffer;
733 (void) FillInputBuffer(cinfo);
735 source->manager.next_input_byte+=number_bytes;
736 source->manager.bytes_in_buffer-=number_bytes;
739 static void TerminateSource(j_decompress_ptr cinfo)
744 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
749 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
750 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
751 source=(SourceManager *) cinfo->src;
752 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
753 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
754 source=(SourceManager *) cinfo->src;
755 source->manager.init_source=InitializeSource;
756 source->manager.fill_input_buffer=FillInputBuffer;
757 source->manager.skip_input_data=SkipInputData;
758 source->manager.resync_to_restart=jpeg_resync_to_restart;
759 source->manager.term_source=TerminateSource;
760 source->manager.bytes_in_buffer=0;
761 source->manager.next_input_byte=NULL;
765 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
768 image->quality=UndefinedCompressionQuality;
769 #if defined(D_PROGRESSIVE_SUPPORTED)
770 if (image->compression == LosslessJPEGCompression)
773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
774 "Quality: 100 (lossless)");
788 Determine the JPEG compression quality from the quantization tables.
791 for (i=0; i < NUM_QUANT_TBLS; i++)
793 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
794 for (j=0; j < DCTSIZE2; j++)
795 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
797 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
798 (jpeg_info->quant_tbl_ptrs[1] != NULL))
803 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
804 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
805 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
806 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
807 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
808 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
809 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
810 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
811 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
812 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
817 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
818 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
819 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
820 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
821 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
822 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
823 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
824 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
825 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
826 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
827 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
831 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
832 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
833 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
834 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
835 for (i=0; i < 100; i++)
837 if ((qvalue < hash[i]) && (sum < sums[i]))
839 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
840 image->quality=(size_t) i+1;
841 if (image->debug != MagickFalse)
842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
843 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
844 (sum <= sums[i]) ? "exact" : "approximate");
849 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
854 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
855 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
856 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
857 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
858 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
859 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
860 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
861 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
862 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
863 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
868 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
869 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
870 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
871 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
872 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
873 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
874 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
875 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
876 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
877 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
878 667, 592, 518, 441, 369, 292, 221, 151, 86,
882 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
883 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
884 for (i=0; i < 100; i++)
886 if ((qvalue < hash[i]) && (sum < sums[i]))
888 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
889 image->quality=(size_t) i+1;
890 if (image->debug != MagickFalse)
891 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
892 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
893 (sum <= sums[i]) ? "exact" : "approximate");
900 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
903 sampling_factor[MaxTextExtent];
905 switch (jpeg_info->out_color_space)
909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
910 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
911 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
912 jpeg_info->comp_info[0].v_samp_factor,
913 jpeg_info->comp_info[1].h_samp_factor,
914 jpeg_info->comp_info[1].v_samp_factor,
915 jpeg_info->comp_info[2].h_samp_factor,
916 jpeg_info->comp_info[2].v_samp_factor,
917 jpeg_info->comp_info[3].h_samp_factor,
918 jpeg_info->comp_info[3].v_samp_factor);
923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
924 "Colorspace: GRAYSCALE");
925 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
926 jpeg_info->comp_info[0].h_samp_factor,
927 jpeg_info->comp_info[0].v_samp_factor);
932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
933 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
934 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
935 jpeg_info->comp_info[0].v_samp_factor,
936 jpeg_info->comp_info[1].h_samp_factor,
937 jpeg_info->comp_info[1].v_samp_factor,
938 jpeg_info->comp_info[2].h_samp_factor,
939 jpeg_info->comp_info[2].v_samp_factor);
944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
945 jpeg_info->out_color_space);
946 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
947 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
948 jpeg_info->comp_info[0].v_samp_factor,
949 jpeg_info->comp_info[1].h_samp_factor,
950 jpeg_info->comp_info[1].v_samp_factor,
951 jpeg_info->comp_info[2].h_samp_factor,
952 jpeg_info->comp_info[2].v_samp_factor,
953 jpeg_info->comp_info[3].h_samp_factor,
954 jpeg_info->comp_info[3].v_samp_factor);
958 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
960 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
964 static Image *ReadJPEGImage(const ImageInfo *image_info,
965 ExceptionInfo *exception)
968 value[MaxTextExtent];
998 struct jpeg_decompress_struct
1001 struct jpeg_error_mgr
1017 assert(image_info != (const ImageInfo *) NULL);
1018 assert(image_info->signature == MagickSignature);
1019 if (image_info->debug != MagickFalse)
1020 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1021 image_info->filename);
1022 assert(exception != (ExceptionInfo *) NULL);
1023 assert(exception->signature == MagickSignature);
1024 debug=IsEventLogging();
1026 image=AcquireImage(image_info,exception);
1027 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1028 if (status == MagickFalse)
1030 image=DestroyImageList(image);
1031 return((Image *) NULL);
1034 Initialize JPEG parameters.
1036 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1037 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1038 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1039 jpeg_info.err=jpeg_std_error(&jpeg_error);
1040 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1041 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1042 jpeg_pixels=(JSAMPLE *) NULL;
1043 error_manager.exception=exception;
1044 error_manager.image=image;
1045 if (setjmp(error_manager.error_recovery) != 0)
1047 jpeg_destroy_decompress(&jpeg_info);
1048 (void) CloseBlob(image);
1049 number_pixels=(MagickSizeType) image->columns*image->rows;
1050 if (number_pixels != 0)
1051 return(GetFirstImageInList(image));
1052 return(DestroyImage(image));
1054 jpeg_info.client_data=(void *) &error_manager;
1055 jpeg_create_decompress(&jpeg_info);
1056 JPEGSourceManager(&jpeg_info,image);
1057 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1058 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1059 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1060 for (i=1; i < 16; i++)
1061 if ((i != 2) && (i != 13) && (i != 14))
1062 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1063 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1064 if ((image_info->colorspace == YCbCrColorspace) ||
1065 (image_info->colorspace == Rec601YCbCrColorspace) ||
1066 (image_info->colorspace == Rec709YCbCrColorspace))
1067 jpeg_info.out_color_space=JCS_YCbCr;
1069 Set image resolution.
1072 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1073 (jpeg_info.Y_density != 1))
1075 image->resolution.x=(double) jpeg_info.X_density;
1076 image->resolution.y=(double) jpeg_info.Y_density;
1077 units=(size_t) jpeg_info.density_unit;
1080 image->units=PixelsPerInchResolution;
1082 image->units=PixelsPerCentimeterResolution;
1083 number_pixels=(MagickSizeType) image->columns*image->rows;
1084 option=GetImageOption(image_info,"jpeg:size");
1085 if (option != (const char *) NULL)
1099 flags=ParseGeometry(option,&geometry_info);
1100 if ((flags & SigmaValue) == 0)
1101 geometry_info.sigma=geometry_info.rho;
1102 jpeg_calc_output_dimensions(&jpeg_info);
1103 image->magick_columns=jpeg_info.output_width;
1104 image->magick_rows=jpeg_info.output_height;
1106 if (geometry_info.rho != 0.0)
1107 scale_factor=jpeg_info.output_width/geometry_info.rho;
1108 if ((geometry_info.sigma != 0.0) &&
1109 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1110 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1111 jpeg_info.scale_num=1U;
1112 jpeg_info.scale_denom=(unsigned int) scale_factor;
1113 jpeg_calc_output_dimensions(&jpeg_info);
1114 if (image->debug != MagickFalse)
1115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1116 "Scale factor: %.20g",(double) scale_factor);
1118 precision=(size_t) jpeg_info.data_precision;
1119 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1120 #if defined(D_LOSSLESS_SUPPORTED)
1121 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1122 JPEGInterlace : NoInterlace;
1123 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1124 LosslessJPEGCompression : JPEGCompression;
1125 if (jpeg_info.data_precision > 8)
1126 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1127 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1129 if (jpeg_info.data_precision == 16)
1130 jpeg_info.data_precision=12;
1132 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1134 image->compression=JPEGCompression;
1137 image->compression=JPEGCompression;
1138 image->interlace=JPEGInterlace;
1140 option=GetImageOption(image_info,"jpeg:colors");
1141 if (option != (const char *) NULL)
1144 Let the JPEG library quantize the image.
1146 jpeg_info.quantize_colors=MagickTrue;
1147 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1149 option=GetImageOption(image_info,"jpeg:block-smoothing");
1150 jpeg_info.do_block_smoothing=IsStringTrue(option);
1151 jpeg_info.dct_method=JDCT_FLOAT;
1152 option=GetImageOption(image_info,"jpeg:dct-method");
1153 if (option != (const char *) NULL)
1159 if (LocaleCompare(option,"default") == 0)
1160 jpeg_info.dct_method=JDCT_DEFAULT;
1166 if (LocaleCompare(option,"fastest") == 0)
1167 jpeg_info.dct_method=JDCT_FASTEST;
1168 if (LocaleCompare(option,"float") == 0)
1169 jpeg_info.dct_method=JDCT_FLOAT;
1175 if (LocaleCompare(option,"ifast") == 0)
1176 jpeg_info.dct_method=JDCT_IFAST;
1177 if (LocaleCompare(option,"islow") == 0)
1178 jpeg_info.dct_method=JDCT_ISLOW;
1182 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1183 jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1184 (void) jpeg_start_decompress(&jpeg_info);
1185 image->columns=jpeg_info.output_width;
1186 image->rows=jpeg_info.output_height;
1187 image->depth=(size_t) jpeg_info.data_precision;
1188 switch (jpeg_info.out_color_space)
1193 SetImageColorspace(image,sRGBColorspace,exception);
1198 SetImageColorspace(image,GRAYColorspace,exception);
1203 SetImageColorspace(image,YCbCrColorspace,exception);
1208 SetImageColorspace(image,CMYKColorspace,exception);
1212 if (IsITUFaxImage(image) != MagickFalse)
1214 SetImageColorspace(image,LabColorspace,exception);
1215 jpeg_info.out_color_space=JCS_YCbCr;
1217 option=GetImageOption(image_info,"jpeg:colors");
1218 if (option != (const char *) NULL)
1219 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1221 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1222 if ((jpeg_info.output_components == 1) &&
1223 (jpeg_info.quantize_colors == MagickFalse))
1228 colors=(size_t) GetQuantumRange(image->depth)+1;
1229 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1230 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1232 if (image->debug != MagickFalse)
1234 if (image->interlace != NoInterlace)
1235 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1236 "Interlace: progressive");
1238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1239 "Interlace: nonprogressive");
1240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1241 (int) jpeg_info.data_precision);
1242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1243 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1245 JPEGSetImageQuality(&jpeg_info,image);
1246 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1247 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1248 jpeg_info.out_color_space);
1249 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1250 if (image_info->ping != MagickFalse)
1252 jpeg_destroy_decompress(&jpeg_info);
1253 (void) CloseBlob(image);
1254 return(GetFirstImageInList(image));
1256 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1257 jpeg_info.output_components*sizeof(JSAMPLE));
1258 if (jpeg_pixels == (JSAMPLE *) NULL)
1259 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1261 Convert JPEG pixels to pixel packets.
1263 if (setjmp(error_manager.error_recovery) != 0)
1265 if (jpeg_pixels != (unsigned char *) NULL)
1266 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1267 jpeg_destroy_decompress(&jpeg_info);
1268 (void) CloseBlob(image);
1269 number_pixels=(MagickSizeType) image->columns*image->rows;
1270 if (number_pixels != 0)
1271 return(GetFirstImageInList(image));
1272 return(DestroyImage(image));
1274 if (jpeg_info.quantize_colors != MagickFalse)
1276 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1277 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1278 for (i=0; i < (ssize_t) image->colors; i++)
1280 image->colormap[i].red=(double) ScaleCharToQuantum(
1281 jpeg_info.colormap[0][i]);
1282 image->colormap[i].green=image->colormap[i].red;
1283 image->colormap[i].blue=image->colormap[i].red;
1284 image->colormap[i].alpha=OpaqueAlpha;
1287 for (i=0; i < (ssize_t) image->colors; i++)
1289 image->colormap[i].red=(double) ScaleCharToQuantum(
1290 jpeg_info.colormap[0][i]);
1291 image->colormap[i].green=(double) ScaleCharToQuantum(
1292 jpeg_info.colormap[1][i]);
1293 image->colormap[i].blue=(double) ScaleCharToQuantum(
1294 jpeg_info.colormap[2][i]);
1295 image->colormap[i].alpha=OpaqueAlpha;
1298 scanline[0]=(JSAMPROW) jpeg_pixels;
1299 for (y=0; y < (ssize_t) image->rows; y++)
1307 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1309 (void) ThrowMagickException(exception,GetMagickModule(),
1310 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1314 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1315 if (q == (Quantum *) NULL)
1317 if (jpeg_info.data_precision > 8)
1319 if (jpeg_info.output_components == 1)
1320 for (x=0; x < (ssize_t) image->columns; x++)
1325 if (precision != 16)
1326 pixel=(size_t) GETJSAMPLE(*p);
1328 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1329 index=ConstrainColormapIndex(image,pixel,exception);
1330 SetPixelIndex(image,index,q);
1331 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1333 q+=GetPixelChannels(image);
1336 if (image->colorspace != CMYKColorspace)
1337 for (x=0; x < (ssize_t) image->columns; x++)
1339 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1340 (GETJSAMPLE(*p++) << 4)),q);
1341 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1342 (GETJSAMPLE(*p++) << 4)),q);
1343 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1344 (GETJSAMPLE(*p++) << 4)),q);
1345 SetPixelAlpha(image,OpaqueAlpha,q);
1346 q+=GetPixelChannels(image);
1349 for (x=0; x < (ssize_t) image->columns; x++)
1351 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1352 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1353 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1354 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1355 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1356 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1357 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1358 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1359 SetPixelAlpha(image,OpaqueAlpha,q);
1360 q+=GetPixelChannels(image);
1364 if (jpeg_info.output_components == 1)
1365 for (x=0; x < (ssize_t) image->columns; x++)
1367 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1368 SetPixelIndex(image,index,q);
1369 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1371 q+=GetPixelChannels(image);
1374 if (image->colorspace != CMYKColorspace)
1375 for (x=0; x < (ssize_t) image->columns; x++)
1377 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1378 GETJSAMPLE(*p++)),q);
1379 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1380 GETJSAMPLE(*p++)),q);
1381 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1382 GETJSAMPLE(*p++)),q);
1383 SetPixelAlpha(image,OpaqueAlpha,q);
1384 q+=GetPixelChannels(image);
1387 for (x=0; x < (ssize_t) image->columns; x++)
1389 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1390 (unsigned char) GETJSAMPLE(*p++)),q);
1391 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1392 (unsigned char) GETJSAMPLE(*p++)),q);
1393 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1394 (unsigned char) GETJSAMPLE(*p++)),q);
1395 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1396 (unsigned char) GETJSAMPLE(*p++)),q);
1397 SetPixelAlpha(image,OpaqueAlpha,q);
1398 q+=GetPixelChannels(image);
1400 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1402 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1404 if (status == MagickFalse)
1406 jpeg_abort_decompress(&jpeg_info);
1410 if (status != MagickFalse)
1412 error_manager.finished=MagickTrue;
1413 if (setjmp(error_manager.error_recovery) == 0)
1414 (void) jpeg_finish_decompress(&jpeg_info);
1417 Free jpeg resources.
1419 jpeg_destroy_decompress(&jpeg_info);
1420 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1421 (void) CloseBlob(image);
1422 return(GetFirstImageInList(image));
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1431 % R e g i s t e r J P E G I m a g e %
1435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437 % RegisterJPEGImage() adds properties for the JPEG image format to
1438 % the list of supported formats. The properties include the image format
1439 % tag, a method to read and/or write the format, whether the format
1440 % supports the saving of more than one frame to the same file or blob,
1441 % whether the format supports native in-memory I/O, and a brief
1442 % description of the format.
1444 % The format of the RegisterJPEGImage method is:
1446 % size_t RegisterJPEGImage(void)
1449 ModuleExport size_t RegisterJPEGImage(void)
1452 version[MaxTextExtent];
1458 description[] = "Joint Photographic Experts Group JFIF format";
1461 #if defined(JPEG_LIB_VERSION)
1462 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1464 entry=SetMagickInfo("JPEG");
1465 entry->thread_support=NoThreadSupport;
1466 #if defined(MAGICKCORE_JPEG_DELEGATE)
1467 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1468 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1470 entry->magick=(IsImageFormatHandler *) IsJPEG;
1471 entry->adjoin=MagickFalse;
1472 entry->description=ConstantString(description);
1473 if (*version != '\0')
1474 entry->version=ConstantString(version);
1475 entry->module=ConstantString("JPEG");
1476 (void) RegisterMagickInfo(entry);
1477 entry=SetMagickInfo("JPG");
1478 entry->thread_support=NoThreadSupport;
1479 #if defined(MAGICKCORE_JPEG_DELEGATE)
1480 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1481 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1483 entry->adjoin=MagickFalse;
1484 entry->description=ConstantString(description);
1485 if (*version != '\0')
1486 entry->version=ConstantString(version);
1487 entry->module=ConstantString("JPEG");
1488 (void) RegisterMagickInfo(entry);
1489 entry=SetMagickInfo("PJPEG");
1490 entry->thread_support=NoThreadSupport;
1491 #if defined(MAGICKCORE_JPEG_DELEGATE)
1492 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1493 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1495 entry->adjoin=MagickFalse;
1496 entry->description=ConstantString(description);
1497 if (*version != '\0')
1498 entry->version=ConstantString(version);
1499 entry->module=ConstantString("JPEG");
1500 (void) RegisterMagickInfo(entry);
1501 return(MagickImageCoderSignature);
1505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1509 % U n r e g i s t e r J P E G I m a g e %
1513 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1515 % UnregisterJPEGImage() removes format registrations made by the
1516 % JPEG module from the list of supported formats.
1518 % The format of the UnregisterJPEGImage method is:
1520 % UnregisterJPEGImage(void)
1523 ModuleExport void UnregisterJPEGImage(void)
1525 (void) UnregisterMagickInfo("PJPG");
1526 (void) UnregisterMagickInfo("JPEG");
1527 (void) UnregisterMagickInfo("JPG");
1530 #if defined(MAGICKCORE_JPEG_DELEGATE)
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 % W r i t e J P E G I m a g e %
1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542 % WriteJPEGImage() writes a JPEG image file and returns it. It
1543 % allocates the memory necessary for the new Image structure and returns a
1544 % pointer to the new image.
1546 % The format of the WriteJPEGImage method is:
1548 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1549 % Image *image,ExceptionInfo *exception)
1551 % A description of each parameter follows:
1553 % o image_info: the image info.
1555 % o jpeg_image: The image.
1557 % o exception: return any errors or warnings in this structure.
1561 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1563 assert(table != (QuantizationTable *) NULL);
1564 if (table->slot != (char *) NULL)
1565 table->slot=DestroyString(table->slot);
1566 if (table->description != (char *) NULL)
1567 table->description=DestroyString(table->description);
1568 if (table->levels != (unsigned int *) NULL)
1569 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1570 table=(QuantizationTable *) RelinquishMagickMemory(table);
1574 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1579 destination=(DestinationManager *) cinfo->dest;
1580 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1581 MaxBufferExtent,destination->buffer);
1582 if (destination->manager.free_in_buffer != MaxBufferExtent)
1583 ERREXIT(cinfo,JERR_FILE_WRITE);
1584 destination->manager.next_output_byte=destination->buffer;
1588 static QuantizationTable *GetQuantizationTable(const char *filename,
1589 const char *slot,ExceptionInfo *exception)
1617 *quantization_tables,
1620 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1621 "Loading quantization tables \"%s\" ...",filename);
1622 table=(QuantizationTable *) NULL;
1623 xml=FileToString(filename,~0,exception);
1624 if (xml == (char *) NULL)
1626 quantization_tables=NewXMLTree(xml,exception);
1627 if (quantization_tables == (XMLTreeInfo *) NULL)
1629 xml=DestroyString(xml);
1632 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1633 table_iterator != (XMLTreeInfo *) NULL;
1634 table_iterator=GetNextXMLTreeTag(table_iterator))
1636 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1637 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1639 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1640 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1643 if (table_iterator == (XMLTreeInfo *) NULL)
1645 xml=DestroyString(xml);
1648 description=GetXMLTreeChild(table_iterator,"description");
1649 if (description == (XMLTreeInfo *) NULL)
1651 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1652 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1653 quantization_tables=DestroyXMLTree(quantization_tables);
1654 xml=DestroyString(xml);
1657 levels=GetXMLTreeChild(table_iterator,"levels");
1658 if (levels == (XMLTreeInfo *) NULL)
1660 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1661 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1662 quantization_tables=DestroyXMLTree(quantization_tables);
1663 xml=DestroyString(xml);
1666 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1667 if (table == (QuantizationTable *) NULL)
1668 ThrowFatalException(ResourceLimitFatalError,
1669 "UnableToAcquireQuantizationTable");
1670 table->slot=(char *) NULL;
1671 table->description=(char *) NULL;
1672 table->levels=(unsigned int *) NULL;
1673 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1674 if (attribute != (char *) NULL)
1675 table->slot=ConstantString(attribute);
1676 content=GetXMLTreeContent(description);
1677 if (content != (char *) NULL)
1678 table->description=ConstantString(content);
1679 attribute=GetXMLTreeAttribute(levels,"width");
1680 if (attribute == (char *) NULL)
1682 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1683 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1684 quantization_tables=DestroyXMLTree(quantization_tables);
1685 table=DestroyQuantizationTable(table);
1686 xml=DestroyString(xml);
1689 table->width=StringToUnsignedLong(attribute);
1690 if (table->width == 0)
1692 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1693 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1694 quantization_tables=DestroyXMLTree(quantization_tables);
1695 table=DestroyQuantizationTable(table);
1696 xml=DestroyString(xml);
1699 attribute=GetXMLTreeAttribute(levels,"height");
1700 if (attribute == (char *) NULL)
1702 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1703 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1704 quantization_tables=DestroyXMLTree(quantization_tables);
1705 table=DestroyQuantizationTable(table);
1706 xml=DestroyString(xml);
1709 table->height=StringToUnsignedLong(attribute);
1710 if (table->height == 0)
1712 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1713 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1714 quantization_tables=DestroyXMLTree(quantization_tables);
1715 table=DestroyQuantizationTable(table);
1716 xml=DestroyString(xml);
1719 attribute=GetXMLTreeAttribute(levels,"divisor");
1720 if (attribute == (char *) NULL)
1722 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1723 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1724 quantization_tables=DestroyXMLTree(quantization_tables);
1725 table=DestroyQuantizationTable(table);
1726 xml=DestroyString(xml);
1729 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1730 if (table->divisor == 0.0)
1732 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1733 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1734 quantization_tables=DestroyXMLTree(quantization_tables);
1735 table=DestroyQuantizationTable(table);
1736 xml=DestroyString(xml);
1739 content=GetXMLTreeContent(levels);
1740 if (content == (char *) NULL)
1742 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1743 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1744 quantization_tables=DestroyXMLTree(quantization_tables);
1745 table=DestroyQuantizationTable(table);
1746 xml=DestroyString(xml);
1749 length=(size_t) table->width*table->height;
1752 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1753 sizeof(*table->levels));
1754 if (table->levels == (unsigned int *) NULL)
1755 ThrowFatalException(ResourceLimitFatalError,
1756 "UnableToAcquireQuantizationTable");
1757 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1759 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1760 table->divisor+0.5);
1761 while (isspace((int) ((unsigned char) *p)) != 0)
1767 value=InterpretLocaleValue(content,&p);
1771 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1772 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1773 quantization_tables=DestroyXMLTree(quantization_tables);
1774 table=DestroyQuantizationTable(table);
1775 xml=DestroyString(xml);
1778 for (j=i; j < 64; j++)
1779 table->levels[j]=table->levels[j-1];
1780 quantization_tables=DestroyXMLTree(quantization_tables);
1781 xml=DestroyString(xml);
1785 static void InitializeDestination(j_compress_ptr cinfo)
1790 destination=(DestinationManager *) cinfo->dest;
1791 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1792 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1793 destination->manager.next_output_byte=destination->buffer;
1794 destination->manager.free_in_buffer=MaxBufferExtent;
1797 static inline size_t MagickMin(const size_t x,const size_t y)
1804 static void TerminateDestination(j_compress_ptr cinfo)
1809 destination=(DestinationManager *) cinfo->dest;
1810 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1815 count=WriteBlob(destination->image,MaxBufferExtent-
1816 destination->manager.free_in_buffer,destination->buffer);
1817 if (count != (ssize_t)
1818 (MaxBufferExtent-destination->manager.free_in_buffer))
1819 ERREXIT(cinfo,JERR_FILE_WRITE);
1823 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1845 Save image profile as a APP marker.
1848 custom_profile=AcquireStringInfo(65535L);
1849 ResetImageProfileIterator(image);
1850 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1852 register unsigned char
1855 profile=GetImageProfile(image,name);
1856 p=GetStringInfoDatum(custom_profile);
1857 if (LocaleCompare(name,"EXIF") == 0)
1858 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1860 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1861 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1862 (unsigned int) length);
1864 if (LocaleCompare(name,"ICC") == 0)
1866 register unsigned char
1870 p=GetStringInfoDatum(custom_profile);
1871 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1872 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1874 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1875 p[12]=(unsigned char) ((i/65519L)+1);
1876 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1877 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1879 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1880 custom_profile),(unsigned int) (length+tag_length));
1883 if (((LocaleCompare(name,"IPTC") == 0) ||
1884 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1890 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1892 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1893 roundup=(size_t) (length & 0x01);
1894 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1896 (void) memcpy(p,"Photoshop 3.0 ",14);
1901 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1903 p[24]=(unsigned char) (length >> 8);
1904 p[25]=(unsigned char) (length & 0xff);
1907 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1909 p[length+tag_length]='\0';
1910 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1911 custom_profile),(unsigned int) (length+tag_length+roundup));
1914 if (LocaleCompare(name,"XMP") == 0)
1920 Add namespace to XMP profile.
1922 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1923 ConcatenateStringInfo(xmp_profile,profile);
1924 GetStringInfoDatum(xmp_profile)[28]='\0';
1925 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1927 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1928 jpeg_write_marker(jpeg_info,XML_MARKER,
1929 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1931 xmp_profile=DestroyStringInfo(xmp_profile);
1933 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1934 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1935 name=GetNextImageProfile(image);
1937 custom_profile=DestroyStringInfo(custom_profile);
1940 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1945 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1946 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1947 destination=(DestinationManager *) cinfo->dest;
1948 destination->manager.init_destination=InitializeDestination;
1949 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1950 destination->manager.term_destination=TerminateDestination;
1951 destination->image=image;
1954 static char **SamplingFactorToList(const char *text)
1971 if (text == (char *) NULL)
1972 return((char **) NULL);
1974 Convert string to an ASCII list.
1977 for (p=text; *p != '\0'; p++)
1980 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1982 if (textlist == (char **) NULL)
1983 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1985 for (i=0; i < (ssize_t) lines; i++)
1987 for (q=(char *) p; *q != '\0'; q++)
1990 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1991 sizeof(*textlist[i]));
1992 if (textlist[i] == (char *) NULL)
1993 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1994 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1999 textlist[i]=(char *) NULL;
2003 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2004 Image *image,ExceptionInfo *exception)
2035 struct jpeg_compress_struct
2038 struct jpeg_error_mgr
2044 assert(image_info != (const ImageInfo *) NULL);
2045 assert(image_info->signature == MagickSignature);
2046 assert(image != (Image *) NULL);
2047 assert(image->signature == MagickSignature);
2048 if (image->debug != MagickFalse)
2049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2050 assert(exception != (ExceptionInfo *) NULL);
2051 assert(exception->signature == MagickSignature);
2052 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2053 if (status == MagickFalse)
2056 Initialize JPEG parameters.
2058 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2059 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2060 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2061 jpeg_info.client_data=(void *) image;
2062 jpeg_info.err=jpeg_std_error(&jpeg_error);
2063 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2064 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2065 error_manager.exception=exception;
2066 error_manager.image=image;
2067 jpeg_pixels=(JSAMPLE *) NULL;
2068 if (setjmp(error_manager.error_recovery) != 0)
2070 jpeg_destroy_compress(&jpeg_info);
2071 (void) CloseBlob(image);
2072 return(MagickFalse);
2074 jpeg_info.client_data=(void *) &error_manager;
2075 jpeg_create_compress(&jpeg_info);
2076 JPEGDestinationManager(&jpeg_info,image);
2077 if ((image->columns != (unsigned int) image->columns) ||
2078 (image->rows != (unsigned int) image->rows))
2079 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2080 jpeg_info.image_width=(unsigned int) image->columns;
2081 jpeg_info.image_height=(unsigned int) image->rows;
2082 jpeg_info.input_components=3;
2083 jpeg_info.data_precision=8;
2084 jpeg_info.in_color_space=JCS_RGB;
2085 switch (image->colorspace)
2087 case CMYKColorspace:
2089 jpeg_info.input_components=4;
2090 jpeg_info.in_color_space=JCS_CMYK;
2093 case YCbCrColorspace:
2094 case Rec601YCbCrColorspace:
2095 case Rec709YCbCrColorspace:
2097 jpeg_info.in_color_space=JCS_YCbCr;
2100 case GRAYColorspace:
2101 case Rec601LumaColorspace:
2102 case Rec709LumaColorspace:
2104 jpeg_info.input_components=1;
2105 jpeg_info.in_color_space=JCS_GRAYSCALE;
2110 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2111 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2115 if ((image_info->type != TrueColorType) &&
2116 (IsImageGray(image,exception) != MagickFalse))
2118 jpeg_info.input_components=1;
2119 jpeg_info.in_color_space=JCS_GRAYSCALE;
2121 jpeg_set_defaults(&jpeg_info);
2122 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2123 jpeg_info.data_precision=8;
2125 if (sizeof(JSAMPLE) > 1)
2126 jpeg_info.data_precision=12;
2127 jpeg_info.density_unit=(UINT8) 1;
2128 if (image->debug != MagickFalse)
2129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2130 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2131 floor(image->resolution.y+0.5));
2132 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2135 Set image resolution.
2137 jpeg_info.write_JFIF_header=MagickTrue;
2138 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2139 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2140 if (image->units == PixelsPerInchResolution)
2141 jpeg_info.density_unit=(UINT8) 1;
2142 if (image->units == PixelsPerCentimeterResolution)
2143 jpeg_info.density_unit=(UINT8) 2;
2145 jpeg_info.dct_method=JDCT_FLOAT;
2146 option=GetImageOption(image_info,"jpeg:dct-method");
2147 if (option != (const char *) NULL)
2153 if (LocaleCompare(option,"default") == 0)
2154 jpeg_info.dct_method=JDCT_DEFAULT;
2160 if (LocaleCompare(option,"fastest") == 0)
2161 jpeg_info.dct_method=JDCT_FASTEST;
2162 if (LocaleCompare(option,"float") == 0)
2163 jpeg_info.dct_method=JDCT_FLOAT;
2169 if (LocaleCompare(option,"ifast") == 0)
2170 jpeg_info.dct_method=JDCT_IFAST;
2171 if (LocaleCompare(option,"islow") == 0)
2172 jpeg_info.dct_method=JDCT_ISLOW;
2176 option=GetImageOption(image_info,"jpeg:optimize-coding");
2177 if (option != (const char *) NULL)
2178 jpeg_info.optimize_coding=IsStringTrue(option);
2184 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2185 image->rows*sizeof(JSAMPLE);
2186 if (length == (MagickSizeType) ((size_t) length))
2189 Perform optimization only if available memory resources permit it.
2191 status=AcquireMagickResource(MemoryResource,length);
2192 RelinquishMagickResource(MemoryResource,length);
2193 jpeg_info.optimize_coding=status;
2196 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2197 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2198 (image_info->interlace != NoInterlace))
2200 if (image->debug != MagickFalse)
2201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2202 "Interlace: progressive");
2203 jpeg_simple_progression(&jpeg_info);
2206 if (image->debug != MagickFalse)
2207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2208 "Interlace: non-progressive");
2210 if (image->debug != MagickFalse)
2211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2212 "Interlace: nonprogressive");
2214 option=GetImageOption(image_info,"jpeg:extent");
2215 if (option != (const char *) NULL)
2223 jpeg_info=CloneImageInfo(image_info);
2224 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2225 if (jpeg_image != (Image *) NULL)
2235 Search for compression quality that does not exceed image extent.
2237 jpeg_info->quality=0;
2238 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2239 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2240 (void) AcquireUniqueFilename(jpeg_image->filename);
2242 for (minimum=0; minimum != maximum; )
2244 jpeg_image->quality=minimum+(maximum-minimum)/2;
2245 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2246 if (GetBlobSize(jpeg_image) <= extent)
2247 minimum=jpeg_image->quality+1;
2249 maximum=jpeg_image->quality-1;
2251 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2252 image->quality=minimum-1;
2253 jpeg_image=DestroyImage(jpeg_image);
2255 jpeg_info=DestroyImageInfo(jpeg_info);
2258 if ((image_info->compression != LosslessJPEGCompression) &&
2259 (image->quality <= 100))
2261 if (image->quality != UndefinedCompressionQuality)
2262 quality=(int) image->quality;
2263 if (image->debug != MagickFalse)
2264 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2265 (double) image->quality);
2269 #if !defined(C_LOSSLESS_SUPPORTED)
2271 if (image->debug != MagickFalse)
2272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2274 if (image->quality < 100)
2275 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2276 "LosslessToLossyJPEGConversion",image->filename);
2283 predictor=image->quality/100; /* range 1-7 */
2284 point_transform=image->quality % 20; /* range 0-15 */
2285 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2286 if (image->debug != MagickFalse)
2288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2289 "Compression: lossless");
2290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2291 "Predictor: %d",predictor);
2292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2293 "Point Transform: %d",point_transform);
2298 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2299 #if (JPEG_LIB_VERSION >= 70)
2300 option=GetImageOption(image_info,"quality");
2301 if (option != (const char *) NULL)
2310 Set quality scaling for luminance and chrominance separately.
2312 flags=ParseGeometry(option,&geometry_info);
2313 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2315 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2316 (geometry_info.rho+0.5));
2317 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2318 (geometry_info.sigma+0.5));
2319 jpeg_default_qtables(&jpeg_info,MagickTrue);
2323 sampling_factor=(const char *) NULL;
2324 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2325 if (value != (char *) NULL)
2327 sampling_factor=value;
2328 if (image->debug != MagickFalse)
2329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2330 " Input sampling-factors=%s",sampling_factor);
2332 if (image_info->sampling_factor != (char *) NULL)
2333 sampling_factor=image_info->sampling_factor;
2334 if (sampling_factor == (const char *) NULL)
2336 if (image->quality >= 90)
2337 for (i=0; i < MAX_COMPONENTS; i++)
2339 jpeg_info.comp_info[i].h_samp_factor=1;
2340 jpeg_info.comp_info[i].v_samp_factor=1;
2355 Set sampling factor.
2358 factors=SamplingFactorToList(sampling_factor);
2359 if (factors != (char **) NULL)
2361 for (i=0; i < MAX_COMPONENTS; i++)
2363 if (factors[i] == (char *) NULL)
2365 flags=ParseGeometry(factors[i],&geometry_info);
2366 if ((flags & SigmaValue) == 0)
2367 geometry_info.sigma=geometry_info.rho;
2368 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2369 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2370 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2372 factors=(char **) RelinquishMagickMemory(factors);
2374 for ( ; i < MAX_COMPONENTS; i++)
2376 jpeg_info.comp_info[i].h_samp_factor=1;
2377 jpeg_info.comp_info[i].v_samp_factor=1;
2380 if (jpeg_info.input_components == 1)
2381 for (i=0; i < MAX_COMPONENTS; i++)
2383 jpeg_info.comp_info[i].h_samp_factor=1;
2384 jpeg_info.comp_info[i].v_samp_factor=1;
2386 option=GetImageOption(image_info,"jpeg:q-table");
2387 if (option != (const char *) NULL)
2393 Custom quantization tables.
2395 table=GetQuantizationTable(option,"0",exception);
2396 if (table != (QuantizationTable *) NULL)
2398 jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2400 table=DestroyQuantizationTable(table);
2402 table=GetQuantizationTable(option,"1",exception);
2403 if (table != (QuantizationTable *) NULL)
2405 jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2407 table=DestroyQuantizationTable(table);
2409 table=GetQuantizationTable(option,"2",exception);
2410 if (table != (QuantizationTable *) NULL)
2412 jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2414 table=DestroyQuantizationTable(table);
2416 table=GetQuantizationTable(option,"3",exception);
2417 if (table != (QuantizationTable *) NULL)
2419 jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2421 table=DestroyQuantizationTable(table);
2424 jpeg_start_compress(&jpeg_info,MagickTrue);
2425 if (image->debug != MagickFalse)
2427 if (image->storage_class == PseudoClass)
2428 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2429 "Storage class: PseudoClass");
2431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2432 "Storage class: DirectClass");
2433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2434 (double) image->depth);
2435 if (image->colors != 0)
2436 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2437 "Number of colors: %.20g",(double) image->colors);
2439 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2440 "Number of colors: unspecified");
2441 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2442 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2443 switch (image->colorspace)
2445 case CMYKColorspace:
2447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2448 "Storage class: DirectClass");
2449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2450 "Colorspace: CMYK");
2453 case YCbCrColorspace:
2454 case Rec601YCbCrColorspace:
2455 case Rec709YCbCrColorspace:
2457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2458 "Colorspace: YCbCr");
2464 switch (image->colorspace)
2466 case CMYKColorspace:
2468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2469 "Colorspace: CMYK");
2470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2471 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2472 jpeg_info.comp_info[0].h_samp_factor,
2473 jpeg_info.comp_info[0].v_samp_factor,
2474 jpeg_info.comp_info[1].h_samp_factor,
2475 jpeg_info.comp_info[1].v_samp_factor,
2476 jpeg_info.comp_info[2].h_samp_factor,
2477 jpeg_info.comp_info[2].v_samp_factor,
2478 jpeg_info.comp_info[3].h_samp_factor,
2479 jpeg_info.comp_info[3].v_samp_factor);
2482 case GRAYColorspace:
2483 case Rec601LumaColorspace:
2484 case Rec709LumaColorspace:
2486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2487 "Colorspace: GRAY");
2488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2489 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2490 jpeg_info.comp_info[0].v_samp_factor);
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 "Image colorspace is RGB");
2497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2498 "Sampling factors: %dx%d,%dx%d,%dx%d",
2499 jpeg_info.comp_info[0].h_samp_factor,
2500 jpeg_info.comp_info[0].v_samp_factor,
2501 jpeg_info.comp_info[1].h_samp_factor,
2502 jpeg_info.comp_info[1].v_samp_factor,
2503 jpeg_info.comp_info[2].h_samp_factor,
2504 jpeg_info.comp_info[2].v_samp_factor);
2507 case YCbCrColorspace:
2508 case Rec601YCbCrColorspace:
2509 case Rec709YCbCrColorspace:
2511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2512 "Colorspace: YCbCr");
2513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2514 "Sampling factors: %dx%d,%dx%d,%dx%d",
2515 jpeg_info.comp_info[0].h_samp_factor,
2516 jpeg_info.comp_info[0].v_samp_factor,
2517 jpeg_info.comp_info[1].h_samp_factor,
2518 jpeg_info.comp_info[1].v_samp_factor,
2519 jpeg_info.comp_info[2].h_samp_factor,
2520 jpeg_info.comp_info[2].v_samp_factor);
2525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2528 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2529 jpeg_info.comp_info[0].h_samp_factor,
2530 jpeg_info.comp_info[0].v_samp_factor,
2531 jpeg_info.comp_info[1].h_samp_factor,
2532 jpeg_info.comp_info[1].v_samp_factor,
2533 jpeg_info.comp_info[2].h_samp_factor,
2534 jpeg_info.comp_info[2].v_samp_factor,
2535 jpeg_info.comp_info[3].h_samp_factor,
2536 jpeg_info.comp_info[3].v_samp_factor);
2542 Write JPEG profiles.
2544 value=GetImageProperty(image,"comment",exception);
2545 if (value != (char *) NULL)
2546 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2547 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2548 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2549 if (image->profiles != (void *) NULL)
2550 WriteProfile(&jpeg_info,image);
2552 Convert MIFF to JPEG raster pixels.
2554 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2555 jpeg_info.input_components*sizeof(*jpeg_pixels));
2556 if (jpeg_pixels == (JSAMPLE *) NULL)
2557 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2558 if (setjmp(error_manager.error_recovery) != 0)
2560 jpeg_destroy_compress(&jpeg_info);
2561 if (jpeg_pixels != (unsigned char *) NULL)
2562 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2563 (void) CloseBlob(image);
2564 return(MagickFalse);
2566 scanline[0]=(JSAMPROW) jpeg_pixels;
2567 if (jpeg_info.data_precision <= 8)
2569 if ((jpeg_info.in_color_space == JCS_RGB) ||
2570 (jpeg_info.in_color_space == JCS_YCbCr))
2571 for (y=0; y < (ssize_t) image->rows; y++)
2573 register const Quantum
2579 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2580 if (p == (const Quantum *) NULL)
2583 for (x=0; x < (ssize_t) image->columns; x++)
2585 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2586 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2587 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2588 p+=GetPixelChannels(image);
2590 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2591 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2593 if (status == MagickFalse)
2597 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2598 for (y=0; y < (ssize_t) image->rows; y++)
2600 register const Quantum
2606 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2607 if (p == (const Quantum *) NULL)
2610 for (x=0; x < (ssize_t) image->columns; x++)
2612 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2613 p+=GetPixelChannels(image);
2615 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2616 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2618 if (status == MagickFalse)
2622 for (y=0; y < (ssize_t) image->rows; y++)
2624 register const Quantum
2630 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2631 if (p == (const Quantum *) NULL)
2634 for (x=0; x < (ssize_t) image->columns; x++)
2637 Convert DirectClass packets to contiguous CMYK scanlines.
2639 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2640 GetPixelRed(image,p))));
2641 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2642 GetPixelGreen(image,p))));
2643 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2644 GetPixelBlue(image,p))));
2645 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2646 GetPixelBlack(image,p))));
2647 p+=GetPixelChannels(image);
2649 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2650 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2652 if (status == MagickFalse)
2657 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2658 for (y=0; y < (ssize_t) image->rows; y++)
2660 register const Quantum
2666 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2667 if (p == (const Quantum *) NULL)
2670 for (x=0; x < (ssize_t) image->columns; x++)
2672 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >> 4);
2673 p+=GetPixelChannels(image);
2675 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2676 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2678 if (status == MagickFalse)
2682 if ((jpeg_info.in_color_space == JCS_RGB) ||
2683 (jpeg_info.in_color_space == JCS_YCbCr))
2684 for (y=0; y < (ssize_t) image->rows; y++)
2686 register const Quantum
2692 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2693 if (p == (const Quantum *) NULL)
2696 for (x=0; x < (ssize_t) image->columns; x++)
2698 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2699 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2700 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2701 p+=GetPixelChannels(image);
2703 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2704 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2706 if (status == MagickFalse)
2710 for (y=0; y < (ssize_t) image->rows; y++)
2712 register const Quantum
2718 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2719 if (p == (const Quantum *) NULL)
2722 for (x=0; x < (ssize_t) image->columns; x++)
2725 Convert DirectClass packets to contiguous CMYK scanlines.
2727 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2728 GetPixelRed(image,p)) >> 4));
2729 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2730 GetPixelGreen(image,p)) >> 4));
2731 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2732 GetPixelBlue(image,p)) >> 4));
2733 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2734 GetPixelBlack(image,p)) >> 4));
2735 p+=GetPixelChannels(image);
2737 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2738 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2740 if (status == MagickFalse)
2743 if (y == (ssize_t) image->rows)
2744 jpeg_finish_compress(&jpeg_info);
2746 Relinquish resources.
2748 jpeg_destroy_compress(&jpeg_info);
2749 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2750 (void) CloseBlob(image);