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
168 Forward declarations.
170 #if defined(MAGICKCORE_JPEG_DELEGATE)
171 static MagickBooleanType
172 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 % IsJPEG() returns MagickTrue if the image format type, identified by the
187 % magick string, is JPEG.
189 % The format of the IsJPEG method is:
191 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
193 % A description of each parameter follows:
195 % o magick: compare image format pattern against these bytes.
197 % o length: Specifies the length of the magick string.
200 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
204 if (memcmp(magick,"\377\330\377",3) == 0)
209 #if defined(MAGICKCORE_JPEG_DELEGATE)
211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 % R e a d J P E G I m a g e %
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
222 % the memory necessary for the new Image structure and returns a pointer to
225 % The format of the ReadJPEGImage method is:
227 % Image *ReadJPEGImage(const ImageInfo *image_info,
228 % ExceptionInfo *exception)
230 % A description of each parameter follows:
232 % o image_info: the image info.
234 % o exception: return any errors or warnings in this structure.
238 static boolean FillInputBuffer(j_decompress_ptr cinfo)
243 source=(SourceManager *) cinfo->src;
244 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
245 MaxBufferExtent,source->buffer);
246 if (source->manager.bytes_in_buffer == 0)
248 if (source->start_of_blob != 0)
249 ERREXIT(cinfo,JERR_INPUT_EMPTY);
250 WARNMS(cinfo,JWRN_JPEG_EOF);
251 source->buffer[0]=(JOCTET) 0xff;
252 source->buffer[1]=(JOCTET) JPEG_EOI;
253 source->manager.bytes_in_buffer=2;
255 source->manager.next_input_byte=source->buffer;
256 source->start_of_blob=FALSE;
260 static int GetCharacter(j_decompress_ptr jpeg_info)
262 if (jpeg_info->src->bytes_in_buffer == 0)
263 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
264 jpeg_info->src->bytes_in_buffer--;
265 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
268 static void InitializeSource(j_decompress_ptr cinfo)
273 source=(SourceManager *) cinfo->src;
274 source->start_of_blob=TRUE;
277 static MagickBooleanType IsITUFaxImage(const Image *image)
285 profile=GetImageProfile(image,"8bim");
286 if (profile == (const StringInfo *) NULL)
288 if (GetStringInfoLength(profile) < 5)
290 datum=GetStringInfoDatum(profile);
291 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
292 (datum[3] == 0x41) && (datum[4] == 0x58))
297 static void JPEGErrorHandler(j_common_ptr jpeg_info)
300 message[JMSG_LENGTH_MAX];
312 error_manager=(ErrorManager *) jpeg_info->client_data;
313 image=error_manager->image;
314 exception=error_manager->exception;
315 (jpeg_info->err->format_message)(jpeg_info,message);
316 if (image->debug != MagickFalse)
317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
318 "[%s] JPEG Trace: \"%s\"",image->filename,message);
319 if (error_manager->finished != MagickFalse)
320 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
321 (char *) message,"`%s'",image->filename);
323 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
324 (char *) message,"`%s'",image->filename);
325 longjmp(error_manager->error_recovery,1);
328 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
331 message[JMSG_LENGTH_MAX];
343 error_manager=(ErrorManager *) jpeg_info->client_data;
344 exception=error_manager->exception;
345 image=error_manager->image;
349 Process warning message.
351 (jpeg_info->err->format_message)(jpeg_info,message);
352 if ((jpeg_info->err->num_warnings == 0) ||
353 (jpeg_info->err->trace_level >= 3))
354 ThrowBinaryException(CorruptImageWarning,(char *) message,
356 jpeg_info->err->num_warnings++;
359 if ((image->debug != MagickFalse) &&
360 (level >= jpeg_info->err->trace_level))
363 Process trace message.
365 (jpeg_info->err->format_message)(jpeg_info,message);
366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
367 "[%s] JPEG Trace: \"%s\"",image->filename,message);
372 static boolean ReadComment(j_decompress_ptr jpeg_info)
396 Determine length of comment.
398 error_manager=(ErrorManager *) jpeg_info->client_data;
399 exception=error_manager->exception;
400 image=error_manager->image;
401 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
402 length+=GetCharacter(jpeg_info);
406 comment=(char *) NULL;
407 if (~length >= (MaxTextExtent-1))
408 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
410 if (comment == (char *) NULL)
411 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
416 i=(ssize_t) length-1;
417 for (p=comment; i-- >= 0; p++)
418 *p=(char) GetCharacter(jpeg_info);
420 (void) SetImageProperty(image,"comment",comment,exception);
421 comment=DestroyString(comment);
425 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
445 register unsigned char
458 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
459 length+=(size_t) GetCharacter(jpeg_info);
464 (void) GetCharacter(jpeg_info);
467 for (i=0; i < 12; i++)
468 magick[i]=(char) GetCharacter(jpeg_info);
469 if (LocaleCompare(magick,ICC_PROFILE) != 0)
472 Not a ICC profile, return.
474 for (i=0; i < (ssize_t) (length-12); i++)
475 (void) GetCharacter(jpeg_info);
478 (void) GetCharacter(jpeg_info); /* id */
479 (void) GetCharacter(jpeg_info); /* markers */
481 error_manager=(ErrorManager *) jpeg_info->client_data;
482 exception=error_manager->exception;
483 image=error_manager->image;
484 profile=BlobToStringInfo((const void *) NULL,length);
485 if (profile == (StringInfo *) NULL)
486 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
488 p=GetStringInfoDatum(profile);
489 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
490 *p++=(unsigned char) GetCharacter(jpeg_info);
491 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
492 if (icc_profile != (StringInfo *) NULL)
494 ConcatenateStringInfo(icc_profile,profile);
495 profile=DestroyStringInfo(profile);
499 status=SetImageProfile(image,"icc",profile,exception);
500 profile=DestroyStringInfo(profile);
501 if (status == MagickFalse)
502 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
505 if (image->debug != MagickFalse)
506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
507 "Profile: ICC, %.20g bytes",(double) length);
511 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
514 magick[MaxTextExtent];
531 register unsigned char
542 Determine length of binary data stored here.
544 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
545 length+=(size_t) GetCharacter(jpeg_info);
550 (void) GetCharacter(jpeg_info);
554 Validate that this was written as a Photoshop resource format slug.
556 for (i=0; i < 10; i++)
557 magick[i]=(char) GetCharacter(jpeg_info);
562 if (LocaleCompare(magick,"Photoshop ") != 0)
565 Not a IPTC profile, return.
567 for (i=0; i < (ssize_t) length; i++)
568 (void) GetCharacter(jpeg_info);
572 Remove the version number.
574 for (i=0; i < 4; i++)
575 (void) GetCharacter(jpeg_info);
581 error_manager=(ErrorManager *) jpeg_info->client_data;
582 exception=error_manager->exception;
583 image=error_manager->image;
584 profile=BlobToStringInfo((const void *) NULL,length);
585 if (profile == (StringInfo *) NULL)
586 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
588 p=GetStringInfoDatum(profile);
589 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
590 *p++=(unsigned char) GetCharacter(jpeg_info);
591 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
592 if (iptc_profile != (StringInfo *) NULL)
594 ConcatenateStringInfo(iptc_profile,profile);
595 profile=DestroyStringInfo(profile);
599 status=SetImageProfile(image,"8bim",profile,exception);
600 profile=DestroyStringInfo(profile);
601 if (status == MagickFalse)
602 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
605 if (image->debug != MagickFalse)
606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
607 "Profile: iptc, %.20g bytes",(double) length);
611 static boolean ReadProfile(j_decompress_ptr jpeg_info)
637 register unsigned char
647 Read generic profile.
649 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
650 length+=(size_t) GetCharacter(jpeg_info);
654 marker=jpeg_info->unread_marker-JPEG_APP0;
655 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
656 error_manager=(ErrorManager *) jpeg_info->client_data;
657 exception=error_manager->exception;
658 image=error_manager->image;
659 profile=BlobToStringInfo((const void *) NULL,length);
660 if (profile == (StringInfo *) NULL)
661 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
663 p=GetStringInfoDatum(profile);
664 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
665 *p++=(unsigned char) GetCharacter(jpeg_info);
668 p=GetStringInfoDatum(profile);
669 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
670 (void) CopyMagickString(name,"exif",MaxTextExtent);
671 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
677 Extract namespace from XMP profile.
679 p=GetStringInfoDatum(profile);
680 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
686 if (j < (ssize_t) GetStringInfoLength(profile))
687 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
688 (void) CopyMagickString(name,"xmp",MaxTextExtent);
691 previous_profile=GetImageProfile(image,name);
692 if (previous_profile != (const StringInfo *) NULL)
697 length=GetStringInfoLength(profile);
698 SetStringInfoLength(profile,GetStringInfoLength(profile)+
699 GetStringInfoLength(previous_profile));
700 (void) memmove(GetStringInfoDatum(profile)+
701 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
703 (void) memcpy(GetStringInfoDatum(profile),
704 GetStringInfoDatum(previous_profile),
705 GetStringInfoLength(previous_profile));
707 status=SetImageProfile(image,name,profile,exception);
708 profile=DestroyStringInfo(profile);
709 if (status == MagickFalse)
710 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
712 if (image->debug != MagickFalse)
713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
714 "Profile: %s, %.20g bytes",name,(double) length);
718 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
723 if (number_bytes <= 0)
725 source=(SourceManager *) cinfo->src;
726 while (number_bytes > (long) source->manager.bytes_in_buffer)
728 number_bytes-=(long) source->manager.bytes_in_buffer;
729 (void) FillInputBuffer(cinfo);
731 source->manager.next_input_byte+=number_bytes;
732 source->manager.bytes_in_buffer-=number_bytes;
735 static void TerminateSource(j_decompress_ptr cinfo)
740 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
745 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
746 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
747 source=(SourceManager *) cinfo->src;
748 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
749 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
750 source=(SourceManager *) cinfo->src;
751 source->manager.init_source=InitializeSource;
752 source->manager.fill_input_buffer=FillInputBuffer;
753 source->manager.skip_input_data=SkipInputData;
754 source->manager.resync_to_restart=jpeg_resync_to_restart;
755 source->manager.term_source=TerminateSource;
756 source->manager.bytes_in_buffer=0;
757 source->manager.next_input_byte=NULL;
761 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
764 image->quality=UndefinedCompressionQuality;
765 #if defined(D_PROGRESSIVE_SUPPORTED)
766 if (image->compression == LosslessJPEGCompression)
769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
770 "Quality: 100 (lossless)");
784 Determine the JPEG compression quality from the quantization tables.
787 for (i=0; i < NUM_QUANT_TBLS; i++)
789 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
790 for (j=0; j < DCTSIZE2; j++)
791 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
793 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
794 (jpeg_info->quant_tbl_ptrs[1] != NULL))
799 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
800 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
801 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
802 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
803 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
804 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
805 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
806 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
807 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
808 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
813 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
814 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
815 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
816 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
817 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
818 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
819 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
820 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
821 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
822 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
823 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
827 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
828 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
829 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
830 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
831 for (i=0; i < 100; i++)
833 if ((qvalue < hash[i]) && (sum < sums[i]))
835 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
836 image->quality=(size_t) i+1;
837 if (image->debug != MagickFalse)
838 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
839 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
840 (sum <= sums[i]) ? "exact" : "approximate");
845 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
850 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
851 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
852 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
853 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
854 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
855 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
856 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
857 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
858 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
859 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
864 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
865 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
866 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
867 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
868 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
869 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
870 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
871 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
872 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
873 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
874 667, 592, 518, 441, 369, 292, 221, 151, 86,
878 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
879 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
880 for (i=0; i < 100; i++)
882 if ((qvalue < hash[i]) && (sum < sums[i]))
884 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
885 image->quality=(size_t) i+1;
886 if (image->debug != MagickFalse)
887 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
888 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
889 (sum <= sums[i]) ? "exact" : "approximate");
896 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
899 sampling_factor[MaxTextExtent];
901 switch (jpeg_info->out_color_space)
905 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
906 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
907 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
908 jpeg_info->comp_info[0].v_samp_factor,
909 jpeg_info->comp_info[1].h_samp_factor,
910 jpeg_info->comp_info[1].v_samp_factor,
911 jpeg_info->comp_info[2].h_samp_factor,
912 jpeg_info->comp_info[2].v_samp_factor,
913 jpeg_info->comp_info[3].h_samp_factor,
914 jpeg_info->comp_info[3].v_samp_factor);
919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
920 "Colorspace: GRAYSCALE");
921 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
922 jpeg_info->comp_info[0].h_samp_factor,
923 jpeg_info->comp_info[0].v_samp_factor);
928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
929 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
930 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
931 jpeg_info->comp_info[0].v_samp_factor,
932 jpeg_info->comp_info[1].h_samp_factor,
933 jpeg_info->comp_info[1].v_samp_factor,
934 jpeg_info->comp_info[2].h_samp_factor,
935 jpeg_info->comp_info[2].v_samp_factor);
940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
941 jpeg_info->out_color_space);
942 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
943 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
944 jpeg_info->comp_info[0].v_samp_factor,
945 jpeg_info->comp_info[1].h_samp_factor,
946 jpeg_info->comp_info[1].v_samp_factor,
947 jpeg_info->comp_info[2].h_samp_factor,
948 jpeg_info->comp_info[2].v_samp_factor,
949 jpeg_info->comp_info[3].h_samp_factor,
950 jpeg_info->comp_info[3].v_samp_factor);
954 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
956 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
960 static Image *ReadJPEGImage(const ImageInfo *image_info,
961 ExceptionInfo *exception)
964 value[MaxTextExtent];
994 struct jpeg_decompress_struct
997 struct jpeg_error_mgr
1013 assert(image_info != (const ImageInfo *) NULL);
1014 assert(image_info->signature == MagickSignature);
1015 if (image_info->debug != MagickFalse)
1016 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1017 image_info->filename);
1018 assert(exception != (ExceptionInfo *) NULL);
1019 assert(exception->signature == MagickSignature);
1020 debug=IsEventLogging();
1022 image=AcquireImage(image_info,exception);
1023 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1024 if (status == MagickFalse)
1026 image=DestroyImageList(image);
1027 return((Image *) NULL);
1030 Initialize JPEG parameters.
1032 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1033 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1034 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1035 jpeg_info.err=jpeg_std_error(&jpeg_error);
1036 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1037 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1038 jpeg_pixels=(JSAMPLE *) NULL;
1039 error_manager.exception=exception;
1040 error_manager.image=image;
1041 if (setjmp(error_manager.error_recovery) != 0)
1043 jpeg_destroy_decompress(&jpeg_info);
1044 (void) CloseBlob(image);
1045 number_pixels=(MagickSizeType) image->columns*image->rows;
1046 if (number_pixels != 0)
1047 return(GetFirstImageInList(image));
1048 return(DestroyImage(image));
1050 jpeg_info.client_data=(void *) &error_manager;
1051 jpeg_create_decompress(&jpeg_info);
1052 JPEGSourceManager(&jpeg_info,image);
1053 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1054 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1055 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1056 for (i=1; i < 16; i++)
1057 if ((i != 2) && (i != 13) && (i != 14))
1058 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1059 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1060 if ((image_info->colorspace == YCbCrColorspace) ||
1061 (image_info->colorspace == Rec601YCbCrColorspace) ||
1062 (image_info->colorspace == Rec709YCbCrColorspace))
1063 jpeg_info.out_color_space=JCS_YCbCr;
1064 if (IsITUFaxImage(image) != MagickFalse)
1066 image->colorspace=LabColorspace;
1067 jpeg_info.out_color_space=JCS_YCbCr;
1070 if (jpeg_info.out_color_space == JCS_CMYK)
1071 image->colorspace=CMYKColorspace;
1073 Set image resolution.
1076 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1077 (jpeg_info.Y_density != 1))
1079 image->resolution.x=(double) jpeg_info.X_density;
1080 image->resolution.y=(double) jpeg_info.Y_density;
1081 units=(size_t) jpeg_info.density_unit;
1084 image->units=PixelsPerInchResolution;
1086 image->units=PixelsPerCentimeterResolution;
1087 number_pixels=(MagickSizeType) image->columns*image->rows;
1088 option=GetImageOption(image_info,"jpeg:size");
1089 if (option != (const char *) NULL)
1103 flags=ParseGeometry(option,&geometry_info);
1104 if ((flags & SigmaValue) == 0)
1105 geometry_info.sigma=geometry_info.rho;
1106 jpeg_calc_output_dimensions(&jpeg_info);
1107 image->magick_columns=jpeg_info.output_width;
1108 image->magick_rows=jpeg_info.output_height;
1110 if (geometry_info.rho != 0.0)
1111 scale_factor=jpeg_info.output_width/geometry_info.rho;
1112 if ((geometry_info.sigma != 0.0) &&
1113 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1114 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1115 jpeg_info.scale_num=1U;
1116 jpeg_info.scale_denom=(unsigned int) scale_factor;
1117 jpeg_calc_output_dimensions(&jpeg_info);
1118 if (image->debug != MagickFalse)
1119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1120 "Scale factor: %.20g",(double) scale_factor);
1122 precision=(size_t) jpeg_info.data_precision;
1123 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1124 #if defined(D_LOSSLESS_SUPPORTED)
1125 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1126 JPEGInterlace : NoInterlace;
1127 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1128 LosslessJPEGCompression : JPEGCompression;
1129 if (jpeg_info.data_precision > 8)
1130 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1131 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1133 if (jpeg_info.data_precision == 16)
1134 jpeg_info.data_precision=12;
1136 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1138 image->compression=JPEGCompression;
1141 image->compression=JPEGCompression;
1142 image->interlace=JPEGInterlace;
1144 option=GetImageOption(image_info,"jpeg:colors");
1145 if (option != (const char *) NULL)
1148 Let the JPEG library quantize the image.
1150 jpeg_info.quantize_colors=MagickTrue;
1151 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1153 option=GetImageOption(image_info,"jpeg:block-smoothing");
1154 if (option != (const char *) NULL)
1156 jpeg_info.do_block_smoothing=MagickFalse;
1157 if (IsMagickTrue(option) != MagickFalse)
1158 jpeg_info.do_block_smoothing=MagickTrue;
1160 jpeg_info.dct_method=JDCT_FLOAT;
1161 option=GetImageOption(image_info,"jpeg:dct-method");
1162 if (option != (const char *) NULL)
1168 if (LocaleCompare(option,"default") == 0)
1169 jpeg_info.dct_method=JDCT_DEFAULT;
1175 if (LocaleCompare(option,"fastest") == 0)
1176 jpeg_info.dct_method=JDCT_FASTEST;
1177 if (LocaleCompare(option,"float") == 0)
1178 jpeg_info.dct_method=JDCT_FLOAT;
1184 if (LocaleCompare(option,"ifast") == 0)
1185 jpeg_info.dct_method=JDCT_IFAST;
1186 if (LocaleCompare(option,"islow") == 0)
1187 jpeg_info.dct_method=JDCT_ISLOW;
1191 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1192 if (option != (const char *) NULL)
1194 jpeg_info.do_fancy_upsampling=MagickFalse;
1195 if (IsMagickTrue(option) != MagickFalse)
1196 jpeg_info.do_fancy_upsampling=MagickTrue;
1198 (void) jpeg_start_decompress(&jpeg_info);
1199 image->columns=jpeg_info.output_width;
1200 image->rows=jpeg_info.output_height;
1201 image->depth=(size_t) jpeg_info.data_precision;
1202 if (jpeg_info.out_color_space == JCS_YCbCr)
1203 image->colorspace=YCbCrColorspace;
1204 if (jpeg_info.out_color_space == JCS_CMYK)
1205 image->colorspace=CMYKColorspace;
1206 option=GetImageOption(image_info,"jpeg:colors");
1207 if (option != (const char *) NULL)
1208 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1210 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1211 if ((jpeg_info.output_components == 1) &&
1212 (jpeg_info.quantize_colors == MagickFalse))
1217 colors=(size_t) GetQuantumRange(image->depth)+1;
1218 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1219 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1221 if (image->debug != MagickFalse)
1223 if (image->interlace != NoInterlace)
1224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1225 "Interlace: progressive");
1227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1228 "Interlace: nonprogressive");
1229 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1230 (int) jpeg_info.data_precision);
1231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1232 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1234 JPEGSetImageQuality(&jpeg_info,image);
1235 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1236 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1237 jpeg_info.out_color_space);
1238 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1239 if (image_info->ping != MagickFalse)
1241 jpeg_destroy_decompress(&jpeg_info);
1242 (void) CloseBlob(image);
1243 return(GetFirstImageInList(image));
1245 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1246 jpeg_info.output_components*sizeof(JSAMPLE));
1247 if (jpeg_pixels == (JSAMPLE *) NULL)
1248 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1250 Convert JPEG pixels to pixel packets.
1252 if (setjmp(error_manager.error_recovery) != 0)
1254 if (jpeg_pixels != (unsigned char *) NULL)
1255 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1256 jpeg_destroy_decompress(&jpeg_info);
1257 (void) CloseBlob(image);
1258 number_pixels=(MagickSizeType) image->columns*image->rows;
1259 if (number_pixels != 0)
1260 return(GetFirstImageInList(image));
1261 return(DestroyImage(image));
1263 if (jpeg_info.quantize_colors != MagickFalse)
1265 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1266 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1267 for (i=0; i < (ssize_t) image->colors; i++)
1269 image->colormap[i].red=(double) ScaleCharToQuantum(
1270 jpeg_info.colormap[0][i]);
1271 image->colormap[i].green=image->colormap[i].red;
1272 image->colormap[i].blue=image->colormap[i].red;
1273 image->colormap[i].alpha=OpaqueAlpha;
1276 for (i=0; i < (ssize_t) image->colors; i++)
1278 image->colormap[i].red=(double) ScaleCharToQuantum(
1279 jpeg_info.colormap[0][i]);
1280 image->colormap[i].green=(double) ScaleCharToQuantum(
1281 jpeg_info.colormap[1][i]);
1282 image->colormap[i].blue=(double) ScaleCharToQuantum(
1283 jpeg_info.colormap[2][i]);
1284 image->colormap[i].alpha=OpaqueAlpha;
1287 scanline[0]=(JSAMPROW) jpeg_pixels;
1288 for (y=0; y < (ssize_t) image->rows; y++)
1296 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1298 (void) ThrowMagickException(exception,GetMagickModule(),
1299 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1303 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1304 if (q == (Quantum *) NULL)
1306 if (jpeg_info.data_precision > 8)
1308 if (jpeg_info.output_components == 1)
1309 for (x=0; x < (ssize_t) image->columns; x++)
1314 if (precision != 16)
1315 pixel=(size_t) GETJSAMPLE(*p);
1317 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1318 index=ConstrainColormapIndex(image,pixel,exception);
1319 SetPixelIndex(image,index,q);
1320 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1322 q+=GetPixelChannels(image);
1325 if (image->colorspace != CMYKColorspace)
1326 for (x=0; x < (ssize_t) image->columns; x++)
1328 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1329 (GETJSAMPLE(*p++) << 4)),q);
1330 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1331 (GETJSAMPLE(*p++) << 4)),q);
1332 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1333 (GETJSAMPLE(*p++) << 4)),q);
1334 SetPixelAlpha(image,OpaqueAlpha,q);
1335 q+=GetPixelChannels(image);
1338 for (x=0; x < (ssize_t) image->columns; x++)
1340 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1341 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1342 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1343 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1344 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1345 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1346 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1347 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1348 SetPixelAlpha(image,OpaqueAlpha,q);
1349 q+=GetPixelChannels(image);
1353 if (jpeg_info.output_components == 1)
1354 for (x=0; x < (ssize_t) image->columns; x++)
1356 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1357 SetPixelIndex(image,index,q);
1358 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1360 q+=GetPixelChannels(image);
1363 if (image->colorspace != CMYKColorspace)
1364 for (x=0; x < (ssize_t) image->columns; x++)
1366 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1367 GETJSAMPLE(*p++)),q);
1368 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1369 GETJSAMPLE(*p++)),q);
1370 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1371 GETJSAMPLE(*p++)),q);
1372 SetPixelAlpha(image,OpaqueAlpha,q);
1373 q+=GetPixelChannels(image);
1376 for (x=0; x < (ssize_t) image->columns; x++)
1378 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1379 (unsigned char) GETJSAMPLE(*p++)),q);
1380 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1381 (unsigned char) GETJSAMPLE(*p++)),q);
1382 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1383 (unsigned char) GETJSAMPLE(*p++)),q);
1384 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1385 (unsigned char) GETJSAMPLE(*p++)),q);
1386 SetPixelAlpha(image,OpaqueAlpha,q);
1387 q+=GetPixelChannels(image);
1389 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1391 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1393 if (status == MagickFalse)
1395 jpeg_abort_decompress(&jpeg_info);
1399 if (status != MagickFalse)
1401 error_manager.finished=MagickTrue;
1402 if (setjmp(error_manager.error_recovery) == 0)
1403 (void) jpeg_finish_decompress(&jpeg_info);
1406 Free jpeg resources.
1408 jpeg_destroy_decompress(&jpeg_info);
1409 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1410 (void) CloseBlob(image);
1411 return(GetFirstImageInList(image));
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 % R e g i s t e r J P E G I m a g e %
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 % RegisterJPEGImage() adds properties for the JPEG image format to
1427 % the list of supported formats. The properties include the image format
1428 % tag, a method to read and/or write the format, whether the format
1429 % supports the saving of more than one frame to the same file or blob,
1430 % whether the format supports native in-memory I/O, and a brief
1431 % description of the format.
1433 % The format of the RegisterJPEGImage method is:
1435 % size_t RegisterJPEGImage(void)
1438 ModuleExport size_t RegisterJPEGImage(void)
1441 version[MaxTextExtent];
1447 description[] = "Joint Photographic Experts Group JFIF format";
1450 #if defined(JPEG_LIB_VERSION)
1451 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1453 entry=SetMagickInfo("JPEG");
1454 entry->thread_support=NoThreadSupport;
1455 #if defined(MAGICKCORE_JPEG_DELEGATE)
1456 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1457 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1459 entry->magick=(IsImageFormatHandler *) IsJPEG;
1460 entry->adjoin=MagickFalse;
1461 entry->description=ConstantString(description);
1462 if (*version != '\0')
1463 entry->version=ConstantString(version);
1464 entry->module=ConstantString("JPEG");
1465 (void) RegisterMagickInfo(entry);
1466 entry=SetMagickInfo("JPG");
1467 entry->thread_support=NoThreadSupport;
1468 #if defined(MAGICKCORE_JPEG_DELEGATE)
1469 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1470 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1472 entry->adjoin=MagickFalse;
1473 entry->description=ConstantString(description);
1474 if (*version != '\0')
1475 entry->version=ConstantString(version);
1476 entry->module=ConstantString("JPEG");
1477 (void) RegisterMagickInfo(entry);
1478 entry=SetMagickInfo("PJPEG");
1479 entry->thread_support=NoThreadSupport;
1480 #if defined(MAGICKCORE_JPEG_DELEGATE)
1481 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1482 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1484 entry->adjoin=MagickFalse;
1485 entry->description=ConstantString(description);
1486 if (*version != '\0')
1487 entry->version=ConstantString(version);
1488 entry->module=ConstantString("JPEG");
1489 (void) RegisterMagickInfo(entry);
1490 return(MagickImageCoderSignature);
1494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1498 % U n r e g i s t e r J P E G I m a g e %
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1504 % UnregisterJPEGImage() removes format registrations made by the
1505 % JPEG module from the list of supported formats.
1507 % The format of the UnregisterJPEGImage method is:
1509 % UnregisterJPEGImage(void)
1512 ModuleExport void UnregisterJPEGImage(void)
1514 (void) UnregisterMagickInfo("PJPG");
1515 (void) UnregisterMagickInfo("JPEG");
1516 (void) UnregisterMagickInfo("JPG");
1519 #if defined(MAGICKCORE_JPEG_DELEGATE)
1521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1525 % W r i t e J P E G I m a g e %
1529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531 % WriteJPEGImage() writes a JPEG image file and returns it. It
1532 % allocates the memory necessary for the new Image structure and returns a
1533 % pointer to the new image.
1535 % The format of the WriteJPEGImage method is:
1537 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1538 % Image *image,ExceptionInfo *exception)
1540 % A description of each parameter follows:
1542 % o image_info: the image info.
1544 % o jpeg_image: The image.
1546 % o exception: return any errors or warnings in this structure.
1550 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1552 assert(table != (QuantizationTable *) NULL);
1553 if (table->slot != (char *) NULL)
1554 table->slot=DestroyString(table->slot);
1555 if (table->description != (char *) NULL)
1556 table->description=DestroyString(table->description);
1557 if (table->levels != (unsigned int *) NULL)
1558 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1559 table=(QuantizationTable *) RelinquishMagickMemory(table);
1563 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1568 destination=(DestinationManager *) cinfo->dest;
1569 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1570 MaxBufferExtent,destination->buffer);
1571 if (destination->manager.free_in_buffer != MaxBufferExtent)
1572 ERREXIT(cinfo,JERR_FILE_WRITE);
1573 destination->manager.next_output_byte=destination->buffer;
1577 static QuantizationTable *GetQuantizationTable(const char *filename,
1578 const char *slot,ExceptionInfo *exception)
1603 *quantization_tables,
1606 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1607 "Loading quantization tables \"%s\" ...",filename);
1608 table=(QuantizationTable *) NULL;
1609 xml=FileToString(filename,~0,exception);
1610 if (xml == (char *) NULL)
1612 quantization_tables=NewXMLTree(xml,exception);
1613 if (quantization_tables == (XMLTreeInfo *) NULL)
1615 xml=DestroyString(xml);
1618 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1619 table_iterator != (XMLTreeInfo *) NULL;
1620 table_iterator=GetNextXMLTreeTag(table_iterator))
1622 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1623 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1625 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1626 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1629 if (table_iterator == (XMLTreeInfo *) NULL)
1631 xml=DestroyString(xml);
1634 description=GetXMLTreeChild(table_iterator,"description");
1635 if (description == (XMLTreeInfo *) NULL)
1637 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1638 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1639 quantization_tables=DestroyXMLTree(quantization_tables);
1640 xml=DestroyString(xml);
1643 levels=GetXMLTreeChild(table_iterator,"levels");
1644 if (levels == (XMLTreeInfo *) NULL)
1646 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1647 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1648 quantization_tables=DestroyXMLTree(quantization_tables);
1649 xml=DestroyString(xml);
1652 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1653 if (table == (QuantizationTable *) NULL)
1654 ThrowFatalException(ResourceLimitFatalError,
1655 "UnableToAcquireQuantizationTable");
1656 table->slot=(char *) NULL;
1657 table->description=(char *) NULL;
1658 table->levels=(unsigned int *) NULL;
1659 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1660 if (attribute != (char *) NULL)
1661 table->slot=ConstantString(attribute);
1662 content=GetXMLTreeContent(description);
1663 if (content != (char *) NULL)
1664 table->description=ConstantString(content);
1665 attribute=GetXMLTreeAttribute(levels,"width");
1666 if (attribute == (char *) NULL)
1668 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1669 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1670 quantization_tables=DestroyXMLTree(quantization_tables);
1671 table=DestroyQuantizationTable(table);
1672 xml=DestroyString(xml);
1675 table->width=StringToUnsignedLong(attribute);
1676 if (table->width == 0)
1678 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1679 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1680 quantization_tables=DestroyXMLTree(quantization_tables);
1681 table=DestroyQuantizationTable(table);
1682 xml=DestroyString(xml);
1685 attribute=GetXMLTreeAttribute(levels,"height");
1686 if (attribute == (char *) NULL)
1688 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1689 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1690 quantization_tables=DestroyXMLTree(quantization_tables);
1691 table=DestroyQuantizationTable(table);
1692 xml=DestroyString(xml);
1695 table->height=StringToUnsignedLong(attribute);
1696 if (table->height == 0)
1698 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1699 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1700 quantization_tables=DestroyXMLTree(quantization_tables);
1701 table=DestroyQuantizationTable(table);
1702 xml=DestroyString(xml);
1705 attribute=GetXMLTreeAttribute(levels,"divisor");
1706 if (attribute == (char *) NULL)
1708 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1709 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1710 quantization_tables=DestroyXMLTree(quantization_tables);
1711 table=DestroyQuantizationTable(table);
1712 xml=DestroyString(xml);
1715 table->divisor=(unsigned int) StringToLong(attribute);
1716 if (table->divisor < 1)
1718 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1719 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1720 quantization_tables=DestroyXMLTree(quantization_tables);
1721 table=DestroyQuantizationTable(table);
1722 xml=DestroyString(xml);
1725 content=GetXMLTreeContent(levels);
1726 if (content == (char *) NULL)
1728 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1729 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1730 quantization_tables=DestroyXMLTree(quantization_tables);
1731 table=DestroyQuantizationTable(table);
1732 xml=DestroyString(xml);
1735 table->levels=(unsigned int *) AcquireQuantumMemory((size_t) table->width,
1736 table->height*sizeof(*table->levels));
1737 if (table->levels == (unsigned int *) NULL)
1738 ThrowFatalException(ResourceLimitFatalError,
1739 "UnableToAcquireQuantizationTable");
1740 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1742 table->levels[i]=(unsigned int) strtol(content,&p,10);
1743 if (table->divisor != 1)
1744 table->levels[i]/=table->divisor;
1745 while (isspace((int) ((unsigned char) *p)) != 0)
1751 for (j=i; i < 64; i++)
1752 table->levels[j]=table->levels[j-1];
1753 value=(double) strtol(content,&p,10);
1757 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1758 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1759 quantization_tables=DestroyXMLTree(quantization_tables);
1760 table=DestroyQuantizationTable(table);
1761 xml=DestroyString(xml);
1764 quantization_tables=DestroyXMLTree(quantization_tables);
1765 xml=DestroyString(xml);
1769 static void InitializeDestination(j_compress_ptr cinfo)
1774 destination=(DestinationManager *) cinfo->dest;
1775 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1776 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1777 destination->manager.next_output_byte=destination->buffer;
1778 destination->manager.free_in_buffer=MaxBufferExtent;
1781 static inline size_t MagickMin(const size_t x,const size_t y)
1788 static void TerminateDestination(j_compress_ptr cinfo)
1793 destination=(DestinationManager *) cinfo->dest;
1794 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1799 count=WriteBlob(destination->image,MaxBufferExtent-
1800 destination->manager.free_in_buffer,destination->buffer);
1801 if (count != (ssize_t)
1802 (MaxBufferExtent-destination->manager.free_in_buffer))
1803 ERREXIT(cinfo,JERR_FILE_WRITE);
1807 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1829 Save image profile as a APP marker.
1832 custom_profile=AcquireStringInfo(65535L);
1833 ResetImageProfileIterator(image);
1834 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1836 register unsigned char
1839 profile=GetImageProfile(image,name);
1840 p=GetStringInfoDatum(custom_profile);
1841 if (LocaleCompare(name,"EXIF") == 0)
1842 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1844 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1845 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1846 (unsigned int) length);
1848 if (LocaleCompare(name,"ICC") == 0)
1850 register unsigned char
1854 p=GetStringInfoDatum(custom_profile);
1855 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1856 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1858 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1859 p[12]=(unsigned char) ((i/65519L)+1);
1860 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1861 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1863 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1864 custom_profile),(unsigned int) (length+tag_length));
1867 if (((LocaleCompare(name,"IPTC") == 0) ||
1868 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1874 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1876 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1877 roundup=(size_t) (length & 0x01);
1878 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1880 (void) memcpy(p,"Photoshop 3.0 ",14);
1885 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1887 p[24]=(unsigned char) (length >> 8);
1888 p[25]=(unsigned char) (length & 0xff);
1891 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1893 p[length+tag_length]='\0';
1894 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1895 custom_profile),(unsigned int) (length+tag_length+roundup));
1898 if (LocaleCompare(name,"XMP") == 0)
1904 Add namespace to XMP profile.
1906 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1907 ConcatenateStringInfo(xmp_profile,profile);
1908 GetStringInfoDatum(xmp_profile)[28]='\0';
1909 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1911 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1912 jpeg_write_marker(jpeg_info,XML_MARKER,
1913 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1915 xmp_profile=DestroyStringInfo(xmp_profile);
1917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1918 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1919 name=GetNextImageProfile(image);
1921 custom_profile=DestroyStringInfo(custom_profile);
1924 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1929 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1930 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1931 destination=(DestinationManager *) cinfo->dest;
1932 destination->manager.init_destination=InitializeDestination;
1933 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1934 destination->manager.term_destination=TerminateDestination;
1935 destination->image=image;
1938 static char **SamplingFactorToList(const char *text)
1955 if (text == (char *) NULL)
1956 return((char **) NULL);
1958 Convert string to an ASCII list.
1961 for (p=text; *p != '\0'; p++)
1964 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1966 if (textlist == (char **) NULL)
1967 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1969 for (i=0; i < (ssize_t) lines; i++)
1971 for (q=(char *) p; *q != '\0'; q++)
1974 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1975 sizeof(*textlist[i]));
1976 if (textlist[i] == (char *) NULL)
1977 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1978 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1983 textlist[i]=(char *) NULL;
1987 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1988 Image *image,ExceptionInfo *exception)
2019 struct jpeg_compress_struct
2022 struct jpeg_error_mgr
2028 assert(image_info != (const ImageInfo *) NULL);
2029 assert(image_info->signature == MagickSignature);
2030 assert(image != (Image *) NULL);
2031 assert(image->signature == MagickSignature);
2032 if (image->debug != MagickFalse)
2033 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2034 assert(exception != (ExceptionInfo *) NULL);
2035 assert(exception->signature == MagickSignature);
2036 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2037 if (status == MagickFalse)
2040 Initialize JPEG parameters.
2042 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2043 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2044 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2045 jpeg_info.client_data=(void *) image;
2046 jpeg_info.err=jpeg_std_error(&jpeg_error);
2047 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2048 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2049 error_manager.exception=exception;
2050 error_manager.image=image;
2051 jpeg_pixels=(JSAMPLE *) NULL;
2052 if (setjmp(error_manager.error_recovery) != 0)
2054 jpeg_destroy_compress(&jpeg_info);
2055 (void) CloseBlob(image);
2056 return(MagickFalse);
2058 jpeg_info.client_data=(void *) &error_manager;
2059 jpeg_create_compress(&jpeg_info);
2060 JPEGDestinationManager(&jpeg_info,image);
2061 if ((image->columns != (unsigned int) image->columns) ||
2062 (image->rows != (unsigned int) image->rows))
2063 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2064 jpeg_info.image_width=(unsigned int) image->columns;
2065 jpeg_info.image_height=(unsigned int) image->rows;
2066 jpeg_info.input_components=3;
2067 jpeg_info.data_precision=8;
2068 jpeg_info.in_color_space=JCS_RGB;
2069 switch (image->colorspace)
2071 case CMYKColorspace:
2073 jpeg_info.input_components=4;
2074 jpeg_info.in_color_space=JCS_CMYK;
2077 case YCbCrColorspace:
2078 case Rec601YCbCrColorspace:
2079 case Rec709YCbCrColorspace:
2081 jpeg_info.in_color_space=JCS_YCbCr;
2084 case GRAYColorspace:
2085 case Rec601LumaColorspace:
2086 case Rec709LumaColorspace:
2088 jpeg_info.input_components=1;
2089 jpeg_info.in_color_space=JCS_GRAYSCALE;
2094 if (IsRGBColorspace(image->colorspace) == MagickFalse)
2095 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2099 if ((image_info->type != TrueColorType) &&
2100 (IsImageGray(image,exception) != MagickFalse))
2102 jpeg_info.input_components=1;
2103 jpeg_info.in_color_space=JCS_GRAYSCALE;
2105 jpeg_set_defaults(&jpeg_info);
2106 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2107 jpeg_info.data_precision=8;
2109 if (sizeof(JSAMPLE) > 1)
2110 jpeg_info.data_precision=12;
2111 jpeg_info.density_unit=(UINT8) 1;
2112 if (image->debug != MagickFalse)
2113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2114 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2115 floor(image->resolution.y+0.5));
2116 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2119 Set image resolution.
2121 jpeg_info.write_JFIF_header=MagickTrue;
2122 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2123 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2124 if (image->units == PixelsPerInchResolution)
2125 jpeg_info.density_unit=(UINT8) 1;
2126 if (image->units == PixelsPerCentimeterResolution)
2127 jpeg_info.density_unit=(UINT8) 2;
2129 jpeg_info.dct_method=JDCT_FLOAT;
2130 option=GetImageOption(image_info,"jpeg:dct-method");
2131 if (option != (const char *) NULL)
2137 if (LocaleCompare(option,"default") == 0)
2138 jpeg_info.dct_method=JDCT_DEFAULT;
2144 if (LocaleCompare(option,"fastest") == 0)
2145 jpeg_info.dct_method=JDCT_FASTEST;
2146 if (LocaleCompare(option,"float") == 0)
2147 jpeg_info.dct_method=JDCT_FLOAT;
2153 if (LocaleCompare(option,"ifast") == 0)
2154 jpeg_info.dct_method=JDCT_IFAST;
2155 if (LocaleCompare(option,"islow") == 0)
2156 jpeg_info.dct_method=JDCT_ISLOW;
2160 option=GetImageOption(image_info,"jpeg:optimize-coding");
2161 if (option != (const char *) NULL)
2163 jpeg_info.optimize_coding=MagickFalse;
2164 if (IsMagickTrue(option) != MagickFalse)
2165 jpeg_info.optimize_coding=MagickTrue;
2172 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2173 image->rows*sizeof(JSAMPLE);
2174 if (length == (MagickSizeType) ((size_t) length))
2177 Perform optimization only if available memory resources permit it.
2179 status=AcquireMagickResource(MemoryResource,length);
2180 if (status != MagickFalse)
2181 jpeg_info.optimize_coding=MagickTrue;
2182 RelinquishMagickResource(MemoryResource,length);
2185 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2186 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2187 (image_info->interlace != NoInterlace))
2189 if (image->debug != MagickFalse)
2190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2191 "Interlace: progressive");
2192 jpeg_simple_progression(&jpeg_info);
2195 if (image->debug != MagickFalse)
2196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2197 "Interlace: non-progressive");
2199 if (image->debug != MagickFalse)
2200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2201 "Interlace: nonprogressive");
2203 option=GetImageOption(image_info,"jpeg:extent");
2204 if (option != (const char *) NULL)
2212 jpeg_info=CloneImageInfo(image_info);
2213 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2214 if (jpeg_image != (Image *) NULL)
2224 Search for compression quality that does not exceed image extent.
2226 jpeg_info->quality=0;
2227 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2228 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2229 (void) AcquireUniqueFilename(jpeg_image->filename);
2231 for (minimum=0; minimum != maximum; )
2233 jpeg_image->quality=minimum+(maximum-minimum)/2;
2234 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2235 if (GetBlobSize(jpeg_image) <= extent)
2236 minimum=jpeg_image->quality+1;
2238 maximum=jpeg_image->quality-1;
2240 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2241 image->quality=minimum-1;
2242 jpeg_image=DestroyImage(jpeg_image);
2244 jpeg_info=DestroyImageInfo(jpeg_info);
2247 if ((image_info->compression != LosslessJPEGCompression) &&
2248 (image->quality <= 100))
2250 if (image->quality != UndefinedCompressionQuality)
2251 quality=(int) image->quality;
2252 if (image->debug != MagickFalse)
2253 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2254 (double) image->quality);
2258 #if !defined(C_LOSSLESS_SUPPORTED)
2260 if (image->debug != MagickFalse)
2261 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2263 if (image->quality < 100)
2264 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2265 "LosslessToLossyJPEGConversion",image->filename);
2272 predictor=image->quality/100; /* range 1-7 */
2273 point_transform=image->quality % 20; /* range 0-15 */
2274 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2275 if (image->debug != MagickFalse)
2277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2278 "Compression: lossless");
2279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2280 "Predictor: %d",predictor);
2281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2282 "Point Transform: %d",point_transform);
2287 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2288 sampling_factor=(const char *) NULL;
2289 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2290 if (value != (char *) NULL)
2292 sampling_factor=value;
2293 if (image->debug != MagickFalse)
2294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2295 " Input sampling-factors=%s",sampling_factor);
2297 if (image_info->sampling_factor != (char *) NULL)
2298 sampling_factor=image_info->sampling_factor;
2299 if (sampling_factor == (const char *) NULL)
2301 if (image->quality >= 90)
2302 for (i=0; i < MAX_COMPONENTS; i++)
2304 jpeg_info.comp_info[i].h_samp_factor=1;
2305 jpeg_info.comp_info[i].v_samp_factor=1;
2320 Set sampling factor.
2323 factors=SamplingFactorToList(sampling_factor);
2324 if (factors != (char **) NULL)
2326 for (i=0; i < MAX_COMPONENTS; i++)
2328 if (factors[i] == (char *) NULL)
2330 flags=ParseGeometry(factors[i],&geometry_info);
2331 if ((flags & SigmaValue) == 0)
2332 geometry_info.sigma=geometry_info.rho;
2333 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2334 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2335 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2337 factors=(char **) RelinquishMagickMemory(factors);
2339 for ( ; i < MAX_COMPONENTS; i++)
2341 jpeg_info.comp_info[i].h_samp_factor=1;
2342 jpeg_info.comp_info[i].v_samp_factor=1;
2345 if (jpeg_info.input_components == 1)
2346 for (i=0; i < MAX_COMPONENTS; i++)
2348 jpeg_info.comp_info[i].h_samp_factor=1;
2349 jpeg_info.comp_info[i].v_samp_factor=1;
2351 option=GetImageOption(image_info,"jpeg:q-table");
2352 if (option != (const char *) NULL)
2358 Custom quantization tables.
2360 table=GetQuantizationTable(option,"0",exception);
2361 if (table != (QuantizationTable *) NULL)
2363 jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2365 table=DestroyQuantizationTable(table);
2367 table=GetQuantizationTable(option,"1",exception);
2368 if (table != (QuantizationTable *) NULL)
2370 jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2372 table=DestroyQuantizationTable(table);
2374 table=GetQuantizationTable(option,"2",exception);
2375 if (table != (QuantizationTable *) NULL)
2377 jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2379 table=DestroyQuantizationTable(table);
2381 table=GetQuantizationTable(option,"3",exception);
2382 if (table != (QuantizationTable *) NULL)
2384 jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2386 table=DestroyQuantizationTable(table);
2389 jpeg_start_compress(&jpeg_info,MagickTrue);
2390 if (image->debug != MagickFalse)
2392 if (image->storage_class == PseudoClass)
2393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2394 "Storage class: PseudoClass");
2396 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2397 "Storage class: DirectClass");
2398 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2399 (double) image->depth);
2400 if (image->colors != 0)
2401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2402 "Number of colors: %.20g",(double) image->colors);
2404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2405 "Number of colors: unspecified");
2406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2407 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2408 switch (image->colorspace)
2410 case CMYKColorspace:
2412 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2413 "Storage class: DirectClass");
2414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2415 "Colorspace: CMYK");
2418 case YCbCrColorspace:
2419 case Rec601YCbCrColorspace:
2420 case Rec709YCbCrColorspace:
2422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2423 "Colorspace: YCbCr");
2429 switch (image->colorspace)
2431 case CMYKColorspace:
2433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2434 "Colorspace: CMYK");
2435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2436 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2437 jpeg_info.comp_info[0].h_samp_factor,
2438 jpeg_info.comp_info[0].v_samp_factor,
2439 jpeg_info.comp_info[1].h_samp_factor,
2440 jpeg_info.comp_info[1].v_samp_factor,
2441 jpeg_info.comp_info[2].h_samp_factor,
2442 jpeg_info.comp_info[2].v_samp_factor,
2443 jpeg_info.comp_info[3].h_samp_factor,
2444 jpeg_info.comp_info[3].v_samp_factor);
2447 case GRAYColorspace:
2448 case Rec601LumaColorspace:
2449 case Rec709LumaColorspace:
2451 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2452 "Colorspace: GRAY");
2453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2454 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2455 jpeg_info.comp_info[0].v_samp_factor);
2460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2461 "Image colorspace is RGB");
2462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2463 "Sampling factors: %dx%d,%dx%d,%dx%d",
2464 jpeg_info.comp_info[0].h_samp_factor,
2465 jpeg_info.comp_info[0].v_samp_factor,
2466 jpeg_info.comp_info[1].h_samp_factor,
2467 jpeg_info.comp_info[1].v_samp_factor,
2468 jpeg_info.comp_info[2].h_samp_factor,
2469 jpeg_info.comp_info[2].v_samp_factor);
2472 case YCbCrColorspace:
2473 case Rec601YCbCrColorspace:
2474 case Rec709YCbCrColorspace:
2476 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2477 "Colorspace: YCbCr");
2478 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2479 "Sampling factors: %dx%d,%dx%d,%dx%d",
2480 jpeg_info.comp_info[0].h_samp_factor,
2481 jpeg_info.comp_info[0].v_samp_factor,
2482 jpeg_info.comp_info[1].h_samp_factor,
2483 jpeg_info.comp_info[1].v_samp_factor,
2484 jpeg_info.comp_info[2].h_samp_factor,
2485 jpeg_info.comp_info[2].v_samp_factor);
2490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2493 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2494 jpeg_info.comp_info[0].h_samp_factor,
2495 jpeg_info.comp_info[0].v_samp_factor,
2496 jpeg_info.comp_info[1].h_samp_factor,
2497 jpeg_info.comp_info[1].v_samp_factor,
2498 jpeg_info.comp_info[2].h_samp_factor,
2499 jpeg_info.comp_info[2].v_samp_factor,
2500 jpeg_info.comp_info[3].h_samp_factor,
2501 jpeg_info.comp_info[3].v_samp_factor);
2507 Write JPEG profiles.
2509 value=GetImageProperty(image,"comment",exception);
2510 if (value != (char *) NULL)
2511 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2512 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2513 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2514 if (image->profiles != (void *) NULL)
2515 WriteProfile(&jpeg_info,image);
2517 Convert MIFF to JPEG raster pixels.
2519 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2520 jpeg_info.input_components*sizeof(*jpeg_pixels));
2521 if (jpeg_pixels == (JSAMPLE *) NULL)
2522 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2523 if (setjmp(error_manager.error_recovery) != 0)
2525 jpeg_destroy_compress(&jpeg_info);
2526 if (jpeg_pixels != (unsigned char *) NULL)
2527 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2528 (void) CloseBlob(image);
2529 return(MagickFalse);
2531 scanline[0]=(JSAMPROW) jpeg_pixels;
2532 if (jpeg_info.data_precision <= 8)
2534 if ((jpeg_info.in_color_space == JCS_RGB) ||
2535 (jpeg_info.in_color_space == JCS_YCbCr))
2536 for (y=0; y < (ssize_t) image->rows; y++)
2538 register const Quantum
2544 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2545 if (p == (const Quantum *) NULL)
2548 for (x=0; x < (ssize_t) image->columns; x++)
2550 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2551 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2552 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2553 p+=GetPixelChannels(image);
2555 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2556 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2558 if (status == MagickFalse)
2562 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2563 for (y=0; y < (ssize_t) image->rows; y++)
2565 register const Quantum
2571 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2572 if (p == (const Quantum *) NULL)
2575 for (x=0; x < (ssize_t) image->columns; x++)
2577 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2578 p+=GetPixelChannels(image);
2580 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2581 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2583 if (status == MagickFalse)
2587 for (y=0; y < (ssize_t) image->rows; y++)
2589 register const Quantum
2595 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2596 if (p == (const Quantum *) NULL)
2599 for (x=0; x < (ssize_t) image->columns; x++)
2602 Convert DirectClass packets to contiguous CMYK scanlines.
2604 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2605 GetPixelRed(image,p))));
2606 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2607 GetPixelGreen(image,p))));
2608 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2609 GetPixelBlue(image,p))));
2610 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2611 GetPixelBlack(image,p))));
2612 p+=GetPixelChannels(image);
2614 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2615 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2617 if (status == MagickFalse)
2622 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2623 for (y=0; y < (ssize_t) image->rows; y++)
2625 register const Quantum
2631 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2632 if (p == (const Quantum *) NULL)
2635 for (x=0; x < (ssize_t) image->columns; x++)
2637 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2639 p+=GetPixelChannels(image);
2641 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2642 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2644 if (status == MagickFalse)
2648 if ((jpeg_info.in_color_space == JCS_RGB) ||
2649 (jpeg_info.in_color_space == JCS_YCbCr))
2650 for (y=0; y < (ssize_t) image->rows; y++)
2652 register const Quantum
2658 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2659 if (p == (const Quantum *) NULL)
2662 for (x=0; x < (ssize_t) image->columns; x++)
2664 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2665 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2666 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2667 p+=GetPixelChannels(image);
2669 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2670 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2672 if (status == MagickFalse)
2676 for (y=0; y < (ssize_t) image->rows; y++)
2678 register const Quantum
2684 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2685 if (p == (const Quantum *) NULL)
2688 for (x=0; x < (ssize_t) image->columns; x++)
2691 Convert DirectClass packets to contiguous CMYK scanlines.
2693 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2694 GetPixelRed(image,p)) >> 4));
2695 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2696 GetPixelGreen(image,p)) >> 4));
2697 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2698 GetPixelBlue(image,p)) >> 4));
2699 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2700 GetPixelBlack(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)
2709 if (y == (ssize_t) image->rows)
2710 jpeg_finish_compress(&jpeg_info);
2712 Relinquish resources.
2714 jpeg_destroy_compress(&jpeg_info);
2715 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2716 (void) CloseBlob(image);