2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
46 #include "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/utility.h"
82 #if defined(MAGICKCORE_JPEG_DELEGATE)
83 #define JPEG_INTERNAL_OPTIONS
84 #if defined(__MINGW32__)
85 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
86 typedef unsigned char boolean;
97 #define ICC_MARKER (JPEG_APP0+2)
98 #define ICC_PROFILE "ICC_PROFILE"
99 #define IPTC_MARKER (JPEG_APP0+13)
100 #define XML_MARKER (JPEG_APP0+1)
101 #define MaxBufferExtent 8192
104 Typedef declarations.
106 #if defined(MAGICKCORE_JPEG_DELEGATE)
107 typedef struct _DestinationManager
109 struct jpeg_destination_mgr
117 } DestinationManager;
119 typedef struct _ErrorManager
134 typedef struct _SourceManager
136 struct jpeg_source_mgr
151 Forward declarations.
153 #if defined(MAGICKCORE_JPEG_DELEGATE)
154 static MagickBooleanType
155 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 % IsJPEG() returns MagickTrue if the image format type, identified by the
170 % magick string, is JPEG.
172 % The format of the IsJPEG method is:
174 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
176 % A description of each parameter follows:
178 % o magick: compare image format pattern against these bytes.
180 % o length: Specifies the length of the magick string.
183 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
187 if (memcmp(magick,"\377\330\377",3) == 0)
192 #if defined(MAGICKCORE_JPEG_DELEGATE)
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % R e a d J P E G I m a g e %
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
205 % the memory necessary for the new Image structure and returns a pointer to
208 % The format of the ReadJPEGImage method is:
210 % Image *ReadJPEGImage(const ImageInfo *image_info,
211 % ExceptionInfo *exception)
213 % A description of each parameter follows:
215 % o image_info: the image info.
217 % o exception: return any errors or warnings in this structure.
221 static boolean FillInputBuffer(j_decompress_ptr cinfo)
226 source=(SourceManager *) cinfo->src;
227 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
228 MaxBufferExtent,source->buffer);
229 if (source->manager.bytes_in_buffer == 0)
231 if (source->start_of_blob != 0)
232 ERREXIT(cinfo,JERR_INPUT_EMPTY);
233 WARNMS(cinfo,JWRN_JPEG_EOF);
234 source->buffer[0]=(JOCTET) 0xff;
235 source->buffer[1]=(JOCTET) JPEG_EOI;
236 source->manager.bytes_in_buffer=2;
238 source->manager.next_input_byte=source->buffer;
239 source->start_of_blob=FALSE;
243 static int GetCharacter(j_decompress_ptr jpeg_info)
245 if (jpeg_info->src->bytes_in_buffer == 0)
246 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
247 jpeg_info->src->bytes_in_buffer--;
248 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
251 static void InitializeSource(j_decompress_ptr cinfo)
256 source=(SourceManager *) cinfo->src;
257 source->start_of_blob=TRUE;
260 static MagickBooleanType IsITUFaxImage(const Image *image)
268 profile=GetImageProfile(image,"8bim");
269 if (profile == (const StringInfo *) NULL)
271 if (GetStringInfoLength(profile) < 5)
273 datum=GetStringInfoDatum(profile);
274 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
275 (datum[3] == 0x41) && (datum[4] == 0x58))
280 static void JPEGErrorHandler(j_common_ptr jpeg_info)
283 message[JMSG_LENGTH_MAX];
295 error_manager=(ErrorManager *) jpeg_info->client_data;
296 image=error_manager->image;
297 exception=error_manager->exception;
298 (jpeg_info->err->format_message)(jpeg_info,message);
299 if (image->debug != MagickFalse)
300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
301 "[%s] JPEG Trace: \"%s\"",image->filename,message);
302 if (error_manager->finished != MagickFalse)
303 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
304 (char *) message,"`%s'",image->filename);
306 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
307 (char *) message,"`%s'",image->filename);
308 longjmp(error_manager->error_recovery,1);
311 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
314 message[JMSG_LENGTH_MAX];
326 error_manager=(ErrorManager *) jpeg_info->client_data;
327 exception=error_manager->exception;
328 image=error_manager->image;
332 Process warning message.
334 (jpeg_info->err->format_message)(jpeg_info,message);
335 if ((jpeg_info->err->num_warnings == 0) ||
336 (jpeg_info->err->trace_level >= 3))
337 ThrowBinaryException(CorruptImageWarning,(char *) message,
339 jpeg_info->err->num_warnings++;
342 if ((image->debug != MagickFalse) &&
343 (level >= jpeg_info->err->trace_level))
346 Process trace message.
348 (jpeg_info->err->format_message)(jpeg_info,message);
349 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
350 "[%s] JPEG Trace: \"%s\"",image->filename,message);
355 static boolean ReadComment(j_decompress_ptr jpeg_info)
379 Determine length of comment.
381 error_manager=(ErrorManager *) jpeg_info->client_data;
382 exception=error_manager->exception;
383 image=error_manager->image;
384 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
385 length+=GetCharacter(jpeg_info);
389 comment=(char *) NULL;
390 if (~length >= (MaxTextExtent-1))
391 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
393 if (comment == (char *) NULL)
394 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
399 i=(ssize_t) length-1;
400 for (p=comment; i-- >= 0; p++)
401 *p=(char) GetCharacter(jpeg_info);
403 (void) SetImageProperty(image,"comment",comment,exception);
404 comment=DestroyString(comment);
408 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
428 register unsigned char
441 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
442 length+=(size_t) GetCharacter(jpeg_info);
447 (void) GetCharacter(jpeg_info);
450 for (i=0; i < 12; i++)
451 magick[i]=(char) GetCharacter(jpeg_info);
452 if (LocaleCompare(magick,ICC_PROFILE) != 0)
455 Not a ICC profile, return.
457 for (i=0; i < (ssize_t) (length-12); i++)
458 (void) GetCharacter(jpeg_info);
461 (void) GetCharacter(jpeg_info); /* id */
462 (void) GetCharacter(jpeg_info); /* markers */
464 error_manager=(ErrorManager *) jpeg_info->client_data;
465 exception=error_manager->exception;
466 image=error_manager->image;
467 profile=BlobToStringInfo((const void *) NULL,length);
468 if (profile == (StringInfo *) NULL)
469 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
471 p=GetStringInfoDatum(profile);
472 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
473 *p++=(unsigned char) GetCharacter(jpeg_info);
474 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
475 if (icc_profile != (StringInfo *) NULL)
477 ConcatenateStringInfo(icc_profile,profile);
478 profile=DestroyStringInfo(profile);
482 status=SetImageProfile(image,"icc",profile,exception);
483 profile=DestroyStringInfo(profile);
484 if (status == MagickFalse)
485 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
488 if (image->debug != MagickFalse)
489 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
490 "Profile: ICC, %.20g bytes",(double) length);
494 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
497 magick[MaxTextExtent];
514 register unsigned char
525 Determine length of binary data stored here.
527 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
528 length+=(size_t) GetCharacter(jpeg_info);
533 (void) GetCharacter(jpeg_info);
537 Validate that this was written as a Photoshop resource format slug.
539 for (i=0; i < 10; i++)
540 magick[i]=(char) GetCharacter(jpeg_info);
545 if (LocaleCompare(magick,"Photoshop ") != 0)
548 Not a IPTC profile, return.
550 for (i=0; i < (ssize_t) length; i++)
551 (void) GetCharacter(jpeg_info);
555 Remove the version number.
557 for (i=0; i < 4; i++)
558 (void) GetCharacter(jpeg_info);
564 error_manager=(ErrorManager *) jpeg_info->client_data;
565 exception=error_manager->exception;
566 image=error_manager->image;
567 profile=BlobToStringInfo((const void *) NULL,length);
568 if (profile == (StringInfo *) NULL)
569 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
571 p=GetStringInfoDatum(profile);
572 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
573 *p++=(unsigned char) GetCharacter(jpeg_info);
574 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
575 if (iptc_profile != (StringInfo *) NULL)
577 ConcatenateStringInfo(iptc_profile,profile);
578 profile=DestroyStringInfo(profile);
582 status=SetImageProfile(image,"8bim",profile,exception);
583 profile=DestroyStringInfo(profile);
584 if (status == MagickFalse)
585 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
588 if (image->debug != MagickFalse)
589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
590 "Profile: iptc, %.20g bytes",(double) length);
594 static boolean ReadProfile(j_decompress_ptr jpeg_info)
620 register unsigned char
630 Read generic profile.
632 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
633 length+=(size_t) GetCharacter(jpeg_info);
637 marker=jpeg_info->unread_marker-JPEG_APP0;
638 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
639 error_manager=(ErrorManager *) jpeg_info->client_data;
640 exception=error_manager->exception;
641 image=error_manager->image;
642 profile=BlobToStringInfo((const void *) NULL,length);
643 if (profile == (StringInfo *) NULL)
644 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
646 p=GetStringInfoDatum(profile);
647 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
648 *p++=(unsigned char) GetCharacter(jpeg_info);
651 p=GetStringInfoDatum(profile);
652 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
653 (void) CopyMagickString(name,"exif",MaxTextExtent);
654 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
660 Extract namespace from XMP profile.
662 p=GetStringInfoDatum(profile);
663 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
669 if (j < (ssize_t) GetStringInfoLength(profile))
670 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
671 (void) CopyMagickString(name,"xmp",MaxTextExtent);
674 previous_profile=GetImageProfile(image,name);
675 if (previous_profile != (const StringInfo *) NULL)
680 length=GetStringInfoLength(profile);
681 SetStringInfoLength(profile,GetStringInfoLength(profile)+
682 GetStringInfoLength(previous_profile));
683 (void) memmove(GetStringInfoDatum(profile)+
684 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
686 (void) memcpy(GetStringInfoDatum(profile),
687 GetStringInfoDatum(previous_profile),
688 GetStringInfoLength(previous_profile));
690 status=SetImageProfile(image,name,profile,exception);
691 profile=DestroyStringInfo(profile);
692 if (status == MagickFalse)
693 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
695 if (image->debug != MagickFalse)
696 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
697 "Profile: %s, %.20g bytes",name,(double) length);
701 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
706 if (number_bytes <= 0)
708 source=(SourceManager *) cinfo->src;
709 while (number_bytes > (long) source->manager.bytes_in_buffer)
711 number_bytes-=(long) source->manager.bytes_in_buffer;
712 (void) FillInputBuffer(cinfo);
714 source->manager.next_input_byte+=number_bytes;
715 source->manager.bytes_in_buffer-=number_bytes;
718 static void TerminateSource(j_decompress_ptr cinfo)
723 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
728 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
729 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
730 source=(SourceManager *) cinfo->src;
731 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
732 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
733 source=(SourceManager *) cinfo->src;
734 source->manager.init_source=InitializeSource;
735 source->manager.fill_input_buffer=FillInputBuffer;
736 source->manager.skip_input_data=SkipInputData;
737 source->manager.resync_to_restart=jpeg_resync_to_restart;
738 source->manager.term_source=TerminateSource;
739 source->manager.bytes_in_buffer=0;
740 source->manager.next_input_byte=NULL;
744 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
747 image->quality=UndefinedCompressionQuality;
748 #if defined(D_PROGRESSIVE_SUPPORTED)
749 if (image->compression == LosslessJPEGCompression)
752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
753 "Quality: 100 (lossless)");
767 Determine the JPEG compression quality from the quantization tables.
770 for (i=0; i < NUM_QUANT_TBLS; i++)
772 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
773 for (j=0; j < DCTSIZE2; j++)
774 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
776 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
777 (jpeg_info->quant_tbl_ptrs[1] != NULL))
782 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
783 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
784 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
785 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
786 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
787 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
788 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
789 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
790 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
791 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
796 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
797 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
798 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
799 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
800 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
801 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
802 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
803 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
804 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
805 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
806 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
810 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
811 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
812 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
813 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
814 for (i=0; i < 100; i++)
816 if ((qvalue < hash[i]) && (sum < sums[i]))
818 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
819 image->quality=(size_t) i+1;
820 if (image->debug != MagickFalse)
821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
822 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
823 (sum <= sums[i]) ? "exact" : "approximate");
828 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
833 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
834 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
835 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
836 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
837 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
838 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
839 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
840 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
841 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
842 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
847 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
848 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
849 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
850 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
851 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
852 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
853 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
854 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
855 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
856 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
857 667, 592, 518, 441, 369, 292, 221, 151, 86,
861 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
862 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
863 for (i=0; i < 100; i++)
865 if ((qvalue < hash[i]) && (sum < sums[i]))
867 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
868 image->quality=(size_t) i+1;
869 if (image->debug != MagickFalse)
870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
871 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
872 (sum <= sums[i]) ? "exact" : "approximate");
879 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
882 sampling_factor[MaxTextExtent];
884 switch (jpeg_info->out_color_space)
888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
889 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
890 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
891 jpeg_info->comp_info[0].v_samp_factor,
892 jpeg_info->comp_info[1].h_samp_factor,
893 jpeg_info->comp_info[1].v_samp_factor,
894 jpeg_info->comp_info[2].h_samp_factor,
895 jpeg_info->comp_info[2].v_samp_factor,
896 jpeg_info->comp_info[3].h_samp_factor,
897 jpeg_info->comp_info[3].v_samp_factor);
902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
903 "Colorspace: GRAYSCALE");
904 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
905 jpeg_info->comp_info[0].h_samp_factor,
906 jpeg_info->comp_info[0].v_samp_factor);
911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
912 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
913 "%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);
923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
924 jpeg_info->out_color_space);
925 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
926 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
927 jpeg_info->comp_info[0].v_samp_factor,
928 jpeg_info->comp_info[1].h_samp_factor,
929 jpeg_info->comp_info[1].v_samp_factor,
930 jpeg_info->comp_info[2].h_samp_factor,
931 jpeg_info->comp_info[2].v_samp_factor,
932 jpeg_info->comp_info[3].h_samp_factor,
933 jpeg_info->comp_info[3].v_samp_factor);
937 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
943 static Image *ReadJPEGImage(const ImageInfo *image_info,
944 ExceptionInfo *exception)
947 value[MaxTextExtent];
977 struct jpeg_decompress_struct
980 struct jpeg_error_mgr
996 assert(image_info != (const ImageInfo *) NULL);
997 assert(image_info->signature == MagickSignature);
998 if (image_info->debug != MagickFalse)
999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1000 image_info->filename);
1001 assert(exception != (ExceptionInfo *) NULL);
1002 assert(exception->signature == MagickSignature);
1003 debug=IsEventLogging();
1005 image=AcquireImage(image_info,exception);
1006 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1007 if (status == MagickFalse)
1009 image=DestroyImageList(image);
1010 return((Image *) NULL);
1013 Initialize JPEG parameters.
1015 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1016 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1017 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1018 jpeg_info.err=jpeg_std_error(&jpeg_error);
1019 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1020 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1021 jpeg_pixels=(JSAMPLE *) NULL;
1022 error_manager.exception=exception;
1023 error_manager.image=image;
1024 if (setjmp(error_manager.error_recovery) != 0)
1026 jpeg_destroy_decompress(&jpeg_info);
1027 (void) CloseBlob(image);
1028 number_pixels=(MagickSizeType) image->columns*image->rows;
1029 if (number_pixels != 0)
1030 return(GetFirstImageInList(image));
1031 return(DestroyImage(image));
1033 jpeg_info.client_data=(void *) &error_manager;
1034 jpeg_create_decompress(&jpeg_info);
1035 JPEGSourceManager(&jpeg_info,image);
1036 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1037 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1038 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1039 for (i=1; i < 16; i++)
1040 if ((i != 2) && (i != 13) && (i != 14))
1041 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1042 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1043 if ((image_info->colorspace == YCbCrColorspace) ||
1044 (image_info->colorspace == Rec601YCbCrColorspace) ||
1045 (image_info->colorspace == Rec709YCbCrColorspace))
1046 jpeg_info.out_color_space=JCS_YCbCr;
1047 if (IsITUFaxImage(image) != MagickFalse)
1049 image->colorspace=LabColorspace;
1050 jpeg_info.out_color_space=JCS_YCbCr;
1053 if (jpeg_info.out_color_space == JCS_CMYK)
1054 image->colorspace=CMYKColorspace;
1056 Set image resolution.
1059 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1060 (jpeg_info.Y_density != 1))
1062 image->resolution.x=(double) jpeg_info.X_density;
1063 image->resolution.y=(double) jpeg_info.Y_density;
1064 units=(size_t) jpeg_info.density_unit;
1067 image->units=PixelsPerInchResolution;
1069 image->units=PixelsPerCentimeterResolution;
1070 number_pixels=(MagickSizeType) image->columns*image->rows;
1071 option=GetImageOption(image_info,"jpeg:size");
1072 if (option != (const char *) NULL)
1086 flags=ParseGeometry(option,&geometry_info);
1087 if ((flags & SigmaValue) == 0)
1088 geometry_info.sigma=geometry_info.rho;
1089 jpeg_calc_output_dimensions(&jpeg_info);
1090 image->magick_columns=jpeg_info.output_width;
1091 image->magick_rows=jpeg_info.output_height;
1093 if (geometry_info.rho != 0.0)
1094 scale_factor=jpeg_info.output_width/geometry_info.rho;
1095 if ((geometry_info.sigma != 0.0) &&
1096 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1097 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1098 jpeg_info.scale_num=1U;
1099 jpeg_info.scale_denom=(unsigned int) scale_factor;
1100 jpeg_calc_output_dimensions(&jpeg_info);
1101 if (image->debug != MagickFalse)
1102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1103 "Scale factor: %.20g",(double) scale_factor);
1105 precision=(size_t) jpeg_info.data_precision;
1106 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1107 #if defined(D_LOSSLESS_SUPPORTED)
1108 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1109 JPEGInterlace : NoInterlace;
1110 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1111 LosslessJPEGCompression : JPEGCompression;
1112 if (jpeg_info.data_precision > 8)
1113 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1114 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1116 if (jpeg_info.data_precision == 16)
1117 jpeg_info.data_precision=12;
1119 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1121 image->compression=JPEGCompression;
1124 image->compression=JPEGCompression;
1125 image->interlace=JPEGInterlace;
1127 option=GetImageOption(image_info,"jpeg:colors");
1128 if (option != (const char *) NULL)
1130 /* Let the JPEG library quantize the image */
1131 jpeg_info.quantize_colors=MagickTrue;
1132 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1134 option=GetImageOption(image_info,"jpeg:block-smoothing");
1135 if (option != (const char *) NULL)
1137 jpeg_info.do_block_smoothing=MagickFalse;
1138 if (IsMagickTrue(option) != MagickFalse)
1139 jpeg_info.do_block_smoothing=MagickTrue;
1141 option=GetImageOption(image_info,"jpeg:dct-method");
1142 if (option != (const char *) NULL)
1148 if (LocaleCompare(option,"default") == 0)
1149 jpeg_info.dct_method=JDCT_DEFAULT;
1155 if (LocaleCompare(option,"fastest") == 0)
1156 jpeg_info.dct_method=JDCT_FASTEST;
1157 if (LocaleCompare(option,"float") == 0)
1158 jpeg_info.dct_method=JDCT_FLOAT;
1164 if (LocaleCompare(option,"ifast") == 0)
1165 jpeg_info.dct_method=JDCT_IFAST;
1166 if (LocaleCompare(option,"islow") == 0)
1167 jpeg_info.dct_method=JDCT_ISLOW;
1171 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1172 if (option != (const char *) NULL)
1174 jpeg_info.do_fancy_upsampling=MagickFalse;
1175 if (IsMagickTrue(option) != MagickFalse)
1176 jpeg_info.do_fancy_upsampling=MagickTrue;
1178 (void) jpeg_start_decompress(&jpeg_info);
1179 image->columns=jpeg_info.output_width;
1180 image->rows=jpeg_info.output_height;
1181 image->depth=(size_t) jpeg_info.data_precision;
1182 if (jpeg_info.out_color_space == JCS_YCbCr)
1183 image->colorspace=YCbCrColorspace;
1184 if (jpeg_info.out_color_space == JCS_CMYK)
1185 image->colorspace=CMYKColorspace;
1186 option=GetImageOption(image_info,"jpeg:colors");
1187 if (option != (const char *) NULL)
1188 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1190 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1191 if ((jpeg_info.output_components == 1) &&
1192 (jpeg_info.quantize_colors == MagickFalse))
1197 colors=(size_t) GetQuantumRange(image->depth)+1;
1198 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1199 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1201 if (image->debug != MagickFalse)
1203 if (image->interlace != NoInterlace)
1204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1205 "Interlace: progressive");
1207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1208 "Interlace: nonprogressive");
1209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1210 (int) jpeg_info.data_precision);
1211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1212 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1214 JPEGSetImageQuality(&jpeg_info,image);
1215 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1216 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1217 jpeg_info.out_color_space);
1218 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1219 if (image_info->ping != MagickFalse)
1221 jpeg_destroy_decompress(&jpeg_info);
1222 (void) CloseBlob(image);
1223 return(GetFirstImageInList(image));
1225 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1226 jpeg_info.output_components*sizeof(JSAMPLE));
1227 if (jpeg_pixels == (JSAMPLE *) NULL)
1228 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1230 Convert JPEG pixels to pixel packets.
1232 if (setjmp(error_manager.error_recovery) != 0)
1234 if (jpeg_pixels != (unsigned char *) NULL)
1235 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1236 jpeg_destroy_decompress(&jpeg_info);
1237 (void) CloseBlob(image);
1238 number_pixels=(MagickSizeType) image->columns*image->rows;
1239 if (number_pixels != 0)
1240 return(GetFirstImageInList(image));
1241 return(DestroyImage(image));
1243 if (jpeg_info.quantize_colors != MagickFalse)
1245 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1246 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1247 for (i=0; i < (ssize_t) image->colors; i++)
1249 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1250 image->colormap[i].green=image->colormap[i].red;
1251 image->colormap[i].blue=image->colormap[i].red;
1252 image->colormap[i].alpha=OpaqueAlpha;
1255 for (i=0; i < (ssize_t) image->colors; i++)
1257 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1258 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1259 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1260 image->colormap[i].alpha=OpaqueAlpha;
1263 scanline[0]=(JSAMPROW) jpeg_pixels;
1264 for (y=0; y < (ssize_t) image->rows; y++)
1272 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1274 (void) ThrowMagickException(exception,GetMagickModule(),
1275 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1279 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1280 if (q == (Quantum *) NULL)
1282 if (jpeg_info.data_precision > 8)
1284 if (jpeg_info.output_components == 1)
1285 for (x=0; x < (ssize_t) image->columns; x++)
1290 if (precision != 16)
1291 pixel=(size_t) GETJSAMPLE(*p);
1293 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1294 index=ConstrainColormapIndex(image,pixel,exception);
1295 SetPixelIndex(image,index,q);
1296 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1298 q+=GetPixelChannels(image);
1301 if (image->colorspace != CMYKColorspace)
1302 for (x=0; x < (ssize_t) image->columns; x++)
1304 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1305 (GETJSAMPLE(*p++) << 4)),q);
1306 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1307 (GETJSAMPLE(*p++) << 4)),q);
1308 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1309 (GETJSAMPLE(*p++) << 4)),q);
1310 SetPixelAlpha(image,OpaqueAlpha,q);
1311 q+=GetPixelChannels(image);
1314 for (x=0; x < (ssize_t) image->columns; x++)
1316 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1317 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1318 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1319 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1320 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1321 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1322 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1323 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1324 SetPixelAlpha(image,OpaqueAlpha,q);
1325 q+=GetPixelChannels(image);
1329 if (jpeg_info.output_components == 1)
1330 for (x=0; x < (ssize_t) image->columns; x++)
1332 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1333 SetPixelIndex(image,index,q);
1334 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1336 q+=GetPixelChannels(image);
1339 if (image->colorspace != CMYKColorspace)
1340 for (x=0; x < (ssize_t) image->columns; x++)
1342 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1343 GETJSAMPLE(*p++)),q);
1344 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1345 GETJSAMPLE(*p++)),q);
1346 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1347 GETJSAMPLE(*p++)),q);
1348 SetPixelAlpha(image,OpaqueAlpha,q);
1349 q+=GetPixelChannels(image);
1352 for (x=0; x < (ssize_t) image->columns; x++)
1354 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1355 (unsigned char) GETJSAMPLE(*p++)),q);
1356 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1357 (unsigned char) GETJSAMPLE(*p++)),q);
1358 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1359 (unsigned char) GETJSAMPLE(*p++)),q);
1360 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1361 (unsigned char) GETJSAMPLE(*p++)),q);
1362 SetPixelAlpha(image,OpaqueAlpha,q);
1363 q+=GetPixelChannels(image);
1365 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1367 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1369 if (status == MagickFalse)
1371 jpeg_abort_decompress(&jpeg_info);
1375 if (status != MagickFalse)
1377 error_manager.finished=MagickTrue;
1378 if (setjmp(error_manager.error_recovery) == 0)
1379 (void) jpeg_finish_decompress(&jpeg_info);
1382 Free jpeg resources.
1384 jpeg_destroy_decompress(&jpeg_info);
1385 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1386 (void) CloseBlob(image);
1387 return(GetFirstImageInList(image));
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 % R e g i s t e r J P E G I m a g e %
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % RegisterJPEGImage() adds properties for the JPEG image format to
1403 % the list of supported formats. The properties include the image format
1404 % tag, a method to read and/or write the format, whether the format
1405 % supports the saving of more than one frame to the same file or blob,
1406 % whether the format supports native in-memory I/O, and a brief
1407 % description of the format.
1409 % The format of the RegisterJPEGImage method is:
1411 % size_t RegisterJPEGImage(void)
1414 ModuleExport size_t RegisterJPEGImage(void)
1417 version[MaxTextExtent];
1423 description[] = "Joint Photographic Experts Group JFIF format";
1426 #if defined(JPEG_LIB_VERSION)
1427 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1429 entry=SetMagickInfo("JPEG");
1430 entry->thread_support=NoThreadSupport;
1431 #if defined(MAGICKCORE_JPEG_DELEGATE)
1432 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1433 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1435 entry->magick=(IsImageFormatHandler *) IsJPEG;
1436 entry->adjoin=MagickFalse;
1437 entry->description=ConstantString(description);
1438 if (*version != '\0')
1439 entry->version=ConstantString(version);
1440 entry->module=ConstantString("JPEG");
1441 (void) RegisterMagickInfo(entry);
1442 entry=SetMagickInfo("JPG");
1443 entry->thread_support=NoThreadSupport;
1444 #if defined(MAGICKCORE_JPEG_DELEGATE)
1445 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1446 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1448 entry->adjoin=MagickFalse;
1449 entry->description=ConstantString(description);
1450 if (*version != '\0')
1451 entry->version=ConstantString(version);
1452 entry->module=ConstantString("JPEG");
1453 (void) RegisterMagickInfo(entry);
1454 entry=SetMagickInfo("PJPEG");
1455 entry->thread_support=NoThreadSupport;
1456 #if defined(MAGICKCORE_JPEG_DELEGATE)
1457 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1458 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1460 entry->adjoin=MagickFalse;
1461 entry->description=ConstantString(description);
1462 if (*version != '\0')
1463 entry->version=ConstantString(version);
1464 entry->module=ConstantString("JPEG");
1465 (void) RegisterMagickInfo(entry);
1466 return(MagickImageCoderSignature);
1470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474 % U n r e g i s t e r J P E G I m a g e %
1478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 % UnregisterJPEGImage() removes format registrations made by the
1481 % JPEG module from the list of supported formats.
1483 % The format of the UnregisterJPEGImage method is:
1485 % UnregisterJPEGImage(void)
1488 ModuleExport void UnregisterJPEGImage(void)
1490 (void) UnregisterMagickInfo("PJPG");
1491 (void) UnregisterMagickInfo("JPEG");
1492 (void) UnregisterMagickInfo("JPG");
1495 #if defined(MAGICKCORE_JPEG_DELEGATE)
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501 % W r i t e J P E G I m a g e %
1505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1507 % WriteJPEGImage() writes a JPEG image file and returns it. It
1508 % allocates the memory necessary for the new Image structure and returns a
1509 % pointer to the new image.
1511 % The format of the WriteJPEGImage method is:
1513 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1514 % Image *image,ExceptionInfo *exception)
1516 % A description of each parameter follows:
1518 % o image_info: the image info.
1520 % o jpeg_image: The image.
1522 % o exception: return any errors or warnings in this structure.
1526 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1531 destination=(DestinationManager *) cinfo->dest;
1532 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1533 MaxBufferExtent,destination->buffer);
1534 if (destination->manager.free_in_buffer != MaxBufferExtent)
1535 ERREXIT(cinfo,JERR_FILE_WRITE);
1536 destination->manager.next_output_byte=destination->buffer;
1540 static void InitializeDestination(j_compress_ptr cinfo)
1545 destination=(DestinationManager *) cinfo->dest;
1546 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1547 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1548 destination->manager.next_output_byte=destination->buffer;
1549 destination->manager.free_in_buffer=MaxBufferExtent;
1552 static inline size_t MagickMin(const size_t x,const size_t y)
1559 static void TerminateDestination(j_compress_ptr cinfo)
1564 destination=(DestinationManager *) cinfo->dest;
1565 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1570 count=WriteBlob(destination->image,MaxBufferExtent-
1571 destination->manager.free_in_buffer,destination->buffer);
1572 if (count != (ssize_t)
1573 (MaxBufferExtent-destination->manager.free_in_buffer))
1574 ERREXIT(cinfo,JERR_FILE_WRITE);
1578 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1600 Save image profile as a APP marker.
1603 custom_profile=AcquireStringInfo(65535L);
1604 ResetImageProfileIterator(image);
1605 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1607 register unsigned char
1610 profile=GetImageProfile(image,name);
1611 p=GetStringInfoDatum(custom_profile);
1612 if (LocaleCompare(name,"EXIF") == 0)
1613 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1615 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1616 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1617 (unsigned int) length);
1619 if (LocaleCompare(name,"ICC") == 0)
1621 register unsigned char
1625 p=GetStringInfoDatum(custom_profile);
1626 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1627 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1629 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1630 p[12]=(unsigned char) ((i/65519L)+1);
1631 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1632 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1634 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1635 custom_profile),(unsigned int) (length+tag_length));
1638 if (((LocaleCompare(name,"IPTC") == 0) ||
1639 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1645 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1647 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1648 roundup=(size_t) (length & 0x01);
1649 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1651 (void) memcpy(p,"Photoshop 3.0 ",14);
1656 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1658 p[24]=(unsigned char) (length >> 8);
1659 p[25]=(unsigned char) (length & 0xff);
1662 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1664 p[length+tag_length]='\0';
1665 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1666 custom_profile),(unsigned int) (length+tag_length+roundup));
1669 if (LocaleCompare(name,"XMP") == 0)
1675 Add namespace to XMP profile.
1677 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1678 ConcatenateStringInfo(xmp_profile,profile);
1679 GetStringInfoDatum(xmp_profile)[28]='\0';
1680 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1682 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1683 jpeg_write_marker(jpeg_info,XML_MARKER,
1684 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1686 xmp_profile=DestroyStringInfo(xmp_profile);
1688 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1689 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1690 name=GetNextImageProfile(image);
1692 custom_profile=DestroyStringInfo(custom_profile);
1695 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1700 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1701 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1702 destination=(DestinationManager *) cinfo->dest;
1703 destination->manager.init_destination=InitializeDestination;
1704 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1705 destination->manager.term_destination=TerminateDestination;
1706 destination->image=image;
1709 static char **SamplingFactorToList(const char *text)
1726 if (text == (char *) NULL)
1727 return((char **) NULL);
1729 Convert string to an ASCII list.
1732 for (p=text; *p != '\0'; p++)
1735 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1737 if (textlist == (char **) NULL)
1738 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1740 for (i=0; i < (ssize_t) lines; i++)
1742 for (q=(char *) p; *q != '\0'; q++)
1745 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1746 sizeof(*textlist[i]));
1747 if (textlist[i] == (char *) NULL)
1748 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1749 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1754 textlist[i]=(char *) NULL;
1758 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1759 Image *image,ExceptionInfo *exception)
1790 struct jpeg_compress_struct
1793 struct jpeg_error_mgr
1796 static const unsigned int
1797 CbQTable[DCTSIZE2] =
1799 17, 19, 24, 37, 68, 148, 384, 1186,
1800 19, 20, 26, 40, 74, 162, 419, 1293,
1801 24, 26, 34, 52, 96, 210, 544, 1676,
1802 37, 40, 52, 81, 148, 323, 838, 2585,
1803 68, 74, 96, 148, 272, 593, 1537, 4741,
1804 148, 162, 210, 323, 593, 1293, 3353, 10338,
1805 384, 419, 544, 838, 1537, 3353, 8694, 12725,
1806 1186, 1293, 1676, 2585, 4741, 10338, 12725, 12725
1808 CrQTable[DCTSIZE2] =
1810 17, 18, 22, 31, 50, 92, 193, 465,
1811 18, 19, 24, 33, 54, 98, 207, 498,
1812 22, 24, 29, 41, 66, 120, 253, 609,
1813 31, 33, 41, 57, 92, 169, 355, 854,
1814 50, 54, 66, 92, 148, 271, 570, 1370,
1815 92, 98, 120, 169, 271, 498, 1046, 2516,
1816 193, 207, 253, 355, 570, 1046, 2198, 5289,
1817 465, 498, 609, 854, 1370, 2516, 5289, 12725
1819 LuminanceQTable[DCTSIZE2] =
1821 16, 11, 11, 15, 21, 34, 50, 65,
1822 11, 12, 13, 18, 24, 48, 62, 69,
1823 13, 13, 16, 23, 38, 56, 72, 71,
1824 15, 18, 23, 29, 53, 77, 83, 80,
1825 21, 24, 38, 53, 68, 98, 104, 100,
1826 30, 44, 56, 73, 92, 105, 117, 117,
1827 50, 62, 74, 83, 104, 119, 121, 122,
1828 67, 77, 79, 88, 108, 119, 122, 122
1834 assert(image_info != (const ImageInfo *) NULL);
1835 assert(image_info->signature == MagickSignature);
1836 assert(image != (Image *) NULL);
1837 assert(image->signature == MagickSignature);
1838 if (image->debug != MagickFalse)
1839 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1840 assert(exception != (ExceptionInfo *) NULL);
1841 assert(exception->signature == MagickSignature);
1842 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1843 if (status == MagickFalse)
1846 Initialize JPEG parameters.
1848 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1849 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1850 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1851 jpeg_info.client_data=(void *) image;
1852 jpeg_info.err=jpeg_std_error(&jpeg_error);
1853 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1854 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1855 error_manager.exception=exception;
1856 error_manager.image=image;
1857 jpeg_pixels=(JSAMPLE *) NULL;
1858 if (setjmp(error_manager.error_recovery) != 0)
1860 jpeg_destroy_compress(&jpeg_info);
1861 (void) CloseBlob(image);
1862 return(MagickFalse);
1864 jpeg_info.client_data=(void *) &error_manager;
1865 jpeg_create_compress(&jpeg_info);
1866 JPEGDestinationManager(&jpeg_info,image);
1867 if ((image->columns != (unsigned int) image->columns) ||
1868 (image->rows != (unsigned int) image->rows))
1869 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1870 jpeg_info.image_width=(unsigned int) image->columns;
1871 jpeg_info.image_height=(unsigned int) image->rows;
1872 jpeg_info.input_components=3;
1873 jpeg_info.data_precision=8;
1874 jpeg_info.in_color_space=JCS_RGB;
1875 switch (image->colorspace)
1877 case CMYKColorspace:
1879 jpeg_info.input_components=4;
1880 jpeg_info.in_color_space=JCS_CMYK;
1883 case YCbCrColorspace:
1884 case Rec601YCbCrColorspace:
1885 case Rec709YCbCrColorspace:
1887 jpeg_info.in_color_space=JCS_YCbCr;
1890 case GRAYColorspace:
1891 case Rec601LumaColorspace:
1892 case Rec709LumaColorspace:
1894 jpeg_info.input_components=1;
1895 jpeg_info.in_color_space=JCS_GRAYSCALE;
1900 if (IsRGBColorspace(image->colorspace) == MagickFalse)
1901 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1905 if ((image_info->type != TrueColorType) &&
1906 (IsImageGray(image,exception) != MagickFalse))
1908 jpeg_info.input_components=1;
1909 jpeg_info.in_color_space=JCS_GRAYSCALE;
1911 jpeg_set_defaults(&jpeg_info);
1912 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1913 jpeg_info.data_precision=8;
1915 if (sizeof(JSAMPLE) > 1)
1916 jpeg_info.data_precision=12;
1917 jpeg_info.density_unit=(UINT8) 1;
1918 if (image->debug != MagickFalse)
1919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1920 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
1921 floor(image->resolution.y+0.5));
1922 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
1925 Set image resolution.
1927 jpeg_info.write_JFIF_header=MagickTrue;
1928 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
1929 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
1930 if (image->units == PixelsPerInchResolution)
1931 jpeg_info.density_unit=(UINT8) 1;
1932 if (image->units == PixelsPerCentimeterResolution)
1933 jpeg_info.density_unit=(UINT8) 2;
1935 option=GetImageOption(image_info,"jpeg:dct-method");
1936 if (option != (const char *) NULL)
1942 if (LocaleCompare(option,"default") == 0)
1943 jpeg_info.dct_method=JDCT_DEFAULT;
1949 if (LocaleCompare(option,"fastest") == 0)
1950 jpeg_info.dct_method=JDCT_FASTEST;
1951 if (LocaleCompare(option,"float") == 0)
1952 jpeg_info.dct_method=JDCT_FLOAT;
1958 if (LocaleCompare(option,"ifast") == 0)
1959 jpeg_info.dct_method=JDCT_IFAST;
1960 if (LocaleCompare(option,"islow") == 0)
1961 jpeg_info.dct_method=JDCT_ISLOW;
1965 option=GetImageOption(image_info,"jpeg:optimize-coding");
1966 if (option != (const char *) NULL)
1968 jpeg_info.optimize_coding=MagickFalse;
1969 if (IsMagickTrue(option) != MagickFalse)
1970 jpeg_info.optimize_coding=MagickTrue;
1977 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1978 image->rows*sizeof(JSAMPLE);
1979 if (length == (MagickSizeType) ((size_t) length))
1982 Perform optimization only if available memory resources permit it.
1984 status=AcquireMagickResource(MemoryResource,length);
1985 if (status != MagickFalse)
1986 jpeg_info.optimize_coding=MagickTrue;
1987 RelinquishMagickResource(MemoryResource,length);
1990 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1991 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1992 (image_info->interlace != NoInterlace))
1994 if (image->debug != MagickFalse)
1995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1996 "Interlace: progressive");
1997 jpeg_simple_progression(&jpeg_info);
2000 if (image->debug != MagickFalse)
2001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2002 "Interlace: non-progressive");
2004 if (image->debug != MagickFalse)
2005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2006 "Interlace: nonprogressive");
2008 option=GetImageOption(image_info,"jpeg:extent");
2009 if (option != (const char *) NULL)
2017 jpeg_info=CloneImageInfo(image_info);
2018 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2019 if (jpeg_image != (Image *) NULL)
2029 Search for compression quality that does not exceed image extent.
2031 jpeg_info->quality=0;
2032 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2033 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2034 (void) AcquireUniqueFilename(jpeg_image->filename);
2036 for (minimum=0; minimum != maximum; )
2038 jpeg_image->quality=minimum+(maximum-minimum)/2;
2039 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2040 if (GetBlobSize(jpeg_image) <= extent)
2041 minimum=jpeg_image->quality+1;
2043 maximum=jpeg_image->quality-1;
2045 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2046 image->quality=minimum-1;
2047 jpeg_image=DestroyImage(jpeg_image);
2049 jpeg_info=DestroyImageInfo(jpeg_info);
2052 if ((image_info->compression != LosslessJPEGCompression) &&
2053 (image->quality <= 100))
2055 if (image->quality != UndefinedCompressionQuality)
2056 quality=(int) image->quality;
2057 if (image->debug != MagickFalse)
2058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2059 (double) image->quality);
2063 #if !defined(C_LOSSLESS_SUPPORTED)
2065 if (image->debug != MagickFalse)
2066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2068 if (image->quality < 100)
2069 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2070 "LosslessToLossyJPEGConversion",image->filename);
2077 predictor=image->quality/100; /* range 1-7 */
2078 point_transform=image->quality % 20; /* range 0-15 */
2079 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2080 if (image->debug != MagickFalse)
2082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2083 "Compression: lossless");
2084 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2085 "Predictor: %d",predictor);
2086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2087 "Point Transform: %d",point_transform);
2092 jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2093 sampling_factor=(const char *) NULL;
2094 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2095 if (value != (char *) NULL)
2097 sampling_factor=value;
2098 if (image->debug != MagickFalse)
2099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2100 " Input sampling-factors=%s",sampling_factor);
2102 if (image_info->sampling_factor != (char *) NULL)
2103 sampling_factor=image_info->sampling_factor;
2104 if (sampling_factor == (const char *) NULL)
2106 if (image->quality >= 90)
2107 for (i=0; i < MAX_COMPONENTS; i++)
2109 jpeg_info.comp_info[i].h_samp_factor=1;
2110 jpeg_info.comp_info[i].v_samp_factor=1;
2125 Set sampling factor.
2128 factors=SamplingFactorToList(sampling_factor);
2129 if (factors != (char **) NULL)
2131 for (i=0; i < MAX_COMPONENTS; i++)
2133 if (factors[i] == (char *) NULL)
2135 flags=ParseGeometry(factors[i],&geometry_info);
2136 if ((flags & SigmaValue) == 0)
2137 geometry_info.sigma=geometry_info.rho;
2138 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2139 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2140 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2142 factors=(char **) RelinquishMagickMemory(factors);
2144 for ( ; i < MAX_COMPONENTS; i++)
2146 jpeg_info.comp_info[i].h_samp_factor=1;
2147 jpeg_info.comp_info[i].v_samp_factor=1;
2150 if (jpeg_info.input_components == 1)
2151 for (i=0; i < MAX_COMPONENTS; i++)
2153 jpeg_info.comp_info[i].h_samp_factor=1;
2154 jpeg_info.comp_info[i].v_samp_factor=1;
2156 if ((jpeg_info.comp_info[0].h_samp_factor > 1) &&
2157 (jpeg_info.comp_info[0].v_samp_factor > 1))
2160 Nicolas Robidoux's remix of ISO-IEC 10918-1 : 1993(E) Annex K.
2162 jpeg_add_quant_table(&jpeg_info,0,LuminanceQTable,jpeg_quality_scaling(
2164 jpeg_add_quant_table(&jpeg_info,1,CbQTable,jpeg_quality_scaling(
2166 jpeg_add_quant_table(&jpeg_info,2,CrQTable,jpeg_quality_scaling(
2169 jpeg_start_compress(&jpeg_info,MagickTrue);
2170 if (image->debug != MagickFalse)
2172 if (image->storage_class == PseudoClass)
2173 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2174 "Storage class: PseudoClass");
2176 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2177 "Storage class: DirectClass");
2178 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2179 (double) image->depth);
2180 if (image->colors != 0)
2181 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2182 "Number of colors: %.20g",(double) image->colors);
2184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2185 "Number of colors: unspecified");
2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2188 switch (image->colorspace)
2190 case CMYKColorspace:
2192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2193 "Storage class: DirectClass");
2194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2195 "Colorspace: CMYK");
2198 case YCbCrColorspace:
2199 case Rec601YCbCrColorspace:
2200 case Rec709YCbCrColorspace:
2202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2203 "Colorspace: YCbCr");
2209 switch (image->colorspace)
2211 case CMYKColorspace:
2213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2214 "Colorspace: CMYK");
2215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2216 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2217 jpeg_info.comp_info[0].h_samp_factor,
2218 jpeg_info.comp_info[0].v_samp_factor,
2219 jpeg_info.comp_info[1].h_samp_factor,
2220 jpeg_info.comp_info[1].v_samp_factor,
2221 jpeg_info.comp_info[2].h_samp_factor,
2222 jpeg_info.comp_info[2].v_samp_factor,
2223 jpeg_info.comp_info[3].h_samp_factor,
2224 jpeg_info.comp_info[3].v_samp_factor);
2227 case GRAYColorspace:
2228 case Rec601LumaColorspace:
2229 case Rec709LumaColorspace:
2231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2232 "Colorspace: GRAY");
2233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2234 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2235 jpeg_info.comp_info[0].v_samp_factor);
2240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2241 "Image colorspace is RGB");
2242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2243 "Sampling factors: %dx%d,%dx%d,%dx%d",
2244 jpeg_info.comp_info[0].h_samp_factor,
2245 jpeg_info.comp_info[0].v_samp_factor,
2246 jpeg_info.comp_info[1].h_samp_factor,
2247 jpeg_info.comp_info[1].v_samp_factor,
2248 jpeg_info.comp_info[2].h_samp_factor,
2249 jpeg_info.comp_info[2].v_samp_factor);
2252 case YCbCrColorspace:
2253 case Rec601YCbCrColorspace:
2254 case Rec709YCbCrColorspace:
2256 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2257 "Colorspace: YCbCr");
2258 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2259 "Sampling factors: %dx%d,%dx%d,%dx%d",
2260 jpeg_info.comp_info[0].h_samp_factor,
2261 jpeg_info.comp_info[0].v_samp_factor,
2262 jpeg_info.comp_info[1].h_samp_factor,
2263 jpeg_info.comp_info[1].v_samp_factor,
2264 jpeg_info.comp_info[2].h_samp_factor,
2265 jpeg_info.comp_info[2].v_samp_factor);
2270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2273 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2274 jpeg_info.comp_info[0].h_samp_factor,
2275 jpeg_info.comp_info[0].v_samp_factor,
2276 jpeg_info.comp_info[1].h_samp_factor,
2277 jpeg_info.comp_info[1].v_samp_factor,
2278 jpeg_info.comp_info[2].h_samp_factor,
2279 jpeg_info.comp_info[2].v_samp_factor,
2280 jpeg_info.comp_info[3].h_samp_factor,
2281 jpeg_info.comp_info[3].v_samp_factor);
2287 Write JPEG profiles.
2289 value=GetImageProperty(image,"comment",exception);
2290 if (value != (char *) NULL)
2291 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2292 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2293 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2294 if (image->profiles != (void *) NULL)
2295 WriteProfile(&jpeg_info,image);
2297 Convert MIFF to JPEG raster pixels.
2299 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2300 jpeg_info.input_components*sizeof(*jpeg_pixels));
2301 if (jpeg_pixels == (JSAMPLE *) NULL)
2302 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2303 if (setjmp(error_manager.error_recovery) != 0)
2305 jpeg_destroy_compress(&jpeg_info);
2306 if (jpeg_pixels != (unsigned char *) NULL)
2307 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2308 (void) CloseBlob(image);
2309 return(MagickFalse);
2311 scanline[0]=(JSAMPROW) jpeg_pixels;
2312 if (jpeg_info.data_precision <= 8)
2314 if ((jpeg_info.in_color_space == JCS_RGB) ||
2315 (jpeg_info.in_color_space == JCS_YCbCr))
2316 for (y=0; y < (ssize_t) image->rows; y++)
2318 register const Quantum
2324 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2325 if (p == (const Quantum *) NULL)
2328 for (x=0; x < (ssize_t) image->columns; x++)
2330 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2331 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2332 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2333 p+=GetPixelChannels(image);
2335 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2336 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2338 if (status == MagickFalse)
2342 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2343 for (y=0; y < (ssize_t) image->rows; y++)
2345 register const Quantum
2351 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2352 if (p == (const Quantum *) NULL)
2355 for (x=0; x < (ssize_t) image->columns; x++)
2357 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2358 p+=GetPixelChannels(image);
2360 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2361 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2363 if (status == MagickFalse)
2367 for (y=0; y < (ssize_t) image->rows; y++)
2369 register const Quantum
2375 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2376 if (p == (const Quantum *) NULL)
2379 for (x=0; x < (ssize_t) image->columns; x++)
2382 Convert DirectClass packets to contiguous CMYK scanlines.
2384 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2385 GetPixelRed(image,p))));
2386 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2387 GetPixelGreen(image,p))));
2388 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2389 GetPixelBlue(image,p))));
2390 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2391 GetPixelBlack(image,p))));
2392 p+=GetPixelChannels(image);
2394 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2395 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2397 if (status == MagickFalse)
2402 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2403 for (y=0; y < (ssize_t) image->rows; y++)
2405 register const Quantum
2411 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2412 if (p == (const Quantum *) NULL)
2415 for (x=0; x < (ssize_t) image->columns; x++)
2417 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2419 p+=GetPixelChannels(image);
2421 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2422 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2424 if (status == MagickFalse)
2428 if ((jpeg_info.in_color_space == JCS_RGB) ||
2429 (jpeg_info.in_color_space == JCS_YCbCr))
2430 for (y=0; y < (ssize_t) image->rows; y++)
2432 register const Quantum
2438 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2439 if (p == (const Quantum *) NULL)
2442 for (x=0; x < (ssize_t) image->columns; x++)
2444 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2445 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2446 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2447 p+=GetPixelChannels(image);
2449 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2450 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2452 if (status == MagickFalse)
2456 for (y=0; y < (ssize_t) image->rows; y++)
2458 register const Quantum
2464 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2465 if (p == (const Quantum *) NULL)
2468 for (x=0; x < (ssize_t) image->columns; x++)
2471 Convert DirectClass packets to contiguous CMYK scanlines.
2473 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2474 GetPixelRed(image,p)) >> 4));
2475 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2476 GetPixelGreen(image,p)) >> 4));
2477 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2478 GetPixelBlue(image,p)) >> 4));
2479 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2480 GetPixelBlack(image,p)) >> 4));
2481 p+=GetPixelChannels(image);
2483 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2484 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2486 if (status == MagickFalse)
2489 if (y == (ssize_t) image->rows)
2490 jpeg_finish_compress(&jpeg_info);
2492 Relinquish resources.
2494 jpeg_destroy_compress(&jpeg_info);
2495 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2496 (void) CloseBlob(image);