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
131 typedef struct _SourceManager
133 struct jpeg_source_mgr
148 Forward declarations.
150 #if defined(MAGICKCORE_JPEG_DELEGATE)
151 static MagickBooleanType
152 WriteJPEGImage(const ImageInfo *,Image *);
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 % IsJPEG() returns MagickTrue if the image format type, identified by the
167 % magick string, is JPEG.
169 % The format of the IsJPEG method is:
171 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
173 % A description of each parameter follows:
175 % o magick: compare image format pattern against these bytes.
177 % o length: Specifies the length of the magick string.
180 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
184 if (memcmp(magick,"\377\330\377",3) == 0)
189 #if defined(MAGICKCORE_JPEG_DELEGATE)
191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 % R e a d J P E G I m a g e %
199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
201 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
202 % the memory necessary for the new Image structure and returns a pointer to
205 % The format of the ReadJPEGImage method is:
207 % Image *ReadJPEGImage(const ImageInfo *image_info,
208 % ExceptionInfo *exception)
210 % A description of each parameter follows:
212 % o image_info: the image info.
214 % o exception: return any errors or warnings in this structure.
218 static boolean FillInputBuffer(j_decompress_ptr cinfo)
223 source=(SourceManager *) cinfo->src;
224 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
225 MaxBufferExtent,source->buffer);
226 if (source->manager.bytes_in_buffer == 0)
228 if (source->start_of_blob != 0)
229 ERREXIT(cinfo,JERR_INPUT_EMPTY);
230 WARNMS(cinfo,JWRN_JPEG_EOF);
231 source->buffer[0]=(JOCTET) 0xff;
232 source->buffer[1]=(JOCTET) JPEG_EOI;
233 source->manager.bytes_in_buffer=2;
235 source->manager.next_input_byte=source->buffer;
236 source->start_of_blob=FALSE;
240 static int GetCharacter(j_decompress_ptr jpeg_info)
242 if (jpeg_info->src->bytes_in_buffer == 0)
243 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
244 jpeg_info->src->bytes_in_buffer--;
245 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
248 static void InitializeSource(j_decompress_ptr cinfo)
253 source=(SourceManager *) cinfo->src;
254 source->start_of_blob=TRUE;
257 static MagickBooleanType IsITUFaxImage(const Image *image)
265 profile=GetImageProfile(image,"8bim");
266 if (profile == (const StringInfo *) NULL)
268 if (GetStringInfoLength(profile) < 5)
270 datum=GetStringInfoDatum(profile);
271 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
272 (datum[3] == 0x41) && (datum[4] == 0x58))
277 static MagickBooleanType JPEGErrorHandler(j_common_ptr jpeg_info)
280 message[JMSG_LENGTH_MAX];
289 error_manager=(ErrorManager *) jpeg_info->client_data;
290 image=error_manager->image;
291 (jpeg_info->err->format_message)(jpeg_info,message);
292 if (image->debug != MagickFalse)
293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
294 "[%s] JPEG Trace: \"%s\"",image->filename,message);
295 if (error_manager->finished != MagickFalse)
296 (void) ThrowMagickException(&image->exception,GetMagickModule(),
297 CorruptImageWarning,(char *) message,image->filename);
299 (void) ThrowMagickException(&image->exception,GetMagickModule(),
300 CorruptImageError,(char *) message,image->filename);
301 longjmp(error_manager->error_recovery,1);
304 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
307 message[JMSG_LENGTH_MAX];
316 error_manager=(ErrorManager *) jpeg_info->client_data;
317 image=error_manager->image;
321 Process warning message.
323 (jpeg_info->err->format_message)(jpeg_info,message);
324 if ((jpeg_info->err->num_warnings == 0) ||
325 (jpeg_info->err->trace_level >= 3))
326 ThrowBinaryException(CorruptImageWarning,(char *) message,
328 jpeg_info->err->num_warnings++;
331 if ((image->debug != MagickFalse) &&
332 (level >= jpeg_info->err->trace_level))
335 Process trace message.
337 (jpeg_info->err->format_message)(jpeg_info,message);
338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
339 "[%s] JPEG Trace: \"%s\"",image->filename,message);
344 static boolean ReadComment(j_decompress_ptr jpeg_info)
365 Determine length of comment.
367 error_manager=(ErrorManager *) jpeg_info->client_data;
368 image=error_manager->image;
369 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
370 length+=GetCharacter(jpeg_info);
374 comment=(char *) NULL;
375 if (~length >= (MaxTextExtent-1))
376 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
378 if (comment == (char *) NULL)
379 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
384 i=(ssize_t) length-1;
385 for (p=comment; i-- >= 0; p++)
386 *p=(char) GetCharacter(jpeg_info);
388 (void) SetImageProperty(image,"comment",comment);
389 comment=DestroyString(comment);
393 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
410 register unsigned char
423 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
424 length+=(size_t) GetCharacter(jpeg_info);
429 (void) GetCharacter(jpeg_info);
432 for (i=0; i < 12; i++)
433 magick[i]=(char) GetCharacter(jpeg_info);
434 if (LocaleCompare(magick,ICC_PROFILE) != 0)
437 Not a ICC profile, return.
439 for (i=0; i < (ssize_t) (length-12); i++)
440 (void) GetCharacter(jpeg_info);
443 (void) GetCharacter(jpeg_info); /* id */
444 (void) GetCharacter(jpeg_info); /* markers */
446 error_manager=(ErrorManager *) jpeg_info->client_data;
447 image=error_manager->image;
448 profile=AcquireStringInfo(length);
449 if (profile == (StringInfo *) NULL)
450 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
452 p=GetStringInfoDatum(profile);
453 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
454 *p++=(unsigned char) GetCharacter(jpeg_info);
455 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
456 if (icc_profile != (StringInfo *) NULL)
458 ConcatenateStringInfo(icc_profile,profile);
459 profile=DestroyStringInfo(profile);
463 status=SetImageProfile(image,"icc",profile);
464 profile=DestroyStringInfo(profile);
465 if (status == MagickFalse)
466 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
469 if (image->debug != MagickFalse)
470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
471 "Profile: ICC, %.20g bytes",(double) length);
475 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
478 magick[MaxTextExtent];
492 register unsigned char
503 Determine length of binary data stored here.
505 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
506 length+=(size_t) GetCharacter(jpeg_info);
511 (void) GetCharacter(jpeg_info);
515 Validate that this was written as a Photoshop resource format slug.
517 for (i=0; i < 10; i++)
518 magick[i]=(char) GetCharacter(jpeg_info);
523 if (LocaleCompare(magick,"Photoshop ") != 0)
526 Not a IPTC profile, return.
528 for (i=0; i < (ssize_t) length; i++)
529 (void) GetCharacter(jpeg_info);
533 Remove the version number.
535 for (i=0; i < 4; i++)
536 (void) GetCharacter(jpeg_info);
542 error_manager=(ErrorManager *) jpeg_info->client_data;
543 image=error_manager->image;
544 profile=AcquireStringInfo(length);
545 if (profile == (StringInfo *) NULL)
546 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
548 p=GetStringInfoDatum(profile);
549 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
550 *p++=(unsigned char) GetCharacter(jpeg_info);
551 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
552 if (iptc_profile != (StringInfo *) NULL)
554 ConcatenateStringInfo(iptc_profile,profile);
555 profile=DestroyStringInfo(profile);
559 status=SetImageProfile(image,"8bim",profile);
560 profile=DestroyStringInfo(profile);
561 if (status == MagickFalse)
562 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
565 if (image->debug != MagickFalse)
566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
567 "Profile: iptc, %.20g bytes",(double) length);
571 static boolean ReadProfile(j_decompress_ptr jpeg_info)
591 register unsigned char
601 Read generic profile.
603 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
604 length+=(size_t) GetCharacter(jpeg_info);
608 marker=jpeg_info->unread_marker-JPEG_APP0;
609 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
610 error_manager=(ErrorManager *) jpeg_info->client_data;
611 image=error_manager->image;
612 profile=AcquireStringInfo(length);
613 if (profile == (StringInfo *) NULL)
614 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
616 p=GetStringInfoDatum(profile);
617 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
618 *p++=(unsigned char) GetCharacter(jpeg_info);
621 p=GetStringInfoDatum(profile);
622 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
623 (void) CopyMagickString(name,"exif",MaxTextExtent);
624 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
630 Extract namespace from XMP profile.
632 p=GetStringInfoDatum(profile);
633 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
639 if (j < (ssize_t) GetStringInfoLength(profile))
640 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
641 (void) CopyMagickString(name,"xmp",MaxTextExtent);
644 status=SetImageProfile(image,name,profile);
645 profile=DestroyStringInfo(profile);
646 if (status == MagickFalse)
647 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
649 if (image->debug != MagickFalse)
650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
651 "Profile: %s, %.20g bytes",name,(double) length);
655 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
660 if (number_bytes <= 0)
662 source=(SourceManager *) cinfo->src;
663 while (number_bytes > (long) source->manager.bytes_in_buffer)
665 number_bytes-=(long) source->manager.bytes_in_buffer;
666 (void) FillInputBuffer(cinfo);
668 source->manager.next_input_byte+=number_bytes;
669 source->manager.bytes_in_buffer-=number_bytes;
672 static void TerminateSource(j_decompress_ptr cinfo)
677 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
682 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
683 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
684 source=(SourceManager *) cinfo->src;
685 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
686 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
687 source=(SourceManager *) cinfo->src;
688 source->manager.init_source=InitializeSource;
689 source->manager.fill_input_buffer=FillInputBuffer;
690 source->manager.skip_input_data=SkipInputData;
691 source->manager.resync_to_restart=jpeg_resync_to_restart;
692 source->manager.term_source=TerminateSource;
693 source->manager.bytes_in_buffer=0;
694 source->manager.next_input_byte=NULL;
698 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
701 image->quality=UndefinedCompressionQuality;
702 #if defined(D_PROGRESSIVE_SUPPORTED)
703 if (image->compression == LosslessJPEGCompression)
706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
707 "Quality: 100 (lossless)");
721 Determine the JPEG compression quality from the quantization tables.
724 for (i=0; i < NUM_QUANT_TBLS; i++)
726 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
727 for (j=0; j < DCTSIZE2; j++)
728 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
730 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
731 (jpeg_info->quant_tbl_ptrs[1] != NULL))
736 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
737 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
738 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
739 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
740 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
741 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
742 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
743 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
744 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
745 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
750 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
751 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
752 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
753 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
754 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
755 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
756 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
757 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
758 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
759 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
760 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
764 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
765 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
766 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
767 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
768 for (i=0; i < 100; i++)
770 if ((qvalue < hash[i]) && (sum < sums[i]))
772 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
773 image->quality=(size_t) i+1;
774 if (image->debug != MagickFalse)
775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
777 (sum <= sums[i]) ? "exact" : "approximate");
782 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
787 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
788 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
789 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
790 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
791 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
792 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
793 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
794 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
795 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
796 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
801 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
802 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
803 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
804 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
805 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
806 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
807 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
808 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
809 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
810 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
811 667, 592, 518, 441, 369, 292, 221, 151, 86,
815 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
816 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
817 for (i=0; i < 100; i++)
819 if ((qvalue < hash[i]) && (sum < sums[i]))
821 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
822 image->quality=(size_t) i+1;
823 if (image->debug != MagickFalse)
824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
825 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
826 (sum <= sums[i]) ? "exact" : "approximate");
833 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
836 sampling_factor[MaxTextExtent];
838 switch (jpeg_info->out_color_space)
842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
843 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
844 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
845 jpeg_info->comp_info[0].v_samp_factor,
846 jpeg_info->comp_info[1].h_samp_factor,
847 jpeg_info->comp_info[1].v_samp_factor,
848 jpeg_info->comp_info[2].h_samp_factor,
849 jpeg_info->comp_info[2].v_samp_factor,
850 jpeg_info->comp_info[3].h_samp_factor,
851 jpeg_info->comp_info[3].v_samp_factor);
856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
857 "Colorspace: GRAYSCALE");
858 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
859 jpeg_info->comp_info[0].h_samp_factor,
860 jpeg_info->comp_info[0].v_samp_factor);
865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
866 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
867 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
868 jpeg_info->comp_info[0].v_samp_factor,
869 jpeg_info->comp_info[1].h_samp_factor,
870 jpeg_info->comp_info[1].v_samp_factor,
871 jpeg_info->comp_info[2].h_samp_factor,
872 jpeg_info->comp_info[2].v_samp_factor);
877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
878 jpeg_info->out_color_space);
879 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
880 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
881 jpeg_info->comp_info[0].v_samp_factor,
882 jpeg_info->comp_info[1].h_samp_factor,
883 jpeg_info->comp_info[1].v_samp_factor,
884 jpeg_info->comp_info[2].h_samp_factor,
885 jpeg_info->comp_info[2].v_samp_factor,
886 jpeg_info->comp_info[3].h_samp_factor,
887 jpeg_info->comp_info[3].v_samp_factor);
891 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
892 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
896 static Image *ReadJPEGImage(const ImageInfo *image_info,
897 ExceptionInfo *exception)
900 value[MaxTextExtent];
930 struct jpeg_decompress_struct
933 struct jpeg_error_mgr
949 assert(image_info != (const ImageInfo *) NULL);
950 assert(image_info->signature == MagickSignature);
951 if (image_info->debug != MagickFalse)
952 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
953 image_info->filename);
954 assert(exception != (ExceptionInfo *) NULL);
955 assert(exception->signature == MagickSignature);
956 debug=IsEventLogging();
958 image=AcquireImage(image_info);
959 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
960 if (status == MagickFalse)
962 image=DestroyImageList(image);
963 return((Image *) NULL);
966 Initialize JPEG parameters.
968 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
969 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
970 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
971 jpeg_info.err=jpeg_std_error(&jpeg_error);
972 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
973 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
974 jpeg_pixels=(JSAMPLE *) NULL;
975 error_manager.image=image;
976 if (setjmp(error_manager.error_recovery) != 0)
978 jpeg_destroy_decompress(&jpeg_info);
979 (void) CloseBlob(image);
980 number_pixels=(MagickSizeType) image->columns*image->rows;
981 if (number_pixels != 0)
982 return(GetFirstImageInList(image));
983 InheritException(exception,&image->exception);
984 return(DestroyImage(image));
986 jpeg_info.client_data=(void *) &error_manager;
987 jpeg_create_decompress(&jpeg_info);
988 JPEGSourceManager(&jpeg_info,image);
989 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
990 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
991 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
992 for (i=1; i < 16; i++)
993 if ((i != 2) && (i != 13) && (i != 14))
994 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
995 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
996 if ((image_info->colorspace == YCbCrColorspace) ||
997 (image_info->colorspace == Rec601YCbCrColorspace) ||
998 (image_info->colorspace == Rec709YCbCrColorspace))
999 jpeg_info.out_color_space=JCS_YCbCr;
1000 if (IsITUFaxImage(image) != MagickFalse)
1002 image->colorspace=LabColorspace;
1003 jpeg_info.out_color_space=JCS_YCbCr;
1006 if (jpeg_info.out_color_space == JCS_CMYK)
1007 image->colorspace=CMYKColorspace;
1009 Set image resolution.
1012 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1013 (jpeg_info.Y_density != 1))
1015 image->x_resolution=(double) jpeg_info.X_density;
1016 image->y_resolution=(double) jpeg_info.Y_density;
1017 units=(size_t) jpeg_info.density_unit;
1020 image->units=PixelsPerInchResolution;
1022 image->units=PixelsPerCentimeterResolution;
1023 number_pixels=(MagickSizeType) image->columns*image->rows;
1024 option=GetImageOption(image_info,"jpeg:size");
1025 if (option != (const char *) NULL)
1039 flags=ParseGeometry(option,&geometry_info);
1040 if ((flags & SigmaValue) == 0)
1041 geometry_info.sigma=geometry_info.rho;
1042 jpeg_calc_output_dimensions(&jpeg_info);
1043 image->magick_columns=jpeg_info.output_width;
1044 image->magick_rows=jpeg_info.output_height;
1046 if (geometry_info.rho != 0.0)
1047 scale_factor=jpeg_info.output_width/geometry_info.rho;
1048 if ((geometry_info.sigma != 0.0) &&
1049 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1050 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1051 jpeg_info.scale_num=1U;
1052 jpeg_info.scale_denom=(unsigned int) scale_factor;
1053 jpeg_calc_output_dimensions(&jpeg_info);
1054 if (image->debug != MagickFalse)
1055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1056 "Scale factor: %.20g",(double) scale_factor);
1058 precision=(size_t) jpeg_info.data_precision;
1059 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1060 #if defined(D_LOSSLESS_SUPPORTED)
1061 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1062 JPEGInterlace : NoInterlace;
1063 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1064 LosslessJPEGCompression : JPEGCompression;
1065 if (jpeg_info.data_precision > 8)
1066 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1067 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1069 if (jpeg_info.data_precision == 16)
1070 jpeg_info.data_precision=12;
1072 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1074 image->compression=JPEGCompression;
1077 image->compression=JPEGCompression;
1078 image->interlace=JPEGInterlace;
1080 if ((image_info->colors > 8) && (image_info->colors <= 256))
1083 Let the JPEG library quantize for us.
1085 jpeg_info.quantize_colors=MagickTrue;
1086 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1088 option=GetImageOption(image_info,"jpeg:block-smoothing");
1089 if (option != (const char *) NULL)
1091 jpeg_info.do_block_smoothing=MagickFalse;
1092 if (IsMagickTrue(option) != MagickFalse)
1093 jpeg_info.do_block_smoothing=MagickTrue;
1095 option=GetImageOption(image_info,"jpeg:dct-method");
1096 if (option != (const char *) NULL)
1102 if (LocaleCompare(option,"default") == 0)
1103 jpeg_info.dct_method=JDCT_DEFAULT;
1109 if (LocaleCompare(option,"fastest") == 0)
1110 jpeg_info.dct_method=JDCT_FASTEST;
1111 if (LocaleCompare(option,"float") == 0)
1112 jpeg_info.dct_method=JDCT_FLOAT;
1118 if (LocaleCompare(option,"ifast") == 0)
1119 jpeg_info.dct_method=JDCT_IFAST;
1120 if (LocaleCompare(option,"islow") == 0)
1121 jpeg_info.dct_method=JDCT_ISLOW;
1125 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1126 if (option != (const char *) NULL)
1128 jpeg_info.do_fancy_upsampling=MagickFalse;
1129 if (IsMagickTrue(option) != MagickFalse)
1130 jpeg_info.do_fancy_upsampling=MagickTrue;
1132 (void) jpeg_start_decompress(&jpeg_info);
1133 image->columns=jpeg_info.output_width;
1134 image->rows=jpeg_info.output_height;
1135 image->depth=(size_t) jpeg_info.data_precision;
1136 if (jpeg_info.out_color_space == JCS_YCbCr)
1137 image->colorspace=YCbCrColorspace;
1138 if (jpeg_info.out_color_space == JCS_CMYK)
1139 image->colorspace=CMYKColorspace;
1140 if ((image_info->colors != 0) && (image_info->colors <= 256))
1141 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1142 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1143 if ((jpeg_info.output_components == 1) &&
1144 (jpeg_info.quantize_colors == MagickFalse))
1149 colors=(size_t) GetQuantumRange(image->depth)+1;
1150 if (AcquireImageColormap(image,colors) == MagickFalse)
1151 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1153 if (image->debug != MagickFalse)
1155 if (image->interlace != NoInterlace)
1156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1157 "Interlace: progressive");
1159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1160 "Interlace: nonprogressive");
1161 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1162 (int) jpeg_info.data_precision);
1163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1164 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1166 JPEGSetImageQuality(&jpeg_info,image);
1167 JPEGSetImageSamplingFactor(&jpeg_info,image);
1168 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1169 jpeg_info.out_color_space);
1170 (void) SetImageProperty(image,"jpeg:colorspace",value);
1171 if (image_info->ping != MagickFalse)
1173 jpeg_destroy_decompress(&jpeg_info);
1174 (void) CloseBlob(image);
1175 return(GetFirstImageInList(image));
1177 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1178 jpeg_info.output_components*sizeof(JSAMPLE));
1179 if (jpeg_pixels == (JSAMPLE *) NULL)
1180 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1182 Convert JPEG pixels to pixel packets.
1184 if (setjmp(error_manager.error_recovery) != 0)
1186 if (jpeg_pixels != (unsigned char *) NULL)
1187 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1188 jpeg_destroy_decompress(&jpeg_info);
1189 (void) CloseBlob(image);
1190 number_pixels=(MagickSizeType) image->columns*image->rows;
1191 if (number_pixels != 0)
1192 return(GetFirstImageInList(image));
1193 return(DestroyImage(image));
1195 if (jpeg_info.quantize_colors != MagickFalse)
1197 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1198 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1199 for (i=0; i < (ssize_t) image->colors; i++)
1201 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1202 image->colormap[i].green=image->colormap[i].red;
1203 image->colormap[i].blue=image->colormap[i].red;
1204 image->colormap[i].alpha=OpaqueAlpha;
1207 for (i=0; i < (ssize_t) image->colors; i++)
1209 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1210 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1211 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1212 image->colormap[i].alpha=OpaqueAlpha;
1215 scanline[0]=(JSAMPROW) jpeg_pixels;
1216 for (y=0; y < (ssize_t) image->rows; y++)
1224 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1226 (void) ThrowMagickException(exception,GetMagickModule(),
1227 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1231 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1232 if (q == (const Quantum *) NULL)
1234 if (jpeg_info.data_precision > 8)
1236 if (jpeg_info.output_components == 1)
1237 for (x=0; x < (ssize_t) image->columns; x++)
1242 if (precision != 16)
1243 pixel=(size_t) GETJSAMPLE(*p);
1245 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1246 index=ConstrainColormapIndex(image,pixel);
1247 SetPixelIndex(image,index,q);
1248 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1250 q+=GetPixelComponents(image);
1253 if (image->colorspace != CMYKColorspace)
1254 for (x=0; x < (ssize_t) image->columns; x++)
1256 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1257 (GETJSAMPLE(*p++) << 4)),q);
1258 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1259 (GETJSAMPLE(*p++) << 4)),q);
1260 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1261 (GETJSAMPLE(*p++) << 4)),q);
1262 SetPixelAlpha(image,OpaqueAlpha,q);
1263 q+=GetPixelComponents(image);
1266 for (x=0; x < (ssize_t) image->columns; x++)
1268 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1269 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1270 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1271 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1272 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1273 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1274 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1275 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1276 SetPixelAlpha(image,OpaqueAlpha,q);
1277 q+=GetPixelComponents(image);
1281 if (jpeg_info.output_components == 1)
1282 for (x=0; x < (ssize_t) image->columns; x++)
1284 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1285 SetPixelIndex(image,index,q);
1286 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1288 q+=GetPixelComponents(image);
1291 if (image->colorspace != CMYKColorspace)
1292 for (x=0; x < (ssize_t) image->columns; x++)
1294 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1295 GETJSAMPLE(*p++)),q);
1296 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1297 GETJSAMPLE(*p++)),q);
1298 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1299 GETJSAMPLE(*p++)),q);
1300 SetPixelAlpha(image,OpaqueAlpha,q);
1301 q+=GetPixelComponents(image);
1304 for (x=0; x < (ssize_t) image->columns; x++)
1306 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1307 (unsigned char) GETJSAMPLE(*p++)),q);
1308 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1309 (unsigned char) GETJSAMPLE(*p++)),q);
1310 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1311 (unsigned char) GETJSAMPLE(*p++)),q);
1312 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1313 (unsigned char) GETJSAMPLE(*p++)),q);
1314 SetPixelAlpha(image,OpaqueAlpha,q);
1315 q+=GetPixelComponents(image);
1317 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1319 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1321 if (status == MagickFalse)
1323 jpeg_abort_decompress(&jpeg_info);
1327 if (status != MagickFalse)
1329 error_manager.finished=MagickTrue;
1330 if (setjmp(error_manager.error_recovery) == 0)
1331 (void) jpeg_finish_decompress(&jpeg_info);
1334 Free jpeg resources.
1336 jpeg_destroy_decompress(&jpeg_info);
1337 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1338 (void) CloseBlob(image);
1339 return(GetFirstImageInList(image));
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 % R e g i s t e r J P E G I m a g e %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % RegisterJPEGImage() adds properties for the JPEG image format to
1355 % the list of supported formats. The properties include the image format
1356 % tag, a method to read and/or write the format, whether the format
1357 % supports the saving of more than one frame to the same file or blob,
1358 % whether the format supports native in-memory I/O, and a brief
1359 % description of the format.
1361 % The format of the RegisterJPEGImage method is:
1363 % size_t RegisterJPEGImage(void)
1366 ModuleExport size_t RegisterJPEGImage(void)
1369 version[MaxTextExtent];
1375 description[] = "Joint Photographic Experts Group JFIF format";
1378 #if defined(JPEG_LIB_VERSION)
1379 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1381 entry=SetMagickInfo("JPEG");
1382 entry->thread_support=NoThreadSupport;
1383 #if defined(MAGICKCORE_JPEG_DELEGATE)
1384 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1385 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1387 entry->magick=(IsImageFormatHandler *) IsJPEG;
1388 entry->adjoin=MagickFalse;
1389 entry->description=ConstantString(description);
1390 if (*version != '\0')
1391 entry->version=ConstantString(version);
1392 entry->module=ConstantString("JPEG");
1393 (void) RegisterMagickInfo(entry);
1394 entry=SetMagickInfo("JPG");
1395 entry->thread_support=NoThreadSupport;
1396 #if defined(MAGICKCORE_JPEG_DELEGATE)
1397 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1398 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1400 entry->adjoin=MagickFalse;
1401 entry->description=ConstantString(description);
1402 if (*version != '\0')
1403 entry->version=ConstantString(version);
1404 entry->module=ConstantString("JPEG");
1405 (void) RegisterMagickInfo(entry);
1406 entry=SetMagickInfo("PJPEG");
1407 entry->thread_support=NoThreadSupport;
1408 #if defined(MAGICKCORE_JPEG_DELEGATE)
1409 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1410 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1412 entry->adjoin=MagickFalse;
1413 entry->description=ConstantString(description);
1414 if (*version != '\0')
1415 entry->version=ConstantString(version);
1416 entry->module=ConstantString("JPEG");
1417 (void) RegisterMagickInfo(entry);
1418 return(MagickImageCoderSignature);
1422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 % U n r e g i s t e r J P E G I m a g e %
1430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1432 % UnregisterJPEGImage() removes format registrations made by the
1433 % JPEG module from the list of supported formats.
1435 % The format of the UnregisterJPEGImage method is:
1437 % UnregisterJPEGImage(void)
1440 ModuleExport void UnregisterJPEGImage(void)
1442 (void) UnregisterMagickInfo("PJPG");
1443 (void) UnregisterMagickInfo("JPEG");
1444 (void) UnregisterMagickInfo("JPG");
1447 #if defined(MAGICKCORE_JPEG_DELEGATE)
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 % W r i t e J P E G I m a g e %
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459 % WriteJPEGImage() writes a JPEG image file and returns it. It
1460 % allocates the memory necessary for the new Image structure and returns a
1461 % pointer to the new image.
1463 % The format of the WriteJPEGImage method is:
1465 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1468 % A description of each parameter follows:
1470 % o image_info: the image info.
1472 % o jpeg_image: The image.
1477 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1482 destination=(DestinationManager *) cinfo->dest;
1483 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1484 MaxBufferExtent,destination->buffer);
1485 if (destination->manager.free_in_buffer != MaxBufferExtent)
1486 ERREXIT(cinfo,JERR_FILE_WRITE);
1487 destination->manager.next_output_byte=destination->buffer;
1491 static void InitializeDestination(j_compress_ptr cinfo)
1496 destination=(DestinationManager *) cinfo->dest;
1497 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1498 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1499 destination->manager.next_output_byte=destination->buffer;
1500 destination->manager.free_in_buffer=MaxBufferExtent;
1503 static inline size_t MagickMin(const size_t x,const size_t y)
1510 static void TerminateDestination(j_compress_ptr cinfo)
1515 destination=(DestinationManager *) cinfo->dest;
1516 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1521 count=WriteBlob(destination->image,MaxBufferExtent-
1522 destination->manager.free_in_buffer,destination->buffer);
1523 if (count != (ssize_t)
1524 (MaxBufferExtent-destination->manager.free_in_buffer))
1525 ERREXIT(cinfo,JERR_FILE_WRITE);
1529 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1551 Save image profile as a APP marker.
1554 custom_profile=AcquireStringInfo(65535L);
1555 ResetImageProfileIterator(image);
1556 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1558 register unsigned char
1561 profile=GetImageProfile(image,name);
1562 p=GetStringInfoDatum(custom_profile);
1563 if (LocaleCompare(name,"EXIF") == 0)
1564 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1566 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1567 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1568 (unsigned int) length);
1570 if (LocaleCompare(name,"ICC") == 0)
1572 register unsigned char
1576 p=GetStringInfoDatum(custom_profile);
1577 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1578 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1580 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1581 p[12]=(unsigned char) ((i/65519L)+1);
1582 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1583 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1585 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1586 custom_profile),(unsigned int) (length+tag_length));
1589 if (((LocaleCompare(name,"IPTC") == 0) ||
1590 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1596 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1598 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1599 roundup=(size_t) (length & 0x01);
1600 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1602 (void) memcpy(p,"Photoshop 3.0 ",14);
1607 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1609 p[24]=(unsigned char) (length >> 8);
1610 p[25]=(unsigned char) (length & 0xff);
1613 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1615 p[length+tag_length]='\0';
1616 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1617 custom_profile),(unsigned int) (length+tag_length+roundup));
1620 if (LocaleCompare(name,"XMP") == 0)
1626 Add namespace to XMP profile.
1628 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1629 ConcatenateStringInfo(xmp_profile,profile);
1630 GetStringInfoDatum(xmp_profile)[28]='\0';
1631 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1633 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1634 jpeg_write_marker(jpeg_info,XML_MARKER,
1635 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1637 xmp_profile=DestroyStringInfo(xmp_profile);
1639 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1640 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1641 name=GetNextImageProfile(image);
1643 custom_profile=DestroyStringInfo(custom_profile);
1646 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1651 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1652 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1653 destination=(DestinationManager *) cinfo->dest;
1654 destination->manager.init_destination=InitializeDestination;
1655 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1656 destination->manager.term_destination=TerminateDestination;
1657 destination->image=image;
1660 static char **SamplingFactorToList(const char *text)
1677 if (text == (char *) NULL)
1678 return((char **) NULL);
1680 Convert string to an ASCII list.
1683 for (p=text; *p != '\0'; p++)
1686 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1688 if (textlist == (char **) NULL)
1689 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1691 for (i=0; i < (ssize_t) lines; i++)
1693 for (q=(char *) p; *q != '\0'; q++)
1696 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1697 sizeof(*textlist[i]));
1698 if (textlist[i] == (char *) NULL)
1699 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1700 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1705 textlist[i]=(char *) NULL;
1709 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1738 struct jpeg_compress_struct
1741 struct jpeg_error_mgr
1747 assert(image_info != (const ImageInfo *) NULL);
1748 assert(image_info->signature == MagickSignature);
1749 assert(image != (Image *) NULL);
1750 assert(image->signature == MagickSignature);
1751 if (image->debug != MagickFalse)
1752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1753 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1754 if (status == MagickFalse)
1757 Initialize JPEG parameters.
1759 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1760 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1761 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1762 jpeg_info.client_data=(void *) image;
1763 jpeg_info.err=jpeg_std_error(&jpeg_error);
1764 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1765 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1766 error_manager.image=image;
1767 jpeg_pixels=(JSAMPLE *) NULL;
1768 if (setjmp(error_manager.error_recovery) != 0)
1770 jpeg_destroy_compress(&jpeg_info);
1771 (void) CloseBlob(image);
1772 return(MagickFalse);
1774 jpeg_info.client_data=(void *) &error_manager;
1775 jpeg_create_compress(&jpeg_info);
1776 JPEGDestinationManager(&jpeg_info,image);
1777 if ((image->columns != (unsigned int) image->columns) ||
1778 (image->rows != (unsigned int) image->rows))
1779 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1780 jpeg_info.image_width=(unsigned int) image->columns;
1781 jpeg_info.image_height=(unsigned int) image->rows;
1782 jpeg_info.input_components=3;
1783 jpeg_info.data_precision=8;
1784 jpeg_info.in_color_space=JCS_RGB;
1785 switch (image->colorspace)
1787 case CMYKColorspace:
1789 jpeg_info.input_components=4;
1790 jpeg_info.in_color_space=JCS_CMYK;
1793 case YCbCrColorspace:
1794 case Rec601YCbCrColorspace:
1795 case Rec709YCbCrColorspace:
1797 jpeg_info.in_color_space=JCS_YCbCr;
1800 case GRAYColorspace:
1801 case Rec601LumaColorspace:
1802 case Rec709LumaColorspace:
1804 jpeg_info.input_components=1;
1805 jpeg_info.in_color_space=JCS_GRAYSCALE;
1810 if (IsRGBColorspace(image->colorspace) == MagickFalse)
1811 (void) TransformImageColorspace(image,RGBColorspace);
1815 if ((image_info->type != TrueColorType) &&
1816 (IsImageGray(image,&image->exception) != MagickFalse))
1818 jpeg_info.input_components=1;
1819 jpeg_info.in_color_space=JCS_GRAYSCALE;
1821 jpeg_set_defaults(&jpeg_info);
1822 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1823 jpeg_info.data_precision=8;
1825 if (sizeof(JSAMPLE) > 1)
1826 jpeg_info.data_precision=12;
1827 jpeg_info.density_unit=(UINT8) 1;
1828 if (image->debug != MagickFalse)
1829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1830 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1831 floor(image->y_resolution+0.5));
1832 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1835 Set image resolution.
1837 jpeg_info.write_JFIF_header=MagickTrue;
1838 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1839 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1840 if (image->units == PixelsPerInchResolution)
1841 jpeg_info.density_unit=(UINT8) 1;
1842 if (image->units == PixelsPerCentimeterResolution)
1843 jpeg_info.density_unit=(UINT8) 2;
1845 option=GetImageOption(image_info,"jpeg:dct-method");
1846 if (option != (const char *) NULL)
1852 if (LocaleCompare(option,"default") == 0)
1853 jpeg_info.dct_method=JDCT_DEFAULT;
1859 if (LocaleCompare(option,"fastest") == 0)
1860 jpeg_info.dct_method=JDCT_FASTEST;
1861 if (LocaleCompare(option,"float") == 0)
1862 jpeg_info.dct_method=JDCT_FLOAT;
1868 if (LocaleCompare(option,"ifast") == 0)
1869 jpeg_info.dct_method=JDCT_IFAST;
1870 if (LocaleCompare(option,"islow") == 0)
1871 jpeg_info.dct_method=JDCT_ISLOW;
1875 option=GetImageOption(image_info,"jpeg:optimize-coding");
1876 if (option != (const char *) NULL)
1878 jpeg_info.optimize_coding=MagickFalse;
1879 if (IsMagickTrue(option) != MagickFalse)
1880 jpeg_info.optimize_coding=MagickTrue;
1887 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1888 image->rows*sizeof(JSAMPLE);
1889 if (length == (MagickSizeType) ((size_t) length))
1892 Perform optimization only if available memory resources permit it.
1894 status=AcquireMagickResource(MemoryResource,length);
1895 if (status != MagickFalse)
1896 jpeg_info.optimize_coding=MagickTrue;
1897 RelinquishMagickResource(MemoryResource,length);
1900 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1901 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1902 (image_info->interlace != NoInterlace))
1904 if (image->debug != MagickFalse)
1905 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1906 "Interlace: progressive");
1907 jpeg_simple_progression(&jpeg_info);
1910 if (image->debug != MagickFalse)
1911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1912 "Interlace: non-progressive");
1914 if (image->debug != MagickFalse)
1915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1916 "Interlace: nonprogressive");
1918 option=GetImageOption(image_info,"jpeg:extent");
1919 if (option != (const char *) NULL)
1927 jpeg_info=CloneImageInfo(image_info);
1928 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1929 if (jpeg_image != (Image *) NULL)
1939 Search for compression quality that does not exceed image extent.
1941 jpeg_info->quality=0;
1942 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1943 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1944 (void) AcquireUniqueFilename(jpeg_image->filename);
1946 for (minimum=0; minimum != maximum; )
1948 jpeg_image->quality=minimum+(maximum-minimum)/2;
1949 status=WriteJPEGImage(jpeg_info,jpeg_image);
1950 if (GetBlobSize(jpeg_image) <= extent)
1951 minimum=jpeg_image->quality+1;
1953 maximum=jpeg_image->quality-1;
1955 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1956 image->quality=minimum-1;
1957 jpeg_image=DestroyImage(jpeg_image);
1959 jpeg_info=DestroyImageInfo(jpeg_info);
1961 if ((image_info->compression != LosslessJPEGCompression) &&
1962 (image->quality <= 100))
1964 if (image->quality == UndefinedCompressionQuality)
1965 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1967 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1968 if (image->debug != MagickFalse)
1969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
1970 (double) image->quality);
1974 #if !defined(C_LOSSLESS_SUPPORTED)
1975 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1976 if (image->debug != MagickFalse)
1977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1979 if (image->quality < 100)
1980 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1981 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1988 predictor=image->quality/100; /* range 1-7 */
1989 point_transform=image->quality % 20; /* range 0-15 */
1990 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1991 if (image->debug != MagickFalse)
1993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1994 "Compression: lossless");
1995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1996 "Predictor: %d",predictor);
1997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1998 "Point Transform: %d",point_transform);
2003 sampling_factor=(const char *) NULL;
2004 value=GetImageProperty(image,"jpeg:sampling-factor");
2005 if (value != (char *) NULL)
2007 sampling_factor=value;
2008 if (image->debug != MagickFalse)
2009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2010 " Input sampling-factors=%s",sampling_factor);
2012 if (image_info->sampling_factor != (char *) NULL)
2013 sampling_factor=image_info->sampling_factor;
2014 if (sampling_factor == (const char *) NULL)
2016 if (image->quality >= 90)
2017 for (i=0; i < MAX_COMPONENTS; i++)
2019 jpeg_info.comp_info[i].h_samp_factor=1;
2020 jpeg_info.comp_info[i].v_samp_factor=1;
2035 Set sampling factor.
2038 factors=SamplingFactorToList(sampling_factor);
2039 if (factors != (char **) NULL)
2041 for (i=0; i < MAX_COMPONENTS; i++)
2043 if (factors[i] == (char *) NULL)
2045 flags=ParseGeometry(factors[i],&geometry_info);
2046 if ((flags & SigmaValue) == 0)
2047 geometry_info.sigma=geometry_info.rho;
2048 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2049 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2050 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2052 factors=(char **) RelinquishMagickMemory(factors);
2054 for ( ; i < MAX_COMPONENTS; i++)
2056 jpeg_info.comp_info[i].h_samp_factor=1;
2057 jpeg_info.comp_info[i].v_samp_factor=1;
2060 if (jpeg_info.input_components == 1)
2061 for (i=0; i < MAX_COMPONENTS; i++)
2063 jpeg_info.comp_info[i].h_samp_factor=1;
2064 jpeg_info.comp_info[i].v_samp_factor=1;
2066 jpeg_start_compress(&jpeg_info,MagickTrue);
2067 if (image->debug != MagickFalse)
2069 if (image->storage_class == PseudoClass)
2070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2071 "Storage class: PseudoClass");
2073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2074 "Storage class: DirectClass");
2075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2076 (double) image->depth);
2077 if (image->colors != 0)
2078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2079 "Number of colors: %.20g",(double) image->colors);
2081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2082 "Number of colors: unspecified");
2083 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2084 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2085 switch (image->colorspace)
2087 case CMYKColorspace:
2089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2090 "Storage class: DirectClass");
2091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2092 "Colorspace: CMYK");
2095 case YCbCrColorspace:
2096 case Rec601YCbCrColorspace:
2097 case Rec709YCbCrColorspace:
2099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2100 "Colorspace: YCbCr");
2106 switch (image->colorspace)
2108 case CMYKColorspace:
2110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2111 "Colorspace: CMYK");
2112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2113 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2114 jpeg_info.comp_info[0].h_samp_factor,
2115 jpeg_info.comp_info[0].v_samp_factor,
2116 jpeg_info.comp_info[1].h_samp_factor,
2117 jpeg_info.comp_info[1].v_samp_factor,
2118 jpeg_info.comp_info[2].h_samp_factor,
2119 jpeg_info.comp_info[2].v_samp_factor,
2120 jpeg_info.comp_info[3].h_samp_factor,
2121 jpeg_info.comp_info[3].v_samp_factor);
2124 case GRAYColorspace:
2125 case Rec601LumaColorspace:
2126 case Rec709LumaColorspace:
2128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2129 "Colorspace: GRAY");
2130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2131 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2132 jpeg_info.comp_info[0].v_samp_factor);
2137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2138 "Image colorspace is RGB");
2139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2140 "Sampling factors: %dx%d,%dx%d,%dx%d",
2141 jpeg_info.comp_info[0].h_samp_factor,
2142 jpeg_info.comp_info[0].v_samp_factor,
2143 jpeg_info.comp_info[1].h_samp_factor,
2144 jpeg_info.comp_info[1].v_samp_factor,
2145 jpeg_info.comp_info[2].h_samp_factor,
2146 jpeg_info.comp_info[2].v_samp_factor);
2149 case YCbCrColorspace:
2150 case Rec601YCbCrColorspace:
2151 case Rec709YCbCrColorspace:
2153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2154 "Colorspace: YCbCr");
2155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156 "Sampling factors: %dx%d,%dx%d,%dx%d",
2157 jpeg_info.comp_info[0].h_samp_factor,
2158 jpeg_info.comp_info[0].v_samp_factor,
2159 jpeg_info.comp_info[1].h_samp_factor,
2160 jpeg_info.comp_info[1].v_samp_factor,
2161 jpeg_info.comp_info[2].h_samp_factor,
2162 jpeg_info.comp_info[2].v_samp_factor);
2167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2169 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2170 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2171 jpeg_info.comp_info[0].h_samp_factor,
2172 jpeg_info.comp_info[0].v_samp_factor,
2173 jpeg_info.comp_info[1].h_samp_factor,
2174 jpeg_info.comp_info[1].v_samp_factor,
2175 jpeg_info.comp_info[2].h_samp_factor,
2176 jpeg_info.comp_info[2].v_samp_factor,
2177 jpeg_info.comp_info[3].h_samp_factor,
2178 jpeg_info.comp_info[3].v_samp_factor);
2184 Write JPEG profiles.
2186 value=GetImageProperty(image,"comment");
2187 if (value != (char *) NULL)
2188 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2189 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2190 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2191 if (image->profiles != (void *) NULL)
2192 WriteProfile(&jpeg_info,image);
2194 Convert MIFF to JPEG raster pixels.
2196 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2197 jpeg_info.input_components*sizeof(*jpeg_pixels));
2198 if (jpeg_pixels == (JSAMPLE *) NULL)
2199 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2200 if (setjmp(error_manager.error_recovery) != 0)
2202 jpeg_destroy_compress(&jpeg_info);
2203 if (jpeg_pixels != (unsigned char *) NULL)
2204 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2205 (void) CloseBlob(image);
2206 return(MagickFalse);
2208 scanline[0]=(JSAMPROW) jpeg_pixels;
2209 if (jpeg_info.data_precision <= 8)
2211 if ((jpeg_info.in_color_space == JCS_RGB) ||
2212 (jpeg_info.in_color_space == JCS_YCbCr))
2213 for (y=0; y < (ssize_t) image->rows; y++)
2215 register const Quantum
2221 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2222 if (p == (const Quantum *) NULL)
2225 for (x=0; x < (ssize_t) image->columns; x++)
2227 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2228 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2229 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2230 p+=GetPixelComponents(image);
2232 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2233 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2235 if (status == MagickFalse)
2239 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2240 for (y=0; y < (ssize_t) image->rows; y++)
2242 register const Quantum
2248 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2249 if (p == (const Quantum *) NULL)
2252 for (x=0; x < (ssize_t) image->columns; x++)
2254 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2255 p+=GetPixelComponents(image);
2257 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2258 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2260 if (status == MagickFalse)
2264 for (y=0; y < (ssize_t) image->rows; y++)
2266 register const Quantum
2272 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2273 if (p == (const Quantum *) NULL)
2276 for (x=0; x < (ssize_t) image->columns; x++)
2279 Convert DirectClass packets to contiguous CMYK scanlines.
2281 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2282 GetPixelRed(image,p))));
2283 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2284 GetPixelGreen(image,p))));
2285 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2286 GetPixelBlue(image,p))));
2287 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2288 GetPixelBlack(image,p))));
2289 p+=GetPixelComponents(image);
2291 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2292 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2294 if (status == MagickFalse)
2299 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2300 for (y=0; y < (ssize_t) image->rows; y++)
2302 register const Quantum
2308 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2309 if (p == (const Quantum *) NULL)
2312 for (x=0; x < (ssize_t) image->columns; x++)
2314 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2316 p+=GetPixelComponents(image);
2318 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2319 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2321 if (status == MagickFalse)
2325 if ((jpeg_info.in_color_space == JCS_RGB) ||
2326 (jpeg_info.in_color_space == JCS_YCbCr))
2327 for (y=0; y < (ssize_t) image->rows; y++)
2329 register const Quantum
2335 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2336 if (p == (const Quantum *) NULL)
2339 for (x=0; x < (ssize_t) image->columns; x++)
2341 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2342 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2343 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2344 p+=GetPixelComponents(image);
2346 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2347 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2349 if (status == MagickFalse)
2353 for (y=0; y < (ssize_t) image->rows; y++)
2355 register const Quantum
2361 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2362 if (p == (const Quantum *) NULL)
2365 for (x=0; x < (ssize_t) image->columns; x++)
2368 Convert DirectClass packets to contiguous CMYK scanlines.
2370 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2371 GetPixelRed(image,p)) >> 4));
2372 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2373 GetPixelGreen(image,p)) >> 4));
2374 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2375 GetPixelBlue(image,p)) >> 4));
2376 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2377 GetPixelBlack(image,p)) >> 4));
2378 p+=GetPixelComponents(image);
2380 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2381 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2383 if (status == MagickFalse)
2386 if (y == (ssize_t) image->rows)
2387 jpeg_finish_compress(&jpeg_info);
2389 Relinquish resources.
2391 jpeg_destroy_compress(&jpeg_info);
2392 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2393 (void) CloseBlob(image);