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/utility.h"
81 #include "MagickCore/xml-tree.h"
82 #include "MagickCore/xml-tree-private.h"
84 #if defined(MAGICKCORE_JPEG_DELEGATE)
85 #define JPEG_INTERNAL_OPTIONS
86 #if defined(__MINGW32__)
87 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
88 typedef unsigned char boolean;
99 #define ICC_MARKER (JPEG_APP0+2)
100 #define ICC_PROFILE "ICC_PROFILE"
101 #define IPTC_MARKER (JPEG_APP0+13)
102 #define XML_MARKER (JPEG_APP0+1)
103 #define MaxBufferExtent 8192
106 Typedef declarations.
108 #if defined(MAGICKCORE_JPEG_DELEGATE)
109 typedef struct _DestinationManager
111 struct jpeg_destination_mgr
119 } DestinationManager;
121 typedef struct _ErrorManager
136 typedef struct _SourceManager
138 struct jpeg_source_mgr
152 typedef struct _QuantizationTable
170 Forward declarations.
172 #if defined(MAGICKCORE_JPEG_DELEGATE)
173 static MagickBooleanType
174 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 % IsJPEG() returns MagickTrue if the image format type, identified by the
189 % magick string, is JPEG.
191 % The format of the IsJPEG method is:
193 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
195 % A description of each parameter follows:
197 % o magick: compare image format pattern against these bytes.
199 % o length: Specifies the length of the magick string.
202 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
206 if (memcmp(magick,"\377\330\377",3) == 0)
211 #if defined(MAGICKCORE_JPEG_DELEGATE)
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % R e a d J P E G I m a g e %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
224 % the memory necessary for the new Image structure and returns a pointer to
227 % The format of the ReadJPEGImage method is:
229 % Image *ReadJPEGImage(const ImageInfo *image_info,
230 % ExceptionInfo *exception)
232 % A description of each parameter follows:
234 % o image_info: the image info.
236 % o exception: return any errors or warnings in this structure.
240 static boolean FillInputBuffer(j_decompress_ptr cinfo)
245 source=(SourceManager *) cinfo->src;
246 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
247 MaxBufferExtent,source->buffer);
248 if (source->manager.bytes_in_buffer == 0)
250 if (source->start_of_blob != 0)
251 ERREXIT(cinfo,JERR_INPUT_EMPTY);
252 WARNMS(cinfo,JWRN_JPEG_EOF);
253 source->buffer[0]=(JOCTET) 0xff;
254 source->buffer[1]=(JOCTET) JPEG_EOI;
255 source->manager.bytes_in_buffer=2;
257 source->manager.next_input_byte=source->buffer;
258 source->start_of_blob=FALSE;
262 static int GetCharacter(j_decompress_ptr jpeg_info)
264 if (jpeg_info->src->bytes_in_buffer == 0)
265 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
266 jpeg_info->src->bytes_in_buffer--;
267 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
270 static void InitializeSource(j_decompress_ptr cinfo)
275 source=(SourceManager *) cinfo->src;
276 source->start_of_blob=TRUE;
279 static MagickBooleanType IsITUFaxImage(const Image *image)
287 profile=GetImageProfile(image,"8bim");
288 if (profile == (const StringInfo *) NULL)
290 if (GetStringInfoLength(profile) < 5)
292 datum=GetStringInfoDatum(profile);
293 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
294 (datum[3] == 0x41) && (datum[4] == 0x58))
299 static void JPEGErrorHandler(j_common_ptr jpeg_info)
302 message[JMSG_LENGTH_MAX];
314 error_manager=(ErrorManager *) jpeg_info->client_data;
315 image=error_manager->image;
316 exception=error_manager->exception;
317 (jpeg_info->err->format_message)(jpeg_info,message);
318 if (image->debug != MagickFalse)
319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
320 "[%s] JPEG Trace: \"%s\"",image->filename,message);
321 if (error_manager->finished != MagickFalse)
322 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
323 (char *) message,"`%s'",image->filename);
325 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
326 (char *) message,"`%s'",image->filename);
327 longjmp(error_manager->error_recovery,1);
330 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
333 message[JMSG_LENGTH_MAX];
345 error_manager=(ErrorManager *) jpeg_info->client_data;
346 exception=error_manager->exception;
347 image=error_manager->image;
351 Process warning message.
353 (jpeg_info->err->format_message)(jpeg_info,message);
354 if ((jpeg_info->err->num_warnings == 0) ||
355 (jpeg_info->err->trace_level >= 3))
356 ThrowBinaryException(CorruptImageWarning,(char *) message,
358 jpeg_info->err->num_warnings++;
361 if ((image->debug != MagickFalse) &&
362 (level >= jpeg_info->err->trace_level))
365 Process trace message.
367 (jpeg_info->err->format_message)(jpeg_info,message);
368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
369 "[%s] JPEG Trace: \"%s\"",image->filename,message);
374 static boolean ReadComment(j_decompress_ptr jpeg_info)
398 Determine length of comment.
400 error_manager=(ErrorManager *) jpeg_info->client_data;
401 exception=error_manager->exception;
402 image=error_manager->image;
403 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
404 length+=GetCharacter(jpeg_info);
408 comment=(char *) NULL;
409 if (~length >= (MaxTextExtent-1))
410 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
412 if (comment == (char *) NULL)
413 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
418 i=(ssize_t) length-1;
419 for (p=comment; i-- >= 0; p++)
420 *p=(char) GetCharacter(jpeg_info);
422 (void) SetImageProperty(image,"comment",comment,exception);
423 comment=DestroyString(comment);
427 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
447 register unsigned char
460 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
461 length+=(size_t) GetCharacter(jpeg_info);
466 (void) GetCharacter(jpeg_info);
469 for (i=0; i < 12; i++)
470 magick[i]=(char) GetCharacter(jpeg_info);
471 if (LocaleCompare(magick,ICC_PROFILE) != 0)
474 Not a ICC profile, return.
476 for (i=0; i < (ssize_t) (length-12); i++)
477 (void) GetCharacter(jpeg_info);
480 (void) GetCharacter(jpeg_info); /* id */
481 (void) GetCharacter(jpeg_info); /* markers */
483 error_manager=(ErrorManager *) jpeg_info->client_data;
484 exception=error_manager->exception;
485 image=error_manager->image;
486 profile=BlobToStringInfo((const void *) NULL,length);
487 if (profile == (StringInfo *) NULL)
488 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
490 p=GetStringInfoDatum(profile);
491 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
492 *p++=(unsigned char) GetCharacter(jpeg_info);
493 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
494 if (icc_profile != (StringInfo *) NULL)
496 ConcatenateStringInfo(icc_profile,profile);
497 profile=DestroyStringInfo(profile);
501 status=SetImageProfile(image,"icc",profile,exception);
502 profile=DestroyStringInfo(profile);
503 if (status == MagickFalse)
504 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
507 if (image->debug != MagickFalse)
508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
509 "Profile: ICC, %.20g bytes",(double) length);
513 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
516 magick[MaxTextExtent];
533 register unsigned char
544 Determine length of binary data stored here.
546 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
547 length+=(size_t) GetCharacter(jpeg_info);
552 (void) GetCharacter(jpeg_info);
556 Validate that this was written as a Photoshop resource format slug.
558 for (i=0; i < 10; i++)
559 magick[i]=(char) GetCharacter(jpeg_info);
564 if (LocaleCompare(magick,"Photoshop ") != 0)
567 Not a IPTC profile, return.
569 for (i=0; i < (ssize_t) length; i++)
570 (void) GetCharacter(jpeg_info);
574 Remove the version number.
576 for (i=0; i < 4; i++)
577 (void) GetCharacter(jpeg_info);
583 error_manager=(ErrorManager *) jpeg_info->client_data;
584 exception=error_manager->exception;
585 image=error_manager->image;
586 profile=BlobToStringInfo((const void *) NULL,length);
587 if (profile == (StringInfo *) NULL)
588 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
590 p=GetStringInfoDatum(profile);
591 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
592 *p++=(unsigned char) GetCharacter(jpeg_info);
593 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
594 if (iptc_profile != (StringInfo *) NULL)
596 ConcatenateStringInfo(iptc_profile,profile);
597 profile=DestroyStringInfo(profile);
601 status=SetImageProfile(image,"8bim",profile,exception);
602 profile=DestroyStringInfo(profile);
603 if (status == MagickFalse)
604 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
607 if (image->debug != MagickFalse)
608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
609 "Profile: iptc, %.20g bytes",(double) length);
613 static boolean ReadProfile(j_decompress_ptr jpeg_info)
639 register unsigned char
649 Read generic profile.
651 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
652 length+=(size_t) GetCharacter(jpeg_info);
656 marker=jpeg_info->unread_marker-JPEG_APP0;
657 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
658 error_manager=(ErrorManager *) jpeg_info->client_data;
659 exception=error_manager->exception;
660 image=error_manager->image;
661 profile=BlobToStringInfo((const void *) NULL,length);
662 if (profile == (StringInfo *) NULL)
663 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
665 p=GetStringInfoDatum(profile);
666 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
667 *p++=(unsigned char) GetCharacter(jpeg_info);
670 p=GetStringInfoDatum(profile);
671 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
672 (void) CopyMagickString(name,"exif",MaxTextExtent);
673 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
679 Extract namespace from XMP profile.
681 p=GetStringInfoDatum(profile);
682 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
688 if (j < (ssize_t) GetStringInfoLength(profile))
689 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
690 (void) CopyMagickString(name,"xmp",MaxTextExtent);
693 previous_profile=GetImageProfile(image,name);
694 if (previous_profile != (const StringInfo *) NULL)
699 length=GetStringInfoLength(profile);
700 SetStringInfoLength(profile,GetStringInfoLength(profile)+
701 GetStringInfoLength(previous_profile));
702 (void) memmove(GetStringInfoDatum(profile)+
703 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
705 (void) memcpy(GetStringInfoDatum(profile),
706 GetStringInfoDatum(previous_profile),
707 GetStringInfoLength(previous_profile));
709 status=SetImageProfile(image,name,profile,exception);
710 profile=DestroyStringInfo(profile);
711 if (status == MagickFalse)
712 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
714 if (image->debug != MagickFalse)
715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
716 "Profile: %s, %.20g bytes",name,(double) length);
720 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
725 if (number_bytes <= 0)
727 source=(SourceManager *) cinfo->src;
728 while (number_bytes > (long) source->manager.bytes_in_buffer)
730 number_bytes-=(long) source->manager.bytes_in_buffer;
731 (void) FillInputBuffer(cinfo);
733 source->manager.next_input_byte+=number_bytes;
734 source->manager.bytes_in_buffer-=number_bytes;
737 static void TerminateSource(j_decompress_ptr cinfo)
742 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
747 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
748 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
749 source=(SourceManager *) cinfo->src;
750 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
751 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
752 source=(SourceManager *) cinfo->src;
753 source->manager.init_source=InitializeSource;
754 source->manager.fill_input_buffer=FillInputBuffer;
755 source->manager.skip_input_data=SkipInputData;
756 source->manager.resync_to_restart=jpeg_resync_to_restart;
757 source->manager.term_source=TerminateSource;
758 source->manager.bytes_in_buffer=0;
759 source->manager.next_input_byte=NULL;
763 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
766 image->quality=UndefinedCompressionQuality;
767 #if defined(D_PROGRESSIVE_SUPPORTED)
768 if (image->compression == LosslessJPEGCompression)
771 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
772 "Quality: 100 (lossless)");
786 Determine the JPEG compression quality from the quantization tables.
789 for (i=0; i < NUM_QUANT_TBLS; i++)
791 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
792 for (j=0; j < DCTSIZE2; j++)
793 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
795 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
796 (jpeg_info->quant_tbl_ptrs[1] != NULL))
801 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
802 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
803 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
804 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
805 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
806 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
807 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
808 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
809 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
810 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
815 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
816 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
817 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
818 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
819 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
820 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
821 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
822 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
823 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
824 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
825 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
829 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
830 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
831 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
832 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
833 for (i=0; i < 100; i++)
835 if ((qvalue < hash[i]) && (sum < sums[i]))
837 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
838 image->quality=(size_t) i+1;
839 if (image->debug != MagickFalse)
840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
841 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
842 (sum <= sums[i]) ? "exact" : "approximate");
847 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
852 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
853 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
854 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
855 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
856 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
857 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
858 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
859 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
860 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
861 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
866 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
867 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
868 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
869 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
870 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
871 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
872 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
873 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
874 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
875 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
876 667, 592, 518, 441, 369, 292, 221, 151, 86,
880 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
881 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
882 for (i=0; i < 100; i++)
884 if ((qvalue < hash[i]) && (sum < sums[i]))
886 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
887 image->quality=(size_t) i+1;
888 if (image->debug != MagickFalse)
889 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
890 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
891 (sum <= sums[i]) ? "exact" : "approximate");
898 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
901 sampling_factor[MaxTextExtent];
903 switch (jpeg_info->out_color_space)
907 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
908 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
909 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
910 jpeg_info->comp_info[0].v_samp_factor,
911 jpeg_info->comp_info[1].h_samp_factor,
912 jpeg_info->comp_info[1].v_samp_factor,
913 jpeg_info->comp_info[2].h_samp_factor,
914 jpeg_info->comp_info[2].v_samp_factor,
915 jpeg_info->comp_info[3].h_samp_factor,
916 jpeg_info->comp_info[3].v_samp_factor);
921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
922 "Colorspace: GRAYSCALE");
923 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
924 jpeg_info->comp_info[0].h_samp_factor,
925 jpeg_info->comp_info[0].v_samp_factor);
930 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
931 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
932 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
933 jpeg_info->comp_info[0].v_samp_factor,
934 jpeg_info->comp_info[1].h_samp_factor,
935 jpeg_info->comp_info[1].v_samp_factor,
936 jpeg_info->comp_info[2].h_samp_factor,
937 jpeg_info->comp_info[2].v_samp_factor);
942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
943 jpeg_info->out_color_space);
944 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
945 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
946 jpeg_info->comp_info[0].v_samp_factor,
947 jpeg_info->comp_info[1].h_samp_factor,
948 jpeg_info->comp_info[1].v_samp_factor,
949 jpeg_info->comp_info[2].h_samp_factor,
950 jpeg_info->comp_info[2].v_samp_factor,
951 jpeg_info->comp_info[3].h_samp_factor,
952 jpeg_info->comp_info[3].v_samp_factor);
956 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
962 static Image *ReadJPEGImage(const ImageInfo *image_info,
963 ExceptionInfo *exception)
966 value[MaxTextExtent];
996 struct jpeg_decompress_struct
999 struct jpeg_error_mgr
1015 assert(image_info != (const ImageInfo *) NULL);
1016 assert(image_info->signature == MagickSignature);
1017 if (image_info->debug != MagickFalse)
1018 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1019 image_info->filename);
1020 assert(exception != (ExceptionInfo *) NULL);
1021 assert(exception->signature == MagickSignature);
1022 debug=IsEventLogging();
1024 image=AcquireImage(image_info,exception);
1025 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1026 if (status == MagickFalse)
1028 image=DestroyImageList(image);
1029 return((Image *) NULL);
1032 Initialize JPEG parameters.
1034 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1035 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1036 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1037 jpeg_info.err=jpeg_std_error(&jpeg_error);
1038 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1039 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1040 jpeg_pixels=(JSAMPLE *) NULL;
1041 error_manager.exception=exception;
1042 error_manager.image=image;
1043 if (setjmp(error_manager.error_recovery) != 0)
1045 jpeg_destroy_decompress(&jpeg_info);
1046 (void) CloseBlob(image);
1047 number_pixels=(MagickSizeType) image->columns*image->rows;
1048 if (number_pixels != 0)
1049 return(GetFirstImageInList(image));
1050 return(DestroyImage(image));
1052 jpeg_info.client_data=(void *) &error_manager;
1053 jpeg_create_decompress(&jpeg_info);
1054 JPEGSourceManager(&jpeg_info,image);
1055 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1056 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1057 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1058 for (i=1; i < 16; i++)
1059 if ((i != 2) && (i != 13) && (i != 14))
1060 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1061 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1062 if ((image_info->colorspace == YCbCrColorspace) ||
1063 (image_info->colorspace == Rec601YCbCrColorspace) ||
1064 (image_info->colorspace == Rec709YCbCrColorspace))
1065 jpeg_info.out_color_space=JCS_YCbCr;
1066 if (IsITUFaxImage(image) != MagickFalse)
1068 image->colorspace=LabColorspace;
1069 jpeg_info.out_color_space=JCS_YCbCr;
1072 if (jpeg_info.out_color_space == JCS_CMYK)
1073 image->colorspace=CMYKColorspace;
1075 Set image resolution.
1078 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1079 (jpeg_info.Y_density != 1))
1081 image->resolution.x=(double) jpeg_info.X_density;
1082 image->resolution.y=(double) jpeg_info.Y_density;
1083 units=(size_t) jpeg_info.density_unit;
1086 image->units=PixelsPerInchResolution;
1088 image->units=PixelsPerCentimeterResolution;
1089 number_pixels=(MagickSizeType) image->columns*image->rows;
1090 option=GetImageOption(image_info,"jpeg:size");
1091 if (option != (const char *) NULL)
1105 flags=ParseGeometry(option,&geometry_info);
1106 if ((flags & SigmaValue) == 0)
1107 geometry_info.sigma=geometry_info.rho;
1108 jpeg_calc_output_dimensions(&jpeg_info);
1109 image->magick_columns=jpeg_info.output_width;
1110 image->magick_rows=jpeg_info.output_height;
1112 if (geometry_info.rho != 0.0)
1113 scale_factor=jpeg_info.output_width/geometry_info.rho;
1114 if ((geometry_info.sigma != 0.0) &&
1115 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1116 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1117 jpeg_info.scale_num=1U;
1118 jpeg_info.scale_denom=(unsigned int) scale_factor;
1119 jpeg_calc_output_dimensions(&jpeg_info);
1120 if (image->debug != MagickFalse)
1121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1122 "Scale factor: %.20g",(double) scale_factor);
1124 precision=(size_t) jpeg_info.data_precision;
1125 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1126 #if defined(D_LOSSLESS_SUPPORTED)
1127 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1128 JPEGInterlace : NoInterlace;
1129 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1130 LosslessJPEGCompression : JPEGCompression;
1131 if (jpeg_info.data_precision > 8)
1132 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1133 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1135 if (jpeg_info.data_precision == 16)
1136 jpeg_info.data_precision=12;
1138 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1140 image->compression=JPEGCompression;
1143 image->compression=JPEGCompression;
1144 image->interlace=JPEGInterlace;
1146 option=GetImageOption(image_info,"jpeg:colors");
1147 if (option != (const char *) NULL)
1150 Let the JPEG library quantize the image.
1152 jpeg_info.quantize_colors=MagickTrue;
1153 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1155 option=GetImageOption(image_info,"jpeg:block-smoothing");
1156 if (option != (const char *) NULL)
1158 jpeg_info.do_block_smoothing=MagickFalse;
1159 if (IsMagickTrue(option) != MagickFalse)
1160 jpeg_info.do_block_smoothing=MagickTrue;
1162 jpeg_info.dct_method=JDCT_FLOAT;
1163 option=GetImageOption(image_info,"jpeg:dct-method");
1164 if (option != (const char *) NULL)
1170 if (LocaleCompare(option,"default") == 0)
1171 jpeg_info.dct_method=JDCT_DEFAULT;
1177 if (LocaleCompare(option,"fastest") == 0)
1178 jpeg_info.dct_method=JDCT_FASTEST;
1179 if (LocaleCompare(option,"float") == 0)
1180 jpeg_info.dct_method=JDCT_FLOAT;
1186 if (LocaleCompare(option,"ifast") == 0)
1187 jpeg_info.dct_method=JDCT_IFAST;
1188 if (LocaleCompare(option,"islow") == 0)
1189 jpeg_info.dct_method=JDCT_ISLOW;
1193 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1194 if (option != (const char *) NULL)
1196 jpeg_info.do_fancy_upsampling=MagickFalse;
1197 if (IsMagickTrue(option) != MagickFalse)
1198 jpeg_info.do_fancy_upsampling=MagickTrue;
1200 (void) jpeg_start_decompress(&jpeg_info);
1201 image->columns=jpeg_info.output_width;
1202 image->rows=jpeg_info.output_height;
1203 image->depth=(size_t) jpeg_info.data_precision;
1204 if (jpeg_info.out_color_space == JCS_YCbCr)
1205 image->colorspace=YCbCrColorspace;
1206 if (jpeg_info.out_color_space == JCS_CMYK)
1207 image->colorspace=CMYKColorspace;
1208 option=GetImageOption(image_info,"jpeg:colors");
1209 if (option != (const char *) NULL)
1210 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1212 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1213 if ((jpeg_info.output_components == 1) &&
1214 (jpeg_info.quantize_colors == MagickFalse))
1219 colors=(size_t) GetQuantumRange(image->depth)+1;
1220 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1221 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1223 if (image->debug != MagickFalse)
1225 if (image->interlace != NoInterlace)
1226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1227 "Interlace: progressive");
1229 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1230 "Interlace: nonprogressive");
1231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1232 (int) jpeg_info.data_precision);
1233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1234 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1236 JPEGSetImageQuality(&jpeg_info,image);
1237 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1238 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1239 jpeg_info.out_color_space);
1240 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1241 if (image_info->ping != MagickFalse)
1243 jpeg_destroy_decompress(&jpeg_info);
1244 (void) CloseBlob(image);
1245 return(GetFirstImageInList(image));
1247 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1248 jpeg_info.output_components*sizeof(JSAMPLE));
1249 if (jpeg_pixels == (JSAMPLE *) NULL)
1250 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1252 Convert JPEG pixels to pixel packets.
1254 if (setjmp(error_manager.error_recovery) != 0)
1256 if (jpeg_pixels != (unsigned char *) NULL)
1257 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1258 jpeg_destroy_decompress(&jpeg_info);
1259 (void) CloseBlob(image);
1260 number_pixels=(MagickSizeType) image->columns*image->rows;
1261 if (number_pixels != 0)
1262 return(GetFirstImageInList(image));
1263 return(DestroyImage(image));
1265 if (jpeg_info.quantize_colors != MagickFalse)
1267 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1268 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1269 for (i=0; i < (ssize_t) image->colors; i++)
1271 image->colormap[i].red=(double) ScaleCharToQuantum(
1272 jpeg_info.colormap[0][i]);
1273 image->colormap[i].green=image->colormap[i].red;
1274 image->colormap[i].blue=image->colormap[i].red;
1275 image->colormap[i].alpha=OpaqueAlpha;
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=(double) ScaleCharToQuantum(
1283 jpeg_info.colormap[1][i]);
1284 image->colormap[i].blue=(double) ScaleCharToQuantum(
1285 jpeg_info.colormap[2][i]);
1286 image->colormap[i].alpha=OpaqueAlpha;
1289 scanline[0]=(JSAMPROW) jpeg_pixels;
1290 for (y=0; y < (ssize_t) image->rows; y++)
1298 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1300 (void) ThrowMagickException(exception,GetMagickModule(),
1301 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1305 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1306 if (q == (Quantum *) NULL)
1308 if (jpeg_info.data_precision > 8)
1310 if (jpeg_info.output_components == 1)
1311 for (x=0; x < (ssize_t) image->columns; x++)
1316 if (precision != 16)
1317 pixel=(size_t) GETJSAMPLE(*p);
1319 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1320 index=ConstrainColormapIndex(image,pixel,exception);
1321 SetPixelIndex(image,index,q);
1322 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1324 q+=GetPixelChannels(image);
1327 if (image->colorspace != CMYKColorspace)
1328 for (x=0; x < (ssize_t) image->columns; x++)
1330 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1331 (GETJSAMPLE(*p++) << 4)),q);
1332 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1333 (GETJSAMPLE(*p++) << 4)),q);
1334 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1335 (GETJSAMPLE(*p++) << 4)),q);
1336 SetPixelAlpha(image,OpaqueAlpha,q);
1337 q+=GetPixelChannels(image);
1340 for (x=0; x < (ssize_t) image->columns; x++)
1342 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1343 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1344 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1345 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1346 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1347 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1348 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1349 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1350 SetPixelAlpha(image,OpaqueAlpha,q);
1351 q+=GetPixelChannels(image);
1355 if (jpeg_info.output_components == 1)
1356 for (x=0; x < (ssize_t) image->columns; x++)
1358 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1359 SetPixelIndex(image,index,q);
1360 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1362 q+=GetPixelChannels(image);
1365 if (image->colorspace != CMYKColorspace)
1366 for (x=0; x < (ssize_t) image->columns; x++)
1368 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1369 GETJSAMPLE(*p++)),q);
1370 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1371 GETJSAMPLE(*p++)),q);
1372 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1373 GETJSAMPLE(*p++)),q);
1374 SetPixelAlpha(image,OpaqueAlpha,q);
1375 q+=GetPixelChannels(image);
1378 for (x=0; x < (ssize_t) image->columns; x++)
1380 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1381 (unsigned char) GETJSAMPLE(*p++)),q);
1382 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1383 (unsigned char) GETJSAMPLE(*p++)),q);
1384 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1385 (unsigned char) GETJSAMPLE(*p++)),q);
1386 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1387 (unsigned char) GETJSAMPLE(*p++)),q);
1388 SetPixelAlpha(image,OpaqueAlpha,q);
1389 q+=GetPixelChannels(image);
1391 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1393 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1395 if (status == MagickFalse)
1397 jpeg_abort_decompress(&jpeg_info);
1401 if (status != MagickFalse)
1403 error_manager.finished=MagickTrue;
1404 if (setjmp(error_manager.error_recovery) == 0)
1405 (void) jpeg_finish_decompress(&jpeg_info);
1408 Free jpeg resources.
1410 jpeg_destroy_decompress(&jpeg_info);
1411 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1412 (void) CloseBlob(image);
1413 return(GetFirstImageInList(image));
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 % R e g i s t e r J P E G I m a g e %
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 % RegisterJPEGImage() adds properties for the JPEG image format to
1429 % the list of supported formats. The properties include the image format
1430 % tag, a method to read and/or write the format, whether the format
1431 % supports the saving of more than one frame to the same file or blob,
1432 % whether the format supports native in-memory I/O, and a brief
1433 % description of the format.
1435 % The format of the RegisterJPEGImage method is:
1437 % size_t RegisterJPEGImage(void)
1440 ModuleExport size_t RegisterJPEGImage(void)
1443 version[MaxTextExtent];
1449 description[] = "Joint Photographic Experts Group JFIF format";
1452 #if defined(JPEG_LIB_VERSION)
1453 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1455 entry=SetMagickInfo("JPEG");
1456 entry->thread_support=NoThreadSupport;
1457 #if defined(MAGICKCORE_JPEG_DELEGATE)
1458 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1459 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1461 entry->magick=(IsImageFormatHandler *) IsJPEG;
1462 entry->adjoin=MagickFalse;
1463 entry->description=ConstantString(description);
1464 if (*version != '\0')
1465 entry->version=ConstantString(version);
1466 entry->module=ConstantString("JPEG");
1467 (void) RegisterMagickInfo(entry);
1468 entry=SetMagickInfo("JPG");
1469 entry->thread_support=NoThreadSupport;
1470 #if defined(MAGICKCORE_JPEG_DELEGATE)
1471 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1472 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1474 entry->adjoin=MagickFalse;
1475 entry->description=ConstantString(description);
1476 if (*version != '\0')
1477 entry->version=ConstantString(version);
1478 entry->module=ConstantString("JPEG");
1479 (void) RegisterMagickInfo(entry);
1480 entry=SetMagickInfo("PJPEG");
1481 entry->thread_support=NoThreadSupport;
1482 #if defined(MAGICKCORE_JPEG_DELEGATE)
1483 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1484 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1486 entry->adjoin=MagickFalse;
1487 entry->description=ConstantString(description);
1488 if (*version != '\0')
1489 entry->version=ConstantString(version);
1490 entry->module=ConstantString("JPEG");
1491 (void) RegisterMagickInfo(entry);
1492 return(MagickImageCoderSignature);
1496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1500 % U n r e g i s t e r J P E G I m a g e %
1504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 % UnregisterJPEGImage() removes format registrations made by the
1507 % JPEG module from the list of supported formats.
1509 % The format of the UnregisterJPEGImage method is:
1511 % UnregisterJPEGImage(void)
1514 ModuleExport void UnregisterJPEGImage(void)
1516 (void) UnregisterMagickInfo("PJPG");
1517 (void) UnregisterMagickInfo("JPEG");
1518 (void) UnregisterMagickInfo("JPG");
1521 #if defined(MAGICKCORE_JPEG_DELEGATE)
1523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527 % W r i t e J P E G I m a g e %
1531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533 % WriteJPEGImage() writes a JPEG image file and returns it. It
1534 % allocates the memory necessary for the new Image structure and returns a
1535 % pointer to the new image.
1537 % The format of the WriteJPEGImage method is:
1539 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1540 % Image *image,ExceptionInfo *exception)
1542 % A description of each parameter follows:
1544 % o image_info: the image info.
1546 % o jpeg_image: The image.
1548 % o exception: return any errors or warnings in this structure.
1552 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1554 assert(table != (QuantizationTable *) NULL);
1555 if (table->slot != (char *) NULL)
1556 table->slot=DestroyString(table->slot);
1557 if (table->description != (char *) NULL)
1558 table->description=DestroyString(table->description);
1559 if (table->levels != (unsigned int *) NULL)
1560 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1561 table=(QuantizationTable *) RelinquishMagickMemory(table);
1565 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1570 destination=(DestinationManager *) cinfo->dest;
1571 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1572 MaxBufferExtent,destination->buffer);
1573 if (destination->manager.free_in_buffer != MaxBufferExtent)
1574 ERREXIT(cinfo,JERR_FILE_WRITE);
1575 destination->manager.next_output_byte=destination->buffer;
1579 static QuantizationTable *GetQuantizationTable(const char *filename,
1580 const char *slot,ExceptionInfo *exception)
1608 *quantization_tables,
1611 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1612 "Loading quantization tables \"%s\" ...",filename);
1613 table=(QuantizationTable *) NULL;
1614 xml=FileToString(filename,~0,exception);
1615 if (xml == (char *) NULL)
1617 quantization_tables=NewXMLTree(xml,exception);
1618 if (quantization_tables == (XMLTreeInfo *) NULL)
1620 xml=DestroyString(xml);
1623 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1624 table_iterator != (XMLTreeInfo *) NULL;
1625 table_iterator=GetNextXMLTreeTag(table_iterator))
1627 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1628 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1630 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1631 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1634 if (table_iterator == (XMLTreeInfo *) NULL)
1636 xml=DestroyString(xml);
1639 description=GetXMLTreeChild(table_iterator,"description");
1640 if (description == (XMLTreeInfo *) NULL)
1642 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1643 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1644 quantization_tables=DestroyXMLTree(quantization_tables);
1645 xml=DestroyString(xml);
1648 levels=GetXMLTreeChild(table_iterator,"levels");
1649 if (levels == (XMLTreeInfo *) NULL)
1651 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1652 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1653 quantization_tables=DestroyXMLTree(quantization_tables);
1654 xml=DestroyString(xml);
1657 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1658 if (table == (QuantizationTable *) NULL)
1659 ThrowFatalException(ResourceLimitFatalError,
1660 "UnableToAcquireQuantizationTable");
1661 table->slot=(char *) NULL;
1662 table->description=(char *) NULL;
1663 table->levels=(unsigned int *) NULL;
1664 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1665 if (attribute != (char *) NULL)
1666 table->slot=ConstantString(attribute);
1667 content=GetXMLTreeContent(description);
1668 if (content != (char *) NULL)
1669 table->description=ConstantString(content);
1670 attribute=GetXMLTreeAttribute(levels,"width");
1671 if (attribute == (char *) NULL)
1673 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1674 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1675 quantization_tables=DestroyXMLTree(quantization_tables);
1676 table=DestroyQuantizationTable(table);
1677 xml=DestroyString(xml);
1680 table->width=StringToUnsignedLong(attribute);
1681 if (table->width == 0)
1683 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1684 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1685 quantization_tables=DestroyXMLTree(quantization_tables);
1686 table=DestroyQuantizationTable(table);
1687 xml=DestroyString(xml);
1690 attribute=GetXMLTreeAttribute(levels,"height");
1691 if (attribute == (char *) NULL)
1693 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1694 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1695 quantization_tables=DestroyXMLTree(quantization_tables);
1696 table=DestroyQuantizationTable(table);
1697 xml=DestroyString(xml);
1700 table->height=StringToUnsignedLong(attribute);
1701 if (table->height == 0)
1703 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1704 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1705 quantization_tables=DestroyXMLTree(quantization_tables);
1706 table=DestroyQuantizationTable(table);
1707 xml=DestroyString(xml);
1710 attribute=GetXMLTreeAttribute(levels,"divisor");
1711 if (attribute == (char *) NULL)
1713 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1714 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1715 quantization_tables=DestroyXMLTree(quantization_tables);
1716 table=DestroyQuantizationTable(table);
1717 xml=DestroyString(xml);
1720 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1721 if (table->divisor == 0.0)
1723 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1724 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1725 quantization_tables=DestroyXMLTree(quantization_tables);
1726 table=DestroyQuantizationTable(table);
1727 xml=DestroyString(xml);
1730 content=GetXMLTreeContent(levels);
1731 if (content == (char *) NULL)
1733 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1734 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1735 quantization_tables=DestroyXMLTree(quantization_tables);
1736 table=DestroyQuantizationTable(table);
1737 xml=DestroyString(xml);
1740 length=(size_t) table->width*table->height;
1743 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1744 sizeof(*table->levels));
1745 if (table->levels == (unsigned int *) NULL)
1746 ThrowFatalException(ResourceLimitFatalError,
1747 "UnableToAcquireQuantizationTable");
1748 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1750 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1751 table->divisor+0.5);
1752 while (isspace((int) ((unsigned char) *p)) != 0)
1758 value=InterpretLocaleValue(content,&p);
1762 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1763 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1764 quantization_tables=DestroyXMLTree(quantization_tables);
1765 table=DestroyQuantizationTable(table);
1766 xml=DestroyString(xml);
1769 for (j=i; j < 64; j++)
1770 table->levels[j]=table->levels[j-1];
1771 quantization_tables=DestroyXMLTree(quantization_tables);
1772 xml=DestroyString(xml);
1776 static void InitializeDestination(j_compress_ptr cinfo)
1781 destination=(DestinationManager *) cinfo->dest;
1782 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1783 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1784 destination->manager.next_output_byte=destination->buffer;
1785 destination->manager.free_in_buffer=MaxBufferExtent;
1788 static inline size_t MagickMin(const size_t x,const size_t y)
1795 static void TerminateDestination(j_compress_ptr cinfo)
1800 destination=(DestinationManager *) cinfo->dest;
1801 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1806 count=WriteBlob(destination->image,MaxBufferExtent-
1807 destination->manager.free_in_buffer,destination->buffer);
1808 if (count != (ssize_t)
1809 (MaxBufferExtent-destination->manager.free_in_buffer))
1810 ERREXIT(cinfo,JERR_FILE_WRITE);
1814 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1836 Save image profile as a APP marker.
1839 custom_profile=AcquireStringInfo(65535L);
1840 ResetImageProfileIterator(image);
1841 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1843 register unsigned char
1846 profile=GetImageProfile(image,name);
1847 p=GetStringInfoDatum(custom_profile);
1848 if (LocaleCompare(name,"EXIF") == 0)
1849 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1851 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1852 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1853 (unsigned int) length);
1855 if (LocaleCompare(name,"ICC") == 0)
1857 register unsigned char
1861 p=GetStringInfoDatum(custom_profile);
1862 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1863 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1865 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1866 p[12]=(unsigned char) ((i/65519L)+1);
1867 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1868 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1870 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1871 custom_profile),(unsigned int) (length+tag_length));
1874 if (((LocaleCompare(name,"IPTC") == 0) ||
1875 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1881 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1883 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1884 roundup=(size_t) (length & 0x01);
1885 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1887 (void) memcpy(p,"Photoshop 3.0 ",14);
1892 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1894 p[24]=(unsigned char) (length >> 8);
1895 p[25]=(unsigned char) (length & 0xff);
1898 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1900 p[length+tag_length]='\0';
1901 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1902 custom_profile),(unsigned int) (length+tag_length+roundup));
1905 if (LocaleCompare(name,"XMP") == 0)
1911 Add namespace to XMP profile.
1913 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1914 ConcatenateStringInfo(xmp_profile,profile);
1915 GetStringInfoDatum(xmp_profile)[28]='\0';
1916 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1918 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1919 jpeg_write_marker(jpeg_info,XML_MARKER,
1920 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1922 xmp_profile=DestroyStringInfo(xmp_profile);
1924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1925 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1926 name=GetNextImageProfile(image);
1928 custom_profile=DestroyStringInfo(custom_profile);
1931 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1936 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1937 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1938 destination=(DestinationManager *) cinfo->dest;
1939 destination->manager.init_destination=InitializeDestination;
1940 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1941 destination->manager.term_destination=TerminateDestination;
1942 destination->image=image;
1945 static char **SamplingFactorToList(const char *text)
1962 if (text == (char *) NULL)
1963 return((char **) NULL);
1965 Convert string to an ASCII list.
1968 for (p=text; *p != '\0'; p++)
1971 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1973 if (textlist == (char **) NULL)
1974 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1976 for (i=0; i < (ssize_t) lines; i++)
1978 for (q=(char *) p; *q != '\0'; q++)
1981 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1982 sizeof(*textlist[i]));
1983 if (textlist[i] == (char *) NULL)
1984 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1985 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1990 textlist[i]=(char *) NULL;
1994 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1995 Image *image,ExceptionInfo *exception)
2026 struct jpeg_compress_struct
2029 struct jpeg_error_mgr
2035 assert(image_info != (const ImageInfo *) NULL);
2036 assert(image_info->signature == MagickSignature);
2037 assert(image != (Image *) NULL);
2038 assert(image->signature == MagickSignature);
2039 if (image->debug != MagickFalse)
2040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2041 assert(exception != (ExceptionInfo *) NULL);
2042 assert(exception->signature == MagickSignature);
2043 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2044 if (status == MagickFalse)
2047 Initialize JPEG parameters.
2049 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2050 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2051 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2052 jpeg_info.client_data=(void *) image;
2053 jpeg_info.err=jpeg_std_error(&jpeg_error);
2054 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2055 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2056 error_manager.exception=exception;
2057 error_manager.image=image;
2058 jpeg_pixels=(JSAMPLE *) NULL;
2059 if (setjmp(error_manager.error_recovery) != 0)
2061 jpeg_destroy_compress(&jpeg_info);
2062 (void) CloseBlob(image);
2063 return(MagickFalse);
2065 jpeg_info.client_data=(void *) &error_manager;
2066 jpeg_create_compress(&jpeg_info);
2067 JPEGDestinationManager(&jpeg_info,image);
2068 if ((image->columns != (unsigned int) image->columns) ||
2069 (image->rows != (unsigned int) image->rows))
2070 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2071 jpeg_info.image_width=(unsigned int) image->columns;
2072 jpeg_info.image_height=(unsigned int) image->rows;
2073 jpeg_info.input_components=3;
2074 jpeg_info.data_precision=8;
2075 jpeg_info.in_color_space=JCS_RGB;
2076 switch (image->colorspace)
2078 case CMYKColorspace:
2080 jpeg_info.input_components=4;
2081 jpeg_info.in_color_space=JCS_CMYK;
2084 case YCbCrColorspace:
2085 case Rec601YCbCrColorspace:
2086 case Rec709YCbCrColorspace:
2088 jpeg_info.in_color_space=JCS_YCbCr;
2091 case GRAYColorspace:
2092 case Rec601LumaColorspace:
2093 case Rec709LumaColorspace:
2095 jpeg_info.input_components=1;
2096 jpeg_info.in_color_space=JCS_GRAYSCALE;
2101 if (IsRGBColorspace(image->colorspace) == MagickFalse)
2102 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2106 if ((image_info->type != TrueColorType) &&
2107 (IsImageGray(image,exception) != MagickFalse))
2109 jpeg_info.input_components=1;
2110 jpeg_info.in_color_space=JCS_GRAYSCALE;
2112 jpeg_set_defaults(&jpeg_info);
2113 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2114 jpeg_info.data_precision=8;
2116 if (sizeof(JSAMPLE) > 1)
2117 jpeg_info.data_precision=12;
2118 jpeg_info.density_unit=(UINT8) 1;
2119 if (image->debug != MagickFalse)
2120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2121 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2122 floor(image->resolution.y+0.5));
2123 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2126 Set image resolution.
2128 jpeg_info.write_JFIF_header=MagickTrue;
2129 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2130 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2131 if (image->units == PixelsPerInchResolution)
2132 jpeg_info.density_unit=(UINT8) 1;
2133 if (image->units == PixelsPerCentimeterResolution)
2134 jpeg_info.density_unit=(UINT8) 2;
2136 jpeg_info.dct_method=JDCT_FLOAT;
2137 option=GetImageOption(image_info,"jpeg:dct-method");
2138 if (option != (const char *) NULL)
2144 if (LocaleCompare(option,"default") == 0)
2145 jpeg_info.dct_method=JDCT_DEFAULT;
2151 if (LocaleCompare(option,"fastest") == 0)
2152 jpeg_info.dct_method=JDCT_FASTEST;
2153 if (LocaleCompare(option,"float") == 0)
2154 jpeg_info.dct_method=JDCT_FLOAT;
2160 if (LocaleCompare(option,"ifast") == 0)
2161 jpeg_info.dct_method=JDCT_IFAST;
2162 if (LocaleCompare(option,"islow") == 0)
2163 jpeg_info.dct_method=JDCT_ISLOW;
2167 option=GetImageOption(image_info,"jpeg:optimize-coding");
2168 if (option != (const char *) NULL)
2170 jpeg_info.optimize_coding=MagickFalse;
2171 if (IsMagickTrue(option) != MagickFalse)
2172 jpeg_info.optimize_coding=MagickTrue;
2179 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2180 image->rows*sizeof(JSAMPLE);
2181 if (length == (MagickSizeType) ((size_t) length))
2184 Perform optimization only if available memory resources permit it.
2186 status=AcquireMagickResource(MemoryResource,length);
2187 if (status != MagickFalse)
2188 jpeg_info.optimize_coding=MagickTrue;
2189 RelinquishMagickResource(MemoryResource,length);
2192 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2193 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2194 (image_info->interlace != NoInterlace))
2196 if (image->debug != MagickFalse)
2197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2198 "Interlace: progressive");
2199 jpeg_simple_progression(&jpeg_info);
2202 if (image->debug != MagickFalse)
2203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2204 "Interlace: non-progressive");
2206 if (image->debug != MagickFalse)
2207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2208 "Interlace: nonprogressive");
2210 option=GetImageOption(image_info,"jpeg:extent");
2211 if (option != (const char *) NULL)
2219 jpeg_info=CloneImageInfo(image_info);
2220 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2221 if (jpeg_image != (Image *) NULL)
2231 Search for compression quality that does not exceed image extent.
2233 jpeg_info->quality=0;
2234 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2235 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2236 (void) AcquireUniqueFilename(jpeg_image->filename);
2238 for (minimum=0; minimum != maximum; )
2240 jpeg_image->quality=minimum+(maximum-minimum)/2;
2241 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2242 if (GetBlobSize(jpeg_image) <= extent)
2243 minimum=jpeg_image->quality+1;
2245 maximum=jpeg_image->quality-1;
2247 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2248 image->quality=minimum-1;
2249 jpeg_image=DestroyImage(jpeg_image);
2251 jpeg_info=DestroyImageInfo(jpeg_info);
2254 if ((image_info->compression != LosslessJPEGCompression) &&
2255 (image->quality <= 100))
2257 if (image->quality != UndefinedCompressionQuality)
2258 quality=(int) image->quality;
2259 if (image->debug != MagickFalse)
2260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2261 (double) image->quality);
2265 #if !defined(C_LOSSLESS_SUPPORTED)
2267 if (image->debug != MagickFalse)
2268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2270 if (image->quality < 100)
2271 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2272 "LosslessToLossyJPEGConversion",image->filename);
2279 predictor=image->quality/100; /* range 1-7 */
2280 point_transform=image->quality % 20; /* range 0-15 */
2281 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2282 if (image->debug != MagickFalse)
2284 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2285 "Compression: lossless");
2286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2287 "Predictor: %d",predictor);
2288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2289 "Point Transform: %d",point_transform);
2294 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2295 sampling_factor=(const char *) NULL;
2296 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2297 if (value != (char *) NULL)
2299 sampling_factor=value;
2300 if (image->debug != MagickFalse)
2301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2302 " Input sampling-factors=%s",sampling_factor);
2304 if (image_info->sampling_factor != (char *) NULL)
2305 sampling_factor=image_info->sampling_factor;
2306 if (sampling_factor == (const char *) NULL)
2308 if (image->quality >= 90)
2309 for (i=0; i < MAX_COMPONENTS; i++)
2311 jpeg_info.comp_info[i].h_samp_factor=1;
2312 jpeg_info.comp_info[i].v_samp_factor=1;
2327 Set sampling factor.
2330 factors=SamplingFactorToList(sampling_factor);
2331 if (factors != (char **) NULL)
2333 for (i=0; i < MAX_COMPONENTS; i++)
2335 if (factors[i] == (char *) NULL)
2337 flags=ParseGeometry(factors[i],&geometry_info);
2338 if ((flags & SigmaValue) == 0)
2339 geometry_info.sigma=geometry_info.rho;
2340 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2341 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2342 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2344 factors=(char **) RelinquishMagickMemory(factors);
2346 for ( ; i < MAX_COMPONENTS; i++)
2348 jpeg_info.comp_info[i].h_samp_factor=1;
2349 jpeg_info.comp_info[i].v_samp_factor=1;
2352 if (jpeg_info.input_components == 1)
2353 for (i=0; i < MAX_COMPONENTS; i++)
2355 jpeg_info.comp_info[i].h_samp_factor=1;
2356 jpeg_info.comp_info[i].v_samp_factor=1;
2358 option=GetImageOption(image_info,"jpeg:q-table");
2359 if (option != (const char *) NULL)
2365 Custom quantization tables.
2367 table=GetQuantizationTable(option,"0",exception);
2368 if (table != (QuantizationTable *) NULL)
2370 jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2372 table=DestroyQuantizationTable(table);
2374 table=GetQuantizationTable(option,"1",exception);
2375 if (table != (QuantizationTable *) NULL)
2377 jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2379 table=DestroyQuantizationTable(table);
2381 table=GetQuantizationTable(option,"2",exception);
2382 if (table != (QuantizationTable *) NULL)
2384 jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2386 table=DestroyQuantizationTable(table);
2388 table=GetQuantizationTable(option,"3",exception);
2389 if (table != (QuantizationTable *) NULL)
2391 jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2393 table=DestroyQuantizationTable(table);
2396 jpeg_start_compress(&jpeg_info,MagickTrue);
2397 if (image->debug != MagickFalse)
2399 if (image->storage_class == PseudoClass)
2400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2401 "Storage class: PseudoClass");
2403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2404 "Storage class: DirectClass");
2405 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2406 (double) image->depth);
2407 if (image->colors != 0)
2408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2409 "Number of colors: %.20g",(double) image->colors);
2411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2412 "Number of colors: unspecified");
2413 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2414 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2415 switch (image->colorspace)
2417 case CMYKColorspace:
2419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2420 "Storage class: DirectClass");
2421 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2422 "Colorspace: CMYK");
2425 case YCbCrColorspace:
2426 case Rec601YCbCrColorspace:
2427 case Rec709YCbCrColorspace:
2429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2430 "Colorspace: YCbCr");
2436 switch (image->colorspace)
2438 case CMYKColorspace:
2440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2441 "Colorspace: CMYK");
2442 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2443 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2444 jpeg_info.comp_info[0].h_samp_factor,
2445 jpeg_info.comp_info[0].v_samp_factor,
2446 jpeg_info.comp_info[1].h_samp_factor,
2447 jpeg_info.comp_info[1].v_samp_factor,
2448 jpeg_info.comp_info[2].h_samp_factor,
2449 jpeg_info.comp_info[2].v_samp_factor,
2450 jpeg_info.comp_info[3].h_samp_factor,
2451 jpeg_info.comp_info[3].v_samp_factor);
2454 case GRAYColorspace:
2455 case Rec601LumaColorspace:
2456 case Rec709LumaColorspace:
2458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459 "Colorspace: GRAY");
2460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2461 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2462 jpeg_info.comp_info[0].v_samp_factor);
2467 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2468 "Image colorspace is RGB");
2469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2470 "Sampling factors: %dx%d,%dx%d,%dx%d",
2471 jpeg_info.comp_info[0].h_samp_factor,
2472 jpeg_info.comp_info[0].v_samp_factor,
2473 jpeg_info.comp_info[1].h_samp_factor,
2474 jpeg_info.comp_info[1].v_samp_factor,
2475 jpeg_info.comp_info[2].h_samp_factor,
2476 jpeg_info.comp_info[2].v_samp_factor);
2479 case YCbCrColorspace:
2480 case Rec601YCbCrColorspace:
2481 case Rec709YCbCrColorspace:
2483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2484 "Colorspace: YCbCr");
2485 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2486 "Sampling factors: %dx%d,%dx%d,%dx%d",
2487 jpeg_info.comp_info[0].h_samp_factor,
2488 jpeg_info.comp_info[0].v_samp_factor,
2489 jpeg_info.comp_info[1].h_samp_factor,
2490 jpeg_info.comp_info[1].v_samp_factor,
2491 jpeg_info.comp_info[2].h_samp_factor,
2492 jpeg_info.comp_info[2].v_samp_factor);
2497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2500 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2501 jpeg_info.comp_info[0].h_samp_factor,
2502 jpeg_info.comp_info[0].v_samp_factor,
2503 jpeg_info.comp_info[1].h_samp_factor,
2504 jpeg_info.comp_info[1].v_samp_factor,
2505 jpeg_info.comp_info[2].h_samp_factor,
2506 jpeg_info.comp_info[2].v_samp_factor,
2507 jpeg_info.comp_info[3].h_samp_factor,
2508 jpeg_info.comp_info[3].v_samp_factor);
2514 Write JPEG profiles.
2516 value=GetImageProperty(image,"comment",exception);
2517 if (value != (char *) NULL)
2518 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2519 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2520 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2521 if (image->profiles != (void *) NULL)
2522 WriteProfile(&jpeg_info,image);
2524 Convert MIFF to JPEG raster pixels.
2526 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2527 jpeg_info.input_components*sizeof(*jpeg_pixels));
2528 if (jpeg_pixels == (JSAMPLE *) NULL)
2529 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2530 if (setjmp(error_manager.error_recovery) != 0)
2532 jpeg_destroy_compress(&jpeg_info);
2533 if (jpeg_pixels != (unsigned char *) NULL)
2534 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2535 (void) CloseBlob(image);
2536 return(MagickFalse);
2538 scanline[0]=(JSAMPROW) jpeg_pixels;
2539 if (jpeg_info.data_precision <= 8)
2541 if ((jpeg_info.in_color_space == JCS_RGB) ||
2542 (jpeg_info.in_color_space == JCS_YCbCr))
2543 for (y=0; y < (ssize_t) image->rows; y++)
2545 register const Quantum
2551 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2552 if (p == (const Quantum *) NULL)
2555 for (x=0; x < (ssize_t) image->columns; x++)
2557 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2558 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2559 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2560 p+=GetPixelChannels(image);
2562 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2563 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2565 if (status == MagickFalse)
2569 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2570 for (y=0; y < (ssize_t) image->rows; y++)
2572 register const Quantum
2578 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2579 if (p == (const Quantum *) NULL)
2582 for (x=0; x < (ssize_t) image->columns; x++)
2584 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2585 p+=GetPixelChannels(image);
2587 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2588 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2590 if (status == MagickFalse)
2594 for (y=0; y < (ssize_t) image->rows; y++)
2596 register const Quantum
2602 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2603 if (p == (const Quantum *) NULL)
2606 for (x=0; x < (ssize_t) image->columns; x++)
2609 Convert DirectClass packets to contiguous CMYK scanlines.
2611 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2612 GetPixelRed(image,p))));
2613 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2614 GetPixelGreen(image,p))));
2615 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2616 GetPixelBlue(image,p))));
2617 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2618 GetPixelBlack(image,p))));
2619 p+=GetPixelChannels(image);
2621 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2622 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2624 if (status == MagickFalse)
2629 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2630 for (y=0; y < (ssize_t) image->rows; y++)
2632 register const Quantum
2638 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2639 if (p == (const Quantum *) NULL)
2642 for (x=0; x < (ssize_t) image->columns; x++)
2644 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >> 4);
2645 p+=GetPixelChannels(image);
2647 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2648 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2650 if (status == MagickFalse)
2654 if ((jpeg_info.in_color_space == JCS_RGB) ||
2655 (jpeg_info.in_color_space == JCS_YCbCr))
2656 for (y=0; y < (ssize_t) image->rows; y++)
2658 register const Quantum
2664 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2665 if (p == (const Quantum *) NULL)
2668 for (x=0; x < (ssize_t) image->columns; x++)
2670 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2671 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2672 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(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 for (y=0; y < (ssize_t) image->rows; y++)
2684 register const Quantum
2690 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2691 if (p == (const Quantum *) NULL)
2694 for (x=0; x < (ssize_t) image->columns; x++)
2697 Convert DirectClass packets to contiguous CMYK scanlines.
2699 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2700 GetPixelRed(image,p)) >> 4));
2701 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2702 GetPixelGreen(image,p)) >> 4));
2703 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2704 GetPixelBlue(image,p)) >> 4));
2705 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2706 GetPixelBlack(image,p)) >> 4));
2707 p+=GetPixelChannels(image);
2709 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2710 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2712 if (status == MagickFalse)
2715 if (y == (ssize_t) image->rows)
2716 jpeg_finish_compress(&jpeg_info);
2718 Relinquish resources.
2720 jpeg_destroy_compress(&jpeg_info);
2721 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2722 (void) CloseBlob(image);