2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
46 #include "magick/studio.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/color.h"
51 #include "magick/colormap-private.h"
52 #include "magick/color-private.h"
53 #include "magick/colormap.h"
54 #include "magick/colorspace.h"
55 #include "magick/constitute.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/geometry.h"
59 #include "magick/image.h"
60 #include "magick/image-private.h"
61 #include "magick/list.h"
62 #include "magick/log.h"
63 #include "magick/magick.h"
64 #include "magick/memory_.h"
65 #include "magick/module.h"
66 #include "magick/monitor.h"
67 #include "magick/monitor-private.h"
68 #include "magick/option.h"
69 #include "magick/profile.h"
70 #include "magick/property.h"
71 #include "magick/quantum-private.h"
72 #include "magick/resource_.h"
73 #include "magick/splay-tree.h"
74 #include "magick/static.h"
75 #include "magick/string_.h"
76 #include "magick/string-private.h"
77 #include "magick/utility.h"
79 #if defined(MAGICKCORE_JPEG_DELEGATE)
80 #define JPEG_INTERNAL_OPTIONS
81 #if defined(__MINGW32__)
82 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
83 typedef unsigned char boolean;
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) ReadBlob(source->image,
246 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) ((size_t) 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",
348 i=(ssize_t) length-1;
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) ((size_t) 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 < (ssize_t) (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=(ssize_t) 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, %.20g bytes",(double) 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) ((size_t) 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 < (ssize_t) 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=0; i < (ssize_t) GetStringInfoLength(profile); 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, %.20g bytes",(double) length);
535 static boolean ReadProfile(j_decompress_ptr jpeg_info)
555 register unsigned char
565 Read generic profile.
567 length=(size_t) ((size_t) 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=(ssize_t) 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 < (ssize_t) GetStringInfoLength(profile); j++)
603 if (j < (ssize_t) 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, %.20g bytes",name,(double) 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+=number_bytes;
633 source->manager.bytes_in_buffer-=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=(ssize_t) (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=(size_t) i+1;
738 if (image->debug != MagickFalse)
739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
740 "Quality: %.20g (%s)",(double) 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=(ssize_t) (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=(size_t) i+1;
787 if (image->debug != MagickFalse)
788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
789 "Quality: %.20g (%s)",(double) 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];
894 struct jpeg_decompress_struct
897 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();
922 image=AcquireImage(image_info);
923 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
924 if (status == MagickFalse)
926 image=DestroyImageList(image);
927 return((Image *) NULL);
930 Initialize JPEG parameters.
932 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
933 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
934 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
935 jpeg_info.err=jpeg_std_error(&jpeg_error);
936 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
937 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
938 jpeg_pixels=(JSAMPLE *) NULL;
939 error_manager.image=image;
940 if (setjmp(error_manager.error_recovery) != 0)
942 jpeg_destroy_decompress(&jpeg_info);
943 (void) CloseBlob(image);
944 number_pixels=(MagickSizeType) image->columns*image->rows;
945 if (number_pixels != 0)
946 return(GetFirstImageInList(image));
947 InheritException(exception,&image->exception);
948 return(DestroyImage(image));
950 jpeg_info.client_data=(void *) &error_manager;
951 jpeg_create_decompress(&jpeg_info);
952 JPEGSourceManager(&jpeg_info,image);
953 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
954 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
955 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
956 for (i=1; i < 16; i++)
957 if ((i != 2) && (i != 13) && (i != 14))
958 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
959 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
960 if ((image_info->colorspace == YCbCrColorspace) ||
961 (image_info->colorspace == Rec601YCbCrColorspace) ||
962 (image_info->colorspace == Rec709YCbCrColorspace))
963 jpeg_info.out_color_space=JCS_YCbCr;
964 if (IsITUFaxImage(image) != MagickFalse)
966 image->colorspace=LabColorspace;
967 jpeg_info.out_color_space=JCS_YCbCr;
970 if (jpeg_info.out_color_space == JCS_CMYK)
971 image->colorspace=CMYKColorspace;
973 Set image resolution.
976 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
977 (jpeg_info.Y_density != 1))
979 image->x_resolution=(double) jpeg_info.X_density;
980 image->y_resolution=(double) jpeg_info.Y_density;
981 units=(size_t) jpeg_info.density_unit;
984 image->units=PixelsPerInchResolution;
986 image->units=PixelsPerCentimeterResolution;
987 number_pixels=(MagickSizeType) image->columns*image->rows;
988 option=GetImageOption(image_info,"jpeg:size");
989 if (option != (const char *) NULL)
1003 flags=ParseGeometry(option,&geometry_info);
1004 if ((flags & SigmaValue) == 0)
1005 geometry_info.sigma=geometry_info.rho;
1006 jpeg_calc_output_dimensions(&jpeg_info);
1007 image->magick_columns=jpeg_info.output_width;
1008 image->magick_rows=jpeg_info.output_height;
1010 if (geometry_info.rho != 0.0)
1011 scale_factor=jpeg_info.output_width/geometry_info.rho;
1012 if ((geometry_info.sigma != 0.0) &&
1013 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1014 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1015 jpeg_info.scale_num=1U;
1016 jpeg_info.scale_denom=(unsigned int) scale_factor;
1017 jpeg_calc_output_dimensions(&jpeg_info);
1018 if (image->debug != MagickFalse)
1019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1020 "Scale factor: %.20g",(double) scale_factor);
1022 precision=(size_t) jpeg_info.data_precision;
1023 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1024 #if defined(D_LOSSLESS_SUPPORTED)
1025 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1026 JPEGInterlace : NoInterlace;
1027 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1028 LosslessJPEGCompression : JPEGCompression;
1029 if (jpeg_info.data_precision > 8)
1030 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1031 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1033 if (jpeg_info.data_precision == 16)
1034 jpeg_info.data_precision=12;
1036 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1038 image->compression=JPEGCompression;
1041 image->compression=JPEGCompression;
1042 image->interlace=JPEGInterlace;
1044 if ((image_info->colors > 8) && (image_info->colors <= 256))
1047 Let the JPEG library quantize for us.
1049 jpeg_info.quantize_colors=MagickTrue;
1050 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1052 option=GetImageOption(image_info,"jpeg:block-smoothing");
1053 if (option != (const char *) NULL)
1055 jpeg_info.do_block_smoothing=MagickFalse;
1056 if (IsMagickTrue(option) != MagickFalse)
1057 jpeg_info.do_block_smoothing=MagickTrue;
1059 option=GetImageOption(image_info,"jpeg:dct-method");
1060 if (option != (const char *) NULL)
1066 if (LocaleCompare(option,"default") == 0)
1067 jpeg_info.dct_method=JDCT_DEFAULT;
1073 if (LocaleCompare(option,"fastest") == 0)
1074 jpeg_info.dct_method=JDCT_FASTEST;
1075 if (LocaleCompare(option,"float") == 0)
1076 jpeg_info.dct_method=JDCT_FLOAT;
1082 if (LocaleCompare(option,"ifast") == 0)
1083 jpeg_info.dct_method=JDCT_IFAST;
1084 if (LocaleCompare(option,"islow") == 0)
1085 jpeg_info.dct_method=JDCT_ISLOW;
1089 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1090 if (option != (const char *) NULL)
1092 jpeg_info.do_fancy_upsampling=MagickFalse;
1093 if (IsMagickTrue(option) != MagickFalse)
1094 jpeg_info.do_fancy_upsampling=MagickTrue;
1096 (void) jpeg_start_decompress(&jpeg_info);
1097 image->columns=jpeg_info.output_width;
1098 image->rows=jpeg_info.output_height;
1099 image->depth=(size_t) jpeg_info.data_precision;
1100 if (jpeg_info.out_color_space == JCS_YCbCr)
1101 image->colorspace=YCbCrColorspace;
1102 if (jpeg_info.out_color_space == JCS_CMYK)
1103 image->colorspace=CMYKColorspace;
1104 if ((image_info->colors != 0) && (image_info->colors <= 256))
1105 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1106 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1107 if ((jpeg_info.output_components == 1) &&
1108 (jpeg_info.quantize_colors == MagickFalse))
1113 colors=(size_t) GetQuantumRange(image->depth)+1;
1114 if (AcquireImageColormap(image,colors) == MagickFalse)
1115 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1117 if (image->debug != MagickFalse)
1119 if (image->interlace != NoInterlace)
1120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1121 "Interlace: progressive");
1123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1124 "Interlace: nonprogressive");
1125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1126 (int) jpeg_info.data_precision);
1127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1128 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1130 JPEGSetImageQuality(&jpeg_info,image);
1131 JPEGSetImageSamplingFactor(&jpeg_info,image);
1132 (void) FormatMagickString(value,MaxTextExtent,"%.20g",(double)
1133 jpeg_info.out_color_space);
1134 (void) SetImageProperty(image,"jpeg:colorspace",value);
1135 if (image_info->ping != MagickFalse)
1137 jpeg_destroy_decompress(&jpeg_info);
1138 (void) CloseBlob(image);
1139 return(GetFirstImageInList(image));
1141 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1142 jpeg_info.output_components*sizeof(JSAMPLE));
1143 if (jpeg_pixels == (JSAMPLE *) NULL)
1144 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1146 Convert JPEG pixels to pixel packets.
1148 if (setjmp(error_manager.error_recovery) != 0)
1150 if (jpeg_pixels != (unsigned char *) NULL)
1151 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1152 jpeg_destroy_decompress(&jpeg_info);
1153 (void) CloseBlob(image);
1154 number_pixels=(MagickSizeType) image->columns*image->rows;
1155 if (number_pixels != 0)
1156 return(GetFirstImageInList(image));
1157 return(DestroyImage(image));
1159 if (jpeg_info.quantize_colors != MagickFalse)
1161 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1162 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1163 for (i=0; i < (ssize_t) image->colors; i++)
1165 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1166 image->colormap[i].green=image->colormap[i].red;
1167 image->colormap[i].blue=image->colormap[i].red;
1168 image->colormap[i].opacity=OpaqueOpacity;
1171 for (i=0; i < (ssize_t) image->colors; i++)
1173 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1174 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1175 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1176 image->colormap[i].opacity=OpaqueOpacity;
1179 scanline[0]=(JSAMPROW) jpeg_pixels;
1180 for (y=0; y < (ssize_t) image->rows; y++)
1182 register IndexPacket
1188 register PixelPacket
1191 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1193 (void) ThrowMagickException(exception,GetMagickModule(),
1194 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1198 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1199 if (q == (PixelPacket *) NULL)
1201 indexes=GetAuthenticIndexQueue(image);
1202 if (jpeg_info.data_precision > 8)
1204 if (jpeg_info.output_components == 1)
1205 for (x=0; x < (ssize_t) image->columns; x++)
1210 if (precision != 16)
1211 pixel=(size_t) GETJSAMPLE(*p);
1213 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1214 index=ConstrainColormapIndex(image,pixel);
1215 SetIndexPixelComponent(indexes+x,index);
1216 SetRedPixelComponent(q,image->colormap[(int) index].red);
1217 SetGreenPixelComponent(q,image->colormap[(int) index].green);
1218 SetBluePixelComponent(q,image->colormap[(int) index].blue);
1223 if (image->colorspace != CMYKColorspace)
1224 for (x=0; x < (ssize_t) image->columns; x++)
1226 SetRedPixelComponent(q,ScaleShortToQuantum((unsigned char)
1227 (GETJSAMPLE(*p++) << 4)));
1228 SetGreenPixelComponent(q,ScaleShortToQuantum((unsigned char)
1229 (GETJSAMPLE(*p++) << 4)));
1230 SetBluePixelComponent(q,ScaleShortToQuantum((unsigned char)
1231 (GETJSAMPLE(*p++) << 4)));
1232 SetOpacityPixelComponent(q,OpaqueOpacity);
1236 for (x=0; x < (ssize_t) image->columns; x++)
1238 SetCyanPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1239 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1240 SetMagentaPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1241 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1242 SetYellowPixelComponent(q,QuantumRange-ScaleShortToQuantum(
1243 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1244 SetBlackPixelComponent(indexes+x,QuantumRange-ScaleShortToQuantum(
1245 (unsigned char) (GETJSAMPLE(*p++) << 4)));
1246 SetOpacityPixelComponent(q,OpaqueOpacity);
1251 if (jpeg_info.output_components == 1)
1252 for (x=0; x < (ssize_t) image->columns; x++)
1254 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1255 SetIndexPixelComponent(indexes+x,index);
1256 SetRedPixelComponent(q,image->colormap[(int) index].red);
1257 SetGreenPixelComponent(q,image->colormap[(int) index].green);
1258 SetBluePixelComponent(q,image->colormap[(int) index].blue);
1263 if (image->colorspace != CMYKColorspace)
1264 for (x=0; x < (ssize_t) image->columns; x++)
1266 SetRedPixelComponent(q,ScaleCharToQuantum((unsigned char)
1268 SetGreenPixelComponent(q,ScaleCharToQuantum((unsigned char)
1270 SetBluePixelComponent(q,ScaleCharToQuantum((unsigned char)
1272 SetOpacityPixelComponent(q,OpaqueOpacity);
1276 for (x=0; x < (ssize_t) image->columns; x++)
1278 SetCyanPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1279 (unsigned char) GETJSAMPLE(*p++)));
1280 SetMagentaPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1281 (unsigned char) GETJSAMPLE(*p++)));
1282 SetYellowPixelComponent(q,QuantumRange-ScaleCharToQuantum(
1283 (unsigned char) GETJSAMPLE(*p++)));
1284 SetBlackPixelComponent(indexes+x,QuantumRange-ScaleCharToQuantum(
1285 (unsigned char) GETJSAMPLE(*p++)));
1286 SetOpacityPixelComponent(q,OpaqueOpacity);
1289 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1291 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1293 if (status == MagickFalse)
1297 Free jpeg resources.
1299 (void) jpeg_finish_decompress(&jpeg_info);
1300 jpeg_destroy_decompress(&jpeg_info);
1301 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1302 (void) CloseBlob(image);
1303 return(GetFirstImageInList(image));
1308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312 % R e g i s t e r J P E G I m a g e %
1316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1318 % RegisterJPEGImage() adds properties for the JPEG image format to
1319 % the list of supported formats. The properties include the image format
1320 % tag, a method to read and/or write the format, whether the format
1321 % supports the saving of more than one frame to the same file or blob,
1322 % whether the format supports native in-memory I/O, and a brief
1323 % description of the format.
1325 % The format of the RegisterJPEGImage method is:
1327 % size_t RegisterJPEGImage(void)
1330 ModuleExport size_t RegisterJPEGImage(void)
1333 version[MaxTextExtent];
1339 description[] = "Joint Photographic Experts Group JFIF format";
1342 #if defined(JPEG_LIB_VERSION)
1343 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1345 entry=SetMagickInfo("JPEG");
1346 entry->thread_support=NoThreadSupport;
1347 #if defined(MAGICKCORE_JPEG_DELEGATE)
1348 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1349 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1351 entry->magick=(IsImageFormatHandler *) IsJPEG;
1352 entry->adjoin=MagickFalse;
1353 entry->description=ConstantString(description);
1354 if (*version != '\0')
1355 entry->version=ConstantString(version);
1356 entry->module=ConstantString("JPEG");
1357 (void) RegisterMagickInfo(entry);
1358 entry=SetMagickInfo("JPG");
1359 entry->thread_support=NoThreadSupport;
1360 #if defined(MAGICKCORE_JPEG_DELEGATE)
1361 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1362 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1364 entry->adjoin=MagickFalse;
1365 entry->description=ConstantString(description);
1366 if (*version != '\0')
1367 entry->version=ConstantString(version);
1368 entry->module=ConstantString("JPEG");
1369 (void) RegisterMagickInfo(entry);
1370 entry=SetMagickInfo("PJPEG");
1371 entry->thread_support=NoThreadSupport;
1372 #if defined(MAGICKCORE_JPEG_DELEGATE)
1373 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1374 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1376 entry->adjoin=MagickFalse;
1377 entry->description=ConstantString(description);
1378 if (*version != '\0')
1379 entry->version=ConstantString(version);
1380 entry->module=ConstantString("JPEG");
1381 (void) RegisterMagickInfo(entry);
1382 return(MagickImageCoderSignature);
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390 % U n r e g i s t e r J P E G I m a g e %
1394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 % UnregisterJPEGImage() removes format registrations made by the
1397 % JPEG module from the list of supported formats.
1399 % The format of the UnregisterJPEGImage method is:
1401 % UnregisterJPEGImage(void)
1404 ModuleExport void UnregisterJPEGImage(void)
1406 (void) UnregisterMagickInfo("PJPG");
1407 (void) UnregisterMagickInfo("JPEG");
1408 (void) UnregisterMagickInfo("JPG");
1411 #if defined(MAGICKCORE_JPEG_DELEGATE)
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417 % W r i t e J P E G I m a g e %
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 % WriteJPEGImage() writes a JPEG image file and returns it. It
1424 % allocates the memory necessary for the new Image structure and returns a
1425 % pointer to the new image.
1427 % The format of the WriteJPEGImage method is:
1429 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1432 % A description of each parameter follows:
1434 % o image_info: the image info.
1436 % o jpeg_image: The image.
1441 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1446 destination=(DestinationManager *) cinfo->dest;
1447 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1448 MaxBufferExtent,destination->buffer);
1449 if (destination->manager.free_in_buffer != MaxBufferExtent)
1450 ERREXIT(cinfo,JERR_FILE_WRITE);
1451 destination->manager.next_output_byte=destination->buffer;
1455 static void InitializeDestination(j_compress_ptr cinfo)
1460 destination=(DestinationManager *) cinfo->dest;
1461 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1462 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1463 destination->manager.next_output_byte=destination->buffer;
1464 destination->manager.free_in_buffer=MaxBufferExtent;
1467 static inline size_t MagickMin(const size_t x,const size_t y)
1474 static void TerminateDestination(j_compress_ptr cinfo)
1479 destination=(DestinationManager *) cinfo->dest;
1480 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1485 count=WriteBlob(destination->image,MaxBufferExtent-
1486 destination->manager.free_in_buffer,destination->buffer);
1487 if (count != (ssize_t)
1488 (MaxBufferExtent-destination->manager.free_in_buffer))
1489 ERREXIT(cinfo,JERR_FILE_WRITE);
1493 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1515 Save image profile as a APP marker.
1518 custom_profile=AcquireStringInfo(65535L);
1519 ResetImageProfileIterator(image);
1520 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1522 register unsigned char
1525 profile=GetImageProfile(image,name);
1526 p=GetStringInfoDatum(custom_profile);
1527 if (LocaleCompare(name,"EXIF") == 0)
1528 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1530 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1531 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1532 (unsigned int) length);
1534 if (LocaleCompare(name,"ICC") == 0)
1536 register unsigned char
1540 p=GetStringInfoDatum(custom_profile);
1541 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1542 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1544 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1545 p[12]=(unsigned char) ((i/65519L)+1);
1546 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1547 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1549 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1550 custom_profile),(unsigned int) (length+tag_length));
1553 if (((LocaleCompare(name,"IPTC") == 0) ||
1554 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1560 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1562 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1563 roundup=(size_t) (length & 0x01);
1564 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1566 (void) memcpy(p,"Photoshop 3.0 ",14);
1571 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1573 p[24]=(unsigned char) (length >> 8);
1574 p[25]=(unsigned char) (length & 0xff);
1577 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1579 p[length+tag_length]='\0';
1580 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1581 custom_profile),(unsigned int) (length+tag_length+roundup));
1584 if (LocaleCompare(name,"XMP") == 0)
1590 Add namespace to XMP profile.
1592 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1593 ConcatenateStringInfo(xmp_profile,profile);
1594 GetStringInfoDatum(xmp_profile)[28]='\0';
1595 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1597 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1598 jpeg_write_marker(jpeg_info,XML_MARKER,
1599 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1601 xmp_profile=DestroyStringInfo(xmp_profile);
1603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1604 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1605 name=GetNextImageProfile(image);
1607 custom_profile=DestroyStringInfo(custom_profile);
1610 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1615 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1616 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1617 destination=(DestinationManager *) cinfo->dest;
1618 destination->manager.init_destination=InitializeDestination;
1619 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1620 destination->manager.term_destination=TerminateDestination;
1621 destination->image=image;
1624 static char **SamplingFactorToList(const char *text)
1641 if (text == (char *) NULL)
1642 return((char **) NULL);
1644 Convert string to an ASCII list.
1647 for (p=text; *p != '\0'; p++)
1650 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1652 if (textlist == (char **) NULL)
1653 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1655 for (i=0; i < (ssize_t) lines; i++)
1657 for (q=(char *) p; *q != '\0'; q++)
1660 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1661 sizeof(*textlist[i]));
1662 if (textlist[i] == (char *) NULL)
1663 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1664 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1669 textlist[i]=(char *) NULL;
1673 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1702 struct jpeg_compress_struct
1705 struct jpeg_error_mgr
1711 assert(image_info != (const ImageInfo *) NULL);
1712 assert(image_info->signature == MagickSignature);
1713 assert(image != (Image *) NULL);
1714 assert(image->signature == MagickSignature);
1715 if (image->debug != MagickFalse)
1716 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1717 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1718 if (status == MagickFalse)
1721 Initialize JPEG parameters.
1723 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1724 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1725 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1726 jpeg_info.client_data=(void *) image;
1727 jpeg_info.err=jpeg_std_error(&jpeg_error);
1728 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
1729 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1730 error_manager.image=image;
1731 jpeg_pixels=(JSAMPLE *) NULL;
1732 if (setjmp(error_manager.error_recovery) != 0)
1734 jpeg_destroy_compress(&jpeg_info);
1735 (void) CloseBlob(image);
1736 return(MagickFalse);
1738 jpeg_info.client_data=(void *) &error_manager;
1739 jpeg_create_compress(&jpeg_info);
1740 JPEGDestinationManager(&jpeg_info,image);
1741 if ((image->columns != (unsigned int) image->columns) ||
1742 (image->rows != (unsigned int) image->rows))
1743 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1744 jpeg_info.image_width=(unsigned int) image->columns;
1745 jpeg_info.image_height=(unsigned int) image->rows;
1746 jpeg_info.input_components=3;
1747 jpeg_info.data_precision=8;
1748 jpeg_info.in_color_space=JCS_RGB;
1749 switch (image->colorspace)
1751 case CMYKColorspace:
1753 jpeg_info.input_components=4;
1754 jpeg_info.in_color_space=JCS_CMYK;
1757 case YCbCrColorspace:
1758 case Rec601YCbCrColorspace:
1759 case Rec709YCbCrColorspace:
1761 jpeg_info.in_color_space=JCS_YCbCr;
1764 case GRAYColorspace:
1765 case Rec601LumaColorspace:
1766 case Rec709LumaColorspace:
1768 jpeg_info.input_components=1;
1769 jpeg_info.in_color_space=JCS_GRAYSCALE;
1774 if (image->colorspace != RGBColorspace)
1775 (void) TransformImageColorspace(image,RGBColorspace);
1779 if ((image_info->type != TrueColorType) &&
1780 (IsGrayImage(image,&image->exception) != MagickFalse))
1782 jpeg_info.input_components=1;
1783 jpeg_info.in_color_space=JCS_GRAYSCALE;
1785 jpeg_set_defaults(&jpeg_info);
1786 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1787 jpeg_info.data_precision=8;
1789 if (sizeof(JSAMPLE) > 1)
1790 jpeg_info.data_precision=12;
1791 jpeg_info.density_unit=(UINT8) 1;
1792 if (image->debug != MagickFalse)
1793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1794 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1795 floor(image->y_resolution+0.5));
1796 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1799 Set image resolution.
1801 jpeg_info.write_JFIF_header=MagickTrue;
1802 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1803 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1804 if (image->units == PixelsPerInchResolution)
1805 jpeg_info.density_unit=(UINT8) 1;
1806 if (image->units == PixelsPerCentimeterResolution)
1807 jpeg_info.density_unit=(UINT8) 2;
1809 option=GetImageOption(image_info,"jpeg:dct-method");
1810 if (option != (const char *) NULL)
1816 if (LocaleCompare(option,"default") == 0)
1817 jpeg_info.dct_method=JDCT_DEFAULT;
1823 if (LocaleCompare(option,"fastest") == 0)
1824 jpeg_info.dct_method=JDCT_FASTEST;
1825 if (LocaleCompare(option,"float") == 0)
1826 jpeg_info.dct_method=JDCT_FLOAT;
1832 if (LocaleCompare(option,"ifast") == 0)
1833 jpeg_info.dct_method=JDCT_IFAST;
1834 if (LocaleCompare(option,"islow") == 0)
1835 jpeg_info.dct_method=JDCT_ISLOW;
1839 option=GetImageOption(image_info,"jpeg:optimize-coding");
1840 if (option != (const char *) NULL)
1842 jpeg_info.optimize_coding=MagickFalse;
1843 if (IsMagickTrue(option) != MagickFalse)
1844 jpeg_info.optimize_coding=MagickTrue;
1851 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1852 image->rows*sizeof(JSAMPLE);
1853 if (length == (MagickSizeType) ((size_t) length))
1856 Perform optimization only if available memory resources permit it.
1858 status=AcquireMagickResource(MemoryResource,length);
1859 if (status != MagickFalse)
1860 jpeg_info.optimize_coding=MagickTrue;
1861 RelinquishMagickResource(MemoryResource,length);
1864 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1865 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1866 (image_info->interlace != NoInterlace))
1868 if (image->debug != MagickFalse)
1869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1870 "Interlace: progressive");
1871 jpeg_simple_progression(&jpeg_info);
1874 if (image->debug != MagickFalse)
1875 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1876 "Interlace: non-progressive");
1878 if (image->debug != MagickFalse)
1879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1880 "Interlace: nonprogressive");
1882 option=GetImageOption(image_info,"jpeg:extent");
1883 if (option != (const char *) NULL)
1891 jpeg_info=CloneImageInfo(image_info);
1892 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1893 if (jpeg_image != (Image *) NULL)
1903 Search for compression quality that does not exceed image extent.
1905 jpeg_info->quality=0;
1906 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1907 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1908 (void) AcquireUniqueFilename(jpeg_image->filename);
1910 for (minimum=0; minimum != maximum; )
1912 jpeg_image->quality=minimum+(maximum-minimum)/2;
1913 status=WriteJPEGImage(jpeg_info,jpeg_image);
1914 if (GetBlobSize(jpeg_image) <= extent)
1915 minimum=jpeg_image->quality+1;
1917 maximum=jpeg_image->quality-1;
1919 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1920 image->quality=minimum-1;
1921 jpeg_image=DestroyImage(jpeg_image);
1923 jpeg_info=DestroyImageInfo(jpeg_info);
1925 if ((image_info->compression != LosslessJPEGCompression) &&
1926 (image->quality <= 100))
1928 if (image->quality == UndefinedCompressionQuality)
1929 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1931 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1932 if (image->debug != MagickFalse)
1933 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
1934 (double) image->quality);
1938 #if !defined(C_LOSSLESS_SUPPORTED)
1939 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1940 if (image->debug != MagickFalse)
1941 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1943 if (image->quality < 100)
1944 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1945 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1952 predictor=image->quality/100; /* range 1-7 */
1953 point_transform=image->quality % 20; /* range 0-15 */
1954 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1955 if (image->debug != MagickFalse)
1957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1958 "Compression: lossless");
1959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1960 "Predictor: %d",predictor);
1961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962 "Point Transform: %d",point_transform);
1967 sampling_factor=(const char *) NULL;
1968 value=GetImageProperty(image,"jpeg:sampling-factor");
1969 if (value != (char *) NULL)
1971 sampling_factor=value;
1972 if (image->debug != MagickFalse)
1973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1974 " Input sampling-factors=%s",sampling_factor);
1976 if (image_info->sampling_factor != (char *) NULL)
1977 sampling_factor=image_info->sampling_factor;
1978 if (sampling_factor == (const char *) NULL)
1980 if (image->quality >= 90)
1981 for (i=0; i < MAX_COMPONENTS; i++)
1983 jpeg_info.comp_info[i].h_samp_factor=1;
1984 jpeg_info.comp_info[i].v_samp_factor=1;
1999 Set sampling factor.
2002 factors=SamplingFactorToList(sampling_factor);
2003 if (factors != (char **) NULL)
2005 for (i=0; i < MAX_COMPONENTS; i++)
2007 if (factors[i] == (char *) NULL)
2009 flags=ParseGeometry(factors[i],&geometry_info);
2010 if ((flags & SigmaValue) == 0)
2011 geometry_info.sigma=geometry_info.rho;
2012 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2013 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2014 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2016 factors=(char **) RelinquishMagickMemory(factors);
2018 for ( ; i < MAX_COMPONENTS; i++)
2020 jpeg_info.comp_info[i].h_samp_factor=1;
2021 jpeg_info.comp_info[i].v_samp_factor=1;
2024 if (jpeg_info.input_components == 1)
2025 for (i=0; i < MAX_COMPONENTS; i++)
2027 jpeg_info.comp_info[i].h_samp_factor=1;
2028 jpeg_info.comp_info[i].v_samp_factor=1;
2030 jpeg_start_compress(&jpeg_info,MagickTrue);
2031 if (image->debug != MagickFalse)
2033 if (image->storage_class == PseudoClass)
2034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2035 "Storage class: PseudoClass");
2037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2038 "Storage class: DirectClass");
2039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2040 (double) image->depth);
2041 if (image->colors != 0)
2042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2043 "Number of colors: %.20g",(double) image->colors);
2045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2046 "Number of colors: unspecified");
2047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2048 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2049 switch (image->colorspace)
2051 case CMYKColorspace:
2053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2054 "Storage class: DirectClass");
2055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2056 "Colorspace: CMYK");
2059 case YCbCrColorspace:
2060 case Rec601YCbCrColorspace:
2061 case Rec709YCbCrColorspace:
2063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2064 "Colorspace: YCbCr");
2070 switch (image->colorspace)
2072 case CMYKColorspace:
2074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2075 "Colorspace: CMYK");
2076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2077 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2078 jpeg_info.comp_info[0].h_samp_factor,
2079 jpeg_info.comp_info[0].v_samp_factor,
2080 jpeg_info.comp_info[1].h_samp_factor,
2081 jpeg_info.comp_info[1].v_samp_factor,
2082 jpeg_info.comp_info[2].h_samp_factor,
2083 jpeg_info.comp_info[2].v_samp_factor,
2084 jpeg_info.comp_info[3].h_samp_factor,
2085 jpeg_info.comp_info[3].v_samp_factor);
2088 case GRAYColorspace:
2089 case Rec601LumaColorspace:
2090 case Rec709LumaColorspace:
2092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2093 "Colorspace: GRAY");
2094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2095 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2096 jpeg_info.comp_info[0].v_samp_factor);
2101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2102 "Image colorspace is RGB");
2103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2104 "Sampling factors: %dx%d,%dx%d,%dx%d",
2105 jpeg_info.comp_info[0].h_samp_factor,
2106 jpeg_info.comp_info[0].v_samp_factor,
2107 jpeg_info.comp_info[1].h_samp_factor,
2108 jpeg_info.comp_info[1].v_samp_factor,
2109 jpeg_info.comp_info[2].h_samp_factor,
2110 jpeg_info.comp_info[2].v_samp_factor);
2113 case YCbCrColorspace:
2114 case Rec601YCbCrColorspace:
2115 case Rec709YCbCrColorspace:
2117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2118 "Colorspace: YCbCr");
2119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2120 "Sampling factors: %dx%d,%dx%d,%dx%d",
2121 jpeg_info.comp_info[0].h_samp_factor,
2122 jpeg_info.comp_info[0].v_samp_factor,
2123 jpeg_info.comp_info[1].h_samp_factor,
2124 jpeg_info.comp_info[1].v_samp_factor,
2125 jpeg_info.comp_info[2].h_samp_factor,
2126 jpeg_info.comp_info[2].v_samp_factor);
2131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2134 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2135 jpeg_info.comp_info[0].h_samp_factor,
2136 jpeg_info.comp_info[0].v_samp_factor,
2137 jpeg_info.comp_info[1].h_samp_factor,
2138 jpeg_info.comp_info[1].v_samp_factor,
2139 jpeg_info.comp_info[2].h_samp_factor,
2140 jpeg_info.comp_info[2].v_samp_factor,
2141 jpeg_info.comp_info[3].h_samp_factor,
2142 jpeg_info.comp_info[3].v_samp_factor);
2148 Write JPEG profiles.
2150 value=GetImageProperty(image,"comment");
2151 if (value != (char *) NULL)
2152 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2153 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2154 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2155 if (image->profiles != (void *) NULL)
2156 WriteProfile(&jpeg_info,image);
2158 Convert MIFF to JPEG raster pixels.
2160 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2161 jpeg_info.input_components*sizeof(*jpeg_pixels));
2162 if (jpeg_pixels == (JSAMPLE *) NULL)
2163 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2164 if (setjmp(error_manager.error_recovery) != 0)
2166 jpeg_destroy_compress(&jpeg_info);
2167 if (jpeg_pixels != (unsigned char *) NULL)
2168 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2169 (void) CloseBlob(image);
2170 return(MagickFalse);
2172 scanline[0]=(JSAMPROW) jpeg_pixels;
2173 if (jpeg_info.data_precision <= 8)
2175 if ((jpeg_info.in_color_space == JCS_RGB) ||
2176 (jpeg_info.in_color_space == JCS_YCbCr))
2177 for (y=0; y < (ssize_t) image->rows; y++)
2179 register const PixelPacket
2185 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2186 if (p == (const PixelPacket *) NULL)
2189 for (x=0; x < (ssize_t) image->columns; x++)
2191 *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
2192 *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
2193 *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
2196 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2197 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2199 if (status == MagickFalse)
2203 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2204 for (y=0; y < (ssize_t) image->rows; y++)
2206 register const PixelPacket
2212 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2213 if (p == (const PixelPacket *) NULL)
2216 for (x=0; x < (ssize_t) image->columns; x++)
2218 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2221 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2222 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2224 if (status == MagickFalse)
2228 for (y=0; y < (ssize_t) image->rows; y++)
2230 register const IndexPacket
2233 register const PixelPacket
2239 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2240 if (p == (const PixelPacket *) NULL)
2243 indexes=GetVirtualIndexQueue(image);
2244 for (x=0; x < (ssize_t) image->columns; x++)
2247 Convert DirectClass packets to contiguous CMYK scanlines.
2249 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2250 GetRedPixelComponent(p))));
2251 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2252 GetGreenPixelComponent(p))));
2253 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2254 GetBluePixelComponent(p))));
2255 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2256 GetIndexPixelComponent(indexes+x))));
2259 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2260 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2262 if (status == MagickFalse)
2267 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2268 for (y=0; y < (ssize_t) image->rows; y++)
2270 register const PixelPacket
2276 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2277 if (p == (const PixelPacket *) NULL)
2280 for (x=0; x < (ssize_t) image->columns; x++)
2282 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2286 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2287 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2289 if (status == MagickFalse)
2293 if ((jpeg_info.in_color_space == JCS_RGB) ||
2294 (jpeg_info.in_color_space == JCS_YCbCr))
2295 for (y=0; y < (ssize_t) image->rows; y++)
2297 register const PixelPacket
2303 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2304 if (p == (const PixelPacket *) NULL)
2307 for (x=0; x < (ssize_t) image->columns; x++)
2309 *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >>
2311 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >>
2313 *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >>
2317 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2318 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2320 if (status == MagickFalse)
2324 for (y=0; y < (ssize_t) image->rows; y++)
2326 register const IndexPacket
2329 register const PixelPacket
2335 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2336 if (p == (const PixelPacket *) NULL)
2339 indexes=GetVirtualIndexQueue(image);
2340 for (x=0; x < (ssize_t) image->columns; x++)
2343 Convert DirectClass packets to contiguous CMYK scanlines.
2345 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2346 GetRedPixelComponent(p)) >> 4));
2347 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2348 GetGreenPixelComponent(p)) >> 4));
2349 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2350 GetBluePixelComponent(p)) >> 4));
2351 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2352 GetIndexPixelComponent(indexes+x)) >> 4));
2355 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2356 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2358 if (status == MagickFalse)
2361 if (y == (ssize_t) image->rows)
2362 jpeg_finish_compress(&jpeg_info);
2364 Relinquish resources.
2366 jpeg_destroy_compress(&jpeg_info);
2367 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2368 (void) CloseBlob(image);