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 MagickBooleanType 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 if ((image_info->colors > 8) && (image_info->colors <= 256))
1126 Let the JPEG library quantize for us.
1128 jpeg_info.quantize_colors=MagickTrue;
1129 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1131 option=GetImageOption(image_info,"jpeg:block-smoothing");
1132 if (option != (const char *) NULL)
1134 jpeg_info.do_block_smoothing=MagickFalse;
1135 if (IsMagickTrue(option) != MagickFalse)
1136 jpeg_info.do_block_smoothing=MagickTrue;
1138 option=GetImageOption(image_info,"jpeg:dct-method");
1139 if (option != (const char *) NULL)
1145 if (LocaleCompare(option,"default") == 0)
1146 jpeg_info.dct_method=JDCT_DEFAULT;
1152 if (LocaleCompare(option,"fastest") == 0)
1153 jpeg_info.dct_method=JDCT_FASTEST;
1154 if (LocaleCompare(option,"float") == 0)
1155 jpeg_info.dct_method=JDCT_FLOAT;
1161 if (LocaleCompare(option,"ifast") == 0)
1162 jpeg_info.dct_method=JDCT_IFAST;
1163 if (LocaleCompare(option,"islow") == 0)
1164 jpeg_info.dct_method=JDCT_ISLOW;
1168 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1169 if (option != (const char *) NULL)
1171 jpeg_info.do_fancy_upsampling=MagickFalse;
1172 if (IsMagickTrue(option) != MagickFalse)
1173 jpeg_info.do_fancy_upsampling=MagickTrue;
1175 (void) jpeg_start_decompress(&jpeg_info);
1176 image->columns=jpeg_info.output_width;
1177 image->rows=jpeg_info.output_height;
1178 image->depth=(size_t) jpeg_info.data_precision;
1179 if (jpeg_info.out_color_space == JCS_YCbCr)
1180 image->colorspace=YCbCrColorspace;
1181 if (jpeg_info.out_color_space == JCS_CMYK)
1182 image->colorspace=CMYKColorspace;
1183 if ((image_info->colors != 0) && (image_info->colors <= 256))
1184 if (AcquireImageColormap(image,image_info->colors,exception) == MagickFalse)
1185 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1186 if ((jpeg_info.output_components == 1) &&
1187 (jpeg_info.quantize_colors == MagickFalse))
1192 colors=(size_t) GetQuantumRange(image->depth)+1;
1193 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1194 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1196 if (image->debug != MagickFalse)
1198 if (image->interlace != NoInterlace)
1199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1200 "Interlace: progressive");
1202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1203 "Interlace: nonprogressive");
1204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1205 (int) jpeg_info.data_precision);
1206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1207 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1209 JPEGSetImageQuality(&jpeg_info,image);
1210 JPEGSetImageSamplingFactor(&jpeg_info,image);
1211 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1212 jpeg_info.out_color_space);
1213 (void) SetImageProperty(image,"jpeg:colorspace",value);
1214 if (image_info->ping != MagickFalse)
1216 jpeg_destroy_decompress(&jpeg_info);
1217 (void) CloseBlob(image);
1218 return(GetFirstImageInList(image));
1220 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1221 jpeg_info.output_components*sizeof(JSAMPLE));
1222 if (jpeg_pixels == (JSAMPLE *) NULL)
1223 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1225 Convert JPEG pixels to pixel packets.
1227 if (setjmp(error_manager.error_recovery) != 0)
1229 if (jpeg_pixels != (unsigned char *) NULL)
1230 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1231 jpeg_destroy_decompress(&jpeg_info);
1232 (void) CloseBlob(image);
1233 number_pixels=(MagickSizeType) image->columns*image->rows;
1234 if (number_pixels != 0)
1235 return(GetFirstImageInList(image));
1236 return(DestroyImage(image));
1238 if (jpeg_info.quantize_colors != MagickFalse)
1240 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1241 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1242 for (i=0; i < (ssize_t) image->colors; i++)
1244 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1245 image->colormap[i].green=image->colormap[i].red;
1246 image->colormap[i].blue=image->colormap[i].red;
1247 image->colormap[i].alpha=OpaqueAlpha;
1250 for (i=0; i < (ssize_t) image->colors; i++)
1252 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1253 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1254 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1255 image->colormap[i].alpha=OpaqueAlpha;
1258 scanline[0]=(JSAMPROW) jpeg_pixels;
1259 for (y=0; y < (ssize_t) image->rows; y++)
1267 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1269 (void) ThrowMagickException(exception,GetMagickModule(),
1270 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1274 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1275 if (q == (Quantum *) NULL)
1277 if (jpeg_info.data_precision > 8)
1279 if (jpeg_info.output_components == 1)
1280 for (x=0; x < (ssize_t) image->columns; x++)
1285 if (precision != 16)
1286 pixel=(size_t) GETJSAMPLE(*p);
1288 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1289 index=ConstrainColormapIndex(image,pixel);
1290 SetPixelIndex(image,index,q);
1291 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1293 q+=GetPixelChannels(image);
1296 if (image->colorspace != CMYKColorspace)
1297 for (x=0; x < (ssize_t) image->columns; x++)
1299 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1300 (GETJSAMPLE(*p++) << 4)),q);
1301 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1302 (GETJSAMPLE(*p++) << 4)),q);
1303 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1304 (GETJSAMPLE(*p++) << 4)),q);
1305 SetPixelAlpha(image,OpaqueAlpha,q);
1306 q+=GetPixelChannels(image);
1309 for (x=0; x < (ssize_t) image->columns; x++)
1311 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1312 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1313 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1314 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1315 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1316 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1317 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1318 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1319 SetPixelAlpha(image,OpaqueAlpha,q);
1320 q+=GetPixelChannels(image);
1324 if (jpeg_info.output_components == 1)
1325 for (x=0; x < (ssize_t) image->columns; x++)
1327 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1328 SetPixelIndex(image,index,q);
1329 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1331 q+=GetPixelChannels(image);
1334 if (image->colorspace != CMYKColorspace)
1335 for (x=0; x < (ssize_t) image->columns; x++)
1337 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1338 GETJSAMPLE(*p++)),q);
1339 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1340 GETJSAMPLE(*p++)),q);
1341 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1342 GETJSAMPLE(*p++)),q);
1343 SetPixelAlpha(image,OpaqueAlpha,q);
1344 q+=GetPixelChannels(image);
1347 for (x=0; x < (ssize_t) image->columns; x++)
1349 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1350 (unsigned char) GETJSAMPLE(*p++)),q);
1351 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1352 (unsigned char) GETJSAMPLE(*p++)),q);
1353 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1354 (unsigned char) GETJSAMPLE(*p++)),q);
1355 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1356 (unsigned char) GETJSAMPLE(*p++)),q);
1357 SetPixelAlpha(image,OpaqueAlpha,q);
1358 q+=GetPixelChannels(image);
1360 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1362 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1364 if (status == MagickFalse)
1366 jpeg_abort_decompress(&jpeg_info);
1370 if (status != MagickFalse)
1372 error_manager.finished=MagickTrue;
1373 if (setjmp(error_manager.error_recovery) == 0)
1374 (void) jpeg_finish_decompress(&jpeg_info);
1377 Free jpeg resources.
1379 jpeg_destroy_decompress(&jpeg_info);
1380 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1381 (void) CloseBlob(image);
1382 return(GetFirstImageInList(image));
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 % R e g i s t e r J P E G I m a g e %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1397 % RegisterJPEGImage() adds properties for the JPEG image format to
1398 % the list of supported formats. The properties include the image format
1399 % tag, a method to read and/or write the format, whether the format
1400 % supports the saving of more than one frame to the same file or blob,
1401 % whether the format supports native in-memory I/O, and a brief
1402 % description of the format.
1404 % The format of the RegisterJPEGImage method is:
1406 % size_t RegisterJPEGImage(void)
1409 ModuleExport size_t RegisterJPEGImage(void)
1412 version[MaxTextExtent];
1418 description[] = "Joint Photographic Experts Group JFIF format";
1421 #if defined(JPEG_LIB_VERSION)
1422 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1424 entry=SetMagickInfo("JPEG");
1425 entry->thread_support=NoThreadSupport;
1426 #if defined(MAGICKCORE_JPEG_DELEGATE)
1427 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1428 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1430 entry->magick=(IsImageFormatHandler *) IsJPEG;
1431 entry->adjoin=MagickFalse;
1432 entry->description=ConstantString(description);
1433 if (*version != '\0')
1434 entry->version=ConstantString(version);
1435 entry->module=ConstantString("JPEG");
1436 (void) RegisterMagickInfo(entry);
1437 entry=SetMagickInfo("JPG");
1438 entry->thread_support=NoThreadSupport;
1439 #if defined(MAGICKCORE_JPEG_DELEGATE)
1440 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1441 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1443 entry->adjoin=MagickFalse;
1444 entry->description=ConstantString(description);
1445 if (*version != '\0')
1446 entry->version=ConstantString(version);
1447 entry->module=ConstantString("JPEG");
1448 (void) RegisterMagickInfo(entry);
1449 entry=SetMagickInfo("PJPEG");
1450 entry->thread_support=NoThreadSupport;
1451 #if defined(MAGICKCORE_JPEG_DELEGATE)
1452 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1453 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1455 entry->adjoin=MagickFalse;
1456 entry->description=ConstantString(description);
1457 if (*version != '\0')
1458 entry->version=ConstantString(version);
1459 entry->module=ConstantString("JPEG");
1460 (void) RegisterMagickInfo(entry);
1461 return(MagickImageCoderSignature);
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469 % U n r e g i s t e r J P E G I m a g e %
1473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475 % UnregisterJPEGImage() removes format registrations made by the
1476 % JPEG module from the list of supported formats.
1478 % The format of the UnregisterJPEGImage method is:
1480 % UnregisterJPEGImage(void)
1483 ModuleExport void UnregisterJPEGImage(void)
1485 (void) UnregisterMagickInfo("PJPG");
1486 (void) UnregisterMagickInfo("JPEG");
1487 (void) UnregisterMagickInfo("JPG");
1490 #if defined(MAGICKCORE_JPEG_DELEGATE)
1492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 % W r i t e J P E G I m a g e %
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502 % WriteJPEGImage() writes a JPEG image file and returns it. It
1503 % allocates the memory necessary for the new Image structure and returns a
1504 % pointer to the new image.
1506 % The format of the WriteJPEGImage method is:
1508 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1509 % Image *image,ExceptionInfo *exception)
1511 % A description of each parameter follows:
1513 % o image_info: the image info.
1515 % o jpeg_image: The image.
1517 % o exception: return any errors or warnings in this structure.
1521 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1526 destination=(DestinationManager *) cinfo->dest;
1527 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1528 MaxBufferExtent,destination->buffer);
1529 if (destination->manager.free_in_buffer != MaxBufferExtent)
1530 ERREXIT(cinfo,JERR_FILE_WRITE);
1531 destination->manager.next_output_byte=destination->buffer;
1535 static void InitializeDestination(j_compress_ptr cinfo)
1540 destination=(DestinationManager *) cinfo->dest;
1541 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1542 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1543 destination->manager.next_output_byte=destination->buffer;
1544 destination->manager.free_in_buffer=MaxBufferExtent;
1547 static inline size_t MagickMin(const size_t x,const size_t y)
1554 static void TerminateDestination(j_compress_ptr cinfo)
1559 destination=(DestinationManager *) cinfo->dest;
1560 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1565 count=WriteBlob(destination->image,MaxBufferExtent-
1566 destination->manager.free_in_buffer,destination->buffer);
1567 if (count != (ssize_t)
1568 (MaxBufferExtent-destination->manager.free_in_buffer))
1569 ERREXIT(cinfo,JERR_FILE_WRITE);
1573 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1595 Save image profile as a APP marker.
1598 custom_profile=AcquireStringInfo(65535L);
1599 ResetImageProfileIterator(image);
1600 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1602 register unsigned char
1605 profile=GetImageProfile(image,name);
1606 p=GetStringInfoDatum(custom_profile);
1607 if (LocaleCompare(name,"EXIF") == 0)
1608 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1610 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1611 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1612 (unsigned int) length);
1614 if (LocaleCompare(name,"ICC") == 0)
1616 register unsigned char
1620 p=GetStringInfoDatum(custom_profile);
1621 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1622 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1624 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1625 p[12]=(unsigned char) ((i/65519L)+1);
1626 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1627 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1629 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1630 custom_profile),(unsigned int) (length+tag_length));
1633 if (((LocaleCompare(name,"IPTC") == 0) ||
1634 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1640 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1642 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1643 roundup=(size_t) (length & 0x01);
1644 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1646 (void) memcpy(p,"Photoshop 3.0 ",14);
1651 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1653 p[24]=(unsigned char) (length >> 8);
1654 p[25]=(unsigned char) (length & 0xff);
1657 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1659 p[length+tag_length]='\0';
1660 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1661 custom_profile),(unsigned int) (length+tag_length+roundup));
1664 if (LocaleCompare(name,"XMP") == 0)
1670 Add namespace to XMP profile.
1672 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1673 ConcatenateStringInfo(xmp_profile,profile);
1674 GetStringInfoDatum(xmp_profile)[28]='\0';
1675 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1677 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1678 jpeg_write_marker(jpeg_info,XML_MARKER,
1679 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1681 xmp_profile=DestroyStringInfo(xmp_profile);
1683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1684 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1685 name=GetNextImageProfile(image);
1687 custom_profile=DestroyStringInfo(custom_profile);
1690 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1695 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1696 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1697 destination=(DestinationManager *) cinfo->dest;
1698 destination->manager.init_destination=InitializeDestination;
1699 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1700 destination->manager.term_destination=TerminateDestination;
1701 destination->image=image;
1704 static char **SamplingFactorToList(const char *text)
1721 if (text == (char *) NULL)
1722 return((char **) NULL);
1724 Convert string to an ASCII list.
1727 for (p=text; *p != '\0'; p++)
1730 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1732 if (textlist == (char **) NULL)
1733 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1735 for (i=0; i < (ssize_t) lines; i++)
1737 for (q=(char *) p; *q != '\0'; q++)
1740 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1741 sizeof(*textlist[i]));
1742 if (textlist[i] == (char *) NULL)
1743 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1744 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1749 textlist[i]=(char *) NULL;
1753 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1754 Image *image,ExceptionInfo *exception)
1782 struct jpeg_compress_struct
1785 struct jpeg_error_mgr
1791 assert(image_info != (const ImageInfo *) NULL);
1792 assert(image_info->signature == MagickSignature);
1793 assert(image != (Image *) NULL);
1794 assert(image->signature == MagickSignature);
1795 if (image->debug != MagickFalse)
1796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1797 assert(exception != (ExceptionInfo *) NULL);
1798 assert(exception->signature == MagickSignature);
1799 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1800 if (status == MagickFalse)
1803 Initialize JPEG parameters.
1805 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1806 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1807 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1808 jpeg_info.client_data=(void *) image;
1809 jpeg_info.err=jpeg_std_error(&jpeg_error);
1810 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1811 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1812 error_manager.exception=exception;
1813 error_manager.image=image;
1814 jpeg_pixels=(JSAMPLE *) NULL;
1815 if (setjmp(error_manager.error_recovery) != 0)
1817 jpeg_destroy_compress(&jpeg_info);
1818 (void) CloseBlob(image);
1819 return(MagickFalse);
1821 jpeg_info.client_data=(void *) &error_manager;
1822 jpeg_create_compress(&jpeg_info);
1823 JPEGDestinationManager(&jpeg_info,image);
1824 if ((image->columns != (unsigned int) image->columns) ||
1825 (image->rows != (unsigned int) image->rows))
1826 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1827 jpeg_info.image_width=(unsigned int) image->columns;
1828 jpeg_info.image_height=(unsigned int) image->rows;
1829 jpeg_info.input_components=3;
1830 jpeg_info.data_precision=8;
1831 jpeg_info.in_color_space=JCS_RGB;
1832 switch (image->colorspace)
1834 case CMYKColorspace:
1836 jpeg_info.input_components=4;
1837 jpeg_info.in_color_space=JCS_CMYK;
1840 case YCbCrColorspace:
1841 case Rec601YCbCrColorspace:
1842 case Rec709YCbCrColorspace:
1844 jpeg_info.in_color_space=JCS_YCbCr;
1847 case GRAYColorspace:
1848 case Rec601LumaColorspace:
1849 case Rec709LumaColorspace:
1851 jpeg_info.input_components=1;
1852 jpeg_info.in_color_space=JCS_GRAYSCALE;
1857 if (IsRGBColorspace(image->colorspace) == MagickFalse)
1858 (void) TransformImageColorspace(image,RGBColorspace);
1862 if ((image_info->type != TrueColorType) &&
1863 (IsImageGray(image,exception) != MagickFalse))
1865 jpeg_info.input_components=1;
1866 jpeg_info.in_color_space=JCS_GRAYSCALE;
1868 jpeg_set_defaults(&jpeg_info);
1869 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1870 jpeg_info.data_precision=8;
1872 if (sizeof(JSAMPLE) > 1)
1873 jpeg_info.data_precision=12;
1874 jpeg_info.density_unit=(UINT8) 1;
1875 if (image->debug != MagickFalse)
1876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1877 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1878 floor(image->y_resolution+0.5));
1879 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1882 Set image resolution.
1884 jpeg_info.write_JFIF_header=MagickTrue;
1885 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1886 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1887 if (image->units == PixelsPerInchResolution)
1888 jpeg_info.density_unit=(UINT8) 1;
1889 if (image->units == PixelsPerCentimeterResolution)
1890 jpeg_info.density_unit=(UINT8) 2;
1892 option=GetImageOption(image_info,"jpeg:dct-method");
1893 if (option != (const char *) NULL)
1899 if (LocaleCompare(option,"default") == 0)
1900 jpeg_info.dct_method=JDCT_DEFAULT;
1906 if (LocaleCompare(option,"fastest") == 0)
1907 jpeg_info.dct_method=JDCT_FASTEST;
1908 if (LocaleCompare(option,"float") == 0)
1909 jpeg_info.dct_method=JDCT_FLOAT;
1915 if (LocaleCompare(option,"ifast") == 0)
1916 jpeg_info.dct_method=JDCT_IFAST;
1917 if (LocaleCompare(option,"islow") == 0)
1918 jpeg_info.dct_method=JDCT_ISLOW;
1922 option=GetImageOption(image_info,"jpeg:optimize-coding");
1923 if (option != (const char *) NULL)
1925 jpeg_info.optimize_coding=MagickFalse;
1926 if (IsMagickTrue(option) != MagickFalse)
1927 jpeg_info.optimize_coding=MagickTrue;
1934 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1935 image->rows*sizeof(JSAMPLE);
1936 if (length == (MagickSizeType) ((size_t) length))
1939 Perform optimization only if available memory resources permit it.
1941 status=AcquireMagickResource(MemoryResource,length);
1942 if (status != MagickFalse)
1943 jpeg_info.optimize_coding=MagickTrue;
1944 RelinquishMagickResource(MemoryResource,length);
1947 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1948 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1949 (image_info->interlace != NoInterlace))
1951 if (image->debug != MagickFalse)
1952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1953 "Interlace: progressive");
1954 jpeg_simple_progression(&jpeg_info);
1957 if (image->debug != MagickFalse)
1958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1959 "Interlace: non-progressive");
1961 if (image->debug != MagickFalse)
1962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1963 "Interlace: nonprogressive");
1965 option=GetImageOption(image_info,"jpeg:extent");
1966 if (option != (const char *) NULL)
1974 jpeg_info=CloneImageInfo(image_info);
1975 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1976 if (jpeg_image != (Image *) NULL)
1986 Search for compression quality that does not exceed image extent.
1988 jpeg_info->quality=0;
1989 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1990 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1991 (void) AcquireUniqueFilename(jpeg_image->filename);
1993 for (minimum=0; minimum != maximum; )
1995 jpeg_image->quality=minimum+(maximum-minimum)/2;
1996 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
1997 if (GetBlobSize(jpeg_image) <= extent)
1998 minimum=jpeg_image->quality+1;
2000 maximum=jpeg_image->quality-1;
2002 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2003 image->quality=minimum-1;
2004 jpeg_image=DestroyImage(jpeg_image);
2006 jpeg_info=DestroyImageInfo(jpeg_info);
2008 if ((image_info->compression != LosslessJPEGCompression) &&
2009 (image->quality <= 100))
2011 if (image->quality == UndefinedCompressionQuality)
2012 jpeg_set_quality(&jpeg_info,92,MagickTrue);
2014 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
2015 if (image->debug != MagickFalse)
2016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2017 (double) image->quality);
2021 #if !defined(C_LOSSLESS_SUPPORTED)
2022 jpeg_set_quality(&jpeg_info,100,MagickTrue);
2023 if (image->debug != MagickFalse)
2024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2026 if (image->quality < 100)
2027 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2028 "LosslessToLossyJPEGConversion",image->filename);
2035 predictor=image->quality/100; /* range 1-7 */
2036 point_transform=image->quality % 20; /* range 0-15 */
2037 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2038 if (image->debug != MagickFalse)
2040 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2041 "Compression: lossless");
2042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2043 "Predictor: %d",predictor);
2044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2045 "Point Transform: %d",point_transform);
2050 sampling_factor=(const char *) NULL;
2051 value=GetImageProperty(image,"jpeg:sampling-factor");
2052 if (value != (char *) NULL)
2054 sampling_factor=value;
2055 if (image->debug != MagickFalse)
2056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2057 " Input sampling-factors=%s",sampling_factor);
2059 if (image_info->sampling_factor != (char *) NULL)
2060 sampling_factor=image_info->sampling_factor;
2061 if (sampling_factor == (const char *) NULL)
2063 if (image->quality >= 90)
2064 for (i=0; i < MAX_COMPONENTS; i++)
2066 jpeg_info.comp_info[i].h_samp_factor=1;
2067 jpeg_info.comp_info[i].v_samp_factor=1;
2082 Set sampling factor.
2085 factors=SamplingFactorToList(sampling_factor);
2086 if (factors != (char **) NULL)
2088 for (i=0; i < MAX_COMPONENTS; i++)
2090 if (factors[i] == (char *) NULL)
2092 flags=ParseGeometry(factors[i],&geometry_info);
2093 if ((flags & SigmaValue) == 0)
2094 geometry_info.sigma=geometry_info.rho;
2095 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2096 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2097 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2099 factors=(char **) RelinquishMagickMemory(factors);
2101 for ( ; i < MAX_COMPONENTS; i++)
2103 jpeg_info.comp_info[i].h_samp_factor=1;
2104 jpeg_info.comp_info[i].v_samp_factor=1;
2107 if (jpeg_info.input_components == 1)
2108 for (i=0; i < MAX_COMPONENTS; i++)
2110 jpeg_info.comp_info[i].h_samp_factor=1;
2111 jpeg_info.comp_info[i].v_samp_factor=1;
2113 jpeg_start_compress(&jpeg_info,MagickTrue);
2114 if (image->debug != MagickFalse)
2116 if (image->storage_class == PseudoClass)
2117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2118 "Storage class: PseudoClass");
2120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2121 "Storage class: DirectClass");
2122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2123 (double) image->depth);
2124 if (image->colors != 0)
2125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2126 "Number of colors: %.20g",(double) image->colors);
2128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2129 "Number of colors: unspecified");
2130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2131 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2132 switch (image->colorspace)
2134 case CMYKColorspace:
2136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2137 "Storage class: DirectClass");
2138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2139 "Colorspace: CMYK");
2142 case YCbCrColorspace:
2143 case Rec601YCbCrColorspace:
2144 case Rec709YCbCrColorspace:
2146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2147 "Colorspace: YCbCr");
2153 switch (image->colorspace)
2155 case CMYKColorspace:
2157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2158 "Colorspace: CMYK");
2159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2160 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2161 jpeg_info.comp_info[0].h_samp_factor,
2162 jpeg_info.comp_info[0].v_samp_factor,
2163 jpeg_info.comp_info[1].h_samp_factor,
2164 jpeg_info.comp_info[1].v_samp_factor,
2165 jpeg_info.comp_info[2].h_samp_factor,
2166 jpeg_info.comp_info[2].v_samp_factor,
2167 jpeg_info.comp_info[3].h_samp_factor,
2168 jpeg_info.comp_info[3].v_samp_factor);
2171 case GRAYColorspace:
2172 case Rec601LumaColorspace:
2173 case Rec709LumaColorspace:
2175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2176 "Colorspace: GRAY");
2177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2178 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2179 jpeg_info.comp_info[0].v_samp_factor);
2184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2185 "Image colorspace is RGB");
2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187 "Sampling factors: %dx%d,%dx%d,%dx%d",
2188 jpeg_info.comp_info[0].h_samp_factor,
2189 jpeg_info.comp_info[0].v_samp_factor,
2190 jpeg_info.comp_info[1].h_samp_factor,
2191 jpeg_info.comp_info[1].v_samp_factor,
2192 jpeg_info.comp_info[2].h_samp_factor,
2193 jpeg_info.comp_info[2].v_samp_factor);
2196 case YCbCrColorspace:
2197 case Rec601YCbCrColorspace:
2198 case Rec709YCbCrColorspace:
2200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2201 "Colorspace: YCbCr");
2202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2203 "Sampling factors: %dx%d,%dx%d,%dx%d",
2204 jpeg_info.comp_info[0].h_samp_factor,
2205 jpeg_info.comp_info[0].v_samp_factor,
2206 jpeg_info.comp_info[1].h_samp_factor,
2207 jpeg_info.comp_info[1].v_samp_factor,
2208 jpeg_info.comp_info[2].h_samp_factor,
2209 jpeg_info.comp_info[2].v_samp_factor);
2214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2217 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2218 jpeg_info.comp_info[0].h_samp_factor,
2219 jpeg_info.comp_info[0].v_samp_factor,
2220 jpeg_info.comp_info[1].h_samp_factor,
2221 jpeg_info.comp_info[1].v_samp_factor,
2222 jpeg_info.comp_info[2].h_samp_factor,
2223 jpeg_info.comp_info[2].v_samp_factor,
2224 jpeg_info.comp_info[3].h_samp_factor,
2225 jpeg_info.comp_info[3].v_samp_factor);
2231 Write JPEG profiles.
2233 value=GetImageProperty(image,"comment");
2234 if (value != (char *) NULL)
2235 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2236 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2237 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2238 if (image->profiles != (void *) NULL)
2239 WriteProfile(&jpeg_info,image);
2241 Convert MIFF to JPEG raster pixels.
2243 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2244 jpeg_info.input_components*sizeof(*jpeg_pixels));
2245 if (jpeg_pixels == (JSAMPLE *) NULL)
2246 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2247 if (setjmp(error_manager.error_recovery) != 0)
2249 jpeg_destroy_compress(&jpeg_info);
2250 if (jpeg_pixels != (unsigned char *) NULL)
2251 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2252 (void) CloseBlob(image);
2253 return(MagickFalse);
2255 scanline[0]=(JSAMPROW) jpeg_pixels;
2256 if (jpeg_info.data_precision <= 8)
2258 if ((jpeg_info.in_color_space == JCS_RGB) ||
2259 (jpeg_info.in_color_space == JCS_YCbCr))
2260 for (y=0; y < (ssize_t) image->rows; y++)
2262 register const Quantum
2268 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2269 if (p == (const Quantum *) NULL)
2272 for (x=0; x < (ssize_t) image->columns; x++)
2274 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2275 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2276 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2277 p+=GetPixelChannels(image);
2279 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2280 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2282 if (status == MagickFalse)
2286 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2287 for (y=0; y < (ssize_t) image->rows; y++)
2289 register const Quantum
2295 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2296 if (p == (const Quantum *) NULL)
2299 for (x=0; x < (ssize_t) image->columns; x++)
2301 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2302 p+=GetPixelChannels(image);
2304 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2305 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2307 if (status == MagickFalse)
2311 for (y=0; y < (ssize_t) image->rows; y++)
2313 register const Quantum
2319 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2320 if (p == (const Quantum *) NULL)
2323 for (x=0; x < (ssize_t) image->columns; x++)
2326 Convert DirectClass packets to contiguous CMYK scanlines.
2328 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2329 GetPixelRed(image,p))));
2330 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2331 GetPixelGreen(image,p))));
2332 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2333 GetPixelBlue(image,p))));
2334 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2335 GetPixelBlack(image,p))));
2336 p+=GetPixelChannels(image);
2338 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2339 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2341 if (status == MagickFalse)
2346 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2347 for (y=0; y < (ssize_t) image->rows; y++)
2349 register const Quantum
2355 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2356 if (p == (const Quantum *) NULL)
2359 for (x=0; x < (ssize_t) image->columns; x++)
2361 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2363 p+=GetPixelChannels(image);
2365 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2366 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2368 if (status == MagickFalse)
2372 if ((jpeg_info.in_color_space == JCS_RGB) ||
2373 (jpeg_info.in_color_space == JCS_YCbCr))
2374 for (y=0; y < (ssize_t) image->rows; y++)
2376 register const Quantum
2382 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2383 if (p == (const Quantum *) NULL)
2386 for (x=0; x < (ssize_t) image->columns; x++)
2388 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2389 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2390 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2391 p+=GetPixelChannels(image);
2393 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2394 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2396 if (status == MagickFalse)
2400 for (y=0; y < (ssize_t) image->rows; y++)
2402 register const Quantum
2408 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2409 if (p == (const Quantum *) NULL)
2412 for (x=0; x < (ssize_t) image->columns; x++)
2415 Convert DirectClass packets to contiguous CMYK scanlines.
2417 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2418 GetPixelRed(image,p)) >> 4));
2419 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2420 GetPixelGreen(image,p)) >> 4));
2421 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2422 GetPixelBlue(image,p)) >> 4));
2423 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2424 GetPixelBlack(image,p)) >> 4));
2425 p+=GetPixelChannels(image);
2427 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2428 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2430 if (status == MagickFalse)
2433 if (y == (ssize_t) image->rows)
2434 jpeg_finish_compress(&jpeg_info);
2436 Relinquish resources.
2438 jpeg_destroy_compress(&jpeg_info);
2439 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2440 (void) CloseBlob(image);