2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2011 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)
1787 struct jpeg_compress_struct
1790 struct jpeg_error_mgr
1796 assert(image_info != (const ImageInfo *) NULL);
1797 assert(image_info->signature == MagickSignature);
1798 assert(image != (Image *) NULL);
1799 assert(image->signature == MagickSignature);
1800 if (image->debug != MagickFalse)
1801 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1802 assert(exception != (ExceptionInfo *) NULL);
1803 assert(exception->signature == MagickSignature);
1804 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1805 if (status == MagickFalse)
1808 Initialize JPEG parameters.
1810 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1811 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1812 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1813 jpeg_info.client_data=(void *) image;
1814 jpeg_info.err=jpeg_std_error(&jpeg_error);
1815 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1816 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1817 error_manager.exception=exception;
1818 error_manager.image=image;
1819 jpeg_pixels=(JSAMPLE *) NULL;
1820 if (setjmp(error_manager.error_recovery) != 0)
1822 jpeg_destroy_compress(&jpeg_info);
1823 (void) CloseBlob(image);
1824 return(MagickFalse);
1826 jpeg_info.client_data=(void *) &error_manager;
1827 jpeg_create_compress(&jpeg_info);
1828 JPEGDestinationManager(&jpeg_info,image);
1829 if ((image->columns != (unsigned int) image->columns) ||
1830 (image->rows != (unsigned int) image->rows))
1831 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1832 jpeg_info.image_width=(unsigned int) image->columns;
1833 jpeg_info.image_height=(unsigned int) image->rows;
1834 jpeg_info.input_components=3;
1835 jpeg_info.data_precision=8;
1836 jpeg_info.in_color_space=JCS_RGB;
1837 switch (image->colorspace)
1839 case CMYKColorspace:
1841 jpeg_info.input_components=4;
1842 jpeg_info.in_color_space=JCS_CMYK;
1845 case YCbCrColorspace:
1846 case Rec601YCbCrColorspace:
1847 case Rec709YCbCrColorspace:
1849 jpeg_info.in_color_space=JCS_YCbCr;
1852 case GRAYColorspace:
1853 case Rec601LumaColorspace:
1854 case Rec709LumaColorspace:
1856 jpeg_info.input_components=1;
1857 jpeg_info.in_color_space=JCS_GRAYSCALE;
1862 if (IsRGBColorspace(image->colorspace) == MagickFalse)
1863 (void) TransformImageColorspace(image,RGBColorspace,exception);
1867 if ((image_info->type != TrueColorType) &&
1868 (IsImageGray(image,exception) != MagickFalse))
1870 jpeg_info.input_components=1;
1871 jpeg_info.in_color_space=JCS_GRAYSCALE;
1873 jpeg_set_defaults(&jpeg_info);
1874 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1875 jpeg_info.data_precision=8;
1877 if (sizeof(JSAMPLE) > 1)
1878 jpeg_info.data_precision=12;
1879 jpeg_info.density_unit=(UINT8) 1;
1880 if (image->debug != MagickFalse)
1881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1882 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
1883 floor(image->resolution.y+0.5));
1884 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
1887 Set image resolution.
1889 jpeg_info.write_JFIF_header=MagickTrue;
1890 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
1891 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
1892 if (image->units == PixelsPerInchResolution)
1893 jpeg_info.density_unit=(UINT8) 1;
1894 if (image->units == PixelsPerCentimeterResolution)
1895 jpeg_info.density_unit=(UINT8) 2;
1897 option=GetImageOption(image_info,"jpeg:dct-method");
1898 if (option != (const char *) NULL)
1904 if (LocaleCompare(option,"default") == 0)
1905 jpeg_info.dct_method=JDCT_DEFAULT;
1911 if (LocaleCompare(option,"fastest") == 0)
1912 jpeg_info.dct_method=JDCT_FASTEST;
1913 if (LocaleCompare(option,"float") == 0)
1914 jpeg_info.dct_method=JDCT_FLOAT;
1920 if (LocaleCompare(option,"ifast") == 0)
1921 jpeg_info.dct_method=JDCT_IFAST;
1922 if (LocaleCompare(option,"islow") == 0)
1923 jpeg_info.dct_method=JDCT_ISLOW;
1927 option=GetImageOption(image_info,"jpeg:optimize-coding");
1928 if (option != (const char *) NULL)
1930 jpeg_info.optimize_coding=MagickFalse;
1931 if (IsMagickTrue(option) != MagickFalse)
1932 jpeg_info.optimize_coding=MagickTrue;
1939 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1940 image->rows*sizeof(JSAMPLE);
1941 if (length == (MagickSizeType) ((size_t) length))
1944 Perform optimization only if available memory resources permit it.
1946 status=AcquireMagickResource(MemoryResource,length);
1947 if (status != MagickFalse)
1948 jpeg_info.optimize_coding=MagickTrue;
1949 RelinquishMagickResource(MemoryResource,length);
1952 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1953 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1954 (image_info->interlace != NoInterlace))
1956 if (image->debug != MagickFalse)
1957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1958 "Interlace: progressive");
1959 jpeg_simple_progression(&jpeg_info);
1962 if (image->debug != MagickFalse)
1963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1964 "Interlace: non-progressive");
1966 if (image->debug != MagickFalse)
1967 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1968 "Interlace: nonprogressive");
1970 option=GetImageOption(image_info,"jpeg:extent");
1971 if (option != (const char *) NULL)
1979 jpeg_info=CloneImageInfo(image_info);
1980 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1981 if (jpeg_image != (Image *) NULL)
1991 Search for compression quality that does not exceed image extent.
1993 jpeg_info->quality=0;
1994 extent=(MagickSizeType) StringToDoubleInterval(option,100.0);
1995 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1996 (void) AcquireUniqueFilename(jpeg_image->filename);
1998 for (minimum=0; minimum != maximum; )
2000 jpeg_image->quality=minimum+(maximum-minimum)/2;
2001 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2002 if (GetBlobSize(jpeg_image) <= extent)
2003 minimum=jpeg_image->quality+1;
2005 maximum=jpeg_image->quality-1;
2007 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2008 image->quality=minimum-1;
2009 jpeg_image=DestroyImage(jpeg_image);
2011 jpeg_info=DestroyImageInfo(jpeg_info);
2013 if ((image_info->compression != LosslessJPEGCompression) &&
2014 (image->quality <= 100))
2016 if (image->quality == UndefinedCompressionQuality)
2017 jpeg_set_quality(&jpeg_info,92,MagickTrue);
2019 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
2020 if (image->debug != MagickFalse)
2021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2022 (double) image->quality);
2026 #if !defined(C_LOSSLESS_SUPPORTED)
2027 jpeg_set_quality(&jpeg_info,100,MagickTrue);
2028 if (image->debug != MagickFalse)
2029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2031 if (image->quality < 100)
2032 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2033 "LosslessToLossyJPEGConversion",image->filename);
2040 predictor=image->quality/100; /* range 1-7 */
2041 point_transform=image->quality % 20; /* range 0-15 */
2042 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2043 if (image->debug != MagickFalse)
2045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2046 "Compression: lossless");
2047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2048 "Predictor: %d",predictor);
2049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2050 "Point Transform: %d",point_transform);
2055 sampling_factor=(const char *) NULL;
2056 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2057 if (value != (char *) NULL)
2059 sampling_factor=value;
2060 if (image->debug != MagickFalse)
2061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2062 " Input sampling-factors=%s",sampling_factor);
2064 if (image_info->sampling_factor != (char *) NULL)
2065 sampling_factor=image_info->sampling_factor;
2066 if (sampling_factor == (const char *) NULL)
2068 if (image->quality >= 90)
2069 for (i=0; i < MAX_COMPONENTS; i++)
2071 jpeg_info.comp_info[i].h_samp_factor=1;
2072 jpeg_info.comp_info[i].v_samp_factor=1;
2087 Set sampling factor.
2090 factors=SamplingFactorToList(sampling_factor);
2091 if (factors != (char **) NULL)
2093 for (i=0; i < MAX_COMPONENTS; i++)
2095 if (factors[i] == (char *) NULL)
2097 flags=ParseGeometry(factors[i],&geometry_info);
2098 if ((flags & SigmaValue) == 0)
2099 geometry_info.sigma=geometry_info.rho;
2100 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2101 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2102 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2104 factors=(char **) RelinquishMagickMemory(factors);
2106 for ( ; i < MAX_COMPONENTS; i++)
2108 jpeg_info.comp_info[i].h_samp_factor=1;
2109 jpeg_info.comp_info[i].v_samp_factor=1;
2112 if (jpeg_info.input_components == 1)
2113 for (i=0; i < MAX_COMPONENTS; i++)
2115 jpeg_info.comp_info[i].h_samp_factor=1;
2116 jpeg_info.comp_info[i].v_samp_factor=1;
2118 jpeg_start_compress(&jpeg_info,MagickTrue);
2119 if (image->debug != MagickFalse)
2121 if (image->storage_class == PseudoClass)
2122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2123 "Storage class: PseudoClass");
2125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2126 "Storage class: DirectClass");
2127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2128 (double) image->depth);
2129 if (image->colors != 0)
2130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2131 "Number of colors: %.20g",(double) image->colors);
2133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2134 "Number of colors: unspecified");
2135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2136 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2137 switch (image->colorspace)
2139 case CMYKColorspace:
2141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2142 "Storage class: DirectClass");
2143 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2144 "Colorspace: CMYK");
2147 case YCbCrColorspace:
2148 case Rec601YCbCrColorspace:
2149 case Rec709YCbCrColorspace:
2151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2152 "Colorspace: YCbCr");
2158 switch (image->colorspace)
2160 case CMYKColorspace:
2162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2163 "Colorspace: CMYK");
2164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2165 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2166 jpeg_info.comp_info[0].h_samp_factor,
2167 jpeg_info.comp_info[0].v_samp_factor,
2168 jpeg_info.comp_info[1].h_samp_factor,
2169 jpeg_info.comp_info[1].v_samp_factor,
2170 jpeg_info.comp_info[2].h_samp_factor,
2171 jpeg_info.comp_info[2].v_samp_factor,
2172 jpeg_info.comp_info[3].h_samp_factor,
2173 jpeg_info.comp_info[3].v_samp_factor);
2176 case GRAYColorspace:
2177 case Rec601LumaColorspace:
2178 case Rec709LumaColorspace:
2180 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2181 "Colorspace: GRAY");
2182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2183 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2184 jpeg_info.comp_info[0].v_samp_factor);
2189 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2190 "Image colorspace is RGB");
2191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2192 "Sampling factors: %dx%d,%dx%d,%dx%d",
2193 jpeg_info.comp_info[0].h_samp_factor,
2194 jpeg_info.comp_info[0].v_samp_factor,
2195 jpeg_info.comp_info[1].h_samp_factor,
2196 jpeg_info.comp_info[1].v_samp_factor,
2197 jpeg_info.comp_info[2].h_samp_factor,
2198 jpeg_info.comp_info[2].v_samp_factor);
2201 case YCbCrColorspace:
2202 case Rec601YCbCrColorspace:
2203 case Rec709YCbCrColorspace:
2205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2206 "Colorspace: YCbCr");
2207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2208 "Sampling factors: %dx%d,%dx%d,%dx%d",
2209 jpeg_info.comp_info[0].h_samp_factor,
2210 jpeg_info.comp_info[0].v_samp_factor,
2211 jpeg_info.comp_info[1].h_samp_factor,
2212 jpeg_info.comp_info[1].v_samp_factor,
2213 jpeg_info.comp_info[2].h_samp_factor,
2214 jpeg_info.comp_info[2].v_samp_factor);
2219 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2221 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2222 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2223 jpeg_info.comp_info[0].h_samp_factor,
2224 jpeg_info.comp_info[0].v_samp_factor,
2225 jpeg_info.comp_info[1].h_samp_factor,
2226 jpeg_info.comp_info[1].v_samp_factor,
2227 jpeg_info.comp_info[2].h_samp_factor,
2228 jpeg_info.comp_info[2].v_samp_factor,
2229 jpeg_info.comp_info[3].h_samp_factor,
2230 jpeg_info.comp_info[3].v_samp_factor);
2236 Write JPEG profiles.
2238 value=GetImageProperty(image,"comment",exception);
2239 if (value != (char *) NULL)
2240 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2241 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2242 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2243 if (image->profiles != (void *) NULL)
2244 WriteProfile(&jpeg_info,image);
2246 Convert MIFF to JPEG raster pixels.
2248 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2249 jpeg_info.input_components*sizeof(*jpeg_pixels));
2250 if (jpeg_pixels == (JSAMPLE *) NULL)
2251 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2252 if (setjmp(error_manager.error_recovery) != 0)
2254 jpeg_destroy_compress(&jpeg_info);
2255 if (jpeg_pixels != (unsigned char *) NULL)
2256 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2257 (void) CloseBlob(image);
2258 return(MagickFalse);
2260 scanline[0]=(JSAMPROW) jpeg_pixels;
2261 if (jpeg_info.data_precision <= 8)
2263 if ((jpeg_info.in_color_space == JCS_RGB) ||
2264 (jpeg_info.in_color_space == JCS_YCbCr))
2265 for (y=0; y < (ssize_t) image->rows; y++)
2267 register const Quantum
2273 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2274 if (p == (const Quantum *) NULL)
2277 for (x=0; x < (ssize_t) image->columns; x++)
2279 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2280 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2281 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2282 p+=GetPixelChannels(image);
2284 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2285 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2287 if (status == MagickFalse)
2291 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2292 for (y=0; y < (ssize_t) image->rows; y++)
2294 register const Quantum
2300 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2301 if (p == (const Quantum *) NULL)
2304 for (x=0; x < (ssize_t) image->columns; x++)
2306 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2307 p+=GetPixelChannels(image);
2309 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2310 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2312 if (status == MagickFalse)
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++)
2331 Convert DirectClass packets to contiguous CMYK scanlines.
2333 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2334 GetPixelRed(image,p))));
2335 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2336 GetPixelGreen(image,p))));
2337 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2338 GetPixelBlue(image,p))));
2339 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2340 GetPixelBlack(image,p))));
2341 p+=GetPixelChannels(image);
2343 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2344 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2346 if (status == MagickFalse)
2351 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2352 for (y=0; y < (ssize_t) image->rows; y++)
2354 register const Quantum
2360 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2361 if (p == (const Quantum *) NULL)
2364 for (x=0; x < (ssize_t) image->columns; x++)
2366 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2368 p+=GetPixelChannels(image);
2370 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2371 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2373 if (status == MagickFalse)
2377 if ((jpeg_info.in_color_space == JCS_RGB) ||
2378 (jpeg_info.in_color_space == JCS_YCbCr))
2379 for (y=0; y < (ssize_t) image->rows; y++)
2381 register const Quantum
2387 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2388 if (p == (const Quantum *) NULL)
2391 for (x=0; x < (ssize_t) image->columns; x++)
2393 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2394 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2395 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2396 p+=GetPixelChannels(image);
2398 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2399 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2401 if (status == MagickFalse)
2405 for (y=0; y < (ssize_t) image->rows; y++)
2407 register const Quantum
2413 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2414 if (p == (const Quantum *) NULL)
2417 for (x=0; x < (ssize_t) image->columns; x++)
2420 Convert DirectClass packets to contiguous CMYK scanlines.
2422 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2423 GetPixelRed(image,p)) >> 4));
2424 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2425 GetPixelGreen(image,p)) >> 4));
2426 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2427 GetPixelBlue(image,p)) >> 4));
2428 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2429 GetPixelBlack(image,p)) >> 4));
2430 p+=GetPixelChannels(image);
2432 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2433 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2435 if (status == MagickFalse)
2438 if (y == (ssize_t) image->rows)
2439 jpeg_finish_compress(&jpeg_info);
2441 Relinquish resources.
2443 jpeg_destroy_compress(&jpeg_info);
2444 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2445 (void) CloseBlob(image);