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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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) FormatLocaleString(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 SetRGBOPixelComponent(q,image->colormap+index);
1257 if (image->colorspace != CMYKColorspace)
1258 for (x=0; x < (ssize_t) image->columns; x++)
1260 SetRedPixelComponent(q,ScaleShortToQuantum((unsigned char)
1261 (GETJSAMPLE(*p++) << 4)));
1262 SetGreenPixelComponent(q,ScaleShortToQuantum((unsigned char)
1263 (GETJSAMPLE(*p++) << 4)));
1264 SetBluePixelComponent(q,ScaleShortToQuantum((unsigned char)
1265 (GETJSAMPLE(*p++) << 4)));
1266 SetOpacityPixelComponent(q,OpaqueOpacity);
1270 for (x=0; x < (ssize_t) image->columns; x++)
1272 SetCyanPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1273 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1274 SetMagentaPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1275 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1276 SetYellowPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1277 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1278 SetBlackPixelComponent(indexes+x,QuantumRange-ScaleShortToQuantum(
1279 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1280 SetOpacityPixelComponent(q,OpaqueOpacity);
1285 if (jpeg_info.output_components == 1)
1286 for (x=0; x < (ssize_t) image->columns; x++)
1288 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1289 SetIndexPixelComponent(indexes+x,index);
1290 SetRGBOPixelComponent(q,image->colormap+index);
1295 if (image->colorspace != CMYKColorspace)
1296 for (x=0; x < (ssize_t) image->columns; x++)
1298 SetRedPixelComponent(q,ScaleCharToQuantum((unsigned char)
1300 SetGreenPixelComponent(q,ScaleCharToQuantum((unsigned char)
1302 SetBluePixelComponent(q,ScaleCharToQuantum((unsigned char)
1304 SetOpacityPixelComponent(q,OpaqueOpacity);
1308 for (x=0; x < (ssize_t) image->columns; x++)
1310 SetCyanPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1311 (unsigned char) GETJSAMPLE(*p++)));
1312 SetMagentaPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1313 (unsigned char) GETJSAMPLE(*p++)));
1314 SetYellowPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1315 (unsigned char) GETJSAMPLE(*p++)));
1316 SetBlackPixelComponent(indexes+x,QuantumRange-ScaleCharToQuantum(
1317 (unsigned char) GETJSAMPLE(*p++)));
1318 SetOpacityPixelComponent(q,OpaqueOpacity);
1321 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1323 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1325 if (status == MagickFalse)
1327 jpeg_abort_decompress(&jpeg_info);
1331 if (status != MagickFalse)
1333 error_manager.finished=MagickTrue;
1334 if (setjmp(error_manager.error_recovery) == 0)
1335 (void) jpeg_finish_decompress(&jpeg_info);
1338 Free jpeg resources.
1340 jpeg_destroy_decompress(&jpeg_info);
1341 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1342 (void) CloseBlob(image);
1343 return(GetFirstImageInList(image));
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352 % R e g i s t e r J P E G I m a g e %
1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358 % RegisterJPEGImage() adds properties for the JPEG image format to
1359 % the list of supported formats. The properties include the image format
1360 % tag, a method to read and/or write the format, whether the format
1361 % supports the saving of more than one frame to the same file or blob,
1362 % whether the format supports native in-memory I/O, and a brief
1363 % description of the format.
1365 % The format of the RegisterJPEGImage method is:
1367 % size_t RegisterJPEGImage(void)
1370 ModuleExport size_t RegisterJPEGImage(void)
1373 version[MaxTextExtent];
1379 description[] = "Joint Photographic Experts Group JFIF format";
1382 #if defined(JPEG_LIB_VERSION)
1383 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1385 entry=SetMagickInfo("JPEG");
1386 entry->thread_support=NoThreadSupport;
1387 #if defined(MAGICKCORE_JPEG_DELEGATE)
1388 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1389 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1391 entry->magick=(IsImageFormatHandler *) IsJPEG;
1392 entry->adjoin=MagickFalse;
1393 entry->description=ConstantString(description);
1394 if (*version != '\0')
1395 entry->version=ConstantString(version);
1396 entry->module=ConstantString("JPEG");
1397 (void) RegisterMagickInfo(entry);
1398 entry=SetMagickInfo("JPG");
1399 entry->thread_support=NoThreadSupport;
1400 #if defined(MAGICKCORE_JPEG_DELEGATE)
1401 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1402 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1404 entry->adjoin=MagickFalse;
1405 entry->description=ConstantString(description);
1406 if (*version != '\0')
1407 entry->version=ConstantString(version);
1408 entry->module=ConstantString("JPEG");
1409 (void) RegisterMagickInfo(entry);
1410 entry=SetMagickInfo("PJPEG");
1411 entry->thread_support=NoThreadSupport;
1412 #if defined(MAGICKCORE_JPEG_DELEGATE)
1413 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1414 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1416 entry->adjoin=MagickFalse;
1417 entry->description=ConstantString(description);
1418 if (*version != '\0')
1419 entry->version=ConstantString(version);
1420 entry->module=ConstantString("JPEG");
1421 (void) RegisterMagickInfo(entry);
1422 return(MagickImageCoderSignature);
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430 % U n r e g i s t e r J P E G I m a g e %
1434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436 % UnregisterJPEGImage() removes format registrations made by the
1437 % JPEG module from the list of supported formats.
1439 % The format of the UnregisterJPEGImage method is:
1441 % UnregisterJPEGImage(void)
1444 ModuleExport void UnregisterJPEGImage(void)
1446 (void) UnregisterMagickInfo("PJPG");
1447 (void) UnregisterMagickInfo("JPEG");
1448 (void) UnregisterMagickInfo("JPG");
1451 #if defined(MAGICKCORE_JPEG_DELEGATE)
1453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 % W r i t e J P E G I m a g e %
1461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463 % WriteJPEGImage() writes a JPEG image file and returns it. It
1464 % allocates the memory necessary for the new Image structure and returns a
1465 % pointer to the new image.
1467 % The format of the WriteJPEGImage method is:
1469 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1472 % A description of each parameter follows:
1474 % o image_info: the image info.
1476 % o jpeg_image: The image.
1481 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1486 destination=(DestinationManager *) cinfo->dest;
1487 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1488 MaxBufferExtent,destination->buffer);
1489 if (destination->manager.free_in_buffer != MaxBufferExtent)
1490 ERREXIT(cinfo,JERR_FILE_WRITE);
1491 destination->manager.next_output_byte=destination->buffer;
1495 static void InitializeDestination(j_compress_ptr cinfo)
1500 destination=(DestinationManager *) cinfo->dest;
1501 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1502 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1503 destination->manager.next_output_byte=destination->buffer;
1504 destination->manager.free_in_buffer=MaxBufferExtent;
1507 static inline size_t MagickMin(const size_t x,const size_t y)
1514 static void TerminateDestination(j_compress_ptr cinfo)
1519 destination=(DestinationManager *) cinfo->dest;
1520 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1525 count=WriteBlob(destination->image,MaxBufferExtent-
1526 destination->manager.free_in_buffer,destination->buffer);
1527 if (count != (ssize_t)
1528 (MaxBufferExtent-destination->manager.free_in_buffer))
1529 ERREXIT(cinfo,JERR_FILE_WRITE);
1533 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1555 Save image profile as a APP marker.
1558 custom_profile=AcquireStringInfo(65535L);
1559 ResetImageProfileIterator(image);
1560 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1562 register unsigned char
1565 profile=GetImageProfile(image,name);
1566 p=GetStringInfoDatum(custom_profile);
1567 if (LocaleCompare(name,"EXIF") == 0)
1568 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1570 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1571 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1572 (unsigned int) length);
1574 if (LocaleCompare(name,"ICC") == 0)
1576 register unsigned char
1580 p=GetStringInfoDatum(custom_profile);
1581 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1582 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1584 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1585 p[12]=(unsigned char) ((i/65519L)+1);
1586 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1587 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1589 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1590 custom_profile),(unsigned int) (length+tag_length));
1593 if (((LocaleCompare(name,"IPTC") == 0) ||
1594 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1600 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1602 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1603 roundup=(size_t) (length & 0x01);
1604 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1606 (void) memcpy(p,"Photoshop 3.0 ",14);
1611 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1613 p[24]=(unsigned char) (length >> 8);
1614 p[25]=(unsigned char) (length & 0xff);
1617 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1619 p[length+tag_length]='\0';
1620 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1621 custom_profile),(unsigned int) (length+tag_length+roundup));
1624 if (LocaleCompare(name,"XMP") == 0)
1630 Add namespace to XMP profile.
1632 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1633 ConcatenateStringInfo(xmp_profile,profile);
1634 GetStringInfoDatum(xmp_profile)[28]='\0';
1635 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1637 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1638 jpeg_write_marker(jpeg_info,XML_MARKER,
1639 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1641 xmp_profile=DestroyStringInfo(xmp_profile);
1643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1644 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1645 name=GetNextImageProfile(image);
1647 custom_profile=DestroyStringInfo(custom_profile);
1650 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1655 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1656 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1657 destination=(DestinationManager *) cinfo->dest;
1658 destination->manager.init_destination=InitializeDestination;
1659 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1660 destination->manager.term_destination=TerminateDestination;
1661 destination->image=image;
1664 static char **SamplingFactorToList(const char *text)
1681 if (text == (char *) NULL)
1682 return((char **) NULL);
1684 Convert string to an ASCII list.
1687 for (p=text; *p != '\0'; p++)
1690 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1692 if (textlist == (char **) NULL)
1693 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1695 for (i=0; i < (ssize_t) lines; i++)
1697 for (q=(char *) p; *q != '\0'; q++)
1700 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1701 sizeof(*textlist[i]));
1702 if (textlist[i] == (char *) NULL)
1703 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1704 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1709 textlist[i]=(char *) NULL;
1713 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1742 struct jpeg_compress_struct
1745 struct jpeg_error_mgr
1751 assert(image_info != (const ImageInfo *) NULL);
1752 assert(image_info->signature == MagickSignature);
1753 assert(image != (Image *) NULL);
1754 assert(image->signature == MagickSignature);
1755 if (image->debug != MagickFalse)
1756 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1757 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1758 if (status == MagickFalse)
1761 Initialize JPEG parameters.
1763 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1764 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1765 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1766 jpeg_info.client_data=(void *) image;
1767 jpeg_info.err=jpeg_std_error(&jpeg_error);
1768 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1769 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1770 error_manager.image=image;
1771 jpeg_pixels=(JSAMPLE *) NULL;
1772 if (setjmp(error_manager.error_recovery) != 0)
1774 jpeg_destroy_compress(&jpeg_info);
1775 (void) CloseBlob(image);
1776 return(MagickFalse);
1778 jpeg_info.client_data=(void *) &error_manager;
1779 jpeg_create_compress(&jpeg_info);
1780 JPEGDestinationManager(&jpeg_info,image);
1781 if ((image->columns != (unsigned int) image->columns) ||
1782 (image->rows != (unsigned int) image->rows))
1783 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1784 jpeg_info.image_width=(unsigned int) image->columns;
1785 jpeg_info.image_height=(unsigned int) image->rows;
1786 jpeg_info.input_components=3;
1787 jpeg_info.data_precision=8;
1788 jpeg_info.in_color_space=JCS_RGB;
1789 switch (image->colorspace)
1791 case CMYKColorspace:
1793 jpeg_info.input_components=4;
1794 jpeg_info.in_color_space=JCS_CMYK;
1797 case YCbCrColorspace:
1798 case Rec601YCbCrColorspace:
1799 case Rec709YCbCrColorspace:
1801 jpeg_info.in_color_space=JCS_YCbCr;
1804 case GRAYColorspace:
1805 case Rec601LumaColorspace:
1806 case Rec709LumaColorspace:
1808 jpeg_info.input_components=1;
1809 jpeg_info.in_color_space=JCS_GRAYSCALE;
1814 if (image->colorspace != RGBColorspace)
1815 (void) TransformImageColorspace(image,RGBColorspace);
1819 if ((image_info->type != TrueColorType) &&
1820 (IsGrayImage(image,&image->exception) != MagickFalse))
1822 jpeg_info.input_components=1;
1823 jpeg_info.in_color_space=JCS_GRAYSCALE;
1825 jpeg_set_defaults(&jpeg_info);
1826 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1827 jpeg_info.data_precision=8;
1829 if (sizeof(JSAMPLE) > 1)
1830 jpeg_info.data_precision=12;
1831 jpeg_info.density_unit=(UINT8) 1;
1832 if (image->debug != MagickFalse)
1833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1834 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1835 floor(image->y_resolution+0.5));
1836 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1839 Set image resolution.
1841 jpeg_info.write_JFIF_header=MagickTrue;
1842 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1843 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1844 if (image->units == PixelsPerInchResolution)
1845 jpeg_info.density_unit=(UINT8) 1;
1846 if (image->units == PixelsPerCentimeterResolution)
1847 jpeg_info.density_unit=(UINT8) 2;
1849 option=GetImageOption(image_info,"jpeg:dct-method");
1850 if (option != (const char *) NULL)
1856 if (LocaleCompare(option,"default") == 0)
1857 jpeg_info.dct_method=JDCT_DEFAULT;
1863 if (LocaleCompare(option,"fastest") == 0)
1864 jpeg_info.dct_method=JDCT_FASTEST;
1865 if (LocaleCompare(option,"float") == 0)
1866 jpeg_info.dct_method=JDCT_FLOAT;
1872 if (LocaleCompare(option,"ifast") == 0)
1873 jpeg_info.dct_method=JDCT_IFAST;
1874 if (LocaleCompare(option,"islow") == 0)
1875 jpeg_info.dct_method=JDCT_ISLOW;
1879 option=GetImageOption(image_info,"jpeg:optimize-coding");
1880 if (option != (const char *) NULL)
1882 jpeg_info.optimize_coding=MagickFalse;
1883 if (IsMagickTrue(option) != MagickFalse)
1884 jpeg_info.optimize_coding=MagickTrue;
1891 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1892 image->rows*sizeof(JSAMPLE);
1893 if (length == (MagickSizeType) ((size_t) length))
1896 Perform optimization only if available memory resources permit it.
1898 status=AcquireMagickResource(MemoryResource,length);
1899 if (status != MagickFalse)
1900 jpeg_info.optimize_coding=MagickTrue;
1901 RelinquishMagickResource(MemoryResource,length);
1904 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1905 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1906 (image_info->interlace != NoInterlace))
1908 if (image->debug != MagickFalse)
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1910 "Interlace: progressive");
1911 jpeg_simple_progression(&jpeg_info);
1914 if (image->debug != MagickFalse)
1915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1916 "Interlace: non-progressive");
1918 if (image->debug != MagickFalse)
1919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1920 "Interlace: nonprogressive");
1922 option=GetImageOption(image_info,"jpeg:extent");
1923 if (option != (const char *) NULL)
1931 jpeg_info=CloneImageInfo(image_info);
1932 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1933 if (jpeg_image != (Image *) NULL)
1943 Search for compression quality that does not exceed image extent.
1945 jpeg_info->quality=0;
1946 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1947 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1948 (void) AcquireUniqueFilename(jpeg_image->filename);
1950 for (minimum=0; minimum != maximum; )
1952 jpeg_image->quality=minimum+(maximum-minimum)/2;
1953 status=WriteJPEGImage(jpeg_info,jpeg_image);
1954 if (GetBlobSize(jpeg_image) <= extent)
1955 minimum=jpeg_image->quality+1;
1957 maximum=jpeg_image->quality-1;
1959 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1960 image->quality=minimum-1;
1961 jpeg_image=DestroyImage(jpeg_image);
1963 jpeg_info=DestroyImageInfo(jpeg_info);
1965 if ((image_info->compression != LosslessJPEGCompression) &&
1966 (image->quality <= 100))
1968 if (image->quality == UndefinedCompressionQuality)
1969 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1971 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1972 if (image->debug != MagickFalse)
1973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
1974 (double) image->quality);
1978 #if !defined(C_LOSSLESS_SUPPORTED)
1979 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1980 if (image->debug != MagickFalse)
1981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1983 if (image->quality < 100)
1984 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1985 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1992 predictor=image->quality/100; /* range 1-7 */
1993 point_transform=image->quality % 20; /* range 0-15 */
1994 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1995 if (image->debug != MagickFalse)
1997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1998 "Compression: lossless");
1999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2000 "Predictor: %d",predictor);
2001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2002 "Point Transform: %d",point_transform);
2007 sampling_factor=(const char *) NULL;
2008 value=GetImageProperty(image,"jpeg:sampling-factor");
2009 if (value != (char *) NULL)
2011 sampling_factor=value;
2012 if (image->debug != MagickFalse)
2013 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2014 " Input sampling-factors=%s",sampling_factor);
2016 if (image_info->sampling_factor != (char *) NULL)
2017 sampling_factor=image_info->sampling_factor;
2018 if (sampling_factor == (const char *) NULL)
2020 if (image->quality >= 90)
2021 for (i=0; i < MAX_COMPONENTS; i++)
2023 jpeg_info.comp_info[i].h_samp_factor=1;
2024 jpeg_info.comp_info[i].v_samp_factor=1;
2039 Set sampling factor.
2042 factors=SamplingFactorToList(sampling_factor);
2043 if (factors != (char **) NULL)
2045 for (i=0; i < MAX_COMPONENTS; i++)
2047 if (factors[i] == (char *) NULL)
2049 flags=ParseGeometry(factors[i],&geometry_info);
2050 if ((flags & SigmaValue) == 0)
2051 geometry_info.sigma=geometry_info.rho;
2052 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2053 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2054 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2056 factors=(char **) RelinquishMagickMemory(factors);
2058 for ( ; i < MAX_COMPONENTS; i++)
2060 jpeg_info.comp_info[i].h_samp_factor=1;
2061 jpeg_info.comp_info[i].v_samp_factor=1;
2064 if (jpeg_info.input_components == 1)
2065 for (i=0; i < MAX_COMPONENTS; i++)
2067 jpeg_info.comp_info[i].h_samp_factor=1;
2068 jpeg_info.comp_info[i].v_samp_factor=1;
2070 jpeg_start_compress(&jpeg_info,MagickTrue);
2071 if (image->debug != MagickFalse)
2073 if (image->storage_class == PseudoClass)
2074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2075 "Storage class: PseudoClass");
2077 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2078 "Storage class: DirectClass");
2079 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2080 (double) image->depth);
2081 if (image->colors != 0)
2082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2083 "Number of colors: %.20g",(double) image->colors);
2085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2086 "Number of colors: unspecified");
2087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2088 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2089 switch (image->colorspace)
2091 case CMYKColorspace:
2093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2094 "Storage class: DirectClass");
2095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2096 "Colorspace: CMYK");
2099 case YCbCrColorspace:
2100 case Rec601YCbCrColorspace:
2101 case Rec709YCbCrColorspace:
2103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2104 "Colorspace: YCbCr");
2110 switch (image->colorspace)
2112 case CMYKColorspace:
2114 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2115 "Colorspace: CMYK");
2116 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2117 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2118 jpeg_info.comp_info[0].h_samp_factor,
2119 jpeg_info.comp_info[0].v_samp_factor,
2120 jpeg_info.comp_info[1].h_samp_factor,
2121 jpeg_info.comp_info[1].v_samp_factor,
2122 jpeg_info.comp_info[2].h_samp_factor,
2123 jpeg_info.comp_info[2].v_samp_factor,
2124 jpeg_info.comp_info[3].h_samp_factor,
2125 jpeg_info.comp_info[3].v_samp_factor);
2128 case GRAYColorspace:
2129 case Rec601LumaColorspace:
2130 case Rec709LumaColorspace:
2132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2133 "Colorspace: GRAY");
2134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2135 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2136 jpeg_info.comp_info[0].v_samp_factor);
2141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2142 "Image colorspace is RGB");
2143 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2144 "Sampling factors: %dx%d,%dx%d,%dx%d",
2145 jpeg_info.comp_info[0].h_samp_factor,
2146 jpeg_info.comp_info[0].v_samp_factor,
2147 jpeg_info.comp_info[1].h_samp_factor,
2148 jpeg_info.comp_info[1].v_samp_factor,
2149 jpeg_info.comp_info[2].h_samp_factor,
2150 jpeg_info.comp_info[2].v_samp_factor);
2153 case YCbCrColorspace:
2154 case Rec601YCbCrColorspace:
2155 case Rec709YCbCrColorspace:
2157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2158 "Colorspace: YCbCr");
2159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2160 "Sampling factors: %dx%d,%dx%d,%dx%d",
2161 jpeg_info.comp_info[0].h_samp_factor,
2162 jpeg_info.comp_info[0].v_samp_factor,
2163 jpeg_info.comp_info[1].h_samp_factor,
2164 jpeg_info.comp_info[1].v_samp_factor,
2165 jpeg_info.comp_info[2].h_samp_factor,
2166 jpeg_info.comp_info[2].v_samp_factor);
2171 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2173 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2174 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2175 jpeg_info.comp_info[0].h_samp_factor,
2176 jpeg_info.comp_info[0].v_samp_factor,
2177 jpeg_info.comp_info[1].h_samp_factor,
2178 jpeg_info.comp_info[1].v_samp_factor,
2179 jpeg_info.comp_info[2].h_samp_factor,
2180 jpeg_info.comp_info[2].v_samp_factor,
2181 jpeg_info.comp_info[3].h_samp_factor,
2182 jpeg_info.comp_info[3].v_samp_factor);
2188 Write JPEG profiles.
2190 value=GetImageProperty(image,"comment");
2191 if (value != (char *) NULL)
2192 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2193 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2194 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2195 if (image->profiles != (void *) NULL)
2196 WriteProfile(&jpeg_info,image);
2198 Convert MIFF to JPEG raster pixels.
2200 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2201 jpeg_info.input_components*sizeof(*jpeg_pixels));
2202 if (jpeg_pixels == (JSAMPLE *) NULL)
2203 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2204 if (setjmp(error_manager.error_recovery) != 0)
2206 jpeg_destroy_compress(&jpeg_info);
2207 if (jpeg_pixels != (unsigned char *) NULL)
2208 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2209 (void) CloseBlob(image);
2210 return(MagickFalse);
2212 scanline[0]=(JSAMPROW) jpeg_pixels;
2213 if (jpeg_info.data_precision <= 8)
2215 if ((jpeg_info.in_color_space == JCS_RGB) ||
2216 (jpeg_info.in_color_space == JCS_YCbCr))
2217 for (y=0; y < (ssize_t) image->rows; y++)
2219 register const PixelPacket
2225 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2226 if (p == (const PixelPacket *) NULL)
2229 for (x=0; x < (ssize_t) image->columns; x++)
2231 *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
2232 *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
2233 *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
2236 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2237 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2239 if (status == MagickFalse)
2243 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2244 for (y=0; y < (ssize_t) image->rows; y++)
2246 register const PixelPacket
2252 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2253 if (p == (const PixelPacket *) NULL)
2256 for (x=0; x < (ssize_t) image->columns; x++)
2258 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2261 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2262 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2264 if (status == MagickFalse)
2268 for (y=0; y < (ssize_t) image->rows; y++)
2270 register const IndexPacket
2273 register const PixelPacket
2279 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2280 if (p == (const PixelPacket *) NULL)
2283 indexes=GetVirtualIndexQueue(image);
2284 for (x=0; x < (ssize_t) image->columns; x++)
2287 Convert DirectClass packets to contiguous CMYK scanlines.
2289 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2290 GetRedPixelComponent(p))));
2291 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2292 GetGreenPixelComponent(p))));
2293 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2294 GetBluePixelComponent(p))));
2295 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2296 GetIndexPixelComponent(indexes+x))));
2299 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2300 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2302 if (status == MagickFalse)
2307 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2308 for (y=0; y < (ssize_t) image->rows; y++)
2310 register const PixelPacket
2316 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2317 if (p == (const PixelPacket *) NULL)
2320 for (x=0; x < (ssize_t) image->columns; x++)
2322 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2326 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2327 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2329 if (status == MagickFalse)
2333 if ((jpeg_info.in_color_space == JCS_RGB) ||
2334 (jpeg_info.in_color_space == JCS_YCbCr))
2335 for (y=0; y < (ssize_t) image->rows; y++)
2337 register const PixelPacket
2343 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2344 if (p == (const PixelPacket *) NULL)
2347 for (x=0; x < (ssize_t) image->columns; x++)
2349 *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >>
2351 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >>
2353 *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >>
2357 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2358 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2360 if (status == MagickFalse)
2364 for (y=0; y < (ssize_t) image->rows; y++)
2366 register const IndexPacket
2369 register const PixelPacket
2375 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2376 if (p == (const PixelPacket *) NULL)
2379 indexes=GetVirtualIndexQueue(image);
2380 for (x=0; x < (ssize_t) image->columns; x++)
2383 Convert DirectClass packets to contiguous CMYK scanlines.
2385 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2386 GetRedPixelComponent(p)) >> 4));
2387 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2388 GetGreenPixelComponent(p)) >> 4));
2389 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2390 GetBluePixelComponent(p)) >> 4));
2391 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2392 GetIndexPixelComponent(indexes+x)) >> 4));
2395 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2396 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2398 if (status == MagickFalse)
2401 if (y == (ssize_t) image->rows)
2402 jpeg_finish_compress(&jpeg_info);
2404 Relinquish resources.
2406 jpeg_destroy_compress(&jpeg_info);
2407 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2408 (void) CloseBlob(image);