2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
46 #include "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/token.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/xml-tree.h"
83 #include "MagickCore/xml-tree-private.h"
85 #if defined(MAGICKCORE_JPEG_DELEGATE)
86 #define JPEG_INTERNAL_OPTIONS
87 #if defined(__MINGW32__)
88 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
89 typedef unsigned char boolean;
100 #define ICC_MARKER (JPEG_APP0+2)
101 #define ICC_PROFILE "ICC_PROFILE"
102 #define IPTC_MARKER (JPEG_APP0+13)
103 #define XML_MARKER (JPEG_APP0+1)
104 #define MaxBufferExtent 8192
107 Typedef declarations.
109 #if defined(MAGICKCORE_JPEG_DELEGATE)
110 typedef struct _DestinationManager
112 struct jpeg_destination_mgr
120 } DestinationManager;
122 typedef struct _ErrorManager
137 typedef struct _SourceManager
139 struct jpeg_source_mgr
153 typedef struct _QuantizationTable
171 Forward declarations.
173 #if defined(MAGICKCORE_JPEG_DELEGATE)
174 static MagickBooleanType
175 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 % IsJPEG() returns MagickTrue if the image format type, identified by the
190 % magick string, is JPEG.
192 % The format of the IsJPEG method is:
194 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
196 % A description of each parameter follows:
198 % o magick: compare image format pattern against these bytes.
200 % o length: Specifies the length of the magick string.
203 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
207 if (memcmp(magick,"\377\330\377",3) == 0)
212 #if defined(MAGICKCORE_JPEG_DELEGATE)
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218 % R e a d J P E G I m a g e %
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
225 % the memory necessary for the new Image structure and returns a pointer to
228 % The format of the ReadJPEGImage method is:
230 % Image *ReadJPEGImage(const ImageInfo *image_info,
231 % ExceptionInfo *exception)
233 % A description of each parameter follows:
235 % o image_info: the image info.
237 % o exception: return any errors or warnings in this structure.
241 static boolean FillInputBuffer(j_decompress_ptr cinfo)
246 source=(SourceManager *) cinfo->src;
247 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
248 MaxBufferExtent,source->buffer);
249 if (source->manager.bytes_in_buffer == 0)
251 if (source->start_of_blob != 0)
252 ERREXIT(cinfo,JERR_INPUT_EMPTY);
253 WARNMS(cinfo,JWRN_JPEG_EOF);
254 source->buffer[0]=(JOCTET) 0xff;
255 source->buffer[1]=(JOCTET) JPEG_EOI;
256 source->manager.bytes_in_buffer=2;
258 source->manager.next_input_byte=source->buffer;
259 source->start_of_blob=FALSE;
263 static int GetCharacter(j_decompress_ptr jpeg_info)
265 if (jpeg_info->src->bytes_in_buffer == 0)
266 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
267 jpeg_info->src->bytes_in_buffer--;
268 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
271 static void InitializeSource(j_decompress_ptr cinfo)
276 source=(SourceManager *) cinfo->src;
277 source->start_of_blob=TRUE;
280 static MagickBooleanType IsITUFaxImage(const Image *image)
288 profile=GetImageProfile(image,"8bim");
289 if (profile == (const StringInfo *) NULL)
291 if (GetStringInfoLength(profile) < 5)
293 datum=GetStringInfoDatum(profile);
294 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
295 (datum[3] == 0x41) && (datum[4] == 0x58))
300 static void JPEGErrorHandler(j_common_ptr jpeg_info)
303 message[JMSG_LENGTH_MAX];
315 error_manager=(ErrorManager *) jpeg_info->client_data;
316 image=error_manager->image;
317 exception=error_manager->exception;
318 (jpeg_info->err->format_message)(jpeg_info,message);
319 if (image->debug != MagickFalse)
320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
321 "[%s] JPEG Trace: \"%s\"",image->filename,message);
322 if (error_manager->finished != MagickFalse)
323 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
324 (char *) message,"`%s'",image->filename);
326 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
327 (char *) message,"`%s'",image->filename);
328 longjmp(error_manager->error_recovery,1);
331 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
333 #define JPEGExcessiveWarnings 1000
336 message[JMSG_LENGTH_MAX];
348 error_manager=(ErrorManager *) jpeg_info->client_data;
349 exception=error_manager->exception;
350 image=error_manager->image;
354 Process warning message.
356 (jpeg_info->err->format_message)(jpeg_info,message);
357 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
358 JPEGErrorHandler(jpeg_info);
359 if ((jpeg_info->err->num_warnings == 0) ||
360 (jpeg_info->err->trace_level >= 3))
361 ThrowBinaryException(CorruptImageWarning,(char *) message,
365 if ((image->debug != MagickFalse) &&
366 (level >= jpeg_info->err->trace_level))
369 Process trace message.
371 (jpeg_info->err->format_message)(jpeg_info,message);
372 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
373 "[%s] JPEG Trace: \"%s\"",image->filename,message);
378 static boolean ReadComment(j_decompress_ptr jpeg_info)
402 Determine length of comment.
404 error_manager=(ErrorManager *) jpeg_info->client_data;
405 exception=error_manager->exception;
406 image=error_manager->image;
407 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
408 length+=GetCharacter(jpeg_info);
412 comment=(char *) NULL;
413 if (~length >= (MaxTextExtent-1))
414 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
416 if (comment == (char *) NULL)
417 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
422 i=(ssize_t) length-1;
423 for (p=comment; i-- >= 0; p++)
424 *p=(char) GetCharacter(jpeg_info);
426 (void) SetImageProperty(image,"comment",comment,exception);
427 comment=DestroyString(comment);
431 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
451 register unsigned char
464 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
465 length+=(size_t) GetCharacter(jpeg_info);
470 (void) GetCharacter(jpeg_info);
473 for (i=0; i < 12; i++)
474 magick[i]=(char) GetCharacter(jpeg_info);
475 if (LocaleCompare(magick,ICC_PROFILE) != 0)
478 Not a ICC profile, return.
480 for (i=0; i < (ssize_t) (length-12); i++)
481 (void) GetCharacter(jpeg_info);
484 (void) GetCharacter(jpeg_info); /* id */
485 (void) GetCharacter(jpeg_info); /* markers */
487 error_manager=(ErrorManager *) jpeg_info->client_data;
488 exception=error_manager->exception;
489 image=error_manager->image;
490 profile=BlobToStringInfo((const void *) NULL,length);
491 if (profile == (StringInfo *) NULL)
492 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
494 p=GetStringInfoDatum(profile);
495 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
496 *p++=(unsigned char) GetCharacter(jpeg_info);
497 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
498 if (icc_profile != (StringInfo *) NULL)
500 ConcatenateStringInfo(icc_profile,profile);
501 profile=DestroyStringInfo(profile);
505 status=SetImageProfile(image,"icc",profile,exception);
506 profile=DestroyStringInfo(profile);
507 if (status == MagickFalse)
508 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
511 if (image->debug != MagickFalse)
512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
513 "Profile: ICC, %.20g bytes",(double) length);
517 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
520 magick[MaxTextExtent];
537 register unsigned char
548 Determine length of binary data stored here.
550 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
551 length+=(size_t) GetCharacter(jpeg_info);
556 (void) GetCharacter(jpeg_info);
560 Validate that this was written as a Photoshop resource format slug.
562 for (i=0; i < 10; i++)
563 magick[i]=(char) GetCharacter(jpeg_info);
568 if (LocaleCompare(magick,"Photoshop ") != 0)
571 Not a IPTC profile, return.
573 for (i=0; i < (ssize_t) length; i++)
574 (void) GetCharacter(jpeg_info);
578 Remove the version number.
580 for (i=0; i < 4; i++)
581 (void) GetCharacter(jpeg_info);
587 error_manager=(ErrorManager *) jpeg_info->client_data;
588 exception=error_manager->exception;
589 image=error_manager->image;
590 profile=BlobToStringInfo((const void *) NULL,length);
591 if (profile == (StringInfo *) NULL)
592 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
594 p=GetStringInfoDatum(profile);
595 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
596 *p++=(unsigned char) GetCharacter(jpeg_info);
597 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
598 if (iptc_profile != (StringInfo *) NULL)
600 ConcatenateStringInfo(iptc_profile,profile);
601 profile=DestroyStringInfo(profile);
605 status=SetImageProfile(image,"8bim",profile,exception);
606 profile=DestroyStringInfo(profile);
607 if (status == MagickFalse)
608 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
611 if (image->debug != MagickFalse)
612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
613 "Profile: iptc, %.20g bytes",(double) length);
617 static boolean ReadProfile(j_decompress_ptr jpeg_info)
643 register unsigned char
653 Read generic profile.
655 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
656 length+=(size_t) GetCharacter(jpeg_info);
660 marker=jpeg_info->unread_marker-JPEG_APP0;
661 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
662 error_manager=(ErrorManager *) jpeg_info->client_data;
663 exception=error_manager->exception;
664 image=error_manager->image;
665 profile=BlobToStringInfo((const void *) NULL,length);
666 if (profile == (StringInfo *) NULL)
667 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
669 p=GetStringInfoDatum(profile);
670 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
671 *p++=(unsigned char) GetCharacter(jpeg_info);
674 p=GetStringInfoDatum(profile);
675 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
676 (void) CopyMagickString(name,"exif",MaxTextExtent);
677 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
683 Extract namespace from XMP profile.
685 p=GetStringInfoDatum(profile);
686 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
692 if (j < (ssize_t) GetStringInfoLength(profile))
693 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
694 (void) CopyMagickString(name,"xmp",MaxTextExtent);
697 previous_profile=GetImageProfile(image,name);
698 if (previous_profile != (const StringInfo *) NULL)
703 length=GetStringInfoLength(profile);
704 SetStringInfoLength(profile,GetStringInfoLength(profile)+
705 GetStringInfoLength(previous_profile));
706 (void) memmove(GetStringInfoDatum(profile)+
707 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
709 (void) memcpy(GetStringInfoDatum(profile),
710 GetStringInfoDatum(previous_profile),
711 GetStringInfoLength(previous_profile));
713 status=SetImageProfile(image,name,profile,exception);
714 profile=DestroyStringInfo(profile);
715 if (status == MagickFalse)
716 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
718 if (image->debug != MagickFalse)
719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
720 "Profile: %s, %.20g bytes",name,(double) length);
724 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
729 if (number_bytes <= 0)
731 source=(SourceManager *) cinfo->src;
732 while (number_bytes > (long) source->manager.bytes_in_buffer)
734 number_bytes-=(long) source->manager.bytes_in_buffer;
735 (void) FillInputBuffer(cinfo);
737 source->manager.next_input_byte+=number_bytes;
738 source->manager.bytes_in_buffer-=number_bytes;
741 static void TerminateSource(j_decompress_ptr cinfo)
746 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
751 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
752 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
753 source=(SourceManager *) cinfo->src;
754 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
755 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
756 source=(SourceManager *) cinfo->src;
757 source->manager.init_source=InitializeSource;
758 source->manager.fill_input_buffer=FillInputBuffer;
759 source->manager.skip_input_data=SkipInputData;
760 source->manager.resync_to_restart=jpeg_resync_to_restart;
761 source->manager.term_source=TerminateSource;
762 source->manager.bytes_in_buffer=0;
763 source->manager.next_input_byte=NULL;
767 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
770 image->quality=UndefinedCompressionQuality;
771 #if defined(D_PROGRESSIVE_SUPPORTED)
772 if (image->compression == LosslessJPEGCompression)
775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776 "Quality: 100 (lossless)");
790 Determine the JPEG compression quality from the quantization tables.
793 for (i=0; i < NUM_QUANT_TBLS; i++)
795 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
796 for (j=0; j < DCTSIZE2; j++)
797 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
799 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
800 (jpeg_info->quant_tbl_ptrs[1] != NULL))
805 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
806 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
807 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
808 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
809 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
810 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
811 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
812 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
813 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
814 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
819 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
820 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
821 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
822 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
823 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
824 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
825 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
826 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
827 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
828 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
829 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
833 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
834 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
835 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
836 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
837 for (i=0; i < 100; i++)
839 if ((qvalue < hash[i]) && (sum < sums[i]))
841 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
842 image->quality=(size_t) i+1;
843 if (image->debug != MagickFalse)
844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
845 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
846 (sum <= sums[i]) ? "exact" : "approximate");
851 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
856 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
857 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
858 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
859 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
860 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
861 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
862 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
863 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
864 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
865 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
870 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
871 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
872 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
873 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
874 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
875 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
876 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
877 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
878 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
879 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
880 667, 592, 518, 441, 369, 292, 221, 151, 86,
884 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
885 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
886 for (i=0; i < 100; i++)
888 if ((qvalue < hash[i]) && (sum < sums[i]))
890 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
891 image->quality=(size_t) i+1;
892 if (image->debug != MagickFalse)
893 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
894 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
895 (sum <= sums[i]) ? "exact" : "approximate");
902 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
905 sampling_factor[MaxTextExtent];
907 switch (jpeg_info->out_color_space)
911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
912 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
913 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
914 jpeg_info->comp_info[0].v_samp_factor,
915 jpeg_info->comp_info[1].h_samp_factor,
916 jpeg_info->comp_info[1].v_samp_factor,
917 jpeg_info->comp_info[2].h_samp_factor,
918 jpeg_info->comp_info[2].v_samp_factor,
919 jpeg_info->comp_info[3].h_samp_factor,
920 jpeg_info->comp_info[3].v_samp_factor);
925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
926 "Colorspace: GRAYSCALE");
927 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
928 jpeg_info->comp_info[0].h_samp_factor,
929 jpeg_info->comp_info[0].v_samp_factor);
934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
935 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
936 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
937 jpeg_info->comp_info[0].v_samp_factor,
938 jpeg_info->comp_info[1].h_samp_factor,
939 jpeg_info->comp_info[1].v_samp_factor,
940 jpeg_info->comp_info[2].h_samp_factor,
941 jpeg_info->comp_info[2].v_samp_factor);
946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
947 jpeg_info->out_color_space);
948 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
949 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
950 jpeg_info->comp_info[0].v_samp_factor,
951 jpeg_info->comp_info[1].h_samp_factor,
952 jpeg_info->comp_info[1].v_samp_factor,
953 jpeg_info->comp_info[2].h_samp_factor,
954 jpeg_info->comp_info[2].v_samp_factor,
955 jpeg_info->comp_info[3].h_samp_factor,
956 jpeg_info->comp_info[3].v_samp_factor);
960 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
966 static Image *ReadJPEGImage(const ImageInfo *image_info,
967 ExceptionInfo *exception)
970 value[MaxTextExtent];
1000 struct jpeg_decompress_struct
1003 struct jpeg_error_mgr
1019 assert(image_info != (const ImageInfo *) NULL);
1020 assert(image_info->signature == MagickSignature);
1021 if (image_info->debug != MagickFalse)
1022 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1023 image_info->filename);
1024 assert(exception != (ExceptionInfo *) NULL);
1025 assert(exception->signature == MagickSignature);
1026 debug=IsEventLogging();
1028 image=AcquireImage(image_info,exception);
1029 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1030 if (status == MagickFalse)
1032 image=DestroyImageList(image);
1033 return((Image *) NULL);
1036 Initialize JPEG parameters.
1038 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1039 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1040 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1041 jpeg_info.err=jpeg_std_error(&jpeg_error);
1042 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1043 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1044 jpeg_pixels=(JSAMPLE *) NULL;
1045 error_manager.exception=exception;
1046 error_manager.image=image;
1047 if (setjmp(error_manager.error_recovery) != 0)
1049 jpeg_destroy_decompress(&jpeg_info);
1050 (void) CloseBlob(image);
1051 number_pixels=(MagickSizeType) image->columns*image->rows;
1052 if (number_pixels != 0)
1053 return(GetFirstImageInList(image));
1054 return(DestroyImage(image));
1056 jpeg_info.client_data=(void *) &error_manager;
1057 jpeg_create_decompress(&jpeg_info);
1058 JPEGSourceManager(&jpeg_info,image);
1059 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1060 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1061 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1062 for (i=1; i < 16; i++)
1063 if ((i != 2) && (i != 13) && (i != 14))
1064 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1065 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1066 if ((image_info->colorspace == YCbCrColorspace) ||
1067 (image_info->colorspace == Rec601YCbCrColorspace) ||
1068 (image_info->colorspace == Rec709YCbCrColorspace))
1069 jpeg_info.out_color_space=JCS_YCbCr;
1070 if (IsITUFaxImage(image) != MagickFalse)
1072 image->colorspace=LabColorspace;
1073 jpeg_info.out_color_space=JCS_YCbCr;
1076 if (jpeg_info.out_color_space == JCS_CMYK)
1077 image->colorspace=CMYKColorspace;
1079 Set image resolution.
1082 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1083 (jpeg_info.Y_density != 1))
1085 image->resolution.x=(double) jpeg_info.X_density;
1086 image->resolution.y=(double) jpeg_info.Y_density;
1087 units=(size_t) jpeg_info.density_unit;
1090 image->units=PixelsPerInchResolution;
1092 image->units=PixelsPerCentimeterResolution;
1093 number_pixels=(MagickSizeType) image->columns*image->rows;
1094 option=GetImageOption(image_info,"jpeg:size");
1095 if (option != (const char *) NULL)
1109 flags=ParseGeometry(option,&geometry_info);
1110 if ((flags & SigmaValue) == 0)
1111 geometry_info.sigma=geometry_info.rho;
1112 jpeg_calc_output_dimensions(&jpeg_info);
1113 image->magick_columns=jpeg_info.output_width;
1114 image->magick_rows=jpeg_info.output_height;
1116 if (geometry_info.rho != 0.0)
1117 scale_factor=jpeg_info.output_width/geometry_info.rho;
1118 if ((geometry_info.sigma != 0.0) &&
1119 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1120 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1121 jpeg_info.scale_num=1U;
1122 jpeg_info.scale_denom=(unsigned int) scale_factor;
1123 jpeg_calc_output_dimensions(&jpeg_info);
1124 if (image->debug != MagickFalse)
1125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1126 "Scale factor: %.20g",(double) scale_factor);
1128 precision=(size_t) jpeg_info.data_precision;
1129 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1130 #if defined(D_LOSSLESS_SUPPORTED)
1131 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1132 JPEGInterlace : NoInterlace;
1133 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1134 LosslessJPEGCompression : JPEGCompression;
1135 if (jpeg_info.data_precision > 8)
1136 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1137 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1139 if (jpeg_info.data_precision == 16)
1140 jpeg_info.data_precision=12;
1142 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1144 image->compression=JPEGCompression;
1147 image->compression=JPEGCompression;
1148 image->interlace=JPEGInterlace;
1150 option=GetImageOption(image_info,"jpeg:colors");
1151 if (option != (const char *) NULL)
1154 Let the JPEG library quantize the image.
1156 jpeg_info.quantize_colors=MagickTrue;
1157 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1159 option=GetImageOption(image_info,"jpeg:block-smoothing");
1160 jpeg_info.do_block_smoothing=IsStringTrue(option);
1161 jpeg_info.dct_method=JDCT_FLOAT;
1162 option=GetImageOption(image_info,"jpeg:dct-method");
1163 if (option != (const char *) NULL)
1169 if (LocaleCompare(option,"default") == 0)
1170 jpeg_info.dct_method=JDCT_DEFAULT;
1176 if (LocaleCompare(option,"fastest") == 0)
1177 jpeg_info.dct_method=JDCT_FASTEST;
1178 if (LocaleCompare(option,"float") == 0)
1179 jpeg_info.dct_method=JDCT_FLOAT;
1185 if (LocaleCompare(option,"ifast") == 0)
1186 jpeg_info.dct_method=JDCT_IFAST;
1187 if (LocaleCompare(option,"islow") == 0)
1188 jpeg_info.dct_method=JDCT_ISLOW;
1192 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1193 jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1194 (void) jpeg_start_decompress(&jpeg_info);
1195 image->columns=jpeg_info.output_width;
1196 image->rows=jpeg_info.output_height;
1197 image->depth=(size_t) jpeg_info.data_precision;
1198 if (jpeg_info.out_color_space == JCS_YCbCr)
1199 image->colorspace=YCbCrColorspace;
1200 if (jpeg_info.out_color_space == JCS_CMYK)
1201 image->colorspace=CMYKColorspace;
1202 option=GetImageOption(image_info,"jpeg:colors");
1203 if (option != (const char *) NULL)
1204 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1206 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1207 if ((jpeg_info.output_components == 1) &&
1208 (jpeg_info.quantize_colors == MagickFalse))
1213 colors=(size_t) GetQuantumRange(image->depth)+1;
1214 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1215 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1217 if (image->debug != MagickFalse)
1219 if (image->interlace != NoInterlace)
1220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1221 "Interlace: progressive");
1223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1224 "Interlace: nonprogressive");
1225 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1226 (int) jpeg_info.data_precision);
1227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1228 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1230 JPEGSetImageQuality(&jpeg_info,image);
1231 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1232 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1233 jpeg_info.out_color_space);
1234 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1235 if (image_info->ping != MagickFalse)
1237 jpeg_destroy_decompress(&jpeg_info);
1238 (void) CloseBlob(image);
1239 return(GetFirstImageInList(image));
1241 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1242 jpeg_info.output_components*sizeof(JSAMPLE));
1243 if (jpeg_pixels == (JSAMPLE *) NULL)
1244 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1246 Convert JPEG pixels to pixel packets.
1248 if (setjmp(error_manager.error_recovery) != 0)
1250 if (jpeg_pixels != (unsigned char *) NULL)
1251 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1252 jpeg_destroy_decompress(&jpeg_info);
1253 (void) CloseBlob(image);
1254 number_pixels=(MagickSizeType) image->columns*image->rows;
1255 if (number_pixels != 0)
1256 return(GetFirstImageInList(image));
1257 return(DestroyImage(image));
1259 if (jpeg_info.quantize_colors != MagickFalse)
1261 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1262 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1263 for (i=0; i < (ssize_t) image->colors; i++)
1265 image->colormap[i].red=(double) ScaleCharToQuantum(
1266 jpeg_info.colormap[0][i]);
1267 image->colormap[i].green=image->colormap[i].red;
1268 image->colormap[i].blue=image->colormap[i].red;
1269 image->colormap[i].alpha=OpaqueAlpha;
1272 for (i=0; i < (ssize_t) image->colors; i++)
1274 image->colormap[i].red=(double) ScaleCharToQuantum(
1275 jpeg_info.colormap[0][i]);
1276 image->colormap[i].green=(double) ScaleCharToQuantum(
1277 jpeg_info.colormap[1][i]);
1278 image->colormap[i].blue=(double) ScaleCharToQuantum(
1279 jpeg_info.colormap[2][i]);
1280 image->colormap[i].alpha=OpaqueAlpha;
1283 scanline[0]=(JSAMPROW) jpeg_pixels;
1284 for (y=0; y < (ssize_t) image->rows; y++)
1292 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1294 (void) ThrowMagickException(exception,GetMagickModule(),
1295 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1299 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1300 if (q == (Quantum *) NULL)
1302 if (jpeg_info.data_precision > 8)
1304 if (jpeg_info.output_components == 1)
1305 for (x=0; x < (ssize_t) image->columns; x++)
1310 if (precision != 16)
1311 pixel=(size_t) GETJSAMPLE(*p);
1313 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1314 index=ConstrainColormapIndex(image,pixel,exception);
1315 SetPixelIndex(image,index,q);
1316 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1318 q+=GetPixelChannels(image);
1321 if (image->colorspace != CMYKColorspace)
1322 for (x=0; x < (ssize_t) image->columns; x++)
1324 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1325 (GETJSAMPLE(*p++) << 4)),q);
1326 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1327 (GETJSAMPLE(*p++) << 4)),q);
1328 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1329 (GETJSAMPLE(*p++) << 4)),q);
1330 SetPixelAlpha(image,OpaqueAlpha,q);
1331 q+=GetPixelChannels(image);
1334 for (x=0; x < (ssize_t) image->columns; x++)
1336 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1337 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1338 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1339 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1340 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1341 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1342 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1343 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1344 SetPixelAlpha(image,OpaqueAlpha,q);
1345 q+=GetPixelChannels(image);
1349 if (jpeg_info.output_components == 1)
1350 for (x=0; x < (ssize_t) image->columns; x++)
1352 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1353 SetPixelIndex(image,index,q);
1354 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1356 q+=GetPixelChannels(image);
1359 if (image->colorspace != CMYKColorspace)
1360 for (x=0; x < (ssize_t) image->columns; x++)
1362 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1363 GETJSAMPLE(*p++)),q);
1364 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1365 GETJSAMPLE(*p++)),q);
1366 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1367 GETJSAMPLE(*p++)),q);
1368 SetPixelAlpha(image,OpaqueAlpha,q);
1369 q+=GetPixelChannels(image);
1372 for (x=0; x < (ssize_t) image->columns; x++)
1374 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1375 (unsigned char) GETJSAMPLE(*p++)),q);
1376 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1377 (unsigned char) GETJSAMPLE(*p++)),q);
1378 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1379 (unsigned char) GETJSAMPLE(*p++)),q);
1380 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1381 (unsigned char) GETJSAMPLE(*p++)),q);
1382 SetPixelAlpha(image,OpaqueAlpha,q);
1383 q+=GetPixelChannels(image);
1385 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1387 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1389 if (status == MagickFalse)
1391 jpeg_abort_decompress(&jpeg_info);
1395 if (status != MagickFalse)
1397 error_manager.finished=MagickTrue;
1398 if (setjmp(error_manager.error_recovery) == 0)
1399 (void) jpeg_finish_decompress(&jpeg_info);
1402 Free jpeg resources.
1404 jpeg_destroy_decompress(&jpeg_info);
1405 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1406 (void) CloseBlob(image);
1407 return(GetFirstImageInList(image));
1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416 % R e g i s t e r J P E G I m a g e %
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 % RegisterJPEGImage() adds properties for the JPEG image format to
1423 % the list of supported formats. The properties include the image format
1424 % tag, a method to read and/or write the format, whether the format
1425 % supports the saving of more than one frame to the same file or blob,
1426 % whether the format supports native in-memory I/O, and a brief
1427 % description of the format.
1429 % The format of the RegisterJPEGImage method is:
1431 % size_t RegisterJPEGImage(void)
1434 ModuleExport size_t RegisterJPEGImage(void)
1437 version[MaxTextExtent];
1443 description[] = "Joint Photographic Experts Group JFIF format";
1446 #if defined(JPEG_LIB_VERSION)
1447 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1449 entry=SetMagickInfo("JPEG");
1450 entry->thread_support=NoThreadSupport;
1451 #if defined(MAGICKCORE_JPEG_DELEGATE)
1452 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1453 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1455 entry->magick=(IsImageFormatHandler *) IsJPEG;
1456 entry->adjoin=MagickFalse;
1457 entry->description=ConstantString(description);
1458 if (*version != '\0')
1459 entry->version=ConstantString(version);
1460 entry->module=ConstantString("JPEG");
1461 (void) RegisterMagickInfo(entry);
1462 entry=SetMagickInfo("JPG");
1463 entry->thread_support=NoThreadSupport;
1464 #if defined(MAGICKCORE_JPEG_DELEGATE)
1465 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1466 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1468 entry->adjoin=MagickFalse;
1469 entry->description=ConstantString(description);
1470 if (*version != '\0')
1471 entry->version=ConstantString(version);
1472 entry->module=ConstantString("JPEG");
1473 (void) RegisterMagickInfo(entry);
1474 entry=SetMagickInfo("PJPEG");
1475 entry->thread_support=NoThreadSupport;
1476 #if defined(MAGICKCORE_JPEG_DELEGATE)
1477 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1478 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1480 entry->adjoin=MagickFalse;
1481 entry->description=ConstantString(description);
1482 if (*version != '\0')
1483 entry->version=ConstantString(version);
1484 entry->module=ConstantString("JPEG");
1485 (void) RegisterMagickInfo(entry);
1486 return(MagickImageCoderSignature);
1490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494 % U n r e g i s t e r J P E G I m a g e %
1498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1500 % UnregisterJPEGImage() removes format registrations made by the
1501 % JPEG module from the list of supported formats.
1503 % The format of the UnregisterJPEGImage method is:
1505 % UnregisterJPEGImage(void)
1508 ModuleExport void UnregisterJPEGImage(void)
1510 (void) UnregisterMagickInfo("PJPG");
1511 (void) UnregisterMagickInfo("JPEG");
1512 (void) UnregisterMagickInfo("JPG");
1515 #if defined(MAGICKCORE_JPEG_DELEGATE)
1517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521 % W r i t e J P E G I m a g e %
1525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527 % WriteJPEGImage() writes a JPEG image file and returns it. It
1528 % allocates the memory necessary for the new Image structure and returns a
1529 % pointer to the new image.
1531 % The format of the WriteJPEGImage method is:
1533 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1534 % Image *image,ExceptionInfo *exception)
1536 % A description of each parameter follows:
1538 % o image_info: the image info.
1540 % o jpeg_image: The image.
1542 % o exception: return any errors or warnings in this structure.
1546 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1548 assert(table != (QuantizationTable *) NULL);
1549 if (table->slot != (char *) NULL)
1550 table->slot=DestroyString(table->slot);
1551 if (table->description != (char *) NULL)
1552 table->description=DestroyString(table->description);
1553 if (table->levels != (unsigned int *) NULL)
1554 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1555 table=(QuantizationTable *) RelinquishMagickMemory(table);
1559 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1564 destination=(DestinationManager *) cinfo->dest;
1565 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1566 MaxBufferExtent,destination->buffer);
1567 if (destination->manager.free_in_buffer != MaxBufferExtent)
1568 ERREXIT(cinfo,JERR_FILE_WRITE);
1569 destination->manager.next_output_byte=destination->buffer;
1573 static QuantizationTable *GetQuantizationTable(const char *filename,
1574 const char *slot,ExceptionInfo *exception)
1602 *quantization_tables,
1605 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1606 "Loading quantization tables \"%s\" ...",filename);
1607 table=(QuantizationTable *) NULL;
1608 xml=FileToString(filename,~0,exception);
1609 if (xml == (char *) NULL)
1611 quantization_tables=NewXMLTree(xml,exception);
1612 if (quantization_tables == (XMLTreeInfo *) NULL)
1614 xml=DestroyString(xml);
1617 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1618 table_iterator != (XMLTreeInfo *) NULL;
1619 table_iterator=GetNextXMLTreeTag(table_iterator))
1621 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1622 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1624 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1625 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1628 if (table_iterator == (XMLTreeInfo *) NULL)
1630 xml=DestroyString(xml);
1633 description=GetXMLTreeChild(table_iterator,"description");
1634 if (description == (XMLTreeInfo *) NULL)
1636 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1637 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1638 quantization_tables=DestroyXMLTree(quantization_tables);
1639 xml=DestroyString(xml);
1642 levels=GetXMLTreeChild(table_iterator,"levels");
1643 if (levels == (XMLTreeInfo *) NULL)
1645 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1646 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1647 quantization_tables=DestroyXMLTree(quantization_tables);
1648 xml=DestroyString(xml);
1651 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1652 if (table == (QuantizationTable *) NULL)
1653 ThrowFatalException(ResourceLimitFatalError,
1654 "UnableToAcquireQuantizationTable");
1655 table->slot=(char *) NULL;
1656 table->description=(char *) NULL;
1657 table->levels=(unsigned int *) NULL;
1658 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1659 if (attribute != (char *) NULL)
1660 table->slot=ConstantString(attribute);
1661 content=GetXMLTreeContent(description);
1662 if (content != (char *) NULL)
1663 table->description=ConstantString(content);
1664 attribute=GetXMLTreeAttribute(levels,"width");
1665 if (attribute == (char *) NULL)
1667 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1668 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1669 quantization_tables=DestroyXMLTree(quantization_tables);
1670 table=DestroyQuantizationTable(table);
1671 xml=DestroyString(xml);
1674 table->width=StringToUnsignedLong(attribute);
1675 if (table->width == 0)
1677 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1678 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1679 quantization_tables=DestroyXMLTree(quantization_tables);
1680 table=DestroyQuantizationTable(table);
1681 xml=DestroyString(xml);
1684 attribute=GetXMLTreeAttribute(levels,"height");
1685 if (attribute == (char *) NULL)
1687 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1688 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1689 quantization_tables=DestroyXMLTree(quantization_tables);
1690 table=DestroyQuantizationTable(table);
1691 xml=DestroyString(xml);
1694 table->height=StringToUnsignedLong(attribute);
1695 if (table->height == 0)
1697 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1698 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1699 quantization_tables=DestroyXMLTree(quantization_tables);
1700 table=DestroyQuantizationTable(table);
1701 xml=DestroyString(xml);
1704 attribute=GetXMLTreeAttribute(levels,"divisor");
1705 if (attribute == (char *) NULL)
1707 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1708 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1709 quantization_tables=DestroyXMLTree(quantization_tables);
1710 table=DestroyQuantizationTable(table);
1711 xml=DestroyString(xml);
1714 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1715 if (table->divisor == 0.0)
1717 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1718 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1719 quantization_tables=DestroyXMLTree(quantization_tables);
1720 table=DestroyQuantizationTable(table);
1721 xml=DestroyString(xml);
1724 content=GetXMLTreeContent(levels);
1725 if (content == (char *) NULL)
1727 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1728 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1729 quantization_tables=DestroyXMLTree(quantization_tables);
1730 table=DestroyQuantizationTable(table);
1731 xml=DestroyString(xml);
1734 length=(size_t) table->width*table->height;
1737 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1738 sizeof(*table->levels));
1739 if (table->levels == (unsigned int *) NULL)
1740 ThrowFatalException(ResourceLimitFatalError,
1741 "UnableToAcquireQuantizationTable");
1742 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1744 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1745 table->divisor+0.5);
1746 while (isspace((int) ((unsigned char) *p)) != 0)
1752 value=InterpretLocaleValue(content,&p);
1756 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1757 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1758 quantization_tables=DestroyXMLTree(quantization_tables);
1759 table=DestroyQuantizationTable(table);
1760 xml=DestroyString(xml);
1763 for (j=i; j < 64; j++)
1764 table->levels[j]=table->levels[j-1];
1765 quantization_tables=DestroyXMLTree(quantization_tables);
1766 xml=DestroyString(xml);
1770 static void InitializeDestination(j_compress_ptr cinfo)
1775 destination=(DestinationManager *) cinfo->dest;
1776 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1777 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1778 destination->manager.next_output_byte=destination->buffer;
1779 destination->manager.free_in_buffer=MaxBufferExtent;
1782 static inline size_t MagickMin(const size_t x,const size_t y)
1789 static void TerminateDestination(j_compress_ptr cinfo)
1794 destination=(DestinationManager *) cinfo->dest;
1795 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1800 count=WriteBlob(destination->image,MaxBufferExtent-
1801 destination->manager.free_in_buffer,destination->buffer);
1802 if (count != (ssize_t)
1803 (MaxBufferExtent-destination->manager.free_in_buffer))
1804 ERREXIT(cinfo,JERR_FILE_WRITE);
1808 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1830 Save image profile as a APP marker.
1833 custom_profile=AcquireStringInfo(65535L);
1834 ResetImageProfileIterator(image);
1835 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1837 register unsigned char
1840 profile=GetImageProfile(image,name);
1841 p=GetStringInfoDatum(custom_profile);
1842 if (LocaleCompare(name,"EXIF") == 0)
1843 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1845 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1846 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1847 (unsigned int) length);
1849 if (LocaleCompare(name,"ICC") == 0)
1851 register unsigned char
1855 p=GetStringInfoDatum(custom_profile);
1856 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1857 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1859 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1860 p[12]=(unsigned char) ((i/65519L)+1);
1861 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1862 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1864 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1865 custom_profile),(unsigned int) (length+tag_length));
1868 if (((LocaleCompare(name,"IPTC") == 0) ||
1869 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1875 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1877 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1878 roundup=(size_t) (length & 0x01);
1879 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1881 (void) memcpy(p,"Photoshop 3.0 ",14);
1886 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1888 p[24]=(unsigned char) (length >> 8);
1889 p[25]=(unsigned char) (length & 0xff);
1892 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1894 p[length+tag_length]='\0';
1895 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1896 custom_profile),(unsigned int) (length+tag_length+roundup));
1899 if (LocaleCompare(name,"XMP") == 0)
1905 Add namespace to XMP profile.
1907 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1908 ConcatenateStringInfo(xmp_profile,profile);
1909 GetStringInfoDatum(xmp_profile)[28]='\0';
1910 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1912 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1913 jpeg_write_marker(jpeg_info,XML_MARKER,
1914 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1916 xmp_profile=DestroyStringInfo(xmp_profile);
1918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1919 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1920 name=GetNextImageProfile(image);
1922 custom_profile=DestroyStringInfo(custom_profile);
1925 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1930 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1931 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1932 destination=(DestinationManager *) cinfo->dest;
1933 destination->manager.init_destination=InitializeDestination;
1934 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1935 destination->manager.term_destination=TerminateDestination;
1936 destination->image=image;
1939 static char **SamplingFactorToList(const char *text)
1956 if (text == (char *) NULL)
1957 return((char **) NULL);
1959 Convert string to an ASCII list.
1962 for (p=text; *p != '\0'; p++)
1965 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1967 if (textlist == (char **) NULL)
1968 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1970 for (i=0; i < (ssize_t) lines; i++)
1972 for (q=(char *) p; *q != '\0'; q++)
1975 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1976 sizeof(*textlist[i]));
1977 if (textlist[i] == (char *) NULL)
1978 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1979 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1984 textlist[i]=(char *) NULL;
1988 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1989 Image *image,ExceptionInfo *exception)
2020 struct jpeg_compress_struct
2023 struct jpeg_error_mgr
2029 assert(image_info != (const ImageInfo *) NULL);
2030 assert(image_info->signature == MagickSignature);
2031 assert(image != (Image *) NULL);
2032 assert(image->signature == MagickSignature);
2033 if (image->debug != MagickFalse)
2034 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2035 assert(exception != (ExceptionInfo *) NULL);
2036 assert(exception->signature == MagickSignature);
2037 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2038 if (status == MagickFalse)
2041 Initialize JPEG parameters.
2043 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2044 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2045 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2046 jpeg_info.client_data=(void *) image;
2047 jpeg_info.err=jpeg_std_error(&jpeg_error);
2048 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2049 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2050 error_manager.exception=exception;
2051 error_manager.image=image;
2052 jpeg_pixels=(JSAMPLE *) NULL;
2053 if (setjmp(error_manager.error_recovery) != 0)
2055 jpeg_destroy_compress(&jpeg_info);
2056 (void) CloseBlob(image);
2057 return(MagickFalse);
2059 jpeg_info.client_data=(void *) &error_manager;
2060 jpeg_create_compress(&jpeg_info);
2061 JPEGDestinationManager(&jpeg_info,image);
2062 if ((image->columns != (unsigned int) image->columns) ||
2063 (image->rows != (unsigned int) image->rows))
2064 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2065 jpeg_info.image_width=(unsigned int) image->columns;
2066 jpeg_info.image_height=(unsigned int) image->rows;
2067 jpeg_info.input_components=3;
2068 jpeg_info.data_precision=8;
2069 jpeg_info.in_color_space=JCS_RGB;
2070 switch (image->colorspace)
2072 case CMYKColorspace:
2074 jpeg_info.input_components=4;
2075 jpeg_info.in_color_space=JCS_CMYK;
2078 case YCbCrColorspace:
2079 case Rec601YCbCrColorspace:
2080 case Rec709YCbCrColorspace:
2082 jpeg_info.in_color_space=JCS_YCbCr;
2085 case GRAYColorspace:
2086 case Rec601LumaColorspace:
2087 case Rec709LumaColorspace:
2089 jpeg_info.input_components=1;
2090 jpeg_info.in_color_space=JCS_GRAYSCALE;
2095 if (IssRGBColorspace(image->colorspace) == MagickFalse)
2096 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2100 if ((image_info->type != TrueColorType) &&
2101 (IsImageGray(image,exception) != MagickFalse))
2103 jpeg_info.input_components=1;
2104 jpeg_info.in_color_space=JCS_GRAYSCALE;
2106 jpeg_set_defaults(&jpeg_info);
2107 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2108 jpeg_info.data_precision=8;
2110 if (sizeof(JSAMPLE) > 1)
2111 jpeg_info.data_precision=12;
2112 jpeg_info.density_unit=(UINT8) 1;
2113 if (image->debug != MagickFalse)
2114 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2115 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2116 floor(image->resolution.y+0.5));
2117 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2120 Set image resolution.
2122 jpeg_info.write_JFIF_header=MagickTrue;
2123 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2124 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2125 if (image->units == PixelsPerInchResolution)
2126 jpeg_info.density_unit=(UINT8) 1;
2127 if (image->units == PixelsPerCentimeterResolution)
2128 jpeg_info.density_unit=(UINT8) 2;
2130 jpeg_info.dct_method=JDCT_FLOAT;
2131 option=GetImageOption(image_info,"jpeg:dct-method");
2132 if (option != (const char *) NULL)
2138 if (LocaleCompare(option,"default") == 0)
2139 jpeg_info.dct_method=JDCT_DEFAULT;
2145 if (LocaleCompare(option,"fastest") == 0)
2146 jpeg_info.dct_method=JDCT_FASTEST;
2147 if (LocaleCompare(option,"float") == 0)
2148 jpeg_info.dct_method=JDCT_FLOAT;
2154 if (LocaleCompare(option,"ifast") == 0)
2155 jpeg_info.dct_method=JDCT_IFAST;
2156 if (LocaleCompare(option,"islow") == 0)
2157 jpeg_info.dct_method=JDCT_ISLOW;
2161 option=GetImageOption(image_info,"jpeg:optimize-coding");
2162 if (option != (const char *) NULL)
2163 jpeg_info.optimize_coding=IsStringTrue(option);
2169 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2170 image->rows*sizeof(JSAMPLE);
2171 if (length == (MagickSizeType) ((size_t) length))
2174 Perform optimization only if available memory resources permit it.
2176 status=AcquireMagickResource(MemoryResource,length);
2177 RelinquishMagickResource(MemoryResource,length);
2178 jpeg_info.optimize_coding=status;
2181 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2182 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2183 (image_info->interlace != NoInterlace))
2185 if (image->debug != MagickFalse)
2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187 "Interlace: progressive");
2188 jpeg_simple_progression(&jpeg_info);
2191 if (image->debug != MagickFalse)
2192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2193 "Interlace: non-progressive");
2195 if (image->debug != MagickFalse)
2196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2197 "Interlace: nonprogressive");
2199 option=GetImageOption(image_info,"jpeg:extent");
2200 if (option != (const char *) NULL)
2208 jpeg_info=CloneImageInfo(image_info);
2209 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2210 if (jpeg_image != (Image *) NULL)
2220 Search for compression quality that does not exceed image extent.
2222 jpeg_info->quality=0;
2223 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2224 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2225 (void) AcquireUniqueFilename(jpeg_image->filename);
2227 for (minimum=0; minimum != maximum; )
2229 jpeg_image->quality=minimum+(maximum-minimum)/2;
2230 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2231 if (GetBlobSize(jpeg_image) <= extent)
2232 minimum=jpeg_image->quality+1;
2234 maximum=jpeg_image->quality-1;
2236 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2237 image->quality=minimum-1;
2238 jpeg_image=DestroyImage(jpeg_image);
2240 jpeg_info=DestroyImageInfo(jpeg_info);
2243 if ((image_info->compression != LosslessJPEGCompression) &&
2244 (image->quality <= 100))
2246 if (image->quality != UndefinedCompressionQuality)
2247 quality=(int) image->quality;
2248 if (image->debug != MagickFalse)
2249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2250 (double) image->quality);
2254 #if !defined(C_LOSSLESS_SUPPORTED)
2256 if (image->debug != MagickFalse)
2257 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2259 if (image->quality < 100)
2260 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2261 "LosslessToLossyJPEGConversion",image->filename);
2268 predictor=image->quality/100; /* range 1-7 */
2269 point_transform=image->quality % 20; /* range 0-15 */
2270 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2271 if (image->debug != MagickFalse)
2273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2274 "Compression: lossless");
2275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2276 "Predictor: %d",predictor);
2277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2278 "Point Transform: %d",point_transform);
2283 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2284 sampling_factor=(const char *) NULL;
2285 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2286 if (value != (char *) NULL)
2288 sampling_factor=value;
2289 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2291 " Input sampling-factors=%s",sampling_factor);
2293 if (image_info->sampling_factor != (char *) NULL)
2294 sampling_factor=image_info->sampling_factor;
2295 if (sampling_factor == (const char *) NULL)
2297 if (image->quality >= 90)
2298 for (i=0; i < MAX_COMPONENTS; i++)
2300 jpeg_info.comp_info[i].h_samp_factor=1;
2301 jpeg_info.comp_info[i].v_samp_factor=1;
2316 Set sampling factor.
2319 factors=SamplingFactorToList(sampling_factor);
2320 if (factors != (char **) NULL)
2322 for (i=0; i < MAX_COMPONENTS; i++)
2324 if (factors[i] == (char *) NULL)
2326 flags=ParseGeometry(factors[i],&geometry_info);
2327 if ((flags & SigmaValue) == 0)
2328 geometry_info.sigma=geometry_info.rho;
2329 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2330 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2331 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2333 factors=(char **) RelinquishMagickMemory(factors);
2335 for ( ; i < MAX_COMPONENTS; i++)
2337 jpeg_info.comp_info[i].h_samp_factor=1;
2338 jpeg_info.comp_info[i].v_samp_factor=1;
2341 if (jpeg_info.input_components == 1)
2342 for (i=0; i < MAX_COMPONENTS; i++)
2344 jpeg_info.comp_info[i].h_samp_factor=1;
2345 jpeg_info.comp_info[i].v_samp_factor=1;
2347 option=GetImageOption(image_info,"jpeg:q-table");
2348 if (option != (const char *) NULL)
2354 Custom quantization tables.
2356 table=GetQuantizationTable(option,"0",exception);
2357 if (table != (QuantizationTable *) NULL)
2359 jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2361 table=DestroyQuantizationTable(table);
2363 table=GetQuantizationTable(option,"1",exception);
2364 if (table != (QuantizationTable *) NULL)
2366 jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2368 table=DestroyQuantizationTable(table);
2370 table=GetQuantizationTable(option,"2",exception);
2371 if (table != (QuantizationTable *) NULL)
2373 jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2375 table=DestroyQuantizationTable(table);
2377 table=GetQuantizationTable(option,"3",exception);
2378 if (table != (QuantizationTable *) NULL)
2380 jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2382 table=DestroyQuantizationTable(table);
2385 jpeg_start_compress(&jpeg_info,MagickTrue);
2386 if (image->debug != MagickFalse)
2388 if (image->storage_class == PseudoClass)
2389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2390 "Storage class: PseudoClass");
2392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2393 "Storage class: DirectClass");
2394 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2395 (double) image->depth);
2396 if (image->colors != 0)
2397 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2398 "Number of colors: %.20g",(double) image->colors);
2400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2401 "Number of colors: unspecified");
2402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2403 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2404 switch (image->colorspace)
2406 case CMYKColorspace:
2408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2409 "Storage class: DirectClass");
2410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411 "Colorspace: CMYK");
2414 case YCbCrColorspace:
2415 case Rec601YCbCrColorspace:
2416 case Rec709YCbCrColorspace:
2418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2419 "Colorspace: YCbCr");
2425 switch (image->colorspace)
2427 case CMYKColorspace:
2429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2430 "Colorspace: CMYK");
2431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2432 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2433 jpeg_info.comp_info[0].h_samp_factor,
2434 jpeg_info.comp_info[0].v_samp_factor,
2435 jpeg_info.comp_info[1].h_samp_factor,
2436 jpeg_info.comp_info[1].v_samp_factor,
2437 jpeg_info.comp_info[2].h_samp_factor,
2438 jpeg_info.comp_info[2].v_samp_factor,
2439 jpeg_info.comp_info[3].h_samp_factor,
2440 jpeg_info.comp_info[3].v_samp_factor);
2443 case GRAYColorspace:
2444 case Rec601LumaColorspace:
2445 case Rec709LumaColorspace:
2447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2448 "Colorspace: GRAY");
2449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2450 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2451 jpeg_info.comp_info[0].v_samp_factor);
2456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2457 "Image colorspace is RGB");
2458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459 "Sampling factors: %dx%d,%dx%d,%dx%d",
2460 jpeg_info.comp_info[0].h_samp_factor,
2461 jpeg_info.comp_info[0].v_samp_factor,
2462 jpeg_info.comp_info[1].h_samp_factor,
2463 jpeg_info.comp_info[1].v_samp_factor,
2464 jpeg_info.comp_info[2].h_samp_factor,
2465 jpeg_info.comp_info[2].v_samp_factor);
2468 case YCbCrColorspace:
2469 case Rec601YCbCrColorspace:
2470 case Rec709YCbCrColorspace:
2472 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2473 "Colorspace: YCbCr");
2474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2475 "Sampling factors: %dx%d,%dx%d,%dx%d",
2476 jpeg_info.comp_info[0].h_samp_factor,
2477 jpeg_info.comp_info[0].v_samp_factor,
2478 jpeg_info.comp_info[1].h_samp_factor,
2479 jpeg_info.comp_info[1].v_samp_factor,
2480 jpeg_info.comp_info[2].h_samp_factor,
2481 jpeg_info.comp_info[2].v_samp_factor);
2486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2489 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2490 jpeg_info.comp_info[0].h_samp_factor,
2491 jpeg_info.comp_info[0].v_samp_factor,
2492 jpeg_info.comp_info[1].h_samp_factor,
2493 jpeg_info.comp_info[1].v_samp_factor,
2494 jpeg_info.comp_info[2].h_samp_factor,
2495 jpeg_info.comp_info[2].v_samp_factor,
2496 jpeg_info.comp_info[3].h_samp_factor,
2497 jpeg_info.comp_info[3].v_samp_factor);
2503 Write JPEG profiles.
2505 value=GetImageProperty(image,"comment",exception);
2506 if (value != (char *) NULL)
2507 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2508 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2509 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2510 if (image->profiles != (void *) NULL)
2511 WriteProfile(&jpeg_info,image);
2513 Convert MIFF to JPEG raster pixels.
2515 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2516 jpeg_info.input_components*sizeof(*jpeg_pixels));
2517 if (jpeg_pixels == (JSAMPLE *) NULL)
2518 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2519 if (setjmp(error_manager.error_recovery) != 0)
2521 jpeg_destroy_compress(&jpeg_info);
2522 if (jpeg_pixels != (unsigned char *) NULL)
2523 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2524 (void) CloseBlob(image);
2525 return(MagickFalse);
2527 scanline[0]=(JSAMPROW) jpeg_pixels;
2528 if (jpeg_info.data_precision <= 8)
2530 if ((jpeg_info.in_color_space == JCS_RGB) ||
2531 (jpeg_info.in_color_space == JCS_YCbCr))
2532 for (y=0; y < (ssize_t) image->rows; y++)
2534 register const Quantum
2540 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2541 if (p == (const Quantum *) NULL)
2544 for (x=0; x < (ssize_t) image->columns; x++)
2546 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2547 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2548 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2549 p+=GetPixelChannels(image);
2551 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2552 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2554 if (status == MagickFalse)
2558 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2559 for (y=0; y < (ssize_t) image->rows; y++)
2561 register const Quantum
2567 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2568 if (p == (const Quantum *) NULL)
2571 for (x=0; x < (ssize_t) image->columns; x++)
2573 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2574 p+=GetPixelChannels(image);
2576 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2577 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2579 if (status == MagickFalse)
2583 for (y=0; y < (ssize_t) image->rows; y++)
2585 register const Quantum
2591 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2592 if (p == (const Quantum *) NULL)
2595 for (x=0; x < (ssize_t) image->columns; x++)
2598 Convert DirectClass packets to contiguous CMYK scanlines.
2600 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2601 GetPixelRed(image,p))));
2602 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2603 GetPixelGreen(image,p))));
2604 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2605 GetPixelBlue(image,p))));
2606 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2607 GetPixelBlack(image,p))));
2608 p+=GetPixelChannels(image);
2610 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2611 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2613 if (status == MagickFalse)
2618 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2619 for (y=0; y < (ssize_t) image->rows; y++)
2621 register const Quantum
2627 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2628 if (p == (const Quantum *) NULL)
2631 for (x=0; x < (ssize_t) image->columns; x++)
2633 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >> 4);
2634 p+=GetPixelChannels(image);
2636 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2637 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2639 if (status == MagickFalse)
2643 if ((jpeg_info.in_color_space == JCS_RGB) ||
2644 (jpeg_info.in_color_space == JCS_YCbCr))
2645 for (y=0; y < (ssize_t) image->rows; y++)
2647 register const Quantum
2653 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2654 if (p == (const Quantum *) NULL)
2657 for (x=0; x < (ssize_t) image->columns; x++)
2659 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2660 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2661 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2662 p+=GetPixelChannels(image);
2664 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2665 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2667 if (status == MagickFalse)
2671 for (y=0; y < (ssize_t) image->rows; y++)
2673 register const Quantum
2679 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2680 if (p == (const Quantum *) NULL)
2683 for (x=0; x < (ssize_t) image->columns; x++)
2686 Convert DirectClass packets to contiguous CMYK scanlines.
2688 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2689 GetPixelRed(image,p)) >> 4));
2690 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2691 GetPixelGreen(image,p)) >> 4));
2692 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2693 GetPixelBlue(image,p)) >> 4));
2694 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2695 GetPixelBlack(image,p)) >> 4));
2696 p+=GetPixelChannels(image);
2698 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2699 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2701 if (status == MagickFalse)
2704 if (y == (ssize_t) image->rows)
2705 jpeg_finish_compress(&jpeg_info);
2707 Relinquish resources.
2709 jpeg_destroy_compress(&jpeg_info);
2710 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2711 (void) CloseBlob(image);