2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2010 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/colorspace.h"
54 #include "magick/constitute.h"
55 #include "magick/exception.h"
56 #include "magick/exception-private.h"
57 #include "magick/geometry.h"
58 #include "magick/image.h"
59 #include "magick/image-private.h"
60 #include "magick/list.h"
61 #include "magick/log.h"
62 #include "magick/magick.h"
63 #include "magick/memory_.h"
64 #include "magick/module.h"
65 #include "magick/monitor.h"
66 #include "magick/monitor-private.h"
67 #include "magick/option.h"
68 #include "magick/profile.h"
69 #include "magick/property.h"
70 #include "magick/quantum-private.h"
71 #include "magick/resource_.h"
72 #include "magick/splay-tree.h"
73 #include "magick/static.h"
74 #include "magick/string_.h"
75 #include "magick/string-private.h"
76 #include "magick/utility.h"
78 #if defined(MAGICKCORE_JPEG_DELEGATE)
79 #define JPEG_INTERNAL_OPTIONS
80 #if defined(__MINGW32__)
81 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
91 #define ICC_MARKER (JPEG_APP0+2)
92 #define ICC_PROFILE "ICC_PROFILE"
93 #define IPTC_MARKER (JPEG_APP0+13)
94 #define XML_MARKER (JPEG_APP0+1)
95 #define MaxBufferExtent 8192
100 #if defined(MAGICKCORE_JPEG_DELEGATE)
101 typedef struct _DestinationManager
103 struct jpeg_destination_mgr
111 } DestinationManager;
113 typedef struct _ErrorManager
122 typedef struct _SourceManager
124 struct jpeg_source_mgr
139 Forward declarations.
141 #if defined(MAGICKCORE_JPEG_DELEGATE)
142 static MagickBooleanType
143 WriteJPEGImage(const ImageInfo *,Image *);
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 % IsJPEG() returns MagickTrue if the image format type, identified by the
158 % magick string, is JPEG.
160 % The format of the IsJPEG method is:
162 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
164 % A description of each parameter follows:
166 % o magick: compare image format pattern against these bytes.
168 % o length: Specifies the length of the magick string.
171 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
175 if (memcmp(magick,"\377\330\377",3) == 0)
180 #if defined(MAGICKCORE_JPEG_DELEGATE)
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 % R e a d J P E G I m a g e %
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
193 % the memory necessary for the new Image structure and returns a pointer to
196 % The format of the ReadJPEGImage method is:
198 % Image *ReadJPEGImage(const ImageInfo *image_info,
199 % ExceptionInfo *exception)
201 % A description of each parameter follows:
203 % o image_info: the image info.
205 % o exception: return any errors or warnings in this structure.
209 static MagickBooleanType EmitMessage(j_common_ptr jpeg_info,int level)
212 message[JMSG_LENGTH_MAX];
220 (jpeg_info->err->format_message)(jpeg_info,message);
221 error_manager=(ErrorManager *) jpeg_info->client_data;
222 image=error_manager->image;
225 if ((jpeg_info->err->num_warnings == 0) ||
226 (jpeg_info->err->trace_level >= 3))
227 ThrowBinaryException(CorruptImageWarning,(char *) message,
229 jpeg_info->err->num_warnings++;
232 if (jpeg_info->err->trace_level >= level)
233 ThrowBinaryException(CoderError,(char *) message,image->filename);
237 static boolean FillInputBuffer(j_decompress_ptr cinfo)
242 source=(SourceManager *) cinfo->src;
243 source->manager.bytes_in_buffer=(size_t)
244 ReadBlob(source->image,MaxBufferExtent,source->buffer);
245 if (source->manager.bytes_in_buffer == 0)
247 if (source->start_of_blob != 0)
248 ERREXIT(cinfo,JERR_INPUT_EMPTY);
249 WARNMS(cinfo,JWRN_JPEG_EOF);
250 source->buffer[0]=(JOCTET) 0xff;
251 source->buffer[1]=(JOCTET) JPEG_EOI;
252 source->manager.bytes_in_buffer=2;
254 source->manager.next_input_byte=source->buffer;
255 source->start_of_blob=FALSE;
259 static int GetCharacter(j_decompress_ptr jpeg_info)
261 if (jpeg_info->src->bytes_in_buffer == 0)
262 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
263 jpeg_info->src->bytes_in_buffer--;
264 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
267 static void InitializeSource(j_decompress_ptr cinfo)
272 source=(SourceManager *) cinfo->src;
273 source->start_of_blob=TRUE;
276 static MagickBooleanType IsITUFaxImage(const Image *image)
284 profile=GetImageProfile(image,"8bim");
285 if (profile == (const StringInfo *) NULL)
287 if (GetStringInfoLength(profile) < 5)
289 datum=GetStringInfoDatum(profile);
290 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
291 (datum[3] == 0x41) && (datum[4] == 0x58))
296 static void JPEGErrorHandler(j_common_ptr jpeg_info)
301 (void) EmitMessage(jpeg_info,0);
302 error_manager=(ErrorManager *) jpeg_info->client_data;
303 longjmp(error_manager->error_recovery,1);
306 static boolean ReadComment(j_decompress_ptr jpeg_info)
327 Determine length of comment.
329 error_manager=(ErrorManager *) jpeg_info->client_data;
330 image=error_manager->image;
331 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
332 length+=GetCharacter(jpeg_info);
336 comment=(char *) NULL;
337 if (~length >= MaxTextExtent)
338 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
340 if (comment == (char *) NULL)
341 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
347 for (p=comment; i-- >= 0; p++)
348 *p=(char) GetCharacter(jpeg_info);
350 (void) SetImageProperty(image,"comment",comment);
351 comment=DestroyString(comment);
355 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
372 register unsigned char
385 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
386 length+=(size_t) GetCharacter(jpeg_info);
391 (void) GetCharacter(jpeg_info);
394 for (i=0; i < 12; i++)
395 magick[i]=(char) GetCharacter(jpeg_info);
396 if (LocaleCompare(magick,ICC_PROFILE) != 0)
399 Not a ICC profile, return.
401 for (i=0; i < (long) (length-12); i++)
402 (void) GetCharacter(jpeg_info);
405 (void) GetCharacter(jpeg_info); /* id */
406 (void) GetCharacter(jpeg_info); /* markers */
408 error_manager=(ErrorManager *) jpeg_info->client_data;
409 image=error_manager->image;
410 profile=AcquireStringInfo(length);
411 if (profile == (StringInfo *) NULL)
412 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
414 p=GetStringInfoDatum(profile);
415 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
416 *p++=(unsigned char) GetCharacter(jpeg_info);
417 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
418 if (icc_profile != (StringInfo *) NULL)
420 ConcatenateStringInfo(icc_profile,profile);
421 profile=DestroyStringInfo(profile);
425 status=SetImageProfile(image,"icc",profile);
426 profile=DestroyStringInfo(profile);
427 if (status == MagickFalse)
428 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
431 if (image->debug != MagickFalse)
432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
433 "Profile: ICC, %lu bytes",(unsigned long) length);
437 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
440 magick[MaxTextExtent];
454 register unsigned char
465 Determine length of binary data stored here.
467 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
468 length+=(size_t) GetCharacter(jpeg_info);
473 (void) GetCharacter(jpeg_info);
477 Validate that this was written as a Photoshop resource format slug.
479 for (i=0; i < 10; i++)
480 magick[i]=(char) GetCharacter(jpeg_info);
485 if (LocaleCompare(magick,"Photoshop ") != 0)
488 Not a IPTC profile, return.
490 for (i=0; i < (long) length; i++)
491 (void) GetCharacter(jpeg_info);
495 Remove the version number.
497 for (i=0; i < 4; i++)
498 (void) GetCharacter(jpeg_info);
504 error_manager=(ErrorManager *) jpeg_info->client_data;
505 image=error_manager->image;
506 profile=AcquireStringInfo(length);
507 if (profile == (StringInfo *) NULL)
508 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
510 p=GetStringInfoDatum(profile);
511 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
512 *p++=(unsigned char) GetCharacter(jpeg_info);
513 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
514 if (iptc_profile != (StringInfo *) NULL)
516 ConcatenateStringInfo(iptc_profile,profile);
517 profile=DestroyStringInfo(profile);
521 status=SetImageProfile(image,"8bim",profile);
522 profile=DestroyStringInfo(profile);
523 if (status == MagickFalse)
524 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
527 if (image->debug != MagickFalse)
528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
529 "Profile: iptc, %lu bytes",(unsigned long) length);
533 static boolean ReadProfile(j_decompress_ptr jpeg_info)
553 register unsigned char
563 Read generic profile.
565 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
566 length+=(size_t) GetCharacter(jpeg_info);
570 marker=jpeg_info->unread_marker-JPEG_APP0;
571 (void) FormatMagickString(name,MaxTextExtent,"APP%d",marker);
572 error_manager=(ErrorManager *) jpeg_info->client_data;
573 image=error_manager->image;
574 profile=AcquireStringInfo(length);
575 if (profile == (StringInfo *) NULL)
576 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
578 p=GetStringInfoDatum(profile);
579 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
580 *p++=(unsigned char) GetCharacter(jpeg_info);
583 p=GetStringInfoDatum(profile);
584 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
585 (void) CopyMagickString(name,"exif",MaxTextExtent);
586 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
592 Extract namespace from XMP profile.
594 p=GetStringInfoDatum(profile);
595 for (j=0; j < (long) GetStringInfoLength(profile); j++)
601 if (j < (long) GetStringInfoLength(profile))
602 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
603 (void) CopyMagickString(name,"xmp",MaxTextExtent);
606 status=SetImageProfile(image,name,profile);
607 profile=DestroyStringInfo(profile);
608 if (status == MagickFalse)
609 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
611 if (image->debug != MagickFalse)
612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
613 "Profile: %s, %lu bytes",name,(unsigned long) length);
617 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
622 if (number_bytes <= 0)
624 source=(SourceManager *) cinfo->src;
625 while (number_bytes > (long) source->manager.bytes_in_buffer)
627 number_bytes-=(long) source->manager.bytes_in_buffer;
628 (void) FillInputBuffer(cinfo);
630 source->manager.next_input_byte+=(size_t) number_bytes;
631 source->manager.bytes_in_buffer-=(size_t) number_bytes;
634 static void TerminateSource(j_decompress_ptr cinfo)
639 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
644 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
645 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
646 source=(SourceManager *) cinfo->src;
647 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
648 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
649 source=(SourceManager *) cinfo->src;
650 source->manager.init_source=InitializeSource;
651 source->manager.fill_input_buffer=FillInputBuffer;
652 source->manager.skip_input_data=SkipInputData;
653 source->manager.resync_to_restart=jpeg_resync_to_restart;
654 source->manager.term_source=TerminateSource;
655 source->manager.bytes_in_buffer=0;
656 source->manager.next_input_byte=NULL;
660 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
663 image->quality=UndefinedCompressionQuality;
664 #if defined(D_PROGRESSIVE_SUPPORTED)
665 if (image->compression == LosslessJPEGCompression)
668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
669 "Quality: 100 (lossless)");
683 Determine the JPEG compression quality from the quantization tables.
686 for (i=0; i < NUM_QUANT_TBLS; i++)
688 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
689 for (j=0; j < DCTSIZE2; j++)
690 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
692 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
693 (jpeg_info->quant_tbl_ptrs[1] != NULL))
698 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
699 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
700 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
701 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
702 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
703 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
704 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
705 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
706 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
707 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
712 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
713 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
714 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
715 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
716 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
717 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
718 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
719 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
720 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
721 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
722 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
726 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
727 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
728 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
729 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
730 for (i=0; i < 100; i++)
732 if ((qvalue < hash[i]) && (sum < sums[i]))
734 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
735 image->quality=(unsigned long) i+1;
736 if (image->debug != MagickFalse)
737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
738 "Quality: %ld (%s)",i+1,(qvalue <= hash[i]) &&
739 (sum <= sums[i]) ? "exact" : "approximate");
744 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
749 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
750 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
751 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
752 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
753 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
754 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
755 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
756 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
757 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
758 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
763 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
764 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
765 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
766 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
767 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
768 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
769 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
770 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
771 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
772 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
773 667, 592, 518, 441, 369, 292, 221, 151, 86,
777 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
778 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
779 for (i=0; i < 100; i++)
781 if ((qvalue < hash[i]) && (sum < sums[i]))
783 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
784 image->quality=(unsigned long) i+1;
785 if (image->debug != MagickFalse)
786 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
787 "Quality: %ld (%s)",i+1,(qvalue <= hash[i]) &&
788 (sum <= sums[i]) ? "exact" : "approximate");
795 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
798 sampling_factor[MaxTextExtent];
800 switch (jpeg_info->out_color_space)
804 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
805 (void) FormatMagickString(sampling_factor,MaxTextExtent,
806 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
807 jpeg_info->comp_info[0].v_samp_factor,
808 jpeg_info->comp_info[1].h_samp_factor,
809 jpeg_info->comp_info[1].v_samp_factor,
810 jpeg_info->comp_info[2].h_samp_factor,
811 jpeg_info->comp_info[2].v_samp_factor,
812 jpeg_info->comp_info[3].h_samp_factor,
813 jpeg_info->comp_info[3].v_samp_factor);
818 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
819 "Colorspace: GRAYSCALE");
820 (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
821 jpeg_info->comp_info[0].h_samp_factor,
822 jpeg_info->comp_info[0].v_samp_factor);
827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
828 (void) FormatMagickString(sampling_factor,MaxTextExtent,
829 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
830 jpeg_info->comp_info[0].v_samp_factor,
831 jpeg_info->comp_info[1].h_samp_factor,
832 jpeg_info->comp_info[1].v_samp_factor,
833 jpeg_info->comp_info[2].h_samp_factor,
834 jpeg_info->comp_info[2].v_samp_factor);
839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
840 jpeg_info->out_color_space);
841 (void) FormatMagickString(sampling_factor,MaxTextExtent,
842 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
843 jpeg_info->comp_info[0].v_samp_factor,
844 jpeg_info->comp_info[1].h_samp_factor,
845 jpeg_info->comp_info[1].v_samp_factor,
846 jpeg_info->comp_info[2].h_samp_factor,
847 jpeg_info->comp_info[2].v_samp_factor,
848 jpeg_info->comp_info[3].h_samp_factor,
849 jpeg_info->comp_info[3].v_samp_factor);
853 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
854 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
855 "Sampling Factors: %s",sampling_factor);
858 static Image *ReadJPEGImage(const ImageInfo *image_info,
859 ExceptionInfo *exception)
862 value[MaxTextExtent];
895 struct jpeg_decompress_struct
898 struct jpeg_error_mgr
911 assert(image_info != (const ImageInfo *) NULL);
912 assert(image_info->signature == MagickSignature);
913 if (image_info->debug != MagickFalse)
914 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
915 image_info->filename);
916 assert(exception != (ExceptionInfo *) NULL);
917 assert(exception->signature == MagickSignature);
918 debug=IsEventLogging();
919 image=AcquireImage(image_info);
920 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
921 if (status == MagickFalse)
923 image=DestroyImageList(image);
924 return((Image *) NULL);
927 Initialize JPEG parameters.
929 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
930 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
931 jpeg_info.err=jpeg_std_error(&jpeg_error);
932 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
933 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
934 jpeg_pixels=(JSAMPLE *) NULL;
935 error_manager.image=image;
936 if (setjmp(error_manager.error_recovery) != 0)
938 jpeg_destroy_decompress(&jpeg_info);
939 (void) CloseBlob(image);
940 number_pixels=(MagickSizeType) image->columns*image->rows;
941 if (number_pixels != 0)
942 return(GetFirstImageInList(image));
943 InheritException(exception,&image->exception);
944 return(DestroyImage(image));
946 jpeg_info.client_data=(void *) &error_manager;
947 jpeg_create_decompress(&jpeg_info);
948 JPEGSourceManager(&jpeg_info,image);
949 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
950 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
951 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
952 for (i=1; i < 16; i++)
953 if ((i != 2) && (i != 13) && (i != 14))
954 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
955 i=jpeg_read_header(&jpeg_info,MagickTrue);
956 if ((image_info->colorspace == YCbCrColorspace) ||
957 (image_info->colorspace == Rec601YCbCrColorspace) ||
958 (image_info->colorspace == Rec709YCbCrColorspace))
959 jpeg_info.out_color_space=JCS_YCbCr;
960 if (IsITUFaxImage(image) != MagickFalse)
962 image->colorspace=LabColorspace;
963 jpeg_info.out_color_space=JCS_YCbCr;
966 if (jpeg_info.out_color_space == JCS_CMYK)
967 image->colorspace=CMYKColorspace;
969 Set image resolution.
972 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
973 (jpeg_info.Y_density != 1))
975 image->x_resolution=(double) jpeg_info.X_density;
976 image->y_resolution=(double) jpeg_info.Y_density;
977 units=(unsigned long) jpeg_info.density_unit;
980 image->units=PixelsPerInchResolution;
982 image->units=PixelsPerCentimeterResolution;
983 number_pixels=(MagickSizeType) image->columns*image->rows;
984 option=GetImageOption(image_info,"jpeg:size");
985 if (option != (const char *) NULL)
999 flags=ParseGeometry(option,&geometry_info);
1000 if ((flags & SigmaValue) == 0)
1001 geometry_info.sigma=geometry_info.rho;
1002 jpeg_calc_output_dimensions(&jpeg_info);
1003 image->magick_columns=jpeg_info.output_width;
1004 image->magick_rows=jpeg_info.output_height;
1006 if (geometry_info.rho != 0.0)
1007 scale_factor=jpeg_info.output_width/geometry_info.rho;
1008 if ((geometry_info.sigma != 0.0) &&
1009 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1010 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1011 jpeg_info.scale_num=1U;
1012 jpeg_info.scale_denom=(unsigned int) scale_factor;
1013 jpeg_calc_output_dimensions(&jpeg_info);
1014 if (image->debug != MagickFalse)
1015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Scale factor: %ld",
1016 (long) scale_factor);
1018 precision=(unsigned long) jpeg_info.data_precision;
1019 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1020 #if defined(D_LOSSLESS_SUPPORTED)
1021 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1022 JPEGInterlace : NoInterlace;
1023 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1024 LosslessJPEGCompression : JPEGCompression;
1025 if (jpeg_info.data_precision > 8)
1026 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1027 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1029 if (jpeg_info.data_precision == 16)
1030 jpeg_info.data_precision=12;
1032 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1034 image->compression=JPEGCompression;
1037 image->compression=JPEGCompression;
1038 image->interlace=JPEGInterlace;
1040 if ((image_info->colors > 8) && (image_info->colors <= 256))
1043 Let the JPEG library quantize for us.
1045 jpeg_info.quantize_colors=MagickTrue;
1046 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1048 option=GetImageOption(image_info,"jpeg:block-smoothing");
1049 if (option != (const char *) NULL)
1051 jpeg_info.do_block_smoothing=MagickFalse;
1052 if (IsMagickTrue(option) != MagickFalse)
1053 jpeg_info.do_block_smoothing=MagickTrue;
1055 option=GetImageOption(image_info,"jpeg:dct-method");
1056 if (option != (const char *) NULL)
1062 if (LocaleCompare(option,"default") == 0)
1063 jpeg_info.dct_method=JDCT_DEFAULT;
1069 if (LocaleCompare(option,"fastest") == 0)
1070 jpeg_info.dct_method=JDCT_FASTEST;
1071 if (LocaleCompare(option,"float") == 0)
1072 jpeg_info.dct_method=JDCT_FLOAT;
1078 if (LocaleCompare(option,"ifast") == 0)
1079 jpeg_info.dct_method=JDCT_IFAST;
1080 if (LocaleCompare(option,"islow") == 0)
1081 jpeg_info.dct_method=JDCT_ISLOW;
1085 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1086 if (option != (const char *) NULL)
1088 jpeg_info.do_fancy_upsampling=MagickFalse;
1089 if (IsMagickTrue(option) != MagickFalse)
1090 jpeg_info.do_fancy_upsampling=MagickTrue;
1092 (void) jpeg_start_decompress(&jpeg_info);
1093 image->columns=jpeg_info.output_width;
1094 image->rows=jpeg_info.output_height;
1095 image->depth=(unsigned long) jpeg_info.data_precision;
1096 if (jpeg_info.out_color_space == JCS_YCbCr)
1097 image->colorspace=YCbCrColorspace;
1098 if (jpeg_info.out_color_space == JCS_CMYK)
1099 image->colorspace=CMYKColorspace;
1100 if ((image_info->colors != 0) && (image_info->colors <= 256))
1101 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1102 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1103 if ((jpeg_info.output_components == 1) &&
1104 (jpeg_info.quantize_colors == MagickFalse))
1109 colors=(unsigned long) GetQuantumRange(image->depth)+1;
1110 if (AcquireImageColormap(image,colors) == MagickFalse)
1111 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1113 if (image->debug != MagickFalse)
1115 if (image->interlace != NoInterlace)
1116 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1117 "Interlace: progressive");
1119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1120 "Interlace: nonprogressive");
1121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1122 (int) jpeg_info.data_precision);
1123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1124 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1126 JPEGSetImageQuality(&jpeg_info,image);
1127 JPEGSetImageSamplingFactor(&jpeg_info,image);
1128 (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
1129 jpeg_info.out_color_space);
1130 (void) SetImageProperty(image,"jpeg:colorspace",value);
1131 if (image_info->ping != MagickFalse)
1133 jpeg_destroy_decompress(&jpeg_info);
1134 (void) CloseBlob(image);
1135 return(GetFirstImageInList(image));
1137 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1138 jpeg_info.output_components*sizeof(JSAMPLE));
1139 if (jpeg_pixels == (JSAMPLE *) NULL)
1140 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1142 Convert JPEG pixels to pixel packets.
1144 if (setjmp(error_manager.error_recovery) != 0)
1146 if (jpeg_pixels != (unsigned char *) NULL)
1147 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1148 jpeg_destroy_decompress(&jpeg_info);
1149 (void) CloseBlob(image);
1150 number_pixels=(MagickSizeType) image->columns*image->rows;
1151 if (number_pixels != 0)
1152 return(GetFirstImageInList(image));
1153 return(DestroyImage(image));
1155 if (jpeg_info.quantize_colors != MagickFalse)
1157 image->colors=(unsigned long) jpeg_info.actual_number_of_colors;
1158 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1159 for (i=0; i < (long) image->colors; i++)
1161 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1162 image->colormap[i].green=image->colormap[i].red;
1163 image->colormap[i].blue=image->colormap[i].red;
1164 image->colormap[i].opacity=OpaqueOpacity;
1167 for (i=0; i < (long) image->colors; i++)
1169 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1170 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1171 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1172 image->colormap[i].opacity=OpaqueOpacity;
1175 scanline[0]=(JSAMPROW) jpeg_pixels;
1176 for (y=0; y < (long) image->rows; y++)
1178 register IndexPacket
1184 register PixelPacket
1187 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1189 (void) ThrowMagickException(exception,GetMagickModule(),
1190 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1194 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1195 if (q == (PixelPacket *) NULL)
1197 indexes=GetAuthenticIndexQueue(image);
1198 if (jpeg_info.data_precision > 8)
1200 if (jpeg_info.output_components == 1)
1201 for (x=0; x < (long) image->columns; x++)
1206 if (precision != 16)
1207 pixel=(unsigned long) GETJSAMPLE(*p);
1209 pixel=(unsigned long) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1210 index=ConstrainColormapIndex(image,pixel);
1212 *q++=image->colormap[(int) index];
1216 if (image->colorspace != CMYKColorspace)
1217 for (x=0; x < (long) image->columns; x++)
1219 q->red=ScaleShortToQuantum((unsigned char)
1220 (GETJSAMPLE(*p++) << 4));
1221 q->green=ScaleShortToQuantum((unsigned char)
1222 (GETJSAMPLE(*p++) << 4));
1223 q->blue=ScaleShortToQuantum((unsigned char)
1224 (GETJSAMPLE(*p++) << 4));
1225 SetOpacityPixelComponent(q,OpaqueOpacity);
1229 for (x=0; x < (long) image->columns; x++)
1231 q->red=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1232 (GETJSAMPLE(*p++) << 4));
1233 q->green=(Quantum) QuantumRange-ScaleShortToQuantum(
1234 (unsigned char) (GETJSAMPLE(*p++) << 4));
1235 q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1236 (GETJSAMPLE(*p++) << 4));
1237 SetOpacityPixelComponent(q,OpaqueOpacity);
1238 indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
1239 (unsigned char) (GETJSAMPLE(*p++) << 4));
1244 if (jpeg_info.output_components == 1)
1245 for (x=0; x < (long) image->columns; x++)
1247 index=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
1248 indexes[x]=(IndexPacket) index;
1249 *q++=image->colormap[(int) index];
1253 if (image->colorspace != CMYKColorspace)
1254 for (x=0; x < (long) image->columns; x++)
1256 q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1257 q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1258 q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1259 SetOpacityPixelComponent(q,OpaqueOpacity);
1263 for (x=0; x < (long) image->columns; x++)
1265 q->red=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1267 q->green=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1269 q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1271 SetOpacityPixelComponent(q,OpaqueOpacity);
1272 indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
1273 (unsigned char) GETJSAMPLE(*p++));
1276 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1278 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
1282 Free jpeg resources.
1284 (void) jpeg_finish_decompress(&jpeg_info);
1285 jpeg_destroy_decompress(&jpeg_info);
1286 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1287 (void) CloseBlob(image);
1288 return(GetFirstImageInList(image));
1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 % R e g i s t e r J P E G I m a g e %
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % RegisterJPEGImage() adds properties for the JPEG image format to
1304 % the list of supported formats. The properties include the image format
1305 % tag, a method to read and/or write the format, whether the format
1306 % supports the saving of more than one frame to the same file or blob,
1307 % whether the format supports native in-memory I/O, and a brief
1308 % description of the format.
1310 % The format of the RegisterJPEGImage method is:
1312 % unsigned long RegisterJPEGImage(void)
1315 ModuleExport unsigned long RegisterJPEGImage(void)
1318 version[MaxTextExtent];
1324 description[] = "Joint Photographic Experts Group JFIF format";
1327 #if defined(JPEG_LIB_VERSION)
1328 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1330 entry=SetMagickInfo("JPEG");
1331 entry->thread_support=NoThreadSupport;
1332 #if defined(MAGICKCORE_JPEG_DELEGATE)
1333 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1334 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1336 entry->magick=(IsImageFormatHandler *) IsJPEG;
1337 entry->adjoin=MagickFalse;
1338 entry->description=ConstantString(description);
1339 if (*version != '\0')
1340 entry->version=ConstantString(version);
1341 entry->module=ConstantString("JPEG");
1342 (void) RegisterMagickInfo(entry);
1343 entry=SetMagickInfo("JPG");
1344 entry->thread_support=NoThreadSupport;
1345 #if defined(MAGICKCORE_JPEG_DELEGATE)
1346 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1347 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1349 entry->adjoin=MagickFalse;
1350 entry->description=ConstantString(description);
1351 if (*version != '\0')
1352 entry->version=ConstantString(version);
1353 entry->module=ConstantString("JPEG");
1354 (void) RegisterMagickInfo(entry);
1355 entry=SetMagickInfo("PJPEG");
1356 entry->thread_support=NoThreadSupport;
1357 #if defined(MAGICKCORE_JPEG_DELEGATE)
1358 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1359 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1361 entry->adjoin=MagickFalse;
1362 entry->description=ConstantString(description);
1363 if (*version != '\0')
1364 entry->version=ConstantString(version);
1365 entry->module=ConstantString("JPEG");
1366 (void) RegisterMagickInfo(entry);
1367 return(MagickImageCoderSignature);
1371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 % U n r e g i s t e r J P E G I m a g e %
1379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % UnregisterJPEGImage() removes format registrations made by the
1382 % JPEG module from the list of supported formats.
1384 % The format of the UnregisterJPEGImage method is:
1386 % UnregisterJPEGImage(void)
1389 ModuleExport void UnregisterJPEGImage(void)
1391 (void) UnregisterMagickInfo("PJPG");
1392 (void) UnregisterMagickInfo("JPEG");
1393 (void) UnregisterMagickInfo("JPG");
1396 #if defined(MAGICKCORE_JPEG_DELEGATE)
1398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % W r i t e J P E G I m a g e %
1406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408 % WriteJPEGImage() writes a JPEG image file and returns it. It
1409 % allocates the memory necessary for the new Image structure and returns a
1410 % pointer to the new image.
1412 % The format of the WriteJPEGImage method is:
1414 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,Image *image)
1416 % A description of each parameter follows:
1418 % o image_info: the image info.
1420 % o jpeg_image: The image.
1425 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1430 destination=(DestinationManager *) cinfo->dest;
1431 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1432 MaxBufferExtent,destination->buffer);
1433 if (destination->manager.free_in_buffer != MaxBufferExtent)
1434 ERREXIT(cinfo,JERR_FILE_WRITE);
1435 destination->manager.next_output_byte=destination->buffer;
1439 static void InitializeDestination(j_compress_ptr cinfo)
1444 destination=(DestinationManager *) cinfo->dest;
1445 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1446 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1447 destination->manager.next_output_byte=destination->buffer;
1448 destination->manager.free_in_buffer=MaxBufferExtent;
1451 static inline size_t MagickMin(const size_t x,const size_t y)
1458 static void TerminateDestination(j_compress_ptr cinfo)
1463 destination=(DestinationManager *) cinfo->dest;
1464 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1469 count=WriteBlob(destination->image,MaxBufferExtent-
1470 destination->manager.free_in_buffer,destination->buffer);
1471 if (count != (ssize_t)
1472 (MaxBufferExtent-destination->manager.free_in_buffer))
1473 ERREXIT(cinfo,JERR_FILE_WRITE);
1477 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1501 Save image profile as a APP marker.
1504 custom_profile=AcquireStringInfo(65535L);
1505 ResetImageProfileIterator(image);
1506 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1508 profile=GetImageProfile(image,name);
1509 if (LocaleCompare(name,"EXIF") == 0)
1510 for (i=0; i < (long) GetStringInfoLength(profile); i+=65533L)
1512 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1513 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1514 (unsigned int) length);
1516 if (LocaleCompare(name,"ICC") == 0)
1518 register unsigned char
1522 p=GetStringInfoDatum(custom_profile);
1523 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1524 for (i=0; i < (long) GetStringInfoLength(profile); i+=65519L)
1526 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1527 p=GetStringInfoDatum(custom_profile);
1528 p[12]=(unsigned char) ((i/65519L)+1);
1529 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1530 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1532 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1533 custom_profile),(unsigned int) (length+tag_length));
1536 if (((LocaleCompare(name,"IPTC") == 0) ||
1537 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1539 register unsigned char
1546 p=GetStringInfoDatum(custom_profile);
1547 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1549 (void) CopyMagickMemory(p,"Photoshop 3.0\0",14);
1554 (void) CopyMagickMemory(p,"Photoshop 3.0\08BIM\04\04\0\0\0\0",24);
1556 p[24]=(unsigned char) (GetStringInfoLength(profile) >> 8);
1557 p[25]=(unsigned char) (GetStringInfoLength(profile) & 0xff);
1560 for (i=0; i < (long) GetStringInfoLength(profile); i+=65500L)
1562 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1563 roundup=(unsigned long) (length & 0x01);
1564 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1567 p[length+tag_length]='\0';
1568 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1569 custom_profile),(unsigned int) (length+tag_length+roundup));
1572 if (LocaleCompare(name,"XMP") == 0)
1578 Add namespace to XMP profile.
1580 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1581 ConcatenateStringInfo(xmp_profile,profile);
1582 GetStringInfoDatum(xmp_profile)[28]='\0';
1583 for (i=0; i < (long) GetStringInfoLength(xmp_profile); i+=65533L)
1585 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1586 jpeg_write_marker(jpeg_info,XML_MARKER,
1587 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1589 xmp_profile=DestroyStringInfo(xmp_profile);
1591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s profile: %lu bytes",
1592 name,(unsigned long) GetStringInfoLength(profile));
1593 name=GetNextImageProfile(image);
1595 custom_profile=DestroyStringInfo(custom_profile);
1598 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1603 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1604 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1605 destination=(DestinationManager *) cinfo->dest;
1606 destination->manager.init_destination=InitializeDestination;
1607 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1608 destination->manager.term_destination=TerminateDestination;
1609 destination->image=image;
1612 static char **SamplingFactorToList(const char *text)
1629 if (text == (char *) NULL)
1630 return((char **) NULL);
1632 Convert string to an ASCII list.
1635 for (p=text; *p != '\0'; p++)
1638 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1640 if (textlist == (char **) NULL)
1641 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1643 for (i=0; i < (long) lines; i++)
1645 for (q=(char *) p; *q != '\0'; q++)
1648 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1649 sizeof(*textlist[i]));
1650 if (textlist[i] == (char *) NULL)
1651 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1652 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1657 textlist[i]=(char *) NULL;
1661 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1690 struct jpeg_compress_struct
1693 struct jpeg_error_mgr
1699 assert(image_info != (const ImageInfo *) NULL);
1700 assert(image_info->signature == MagickSignature);
1701 assert(image != (Image *) NULL);
1702 assert(image->signature == MagickSignature);
1703 if (image->debug != MagickFalse)
1704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1705 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1706 if (status == MagickFalse)
1709 Initialize JPEG parameters.
1711 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1712 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1713 jpeg_info.client_data=(void *) image;
1714 jpeg_info.err=jpeg_std_error(&jpeg_error);
1715 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
1716 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1717 error_manager.image=image;
1718 jpeg_pixels=(JSAMPLE *) NULL;
1719 if (setjmp(error_manager.error_recovery) != 0)
1721 jpeg_destroy_compress(&jpeg_info);
1722 (void) CloseBlob(image);
1723 return(MagickFalse);
1725 jpeg_info.client_data=(void *) &error_manager;
1726 jpeg_create_compress(&jpeg_info);
1727 JPEGDestinationManager(&jpeg_info,image);
1728 if ((image->columns != (unsigned int) image->columns) ||
1729 (image->rows != (unsigned int) image->rows))
1730 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1731 jpeg_info.image_width=(unsigned int) image->columns;
1732 jpeg_info.image_height=(unsigned int) image->rows;
1733 jpeg_info.input_components=3;
1734 jpeg_info.data_precision=8;
1735 jpeg_info.in_color_space=JCS_RGB;
1736 switch (image->colorspace)
1738 case CMYKColorspace:
1740 jpeg_info.input_components=4;
1741 jpeg_info.in_color_space=JCS_CMYK;
1744 case YCbCrColorspace:
1745 case Rec601YCbCrColorspace:
1746 case Rec709YCbCrColorspace:
1748 jpeg_info.in_color_space=JCS_YCbCr;
1751 case GRAYColorspace:
1752 case Rec601LumaColorspace:
1753 case Rec709LumaColorspace:
1755 jpeg_info.input_components=1;
1756 jpeg_info.in_color_space=JCS_GRAYSCALE;
1761 if (image->colorspace != RGBColorspace)
1762 (void) TransformImageColorspace(image,RGBColorspace);
1766 if ((image_info->type != TrueColorType) &&
1767 (IsGrayImage(image,&image->exception) != MagickFalse))
1769 jpeg_info.input_components=1;
1770 jpeg_info.in_color_space=JCS_GRAYSCALE;
1772 jpeg_set_defaults(&jpeg_info);
1773 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1774 jpeg_info.data_precision=8;
1776 if (sizeof(JSAMPLE) > 1)
1777 jpeg_info.data_precision=12;
1778 jpeg_info.density_unit=(UINT8) 1;
1779 if (image->debug != MagickFalse)
1780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781 "Image resolution: %ld,%ld",(long) (image->x_resolution+0.5),
1782 (long) (image->y_resolution+0.5));
1783 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1786 Set image resolution.
1788 jpeg_info.write_JFIF_header=MagickTrue;
1789 jpeg_info.X_density=(UINT16) image->x_resolution;
1790 jpeg_info.Y_density=(UINT16) image->y_resolution;
1791 if (image->units == PixelsPerInchResolution)
1792 jpeg_info.density_unit=(UINT8) 1;
1793 if (image->units == PixelsPerCentimeterResolution)
1794 jpeg_info.density_unit=(UINT8) 2;
1796 option=GetImageOption(image_info,"jpeg:dct-method");
1797 if (option != (const char *) NULL)
1803 if (LocaleCompare(option,"default") == 0)
1804 jpeg_info.dct_method=JDCT_DEFAULT;
1810 if (LocaleCompare(option,"fastest") == 0)
1811 jpeg_info.dct_method=JDCT_FASTEST;
1812 if (LocaleCompare(option,"float") == 0)
1813 jpeg_info.dct_method=JDCT_FLOAT;
1819 if (LocaleCompare(option,"ifast") == 0)
1820 jpeg_info.dct_method=JDCT_IFAST;
1821 if (LocaleCompare(option,"islow") == 0)
1822 jpeg_info.dct_method=JDCT_ISLOW;
1826 option=GetImageOption(image_info,"jpeg:optimize-coding");
1827 if (option != (const char *) NULL)
1829 jpeg_info.optimize_coding=MagickFalse;
1830 if (IsMagickTrue(option) != MagickFalse)
1831 jpeg_info.optimize_coding=MagickTrue;
1838 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1839 image->rows*sizeof(JSAMPLE);
1840 if (length == (MagickSizeType) ((size_t) length))
1843 Perform optimization only if available memory resources permit it.
1845 status=AcquireMagickResource(MemoryResource,length);
1846 if (status != MagickFalse)
1847 jpeg_info.optimize_coding=MagickTrue;
1848 RelinquishMagickResource(MemoryResource,length);
1851 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1852 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1853 (image_info->interlace != NoInterlace))
1855 if (image->debug != MagickFalse)
1856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1857 "Interlace: progressive");
1858 jpeg_simple_progression(&jpeg_info);
1861 if (image->debug != MagickFalse)
1862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1863 "Interlace: non-progressive");
1865 if (image->debug != MagickFalse)
1866 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1867 "Interlace: nonprogressive");
1869 option=GetImageOption(image_info,"jpeg:extent");
1870 if (option != (const char *) NULL)
1878 jpeg_info=CloneImageInfo(image_info);
1879 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1880 if (jpeg_image != (Image *) NULL)
1890 Search for compression quality that does not exceed image extent.
1892 jpeg_info->quality=0;
1893 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1894 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1895 (void) AcquireUniqueFilename(jpeg_image->filename);
1897 for (minimum=0; minimum != maximum; )
1899 jpeg_image->quality=minimum+(maximum-minimum)/2;
1900 status=WriteJPEGImage(jpeg_info,jpeg_image);
1901 if (GetBlobSize(jpeg_image) <= extent)
1902 minimum=jpeg_image->quality+1;
1904 maximum=jpeg_image->quality-1;
1906 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1907 image->quality=minimum-1;
1908 jpeg_image=DestroyImage(jpeg_image);
1910 jpeg_info=DestroyImageInfo(jpeg_info);
1912 if ((image_info->compression != LosslessJPEGCompression) &&
1913 (image->quality <= 100))
1915 if (image->quality == UndefinedCompressionQuality)
1916 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1918 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1919 if (image->debug != MagickFalse)
1920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
1925 #if !defined(C_LOSSLESS_SUPPORTED)
1926 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1927 if (image->debug != MagickFalse)
1928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1930 if (image->quality < 100)
1931 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1932 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1939 predictor=image->quality/100; /* range 1-7 */
1940 point_transform=image->quality % 20; /* range 0-15 */
1941 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1942 if (image->debug != MagickFalse)
1944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1945 "Compression: lossless");
1946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1947 "Predictor: %d",predictor);
1948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1949 "Point Transform: %d",point_transform);
1954 sampling_factor=(const char *) NULL;
1955 value=GetImageProperty(image,"jpeg:sampling-factor");
1956 if (value != (char *) NULL)
1958 sampling_factor=value;
1959 if (image->debug != MagickFalse)
1960 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1961 " Input sampling-factors=%s",sampling_factor);
1963 if (image_info->sampling_factor != (char *) NULL)
1964 sampling_factor=image_info->sampling_factor;
1965 if (sampling_factor == (const char *) NULL)
1967 if (image->quality >= 90)
1968 for (i=0; i < MAX_COMPONENTS; i++)
1970 jpeg_info.comp_info[i].h_samp_factor=1;
1971 jpeg_info.comp_info[i].v_samp_factor=1;
1986 Set sampling factor.
1989 factors=SamplingFactorToList(sampling_factor);
1990 if (factors != (char **) NULL)
1992 for (i=0; i < MAX_COMPONENTS; i++)
1994 if (factors[i] == (char *) NULL)
1996 flags=ParseGeometry(factors[i],&geometry_info);
1997 if ((flags & SigmaValue) == 0)
1998 geometry_info.sigma=geometry_info.rho;
1999 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2000 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2001 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2003 factors=(char **) RelinquishMagickMemory(factors);
2005 for ( ; i < MAX_COMPONENTS; i++)
2007 jpeg_info.comp_info[i].h_samp_factor=1;
2008 jpeg_info.comp_info[i].v_samp_factor=1;
2011 if (jpeg_info.input_components == 1)
2012 for (i=0; i < MAX_COMPONENTS; i++)
2014 jpeg_info.comp_info[i].h_samp_factor=1;
2015 jpeg_info.comp_info[i].v_samp_factor=1;
2017 jpeg_start_compress(&jpeg_info,MagickTrue);
2018 if (image->debug != MagickFalse)
2020 if (image->storage_class == PseudoClass)
2021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2022 "Storage class: PseudoClass");
2024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2025 "Storage class: DirectClass");
2026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %lu",
2028 if (image->colors != 0)
2029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2030 "Number of colors: %lu",image->colors);
2032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2033 "Number of colors: unspecified");
2034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2035 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2036 switch (image->colorspace)
2038 case CMYKColorspace:
2040 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2041 "Storage class: DirectClass");
2042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2043 "Colorspace: CMYK");
2046 case YCbCrColorspace:
2047 case Rec601YCbCrColorspace:
2048 case Rec709YCbCrColorspace:
2050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2051 "Colorspace: YCbCr");
2057 switch (image->colorspace)
2059 case CMYKColorspace:
2061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2062 "Colorspace: CMYK");
2063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2064 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2065 jpeg_info.comp_info[0].h_samp_factor,
2066 jpeg_info.comp_info[0].v_samp_factor,
2067 jpeg_info.comp_info[1].h_samp_factor,
2068 jpeg_info.comp_info[1].v_samp_factor,
2069 jpeg_info.comp_info[2].h_samp_factor,
2070 jpeg_info.comp_info[2].v_samp_factor,
2071 jpeg_info.comp_info[3].h_samp_factor,
2072 jpeg_info.comp_info[3].v_samp_factor);
2075 case GRAYColorspace:
2076 case Rec601LumaColorspace:
2077 case Rec709LumaColorspace:
2079 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2080 "Colorspace: GRAY");
2081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2082 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2083 jpeg_info.comp_info[0].v_samp_factor);
2088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2089 "Image colorspace is RGB");
2090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2091 "Sampling factors: %dx%d,%dx%d,%dx%d",
2092 jpeg_info.comp_info[0].h_samp_factor,
2093 jpeg_info.comp_info[0].v_samp_factor,
2094 jpeg_info.comp_info[1].h_samp_factor,
2095 jpeg_info.comp_info[1].v_samp_factor,
2096 jpeg_info.comp_info[2].h_samp_factor,
2097 jpeg_info.comp_info[2].v_samp_factor);
2100 case YCbCrColorspace:
2101 case Rec601YCbCrColorspace:
2102 case Rec709YCbCrColorspace:
2104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2105 "Colorspace: YCbCr");
2106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2107 "Sampling factors: %dx%d,%dx%d,%dx%d",
2108 jpeg_info.comp_info[0].h_samp_factor,
2109 jpeg_info.comp_info[0].v_samp_factor,
2110 jpeg_info.comp_info[1].h_samp_factor,
2111 jpeg_info.comp_info[1].v_samp_factor,
2112 jpeg_info.comp_info[2].h_samp_factor,
2113 jpeg_info.comp_info[2].v_samp_factor);
2118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
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);
2135 Write JPEG profiles.
2137 value=GetImageProperty(image,"comment");
2138 if (value != (char *) NULL)
2139 for (i=0; i < (long) strlen(value); i+=65533L)
2140 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2141 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2142 if (image->profiles != (void *) NULL)
2143 WriteProfile(&jpeg_info,image);
2145 Convert MIFF to JPEG raster pixels.
2147 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2148 jpeg_info.input_components*sizeof(*jpeg_pixels));
2149 if (jpeg_pixels == (JSAMPLE *) NULL)
2150 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2151 if (setjmp(error_manager.error_recovery) != 0)
2153 jpeg_destroy_compress(&jpeg_info);
2154 if (jpeg_pixels != (unsigned char *) NULL)
2155 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2156 (void) CloseBlob(image);
2157 return(MagickFalse);
2159 scanline[0]=(JSAMPROW) jpeg_pixels;
2160 if (jpeg_info.data_precision > 8)
2162 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2163 for (y=0; y < (long) image->rows; y++)
2165 register const PixelPacket
2171 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2172 if (p == (const PixelPacket *) NULL)
2175 for (x=0; x < (long) image->columns; x++)
2177 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2181 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2182 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2186 if ((jpeg_info.in_color_space == JCS_RGB) ||
2187 (jpeg_info.in_color_space == JCS_YCbCr))
2188 for (y=0; y < (long) image->rows; y++)
2190 register const PixelPacket
2196 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2197 if (p == (const PixelPacket *) NULL)
2200 for (x=0; x < (long) image->columns; x++)
2202 *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >> 4);
2203 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >> 4);
2204 *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >> 4);
2207 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2208 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2209 if (status == MagickFalse)
2213 for (y=0; y < (long) image->rows; y++)
2215 register const IndexPacket
2218 register const PixelPacket
2224 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2225 if (p == (const PixelPacket *) NULL)
2228 indexes=GetVirtualIndexQueue(image);
2229 for (x=0; x < (long) image->columns; x++)
2232 Convert DirectClass packets to contiguous CMYK scanlines.
2234 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(GetRedPixelComponent(p)) >> 4));
2235 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(GetGreenPixelComponent(p)) >> 4));
2236 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(GetBluePixelComponent(p)) >> 4));
2237 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
2240 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2241 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2242 if (status == MagickFalse)
2247 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2248 for (y=0; y < (long) 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 < (long) image->columns; x++)
2262 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2265 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2266 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2270 if ((jpeg_info.in_color_space == JCS_RGB) ||
2271 (jpeg_info.in_color_space == JCS_YCbCr))
2272 for (y=0; y < (long) image->rows; y++)
2274 register const PixelPacket
2280 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2281 if (p == (const PixelPacket *) NULL)
2284 for (x=0; x < (long) image->columns; x++)
2286 *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
2287 *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
2288 *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
2291 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2292 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2296 for (y=0; y < (long) image->rows; y++)
2298 register const IndexPacket
2301 register const PixelPacket
2307 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2308 if (p == (const PixelPacket *) NULL)
2311 indexes=GetVirtualIndexQueue(image);
2312 for (x=0; x < (long) image->columns; x++)
2315 Convert DirectClass packets to contiguous CMYK scanlines.
2317 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2318 GetRedPixelComponent(p))));
2319 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2320 GetGreenPixelComponent(p))));
2321 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2322 GetBluePixelComponent(p))));
2323 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2327 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2328 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2331 if (y == (long) image->rows)
2332 jpeg_finish_compress(&jpeg_info);
2334 Relinquish resources.
2336 jpeg_destroy_compress(&jpeg_info);
2337 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2338 (void) CloseBlob(image);