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 "magick/studio.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/color.h"
51 #include "magick/colormap-private.h"
52 #include "magick/color-private.h"
53 #include "magick/colormap.h"
54 #include "magick/colorspace.h"
55 #include "magick/constitute.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/geometry.h"
59 #include "magick/image.h"
60 #include "magick/image-private.h"
61 #include "magick/list.h"
62 #include "magick/log.h"
63 #include "magick/magick.h"
64 #include "magick/memory_.h"
65 #include "magick/module.h"
66 #include "magick/monitor.h"
67 #include "magick/monitor-private.h"
68 #include "magick/option.h"
69 #include "magick/profile.h"
70 #include "magick/property.h"
71 #include "magick/quantum-private.h"
72 #include "magick/resource_.h"
73 #include "magick/splay-tree.h"
74 #include "magick/static.h"
75 #include "magick/string_.h"
76 #include "magick/string-private.h"
77 #include "magick/utility.h"
79 #if defined(MAGICKCORE_JPEG_DELEGATE)
80 #define JPEG_INTERNAL_OPTIONS
81 #if defined(__MINGW32__)
82 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
83 typedef unsigned char boolean;
94 #define ICC_MARKER (JPEG_APP0+2)
95 #define ICC_PROFILE "ICC_PROFILE"
96 #define IPTC_MARKER (JPEG_APP0+13)
97 #define XML_MARKER (JPEG_APP0+1)
98 #define MaxBufferExtent 8192
101 Typedef declarations.
103 #if defined(MAGICKCORE_JPEG_DELEGATE)
104 typedef struct _DestinationManager
106 struct jpeg_destination_mgr
114 } DestinationManager;
116 typedef struct _ErrorManager
128 typedef struct _SourceManager
130 struct jpeg_source_mgr
145 Forward declarations.
147 #if defined(MAGICKCORE_JPEG_DELEGATE)
148 static MagickBooleanType
149 WriteJPEGImage(const ImageInfo *,Image *);
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 % IsJPEG() returns MagickTrue if the image format type, identified by the
164 % magick string, is JPEG.
166 % The format of the IsJPEG method is:
168 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
170 % A description of each parameter follows:
172 % o magick: compare image format pattern against these bytes.
174 % o length: Specifies the length of the magick string.
177 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
181 if (memcmp(magick,"\377\330\377",3) == 0)
186 #if defined(MAGICKCORE_JPEG_DELEGATE)
188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 % R e a d J P E G I m a g e %
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
199 % the memory necessary for the new Image structure and returns a pointer to
202 % The format of the ReadJPEGImage method is:
204 % Image *ReadJPEGImage(const ImageInfo *image_info,
205 % ExceptionInfo *exception)
207 % A description of each parameter follows:
209 % o image_info: the image info.
211 % o exception: return any errors or warnings in this structure.
215 static boolean FillInputBuffer(j_decompress_ptr cinfo)
220 source=(SourceManager *) cinfo->src;
221 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
222 MaxBufferExtent,source->buffer);
223 if (source->manager.bytes_in_buffer == 0)
225 if (source->start_of_blob != 0)
226 ERREXIT(cinfo,JERR_INPUT_EMPTY);
227 WARNMS(cinfo,JWRN_JPEG_EOF);
228 source->buffer[0]=(JOCTET) 0xff;
229 source->buffer[1]=(JOCTET) JPEG_EOI;
230 source->manager.bytes_in_buffer=2;
232 source->manager.next_input_byte=source->buffer;
233 source->start_of_blob=FALSE;
237 static int GetCharacter(j_decompress_ptr jpeg_info)
239 if (jpeg_info->src->bytes_in_buffer == 0)
240 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
241 jpeg_info->src->bytes_in_buffer--;
242 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
245 static void InitializeSource(j_decompress_ptr cinfo)
250 source=(SourceManager *) cinfo->src;
251 source->start_of_blob=TRUE;
254 static MagickBooleanType IsITUFaxImage(const Image *image)
262 profile=GetImageProfile(image,"8bim");
263 if (profile == (const StringInfo *) NULL)
265 if (GetStringInfoLength(profile) < 5)
267 datum=GetStringInfoDatum(profile);
268 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
269 (datum[3] == 0x41) && (datum[4] == 0x58))
274 static MagickBooleanType JPEGErrorHandler(j_common_ptr jpeg_info)
277 message[JMSG_LENGTH_MAX];
286 error_manager=(ErrorManager *) jpeg_info->client_data;
287 image=error_manager->image;
288 if (image->debug != MagickFalse)
293 (jpeg_info->err->format_message)(jpeg_info,message);
294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
295 "[%s] JPEG Trace: \"%s\"",image->filename,message);
297 if (error_manager->finished != MagickFalse)
298 ThrowBinaryException(CorruptImageWarning,(char *) message,image->filename)
300 ThrowBinaryException(CorruptImageError,(char *) message,image->filename);
301 longjmp(error_manager->error_recovery,1);
304 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
307 message[JMSG_LENGTH_MAX];
316 error_manager=(ErrorManager *) jpeg_info->client_data;
317 image=error_manager->image;
321 Process warning message.
323 (jpeg_info->err->format_message)(jpeg_info,message);
324 if ((jpeg_info->err->num_warnings == 0) ||
325 (jpeg_info->err->trace_level >= 3))
326 ThrowBinaryException(CorruptImageWarning,(char *) message,
328 jpeg_info->err->num_warnings++;
331 if ((image->debug != MagickFalse) &&
332 (level >= jpeg_info->err->trace_level))
335 Process trace message.
337 (jpeg_info->err->format_message)(jpeg_info,message);
338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
339 "[%s] JPEG Trace: \"%s\"",image->filename,message);
344 static boolean ReadComment(j_decompress_ptr jpeg_info)
365 Determine length of comment.
367 error_manager=(ErrorManager *) jpeg_info->client_data;
368 image=error_manager->image;
369 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
370 length+=GetCharacter(jpeg_info);
374 comment=(char *) NULL;
375 if (~length >= MaxTextExtent)
376 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
378 if (comment == (char *) NULL)
379 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
384 i=(ssize_t) length-1;
385 for (p=comment; i-- >= 0; p++)
386 *p=(char) GetCharacter(jpeg_info);
388 (void) SetImageProperty(image,"comment",comment);
389 comment=DestroyString(comment);
393 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
410 register unsigned char
423 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
424 length+=(size_t) GetCharacter(jpeg_info);
429 (void) GetCharacter(jpeg_info);
432 for (i=0; i < 12; i++)
433 magick[i]=(char) GetCharacter(jpeg_info);
434 if (LocaleCompare(magick,ICC_PROFILE) != 0)
437 Not a ICC profile, return.
439 for (i=0; i < (ssize_t) (length-12); i++)
440 (void) GetCharacter(jpeg_info);
443 (void) GetCharacter(jpeg_info); /* id */
444 (void) GetCharacter(jpeg_info); /* markers */
446 error_manager=(ErrorManager *) jpeg_info->client_data;
447 image=error_manager->image;
448 profile=AcquireStringInfo(length);
449 if (profile == (StringInfo *) NULL)
450 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
452 p=GetStringInfoDatum(profile);
453 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
454 *p++=(unsigned char) GetCharacter(jpeg_info);
455 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
456 if (icc_profile != (StringInfo *) NULL)
458 ConcatenateStringInfo(icc_profile,profile);
459 profile=DestroyStringInfo(profile);
463 status=SetImageProfile(image,"icc",profile);
464 profile=DestroyStringInfo(profile);
465 if (status == MagickFalse)
466 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
469 if (image->debug != MagickFalse)
470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
471 "Profile: ICC, %.20g bytes",(double) length);
475 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
478 magick[MaxTextExtent];
492 register unsigned char
503 Determine length of binary data stored here.
505 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
506 length+=(size_t) GetCharacter(jpeg_info);
511 (void) GetCharacter(jpeg_info);
515 Validate that this was written as a Photoshop resource format slug.
517 for (i=0; i < 10; i++)
518 magick[i]=(char) GetCharacter(jpeg_info);
523 if (LocaleCompare(magick,"Photoshop ") != 0)
526 Not a IPTC profile, return.
528 for (i=0; i < (ssize_t) length; i++)
529 (void) GetCharacter(jpeg_info);
533 Remove the version number.
535 for (i=0; i < 4; i++)
536 (void) GetCharacter(jpeg_info);
542 error_manager=(ErrorManager *) jpeg_info->client_data;
543 image=error_manager->image;
544 profile=AcquireStringInfo(length);
545 if (profile == (StringInfo *) NULL)
546 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
548 p=GetStringInfoDatum(profile);
549 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
550 *p++=(unsigned char) GetCharacter(jpeg_info);
551 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
552 if (iptc_profile != (StringInfo *) NULL)
554 ConcatenateStringInfo(iptc_profile,profile);
555 profile=DestroyStringInfo(profile);
559 status=SetImageProfile(image,"8bim",profile);
560 profile=DestroyStringInfo(profile);
561 if (status == MagickFalse)
562 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
565 if (image->debug != MagickFalse)
566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
567 "Profile: iptc, %.20g bytes",(double) length);
571 static boolean ReadProfile(j_decompress_ptr jpeg_info)
591 register unsigned char
601 Read generic profile.
603 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
604 length+=(size_t) GetCharacter(jpeg_info);
608 marker=jpeg_info->unread_marker-JPEG_APP0;
609 (void) FormatMagickString(name,MaxTextExtent,"APP%d",marker);
610 error_manager=(ErrorManager *) jpeg_info->client_data;
611 image=error_manager->image;
612 profile=AcquireStringInfo(length);
613 if (profile == (StringInfo *) NULL)
614 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
616 p=GetStringInfoDatum(profile);
617 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
618 *p++=(unsigned char) GetCharacter(jpeg_info);
621 p=GetStringInfoDatum(profile);
622 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
623 (void) CopyMagickString(name,"exif",MaxTextExtent);
624 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
630 Extract namespace from XMP profile.
632 p=GetStringInfoDatum(profile);
633 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
639 if (j < (ssize_t) GetStringInfoLength(profile))
640 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
641 (void) CopyMagickString(name,"xmp",MaxTextExtent);
644 status=SetImageProfile(image,name,profile);
645 profile=DestroyStringInfo(profile);
646 if (status == MagickFalse)
647 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
649 if (image->debug != MagickFalse)
650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
651 "Profile: %s, %.20g bytes",name,(double) length);
655 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
660 if (number_bytes <= 0)
662 source=(SourceManager *) cinfo->src;
663 while (number_bytes > (long) source->manager.bytes_in_buffer)
665 number_bytes-=(long) source->manager.bytes_in_buffer;
666 (void) FillInputBuffer(cinfo);
668 source->manager.next_input_byte+=number_bytes;
669 source->manager.bytes_in_buffer-=number_bytes;
672 static void TerminateSource(j_decompress_ptr cinfo)
677 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
682 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
683 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
684 source=(SourceManager *) cinfo->src;
685 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
686 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
687 source=(SourceManager *) cinfo->src;
688 source->manager.init_source=InitializeSource;
689 source->manager.fill_input_buffer=FillInputBuffer;
690 source->manager.skip_input_data=SkipInputData;
691 source->manager.resync_to_restart=jpeg_resync_to_restart;
692 source->manager.term_source=TerminateSource;
693 source->manager.bytes_in_buffer=0;
694 source->manager.next_input_byte=NULL;
698 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
701 image->quality=UndefinedCompressionQuality;
702 #if defined(D_PROGRESSIVE_SUPPORTED)
703 if (image->compression == LosslessJPEGCompression)
706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
707 "Quality: 100 (lossless)");
721 Determine the JPEG compression quality from the quantization tables.
724 for (i=0; i < NUM_QUANT_TBLS; i++)
726 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
727 for (j=0; j < DCTSIZE2; j++)
728 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
730 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
731 (jpeg_info->quant_tbl_ptrs[1] != NULL))
736 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
737 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
738 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
739 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
740 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
741 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
742 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
743 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
744 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
745 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
750 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
751 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
752 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
753 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
754 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
755 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
756 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
757 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
758 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
759 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
760 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
764 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
765 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
766 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
767 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
768 for (i=0; i < 100; i++)
770 if ((qvalue < hash[i]) && (sum < sums[i]))
772 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
773 image->quality=(size_t) i+1;
774 if (image->debug != MagickFalse)
775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
777 (sum <= sums[i]) ? "exact" : "approximate");
782 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
787 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
788 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
789 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
790 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
791 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
792 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
793 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
794 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
795 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
796 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
801 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
802 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
803 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
804 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
805 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
806 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
807 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
808 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
809 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
810 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
811 667, 592, 518, 441, 369, 292, 221, 151, 86,
815 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
816 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
817 for (i=0; i < 100; i++)
819 if ((qvalue < hash[i]) && (sum < sums[i]))
821 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
822 image->quality=(size_t) i+1;
823 if (image->debug != MagickFalse)
824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
825 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
826 (sum <= sums[i]) ? "exact" : "approximate");
833 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
836 sampling_factor[MaxTextExtent];
838 switch (jpeg_info->out_color_space)
842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
843 (void) FormatMagickString(sampling_factor,MaxTextExtent,
844 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
845 jpeg_info->comp_info[0].v_samp_factor,
846 jpeg_info->comp_info[1].h_samp_factor,
847 jpeg_info->comp_info[1].v_samp_factor,
848 jpeg_info->comp_info[2].h_samp_factor,
849 jpeg_info->comp_info[2].v_samp_factor,
850 jpeg_info->comp_info[3].h_samp_factor,
851 jpeg_info->comp_info[3].v_samp_factor);
856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
857 "Colorspace: GRAYSCALE");
858 (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
859 jpeg_info->comp_info[0].h_samp_factor,
860 jpeg_info->comp_info[0].v_samp_factor);
865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
866 (void) FormatMagickString(sampling_factor,MaxTextExtent,
867 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
868 jpeg_info->comp_info[0].v_samp_factor,
869 jpeg_info->comp_info[1].h_samp_factor,
870 jpeg_info->comp_info[1].v_samp_factor,
871 jpeg_info->comp_info[2].h_samp_factor,
872 jpeg_info->comp_info[2].v_samp_factor);
877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
878 jpeg_info->out_color_space);
879 (void) FormatMagickString(sampling_factor,MaxTextExtent,
880 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
881 jpeg_info->comp_info[0].v_samp_factor,
882 jpeg_info->comp_info[1].h_samp_factor,
883 jpeg_info->comp_info[1].v_samp_factor,
884 jpeg_info->comp_info[2].h_samp_factor,
885 jpeg_info->comp_info[2].v_samp_factor,
886 jpeg_info->comp_info[3].h_samp_factor,
887 jpeg_info->comp_info[3].v_samp_factor);
891 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
892 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
896 static Image *ReadJPEGImage(const ImageInfo *image_info,
897 ExceptionInfo *exception)
900 value[MaxTextExtent];
930 struct jpeg_decompress_struct
933 struct jpeg_error_mgr
949 assert(image_info != (const ImageInfo *) NULL);
950 assert(image_info->signature == MagickSignature);
951 if (image_info->debug != MagickFalse)
952 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
953 image_info->filename);
954 assert(exception != (ExceptionInfo *) NULL);
955 assert(exception->signature == MagickSignature);
956 debug=IsEventLogging();
958 image=AcquireImage(image_info);
959 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
960 if (status == MagickFalse)
962 image=DestroyImageList(image);
963 return((Image *) NULL);
966 Initialize JPEG parameters.
968 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
969 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
970 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
971 jpeg_info.err=jpeg_std_error(&jpeg_error);
972 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
973 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
974 jpeg_pixels=(JSAMPLE *) NULL;
975 error_manager.image=image;
976 if (setjmp(error_manager.error_recovery) != 0)
978 jpeg_destroy_decompress(&jpeg_info);
979 (void) CloseBlob(image);
980 number_pixels=(MagickSizeType) image->columns*image->rows;
981 if (number_pixels != 0)
982 return(GetFirstImageInList(image));
983 InheritException(exception,&image->exception);
984 return(DestroyImage(image));
986 jpeg_info.client_data=(void *) &error_manager;
987 jpeg_create_decompress(&jpeg_info);
988 JPEGSourceManager(&jpeg_info,image);
989 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
990 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
991 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
992 for (i=1; i < 16; i++)
993 if ((i != 2) && (i != 13) && (i != 14))
994 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
995 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
996 if ((image_info->colorspace == YCbCrColorspace) ||
997 (image_info->colorspace == Rec601YCbCrColorspace) ||
998 (image_info->colorspace == Rec709YCbCrColorspace))
999 jpeg_info.out_color_space=JCS_YCbCr;
1000 if (IsITUFaxImage(image) != MagickFalse)
1002 image->colorspace=LabColorspace;
1003 jpeg_info.out_color_space=JCS_YCbCr;
1006 if (jpeg_info.out_color_space == JCS_CMYK)
1007 image->colorspace=CMYKColorspace;
1009 Set image resolution.
1012 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1013 (jpeg_info.Y_density != 1))
1015 image->x_resolution=(double) jpeg_info.X_density;
1016 image->y_resolution=(double) jpeg_info.Y_density;
1017 units=(size_t) jpeg_info.density_unit;
1020 image->units=PixelsPerInchResolution;
1022 image->units=PixelsPerCentimeterResolution;
1023 number_pixels=(MagickSizeType) image->columns*image->rows;
1024 option=GetImageOption(image_info,"jpeg:size");
1025 if (option != (const char *) NULL)
1039 flags=ParseGeometry(option,&geometry_info);
1040 if ((flags & SigmaValue) == 0)
1041 geometry_info.sigma=geometry_info.rho;
1042 jpeg_calc_output_dimensions(&jpeg_info);
1043 image->magick_columns=jpeg_info.output_width;
1044 image->magick_rows=jpeg_info.output_height;
1046 if (geometry_info.rho != 0.0)
1047 scale_factor=jpeg_info.output_width/geometry_info.rho;
1048 if ((geometry_info.sigma != 0.0) &&
1049 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1050 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1051 jpeg_info.scale_num=1U;
1052 jpeg_info.scale_denom=(unsigned int) scale_factor;
1053 jpeg_calc_output_dimensions(&jpeg_info);
1054 if (image->debug != MagickFalse)
1055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1056 "Scale factor: %.20g",(double) scale_factor);
1058 precision=(size_t) jpeg_info.data_precision;
1059 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1060 #if defined(D_LOSSLESS_SUPPORTED)
1061 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1062 JPEGInterlace : NoInterlace;
1063 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1064 LosslessJPEGCompression : JPEGCompression;
1065 if (jpeg_info.data_precision > 8)
1066 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1067 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1069 if (jpeg_info.data_precision == 16)
1070 jpeg_info.data_precision=12;
1072 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1074 image->compression=JPEGCompression;
1077 image->compression=JPEGCompression;
1078 image->interlace=JPEGInterlace;
1080 if ((image_info->colors > 8) && (image_info->colors <= 256))
1083 Let the JPEG library quantize for us.
1085 jpeg_info.quantize_colors=MagickTrue;
1086 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1088 option=GetImageOption(image_info,"jpeg:block-smoothing");
1089 if (option != (const char *) NULL)
1091 jpeg_info.do_block_smoothing=MagickFalse;
1092 if (IsMagickTrue(option) != MagickFalse)
1093 jpeg_info.do_block_smoothing=MagickTrue;
1095 option=GetImageOption(image_info,"jpeg:dct-method");
1096 if (option != (const char *) NULL)
1102 if (LocaleCompare(option,"default") == 0)
1103 jpeg_info.dct_method=JDCT_DEFAULT;
1109 if (LocaleCompare(option,"fastest") == 0)
1110 jpeg_info.dct_method=JDCT_FASTEST;
1111 if (LocaleCompare(option,"float") == 0)
1112 jpeg_info.dct_method=JDCT_FLOAT;
1118 if (LocaleCompare(option,"ifast") == 0)
1119 jpeg_info.dct_method=JDCT_IFAST;
1120 if (LocaleCompare(option,"islow") == 0)
1121 jpeg_info.dct_method=JDCT_ISLOW;
1125 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1126 if (option != (const char *) NULL)
1128 jpeg_info.do_fancy_upsampling=MagickFalse;
1129 if (IsMagickTrue(option) != MagickFalse)
1130 jpeg_info.do_fancy_upsampling=MagickTrue;
1132 (void) jpeg_start_decompress(&jpeg_info);
1133 image->columns=jpeg_info.output_width;
1134 image->rows=jpeg_info.output_height;
1135 image->depth=(size_t) jpeg_info.data_precision;
1136 if (jpeg_info.out_color_space == JCS_YCbCr)
1137 image->colorspace=YCbCrColorspace;
1138 if (jpeg_info.out_color_space == JCS_CMYK)
1139 image->colorspace=CMYKColorspace;
1140 if ((image_info->colors != 0) && (image_info->colors <= 256))
1141 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1142 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1143 if ((jpeg_info.output_components == 1) &&
1144 (jpeg_info.quantize_colors == MagickFalse))
1149 colors=(size_t) GetQuantumRange(image->depth)+1;
1150 if (AcquireImageColormap(image,colors) == MagickFalse)
1151 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1153 if (image->debug != MagickFalse)
1155 if (image->interlace != NoInterlace)
1156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1157 "Interlace: progressive");
1159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1160 "Interlace: nonprogressive");
1161 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1162 (int) jpeg_info.data_precision);
1163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1164 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1166 JPEGSetImageQuality(&jpeg_info,image);
1167 JPEGSetImageSamplingFactor(&jpeg_info,image);
1168 (void) FormatMagickString(value,MaxTextExtent,"%.20g",(double)
1169 jpeg_info.out_color_space);
1170 (void) SetImageProperty(image,"jpeg:colorspace",value);
1171 if (image_info->ping != MagickFalse)
1173 jpeg_destroy_decompress(&jpeg_info);
1174 (void) CloseBlob(image);
1175 return(GetFirstImageInList(image));
1177 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1178 jpeg_info.output_components*sizeof(JSAMPLE));
1179 if (jpeg_pixels == (JSAMPLE *) NULL)
1180 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1182 Convert JPEG pixels to pixel packets.
1184 if (setjmp(error_manager.error_recovery) != 0)
1186 if (jpeg_pixels != (unsigned char *) NULL)
1187 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1188 jpeg_destroy_decompress(&jpeg_info);
1189 (void) CloseBlob(image);
1190 number_pixels=(MagickSizeType) image->columns*image->rows;
1191 if (number_pixels != 0)
1192 return(GetFirstImageInList(image));
1193 return(DestroyImage(image));
1195 if (jpeg_info.quantize_colors != MagickFalse)
1197 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1198 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1199 for (i=0; i < (ssize_t) image->colors; i++)
1201 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1202 image->colormap[i].green=image->colormap[i].red;
1203 image->colormap[i].blue=image->colormap[i].red;
1204 image->colormap[i].opacity=OpaqueOpacity;
1207 for (i=0; i < (ssize_t) image->colors; i++)
1209 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1210 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1211 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1212 image->colormap[i].opacity=OpaqueOpacity;
1215 scanline[0]=(JSAMPROW) jpeg_pixels;
1216 for (y=0; y < (ssize_t) image->rows; y++)
1218 register IndexPacket
1224 register PixelPacket
1227 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1229 (void) ThrowMagickException(exception,GetMagickModule(),
1230 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1234 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1235 if (q == (PixelPacket *) NULL)
1237 indexes=GetAuthenticIndexQueue(image);
1238 if (jpeg_info.data_precision > 8)
1240 if (jpeg_info.output_components == 1)
1241 for (x=0; x < (ssize_t) image->columns; x++)
1246 if (precision != 16)
1247 pixel=(size_t) GETJSAMPLE(*p);
1249 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1250 index=ConstrainColormapIndex(image,pixel);
1251 SetIndexPixelComponent(indexes+x,index);
1252 SetRedPixelComponent(q,image->colormap[(int) index].red);
1253 SetGreenPixelComponent(q,image->colormap[(int) index].green);
1254 SetBluePixelComponent(q,image->colormap[(int) index].blue);
1259 if (image->colorspace != CMYKColorspace)
1260 for (x=0; x < (ssize_t) image->columns; x++)
1262 SetRedPixelComponent(q,ScaleShortToQuantum((unsigned char)
1263 (GETJSAMPLE(*p++) << 4)));
1264 SetGreenPixelComponent(q,ScaleShortToQuantum((unsigned char)
1265 (GETJSAMPLE(*p++) << 4)));
1266 SetBluePixelComponent(q,ScaleShortToQuantum((unsigned char)
1267 (GETJSAMPLE(*p++) << 4)));
1268 SetOpacityPixelComponent(q,OpaqueOpacity);
1272 for (x=0; x < (ssize_t) image->columns; x++)
1274 SetCyanPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1275 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1276 SetMagentaPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1277 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1278 SetYellowPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1279 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1280 SetBlackPixelComponent(indexes+x,QuantumRange-ScaleShortToQuantum(
1281 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1282 SetOpacityPixelComponent(q,OpaqueOpacity);
1287 if (jpeg_info.output_components == 1)
1288 for (x=0; x < (ssize_t) image->columns; x++)
1290 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1291 SetIndexPixelComponent(indexes+x,index);
1292 SetRedPixelComponent(q,image->colormap[(int) index].red);
1293 SetGreenPixelComponent(q,image->colormap[(int) index].green);
1294 SetBluePixelComponent(q,image->colormap[(int) index].blue);
1299 if (image->colorspace != CMYKColorspace)
1300 for (x=0; x < (ssize_t) image->columns; x++)
1302 SetRedPixelComponent(q,ScaleCharToQuantum((unsigned char)
1304 SetGreenPixelComponent(q,ScaleCharToQuantum((unsigned char)
1306 SetBluePixelComponent(q,ScaleCharToQuantum((unsigned char)
1308 SetOpacityPixelComponent(q,OpaqueOpacity);
1312 for (x=0; x < (ssize_t) image->columns; x++)
1314 SetCyanPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1315 (unsigned char) GETJSAMPLE(*p++)));
1316 SetMagentaPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1317 (unsigned char) GETJSAMPLE(*p++)));
1318 SetYellowPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1319 (unsigned char) GETJSAMPLE(*p++)));
1320 SetBlackPixelComponent(indexes+x,QuantumRange-ScaleCharToQuantum(
1321 (unsigned char) GETJSAMPLE(*p++)));
1322 SetOpacityPixelComponent(q,OpaqueOpacity);
1325 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1327 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1329 if (status == MagickFalse)
1331 jpeg_abort_decompress(&jpeg_info);
1335 if (status != MagickFalse)
1337 error_manager.finished=MagickTrue;
1338 if (setjmp(error_manager.error_recovery) == 0)
1339 (void) jpeg_finish_decompress(&jpeg_info);
1342 Free jpeg resources.
1344 jpeg_destroy_decompress(&jpeg_info);
1345 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1346 (void) CloseBlob(image);
1347 return(GetFirstImageInList(image));
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356 % R e g i s t e r J P E G I m a g e %
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 % RegisterJPEGImage() adds properties for the JPEG image format to
1363 % the list of supported formats. The properties include the image format
1364 % tag, a method to read and/or write the format, whether the format
1365 % supports the saving of more than one frame to the same file or blob,
1366 % whether the format supports native in-memory I/O, and a brief
1367 % description of the format.
1369 % The format of the RegisterJPEGImage method is:
1371 % size_t RegisterJPEGImage(void)
1374 ModuleExport size_t RegisterJPEGImage(void)
1377 version[MaxTextExtent];
1383 description[] = "Joint Photographic Experts Group JFIF format";
1386 #if defined(JPEG_LIB_VERSION)
1387 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1389 entry=SetMagickInfo("JPEG");
1390 entry->thread_support=NoThreadSupport;
1391 #if defined(MAGICKCORE_JPEG_DELEGATE)
1392 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1393 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1395 entry->magick=(IsImageFormatHandler *) IsJPEG;
1396 entry->adjoin=MagickFalse;
1397 entry->description=ConstantString(description);
1398 if (*version != '\0')
1399 entry->version=ConstantString(version);
1400 entry->module=ConstantString("JPEG");
1401 (void) RegisterMagickInfo(entry);
1402 entry=SetMagickInfo("JPG");
1403 entry->thread_support=NoThreadSupport;
1404 #if defined(MAGICKCORE_JPEG_DELEGATE)
1405 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1406 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1408 entry->adjoin=MagickFalse;
1409 entry->description=ConstantString(description);
1410 if (*version != '\0')
1411 entry->version=ConstantString(version);
1412 entry->module=ConstantString("JPEG");
1413 (void) RegisterMagickInfo(entry);
1414 entry=SetMagickInfo("PJPEG");
1415 entry->thread_support=NoThreadSupport;
1416 #if defined(MAGICKCORE_JPEG_DELEGATE)
1417 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1418 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1420 entry->adjoin=MagickFalse;
1421 entry->description=ConstantString(description);
1422 if (*version != '\0')
1423 entry->version=ConstantString(version);
1424 entry->module=ConstantString("JPEG");
1425 (void) RegisterMagickInfo(entry);
1426 return(MagickImageCoderSignature);
1430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434 % U n r e g i s t e r J P E G I m a g e %
1438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % UnregisterJPEGImage() removes format registrations made by the
1441 % JPEG module from the list of supported formats.
1443 % The format of the UnregisterJPEGImage method is:
1445 % UnregisterJPEGImage(void)
1448 ModuleExport void UnregisterJPEGImage(void)
1450 (void) UnregisterMagickInfo("PJPG");
1451 (void) UnregisterMagickInfo("JPEG");
1452 (void) UnregisterMagickInfo("JPG");
1455 #if defined(MAGICKCORE_JPEG_DELEGATE)
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461 % W r i t e J P E G I m a g e %
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467 % WriteJPEGImage() writes a JPEG image file and returns it. It
1468 % allocates the memory necessary for the new Image structure and returns a
1469 % pointer to the new image.
1471 % The format of the WriteJPEGImage method is:
1473 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1476 % A description of each parameter follows:
1478 % o image_info: the image info.
1480 % o jpeg_image: The image.
1485 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1490 destination=(DestinationManager *) cinfo->dest;
1491 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1492 MaxBufferExtent,destination->buffer);
1493 if (destination->manager.free_in_buffer != MaxBufferExtent)
1494 ERREXIT(cinfo,JERR_FILE_WRITE);
1495 destination->manager.next_output_byte=destination->buffer;
1499 static void InitializeDestination(j_compress_ptr cinfo)
1504 destination=(DestinationManager *) cinfo->dest;
1505 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1506 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1507 destination->manager.next_output_byte=destination->buffer;
1508 destination->manager.free_in_buffer=MaxBufferExtent;
1511 static inline size_t MagickMin(const size_t x,const size_t y)
1518 static void TerminateDestination(j_compress_ptr cinfo)
1523 destination=(DestinationManager *) cinfo->dest;
1524 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1529 count=WriteBlob(destination->image,MaxBufferExtent-
1530 destination->manager.free_in_buffer,destination->buffer);
1531 if (count != (ssize_t)
1532 (MaxBufferExtent-destination->manager.free_in_buffer))
1533 ERREXIT(cinfo,JERR_FILE_WRITE);
1537 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1559 Save image profile as a APP marker.
1562 custom_profile=AcquireStringInfo(65535L);
1563 ResetImageProfileIterator(image);
1564 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1566 register unsigned char
1569 profile=GetImageProfile(image,name);
1570 p=GetStringInfoDatum(custom_profile);
1571 if (LocaleCompare(name,"EXIF") == 0)
1572 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1574 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1575 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1576 (unsigned int) length);
1578 if (LocaleCompare(name,"ICC") == 0)
1580 register unsigned char
1584 p=GetStringInfoDatum(custom_profile);
1585 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1586 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1588 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1589 p[12]=(unsigned char) ((i/65519L)+1);
1590 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1591 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1593 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1594 custom_profile),(unsigned int) (length+tag_length));
1597 if (((LocaleCompare(name,"IPTC") == 0) ||
1598 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1604 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1606 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1607 roundup=(size_t) (length & 0x01);
1608 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1610 (void) memcpy(p,"Photoshop 3.0 ",14);
1615 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1617 p[24]=(unsigned char) (length >> 8);
1618 p[25]=(unsigned char) (length & 0xff);
1621 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1623 p[length+tag_length]='\0';
1624 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1625 custom_profile),(unsigned int) (length+tag_length+roundup));
1628 if (LocaleCompare(name,"XMP") == 0)
1634 Add namespace to XMP profile.
1636 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1637 ConcatenateStringInfo(xmp_profile,profile);
1638 GetStringInfoDatum(xmp_profile)[28]='\0';
1639 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1641 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1642 jpeg_write_marker(jpeg_info,XML_MARKER,
1643 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1645 xmp_profile=DestroyStringInfo(xmp_profile);
1647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1648 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1649 name=GetNextImageProfile(image);
1651 custom_profile=DestroyStringInfo(custom_profile);
1654 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1659 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1660 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1661 destination=(DestinationManager *) cinfo->dest;
1662 destination->manager.init_destination=InitializeDestination;
1663 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1664 destination->manager.term_destination=TerminateDestination;
1665 destination->image=image;
1668 static char **SamplingFactorToList(const char *text)
1685 if (text == (char *) NULL)
1686 return((char **) NULL);
1688 Convert string to an ASCII list.
1691 for (p=text; *p != '\0'; p++)
1694 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1696 if (textlist == (char **) NULL)
1697 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1699 for (i=0; i < (ssize_t) lines; i++)
1701 for (q=(char *) p; *q != '\0'; q++)
1704 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1705 sizeof(*textlist[i]));
1706 if (textlist[i] == (char *) NULL)
1707 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1708 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1713 textlist[i]=(char *) NULL;
1717 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1746 struct jpeg_compress_struct
1749 struct jpeg_error_mgr
1755 assert(image_info != (const ImageInfo *) NULL);
1756 assert(image_info->signature == MagickSignature);
1757 assert(image != (Image *) NULL);
1758 assert(image->signature == MagickSignature);
1759 if (image->debug != MagickFalse)
1760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1761 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1762 if (status == MagickFalse)
1765 Initialize JPEG parameters.
1767 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1768 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1769 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1770 jpeg_info.client_data=(void *) image;
1771 jpeg_info.err=jpeg_std_error(&jpeg_error);
1772 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1773 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1774 error_manager.image=image;
1775 jpeg_pixels=(JSAMPLE *) NULL;
1776 if (setjmp(error_manager.error_recovery) != 0)
1778 jpeg_destroy_compress(&jpeg_info);
1779 (void) CloseBlob(image);
1780 return(MagickFalse);
1782 jpeg_info.client_data=(void *) &error_manager;
1783 jpeg_create_compress(&jpeg_info);
1784 JPEGDestinationManager(&jpeg_info,image);
1785 if ((image->columns != (unsigned int) image->columns) ||
1786 (image->rows != (unsigned int) image->rows))
1787 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1788 jpeg_info.image_width=(unsigned int) image->columns;
1789 jpeg_info.image_height=(unsigned int) image->rows;
1790 jpeg_info.input_components=3;
1791 jpeg_info.data_precision=8;
1792 jpeg_info.in_color_space=JCS_RGB;
1793 switch (image->colorspace)
1795 case CMYKColorspace:
1797 jpeg_info.input_components=4;
1798 jpeg_info.in_color_space=JCS_CMYK;
1801 case YCbCrColorspace:
1802 case Rec601YCbCrColorspace:
1803 case Rec709YCbCrColorspace:
1805 jpeg_info.in_color_space=JCS_YCbCr;
1808 case GRAYColorspace:
1809 case Rec601LumaColorspace:
1810 case Rec709LumaColorspace:
1812 jpeg_info.input_components=1;
1813 jpeg_info.in_color_space=JCS_GRAYSCALE;
1818 if (image->colorspace != RGBColorspace)
1819 (void) TransformImageColorspace(image,RGBColorspace);
1823 if ((image_info->type != TrueColorType) &&
1824 (IsGrayImage(image,&image->exception) != MagickFalse))
1826 jpeg_info.input_components=1;
1827 jpeg_info.in_color_space=JCS_GRAYSCALE;
1829 jpeg_set_defaults(&jpeg_info);
1830 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1831 jpeg_info.data_precision=8;
1833 if (sizeof(JSAMPLE) > 1)
1834 jpeg_info.data_precision=12;
1835 jpeg_info.density_unit=(UINT8) 1;
1836 if (image->debug != MagickFalse)
1837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1838 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1839 floor(image->y_resolution+0.5));
1840 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1843 Set image resolution.
1845 jpeg_info.write_JFIF_header=MagickTrue;
1846 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1847 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1848 if (image->units == PixelsPerInchResolution)
1849 jpeg_info.density_unit=(UINT8) 1;
1850 if (image->units == PixelsPerCentimeterResolution)
1851 jpeg_info.density_unit=(UINT8) 2;
1853 option=GetImageOption(image_info,"jpeg:dct-method");
1854 if (option != (const char *) NULL)
1860 if (LocaleCompare(option,"default") == 0)
1861 jpeg_info.dct_method=JDCT_DEFAULT;
1867 if (LocaleCompare(option,"fastest") == 0)
1868 jpeg_info.dct_method=JDCT_FASTEST;
1869 if (LocaleCompare(option,"float") == 0)
1870 jpeg_info.dct_method=JDCT_FLOAT;
1876 if (LocaleCompare(option,"ifast") == 0)
1877 jpeg_info.dct_method=JDCT_IFAST;
1878 if (LocaleCompare(option,"islow") == 0)
1879 jpeg_info.dct_method=JDCT_ISLOW;
1883 option=GetImageOption(image_info,"jpeg:optimize-coding");
1884 if (option != (const char *) NULL)
1886 jpeg_info.optimize_coding=MagickFalse;
1887 if (IsMagickTrue(option) != MagickFalse)
1888 jpeg_info.optimize_coding=MagickTrue;
1895 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1896 image->rows*sizeof(JSAMPLE);
1897 if (length == (MagickSizeType) ((size_t) length))
1900 Perform optimization only if available memory resources permit it.
1902 status=AcquireMagickResource(MemoryResource,length);
1903 if (status != MagickFalse)
1904 jpeg_info.optimize_coding=MagickTrue;
1905 RelinquishMagickResource(MemoryResource,length);
1908 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1909 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1910 (image_info->interlace != NoInterlace))
1912 if (image->debug != MagickFalse)
1913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1914 "Interlace: progressive");
1915 jpeg_simple_progression(&jpeg_info);
1918 if (image->debug != MagickFalse)
1919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1920 "Interlace: non-progressive");
1922 if (image->debug != MagickFalse)
1923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1924 "Interlace: nonprogressive");
1926 option=GetImageOption(image_info,"jpeg:extent");
1927 if (option != (const char *) NULL)
1935 jpeg_info=CloneImageInfo(image_info);
1936 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1937 if (jpeg_image != (Image *) NULL)
1947 Search for compression quality that does not exceed image extent.
1949 jpeg_info->quality=0;
1950 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1951 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1952 (void) AcquireUniqueFilename(jpeg_image->filename);
1954 for (minimum=0; minimum != maximum; )
1956 jpeg_image->quality=minimum+(maximum-minimum)/2;
1957 status=WriteJPEGImage(jpeg_info,jpeg_image);
1958 if (GetBlobSize(jpeg_image) <= extent)
1959 minimum=jpeg_image->quality+1;
1961 maximum=jpeg_image->quality-1;
1963 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1964 image->quality=minimum-1;
1965 jpeg_image=DestroyImage(jpeg_image);
1967 jpeg_info=DestroyImageInfo(jpeg_info);
1969 if ((image_info->compression != LosslessJPEGCompression) &&
1970 (image->quality <= 100))
1972 if (image->quality == UndefinedCompressionQuality)
1973 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1975 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1976 if (image->debug != MagickFalse)
1977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
1978 (double) image->quality);
1982 #if !defined(C_LOSSLESS_SUPPORTED)
1983 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1984 if (image->debug != MagickFalse)
1985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1987 if (image->quality < 100)
1988 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1989 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1996 predictor=image->quality/100; /* range 1-7 */
1997 point_transform=image->quality % 20; /* range 0-15 */
1998 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1999 if (image->debug != MagickFalse)
2001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2002 "Compression: lossless");
2003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2004 "Predictor: %d",predictor);
2005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2006 "Point Transform: %d",point_transform);
2011 sampling_factor=(const char *) NULL;
2012 value=GetImageProperty(image,"jpeg:sampling-factor");
2013 if (value != (char *) NULL)
2015 sampling_factor=value;
2016 if (image->debug != MagickFalse)
2017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2018 " Input sampling-factors=%s",sampling_factor);
2020 if (image_info->sampling_factor != (char *) NULL)
2021 sampling_factor=image_info->sampling_factor;
2022 if (sampling_factor == (const char *) NULL)
2024 if (image->quality >= 90)
2025 for (i=0; i < MAX_COMPONENTS; i++)
2027 jpeg_info.comp_info[i].h_samp_factor=1;
2028 jpeg_info.comp_info[i].v_samp_factor=1;
2043 Set sampling factor.
2046 factors=SamplingFactorToList(sampling_factor);
2047 if (factors != (char **) NULL)
2049 for (i=0; i < MAX_COMPONENTS; i++)
2051 if (factors[i] == (char *) NULL)
2053 flags=ParseGeometry(factors[i],&geometry_info);
2054 if ((flags & SigmaValue) == 0)
2055 geometry_info.sigma=geometry_info.rho;
2056 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2057 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2058 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2060 factors=(char **) RelinquishMagickMemory(factors);
2062 for ( ; i < MAX_COMPONENTS; i++)
2064 jpeg_info.comp_info[i].h_samp_factor=1;
2065 jpeg_info.comp_info[i].v_samp_factor=1;
2068 if (jpeg_info.input_components == 1)
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;
2074 jpeg_start_compress(&jpeg_info,MagickTrue);
2075 if (image->debug != MagickFalse)
2077 if (image->storage_class == PseudoClass)
2078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2079 "Storage class: PseudoClass");
2081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2082 "Storage class: DirectClass");
2083 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2084 (double) image->depth);
2085 if (image->colors != 0)
2086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2087 "Number of colors: %.20g",(double) image->colors);
2089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2090 "Number of colors: unspecified");
2091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2092 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2093 switch (image->colorspace)
2095 case CMYKColorspace:
2097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2098 "Storage class: DirectClass");
2099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2100 "Colorspace: CMYK");
2103 case YCbCrColorspace:
2104 case Rec601YCbCrColorspace:
2105 case Rec709YCbCrColorspace:
2107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2108 "Colorspace: YCbCr");
2114 switch (image->colorspace)
2116 case CMYKColorspace:
2118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2119 "Colorspace: CMYK");
2120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2121 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2122 jpeg_info.comp_info[0].h_samp_factor,
2123 jpeg_info.comp_info[0].v_samp_factor,
2124 jpeg_info.comp_info[1].h_samp_factor,
2125 jpeg_info.comp_info[1].v_samp_factor,
2126 jpeg_info.comp_info[2].h_samp_factor,
2127 jpeg_info.comp_info[2].v_samp_factor,
2128 jpeg_info.comp_info[3].h_samp_factor,
2129 jpeg_info.comp_info[3].v_samp_factor);
2132 case GRAYColorspace:
2133 case Rec601LumaColorspace:
2134 case Rec709LumaColorspace:
2136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2137 "Colorspace: GRAY");
2138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2139 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2140 jpeg_info.comp_info[0].v_samp_factor);
2145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2146 "Image colorspace is RGB");
2147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2148 "Sampling factors: %dx%d,%dx%d,%dx%d",
2149 jpeg_info.comp_info[0].h_samp_factor,
2150 jpeg_info.comp_info[0].v_samp_factor,
2151 jpeg_info.comp_info[1].h_samp_factor,
2152 jpeg_info.comp_info[1].v_samp_factor,
2153 jpeg_info.comp_info[2].h_samp_factor,
2154 jpeg_info.comp_info[2].v_samp_factor);
2157 case YCbCrColorspace:
2158 case Rec601YCbCrColorspace:
2159 case Rec709YCbCrColorspace:
2161 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2162 "Colorspace: YCbCr");
2163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2164 "Sampling factors: %dx%d,%dx%d,%dx%d",
2165 jpeg_info.comp_info[0].h_samp_factor,
2166 jpeg_info.comp_info[0].v_samp_factor,
2167 jpeg_info.comp_info[1].h_samp_factor,
2168 jpeg_info.comp_info[1].v_samp_factor,
2169 jpeg_info.comp_info[2].h_samp_factor,
2170 jpeg_info.comp_info[2].v_samp_factor);
2175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2178 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2179 jpeg_info.comp_info[0].h_samp_factor,
2180 jpeg_info.comp_info[0].v_samp_factor,
2181 jpeg_info.comp_info[1].h_samp_factor,
2182 jpeg_info.comp_info[1].v_samp_factor,
2183 jpeg_info.comp_info[2].h_samp_factor,
2184 jpeg_info.comp_info[2].v_samp_factor,
2185 jpeg_info.comp_info[3].h_samp_factor,
2186 jpeg_info.comp_info[3].v_samp_factor);
2192 Write JPEG profiles.
2194 value=GetImageProperty(image,"comment");
2195 if (value != (char *) NULL)
2196 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2197 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2198 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2199 if (image->profiles != (void *) NULL)
2200 WriteProfile(&jpeg_info,image);
2202 Convert MIFF to JPEG raster pixels.
2204 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2205 jpeg_info.input_components*sizeof(*jpeg_pixels));
2206 if (jpeg_pixels == (JSAMPLE *) NULL)
2207 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2208 if (setjmp(error_manager.error_recovery) != 0)
2210 jpeg_destroy_compress(&jpeg_info);
2211 if (jpeg_pixels != (unsigned char *) NULL)
2212 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2213 (void) CloseBlob(image);
2214 return(MagickFalse);
2216 scanline[0]=(JSAMPROW) jpeg_pixels;
2217 if (jpeg_info.data_precision <= 8)
2219 if ((jpeg_info.in_color_space == JCS_RGB) ||
2220 (jpeg_info.in_color_space == JCS_YCbCr))
2221 for (y=0; y < (ssize_t) image->rows; y++)
2223 register const PixelPacket
2229 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2230 if (p == (const PixelPacket *) NULL)
2233 for (x=0; x < (ssize_t) image->columns; x++)
2235 *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
2236 *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
2237 *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
2240 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2241 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2243 if (status == MagickFalse)
2247 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2248 for (y=0; y < (ssize_t) image->rows; y++)
2250 register const PixelPacket
2256 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2257 if (p == (const PixelPacket *) NULL)
2260 for (x=0; x < (ssize_t) image->columns; x++)
2262 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2265 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2266 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2268 if (status == MagickFalse)
2272 for (y=0; y < (ssize_t) image->rows; y++)
2274 register const IndexPacket
2277 register const PixelPacket
2283 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2284 if (p == (const PixelPacket *) NULL)
2287 indexes=GetVirtualIndexQueue(image);
2288 for (x=0; x < (ssize_t) image->columns; x++)
2291 Convert DirectClass packets to contiguous CMYK scanlines.
2293 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2294 GetRedPixelComponent(p))));
2295 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2296 GetGreenPixelComponent(p))));
2297 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2298 GetBluePixelComponent(p))));
2299 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2300 GetIndexPixelComponent(indexes+x))));
2303 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2304 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2306 if (status == MagickFalse)
2311 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2312 for (y=0; y < (ssize_t) image->rows; y++)
2314 register const PixelPacket
2320 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2321 if (p == (const PixelPacket *) NULL)
2324 for (x=0; x < (ssize_t) image->columns; x++)
2326 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2330 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2331 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2333 if (status == MagickFalse)
2337 if ((jpeg_info.in_color_space == JCS_RGB) ||
2338 (jpeg_info.in_color_space == JCS_YCbCr))
2339 for (y=0; y < (ssize_t) image->rows; y++)
2341 register const PixelPacket
2347 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2348 if (p == (const PixelPacket *) NULL)
2351 for (x=0; x < (ssize_t) image->columns; x++)
2353 *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >>
2355 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >>
2357 *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >>
2361 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2362 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2364 if (status == MagickFalse)
2368 for (y=0; y < (ssize_t) image->rows; y++)
2370 register const IndexPacket
2373 register const PixelPacket
2379 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2380 if (p == (const PixelPacket *) NULL)
2383 indexes=GetVirtualIndexQueue(image);
2384 for (x=0; x < (ssize_t) image->columns; x++)
2387 Convert DirectClass packets to contiguous CMYK scanlines.
2389 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2390 GetRedPixelComponent(p)) >> 4));
2391 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2392 GetGreenPixelComponent(p)) >> 4));
2393 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2394 GetBluePixelComponent(p)) >> 4));
2395 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2396 GetIndexPixelComponent(indexes+x)) >> 4));
2399 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2400 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2402 if (status == MagickFalse)
2405 if (y == (ssize_t) image->rows)
2406 jpeg_finish_compress(&jpeg_info);
2408 Relinquish resources.
2410 jpeg_destroy_compress(&jpeg_info);
2411 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2412 (void) CloseBlob(image);