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/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;
93 #define ICC_MARKER (JPEG_APP0+2)
94 #define ICC_PROFILE "ICC_PROFILE"
95 #define IPTC_MARKER (JPEG_APP0+13)
96 #define XML_MARKER (JPEG_APP0+1)
97 #define MaxBufferExtent 8192
100 Typedef declarations.
102 #if defined(MAGICKCORE_JPEG_DELEGATE)
103 typedef struct _DestinationManager
105 struct jpeg_destination_mgr
113 } DestinationManager;
115 typedef struct _ErrorManager
124 typedef struct _SourceManager
126 struct jpeg_source_mgr
141 Forward declarations.
143 #if defined(MAGICKCORE_JPEG_DELEGATE)
144 static MagickBooleanType
145 WriteJPEGImage(const ImageInfo *,Image *);
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 % IsJPEG() returns MagickTrue if the image format type, identified by the
160 % magick string, is JPEG.
162 % The format of the IsJPEG method is:
164 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
166 % A description of each parameter follows:
168 % o magick: compare image format pattern against these bytes.
170 % o length: Specifies the length of the magick string.
173 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
177 if (memcmp(magick,"\377\330\377",3) == 0)
182 #if defined(MAGICKCORE_JPEG_DELEGATE)
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 % R e a d J P E G I m a g e %
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
195 % the memory necessary for the new Image structure and returns a pointer to
198 % The format of the ReadJPEGImage method is:
200 % Image *ReadJPEGImage(const ImageInfo *image_info,
201 % ExceptionInfo *exception)
203 % A description of each parameter follows:
205 % o image_info: the image info.
207 % o exception: return any errors or warnings in this structure.
211 static MagickBooleanType EmitMessage(j_common_ptr jpeg_info,int level)
214 message[JMSG_LENGTH_MAX];
222 (jpeg_info->err->format_message)(jpeg_info,message);
223 error_manager=(ErrorManager *) jpeg_info->client_data;
224 image=error_manager->image;
227 if ((jpeg_info->err->num_warnings == 0) ||
228 (jpeg_info->err->trace_level >= 3))
229 ThrowBinaryException(CorruptImageWarning,(char *) message,
231 jpeg_info->err->num_warnings++;
234 if (jpeg_info->err->trace_level >= level)
235 ThrowBinaryException(CoderError,(char *) message,image->filename);
239 static boolean FillInputBuffer(j_decompress_ptr cinfo)
244 source=(SourceManager *) cinfo->src;
245 source->manager.bytes_in_buffer=(size_t)
246 ReadBlob(source->image,MaxBufferExtent,source->buffer);
247 if (source->manager.bytes_in_buffer == 0)
249 if (source->start_of_blob != 0)
250 ERREXIT(cinfo,JERR_INPUT_EMPTY);
251 WARNMS(cinfo,JWRN_JPEG_EOF);
252 source->buffer[0]=(JOCTET) 0xff;
253 source->buffer[1]=(JOCTET) JPEG_EOI;
254 source->manager.bytes_in_buffer=2;
256 source->manager.next_input_byte=source->buffer;
257 source->start_of_blob=FALSE;
261 static int GetCharacter(j_decompress_ptr jpeg_info)
263 if (jpeg_info->src->bytes_in_buffer == 0)
264 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
265 jpeg_info->src->bytes_in_buffer--;
266 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
269 static void InitializeSource(j_decompress_ptr cinfo)
274 source=(SourceManager *) cinfo->src;
275 source->start_of_blob=TRUE;
278 static MagickBooleanType IsITUFaxImage(const Image *image)
286 profile=GetImageProfile(image,"8bim");
287 if (profile == (const StringInfo *) NULL)
289 if (GetStringInfoLength(profile) < 5)
291 datum=GetStringInfoDatum(profile);
292 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
293 (datum[3] == 0x41) && (datum[4] == 0x58))
298 static void JPEGErrorHandler(j_common_ptr jpeg_info)
303 (void) EmitMessage(jpeg_info,0);
304 error_manager=(ErrorManager *) jpeg_info->client_data;
305 longjmp(error_manager->error_recovery,1);
308 static boolean ReadComment(j_decompress_ptr jpeg_info)
329 Determine length of comment.
331 error_manager=(ErrorManager *) jpeg_info->client_data;
332 image=error_manager->image;
333 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
334 length+=GetCharacter(jpeg_info);
338 comment=(char *) NULL;
339 if (~length >= MaxTextExtent)
340 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
342 if (comment == (char *) NULL)
343 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
349 for (p=comment; i-- >= 0; p++)
350 *p=(char) GetCharacter(jpeg_info);
352 (void) SetImageProperty(image,"comment",comment);
353 comment=DestroyString(comment);
357 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
374 register unsigned char
387 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
388 length+=(size_t) GetCharacter(jpeg_info);
393 (void) GetCharacter(jpeg_info);
396 for (i=0; i < 12; i++)
397 magick[i]=(char) GetCharacter(jpeg_info);
398 if (LocaleCompare(magick,ICC_PROFILE) != 0)
401 Not a ICC profile, return.
403 for (i=0; i < (long) (length-12); i++)
404 (void) GetCharacter(jpeg_info);
407 (void) GetCharacter(jpeg_info); /* id */
408 (void) GetCharacter(jpeg_info); /* markers */
410 error_manager=(ErrorManager *) jpeg_info->client_data;
411 image=error_manager->image;
412 profile=AcquireStringInfo(length);
413 if (profile == (StringInfo *) NULL)
414 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
416 p=GetStringInfoDatum(profile);
417 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
418 *p++=(unsigned char) GetCharacter(jpeg_info);
419 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
420 if (icc_profile != (StringInfo *) NULL)
422 ConcatenateStringInfo(icc_profile,profile);
423 profile=DestroyStringInfo(profile);
427 status=SetImageProfile(image,"icc",profile);
428 profile=DestroyStringInfo(profile);
429 if (status == MagickFalse)
430 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
435 "Profile: ICC, %lu bytes",(unsigned long) length);
439 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
442 magick[MaxTextExtent];
456 register unsigned char
467 Determine length of binary data stored here.
469 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
470 length+=(size_t) GetCharacter(jpeg_info);
475 (void) GetCharacter(jpeg_info);
479 Validate that this was written as a Photoshop resource format slug.
481 for (i=0; i < 10; i++)
482 magick[i]=(char) GetCharacter(jpeg_info);
487 if (LocaleCompare(magick,"Photoshop ") != 0)
490 Not a IPTC profile, return.
492 for (i=0; i < (long) length; i++)
493 (void) GetCharacter(jpeg_info);
497 Remove the version number.
499 for (i=0; i < 4; i++)
500 (void) GetCharacter(jpeg_info);
506 error_manager=(ErrorManager *) jpeg_info->client_data;
507 image=error_manager->image;
508 profile=AcquireStringInfo(length);
509 if (profile == (StringInfo *) NULL)
510 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
512 p=GetStringInfoDatum(profile);
513 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
514 *p++=(unsigned char) GetCharacter(jpeg_info);
515 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
516 if (iptc_profile != (StringInfo *) NULL)
518 ConcatenateStringInfo(iptc_profile,profile);
519 profile=DestroyStringInfo(profile);
523 status=SetImageProfile(image,"8bim",profile);
524 profile=DestroyStringInfo(profile);
525 if (status == MagickFalse)
526 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
529 if (image->debug != MagickFalse)
530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
531 "Profile: iptc, %lu bytes",(unsigned long) length);
535 static boolean ReadProfile(j_decompress_ptr jpeg_info)
555 register unsigned char
565 Read generic profile.
567 length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
568 length+=(size_t) GetCharacter(jpeg_info);
572 marker=jpeg_info->unread_marker-JPEG_APP0;
573 (void) FormatMagickString(name,MaxTextExtent,"APP%d",marker);
574 error_manager=(ErrorManager *) jpeg_info->client_data;
575 image=error_manager->image;
576 profile=AcquireStringInfo(length);
577 if (profile == (StringInfo *) NULL)
578 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
580 p=GetStringInfoDatum(profile);
581 for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
582 *p++=(unsigned char) GetCharacter(jpeg_info);
585 p=GetStringInfoDatum(profile);
586 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
587 (void) CopyMagickString(name,"exif",MaxTextExtent);
588 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
594 Extract namespace from XMP profile.
596 p=GetStringInfoDatum(profile);
597 for (j=0; j < (long) GetStringInfoLength(profile); j++)
603 if (j < (long) GetStringInfoLength(profile))
604 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
605 (void) CopyMagickString(name,"xmp",MaxTextExtent);
608 status=SetImageProfile(image,name,profile);
609 profile=DestroyStringInfo(profile);
610 if (status == MagickFalse)
611 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
613 if (image->debug != MagickFalse)
614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
615 "Profile: %s, %lu bytes",name,(unsigned long) length);
619 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
624 if (number_bytes <= 0)
626 source=(SourceManager *) cinfo->src;
627 while (number_bytes > (long) source->manager.bytes_in_buffer)
629 number_bytes-=(long) source->manager.bytes_in_buffer;
630 (void) FillInputBuffer(cinfo);
632 source->manager.next_input_byte+=(size_t) number_bytes;
633 source->manager.bytes_in_buffer-=(size_t) number_bytes;
636 static void TerminateSource(j_decompress_ptr cinfo)
641 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
646 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
647 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
648 source=(SourceManager *) cinfo->src;
649 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
650 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
651 source=(SourceManager *) cinfo->src;
652 source->manager.init_source=InitializeSource;
653 source->manager.fill_input_buffer=FillInputBuffer;
654 source->manager.skip_input_data=SkipInputData;
655 source->manager.resync_to_restart=jpeg_resync_to_restart;
656 source->manager.term_source=TerminateSource;
657 source->manager.bytes_in_buffer=0;
658 source->manager.next_input_byte=NULL;
662 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
665 image->quality=UndefinedCompressionQuality;
666 #if defined(D_PROGRESSIVE_SUPPORTED)
667 if (image->compression == LosslessJPEGCompression)
670 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
671 "Quality: 100 (lossless)");
685 Determine the JPEG compression quality from the quantization tables.
688 for (i=0; i < NUM_QUANT_TBLS; i++)
690 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
691 for (j=0; j < DCTSIZE2; j++)
692 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
694 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
695 (jpeg_info->quant_tbl_ptrs[1] != NULL))
700 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
701 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
702 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
703 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
704 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
705 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
706 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
707 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
708 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
709 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
714 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
715 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
716 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
717 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
718 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
719 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
720 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
721 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
722 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
723 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
724 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
728 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
729 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
730 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
731 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
732 for (i=0; i < 100; i++)
734 if ((qvalue < hash[i]) && (sum < sums[i]))
736 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
737 image->quality=(unsigned long) i+1;
738 if (image->debug != MagickFalse)
739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
740 "Quality: %ld (%s)",i+1,(qvalue <= hash[i]) &&
741 (sum <= sums[i]) ? "exact" : "approximate");
746 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
751 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
752 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
753 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
754 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
755 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
756 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
757 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
758 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
759 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
760 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
765 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
766 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
767 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
768 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
769 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
770 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
771 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
772 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
773 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
774 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
775 667, 592, 518, 441, 369, 292, 221, 151, 86,
779 qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
780 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
781 for (i=0; i < 100; i++)
783 if ((qvalue < hash[i]) && (sum < sums[i]))
785 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
786 image->quality=(unsigned long) i+1;
787 if (image->debug != MagickFalse)
788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
789 "Quality: %ld (%s)",i+1,(qvalue <= hash[i]) &&
790 (sum <= sums[i]) ? "exact" : "approximate");
797 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
800 sampling_factor[MaxTextExtent];
802 switch (jpeg_info->out_color_space)
806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
807 (void) FormatMagickString(sampling_factor,MaxTextExtent,
808 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
809 jpeg_info->comp_info[0].v_samp_factor,
810 jpeg_info->comp_info[1].h_samp_factor,
811 jpeg_info->comp_info[1].v_samp_factor,
812 jpeg_info->comp_info[2].h_samp_factor,
813 jpeg_info->comp_info[2].v_samp_factor,
814 jpeg_info->comp_info[3].h_samp_factor,
815 jpeg_info->comp_info[3].v_samp_factor);
820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
821 "Colorspace: GRAYSCALE");
822 (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
823 jpeg_info->comp_info[0].h_samp_factor,
824 jpeg_info->comp_info[0].v_samp_factor);
829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
830 (void) FormatMagickString(sampling_factor,MaxTextExtent,
831 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
832 jpeg_info->comp_info[0].v_samp_factor,
833 jpeg_info->comp_info[1].h_samp_factor,
834 jpeg_info->comp_info[1].v_samp_factor,
835 jpeg_info->comp_info[2].h_samp_factor,
836 jpeg_info->comp_info[2].v_samp_factor);
841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
842 jpeg_info->out_color_space);
843 (void) FormatMagickString(sampling_factor,MaxTextExtent,
844 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
845 jpeg_info->comp_info[0].v_samp_factor,
846 jpeg_info->comp_info[1].h_samp_factor,
847 jpeg_info->comp_info[1].v_samp_factor,
848 jpeg_info->comp_info[2].h_samp_factor,
849 jpeg_info->comp_info[2].v_samp_factor,
850 jpeg_info->comp_info[3].h_samp_factor,
851 jpeg_info->comp_info[3].v_samp_factor);
855 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
860 static Image *ReadJPEGImage(const ImageInfo *image_info,
861 ExceptionInfo *exception)
864 value[MaxTextExtent];
897 struct jpeg_decompress_struct
900 struct jpeg_error_mgr
913 assert(image_info != (const ImageInfo *) NULL);
914 assert(image_info->signature == MagickSignature);
915 if (image_info->debug != MagickFalse)
916 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
917 image_info->filename);
918 assert(exception != (ExceptionInfo *) NULL);
919 assert(exception->signature == MagickSignature);
920 debug=IsEventLogging();
921 image=AcquireImage(image_info);
922 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
923 if (status == MagickFalse)
925 image=DestroyImageList(image);
926 return((Image *) NULL);
929 Initialize JPEG parameters.
931 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
932 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
933 jpeg_info.err=jpeg_std_error(&jpeg_error);
934 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
935 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
936 jpeg_pixels=(JSAMPLE *) NULL;
937 error_manager.image=image;
938 if (setjmp(error_manager.error_recovery) != 0)
940 jpeg_destroy_decompress(&jpeg_info);
941 (void) CloseBlob(image);
942 number_pixels=(MagickSizeType) image->columns*image->rows;
943 if (number_pixels != 0)
944 return(GetFirstImageInList(image));
945 InheritException(exception,&image->exception);
946 return(DestroyImage(image));
948 jpeg_info.client_data=(void *) &error_manager;
949 jpeg_create_decompress(&jpeg_info);
950 JPEGSourceManager(&jpeg_info,image);
951 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
952 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
953 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
954 for (i=1; i < 16; i++)
955 if ((i != 2) && (i != 13) && (i != 14))
956 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
957 i=jpeg_read_header(&jpeg_info,MagickTrue);
958 if ((image_info->colorspace == YCbCrColorspace) ||
959 (image_info->colorspace == Rec601YCbCrColorspace) ||
960 (image_info->colorspace == Rec709YCbCrColorspace))
961 jpeg_info.out_color_space=JCS_YCbCr;
962 if (IsITUFaxImage(image) != MagickFalse)
964 image->colorspace=LabColorspace;
965 jpeg_info.out_color_space=JCS_YCbCr;
968 if (jpeg_info.out_color_space == JCS_CMYK)
969 image->colorspace=CMYKColorspace;
971 Set image resolution.
974 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
975 (jpeg_info.Y_density != 1))
977 image->x_resolution=(double) jpeg_info.X_density;
978 image->y_resolution=(double) jpeg_info.Y_density;
979 units=(unsigned long) jpeg_info.density_unit;
982 image->units=PixelsPerInchResolution;
984 image->units=PixelsPerCentimeterResolution;
985 number_pixels=(MagickSizeType) image->columns*image->rows;
986 option=GetImageOption(image_info,"jpeg:size");
987 if (option != (const char *) NULL)
1001 flags=ParseGeometry(option,&geometry_info);
1002 if ((flags & SigmaValue) == 0)
1003 geometry_info.sigma=geometry_info.rho;
1004 jpeg_calc_output_dimensions(&jpeg_info);
1005 image->magick_columns=jpeg_info.output_width;
1006 image->magick_rows=jpeg_info.output_height;
1008 if (geometry_info.rho != 0.0)
1009 scale_factor=jpeg_info.output_width/geometry_info.rho;
1010 if ((geometry_info.sigma != 0.0) &&
1011 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1012 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1013 jpeg_info.scale_num=1U;
1014 jpeg_info.scale_denom=(unsigned int) scale_factor;
1015 jpeg_calc_output_dimensions(&jpeg_info);
1016 if (image->debug != MagickFalse)
1017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Scale factor: %ld",
1018 (long) scale_factor);
1020 precision=(unsigned long) jpeg_info.data_precision;
1021 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1022 #if defined(D_LOSSLESS_SUPPORTED)
1023 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1024 JPEGInterlace : NoInterlace;
1025 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1026 LosslessJPEGCompression : JPEGCompression;
1027 if (jpeg_info.data_precision > 8)
1028 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1029 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1031 if (jpeg_info.data_precision == 16)
1032 jpeg_info.data_precision=12;
1034 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1036 image->compression=JPEGCompression;
1039 image->compression=JPEGCompression;
1040 image->interlace=JPEGInterlace;
1042 if ((image_info->colors > 8) && (image_info->colors <= 256))
1045 Let the JPEG library quantize for us.
1047 jpeg_info.quantize_colors=MagickTrue;
1048 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1050 option=GetImageOption(image_info,"jpeg:block-smoothing");
1051 if (option != (const char *) NULL)
1053 jpeg_info.do_block_smoothing=MagickFalse;
1054 if (IsMagickTrue(option) != MagickFalse)
1055 jpeg_info.do_block_smoothing=MagickTrue;
1057 option=GetImageOption(image_info,"jpeg:dct-method");
1058 if (option != (const char *) NULL)
1064 if (LocaleCompare(option,"default") == 0)
1065 jpeg_info.dct_method=JDCT_DEFAULT;
1071 if (LocaleCompare(option,"fastest") == 0)
1072 jpeg_info.dct_method=JDCT_FASTEST;
1073 if (LocaleCompare(option,"float") == 0)
1074 jpeg_info.dct_method=JDCT_FLOAT;
1080 if (LocaleCompare(option,"ifast") == 0)
1081 jpeg_info.dct_method=JDCT_IFAST;
1082 if (LocaleCompare(option,"islow") == 0)
1083 jpeg_info.dct_method=JDCT_ISLOW;
1087 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1088 if (option != (const char *) NULL)
1090 jpeg_info.do_fancy_upsampling=MagickFalse;
1091 if (IsMagickTrue(option) != MagickFalse)
1092 jpeg_info.do_fancy_upsampling=MagickTrue;
1094 (void) jpeg_start_decompress(&jpeg_info);
1095 image->columns=jpeg_info.output_width;
1096 image->rows=jpeg_info.output_height;
1097 image->depth=(unsigned long) jpeg_info.data_precision;
1098 if (jpeg_info.out_color_space == JCS_YCbCr)
1099 image->colorspace=YCbCrColorspace;
1100 if (jpeg_info.out_color_space == JCS_CMYK)
1101 image->colorspace=CMYKColorspace;
1102 if ((image_info->colors != 0) && (image_info->colors <= 256))
1103 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1104 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1105 if ((jpeg_info.output_components == 1) &&
1106 (jpeg_info.quantize_colors == MagickFalse))
1111 colors=(unsigned long) GetQuantumRange(image->depth)+1;
1112 if (AcquireImageColormap(image,colors) == MagickFalse)
1113 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1115 if (image->debug != MagickFalse)
1117 if (image->interlace != NoInterlace)
1118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1119 "Interlace: progressive");
1121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1122 "Interlace: nonprogressive");
1123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1124 (int) jpeg_info.data_precision);
1125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1126 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1128 JPEGSetImageQuality(&jpeg_info,image);
1129 JPEGSetImageSamplingFactor(&jpeg_info,image);
1130 (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
1131 jpeg_info.out_color_space);
1132 (void) SetImageProperty(image,"jpeg:colorspace",value);
1133 if (image_info->ping != MagickFalse)
1135 jpeg_destroy_decompress(&jpeg_info);
1136 (void) CloseBlob(image);
1137 return(GetFirstImageInList(image));
1139 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1140 jpeg_info.output_components*sizeof(JSAMPLE));
1141 if (jpeg_pixels == (JSAMPLE *) NULL)
1142 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1144 Convert JPEG pixels to pixel packets.
1146 if (setjmp(error_manager.error_recovery) != 0)
1148 if (jpeg_pixels != (unsigned char *) NULL)
1149 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1150 jpeg_destroy_decompress(&jpeg_info);
1151 (void) CloseBlob(image);
1152 number_pixels=(MagickSizeType) image->columns*image->rows;
1153 if (number_pixels != 0)
1154 return(GetFirstImageInList(image));
1155 return(DestroyImage(image));
1157 if (jpeg_info.quantize_colors != MagickFalse)
1159 image->colors=(unsigned long) jpeg_info.actual_number_of_colors;
1160 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1161 for (i=0; i < (long) image->colors; i++)
1163 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1164 image->colormap[i].green=image->colormap[i].red;
1165 image->colormap[i].blue=image->colormap[i].red;
1166 image->colormap[i].opacity=OpaqueOpacity;
1169 for (i=0; i < (long) image->colors; i++)
1171 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1172 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1173 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1174 image->colormap[i].opacity=OpaqueOpacity;
1177 scanline[0]=(JSAMPROW) jpeg_pixels;
1178 for (y=0; y < (long) image->rows; y++)
1180 register IndexPacket
1186 register PixelPacket
1189 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1191 (void) ThrowMagickException(exception,GetMagickModule(),
1192 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1196 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1197 if (q == (PixelPacket *) NULL)
1199 indexes=GetAuthenticIndexQueue(image);
1200 if (jpeg_info.data_precision > 8)
1202 if (jpeg_info.output_components == 1)
1203 for (x=0; x < (long) image->columns; x++)
1208 if (precision != 16)
1209 pixel=(unsigned long) GETJSAMPLE(*p);
1211 pixel=(unsigned long) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1212 index=ConstrainColormapIndex(image,pixel);
1214 *q++=image->colormap[(int) index];
1218 if (image->colorspace != CMYKColorspace)
1219 for (x=0; x < (long) image->columns; x++)
1221 q->red=ScaleShortToQuantum((unsigned char)
1222 (GETJSAMPLE(*p++) << 4));
1223 q->green=ScaleShortToQuantum((unsigned char)
1224 (GETJSAMPLE(*p++) << 4));
1225 q->blue=ScaleShortToQuantum((unsigned char)
1226 (GETJSAMPLE(*p++) << 4));
1227 SetOpacityPixelComponent(q,OpaqueOpacity);
1231 for (x=0; x < (long) image->columns; x++)
1233 q->red=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1234 (GETJSAMPLE(*p++) << 4));
1235 q->green=(Quantum) QuantumRange-ScaleShortToQuantum(
1236 (unsigned char) (GETJSAMPLE(*p++) << 4));
1237 q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1238 (GETJSAMPLE(*p++) << 4));
1239 SetOpacityPixelComponent(q,OpaqueOpacity);
1240 indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
1241 (unsigned char) (GETJSAMPLE(*p++) << 4));
1246 if (jpeg_info.output_components == 1)
1247 for (x=0; x < (long) image->columns; x++)
1249 index=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
1250 indexes[x]=(IndexPacket) index;
1251 *q++=image->colormap[(int) index];
1255 if (image->colorspace != CMYKColorspace)
1256 for (x=0; x < (long) image->columns; x++)
1258 q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1259 q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1260 q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1261 SetOpacityPixelComponent(q,OpaqueOpacity);
1265 for (x=0; x < (long) image->columns; x++)
1267 q->red=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1269 q->green=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1271 q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1273 SetOpacityPixelComponent(q,OpaqueOpacity);
1274 indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
1275 (unsigned char) GETJSAMPLE(*p++));
1278 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1280 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
1284 Free jpeg resources.
1286 (void) jpeg_finish_decompress(&jpeg_info);
1287 jpeg_destroy_decompress(&jpeg_info);
1288 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1289 (void) CloseBlob(image);
1290 return(GetFirstImageInList(image));
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299 % R e g i s t e r J P E G I m a g e %
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 % RegisterJPEGImage() adds properties for the JPEG image format to
1306 % the list of supported formats. The properties include the image format
1307 % tag, a method to read and/or write the format, whether the format
1308 % supports the saving of more than one frame to the same file or blob,
1309 % whether the format supports native in-memory I/O, and a brief
1310 % description of the format.
1312 % The format of the RegisterJPEGImage method is:
1314 % unsigned long RegisterJPEGImage(void)
1317 ModuleExport unsigned long RegisterJPEGImage(void)
1320 version[MaxTextExtent];
1326 description[] = "Joint Photographic Experts Group JFIF format";
1329 #if defined(JPEG_LIB_VERSION)
1330 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1332 entry=SetMagickInfo("JPEG");
1333 entry->thread_support=NoThreadSupport;
1334 #if defined(MAGICKCORE_JPEG_DELEGATE)
1335 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1336 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1338 entry->magick=(IsImageFormatHandler *) IsJPEG;
1339 entry->adjoin=MagickFalse;
1340 entry->description=ConstantString(description);
1341 if (*version != '\0')
1342 entry->version=ConstantString(version);
1343 entry->module=ConstantString("JPEG");
1344 (void) RegisterMagickInfo(entry);
1345 entry=SetMagickInfo("JPG");
1346 entry->thread_support=NoThreadSupport;
1347 #if defined(MAGICKCORE_JPEG_DELEGATE)
1348 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1349 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1351 entry->adjoin=MagickFalse;
1352 entry->description=ConstantString(description);
1353 if (*version != '\0')
1354 entry->version=ConstantString(version);
1355 entry->module=ConstantString("JPEG");
1356 (void) RegisterMagickInfo(entry);
1357 entry=SetMagickInfo("PJPEG");
1358 entry->thread_support=NoThreadSupport;
1359 #if defined(MAGICKCORE_JPEG_DELEGATE)
1360 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1361 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1363 entry->adjoin=MagickFalse;
1364 entry->description=ConstantString(description);
1365 if (*version != '\0')
1366 entry->version=ConstantString(version);
1367 entry->module=ConstantString("JPEG");
1368 (void) RegisterMagickInfo(entry);
1369 return(MagickImageCoderSignature);
1373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % U n r e g i s t e r J P E G I m a g e %
1381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 % UnregisterJPEGImage() removes format registrations made by the
1384 % JPEG module from the list of supported formats.
1386 % The format of the UnregisterJPEGImage method is:
1388 % UnregisterJPEGImage(void)
1391 ModuleExport void UnregisterJPEGImage(void)
1393 (void) UnregisterMagickInfo("PJPG");
1394 (void) UnregisterMagickInfo("JPEG");
1395 (void) UnregisterMagickInfo("JPG");
1398 #if defined(MAGICKCORE_JPEG_DELEGATE)
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404 % W r i t e J P E G I m a g e %
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 % WriteJPEGImage() writes a JPEG image file and returns it. It
1411 % allocates the memory necessary for the new Image structure and returns a
1412 % pointer to the new image.
1414 % The format of the WriteJPEGImage method is:
1416 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,Image *image)
1418 % A description of each parameter follows:
1420 % o image_info: the image info.
1422 % o jpeg_image: The image.
1427 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1432 destination=(DestinationManager *) cinfo->dest;
1433 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1434 MaxBufferExtent,destination->buffer);
1435 if (destination->manager.free_in_buffer != MaxBufferExtent)
1436 ERREXIT(cinfo,JERR_FILE_WRITE);
1437 destination->manager.next_output_byte=destination->buffer;
1441 static void InitializeDestination(j_compress_ptr cinfo)
1446 destination=(DestinationManager *) cinfo->dest;
1447 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1448 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1449 destination->manager.next_output_byte=destination->buffer;
1450 destination->manager.free_in_buffer=MaxBufferExtent;
1453 static inline size_t MagickMin(const size_t x,const size_t y)
1460 static void TerminateDestination(j_compress_ptr cinfo)
1465 destination=(DestinationManager *) cinfo->dest;
1466 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1471 count=WriteBlob(destination->image,MaxBufferExtent-
1472 destination->manager.free_in_buffer,destination->buffer);
1473 if (count != (ssize_t)
1474 (MaxBufferExtent-destination->manager.free_in_buffer))
1475 ERREXIT(cinfo,JERR_FILE_WRITE);
1479 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1503 Save image profile as a APP marker.
1506 custom_profile=AcquireStringInfo(65535L);
1507 ResetImageProfileIterator(image);
1508 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1510 profile=GetImageProfile(image,name);
1511 if (LocaleCompare(name,"EXIF") == 0)
1512 for (i=0; i < (long) GetStringInfoLength(profile); i+=65533L)
1514 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1515 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1516 (unsigned int) length);
1518 if (LocaleCompare(name,"ICC") == 0)
1520 register unsigned char
1524 p=GetStringInfoDatum(custom_profile);
1525 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1526 for (i=0; i < (long) GetStringInfoLength(profile); i+=65519L)
1528 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1529 p=GetStringInfoDatum(custom_profile);
1530 p[12]=(unsigned char) ((i/65519L)+1);
1531 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1532 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1534 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1535 custom_profile),(unsigned int) (length+tag_length));
1538 if (((LocaleCompare(name,"IPTC") == 0) ||
1539 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1541 register unsigned char
1548 p=GetStringInfoDatum(custom_profile);
1549 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1551 (void) CopyMagickMemory(p,"Photoshop 3.0\0",14);
1556 (void) CopyMagickMemory(p,"Photoshop 3.0\08BIM\04\04\0\0\0\0",24);
1558 p[24]=(unsigned char) (GetStringInfoLength(profile) >> 8);
1559 p[25]=(unsigned char) (GetStringInfoLength(profile) & 0xff);
1562 for (i=0; i < (long) GetStringInfoLength(profile); i+=65500L)
1564 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1565 roundup=(unsigned long) (length & 0x01);
1566 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1569 p[length+tag_length]='\0';
1570 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1571 custom_profile),(unsigned int) (length+tag_length+roundup));
1574 if (LocaleCompare(name,"XMP") == 0)
1580 Add namespace to XMP profile.
1582 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1583 ConcatenateStringInfo(xmp_profile,profile);
1584 GetStringInfoDatum(xmp_profile)[28]='\0';
1585 for (i=0; i < (long) GetStringInfoLength(xmp_profile); i+=65533L)
1587 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1588 jpeg_write_marker(jpeg_info,XML_MARKER,
1589 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1591 xmp_profile=DestroyStringInfo(xmp_profile);
1593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s profile: %lu bytes",
1594 name,(unsigned long) GetStringInfoLength(profile));
1595 name=GetNextImageProfile(image);
1597 custom_profile=DestroyStringInfo(custom_profile);
1600 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1605 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1606 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1607 destination=(DestinationManager *) cinfo->dest;
1608 destination->manager.init_destination=InitializeDestination;
1609 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1610 destination->manager.term_destination=TerminateDestination;
1611 destination->image=image;
1614 static char **SamplingFactorToList(const char *text)
1631 if (text == (char *) NULL)
1632 return((char **) NULL);
1634 Convert string to an ASCII list.
1637 for (p=text; *p != '\0'; p++)
1640 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1642 if (textlist == (char **) NULL)
1643 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1645 for (i=0; i < (long) lines; i++)
1647 for (q=(char *) p; *q != '\0'; q++)
1650 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1651 sizeof(*textlist[i]));
1652 if (textlist[i] == (char *) NULL)
1653 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1654 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1659 textlist[i]=(char *) NULL;
1663 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1692 struct jpeg_compress_struct
1695 struct jpeg_error_mgr
1701 assert(image_info != (const ImageInfo *) NULL);
1702 assert(image_info->signature == MagickSignature);
1703 assert(image != (Image *) NULL);
1704 assert(image->signature == MagickSignature);
1705 if (image->debug != MagickFalse)
1706 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1707 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1708 if (status == MagickFalse)
1711 Initialize JPEG parameters.
1713 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1714 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1715 jpeg_info.client_data=(void *) image;
1716 jpeg_info.err=jpeg_std_error(&jpeg_error);
1717 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
1718 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1719 error_manager.image=image;
1720 jpeg_pixels=(JSAMPLE *) NULL;
1721 if (setjmp(error_manager.error_recovery) != 0)
1723 jpeg_destroy_compress(&jpeg_info);
1724 (void) CloseBlob(image);
1725 return(MagickFalse);
1727 jpeg_info.client_data=(void *) &error_manager;
1728 jpeg_create_compress(&jpeg_info);
1729 JPEGDestinationManager(&jpeg_info,image);
1730 if ((image->columns != (unsigned int) image->columns) ||
1731 (image->rows != (unsigned int) image->rows))
1732 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1733 jpeg_info.image_width=(unsigned int) image->columns;
1734 jpeg_info.image_height=(unsigned int) image->rows;
1735 jpeg_info.input_components=3;
1736 jpeg_info.data_precision=8;
1737 jpeg_info.in_color_space=JCS_RGB;
1738 switch (image->colorspace)
1740 case CMYKColorspace:
1742 jpeg_info.input_components=4;
1743 jpeg_info.in_color_space=JCS_CMYK;
1746 case YCbCrColorspace:
1747 case Rec601YCbCrColorspace:
1748 case Rec709YCbCrColorspace:
1750 jpeg_info.in_color_space=JCS_YCbCr;
1753 case GRAYColorspace:
1754 case Rec601LumaColorspace:
1755 case Rec709LumaColorspace:
1757 jpeg_info.input_components=1;
1758 jpeg_info.in_color_space=JCS_GRAYSCALE;
1763 if (image->colorspace != RGBColorspace)
1764 (void) TransformImageColorspace(image,RGBColorspace);
1768 if ((image_info->type != TrueColorType) &&
1769 (IsGrayImage(image,&image->exception) != MagickFalse))
1771 jpeg_info.input_components=1;
1772 jpeg_info.in_color_space=JCS_GRAYSCALE;
1774 jpeg_set_defaults(&jpeg_info);
1775 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1776 jpeg_info.data_precision=8;
1778 if (sizeof(JSAMPLE) > 1)
1779 jpeg_info.data_precision=12;
1780 jpeg_info.density_unit=(UINT8) 1;
1781 if (image->debug != MagickFalse)
1782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1783 "Image resolution: %ld,%ld",(long) floor(image->x_resolution+0.5),
1784 (long) floor(image->y_resolution+0.5));
1785 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1788 Set image resolution.
1790 jpeg_info.write_JFIF_header=MagickTrue;
1791 jpeg_info.X_density=(UINT16) image->x_resolution;
1792 jpeg_info.Y_density=(UINT16) image->y_resolution;
1793 if (image->units == PixelsPerInchResolution)
1794 jpeg_info.density_unit=(UINT8) 1;
1795 if (image->units == PixelsPerCentimeterResolution)
1796 jpeg_info.density_unit=(UINT8) 2;
1798 option=GetImageOption(image_info,"jpeg:dct-method");
1799 if (option != (const char *) NULL)
1805 if (LocaleCompare(option,"default") == 0)
1806 jpeg_info.dct_method=JDCT_DEFAULT;
1812 if (LocaleCompare(option,"fastest") == 0)
1813 jpeg_info.dct_method=JDCT_FASTEST;
1814 if (LocaleCompare(option,"float") == 0)
1815 jpeg_info.dct_method=JDCT_FLOAT;
1821 if (LocaleCompare(option,"ifast") == 0)
1822 jpeg_info.dct_method=JDCT_IFAST;
1823 if (LocaleCompare(option,"islow") == 0)
1824 jpeg_info.dct_method=JDCT_ISLOW;
1828 option=GetImageOption(image_info,"jpeg:optimize-coding");
1829 if (option != (const char *) NULL)
1831 jpeg_info.optimize_coding=MagickFalse;
1832 if (IsMagickTrue(option) != MagickFalse)
1833 jpeg_info.optimize_coding=MagickTrue;
1840 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1841 image->rows*sizeof(JSAMPLE);
1842 if (length == (MagickSizeType) ((size_t) length))
1845 Perform optimization only if available memory resources permit it.
1847 status=AcquireMagickResource(MemoryResource,length);
1848 if (status != MagickFalse)
1849 jpeg_info.optimize_coding=MagickTrue;
1850 RelinquishMagickResource(MemoryResource,length);
1853 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1854 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1855 (image_info->interlace != NoInterlace))
1857 if (image->debug != MagickFalse)
1858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1859 "Interlace: progressive");
1860 jpeg_simple_progression(&jpeg_info);
1863 if (image->debug != MagickFalse)
1864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1865 "Interlace: non-progressive");
1867 if (image->debug != MagickFalse)
1868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1869 "Interlace: nonprogressive");
1871 option=GetImageOption(image_info,"jpeg:extent");
1872 if (option != (const char *) NULL)
1880 jpeg_info=CloneImageInfo(image_info);
1881 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1882 if (jpeg_image != (Image *) NULL)
1892 Search for compression quality that does not exceed image extent.
1894 jpeg_info->quality=0;
1895 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1896 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1897 (void) AcquireUniqueFilename(jpeg_image->filename);
1899 for (minimum=0; minimum != maximum; )
1901 jpeg_image->quality=minimum+(maximum-minimum)/2;
1902 status=WriteJPEGImage(jpeg_info,jpeg_image);
1903 if (GetBlobSize(jpeg_image) <= extent)
1904 minimum=jpeg_image->quality+1;
1906 maximum=jpeg_image->quality-1;
1908 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1909 image->quality=minimum-1;
1910 jpeg_image=DestroyImage(jpeg_image);
1912 jpeg_info=DestroyImageInfo(jpeg_info);
1914 if ((image_info->compression != LosslessJPEGCompression) &&
1915 (image->quality <= 100))
1917 if (image->quality == UndefinedCompressionQuality)
1918 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1920 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1921 if (image->debug != MagickFalse)
1922 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
1927 #if !defined(C_LOSSLESS_SUPPORTED)
1928 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1929 if (image->debug != MagickFalse)
1930 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1932 if (image->quality < 100)
1933 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1934 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1941 predictor=image->quality/100; /* range 1-7 */
1942 point_transform=image->quality % 20; /* range 0-15 */
1943 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1944 if (image->debug != MagickFalse)
1946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1947 "Compression: lossless");
1948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1949 "Predictor: %d",predictor);
1950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1951 "Point Transform: %d",point_transform);
1956 sampling_factor=(const char *) NULL;
1957 value=GetImageProperty(image,"jpeg:sampling-factor");
1958 if (value != (char *) NULL)
1960 sampling_factor=value;
1961 if (image->debug != MagickFalse)
1962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1963 " Input sampling-factors=%s",sampling_factor);
1965 if (image_info->sampling_factor != (char *) NULL)
1966 sampling_factor=image_info->sampling_factor;
1967 if (sampling_factor == (const char *) NULL)
1969 if (image->quality >= 90)
1970 for (i=0; i < MAX_COMPONENTS; i++)
1972 jpeg_info.comp_info[i].h_samp_factor=1;
1973 jpeg_info.comp_info[i].v_samp_factor=1;
1988 Set sampling factor.
1991 factors=SamplingFactorToList(sampling_factor);
1992 if (factors != (char **) NULL)
1994 for (i=0; i < MAX_COMPONENTS; i++)
1996 if (factors[i] == (char *) NULL)
1998 flags=ParseGeometry(factors[i],&geometry_info);
1999 if ((flags & SigmaValue) == 0)
2000 geometry_info.sigma=geometry_info.rho;
2001 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2002 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2003 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2005 factors=(char **) RelinquishMagickMemory(factors);
2007 for ( ; i < MAX_COMPONENTS; i++)
2009 jpeg_info.comp_info[i].h_samp_factor=1;
2010 jpeg_info.comp_info[i].v_samp_factor=1;
2013 if (jpeg_info.input_components == 1)
2014 for (i=0; i < MAX_COMPONENTS; i++)
2016 jpeg_info.comp_info[i].h_samp_factor=1;
2017 jpeg_info.comp_info[i].v_samp_factor=1;
2019 jpeg_start_compress(&jpeg_info,MagickTrue);
2020 if (image->debug != MagickFalse)
2022 if (image->storage_class == PseudoClass)
2023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2024 "Storage class: PseudoClass");
2026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2027 "Storage class: DirectClass");
2028 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %lu",
2030 if (image->colors != 0)
2031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2032 "Number of colors: %lu",image->colors);
2034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2035 "Number of colors: unspecified");
2036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2037 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2038 switch (image->colorspace)
2040 case CMYKColorspace:
2042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2043 "Storage class: DirectClass");
2044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2045 "Colorspace: CMYK");
2048 case YCbCrColorspace:
2049 case Rec601YCbCrColorspace:
2050 case Rec709YCbCrColorspace:
2052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2053 "Colorspace: YCbCr");
2059 switch (image->colorspace)
2061 case CMYKColorspace:
2063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2064 "Colorspace: CMYK");
2065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2066 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2067 jpeg_info.comp_info[0].h_samp_factor,
2068 jpeg_info.comp_info[0].v_samp_factor,
2069 jpeg_info.comp_info[1].h_samp_factor,
2070 jpeg_info.comp_info[1].v_samp_factor,
2071 jpeg_info.comp_info[2].h_samp_factor,
2072 jpeg_info.comp_info[2].v_samp_factor,
2073 jpeg_info.comp_info[3].h_samp_factor,
2074 jpeg_info.comp_info[3].v_samp_factor);
2077 case GRAYColorspace:
2078 case Rec601LumaColorspace:
2079 case Rec709LumaColorspace:
2081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2082 "Colorspace: GRAY");
2083 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2084 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2085 jpeg_info.comp_info[0].v_samp_factor);
2090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2091 "Image colorspace is RGB");
2092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2093 "Sampling factors: %dx%d,%dx%d,%dx%d",
2094 jpeg_info.comp_info[0].h_samp_factor,
2095 jpeg_info.comp_info[0].v_samp_factor,
2096 jpeg_info.comp_info[1].h_samp_factor,
2097 jpeg_info.comp_info[1].v_samp_factor,
2098 jpeg_info.comp_info[2].h_samp_factor,
2099 jpeg_info.comp_info[2].v_samp_factor);
2102 case YCbCrColorspace:
2103 case Rec601YCbCrColorspace:
2104 case Rec709YCbCrColorspace:
2106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2107 "Colorspace: YCbCr");
2108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2109 "Sampling factors: %dx%d,%dx%d,%dx%d",
2110 jpeg_info.comp_info[0].h_samp_factor,
2111 jpeg_info.comp_info[0].v_samp_factor,
2112 jpeg_info.comp_info[1].h_samp_factor,
2113 jpeg_info.comp_info[1].v_samp_factor,
2114 jpeg_info.comp_info[2].h_samp_factor,
2115 jpeg_info.comp_info[2].v_samp_factor);
2120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2123 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2124 jpeg_info.comp_info[0].h_samp_factor,
2125 jpeg_info.comp_info[0].v_samp_factor,
2126 jpeg_info.comp_info[1].h_samp_factor,
2127 jpeg_info.comp_info[1].v_samp_factor,
2128 jpeg_info.comp_info[2].h_samp_factor,
2129 jpeg_info.comp_info[2].v_samp_factor,
2130 jpeg_info.comp_info[3].h_samp_factor,
2131 jpeg_info.comp_info[3].v_samp_factor);
2137 Write JPEG profiles.
2139 value=GetImageProperty(image,"comment");
2140 if (value != (char *) NULL)
2141 for (i=0; i < (long) strlen(value); i+=65533L)
2142 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2143 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2144 if (image->profiles != (void *) NULL)
2145 WriteProfile(&jpeg_info,image);
2147 Convert MIFF to JPEG raster pixels.
2149 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2150 jpeg_info.input_components*sizeof(*jpeg_pixels));
2151 if (jpeg_pixels == (JSAMPLE *) NULL)
2152 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2153 if (setjmp(error_manager.error_recovery) != 0)
2155 jpeg_destroy_compress(&jpeg_info);
2156 if (jpeg_pixels != (unsigned char *) NULL)
2157 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2158 (void) CloseBlob(image);
2159 return(MagickFalse);
2161 scanline[0]=(JSAMPROW) jpeg_pixels;
2162 if (jpeg_info.data_precision <= 8)
2164 if ((jpeg_info.in_color_space == JCS_RGB) ||
2165 (jpeg_info.in_color_space == JCS_YCbCr))
2166 for (y=0; y < (long) image->rows; y++)
2168 register const PixelPacket
2174 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2175 if (p == (const PixelPacket *) NULL)
2178 for (x=0; x < (long) image->columns; x++)
2180 *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
2181 *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
2182 *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
2185 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2186 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2190 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2191 for (y=0; y < (long) image->rows; y++)
2193 register const PixelPacket
2199 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2200 if (p == (const PixelPacket *) NULL)
2203 for (x=0; x < (long) image->columns; x++)
2205 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2208 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2209 if (SetImageProgress(image,SaveImageTag,y,image->rows) == 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) (ScaleQuantumToChar((Quantum) (QuantumRange-
2235 GetRedPixelComponent(p))));
2236 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2237 GetGreenPixelComponent(p))));
2238 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2239 GetBluePixelComponent(p))));
2240 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2244 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2245 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2250 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2251 for (y=0; y < (long) image->rows; y++)
2253 register const PixelPacket
2259 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2260 if (p == (const PixelPacket *) NULL)
2263 for (x=0; x < (long) image->columns; x++)
2265 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2269 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2270 if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
2274 if ((jpeg_info.in_color_space == JCS_RGB) ||
2275 (jpeg_info.in_color_space == JCS_YCbCr))
2276 for (y=0; y < (long) image->rows; y++)
2278 register const PixelPacket
2284 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2285 if (p == (const PixelPacket *) NULL)
2288 for (x=0; x < (long) image->columns; x++)
2290 *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >>
2292 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >>
2294 *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >>
2298 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2299 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2300 if (status == MagickFalse)
2304 for (y=0; y < (long) image->rows; y++)
2306 register const IndexPacket
2309 register const PixelPacket
2315 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2316 if (p == (const PixelPacket *) NULL)
2319 indexes=GetVirtualIndexQueue(image);
2320 for (x=0; x < (long) image->columns; x++)
2323 Convert DirectClass packets to contiguous CMYK scanlines.
2325 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2326 GetRedPixelComponent(p)) >> 4));
2327 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2328 GetGreenPixelComponent(p)) >> 4));
2329 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2330 GetBluePixelComponent(p)) >> 4));
2331 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
2334 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2335 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2336 if (status == MagickFalse)
2339 if (y == (long) image->rows)
2340 jpeg_finish_compress(&jpeg_info);
2342 Relinquish resources.
2344 jpeg_destroy_compress(&jpeg_info);
2345 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2346 (void) CloseBlob(image);