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 "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/utility.h"
82 #if defined(MAGICKCORE_JPEG_DELEGATE)
83 #define JPEG_INTERNAL_OPTIONS
84 #if defined(__MINGW32__)
85 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
86 typedef unsigned char boolean;
97 #define ICC_MARKER (JPEG_APP0+2)
98 #define ICC_PROFILE "ICC_PROFILE"
99 #define IPTC_MARKER (JPEG_APP0+13)
100 #define XML_MARKER (JPEG_APP0+1)
101 #define MaxBufferExtent 8192
104 Typedef declarations.
106 #if defined(MAGICKCORE_JPEG_DELEGATE)
107 typedef struct _DestinationManager
109 struct jpeg_destination_mgr
117 } DestinationManager;
119 typedef struct _ErrorManager
134 typedef struct _SourceManager
136 struct jpeg_source_mgr
151 Forward declarations.
153 #if defined(MAGICKCORE_JPEG_DELEGATE)
154 static MagickBooleanType
155 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 % IsJPEG() returns MagickTrue if the image format type, identified by the
170 % magick string, is JPEG.
172 % The format of the IsJPEG method is:
174 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
176 % A description of each parameter follows:
178 % o magick: compare image format pattern against these bytes.
180 % o length: Specifies the length of the magick string.
183 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
187 if (memcmp(magick,"\377\330\377",3) == 0)
192 #if defined(MAGICKCORE_JPEG_DELEGATE)
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % R e a d J P E G I m a g e %
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
205 % the memory necessary for the new Image structure and returns a pointer to
208 % The format of the ReadJPEGImage method is:
210 % Image *ReadJPEGImage(const ImageInfo *image_info,
211 % ExceptionInfo *exception)
213 % A description of each parameter follows:
215 % o image_info: the image info.
217 % o exception: return any errors or warnings in this structure.
221 static boolean FillInputBuffer(j_decompress_ptr cinfo)
226 source=(SourceManager *) cinfo->src;
227 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
228 MaxBufferExtent,source->buffer);
229 if (source->manager.bytes_in_buffer == 0)
231 if (source->start_of_blob != 0)
232 ERREXIT(cinfo,JERR_INPUT_EMPTY);
233 WARNMS(cinfo,JWRN_JPEG_EOF);
234 source->buffer[0]=(JOCTET) 0xff;
235 source->buffer[1]=(JOCTET) JPEG_EOI;
236 source->manager.bytes_in_buffer=2;
238 source->manager.next_input_byte=source->buffer;
239 source->start_of_blob=FALSE;
243 static int GetCharacter(j_decompress_ptr jpeg_info)
245 if (jpeg_info->src->bytes_in_buffer == 0)
246 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
247 jpeg_info->src->bytes_in_buffer--;
248 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
251 static void InitializeSource(j_decompress_ptr cinfo)
256 source=(SourceManager *) cinfo->src;
257 source->start_of_blob=TRUE;
260 static MagickBooleanType IsITUFaxImage(const Image *image)
268 profile=GetImageProfile(image,"8bim");
269 if (profile == (const StringInfo *) NULL)
271 if (GetStringInfoLength(profile) < 5)
273 datum=GetStringInfoDatum(profile);
274 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
275 (datum[3] == 0x41) && (datum[4] == 0x58))
280 static void JPEGErrorHandler(j_common_ptr jpeg_info)
283 message[JMSG_LENGTH_MAX];
292 error_manager=(ErrorManager *) jpeg_info->client_data;
293 image=error_manager->image;
294 (jpeg_info->err->format_message)(jpeg_info,message);
295 if (image->debug != MagickFalse)
296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
297 "[%s] JPEG Trace: \"%s\"",image->filename,message);
298 if (error_manager->finished != MagickFalse)
299 (void) ThrowMagickException(&image->exception,GetMagickModule(),
300 CorruptImageWarning,(char *) message,"`%s'",image->filename);
302 (void) ThrowMagickException(&image->exception,GetMagickModule(),
303 CorruptImageError,(char *) message,"`%s'",image->filename);
304 longjmp(error_manager->error_recovery,1);
307 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
310 message[JMSG_LENGTH_MAX];
322 error_manager=(ErrorManager *) jpeg_info->client_data;
323 exception=error_manager->exception;
324 image=error_manager->image;
328 Process warning message.
330 (jpeg_info->err->format_message)(jpeg_info,message);
331 if ((jpeg_info->err->num_warnings == 0) ||
332 (jpeg_info->err->trace_level >= 3))
333 ThrowBinaryException(CorruptImageWarning,(char *) message,
335 jpeg_info->err->num_warnings++;
338 if ((image->debug != MagickFalse) &&
339 (level >= jpeg_info->err->trace_level))
342 Process trace message.
344 (jpeg_info->err->format_message)(jpeg_info,message);
345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
346 "[%s] JPEG Trace: \"%s\"",image->filename,message);
351 static boolean ReadComment(j_decompress_ptr jpeg_info)
375 Determine length of comment.
377 error_manager=(ErrorManager *) jpeg_info->client_data;
378 exception=error_manager->exception;
379 image=error_manager->image;
380 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
381 length+=GetCharacter(jpeg_info);
385 comment=(char *) NULL;
386 if (~length >= (MaxTextExtent-1))
387 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
389 if (comment == (char *) NULL)
390 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
395 i=(ssize_t) length-1;
396 for (p=comment; i-- >= 0; p++)
397 *p=(char) GetCharacter(jpeg_info);
399 (void) SetImageProperty(image,"comment",comment);
400 comment=DestroyString(comment);
404 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
424 register unsigned char
437 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
438 length+=(size_t) GetCharacter(jpeg_info);
443 (void) GetCharacter(jpeg_info);
446 for (i=0; i < 12; i++)
447 magick[i]=(char) GetCharacter(jpeg_info);
448 if (LocaleCompare(magick,ICC_PROFILE) != 0)
451 Not a ICC profile, return.
453 for (i=0; i < (ssize_t) (length-12); i++)
454 (void) GetCharacter(jpeg_info);
457 (void) GetCharacter(jpeg_info); /* id */
458 (void) GetCharacter(jpeg_info); /* markers */
460 error_manager=(ErrorManager *) jpeg_info->client_data;
461 exception=error_manager->exception;
462 image=error_manager->image;
463 profile=BlobToStringInfo((const void *) NULL,length);
464 if (profile == (StringInfo *) NULL)
465 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
467 p=GetStringInfoDatum(profile);
468 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
469 *p++=(unsigned char) GetCharacter(jpeg_info);
470 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
471 if (icc_profile != (StringInfo *) NULL)
473 ConcatenateStringInfo(icc_profile,profile);
474 profile=DestroyStringInfo(profile);
478 status=SetImageProfile(image,"icc",profile);
479 profile=DestroyStringInfo(profile);
480 if (status == MagickFalse)
481 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
484 if (image->debug != MagickFalse)
485 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
486 "Profile: ICC, %.20g bytes",(double) length);
490 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
493 magick[MaxTextExtent];
510 register unsigned char
521 Determine length of binary data stored here.
523 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
524 length+=(size_t) GetCharacter(jpeg_info);
529 (void) GetCharacter(jpeg_info);
533 Validate that this was written as a Photoshop resource format slug.
535 for (i=0; i < 10; i++)
536 magick[i]=(char) GetCharacter(jpeg_info);
541 if (LocaleCompare(magick,"Photoshop ") != 0)
544 Not a IPTC profile, return.
546 for (i=0; i < (ssize_t) length; i++)
547 (void) GetCharacter(jpeg_info);
551 Remove the version number.
553 for (i=0; i < 4; i++)
554 (void) GetCharacter(jpeg_info);
560 error_manager=(ErrorManager *) jpeg_info->client_data;
561 exception=error_manager->exception;
562 image=error_manager->image;
563 profile=BlobToStringInfo((const void *) NULL,length);
564 if (profile == (StringInfo *) NULL)
565 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
567 p=GetStringInfoDatum(profile);
568 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
569 *p++=(unsigned char) GetCharacter(jpeg_info);
570 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
571 if (iptc_profile != (StringInfo *) NULL)
573 ConcatenateStringInfo(iptc_profile,profile);
574 profile=DestroyStringInfo(profile);
578 status=SetImageProfile(image,"8bim",profile);
579 profile=DestroyStringInfo(profile);
580 if (status == MagickFalse)
581 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
584 if (image->debug != MagickFalse)
585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
586 "Profile: iptc, %.20g bytes",(double) length);
590 static boolean ReadProfile(j_decompress_ptr jpeg_info)
616 register unsigned char
626 Read generic profile.
628 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
629 length+=(size_t) GetCharacter(jpeg_info);
633 marker=jpeg_info->unread_marker-JPEG_APP0;
634 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
635 error_manager=(ErrorManager *) jpeg_info->client_data;
636 exception=error_manager->exception;
637 image=error_manager->image;
638 profile=BlobToStringInfo((const void *) NULL,length);
639 if (profile == (StringInfo *) NULL)
640 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
642 p=GetStringInfoDatum(profile);
643 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
644 *p++=(unsigned char) GetCharacter(jpeg_info);
647 p=GetStringInfoDatum(profile);
648 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
649 (void) CopyMagickString(name,"exif",MaxTextExtent);
650 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
656 Extract namespace from XMP profile.
658 p=GetStringInfoDatum(profile);
659 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
665 if (j < (ssize_t) GetStringInfoLength(profile))
666 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
667 (void) CopyMagickString(name,"xmp",MaxTextExtent);
670 previous_profile=GetImageProfile(image,name);
671 if (previous_profile != (const StringInfo *) NULL)
676 length=GetStringInfoLength(profile);
677 SetStringInfoLength(profile,GetStringInfoLength(profile)+
678 GetStringInfoLength(previous_profile));
679 (void) memmove(GetStringInfoDatum(profile)+
680 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
682 (void) memcpy(GetStringInfoDatum(profile),
683 GetStringInfoDatum(previous_profile),
684 GetStringInfoLength(previous_profile));
686 status=SetImageProfile(image,name,profile);
687 profile=DestroyStringInfo(profile);
688 if (status == MagickFalse)
689 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
691 if (image->debug != MagickFalse)
692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
693 "Profile: %s, %.20g bytes",name,(double) length);
697 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
702 if (number_bytes <= 0)
704 source=(SourceManager *) cinfo->src;
705 while (number_bytes > (long) source->manager.bytes_in_buffer)
707 number_bytes-=(long) source->manager.bytes_in_buffer;
708 (void) FillInputBuffer(cinfo);
710 source->manager.next_input_byte+=number_bytes;
711 source->manager.bytes_in_buffer-=number_bytes;
714 static void TerminateSource(j_decompress_ptr cinfo)
719 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
724 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
725 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
726 source=(SourceManager *) cinfo->src;
727 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
728 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
729 source=(SourceManager *) cinfo->src;
730 source->manager.init_source=InitializeSource;
731 source->manager.fill_input_buffer=FillInputBuffer;
732 source->manager.skip_input_data=SkipInputData;
733 source->manager.resync_to_restart=jpeg_resync_to_restart;
734 source->manager.term_source=TerminateSource;
735 source->manager.bytes_in_buffer=0;
736 source->manager.next_input_byte=NULL;
740 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
743 image->quality=UndefinedCompressionQuality;
744 #if defined(D_PROGRESSIVE_SUPPORTED)
745 if (image->compression == LosslessJPEGCompression)
748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
749 "Quality: 100 (lossless)");
763 Determine the JPEG compression quality from the quantization tables.
766 for (i=0; i < NUM_QUANT_TBLS; i++)
768 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
769 for (j=0; j < DCTSIZE2; j++)
770 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
772 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
773 (jpeg_info->quant_tbl_ptrs[1] != NULL))
778 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
779 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
780 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
781 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
782 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
783 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
784 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
785 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
786 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
787 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
792 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
793 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
794 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
795 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
796 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
797 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
798 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
799 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
800 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
801 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
802 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
806 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
807 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
808 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
809 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
810 for (i=0; i < 100; i++)
812 if ((qvalue < hash[i]) && (sum < sums[i]))
814 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
815 image->quality=(size_t) i+1;
816 if (image->debug != MagickFalse)
817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
818 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
819 (sum <= sums[i]) ? "exact" : "approximate");
824 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
829 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
830 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
831 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
832 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
833 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
834 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
835 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
836 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
837 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
838 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
843 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
844 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
845 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
846 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
847 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
848 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
849 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
850 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
851 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
852 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
853 667, 592, 518, 441, 369, 292, 221, 151, 86,
857 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
858 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
859 for (i=0; i < 100; i++)
861 if ((qvalue < hash[i]) && (sum < sums[i]))
863 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
864 image->quality=(size_t) i+1;
865 if (image->debug != MagickFalse)
866 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
867 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
868 (sum <= sums[i]) ? "exact" : "approximate");
875 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
878 sampling_factor[MaxTextExtent];
880 switch (jpeg_info->out_color_space)
884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
885 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
886 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
887 jpeg_info->comp_info[0].v_samp_factor,
888 jpeg_info->comp_info[1].h_samp_factor,
889 jpeg_info->comp_info[1].v_samp_factor,
890 jpeg_info->comp_info[2].h_samp_factor,
891 jpeg_info->comp_info[2].v_samp_factor,
892 jpeg_info->comp_info[3].h_samp_factor,
893 jpeg_info->comp_info[3].v_samp_factor);
898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
899 "Colorspace: GRAYSCALE");
900 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
901 jpeg_info->comp_info[0].h_samp_factor,
902 jpeg_info->comp_info[0].v_samp_factor);
907 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
908 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
909 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
910 jpeg_info->comp_info[0].v_samp_factor,
911 jpeg_info->comp_info[1].h_samp_factor,
912 jpeg_info->comp_info[1].v_samp_factor,
913 jpeg_info->comp_info[2].h_samp_factor,
914 jpeg_info->comp_info[2].v_samp_factor);
919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
920 jpeg_info->out_color_space);
921 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
922 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
923 jpeg_info->comp_info[0].v_samp_factor,
924 jpeg_info->comp_info[1].h_samp_factor,
925 jpeg_info->comp_info[1].v_samp_factor,
926 jpeg_info->comp_info[2].h_samp_factor,
927 jpeg_info->comp_info[2].v_samp_factor,
928 jpeg_info->comp_info[3].h_samp_factor,
929 jpeg_info->comp_info[3].v_samp_factor);
933 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
938 static Image *ReadJPEGImage(const ImageInfo *image_info,
939 ExceptionInfo *exception)
942 value[MaxTextExtent];
972 struct jpeg_decompress_struct
975 struct jpeg_error_mgr
991 assert(image_info != (const ImageInfo *) NULL);
992 assert(image_info->signature == MagickSignature);
993 if (image_info->debug != MagickFalse)
994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
995 image_info->filename);
996 assert(exception != (ExceptionInfo *) NULL);
997 assert(exception->signature == MagickSignature);
998 debug=IsEventLogging();
1000 image=AcquireImage(image_info,exception);
1001 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1002 if (status == MagickFalse)
1004 image=DestroyImageList(image);
1005 return((Image *) NULL);
1008 Initialize JPEG parameters.
1010 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1011 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1012 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1013 jpeg_info.err=jpeg_std_error(&jpeg_error);
1014 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1015 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1016 jpeg_pixels=(JSAMPLE *) NULL;
1017 error_manager.exception=exception;
1018 error_manager.image=image;
1019 if (setjmp(error_manager.error_recovery) != 0)
1021 jpeg_destroy_decompress(&jpeg_info);
1022 (void) CloseBlob(image);
1023 number_pixels=(MagickSizeType) image->columns*image->rows;
1024 if (number_pixels != 0)
1025 return(GetFirstImageInList(image));
1026 InheritException(exception,&image->exception);
1027 return(DestroyImage(image));
1029 jpeg_info.client_data=(void *) &error_manager;
1030 jpeg_create_decompress(&jpeg_info);
1031 JPEGSourceManager(&jpeg_info,image);
1032 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1033 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1034 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1035 for (i=1; i < 16; i++)
1036 if ((i != 2) && (i != 13) && (i != 14))
1037 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1038 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1039 if ((image_info->colorspace == YCbCrColorspace) ||
1040 (image_info->colorspace == Rec601YCbCrColorspace) ||
1041 (image_info->colorspace == Rec709YCbCrColorspace))
1042 jpeg_info.out_color_space=JCS_YCbCr;
1043 if (IsITUFaxImage(image) != MagickFalse)
1045 image->colorspace=LabColorspace;
1046 jpeg_info.out_color_space=JCS_YCbCr;
1049 if (jpeg_info.out_color_space == JCS_CMYK)
1050 image->colorspace=CMYKColorspace;
1052 Set image resolution.
1055 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1056 (jpeg_info.Y_density != 1))
1058 image->x_resolution=(double) jpeg_info.X_density;
1059 image->y_resolution=(double) jpeg_info.Y_density;
1060 units=(size_t) jpeg_info.density_unit;
1063 image->units=PixelsPerInchResolution;
1065 image->units=PixelsPerCentimeterResolution;
1066 number_pixels=(MagickSizeType) image->columns*image->rows;
1067 option=GetImageOption(image_info,"jpeg:size");
1068 if (option != (const char *) NULL)
1082 flags=ParseGeometry(option,&geometry_info);
1083 if ((flags & SigmaValue) == 0)
1084 geometry_info.sigma=geometry_info.rho;
1085 jpeg_calc_output_dimensions(&jpeg_info);
1086 image->magick_columns=jpeg_info.output_width;
1087 image->magick_rows=jpeg_info.output_height;
1089 if (geometry_info.rho != 0.0)
1090 scale_factor=jpeg_info.output_width/geometry_info.rho;
1091 if ((geometry_info.sigma != 0.0) &&
1092 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1093 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1094 jpeg_info.scale_num=1U;
1095 jpeg_info.scale_denom=(unsigned int) scale_factor;
1096 jpeg_calc_output_dimensions(&jpeg_info);
1097 if (image->debug != MagickFalse)
1098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1099 "Scale factor: %.20g",(double) scale_factor);
1101 precision=(size_t) jpeg_info.data_precision;
1102 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1103 #if defined(D_LOSSLESS_SUPPORTED)
1104 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1105 JPEGInterlace : NoInterlace;
1106 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1107 LosslessJPEGCompression : JPEGCompression;
1108 if (jpeg_info.data_precision > 8)
1109 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1110 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1112 if (jpeg_info.data_precision == 16)
1113 jpeg_info.data_precision=12;
1115 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1117 image->compression=JPEGCompression;
1120 image->compression=JPEGCompression;
1121 image->interlace=JPEGInterlace;
1123 option=GetImageOption(image_info,"jpeg:colors");
1124 if (option != (const char *) NULL)
1126 /* Let the JPEG library quantize the image */
1127 jpeg_info.quantize_colors=MagickTrue;
1128 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1130 option=GetImageOption(image_info,"jpeg:block-smoothing");
1131 if (option != (const char *) NULL)
1133 jpeg_info.do_block_smoothing=MagickFalse;
1134 if (IsMagickTrue(option) != MagickFalse)
1135 jpeg_info.do_block_smoothing=MagickTrue;
1137 option=GetImageOption(image_info,"jpeg:dct-method");
1138 if (option != (const char *) NULL)
1144 if (LocaleCompare(option,"default") == 0)
1145 jpeg_info.dct_method=JDCT_DEFAULT;
1151 if (LocaleCompare(option,"fastest") == 0)
1152 jpeg_info.dct_method=JDCT_FASTEST;
1153 if (LocaleCompare(option,"float") == 0)
1154 jpeg_info.dct_method=JDCT_FLOAT;
1160 if (LocaleCompare(option,"ifast") == 0)
1161 jpeg_info.dct_method=JDCT_IFAST;
1162 if (LocaleCompare(option,"islow") == 0)
1163 jpeg_info.dct_method=JDCT_ISLOW;
1167 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1168 if (option != (const char *) NULL)
1170 jpeg_info.do_fancy_upsampling=MagickFalse;
1171 if (IsMagickTrue(option) != MagickFalse)
1172 jpeg_info.do_fancy_upsampling=MagickTrue;
1174 (void) jpeg_start_decompress(&jpeg_info);
1175 image->columns=jpeg_info.output_width;
1176 image->rows=jpeg_info.output_height;
1177 image->depth=(size_t) jpeg_info.data_precision;
1178 if (jpeg_info.out_color_space == JCS_YCbCr)
1179 image->colorspace=YCbCrColorspace;
1180 if (jpeg_info.out_color_space == JCS_CMYK)
1181 image->colorspace=CMYKColorspace;
1182 option=GetImageOption(image_info,"jpeg:colors");
1183 if (option != (const char *) NULL)
1184 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1186 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1187 if ((jpeg_info.output_components == 1) &&
1188 (jpeg_info.quantize_colors == MagickFalse))
1193 colors=(size_t) GetQuantumRange(image->depth)+1;
1194 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1195 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1197 if (image->debug != MagickFalse)
1199 if (image->interlace != NoInterlace)
1200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1201 "Interlace: progressive");
1203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1204 "Interlace: nonprogressive");
1205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1206 (int) jpeg_info.data_precision);
1207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1208 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1210 JPEGSetImageQuality(&jpeg_info,image);
1211 JPEGSetImageSamplingFactor(&jpeg_info,image);
1212 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1213 jpeg_info.out_color_space);
1214 (void) SetImageProperty(image,"jpeg:colorspace",value);
1215 if (image_info->ping != MagickFalse)
1217 jpeg_destroy_decompress(&jpeg_info);
1218 (void) CloseBlob(image);
1219 return(GetFirstImageInList(image));
1221 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1222 jpeg_info.output_components*sizeof(JSAMPLE));
1223 if (jpeg_pixels == (JSAMPLE *) NULL)
1224 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1226 Convert JPEG pixels to pixel packets.
1228 if (setjmp(error_manager.error_recovery) != 0)
1230 if (jpeg_pixels != (unsigned char *) NULL)
1231 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1232 jpeg_destroy_decompress(&jpeg_info);
1233 (void) CloseBlob(image);
1234 number_pixels=(MagickSizeType) image->columns*image->rows;
1235 if (number_pixels != 0)
1236 return(GetFirstImageInList(image));
1237 return(DestroyImage(image));
1239 if (jpeg_info.quantize_colors != MagickFalse)
1241 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1242 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1243 for (i=0; i < (ssize_t) image->colors; i++)
1245 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1246 image->colormap[i].green=image->colormap[i].red;
1247 image->colormap[i].blue=image->colormap[i].red;
1248 image->colormap[i].alpha=OpaqueAlpha;
1251 for (i=0; i < (ssize_t) image->colors; i++)
1253 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1254 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1255 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1256 image->colormap[i].alpha=OpaqueAlpha;
1259 scanline[0]=(JSAMPROW) jpeg_pixels;
1260 for (y=0; y < (ssize_t) image->rows; y++)
1268 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1270 (void) ThrowMagickException(exception,GetMagickModule(),
1271 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1275 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1276 if (q == (Quantum *) NULL)
1278 if (jpeg_info.data_precision > 8)
1280 if (jpeg_info.output_components == 1)
1281 for (x=0; x < (ssize_t) image->columns; x++)
1286 if (precision != 16)
1287 pixel=(size_t) GETJSAMPLE(*p);
1289 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1290 index=ConstrainColormapIndex(image,pixel);
1291 SetPixelIndex(image,index,q);
1292 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1294 q+=GetPixelChannels(image);
1297 if (image->colorspace != CMYKColorspace)
1298 for (x=0; x < (ssize_t) image->columns; x++)
1300 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1301 (GETJSAMPLE(*p++) << 4)),q);
1302 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1303 (GETJSAMPLE(*p++) << 4)),q);
1304 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1305 (GETJSAMPLE(*p++) << 4)),q);
1306 SetPixelAlpha(image,OpaqueAlpha,q);
1307 q+=GetPixelChannels(image);
1310 for (x=0; x < (ssize_t) image->columns; x++)
1312 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1313 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1314 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1315 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1316 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1317 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1318 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1319 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1320 SetPixelAlpha(image,OpaqueAlpha,q);
1321 q+=GetPixelChannels(image);
1325 if (jpeg_info.output_components == 1)
1326 for (x=0; x < (ssize_t) image->columns; x++)
1328 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1329 SetPixelIndex(image,index,q);
1330 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1332 q+=GetPixelChannels(image);
1335 if (image->colorspace != CMYKColorspace)
1336 for (x=0; x < (ssize_t) image->columns; x++)
1338 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1339 GETJSAMPLE(*p++)),q);
1340 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1341 GETJSAMPLE(*p++)),q);
1342 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1343 GETJSAMPLE(*p++)),q);
1344 SetPixelAlpha(image,OpaqueAlpha,q);
1345 q+=GetPixelChannels(image);
1348 for (x=0; x < (ssize_t) image->columns; x++)
1350 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1351 (unsigned char) GETJSAMPLE(*p++)),q);
1352 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1353 (unsigned char) GETJSAMPLE(*p++)),q);
1354 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1355 (unsigned char) GETJSAMPLE(*p++)),q);
1356 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1357 (unsigned char) GETJSAMPLE(*p++)),q);
1358 SetPixelAlpha(image,OpaqueAlpha,q);
1359 q+=GetPixelChannels(image);
1361 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1363 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1365 if (status == MagickFalse)
1367 jpeg_abort_decompress(&jpeg_info);
1371 if (status != MagickFalse)
1373 error_manager.finished=MagickTrue;
1374 if (setjmp(error_manager.error_recovery) == 0)
1375 (void) jpeg_finish_decompress(&jpeg_info);
1378 Free jpeg resources.
1380 jpeg_destroy_decompress(&jpeg_info);
1381 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1382 (void) CloseBlob(image);
1383 return(GetFirstImageInList(image));
1388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 % R e g i s t e r J P E G I m a g e %
1396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 % RegisterJPEGImage() adds properties for the JPEG image format to
1399 % the list of supported formats. The properties include the image format
1400 % tag, a method to read and/or write the format, whether the format
1401 % supports the saving of more than one frame to the same file or blob,
1402 % whether the format supports native in-memory I/O, and a brief
1403 % description of the format.
1405 % The format of the RegisterJPEGImage method is:
1407 % size_t RegisterJPEGImage(void)
1410 ModuleExport size_t RegisterJPEGImage(void)
1413 version[MaxTextExtent];
1419 description[] = "Joint Photographic Experts Group JFIF format";
1422 #if defined(JPEG_LIB_VERSION)
1423 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1425 entry=SetMagickInfo("JPEG");
1426 entry->thread_support=NoThreadSupport;
1427 #if defined(MAGICKCORE_JPEG_DELEGATE)
1428 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1429 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1431 entry->magick=(IsImageFormatHandler *) IsJPEG;
1432 entry->adjoin=MagickFalse;
1433 entry->description=ConstantString(description);
1434 if (*version != '\0')
1435 entry->version=ConstantString(version);
1436 entry->module=ConstantString("JPEG");
1437 (void) RegisterMagickInfo(entry);
1438 entry=SetMagickInfo("JPG");
1439 entry->thread_support=NoThreadSupport;
1440 #if defined(MAGICKCORE_JPEG_DELEGATE)
1441 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1442 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1444 entry->adjoin=MagickFalse;
1445 entry->description=ConstantString(description);
1446 if (*version != '\0')
1447 entry->version=ConstantString(version);
1448 entry->module=ConstantString("JPEG");
1449 (void) RegisterMagickInfo(entry);
1450 entry=SetMagickInfo("PJPEG");
1451 entry->thread_support=NoThreadSupport;
1452 #if defined(MAGICKCORE_JPEG_DELEGATE)
1453 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1454 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1456 entry->adjoin=MagickFalse;
1457 entry->description=ConstantString(description);
1458 if (*version != '\0')
1459 entry->version=ConstantString(version);
1460 entry->module=ConstantString("JPEG");
1461 (void) RegisterMagickInfo(entry);
1462 return(MagickImageCoderSignature);
1466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470 % U n r e g i s t e r J P E G I m a g e %
1474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476 % UnregisterJPEGImage() removes format registrations made by the
1477 % JPEG module from the list of supported formats.
1479 % The format of the UnregisterJPEGImage method is:
1481 % UnregisterJPEGImage(void)
1484 ModuleExport void UnregisterJPEGImage(void)
1486 (void) UnregisterMagickInfo("PJPG");
1487 (void) UnregisterMagickInfo("JPEG");
1488 (void) UnregisterMagickInfo("JPG");
1491 #if defined(MAGICKCORE_JPEG_DELEGATE)
1493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1497 % W r i t e J P E G I m a g e %
1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503 % WriteJPEGImage() writes a JPEG image file and returns it. It
1504 % allocates the memory necessary for the new Image structure and returns a
1505 % pointer to the new image.
1507 % The format of the WriteJPEGImage method is:
1509 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1510 % Image *image,ExceptionInfo *exception)
1512 % A description of each parameter follows:
1514 % o image_info: the image info.
1516 % o jpeg_image: The image.
1518 % o exception: return any errors or warnings in this structure.
1522 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1527 destination=(DestinationManager *) cinfo->dest;
1528 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1529 MaxBufferExtent,destination->buffer);
1530 if (destination->manager.free_in_buffer != MaxBufferExtent)
1531 ERREXIT(cinfo,JERR_FILE_WRITE);
1532 destination->manager.next_output_byte=destination->buffer;
1536 static void InitializeDestination(j_compress_ptr cinfo)
1541 destination=(DestinationManager *) cinfo->dest;
1542 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1543 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1544 destination->manager.next_output_byte=destination->buffer;
1545 destination->manager.free_in_buffer=MaxBufferExtent;
1548 static inline size_t MagickMin(const size_t x,const size_t y)
1555 static void TerminateDestination(j_compress_ptr cinfo)
1560 destination=(DestinationManager *) cinfo->dest;
1561 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1566 count=WriteBlob(destination->image,MaxBufferExtent-
1567 destination->manager.free_in_buffer,destination->buffer);
1568 if (count != (ssize_t)
1569 (MaxBufferExtent-destination->manager.free_in_buffer))
1570 ERREXIT(cinfo,JERR_FILE_WRITE);
1574 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1596 Save image profile as a APP marker.
1599 custom_profile=AcquireStringInfo(65535L);
1600 ResetImageProfileIterator(image);
1601 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1603 register unsigned char
1606 profile=GetImageProfile(image,name);
1607 p=GetStringInfoDatum(custom_profile);
1608 if (LocaleCompare(name,"EXIF") == 0)
1609 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1611 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1612 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1613 (unsigned int) length);
1615 if (LocaleCompare(name,"ICC") == 0)
1617 register unsigned char
1621 p=GetStringInfoDatum(custom_profile);
1622 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1623 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1625 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1626 p[12]=(unsigned char) ((i/65519L)+1);
1627 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1628 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1630 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1631 custom_profile),(unsigned int) (length+tag_length));
1634 if (((LocaleCompare(name,"IPTC") == 0) ||
1635 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1641 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1643 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1644 roundup=(size_t) (length & 0x01);
1645 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1647 (void) memcpy(p,"Photoshop 3.0 ",14);
1652 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1654 p[24]=(unsigned char) (length >> 8);
1655 p[25]=(unsigned char) (length & 0xff);
1658 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1660 p[length+tag_length]='\0';
1661 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1662 custom_profile),(unsigned int) (length+tag_length+roundup));
1665 if (LocaleCompare(name,"XMP") == 0)
1671 Add namespace to XMP profile.
1673 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1674 ConcatenateStringInfo(xmp_profile,profile);
1675 GetStringInfoDatum(xmp_profile)[28]='\0';
1676 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1678 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1679 jpeg_write_marker(jpeg_info,XML_MARKER,
1680 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1682 xmp_profile=DestroyStringInfo(xmp_profile);
1684 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1685 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1686 name=GetNextImageProfile(image);
1688 custom_profile=DestroyStringInfo(custom_profile);
1691 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1696 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1697 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1698 destination=(DestinationManager *) cinfo->dest;
1699 destination->manager.init_destination=InitializeDestination;
1700 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1701 destination->manager.term_destination=TerminateDestination;
1702 destination->image=image;
1705 static char **SamplingFactorToList(const char *text)
1722 if (text == (char *) NULL)
1723 return((char **) NULL);
1725 Convert string to an ASCII list.
1728 for (p=text; *p != '\0'; p++)
1731 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1733 if (textlist == (char **) NULL)
1734 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1736 for (i=0; i < (ssize_t) lines; i++)
1738 for (q=(char *) p; *q != '\0'; q++)
1741 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1742 sizeof(*textlist[i]));
1743 if (textlist[i] == (char *) NULL)
1744 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1745 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1750 textlist[i]=(char *) NULL;
1754 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1755 Image *image,ExceptionInfo *exception)
1783 struct jpeg_compress_struct
1786 struct jpeg_error_mgr
1792 assert(image_info != (const ImageInfo *) NULL);
1793 assert(image_info->signature == MagickSignature);
1794 assert(image != (Image *) NULL);
1795 assert(image->signature == MagickSignature);
1796 if (image->debug != MagickFalse)
1797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1798 assert(exception != (ExceptionInfo *) NULL);
1799 assert(exception->signature == MagickSignature);
1800 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1801 if (status == MagickFalse)
1804 Initialize JPEG parameters.
1806 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1807 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1808 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1809 jpeg_info.client_data=(void *) image;
1810 jpeg_info.err=jpeg_std_error(&jpeg_error);
1811 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1812 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1813 error_manager.exception=exception;
1814 error_manager.image=image;
1815 jpeg_pixels=(JSAMPLE *) NULL;
1816 if (setjmp(error_manager.error_recovery) != 0)
1818 jpeg_destroy_compress(&jpeg_info);
1819 (void) CloseBlob(image);
1820 return(MagickFalse);
1822 jpeg_info.client_data=(void *) &error_manager;
1823 jpeg_create_compress(&jpeg_info);
1824 JPEGDestinationManager(&jpeg_info,image);
1825 if ((image->columns != (unsigned int) image->columns) ||
1826 (image->rows != (unsigned int) image->rows))
1827 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1828 jpeg_info.image_width=(unsigned int) image->columns;
1829 jpeg_info.image_height=(unsigned int) image->rows;
1830 jpeg_info.input_components=3;
1831 jpeg_info.data_precision=8;
1832 jpeg_info.in_color_space=JCS_RGB;
1833 switch (image->colorspace)
1835 case CMYKColorspace:
1837 jpeg_info.input_components=4;
1838 jpeg_info.in_color_space=JCS_CMYK;
1841 case YCbCrColorspace:
1842 case Rec601YCbCrColorspace:
1843 case Rec709YCbCrColorspace:
1845 jpeg_info.in_color_space=JCS_YCbCr;
1848 case GRAYColorspace:
1849 case Rec601LumaColorspace:
1850 case Rec709LumaColorspace:
1852 jpeg_info.input_components=1;
1853 jpeg_info.in_color_space=JCS_GRAYSCALE;
1858 if (IsRGBColorspace(image->colorspace) == MagickFalse)
1859 (void) TransformImageColorspace(image,RGBColorspace);
1863 if ((image_info->type != TrueColorType) &&
1864 (IsImageGray(image,exception) != MagickFalse))
1866 jpeg_info.input_components=1;
1867 jpeg_info.in_color_space=JCS_GRAYSCALE;
1869 jpeg_set_defaults(&jpeg_info);
1870 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1871 jpeg_info.data_precision=8;
1873 if (sizeof(JSAMPLE) > 1)
1874 jpeg_info.data_precision=12;
1875 jpeg_info.density_unit=(UINT8) 1;
1876 if (image->debug != MagickFalse)
1877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1878 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1879 floor(image->y_resolution+0.5));
1880 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1883 Set image resolution.
1885 jpeg_info.write_JFIF_header=MagickTrue;
1886 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1887 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1888 if (image->units == PixelsPerInchResolution)
1889 jpeg_info.density_unit=(UINT8) 1;
1890 if (image->units == PixelsPerCentimeterResolution)
1891 jpeg_info.density_unit=(UINT8) 2;
1893 option=GetImageOption(image_info,"jpeg:dct-method");
1894 if (option != (const char *) NULL)
1900 if (LocaleCompare(option,"default") == 0)
1901 jpeg_info.dct_method=JDCT_DEFAULT;
1907 if (LocaleCompare(option,"fastest") == 0)
1908 jpeg_info.dct_method=JDCT_FASTEST;
1909 if (LocaleCompare(option,"float") == 0)
1910 jpeg_info.dct_method=JDCT_FLOAT;
1916 if (LocaleCompare(option,"ifast") == 0)
1917 jpeg_info.dct_method=JDCT_IFAST;
1918 if (LocaleCompare(option,"islow") == 0)
1919 jpeg_info.dct_method=JDCT_ISLOW;
1923 option=GetImageOption(image_info,"jpeg:optimize-coding");
1924 if (option != (const char *) NULL)
1926 jpeg_info.optimize_coding=MagickFalse;
1927 if (IsMagickTrue(option) != MagickFalse)
1928 jpeg_info.optimize_coding=MagickTrue;
1935 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1936 image->rows*sizeof(JSAMPLE);
1937 if (length == (MagickSizeType) ((size_t) length))
1940 Perform optimization only if available memory resources permit it.
1942 status=AcquireMagickResource(MemoryResource,length);
1943 if (status != MagickFalse)
1944 jpeg_info.optimize_coding=MagickTrue;
1945 RelinquishMagickResource(MemoryResource,length);
1948 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1949 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1950 (image_info->interlace != NoInterlace))
1952 if (image->debug != MagickFalse)
1953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1954 "Interlace: progressive");
1955 jpeg_simple_progression(&jpeg_info);
1958 if (image->debug != MagickFalse)
1959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1960 "Interlace: non-progressive");
1962 if (image->debug != MagickFalse)
1963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1964 "Interlace: nonprogressive");
1966 option=GetImageOption(image_info,"jpeg:extent");
1967 if (option != (const char *) NULL)
1975 jpeg_info=CloneImageInfo(image_info);
1976 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1977 if (jpeg_image != (Image *) NULL)
1987 Search for compression quality that does not exceed image extent.
1989 jpeg_info->quality=0;
1990 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1991 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1992 (void) AcquireUniqueFilename(jpeg_image->filename);
1994 for (minimum=0; minimum != maximum; )
1996 jpeg_image->quality=minimum+(maximum-minimum)/2;
1997 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
1998 if (GetBlobSize(jpeg_image) <= extent)
1999 minimum=jpeg_image->quality+1;
2001 maximum=jpeg_image->quality-1;
2003 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2004 image->quality=minimum-1;
2005 jpeg_image=DestroyImage(jpeg_image);
2007 jpeg_info=DestroyImageInfo(jpeg_info);
2009 if ((image_info->compression != LosslessJPEGCompression) &&
2010 (image->quality <= 100))
2012 if (image->quality == UndefinedCompressionQuality)
2013 jpeg_set_quality(&jpeg_info,92,MagickTrue);
2015 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
2016 if (image->debug != MagickFalse)
2017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2018 (double) image->quality);
2022 #if !defined(C_LOSSLESS_SUPPORTED)
2023 jpeg_set_quality(&jpeg_info,100,MagickTrue);
2024 if (image->debug != MagickFalse)
2025 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2027 if (image->quality < 100)
2028 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2029 "LosslessToLossyJPEGConversion",image->filename);
2036 predictor=image->quality/100; /* range 1-7 */
2037 point_transform=image->quality % 20; /* range 0-15 */
2038 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2039 if (image->debug != MagickFalse)
2041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2042 "Compression: lossless");
2043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2044 "Predictor: %d",predictor);
2045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2046 "Point Transform: %d",point_transform);
2051 sampling_factor=(const char *) NULL;
2052 value=GetImageProperty(image,"jpeg:sampling-factor");
2053 if (value != (char *) NULL)
2055 sampling_factor=value;
2056 if (image->debug != MagickFalse)
2057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2058 " Input sampling-factors=%s",sampling_factor);
2060 if (image_info->sampling_factor != (char *) NULL)
2061 sampling_factor=image_info->sampling_factor;
2062 if (sampling_factor == (const char *) NULL)
2064 if (image->quality >= 90)
2065 for (i=0; i < MAX_COMPONENTS; i++)
2067 jpeg_info.comp_info[i].h_samp_factor=1;
2068 jpeg_info.comp_info[i].v_samp_factor=1;
2083 Set sampling factor.
2086 factors=SamplingFactorToList(sampling_factor);
2087 if (factors != (char **) NULL)
2089 for (i=0; i < MAX_COMPONENTS; i++)
2091 if (factors[i] == (char *) NULL)
2093 flags=ParseGeometry(factors[i],&geometry_info);
2094 if ((flags & SigmaValue) == 0)
2095 geometry_info.sigma=geometry_info.rho;
2096 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2097 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2098 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2100 factors=(char **) RelinquishMagickMemory(factors);
2102 for ( ; i < MAX_COMPONENTS; i++)
2104 jpeg_info.comp_info[i].h_samp_factor=1;
2105 jpeg_info.comp_info[i].v_samp_factor=1;
2108 if (jpeg_info.input_components == 1)
2109 for (i=0; i < MAX_COMPONENTS; i++)
2111 jpeg_info.comp_info[i].h_samp_factor=1;
2112 jpeg_info.comp_info[i].v_samp_factor=1;
2114 jpeg_start_compress(&jpeg_info,MagickTrue);
2115 if (image->debug != MagickFalse)
2117 if (image->storage_class == PseudoClass)
2118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2119 "Storage class: PseudoClass");
2121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2122 "Storage class: DirectClass");
2123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2124 (double) image->depth);
2125 if (image->colors != 0)
2126 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2127 "Number of colors: %.20g",(double) image->colors);
2129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2130 "Number of colors: unspecified");
2131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2132 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2133 switch (image->colorspace)
2135 case CMYKColorspace:
2137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2138 "Storage class: DirectClass");
2139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2140 "Colorspace: CMYK");
2143 case YCbCrColorspace:
2144 case Rec601YCbCrColorspace:
2145 case Rec709YCbCrColorspace:
2147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2148 "Colorspace: YCbCr");
2154 switch (image->colorspace)
2156 case CMYKColorspace:
2158 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2159 "Colorspace: CMYK");
2160 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2161 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2162 jpeg_info.comp_info[0].h_samp_factor,
2163 jpeg_info.comp_info[0].v_samp_factor,
2164 jpeg_info.comp_info[1].h_samp_factor,
2165 jpeg_info.comp_info[1].v_samp_factor,
2166 jpeg_info.comp_info[2].h_samp_factor,
2167 jpeg_info.comp_info[2].v_samp_factor,
2168 jpeg_info.comp_info[3].h_samp_factor,
2169 jpeg_info.comp_info[3].v_samp_factor);
2172 case GRAYColorspace:
2173 case Rec601LumaColorspace:
2174 case Rec709LumaColorspace:
2176 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2177 "Colorspace: GRAY");
2178 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2179 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2180 jpeg_info.comp_info[0].v_samp_factor);
2185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2186 "Image colorspace is RGB");
2187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2188 "Sampling factors: %dx%d,%dx%d,%dx%d",
2189 jpeg_info.comp_info[0].h_samp_factor,
2190 jpeg_info.comp_info[0].v_samp_factor,
2191 jpeg_info.comp_info[1].h_samp_factor,
2192 jpeg_info.comp_info[1].v_samp_factor,
2193 jpeg_info.comp_info[2].h_samp_factor,
2194 jpeg_info.comp_info[2].v_samp_factor);
2197 case YCbCrColorspace:
2198 case Rec601YCbCrColorspace:
2199 case Rec709YCbCrColorspace:
2201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2202 "Colorspace: YCbCr");
2203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2204 "Sampling factors: %dx%d,%dx%d,%dx%d",
2205 jpeg_info.comp_info[0].h_samp_factor,
2206 jpeg_info.comp_info[0].v_samp_factor,
2207 jpeg_info.comp_info[1].h_samp_factor,
2208 jpeg_info.comp_info[1].v_samp_factor,
2209 jpeg_info.comp_info[2].h_samp_factor,
2210 jpeg_info.comp_info[2].v_samp_factor);
2215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2217 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2218 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2219 jpeg_info.comp_info[0].h_samp_factor,
2220 jpeg_info.comp_info[0].v_samp_factor,
2221 jpeg_info.comp_info[1].h_samp_factor,
2222 jpeg_info.comp_info[1].v_samp_factor,
2223 jpeg_info.comp_info[2].h_samp_factor,
2224 jpeg_info.comp_info[2].v_samp_factor,
2225 jpeg_info.comp_info[3].h_samp_factor,
2226 jpeg_info.comp_info[3].v_samp_factor);
2232 Write JPEG profiles.
2234 value=GetImageProperty(image,"comment");
2235 if (value != (char *) NULL)
2236 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2237 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2238 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2239 if (image->profiles != (void *) NULL)
2240 WriteProfile(&jpeg_info,image);
2242 Convert MIFF to JPEG raster pixels.
2244 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2245 jpeg_info.input_components*sizeof(*jpeg_pixels));
2246 if (jpeg_pixels == (JSAMPLE *) NULL)
2247 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2248 if (setjmp(error_manager.error_recovery) != 0)
2250 jpeg_destroy_compress(&jpeg_info);
2251 if (jpeg_pixels != (unsigned char *) NULL)
2252 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2253 (void) CloseBlob(image);
2254 return(MagickFalse);
2256 scanline[0]=(JSAMPROW) jpeg_pixels;
2257 if (jpeg_info.data_precision <= 8)
2259 if ((jpeg_info.in_color_space == JCS_RGB) ||
2260 (jpeg_info.in_color_space == JCS_YCbCr))
2261 for (y=0; y < (ssize_t) image->rows; y++)
2263 register const Quantum
2269 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2270 if (p == (const Quantum *) NULL)
2273 for (x=0; x < (ssize_t) image->columns; x++)
2275 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2276 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2277 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2278 p+=GetPixelChannels(image);
2280 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2281 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2283 if (status == MagickFalse)
2287 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2288 for (y=0; y < (ssize_t) image->rows; y++)
2290 register const Quantum
2296 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2297 if (p == (const Quantum *) NULL)
2300 for (x=0; x < (ssize_t) image->columns; x++)
2302 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2303 p+=GetPixelChannels(image);
2305 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2306 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2308 if (status == MagickFalse)
2312 for (y=0; y < (ssize_t) image->rows; y++)
2314 register const Quantum
2320 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2321 if (p == (const Quantum *) NULL)
2324 for (x=0; x < (ssize_t) image->columns; x++)
2327 Convert DirectClass packets to contiguous CMYK scanlines.
2329 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2330 GetPixelRed(image,p))));
2331 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2332 GetPixelGreen(image,p))));
2333 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2334 GetPixelBlue(image,p))));
2335 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2336 GetPixelBlack(image,p))));
2337 p+=GetPixelChannels(image);
2339 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2340 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2342 if (status == MagickFalse)
2347 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2348 for (y=0; y < (ssize_t) image->rows; y++)
2350 register const Quantum
2356 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2357 if (p == (const Quantum *) NULL)
2360 for (x=0; x < (ssize_t) image->columns; x++)
2362 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2364 p+=GetPixelChannels(image);
2366 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2367 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2369 if (status == MagickFalse)
2373 if ((jpeg_info.in_color_space == JCS_RGB) ||
2374 (jpeg_info.in_color_space == JCS_YCbCr))
2375 for (y=0; y < (ssize_t) image->rows; y++)
2377 register const Quantum
2383 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2384 if (p == (const Quantum *) NULL)
2387 for (x=0; x < (ssize_t) image->columns; x++)
2389 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2390 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2391 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2392 p+=GetPixelChannels(image);
2394 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2395 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2397 if (status == MagickFalse)
2401 for (y=0; y < (ssize_t) image->rows; y++)
2403 register const Quantum
2409 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2410 if (p == (const Quantum *) NULL)
2413 for (x=0; x < (ssize_t) image->columns; x++)
2416 Convert DirectClass packets to contiguous CMYK scanlines.
2418 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2419 GetPixelRed(image,p)) >> 4));
2420 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2421 GetPixelGreen(image,p)) >> 4));
2422 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2423 GetPixelBlue(image,p)) >> 4));
2424 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2425 GetPixelBlack(image,p)) >> 4));
2426 p+=GetPixelChannels(image);
2428 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2429 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2431 if (status == MagickFalse)
2434 if (y == (ssize_t) image->rows)
2435 jpeg_finish_compress(&jpeg_info);
2437 Relinquish resources.
2439 jpeg_destroy_compress(&jpeg_info);
2440 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2441 (void) CloseBlob(image);