2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
46 #include "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/token.h"
81 #include "MagickCore/utility.h"
82 #include "MagickCore/xml-tree.h"
83 #include "MagickCore/xml-tree-private.h"
85 #if defined(MAGICKCORE_JPEG_DELEGATE)
86 #define JPEG_INTERNAL_OPTIONS
87 #if defined(__MINGW32__)
88 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
89 typedef unsigned char boolean;
100 #define ICC_MARKER (JPEG_APP0+2)
101 #define ICC_PROFILE "ICC_PROFILE"
102 #define IPTC_MARKER (JPEG_APP0+13)
103 #define XML_MARKER (JPEG_APP0+1)
104 #define MaxBufferExtent 16384
107 Typedef declarations.
109 #if defined(MAGICKCORE_JPEG_DELEGATE)
110 typedef struct _DestinationManager
112 struct jpeg_destination_mgr
120 } DestinationManager;
122 typedef struct _ErrorManager
137 typedef struct _SourceManager
139 struct jpeg_source_mgr
153 typedef struct _QuantizationTable
171 Forward declarations.
173 #if defined(MAGICKCORE_JPEG_DELEGATE)
174 static MagickBooleanType
175 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 % IsJPEG() returns MagickTrue if the image format type, identified by the
190 % magick string, is JPEG.
192 % The format of the IsJPEG method is:
194 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
196 % A description of each parameter follows:
198 % o magick: compare image format pattern against these bytes.
200 % o length: Specifies the length of the magick string.
203 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
207 if (memcmp(magick,"\377\330\377",3) == 0)
212 #if defined(MAGICKCORE_JPEG_DELEGATE)
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218 % R e a d J P E G I m a g e %
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
225 % the memory necessary for the new Image structure and returns a pointer to
228 % The format of the ReadJPEGImage method is:
230 % Image *ReadJPEGImage(const ImageInfo *image_info,
231 % ExceptionInfo *exception)
233 % A description of each parameter follows:
235 % o image_info: the image info.
237 % o exception: return any errors or warnings in this structure.
241 static boolean FillInputBuffer(j_decompress_ptr cinfo)
246 source=(SourceManager *) cinfo->src;
247 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
248 MaxBufferExtent,source->buffer);
249 if (source->manager.bytes_in_buffer == 0)
251 if (source->start_of_blob != FALSE)
252 ERREXIT(cinfo,JERR_INPUT_EMPTY);
253 WARNMS(cinfo,JWRN_JPEG_EOF);
254 source->buffer[0]=(JOCTET) 0xff;
255 source->buffer[1]=(JOCTET) JPEG_EOI;
256 source->manager.bytes_in_buffer=2;
258 source->manager.next_input_byte=source->buffer;
259 source->start_of_blob=FALSE;
263 static int GetCharacter(j_decompress_ptr jpeg_info)
265 if (jpeg_info->src->bytes_in_buffer == 0)
266 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
267 jpeg_info->src->bytes_in_buffer--;
268 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
271 static void InitializeSource(j_decompress_ptr cinfo)
276 source=(SourceManager *) cinfo->src;
277 source->start_of_blob=TRUE;
280 static MagickBooleanType IsITUFaxImage(const Image *image)
288 profile=GetImageProfile(image,"8bim");
289 if (profile == (const StringInfo *) NULL)
291 if (GetStringInfoLength(profile) < 5)
293 datum=GetStringInfoDatum(profile);
294 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
295 (datum[3] == 0x41) && (datum[4] == 0x58))
300 static void JPEGErrorHandler(j_common_ptr jpeg_info)
303 message[JMSG_LENGTH_MAX];
315 error_manager=(ErrorManager *) jpeg_info->client_data;
316 image=error_manager->image;
317 exception=error_manager->exception;
318 (jpeg_info->err->format_message)(jpeg_info,message);
319 if (image->debug != MagickFalse)
320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
321 "[%s] JPEG Trace: \"%s\"",image->filename,message);
322 if (error_manager->finished != MagickFalse)
323 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
324 (char *) message,"`%s'",image->filename);
326 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
327 (char *) message,"`%s'",image->filename);
328 longjmp(error_manager->error_recovery,1);
331 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
333 #define JPEGExcessiveWarnings 1000
336 message[JMSG_LENGTH_MAX];
348 error_manager=(ErrorManager *) jpeg_info->client_data;
349 exception=error_manager->exception;
350 image=error_manager->image;
354 Process warning message.
356 (jpeg_info->err->format_message)(jpeg_info,message);
357 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
358 JPEGErrorHandler(jpeg_info);
359 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;
1071 Set image resolution.
1074 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1075 (jpeg_info.Y_density != 1))
1077 image->resolution.x=(double) jpeg_info.X_density;
1078 image->resolution.y=(double) jpeg_info.Y_density;
1079 units=(size_t) jpeg_info.density_unit;
1082 image->units=PixelsPerInchResolution;
1084 image->units=PixelsPerCentimeterResolution;
1085 number_pixels=(MagickSizeType) image->columns*image->rows;
1086 option=GetImageOption(image_info,"jpeg:size");
1087 if (option != (const char *) NULL)
1101 flags=ParseGeometry(option,&geometry_info);
1102 if ((flags & SigmaValue) == 0)
1103 geometry_info.sigma=geometry_info.rho;
1104 jpeg_calc_output_dimensions(&jpeg_info);
1105 image->magick_columns=jpeg_info.output_width;
1106 image->magick_rows=jpeg_info.output_height;
1108 if (geometry_info.rho != 0.0)
1109 scale_factor=jpeg_info.output_width/geometry_info.rho;
1110 if ((geometry_info.sigma != 0.0) &&
1111 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1112 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1113 jpeg_info.scale_num=1U;
1114 jpeg_info.scale_denom=(unsigned int) scale_factor;
1115 jpeg_calc_output_dimensions(&jpeg_info);
1116 if (image->debug != MagickFalse)
1117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1118 "Scale factor: %.20g",(double) scale_factor);
1120 precision=(size_t) jpeg_info.data_precision;
1121 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1122 #if defined(D_LOSSLESS_SUPPORTED)
1123 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1124 JPEGInterlace : NoInterlace;
1125 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1126 LosslessJPEGCompression : JPEGCompression;
1127 if (jpeg_info.data_precision > 8)
1128 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1129 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1131 if (jpeg_info.data_precision == 16)
1132 jpeg_info.data_precision=12;
1134 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1136 image->compression=JPEGCompression;
1139 image->compression=JPEGCompression;
1140 image->interlace=JPEGInterlace;
1142 option=GetImageOption(image_info,"jpeg:colors");
1143 if (option != (const char *) NULL)
1146 Let the JPEG library quantize the image.
1148 jpeg_info.quantize_colors=MagickTrue;
1149 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1151 option=GetImageOption(image_info,"jpeg:block-smoothing");
1152 jpeg_info.do_block_smoothing=IsStringTrue(option);
1153 jpeg_info.dct_method=JDCT_FLOAT;
1154 option=GetImageOption(image_info,"jpeg:dct-method");
1155 if (option != (const char *) NULL)
1161 if (LocaleCompare(option,"default") == 0)
1162 jpeg_info.dct_method=JDCT_DEFAULT;
1168 if (LocaleCompare(option,"fastest") == 0)
1169 jpeg_info.dct_method=JDCT_FASTEST;
1170 if (LocaleCompare(option,"float") == 0)
1171 jpeg_info.dct_method=JDCT_FLOAT;
1177 if (LocaleCompare(option,"ifast") == 0)
1178 jpeg_info.dct_method=JDCT_IFAST;
1179 if (LocaleCompare(option,"islow") == 0)
1180 jpeg_info.dct_method=JDCT_ISLOW;
1184 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1185 jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1186 (void) jpeg_start_decompress(&jpeg_info);
1187 image->columns=jpeg_info.output_width;
1188 image->rows=jpeg_info.output_height;
1189 image->depth=(size_t) jpeg_info.data_precision;
1190 switch (jpeg_info.out_color_space)
1195 SetImageColorspace(image,sRGBColorspace,exception);
1200 SetImageColorspace(image,GRAYColorspace,exception);
1205 SetImageColorspace(image,YCbCrColorspace,exception);
1210 SetImageColorspace(image,CMYKColorspace,exception);
1214 if (IsITUFaxImage(image) != MagickFalse)
1216 SetImageColorspace(image,LabColorspace,exception);
1217 jpeg_info.out_color_space=JCS_YCbCr;
1219 option=GetImageOption(image_info,"jpeg:colors");
1220 if (option != (const char *) NULL)
1221 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1223 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1224 if ((jpeg_info.output_components == 1) &&
1225 (jpeg_info.quantize_colors == MagickFalse))
1230 colors=(size_t) GetQuantumRange(image->depth)+1;
1231 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1232 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1234 if (image->debug != MagickFalse)
1236 if (image->interlace != NoInterlace)
1237 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1238 "Interlace: progressive");
1240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1241 "Interlace: nonprogressive");
1242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1243 (int) jpeg_info.data_precision);
1244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1245 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1247 JPEGSetImageQuality(&jpeg_info,image);
1248 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1249 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1250 jpeg_info.out_color_space);
1251 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1252 if (image_info->ping != MagickFalse)
1254 jpeg_destroy_decompress(&jpeg_info);
1255 (void) CloseBlob(image);
1256 return(GetFirstImageInList(image));
1258 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1259 jpeg_info.output_components*sizeof(JSAMPLE));
1260 if (jpeg_pixels == (JSAMPLE *) NULL)
1261 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1263 Convert JPEG pixels to pixel packets.
1265 if (setjmp(error_manager.error_recovery) != 0)
1267 if (jpeg_pixels != (unsigned char *) NULL)
1268 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1269 jpeg_destroy_decompress(&jpeg_info);
1270 (void) CloseBlob(image);
1271 number_pixels=(MagickSizeType) image->columns*image->rows;
1272 if (number_pixels != 0)
1273 return(GetFirstImageInList(image));
1274 return(DestroyImage(image));
1276 if (jpeg_info.quantize_colors != MagickFalse)
1278 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1279 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1280 for (i=0; i < (ssize_t) image->colors; i++)
1282 image->colormap[i].red=(double) ScaleCharToQuantum(
1283 jpeg_info.colormap[0][i]);
1284 image->colormap[i].green=image->colormap[i].red;
1285 image->colormap[i].blue=image->colormap[i].red;
1286 image->colormap[i].alpha=OpaqueAlpha;
1289 for (i=0; i < (ssize_t) image->colors; i++)
1291 image->colormap[i].red=(double) ScaleCharToQuantum(
1292 jpeg_info.colormap[0][i]);
1293 image->colormap[i].green=(double) ScaleCharToQuantum(
1294 jpeg_info.colormap[1][i]);
1295 image->colormap[i].blue=(double) ScaleCharToQuantum(
1296 jpeg_info.colormap[2][i]);
1297 image->colormap[i].alpha=OpaqueAlpha;
1300 scanline[0]=(JSAMPROW) jpeg_pixels;
1301 for (y=0; y < (ssize_t) image->rows; y++)
1309 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1311 (void) ThrowMagickException(exception,GetMagickModule(),
1312 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1316 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1317 if (q == (Quantum *) NULL)
1319 if (jpeg_info.data_precision > 8)
1321 if (jpeg_info.output_components == 1)
1322 for (x=0; x < (ssize_t) image->columns; x++)
1327 if (precision != 16)
1328 pixel=(size_t) GETJSAMPLE(*p);
1330 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1331 index=ConstrainColormapIndex(image,pixel,exception);
1332 SetPixelIndex(image,index,q);
1333 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1335 q+=GetPixelChannels(image);
1338 if (image->colorspace != CMYKColorspace)
1339 for (x=0; x < (ssize_t) image->columns; x++)
1341 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1342 (GETJSAMPLE(*p++) << 4)),q);
1343 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1344 (GETJSAMPLE(*p++) << 4)),q);
1345 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1346 (GETJSAMPLE(*p++) << 4)),q);
1347 SetPixelAlpha(image,OpaqueAlpha,q);
1348 q+=GetPixelChannels(image);
1351 for (x=0; x < (ssize_t) image->columns; x++)
1353 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1354 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1355 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1356 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1357 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1358 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1359 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1360 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1361 SetPixelAlpha(image,OpaqueAlpha,q);
1362 q+=GetPixelChannels(image);
1366 if (jpeg_info.output_components == 1)
1367 for (x=0; x < (ssize_t) image->columns; x++)
1369 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1370 SetPixelIndex(image,index,q);
1371 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1373 q+=GetPixelChannels(image);
1376 if (image->colorspace != CMYKColorspace)
1377 for (x=0; x < (ssize_t) image->columns; x++)
1379 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1380 GETJSAMPLE(*p++)),q);
1381 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1382 GETJSAMPLE(*p++)),q);
1383 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1384 GETJSAMPLE(*p++)),q);
1385 SetPixelAlpha(image,OpaqueAlpha,q);
1386 q+=GetPixelChannels(image);
1389 for (x=0; x < (ssize_t) image->columns; x++)
1391 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1392 (unsigned char) GETJSAMPLE(*p++)),q);
1393 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1394 (unsigned char) GETJSAMPLE(*p++)),q);
1395 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1396 (unsigned char) GETJSAMPLE(*p++)),q);
1397 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1398 (unsigned char) GETJSAMPLE(*p++)),q);
1399 SetPixelAlpha(image,OpaqueAlpha,q);
1400 q+=GetPixelChannels(image);
1402 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1404 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1406 if (status == MagickFalse)
1408 jpeg_abort_decompress(&jpeg_info);
1412 if (status != MagickFalse)
1414 error_manager.finished=MagickTrue;
1415 if (setjmp(error_manager.error_recovery) == 0)
1416 (void) jpeg_finish_decompress(&jpeg_info);
1419 Free jpeg resources.
1421 jpeg_destroy_decompress(&jpeg_info);
1422 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1423 (void) CloseBlob(image);
1424 return(GetFirstImageInList(image));
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433 % R e g i s t e r J P E G I m a g e %
1437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439 % RegisterJPEGImage() adds properties for the JPEG image format to
1440 % the list of supported formats. The properties include the image format
1441 % tag, a method to read and/or write the format, whether the format
1442 % supports the saving of more than one frame to the same file or blob,
1443 % whether the format supports native in-memory I/O, and a brief
1444 % description of the format.
1446 % The format of the RegisterJPEGImage method is:
1448 % size_t RegisterJPEGImage(void)
1451 ModuleExport size_t RegisterJPEGImage(void)
1454 version[MaxTextExtent];
1460 description[] = "Joint Photographic Experts Group JFIF format";
1463 #if defined(JPEG_LIB_VERSION)
1464 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1466 entry=SetMagickInfo("JPEG");
1467 entry->thread_support=NoThreadSupport;
1468 #if defined(MAGICKCORE_JPEG_DELEGATE)
1469 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1470 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1472 entry->magick=(IsImageFormatHandler *) IsJPEG;
1473 entry->adjoin=MagickFalse;
1474 entry->description=ConstantString(description);
1475 if (*version != '\0')
1476 entry->version=ConstantString(version);
1477 entry->module=ConstantString("JPEG");
1478 (void) RegisterMagickInfo(entry);
1479 entry=SetMagickInfo("JPG");
1480 entry->thread_support=NoThreadSupport;
1481 #if defined(MAGICKCORE_JPEG_DELEGATE)
1482 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1483 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1485 entry->adjoin=MagickFalse;
1486 entry->description=ConstantString(description);
1487 if (*version != '\0')
1488 entry->version=ConstantString(version);
1489 entry->module=ConstantString("JPEG");
1490 (void) RegisterMagickInfo(entry);
1491 entry=SetMagickInfo("PJPEG");
1492 entry->thread_support=NoThreadSupport;
1493 #if defined(MAGICKCORE_JPEG_DELEGATE)
1494 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1495 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1497 entry->adjoin=MagickFalse;
1498 entry->description=ConstantString(description);
1499 if (*version != '\0')
1500 entry->version=ConstantString(version);
1501 entry->module=ConstantString("JPEG");
1502 (void) RegisterMagickInfo(entry);
1503 return(MagickImageCoderSignature);
1507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1511 % U n r e g i s t e r J P E G I m a g e %
1515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1517 % UnregisterJPEGImage() removes format registrations made by the
1518 % JPEG module from the list of supported formats.
1520 % The format of the UnregisterJPEGImage method is:
1522 % UnregisterJPEGImage(void)
1525 ModuleExport void UnregisterJPEGImage(void)
1527 (void) UnregisterMagickInfo("PJPG");
1528 (void) UnregisterMagickInfo("JPEG");
1529 (void) UnregisterMagickInfo("JPG");
1532 #if defined(MAGICKCORE_JPEG_DELEGATE)
1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1538 % W r i t e J P E G I m a g e %
1542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544 % WriteJPEGImage() writes a JPEG image file and returns it. It
1545 % allocates the memory necessary for the new Image structure and returns a
1546 % pointer to the new image.
1548 % The format of the WriteJPEGImage method is:
1550 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1551 % Image *image,ExceptionInfo *exception)
1553 % A description of each parameter follows:
1555 % o image_info: the image info.
1557 % o jpeg_image: The image.
1559 % o exception: return any errors or warnings in this structure.
1563 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1565 assert(table != (QuantizationTable *) NULL);
1566 if (table->slot != (char *) NULL)
1567 table->slot=DestroyString(table->slot);
1568 if (table->description != (char *) NULL)
1569 table->description=DestroyString(table->description);
1570 if (table->levels != (unsigned int *) NULL)
1571 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1572 table=(QuantizationTable *) RelinquishMagickMemory(table);
1576 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1581 destination=(DestinationManager *) cinfo->dest;
1582 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1583 MaxBufferExtent,destination->buffer);
1584 if (destination->manager.free_in_buffer != MaxBufferExtent)
1585 ERREXIT(cinfo,JERR_FILE_WRITE);
1586 destination->manager.next_output_byte=destination->buffer;
1590 static QuantizationTable *GetQuantizationTable(const char *filename,
1591 const char *slot,ExceptionInfo *exception)
1619 *quantization_tables,
1622 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1623 "Loading quantization tables \"%s\" ...",filename);
1624 table=(QuantizationTable *) NULL;
1625 xml=FileToString(filename,~0,exception);
1626 if (xml == (char *) NULL)
1628 quantization_tables=NewXMLTree(xml,exception);
1629 if (quantization_tables == (XMLTreeInfo *) NULL)
1631 xml=DestroyString(xml);
1634 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1635 table_iterator != (XMLTreeInfo *) NULL;
1636 table_iterator=GetNextXMLTreeTag(table_iterator))
1638 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1639 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1641 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1642 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1645 if (table_iterator == (XMLTreeInfo *) NULL)
1647 xml=DestroyString(xml);
1650 description=GetXMLTreeChild(table_iterator,"description");
1651 if (description == (XMLTreeInfo *) NULL)
1653 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1654 "XmlMissingElement", "<description>, slot \"%s\"",slot);
1655 quantization_tables=DestroyXMLTree(quantization_tables);
1656 xml=DestroyString(xml);
1659 levels=GetXMLTreeChild(table_iterator,"levels");
1660 if (levels == (XMLTreeInfo *) NULL)
1662 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1663 "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1664 quantization_tables=DestroyXMLTree(quantization_tables);
1665 xml=DestroyString(xml);
1668 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1669 if (table == (QuantizationTable *) NULL)
1670 ThrowFatalException(ResourceLimitFatalError,
1671 "UnableToAcquireQuantizationTable");
1672 table->slot=(char *) NULL;
1673 table->description=(char *) NULL;
1674 table->levels=(unsigned int *) NULL;
1675 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1676 if (attribute != (char *) NULL)
1677 table->slot=ConstantString(attribute);
1678 content=GetXMLTreeContent(description);
1679 if (content != (char *) NULL)
1680 table->description=ConstantString(content);
1681 attribute=GetXMLTreeAttribute(levels,"width");
1682 if (attribute == (char *) NULL)
1684 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1685 "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1686 quantization_tables=DestroyXMLTree(quantization_tables);
1687 table=DestroyQuantizationTable(table);
1688 xml=DestroyString(xml);
1691 table->width=StringToUnsignedLong(attribute);
1692 if (table->width == 0)
1694 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1695 "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1696 quantization_tables=DestroyXMLTree(quantization_tables);
1697 table=DestroyQuantizationTable(table);
1698 xml=DestroyString(xml);
1701 attribute=GetXMLTreeAttribute(levels,"height");
1702 if (attribute == (char *) NULL)
1704 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1705 "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1706 quantization_tables=DestroyXMLTree(quantization_tables);
1707 table=DestroyQuantizationTable(table);
1708 xml=DestroyString(xml);
1711 table->height=StringToUnsignedLong(attribute);
1712 if (table->height == 0)
1714 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1715 "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1716 quantization_tables=DestroyXMLTree(quantization_tables);
1717 table=DestroyQuantizationTable(table);
1718 xml=DestroyString(xml);
1721 attribute=GetXMLTreeAttribute(levels,"divisor");
1722 if (attribute == (char *) NULL)
1724 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1725 "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1726 quantization_tables=DestroyXMLTree(quantization_tables);
1727 table=DestroyQuantizationTable(table);
1728 xml=DestroyString(xml);
1731 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1732 if (table->divisor == 0.0)
1734 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1735 "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1736 quantization_tables=DestroyXMLTree(quantization_tables);
1737 table=DestroyQuantizationTable(table);
1738 xml=DestroyString(xml);
1741 content=GetXMLTreeContent(levels);
1742 if (content == (char *) NULL)
1744 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1745 "XmlMissingContent", "<levels>, table \"%s\"",slot);
1746 quantization_tables=DestroyXMLTree(quantization_tables);
1747 table=DestroyQuantizationTable(table);
1748 xml=DestroyString(xml);
1751 length=(size_t) table->width*table->height;
1754 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1755 sizeof(*table->levels));
1756 if (table->levels == (unsigned int *) NULL)
1757 ThrowFatalException(ResourceLimitFatalError,
1758 "UnableToAcquireQuantizationTable");
1759 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1761 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1762 table->divisor+0.5);
1763 while (isspace((int) ((unsigned char) *p)) != 0)
1769 value=InterpretLocaleValue(content,&p);
1773 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1774 "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1775 quantization_tables=DestroyXMLTree(quantization_tables);
1776 table=DestroyQuantizationTable(table);
1777 xml=DestroyString(xml);
1780 for (j=i; j < 64; j++)
1781 table->levels[j]=table->levels[j-1];
1782 quantization_tables=DestroyXMLTree(quantization_tables);
1783 xml=DestroyString(xml);
1787 static void InitializeDestination(j_compress_ptr cinfo)
1792 destination=(DestinationManager *) cinfo->dest;
1793 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1794 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1795 destination->manager.next_output_byte=destination->buffer;
1796 destination->manager.free_in_buffer=MaxBufferExtent;
1799 static inline size_t MagickMin(const size_t x,const size_t y)
1806 static void TerminateDestination(j_compress_ptr cinfo)
1811 destination=(DestinationManager *) cinfo->dest;
1812 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1817 count=WriteBlob(destination->image,MaxBufferExtent-
1818 destination->manager.free_in_buffer,destination->buffer);
1819 if (count != (ssize_t)
1820 (MaxBufferExtent-destination->manager.free_in_buffer))
1821 ERREXIT(cinfo,JERR_FILE_WRITE);
1825 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1847 Save image profile as a APP marker.
1850 custom_profile=AcquireStringInfo(65535L);
1851 ResetImageProfileIterator(image);
1852 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1854 register unsigned char
1857 profile=GetImageProfile(image,name);
1858 p=GetStringInfoDatum(custom_profile);
1859 if (LocaleCompare(name,"EXIF") == 0)
1860 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1862 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1863 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1864 (unsigned int) length);
1866 if (LocaleCompare(name,"ICC") == 0)
1868 register unsigned char
1872 p=GetStringInfoDatum(custom_profile);
1873 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1874 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1876 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1877 p[12]=(unsigned char) ((i/65519L)+1);
1878 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1879 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1881 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1882 custom_profile),(unsigned int) (length+tag_length));
1885 if (((LocaleCompare(name,"IPTC") == 0) ||
1886 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1892 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1894 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1895 roundup=(size_t) (length & 0x01);
1896 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1898 (void) memcpy(p,"Photoshop 3.0 ",14);
1903 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1905 p[24]=(unsigned char) (length >> 8);
1906 p[25]=(unsigned char) (length & 0xff);
1909 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1911 p[length+tag_length]='\0';
1912 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1913 custom_profile),(unsigned int) (length+tag_length+roundup));
1916 if (LocaleCompare(name,"XMP") == 0)
1922 Add namespace to XMP profile.
1924 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1925 ConcatenateStringInfo(xmp_profile,profile);
1926 GetStringInfoDatum(xmp_profile)[28]='\0';
1927 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1929 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1930 jpeg_write_marker(jpeg_info,XML_MARKER,
1931 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1933 xmp_profile=DestroyStringInfo(xmp_profile);
1935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1936 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1937 name=GetNextImageProfile(image);
1939 custom_profile=DestroyStringInfo(custom_profile);
1942 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1947 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1948 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1949 destination=(DestinationManager *) cinfo->dest;
1950 destination->manager.init_destination=InitializeDestination;
1951 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1952 destination->manager.term_destination=TerminateDestination;
1953 destination->image=image;
1956 static char **SamplingFactorToList(const char *text)
1973 if (text == (char *) NULL)
1974 return((char **) NULL);
1976 Convert string to an ASCII list.
1979 for (p=text; *p != '\0'; p++)
1982 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1984 if (textlist == (char **) NULL)
1985 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1987 for (i=0; i < (ssize_t) lines; i++)
1989 for (q=(char *) p; *q != '\0'; q++)
1992 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1993 sizeof(*textlist[i]));
1994 if (textlist[i] == (char *) NULL)
1995 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1996 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2001 textlist[i]=(char *) NULL;
2005 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2006 Image *image,ExceptionInfo *exception)
2037 struct jpeg_compress_struct
2040 struct jpeg_error_mgr
2046 assert(image_info != (const ImageInfo *) NULL);
2047 assert(image_info->signature == MagickSignature);
2048 assert(image != (Image *) NULL);
2049 assert(image->signature == MagickSignature);
2050 if (image->debug != MagickFalse)
2051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2052 assert(exception != (ExceptionInfo *) NULL);
2053 assert(exception->signature == MagickSignature);
2054 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2055 if (status == MagickFalse)
2058 Initialize JPEG parameters.
2060 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2061 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2062 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2063 jpeg_info.client_data=(void *) image;
2064 jpeg_info.err=jpeg_std_error(&jpeg_error);
2065 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2066 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2067 error_manager.exception=exception;
2068 error_manager.image=image;
2069 jpeg_pixels=(JSAMPLE *) NULL;
2070 if (setjmp(error_manager.error_recovery) != 0)
2072 jpeg_destroy_compress(&jpeg_info);
2073 (void) CloseBlob(image);
2074 return(MagickFalse);
2076 jpeg_info.client_data=(void *) &error_manager;
2077 jpeg_create_compress(&jpeg_info);
2078 JPEGDestinationManager(&jpeg_info,image);
2079 if ((image->columns != (unsigned int) image->columns) ||
2080 (image->rows != (unsigned int) image->rows))
2081 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2082 jpeg_info.image_width=(unsigned int) image->columns;
2083 jpeg_info.image_height=(unsigned int) image->rows;
2084 jpeg_info.input_components=3;
2085 jpeg_info.data_precision=8;
2086 jpeg_info.in_color_space=JCS_RGB;
2087 switch (image->colorspace)
2089 case CMYKColorspace:
2091 jpeg_info.input_components=4;
2092 jpeg_info.in_color_space=JCS_CMYK;
2095 case YCbCrColorspace:
2096 case Rec601YCbCrColorspace:
2097 case Rec709YCbCrColorspace:
2099 jpeg_info.in_color_space=JCS_YCbCr;
2102 case GRAYColorspace:
2103 case Rec601LumaColorspace:
2104 case Rec709LumaColorspace:
2106 jpeg_info.input_components=1;
2107 jpeg_info.in_color_space=JCS_GRAYSCALE;
2112 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2113 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2117 if ((image_info->type != TrueColorType) &&
2118 (IsImageGray(image,exception) != MagickFalse))
2120 jpeg_info.input_components=1;
2121 jpeg_info.in_color_space=JCS_GRAYSCALE;
2123 jpeg_set_defaults(&jpeg_info);
2124 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2125 jpeg_info.data_precision=8;
2127 if (sizeof(JSAMPLE) > 1)
2128 jpeg_info.data_precision=12;
2129 jpeg_info.density_unit=(UINT8) 1;
2130 if (image->debug != MagickFalse)
2131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2132 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2133 floor(image->resolution.y+0.5));
2134 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2137 Set image resolution.
2139 jpeg_info.write_JFIF_header=MagickTrue;
2140 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2141 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2142 if (image->units == PixelsPerInchResolution)
2143 jpeg_info.density_unit=(UINT8) 1;
2144 if (image->units == PixelsPerCentimeterResolution)
2145 jpeg_info.density_unit=(UINT8) 2;
2147 jpeg_info.dct_method=JDCT_FLOAT;
2148 option=GetImageOption(image_info,"jpeg:dct-method");
2149 if (option != (const char *) NULL)
2155 if (LocaleCompare(option,"default") == 0)
2156 jpeg_info.dct_method=JDCT_DEFAULT;
2162 if (LocaleCompare(option,"fastest") == 0)
2163 jpeg_info.dct_method=JDCT_FASTEST;
2164 if (LocaleCompare(option,"float") == 0)
2165 jpeg_info.dct_method=JDCT_FLOAT;
2171 if (LocaleCompare(option,"ifast") == 0)
2172 jpeg_info.dct_method=JDCT_IFAST;
2173 if (LocaleCompare(option,"islow") == 0)
2174 jpeg_info.dct_method=JDCT_ISLOW;
2178 option=GetImageOption(image_info,"jpeg:optimize-coding");
2179 if (option != (const char *) NULL)
2180 jpeg_info.optimize_coding=IsStringTrue(option);
2186 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2187 image->rows*sizeof(JSAMPLE);
2188 if (length == (MagickSizeType) ((size_t) length))
2191 Perform optimization only if available memory resources permit it.
2193 status=AcquireMagickResource(MemoryResource,length);
2194 RelinquishMagickResource(MemoryResource,length);
2195 jpeg_info.optimize_coding=status;
2198 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2199 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2200 (image_info->interlace != NoInterlace))
2202 if (image->debug != MagickFalse)
2203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2204 "Interlace: progressive");
2205 jpeg_simple_progression(&jpeg_info);
2208 if (image->debug != MagickFalse)
2209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2210 "Interlace: non-progressive");
2212 if (image->debug != MagickFalse)
2213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2214 "Interlace: nonprogressive");
2216 option=GetImageOption(image_info,"jpeg:extent");
2217 if (option != (const char *) NULL)
2225 jpeg_info=CloneImageInfo(image_info);
2226 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2227 if (jpeg_image != (Image *) NULL)
2237 Search for compression quality that does not exceed image extent.
2239 jpeg_info->quality=0;
2240 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2241 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2242 (void) AcquireUniqueFilename(jpeg_image->filename);
2244 for (minimum=0; minimum != maximum; )
2246 jpeg_image->quality=minimum+(maximum-minimum)/2;
2247 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2248 if (GetBlobSize(jpeg_image) <= extent)
2249 minimum=jpeg_image->quality+1;
2251 maximum=jpeg_image->quality-1;
2253 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2254 image->quality=minimum-1;
2255 jpeg_image=DestroyImage(jpeg_image);
2257 jpeg_info=DestroyImageInfo(jpeg_info);
2260 if ((image_info->compression != LosslessJPEGCompression) &&
2261 (image->quality <= 100))
2263 if (image->quality != UndefinedCompressionQuality)
2264 quality=(int) image->quality;
2265 if (image->debug != MagickFalse)
2266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2267 (double) image->quality);
2271 #if !defined(C_LOSSLESS_SUPPORTED)
2273 if (image->debug != MagickFalse)
2274 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2276 if (image->quality < 100)
2277 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2278 "LosslessToLossyJPEGConversion",image->filename);
2285 predictor=image->quality/100; /* range 1-7 */
2286 point_transform=image->quality % 20; /* range 0-15 */
2287 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2288 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2291 "Compression: lossless");
2292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2293 "Predictor: %d",predictor);
2294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2295 "Point Transform: %d",point_transform);
2300 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2301 sampling_factor=(const char *) NULL;
2302 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2303 if (value != (char *) NULL)
2305 sampling_factor=value;
2306 if (image->debug != MagickFalse)
2307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2308 " Input sampling-factors=%s",sampling_factor);
2310 if (image_info->sampling_factor != (char *) NULL)
2311 sampling_factor=image_info->sampling_factor;
2312 if (sampling_factor == (const char *) NULL)
2314 if (image->quality >= 90)
2315 for (i=0; i < MAX_COMPONENTS; i++)
2317 jpeg_info.comp_info[i].h_samp_factor=1;
2318 jpeg_info.comp_info[i].v_samp_factor=1;
2333 Set sampling factor.
2336 factors=SamplingFactorToList(sampling_factor);
2337 if (factors != (char **) NULL)
2339 for (i=0; i < MAX_COMPONENTS; i++)
2341 if (factors[i] == (char *) NULL)
2343 flags=ParseGeometry(factors[i],&geometry_info);
2344 if ((flags & SigmaValue) == 0)
2345 geometry_info.sigma=geometry_info.rho;
2346 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2347 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2348 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2350 factors=(char **) RelinquishMagickMemory(factors);
2352 for ( ; i < MAX_COMPONENTS; i++)
2354 jpeg_info.comp_info[i].h_samp_factor=1;
2355 jpeg_info.comp_info[i].v_samp_factor=1;
2358 if (jpeg_info.input_components == 1)
2359 for (i=0; i < MAX_COMPONENTS; i++)
2361 jpeg_info.comp_info[i].h_samp_factor=1;
2362 jpeg_info.comp_info[i].v_samp_factor=1;
2364 option=GetImageOption(image_info,"jpeg:q-table");
2365 if (option != (const char *) NULL)
2371 Custom quantization tables.
2373 table=GetQuantizationTable(option,"0",exception);
2374 if (table != (QuantizationTable *) NULL)
2376 jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2378 table=DestroyQuantizationTable(table);
2380 table=GetQuantizationTable(option,"1",exception);
2381 if (table != (QuantizationTable *) NULL)
2383 jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2385 table=DestroyQuantizationTable(table);
2387 table=GetQuantizationTable(option,"2",exception);
2388 if (table != (QuantizationTable *) NULL)
2390 jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2392 table=DestroyQuantizationTable(table);
2394 table=GetQuantizationTable(option,"3",exception);
2395 if (table != (QuantizationTable *) NULL)
2397 jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2399 table=DestroyQuantizationTable(table);
2402 jpeg_start_compress(&jpeg_info,MagickTrue);
2403 if (image->debug != MagickFalse)
2405 if (image->storage_class == PseudoClass)
2406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2407 "Storage class: PseudoClass");
2409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2410 "Storage class: DirectClass");
2411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2412 (double) image->depth);
2413 if (image->colors != 0)
2414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2415 "Number of colors: %.20g",(double) image->colors);
2417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2418 "Number of colors: unspecified");
2419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2420 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2421 switch (image->colorspace)
2423 case CMYKColorspace:
2425 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2426 "Storage class: DirectClass");
2427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2428 "Colorspace: CMYK");
2431 case YCbCrColorspace:
2432 case Rec601YCbCrColorspace:
2433 case Rec709YCbCrColorspace:
2435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2436 "Colorspace: YCbCr");
2442 switch (image->colorspace)
2444 case CMYKColorspace:
2446 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2447 "Colorspace: CMYK");
2448 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2449 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2450 jpeg_info.comp_info[0].h_samp_factor,
2451 jpeg_info.comp_info[0].v_samp_factor,
2452 jpeg_info.comp_info[1].h_samp_factor,
2453 jpeg_info.comp_info[1].v_samp_factor,
2454 jpeg_info.comp_info[2].h_samp_factor,
2455 jpeg_info.comp_info[2].v_samp_factor,
2456 jpeg_info.comp_info[3].h_samp_factor,
2457 jpeg_info.comp_info[3].v_samp_factor);
2460 case GRAYColorspace:
2461 case Rec601LumaColorspace:
2462 case Rec709LumaColorspace:
2464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2465 "Colorspace: GRAY");
2466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2467 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2468 jpeg_info.comp_info[0].v_samp_factor);
2473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2474 "Image colorspace is RGB");
2475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2476 "Sampling factors: %dx%d,%dx%d,%dx%d",
2477 jpeg_info.comp_info[0].h_samp_factor,
2478 jpeg_info.comp_info[0].v_samp_factor,
2479 jpeg_info.comp_info[1].h_samp_factor,
2480 jpeg_info.comp_info[1].v_samp_factor,
2481 jpeg_info.comp_info[2].h_samp_factor,
2482 jpeg_info.comp_info[2].v_samp_factor);
2485 case YCbCrColorspace:
2486 case Rec601YCbCrColorspace:
2487 case Rec709YCbCrColorspace:
2489 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2490 "Colorspace: YCbCr");
2491 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2492 "Sampling factors: %dx%d,%dx%d,%dx%d",
2493 jpeg_info.comp_info[0].h_samp_factor,
2494 jpeg_info.comp_info[0].v_samp_factor,
2495 jpeg_info.comp_info[1].h_samp_factor,
2496 jpeg_info.comp_info[1].v_samp_factor,
2497 jpeg_info.comp_info[2].h_samp_factor,
2498 jpeg_info.comp_info[2].v_samp_factor);
2503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2506 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2507 jpeg_info.comp_info[0].h_samp_factor,
2508 jpeg_info.comp_info[0].v_samp_factor,
2509 jpeg_info.comp_info[1].h_samp_factor,
2510 jpeg_info.comp_info[1].v_samp_factor,
2511 jpeg_info.comp_info[2].h_samp_factor,
2512 jpeg_info.comp_info[2].v_samp_factor,
2513 jpeg_info.comp_info[3].h_samp_factor,
2514 jpeg_info.comp_info[3].v_samp_factor);
2520 Write JPEG profiles.
2522 value=GetImageProperty(image,"comment",exception);
2523 if (value != (char *) NULL)
2524 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2525 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2526 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2527 if (image->profiles != (void *) NULL)
2528 WriteProfile(&jpeg_info,image);
2530 Convert MIFF to JPEG raster pixels.
2532 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2533 jpeg_info.input_components*sizeof(*jpeg_pixels));
2534 if (jpeg_pixels == (JSAMPLE *) NULL)
2535 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2536 if (setjmp(error_manager.error_recovery) != 0)
2538 jpeg_destroy_compress(&jpeg_info);
2539 if (jpeg_pixels != (unsigned char *) NULL)
2540 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2541 (void) CloseBlob(image);
2542 return(MagickFalse);
2544 scanline[0]=(JSAMPROW) jpeg_pixels;
2545 if (jpeg_info.data_precision <= 8)
2547 if ((jpeg_info.in_color_space == JCS_RGB) ||
2548 (jpeg_info.in_color_space == JCS_YCbCr))
2549 for (y=0; y < (ssize_t) image->rows; y++)
2551 register const Quantum
2557 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2558 if (p == (const Quantum *) NULL)
2561 for (x=0; x < (ssize_t) image->columns; x++)
2563 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2564 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2565 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2566 p+=GetPixelChannels(image);
2568 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2569 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2571 if (status == MagickFalse)
2575 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2576 for (y=0; y < (ssize_t) image->rows; y++)
2578 register const Quantum
2584 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2585 if (p == (const Quantum *) NULL)
2588 for (x=0; x < (ssize_t) image->columns; x++)
2590 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2591 p+=GetPixelChannels(image);
2593 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2594 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2596 if (status == MagickFalse)
2600 for (y=0; y < (ssize_t) image->rows; y++)
2602 register const Quantum
2608 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2609 if (p == (const Quantum *) NULL)
2612 for (x=0; x < (ssize_t) image->columns; x++)
2615 Convert DirectClass packets to contiguous CMYK scanlines.
2617 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2618 GetPixelRed(image,p))));
2619 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2620 GetPixelGreen(image,p))));
2621 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2622 GetPixelBlue(image,p))));
2623 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2624 GetPixelBlack(image,p))));
2625 p+=GetPixelChannels(image);
2627 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2628 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2630 if (status == MagickFalse)
2635 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2636 for (y=0; y < (ssize_t) image->rows; y++)
2638 register const Quantum
2644 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2645 if (p == (const Quantum *) NULL)
2648 for (x=0; x < (ssize_t) image->columns; x++)
2650 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >> 4);
2651 p+=GetPixelChannels(image);
2653 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2654 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2656 if (status == MagickFalse)
2660 if ((jpeg_info.in_color_space == JCS_RGB) ||
2661 (jpeg_info.in_color_space == JCS_YCbCr))
2662 for (y=0; y < (ssize_t) image->rows; y++)
2664 register const Quantum
2670 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2671 if (p == (const Quantum *) NULL)
2674 for (x=0; x < (ssize_t) image->columns; x++)
2676 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2677 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2678 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2679 p+=GetPixelChannels(image);
2681 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2682 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2684 if (status == MagickFalse)
2688 for (y=0; y < (ssize_t) image->rows; y++)
2690 register const Quantum
2696 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2697 if (p == (const Quantum *) NULL)
2700 for (x=0; x < (ssize_t) image->columns; x++)
2703 Convert DirectClass packets to contiguous CMYK scanlines.
2705 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2706 GetPixelRed(image,p)) >> 4));
2707 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2708 GetPixelGreen(image,p)) >> 4));
2709 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2710 GetPixelBlue(image,p)) >> 4));
2711 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2712 GetPixelBlack(image,p)) >> 4));
2713 p+=GetPixelChannels(image);
2715 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2716 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2718 if (status == MagickFalse)
2721 if (y == (ssize_t) image->rows)
2722 jpeg_finish_compress(&jpeg_info);
2724 Relinquish resources.
2726 jpeg_destroy_compress(&jpeg_info);
2727 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2728 (void) CloseBlob(image);