2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
46 #include "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/utility.h"
82 #if defined(MAGICKCORE_JPEG_DELEGATE)
83 #define JPEG_INTERNAL_OPTIONS
84 #if defined(__MINGW32__)
85 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
86 typedef unsigned char boolean;
97 #define ICC_MARKER (JPEG_APP0+2)
98 #define ICC_PROFILE "ICC_PROFILE"
99 #define IPTC_MARKER (JPEG_APP0+13)
100 #define XML_MARKER (JPEG_APP0+1)
101 #define MaxBufferExtent 8192
104 Typedef declarations.
106 #if defined(MAGICKCORE_JPEG_DELEGATE)
107 typedef struct _DestinationManager
109 struct jpeg_destination_mgr
117 } DestinationManager;
119 typedef struct _ErrorManager
134 typedef struct _SourceManager
136 struct jpeg_source_mgr
151 Forward declarations.
153 #if defined(MAGICKCORE_JPEG_DELEGATE)
154 static MagickBooleanType
155 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 % IsJPEG() returns MagickTrue if the image format type, identified by the
170 % magick string, is JPEG.
172 % The format of the IsJPEG method is:
174 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
176 % A description of each parameter follows:
178 % o magick: compare image format pattern against these bytes.
180 % o length: Specifies the length of the magick string.
183 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
187 if (memcmp(magick,"\377\330\377",3) == 0)
192 #if defined(MAGICKCORE_JPEG_DELEGATE)
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % R e a d J P E G I m a g e %
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
205 % the memory necessary for the new Image structure and returns a pointer to
208 % The format of the ReadJPEGImage method is:
210 % Image *ReadJPEGImage(const ImageInfo *image_info,
211 % ExceptionInfo *exception)
213 % A description of each parameter follows:
215 % o image_info: the image info.
217 % o exception: return any errors or warnings in this structure.
221 static boolean FillInputBuffer(j_decompress_ptr cinfo)
226 source=(SourceManager *) cinfo->src;
227 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
228 MaxBufferExtent,source->buffer);
229 if (source->manager.bytes_in_buffer == 0)
231 if (source->start_of_blob != 0)
232 ERREXIT(cinfo,JERR_INPUT_EMPTY);
233 WARNMS(cinfo,JWRN_JPEG_EOF);
234 source->buffer[0]=(JOCTET) 0xff;
235 source->buffer[1]=(JOCTET) JPEG_EOI;
236 source->manager.bytes_in_buffer=2;
238 source->manager.next_input_byte=source->buffer;
239 source->start_of_blob=FALSE;
243 static int GetCharacter(j_decompress_ptr jpeg_info)
245 if (jpeg_info->src->bytes_in_buffer == 0)
246 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
247 jpeg_info->src->bytes_in_buffer--;
248 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
251 static void InitializeSource(j_decompress_ptr cinfo)
256 source=(SourceManager *) cinfo->src;
257 source->start_of_blob=TRUE;
260 static MagickBooleanType IsITUFaxImage(const Image *image)
268 profile=GetImageProfile(image,"8bim");
269 if (profile == (const StringInfo *) NULL)
271 if (GetStringInfoLength(profile) < 5)
273 datum=GetStringInfoDatum(profile);
274 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
275 (datum[3] == 0x41) && (datum[4] == 0x58))
280 static void JPEGErrorHandler(j_common_ptr jpeg_info)
283 message[JMSG_LENGTH_MAX];
295 error_manager=(ErrorManager *) jpeg_info->client_data;
296 image=error_manager->image;
297 exception=error_manager->exception;
298 (jpeg_info->err->format_message)(jpeg_info,message);
299 if (image->debug != MagickFalse)
300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
301 "[%s] JPEG Trace: \"%s\"",image->filename,message);
302 if (error_manager->finished != MagickFalse)
303 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
304 (char *) message,"`%s'",image->filename);
306 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
307 (char *) message,"`%s'",image->filename);
308 longjmp(error_manager->error_recovery,1);
311 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
314 message[JMSG_LENGTH_MAX];
326 error_manager=(ErrorManager *) jpeg_info->client_data;
327 exception=error_manager->exception;
328 image=error_manager->image;
332 Process warning message.
334 (jpeg_info->err->format_message)(jpeg_info,message);
335 if ((jpeg_info->err->num_warnings == 0) ||
336 (jpeg_info->err->trace_level >= 3))
337 ThrowBinaryException(CorruptImageWarning,(char *) message,
339 jpeg_info->err->num_warnings++;
342 if ((image->debug != MagickFalse) &&
343 (level >= jpeg_info->err->trace_level))
346 Process trace message.
348 (jpeg_info->err->format_message)(jpeg_info,message);
349 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
350 "[%s] JPEG Trace: \"%s\"",image->filename,message);
355 static boolean ReadComment(j_decompress_ptr jpeg_info)
379 Determine length of comment.
381 error_manager=(ErrorManager *) jpeg_info->client_data;
382 exception=error_manager->exception;
383 image=error_manager->image;
384 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
385 length+=GetCharacter(jpeg_info);
389 comment=(char *) NULL;
390 if (~length >= (MaxTextExtent-1))
391 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
393 if (comment == (char *) NULL)
394 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
399 i=(ssize_t) length-1;
400 for (p=comment; i-- >= 0; p++)
401 *p=(char) GetCharacter(jpeg_info);
403 (void) SetImageProperty(image,"comment",comment,exception);
404 comment=DestroyString(comment);
408 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
428 register unsigned char
441 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
442 length+=(size_t) GetCharacter(jpeg_info);
447 (void) GetCharacter(jpeg_info);
450 for (i=0; i < 12; i++)
451 magick[i]=(char) GetCharacter(jpeg_info);
452 if (LocaleCompare(magick,ICC_PROFILE) != 0)
455 Not a ICC profile, return.
457 for (i=0; i < (ssize_t) (length-12); i++)
458 (void) GetCharacter(jpeg_info);
461 (void) GetCharacter(jpeg_info); /* id */
462 (void) GetCharacter(jpeg_info); /* markers */
464 error_manager=(ErrorManager *) jpeg_info->client_data;
465 exception=error_manager->exception;
466 image=error_manager->image;
467 profile=BlobToStringInfo((const void *) NULL,length);
468 if (profile == (StringInfo *) NULL)
469 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
471 p=GetStringInfoDatum(profile);
472 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
473 *p++=(unsigned char) GetCharacter(jpeg_info);
474 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
475 if (icc_profile != (StringInfo *) NULL)
477 ConcatenateStringInfo(icc_profile,profile);
478 profile=DestroyStringInfo(profile);
482 status=SetImageProfile(image,"icc",profile,exception);
483 profile=DestroyStringInfo(profile);
484 if (status == MagickFalse)
485 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
488 if (image->debug != MagickFalse)
489 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
490 "Profile: ICC, %.20g bytes",(double) length);
494 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
497 magick[MaxTextExtent];
514 register unsigned char
525 Determine length of binary data stored here.
527 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
528 length+=(size_t) GetCharacter(jpeg_info);
533 (void) GetCharacter(jpeg_info);
537 Validate that this was written as a Photoshop resource format slug.
539 for (i=0; i < 10; i++)
540 magick[i]=(char) GetCharacter(jpeg_info);
545 if (LocaleCompare(magick,"Photoshop ") != 0)
548 Not a IPTC profile, return.
550 for (i=0; i < (ssize_t) length; i++)
551 (void) GetCharacter(jpeg_info);
555 Remove the version number.
557 for (i=0; i < 4; i++)
558 (void) GetCharacter(jpeg_info);
564 error_manager=(ErrorManager *) jpeg_info->client_data;
565 exception=error_manager->exception;
566 image=error_manager->image;
567 profile=BlobToStringInfo((const void *) NULL,length);
568 if (profile == (StringInfo *) NULL)
569 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
571 p=GetStringInfoDatum(profile);
572 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
573 *p++=(unsigned char) GetCharacter(jpeg_info);
574 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
575 if (iptc_profile != (StringInfo *) NULL)
577 ConcatenateStringInfo(iptc_profile,profile);
578 profile=DestroyStringInfo(profile);
582 status=SetImageProfile(image,"8bim",profile,exception);
583 profile=DestroyStringInfo(profile);
584 if (status == MagickFalse)
585 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
588 if (image->debug != MagickFalse)
589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
590 "Profile: iptc, %.20g bytes",(double) length);
594 static boolean ReadProfile(j_decompress_ptr jpeg_info)
620 register unsigned char
630 Read generic profile.
632 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
633 length+=(size_t) GetCharacter(jpeg_info);
637 marker=jpeg_info->unread_marker-JPEG_APP0;
638 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
639 error_manager=(ErrorManager *) jpeg_info->client_data;
640 exception=error_manager->exception;
641 image=error_manager->image;
642 profile=BlobToStringInfo((const void *) NULL,length);
643 if (profile == (StringInfo *) NULL)
644 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
646 p=GetStringInfoDatum(profile);
647 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
648 *p++=(unsigned char) GetCharacter(jpeg_info);
651 p=GetStringInfoDatum(profile);
652 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
653 (void) CopyMagickString(name,"exif",MaxTextExtent);
654 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
660 Extract namespace from XMP profile.
662 p=GetStringInfoDatum(profile);
663 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
669 if (j < (ssize_t) GetStringInfoLength(profile))
670 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
671 (void) CopyMagickString(name,"xmp",MaxTextExtent);
674 previous_profile=GetImageProfile(image,name);
675 if (previous_profile != (const StringInfo *) NULL)
680 length=GetStringInfoLength(profile);
681 SetStringInfoLength(profile,GetStringInfoLength(profile)+
682 GetStringInfoLength(previous_profile));
683 (void) memmove(GetStringInfoDatum(profile)+
684 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
686 (void) memcpy(GetStringInfoDatum(profile),
687 GetStringInfoDatum(previous_profile),
688 GetStringInfoLength(previous_profile));
690 status=SetImageProfile(image,name,profile,exception);
691 profile=DestroyStringInfo(profile);
692 if (status == MagickFalse)
693 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
695 if (image->debug != MagickFalse)
696 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
697 "Profile: %s, %.20g bytes",name,(double) length);
701 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
706 if (number_bytes <= 0)
708 source=(SourceManager *) cinfo->src;
709 while (number_bytes > (long) source->manager.bytes_in_buffer)
711 number_bytes-=(long) source->manager.bytes_in_buffer;
712 (void) FillInputBuffer(cinfo);
714 source->manager.next_input_byte+=number_bytes;
715 source->manager.bytes_in_buffer-=number_bytes;
718 static void TerminateSource(j_decompress_ptr cinfo)
723 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
728 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
729 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
730 source=(SourceManager *) cinfo->src;
731 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
732 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
733 source=(SourceManager *) cinfo->src;
734 source->manager.init_source=InitializeSource;
735 source->manager.fill_input_buffer=FillInputBuffer;
736 source->manager.skip_input_data=SkipInputData;
737 source->manager.resync_to_restart=jpeg_resync_to_restart;
738 source->manager.term_source=TerminateSource;
739 source->manager.bytes_in_buffer=0;
740 source->manager.next_input_byte=NULL;
744 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
747 image->quality=UndefinedCompressionQuality;
748 #if defined(D_PROGRESSIVE_SUPPORTED)
749 if (image->compression == LosslessJPEGCompression)
752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
753 "Quality: 100 (lossless)");
767 Determine the JPEG compression quality from the quantization tables.
770 for (i=0; i < NUM_QUANT_TBLS; i++)
772 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
773 for (j=0; j < DCTSIZE2; j++)
774 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
776 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
777 (jpeg_info->quant_tbl_ptrs[1] != NULL))
782 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
783 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
784 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
785 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
786 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
787 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
788 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
789 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
790 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
791 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
796 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
797 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
798 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
799 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
800 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
801 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
802 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
803 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
804 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
805 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
806 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
810 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
811 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
812 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
813 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
814 for (i=0; i < 100; i++)
816 if ((qvalue < hash[i]) && (sum < sums[i]))
818 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
819 image->quality=(size_t) i+1;
820 if (image->debug != MagickFalse)
821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
822 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
823 (sum <= sums[i]) ? "exact" : "approximate");
828 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
833 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
834 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
835 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
836 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
837 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
838 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
839 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
840 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
841 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
842 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
847 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
848 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
849 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
850 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
851 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
852 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
853 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
854 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
855 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
856 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
857 667, 592, 518, 441, 369, 292, 221, 151, 86,
861 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
862 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
863 for (i=0; i < 100; i++)
865 if ((qvalue < hash[i]) && (sum < sums[i]))
867 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
868 image->quality=(size_t) i+1;
869 if (image->debug != MagickFalse)
870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
871 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
872 (sum <= sums[i]) ? "exact" : "approximate");
879 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
882 sampling_factor[MaxTextExtent];
884 switch (jpeg_info->out_color_space)
888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
889 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
890 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
891 jpeg_info->comp_info[0].v_samp_factor,
892 jpeg_info->comp_info[1].h_samp_factor,
893 jpeg_info->comp_info[1].v_samp_factor,
894 jpeg_info->comp_info[2].h_samp_factor,
895 jpeg_info->comp_info[2].v_samp_factor,
896 jpeg_info->comp_info[3].h_samp_factor,
897 jpeg_info->comp_info[3].v_samp_factor);
902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
903 "Colorspace: GRAYSCALE");
904 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
905 jpeg_info->comp_info[0].h_samp_factor,
906 jpeg_info->comp_info[0].v_samp_factor);
911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
912 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
913 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
914 jpeg_info->comp_info[0].v_samp_factor,
915 jpeg_info->comp_info[1].h_samp_factor,
916 jpeg_info->comp_info[1].v_samp_factor,
917 jpeg_info->comp_info[2].h_samp_factor,
918 jpeg_info->comp_info[2].v_samp_factor);
923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
924 jpeg_info->out_color_space);
925 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
926 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
927 jpeg_info->comp_info[0].v_samp_factor,
928 jpeg_info->comp_info[1].h_samp_factor,
929 jpeg_info->comp_info[1].v_samp_factor,
930 jpeg_info->comp_info[2].h_samp_factor,
931 jpeg_info->comp_info[2].v_samp_factor,
932 jpeg_info->comp_info[3].h_samp_factor,
933 jpeg_info->comp_info[3].v_samp_factor);
937 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
943 static Image *ReadJPEGImage(const ImageInfo *image_info,
944 ExceptionInfo *exception)
947 value[MaxTextExtent];
977 struct jpeg_decompress_struct
980 struct jpeg_error_mgr
996 assert(image_info != (const ImageInfo *) NULL);
997 assert(image_info->signature == MagickSignature);
998 if (image_info->debug != MagickFalse)
999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1000 image_info->filename);
1001 assert(exception != (ExceptionInfo *) NULL);
1002 assert(exception->signature == MagickSignature);
1003 debug=IsEventLogging();
1005 image=AcquireImage(image_info,exception);
1006 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1007 if (status == MagickFalse)
1009 image=DestroyImageList(image);
1010 return((Image *) NULL);
1013 Initialize JPEG parameters.
1015 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1016 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1017 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1018 jpeg_info.err=jpeg_std_error(&jpeg_error);
1019 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1020 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1021 jpeg_pixels=(JSAMPLE *) NULL;
1022 error_manager.exception=exception;
1023 error_manager.image=image;
1024 if (setjmp(error_manager.error_recovery) != 0)
1026 jpeg_destroy_decompress(&jpeg_info);
1027 (void) CloseBlob(image);
1028 number_pixels=(MagickSizeType) image->columns*image->rows;
1029 if (number_pixels != 0)
1030 return(GetFirstImageInList(image));
1031 return(DestroyImage(image));
1033 jpeg_info.client_data=(void *) &error_manager;
1034 jpeg_create_decompress(&jpeg_info);
1035 JPEGSourceManager(&jpeg_info,image);
1036 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1037 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1038 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1039 for (i=1; i < 16; i++)
1040 if ((i != 2) && (i != 13) && (i != 14))
1041 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1042 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1043 if ((image_info->colorspace == YCbCrColorspace) ||
1044 (image_info->colorspace == Rec601YCbCrColorspace) ||
1045 (image_info->colorspace == Rec709YCbCrColorspace))
1046 jpeg_info.out_color_space=JCS_YCbCr;
1047 if (IsITUFaxImage(image) != MagickFalse)
1049 image->colorspace=LabColorspace;
1050 jpeg_info.out_color_space=JCS_YCbCr;
1053 if (jpeg_info.out_color_space == JCS_CMYK)
1054 image->colorspace=CMYKColorspace;
1056 image->colorspace=sRGBColorspace;
1058 Set image resolution.
1061 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1062 (jpeg_info.Y_density != 1))
1064 image->resolution.x=(double) jpeg_info.X_density;
1065 image->resolution.y=(double) jpeg_info.Y_density;
1066 units=(size_t) jpeg_info.density_unit;
1069 image->units=PixelsPerInchResolution;
1071 image->units=PixelsPerCentimeterResolution;
1072 number_pixels=(MagickSizeType) image->columns*image->rows;
1073 option=GetImageOption(image_info,"jpeg:size");
1074 if (option != (const char *) NULL)
1088 flags=ParseGeometry(option,&geometry_info);
1089 if ((flags & SigmaValue) == 0)
1090 geometry_info.sigma=geometry_info.rho;
1091 jpeg_calc_output_dimensions(&jpeg_info);
1092 image->magick_columns=jpeg_info.output_width;
1093 image->magick_rows=jpeg_info.output_height;
1095 if (geometry_info.rho != 0.0)
1096 scale_factor=jpeg_info.output_width/geometry_info.rho;
1097 if ((geometry_info.sigma != 0.0) &&
1098 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1099 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1100 jpeg_info.scale_num=1U;
1101 jpeg_info.scale_denom=(unsigned int) scale_factor;
1102 jpeg_calc_output_dimensions(&jpeg_info);
1103 if (image->debug != MagickFalse)
1104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1105 "Scale factor: %.20g",(double) scale_factor);
1107 precision=(size_t) jpeg_info.data_precision;
1108 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1109 #if defined(D_LOSSLESS_SUPPORTED)
1110 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1111 JPEGInterlace : NoInterlace;
1112 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1113 LosslessJPEGCompression : JPEGCompression;
1114 if (jpeg_info.data_precision > 8)
1115 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1116 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1118 if (jpeg_info.data_precision == 16)
1119 jpeg_info.data_precision=12;
1121 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1123 image->compression=JPEGCompression;
1126 image->compression=JPEGCompression;
1127 image->interlace=JPEGInterlace;
1129 option=GetImageOption(image_info,"jpeg:colors");
1130 if (option != (const char *) NULL)
1132 /* Let the JPEG library quantize the image */
1133 jpeg_info.quantize_colors=MagickTrue;
1134 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1136 option=GetImageOption(image_info,"jpeg:block-smoothing");
1137 if (option != (const char *) NULL)
1139 jpeg_info.do_block_smoothing=MagickFalse;
1140 if (IsMagickTrue(option) != MagickFalse)
1141 jpeg_info.do_block_smoothing=MagickTrue;
1143 option=GetImageOption(image_info,"jpeg:dct-method");
1144 if (option != (const char *) NULL)
1150 if (LocaleCompare(option,"default") == 0)
1151 jpeg_info.dct_method=JDCT_DEFAULT;
1157 if (LocaleCompare(option,"fastest") == 0)
1158 jpeg_info.dct_method=JDCT_FASTEST;
1159 if (LocaleCompare(option,"float") == 0)
1160 jpeg_info.dct_method=JDCT_FLOAT;
1166 if (LocaleCompare(option,"ifast") == 0)
1167 jpeg_info.dct_method=JDCT_IFAST;
1168 if (LocaleCompare(option,"islow") == 0)
1169 jpeg_info.dct_method=JDCT_ISLOW;
1173 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1174 if (option != (const char *) NULL)
1176 jpeg_info.do_fancy_upsampling=MagickFalse;
1177 if (IsMagickTrue(option) != MagickFalse)
1178 jpeg_info.do_fancy_upsampling=MagickTrue;
1180 (void) jpeg_start_decompress(&jpeg_info);
1181 image->columns=jpeg_info.output_width;
1182 image->rows=jpeg_info.output_height;
1183 image->depth=(size_t) jpeg_info.data_precision;
1184 if (jpeg_info.out_color_space == JCS_YCbCr)
1185 image->colorspace=YCbCrColorspace;
1186 if (jpeg_info.out_color_space == JCS_CMYK)
1187 image->colorspace=CMYKColorspace;
1188 option=GetImageOption(image_info,"jpeg:colors");
1189 if (option != (const char *) NULL)
1190 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1192 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1193 if ((jpeg_info.output_components == 1) &&
1194 (jpeg_info.quantize_colors == MagickFalse))
1199 colors=(size_t) GetQuantumRange(image->depth)+1;
1200 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1201 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1203 if (image->debug != MagickFalse)
1205 if (image->interlace != NoInterlace)
1206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1207 "Interlace: progressive");
1209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1210 "Interlace: nonprogressive");
1211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1212 (int) jpeg_info.data_precision);
1213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1214 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1216 JPEGSetImageQuality(&jpeg_info,image);
1217 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1218 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1219 jpeg_info.out_color_space);
1220 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1221 if (image_info->ping != MagickFalse)
1223 jpeg_destroy_decompress(&jpeg_info);
1224 (void) CloseBlob(image);
1225 return(GetFirstImageInList(image));
1227 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1228 jpeg_info.output_components*sizeof(JSAMPLE));
1229 if (jpeg_pixels == (JSAMPLE *) NULL)
1230 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1232 Convert JPEG pixels to pixel packets.
1234 if (setjmp(error_manager.error_recovery) != 0)
1236 if (jpeg_pixels != (unsigned char *) NULL)
1237 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1238 jpeg_destroy_decompress(&jpeg_info);
1239 (void) CloseBlob(image);
1240 number_pixels=(MagickSizeType) image->columns*image->rows;
1241 if (number_pixels != 0)
1242 return(GetFirstImageInList(image));
1243 return(DestroyImage(image));
1245 if (jpeg_info.quantize_colors != MagickFalse)
1247 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1248 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1249 for (i=0; i < (ssize_t) image->colors; i++)
1251 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1252 image->colormap[i].green=image->colormap[i].red;
1253 image->colormap[i].blue=image->colormap[i].red;
1254 image->colormap[i].alpha=OpaqueAlpha;
1257 for (i=0; i < (ssize_t) image->colors; i++)
1259 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1260 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1261 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1262 image->colormap[i].alpha=OpaqueAlpha;
1265 scanline[0]=(JSAMPROW) jpeg_pixels;
1266 for (y=0; y < (ssize_t) image->rows; y++)
1274 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1276 (void) ThrowMagickException(exception,GetMagickModule(),
1277 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1281 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1282 if (q == (Quantum *) NULL)
1284 if (jpeg_info.data_precision > 8)
1286 if (jpeg_info.output_components == 1)
1287 for (x=0; x < (ssize_t) image->columns; x++)
1292 if (precision != 16)
1293 pixel=(size_t) GETJSAMPLE(*p);
1295 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1296 index=ConstrainColormapIndex(image,pixel,exception);
1297 SetPixelIndex(image,index,q);
1298 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1300 q+=GetPixelChannels(image);
1303 if (image->colorspace != CMYKColorspace)
1304 for (x=0; x < (ssize_t) image->columns; x++)
1306 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1307 (GETJSAMPLE(*p++) << 4)),q);
1308 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1309 (GETJSAMPLE(*p++) << 4)),q);
1310 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1311 (GETJSAMPLE(*p++) << 4)),q);
1312 SetPixelAlpha(image,OpaqueAlpha,q);
1313 q+=GetPixelChannels(image);
1316 for (x=0; x < (ssize_t) image->columns; x++)
1318 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1319 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1320 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1321 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1322 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1323 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1324 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1325 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1326 SetPixelAlpha(image,OpaqueAlpha,q);
1327 q+=GetPixelChannels(image);
1331 if (jpeg_info.output_components == 1)
1332 for (x=0; x < (ssize_t) image->columns; x++)
1334 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1335 SetPixelIndex(image,index,q);
1336 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1338 q+=GetPixelChannels(image);
1341 if (image->colorspace != CMYKColorspace)
1342 for (x=0; x < (ssize_t) image->columns; x++)
1344 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1345 GETJSAMPLE(*p++)),q);
1346 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1347 GETJSAMPLE(*p++)),q);
1348 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1349 GETJSAMPLE(*p++)),q);
1350 SetPixelAlpha(image,OpaqueAlpha,q);
1351 q+=GetPixelChannels(image);
1354 for (x=0; x < (ssize_t) image->columns; x++)
1356 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1357 (unsigned char) GETJSAMPLE(*p++)),q);
1358 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1359 (unsigned char) GETJSAMPLE(*p++)),q);
1360 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1361 (unsigned char) GETJSAMPLE(*p++)),q);
1362 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1363 (unsigned char) GETJSAMPLE(*p++)),q);
1364 SetPixelAlpha(image,OpaqueAlpha,q);
1365 q+=GetPixelChannels(image);
1367 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1369 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1371 if (status == MagickFalse)
1373 jpeg_abort_decompress(&jpeg_info);
1377 if (status != MagickFalse)
1379 error_manager.finished=MagickTrue;
1380 if (setjmp(error_manager.error_recovery) == 0)
1381 (void) jpeg_finish_decompress(&jpeg_info);
1384 Free jpeg resources.
1386 jpeg_destroy_decompress(&jpeg_info);
1387 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1388 (void) CloseBlob(image);
1389 return(GetFirstImageInList(image));
1394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 % R e g i s t e r J P E G I m a g e %
1402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404 % RegisterJPEGImage() adds properties for the JPEG image format to
1405 % the list of supported formats. The properties include the image format
1406 % tag, a method to read and/or write the format, whether the format
1407 % supports the saving of more than one frame to the same file or blob,
1408 % whether the format supports native in-memory I/O, and a brief
1409 % description of the format.
1411 % The format of the RegisterJPEGImage method is:
1413 % size_t RegisterJPEGImage(void)
1416 ModuleExport size_t RegisterJPEGImage(void)
1419 version[MaxTextExtent];
1425 description[] = "Joint Photographic Experts Group JFIF format";
1428 #if defined(JPEG_LIB_VERSION)
1429 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1431 entry=SetMagickInfo("JPEG");
1432 entry->thread_support=NoThreadSupport;
1433 #if defined(MAGICKCORE_JPEG_DELEGATE)
1434 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1435 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1437 entry->magick=(IsImageFormatHandler *) IsJPEG;
1438 entry->adjoin=MagickFalse;
1439 entry->description=ConstantString(description);
1440 if (*version != '\0')
1441 entry->version=ConstantString(version);
1442 entry->module=ConstantString("JPEG");
1443 (void) RegisterMagickInfo(entry);
1444 entry=SetMagickInfo("JPG");
1445 entry->thread_support=NoThreadSupport;
1446 #if defined(MAGICKCORE_JPEG_DELEGATE)
1447 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1448 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1450 entry->adjoin=MagickFalse;
1451 entry->description=ConstantString(description);
1452 if (*version != '\0')
1453 entry->version=ConstantString(version);
1454 entry->module=ConstantString("JPEG");
1455 (void) RegisterMagickInfo(entry);
1456 entry=SetMagickInfo("PJPEG");
1457 entry->thread_support=NoThreadSupport;
1458 #if defined(MAGICKCORE_JPEG_DELEGATE)
1459 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1460 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1462 entry->adjoin=MagickFalse;
1463 entry->description=ConstantString(description);
1464 if (*version != '\0')
1465 entry->version=ConstantString(version);
1466 entry->module=ConstantString("JPEG");
1467 (void) RegisterMagickInfo(entry);
1468 return(MagickImageCoderSignature);
1472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476 % U n r e g i s t e r J P E G I m a g e %
1480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482 % UnregisterJPEGImage() removes format registrations made by the
1483 % JPEG module from the list of supported formats.
1485 % The format of the UnregisterJPEGImage method is:
1487 % UnregisterJPEGImage(void)
1490 ModuleExport void UnregisterJPEGImage(void)
1492 (void) UnregisterMagickInfo("PJPG");
1493 (void) UnregisterMagickInfo("JPEG");
1494 (void) UnregisterMagickInfo("JPG");
1497 #if defined(MAGICKCORE_JPEG_DELEGATE)
1499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503 % W r i t e J P E G I m a g e %
1507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1509 % WriteJPEGImage() writes a JPEG image file and returns it. It
1510 % allocates the memory necessary for the new Image structure and returns a
1511 % pointer to the new image.
1513 % The format of the WriteJPEGImage method is:
1515 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1516 % Image *image,ExceptionInfo *exception)
1518 % A description of each parameter follows:
1520 % o image_info: the image info.
1522 % o jpeg_image: The image.
1524 % o exception: return any errors or warnings in this structure.
1528 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1533 destination=(DestinationManager *) cinfo->dest;
1534 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1535 MaxBufferExtent,destination->buffer);
1536 if (destination->manager.free_in_buffer != MaxBufferExtent)
1537 ERREXIT(cinfo,JERR_FILE_WRITE);
1538 destination->manager.next_output_byte=destination->buffer;
1542 static void InitializeDestination(j_compress_ptr cinfo)
1547 destination=(DestinationManager *) cinfo->dest;
1548 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1549 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1550 destination->manager.next_output_byte=destination->buffer;
1551 destination->manager.free_in_buffer=MaxBufferExtent;
1554 static inline size_t MagickMin(const size_t x,const size_t y)
1561 static void TerminateDestination(j_compress_ptr cinfo)
1566 destination=(DestinationManager *) cinfo->dest;
1567 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1572 count=WriteBlob(destination->image,MaxBufferExtent-
1573 destination->manager.free_in_buffer,destination->buffer);
1574 if (count != (ssize_t)
1575 (MaxBufferExtent-destination->manager.free_in_buffer))
1576 ERREXIT(cinfo,JERR_FILE_WRITE);
1580 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1602 Save image profile as a APP marker.
1605 custom_profile=AcquireStringInfo(65535L);
1606 ResetImageProfileIterator(image);
1607 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1609 register unsigned char
1612 profile=GetImageProfile(image,name);
1613 p=GetStringInfoDatum(custom_profile);
1614 if (LocaleCompare(name,"EXIF") == 0)
1615 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1617 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1618 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1619 (unsigned int) length);
1621 if (LocaleCompare(name,"ICC") == 0)
1623 register unsigned char
1627 p=GetStringInfoDatum(custom_profile);
1628 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1629 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1631 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1632 p[12]=(unsigned char) ((i/65519L)+1);
1633 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1634 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1636 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1637 custom_profile),(unsigned int) (length+tag_length));
1640 if (((LocaleCompare(name,"IPTC") == 0) ||
1641 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1647 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1649 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1650 roundup=(size_t) (length & 0x01);
1651 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1653 (void) memcpy(p,"Photoshop 3.0 ",14);
1658 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1660 p[24]=(unsigned char) (length >> 8);
1661 p[25]=(unsigned char) (length & 0xff);
1664 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1666 p[length+tag_length]='\0';
1667 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1668 custom_profile),(unsigned int) (length+tag_length+roundup));
1671 if (LocaleCompare(name,"XMP") == 0)
1677 Add namespace to XMP profile.
1679 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1680 ConcatenateStringInfo(xmp_profile,profile);
1681 GetStringInfoDatum(xmp_profile)[28]='\0';
1682 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1684 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1685 jpeg_write_marker(jpeg_info,XML_MARKER,
1686 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1688 xmp_profile=DestroyStringInfo(xmp_profile);
1690 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1691 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1692 name=GetNextImageProfile(image);
1694 custom_profile=DestroyStringInfo(custom_profile);
1697 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1702 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1703 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1704 destination=(DestinationManager *) cinfo->dest;
1705 destination->manager.init_destination=InitializeDestination;
1706 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1707 destination->manager.term_destination=TerminateDestination;
1708 destination->image=image;
1711 static char **SamplingFactorToList(const char *text)
1728 if (text == (char *) NULL)
1729 return((char **) NULL);
1731 Convert string to an ASCII list.
1734 for (p=text; *p != '\0'; p++)
1737 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1739 if (textlist == (char **) NULL)
1740 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1742 for (i=0; i < (ssize_t) lines; i++)
1744 for (q=(char *) p; *q != '\0'; q++)
1747 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1748 sizeof(*textlist[i]));
1749 if (textlist[i] == (char *) NULL)
1750 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1751 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1756 textlist[i]=(char *) NULL;
1760 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1761 Image *image,ExceptionInfo *exception)
1789 struct jpeg_compress_struct
1792 struct jpeg_error_mgr
1798 assert(image_info != (const ImageInfo *) NULL);
1799 assert(image_info->signature == MagickSignature);
1800 assert(image != (Image *) NULL);
1801 assert(image->signature == MagickSignature);
1802 if (image->debug != MagickFalse)
1803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1804 assert(exception != (ExceptionInfo *) NULL);
1805 assert(exception->signature == MagickSignature);
1806 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1807 if (status == MagickFalse)
1810 Initialize JPEG parameters.
1812 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1813 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1814 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1815 jpeg_info.client_data=(void *) image;
1816 jpeg_info.err=jpeg_std_error(&jpeg_error);
1817 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1818 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1819 error_manager.exception=exception;
1820 error_manager.image=image;
1821 jpeg_pixels=(JSAMPLE *) NULL;
1822 if (setjmp(error_manager.error_recovery) != 0)
1824 jpeg_destroy_compress(&jpeg_info);
1825 (void) CloseBlob(image);
1826 return(MagickFalse);
1828 jpeg_info.client_data=(void *) &error_manager;
1829 jpeg_create_compress(&jpeg_info);
1830 JPEGDestinationManager(&jpeg_info,image);
1831 if ((image->columns != (unsigned int) image->columns) ||
1832 (image->rows != (unsigned int) image->rows))
1833 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1834 jpeg_info.image_width=(unsigned int) image->columns;
1835 jpeg_info.image_height=(unsigned int) image->rows;
1836 jpeg_info.input_components=3;
1837 jpeg_info.data_precision=8;
1838 jpeg_info.in_color_space=JCS_RGB;
1839 switch (image->colorspace)
1841 case CMYKColorspace:
1843 jpeg_info.input_components=4;
1844 jpeg_info.in_color_space=JCS_CMYK;
1847 case YCbCrColorspace:
1848 case Rec601YCbCrColorspace:
1849 case Rec709YCbCrColorspace:
1851 jpeg_info.in_color_space=JCS_YCbCr;
1854 case GRAYColorspace:
1855 case Rec601LumaColorspace:
1856 case Rec709LumaColorspace:
1858 jpeg_info.input_components=1;
1859 jpeg_info.in_color_space=JCS_GRAYSCALE;
1864 if (IsRGBColorspace(image->colorspace) == MagickFalse)
1865 (void) TransformImageColorspace(image,RGBColorspace,exception);
1869 if ((image_info->type != TrueColorType) &&
1870 (IsImageGray(image,exception) != MagickFalse))
1872 jpeg_info.input_components=1;
1873 jpeg_info.in_color_space=JCS_GRAYSCALE;
1875 jpeg_set_defaults(&jpeg_info);
1876 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1877 jpeg_info.data_precision=8;
1879 if (sizeof(JSAMPLE) > 1)
1880 jpeg_info.data_precision=12;
1881 jpeg_info.density_unit=(UINT8) 1;
1882 if (image->debug != MagickFalse)
1883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1884 "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
1885 floor(image->resolution.y+0.5));
1886 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
1889 Set image resolution.
1891 jpeg_info.write_JFIF_header=MagickTrue;
1892 jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
1893 jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
1894 if (image->units == PixelsPerInchResolution)
1895 jpeg_info.density_unit=(UINT8) 1;
1896 if (image->units == PixelsPerCentimeterResolution)
1897 jpeg_info.density_unit=(UINT8) 2;
1899 option=GetImageOption(image_info,"jpeg:dct-method");
1900 if (option != (const char *) NULL)
1906 if (LocaleCompare(option,"default") == 0)
1907 jpeg_info.dct_method=JDCT_DEFAULT;
1913 if (LocaleCompare(option,"fastest") == 0)
1914 jpeg_info.dct_method=JDCT_FASTEST;
1915 if (LocaleCompare(option,"float") == 0)
1916 jpeg_info.dct_method=JDCT_FLOAT;
1922 if (LocaleCompare(option,"ifast") == 0)
1923 jpeg_info.dct_method=JDCT_IFAST;
1924 if (LocaleCompare(option,"islow") == 0)
1925 jpeg_info.dct_method=JDCT_ISLOW;
1929 option=GetImageOption(image_info,"jpeg:optimize-coding");
1930 if (option != (const char *) NULL)
1932 jpeg_info.optimize_coding=MagickFalse;
1933 if (IsMagickTrue(option) != MagickFalse)
1934 jpeg_info.optimize_coding=MagickTrue;
1941 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1942 image->rows*sizeof(JSAMPLE);
1943 if (length == (MagickSizeType) ((size_t) length))
1946 Perform optimization only if available memory resources permit it.
1948 status=AcquireMagickResource(MemoryResource,length);
1949 if (status != MagickFalse)
1950 jpeg_info.optimize_coding=MagickTrue;
1951 RelinquishMagickResource(MemoryResource,length);
1954 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1955 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1956 (image_info->interlace != NoInterlace))
1958 if (image->debug != MagickFalse)
1959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1960 "Interlace: progressive");
1961 jpeg_simple_progression(&jpeg_info);
1964 if (image->debug != MagickFalse)
1965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1966 "Interlace: non-progressive");
1968 if (image->debug != MagickFalse)
1969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1970 "Interlace: nonprogressive");
1972 option=GetImageOption(image_info,"jpeg:extent");
1973 if (option != (const char *) NULL)
1981 jpeg_info=CloneImageInfo(image_info);
1982 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1983 if (jpeg_image != (Image *) NULL)
1993 Search for compression quality that does not exceed image extent.
1995 jpeg_info->quality=0;
1996 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
1997 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1998 (void) AcquireUniqueFilename(jpeg_image->filename);
2000 for (minimum=0; minimum != maximum; )
2002 jpeg_image->quality=minimum+(maximum-minimum)/2;
2003 status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2004 if (GetBlobSize(jpeg_image) <= extent)
2005 minimum=jpeg_image->quality+1;
2007 maximum=jpeg_image->quality-1;
2009 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2010 image->quality=minimum-1;
2011 jpeg_image=DestroyImage(jpeg_image);
2013 jpeg_info=DestroyImageInfo(jpeg_info);
2015 if ((image_info->compression != LosslessJPEGCompression) &&
2016 (image->quality <= 100))
2018 if (image->quality == UndefinedCompressionQuality)
2019 jpeg_set_quality(&jpeg_info,92,MagickTrue);
2021 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
2022 if (image->debug != MagickFalse)
2023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2024 (double) image->quality);
2028 #if !defined(C_LOSSLESS_SUPPORTED)
2029 jpeg_set_quality(&jpeg_info,100,MagickTrue);
2030 if (image->debug != MagickFalse)
2031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2033 if (image->quality < 100)
2034 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2035 "LosslessToLossyJPEGConversion",image->filename);
2042 predictor=image->quality/100; /* range 1-7 */
2043 point_transform=image->quality % 20; /* range 0-15 */
2044 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2045 if (image->debug != MagickFalse)
2047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2048 "Compression: lossless");
2049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2050 "Predictor: %d",predictor);
2051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2052 "Point Transform: %d",point_transform);
2057 sampling_factor=(const char *) NULL;
2058 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2059 if (value != (char *) NULL)
2061 sampling_factor=value;
2062 if (image->debug != MagickFalse)
2063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2064 " Input sampling-factors=%s",sampling_factor);
2066 if (image_info->sampling_factor != (char *) NULL)
2067 sampling_factor=image_info->sampling_factor;
2068 if (sampling_factor == (const char *) NULL)
2070 if (image->quality >= 90)
2071 for (i=0; i < MAX_COMPONENTS; i++)
2073 jpeg_info.comp_info[i].h_samp_factor=1;
2074 jpeg_info.comp_info[i].v_samp_factor=1;
2089 Set sampling factor.
2092 factors=SamplingFactorToList(sampling_factor);
2093 if (factors != (char **) NULL)
2095 for (i=0; i < MAX_COMPONENTS; i++)
2097 if (factors[i] == (char *) NULL)
2099 flags=ParseGeometry(factors[i],&geometry_info);
2100 if ((flags & SigmaValue) == 0)
2101 geometry_info.sigma=geometry_info.rho;
2102 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2103 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2104 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2106 factors=(char **) RelinquishMagickMemory(factors);
2108 for ( ; i < MAX_COMPONENTS; i++)
2110 jpeg_info.comp_info[i].h_samp_factor=1;
2111 jpeg_info.comp_info[i].v_samp_factor=1;
2114 if (jpeg_info.input_components == 1)
2115 for (i=0; i < MAX_COMPONENTS; i++)
2117 jpeg_info.comp_info[i].h_samp_factor=1;
2118 jpeg_info.comp_info[i].v_samp_factor=1;
2120 jpeg_start_compress(&jpeg_info,MagickTrue);
2121 if (image->debug != MagickFalse)
2123 if (image->storage_class == PseudoClass)
2124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2125 "Storage class: PseudoClass");
2127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2128 "Storage class: DirectClass");
2129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2130 (double) image->depth);
2131 if (image->colors != 0)
2132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2133 "Number of colors: %.20g",(double) image->colors);
2135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2136 "Number of colors: unspecified");
2137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2138 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2139 switch (image->colorspace)
2141 case CMYKColorspace:
2143 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2144 "Storage class: DirectClass");
2145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2146 "Colorspace: CMYK");
2149 case YCbCrColorspace:
2150 case Rec601YCbCrColorspace:
2151 case Rec709YCbCrColorspace:
2153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2154 "Colorspace: YCbCr");
2160 switch (image->colorspace)
2162 case CMYKColorspace:
2164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2165 "Colorspace: CMYK");
2166 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2167 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2168 jpeg_info.comp_info[0].h_samp_factor,
2169 jpeg_info.comp_info[0].v_samp_factor,
2170 jpeg_info.comp_info[1].h_samp_factor,
2171 jpeg_info.comp_info[1].v_samp_factor,
2172 jpeg_info.comp_info[2].h_samp_factor,
2173 jpeg_info.comp_info[2].v_samp_factor,
2174 jpeg_info.comp_info[3].h_samp_factor,
2175 jpeg_info.comp_info[3].v_samp_factor);
2178 case GRAYColorspace:
2179 case Rec601LumaColorspace:
2180 case Rec709LumaColorspace:
2182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2183 "Colorspace: GRAY");
2184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2185 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2186 jpeg_info.comp_info[0].v_samp_factor);
2191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2192 "Image colorspace is RGB");
2193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2194 "Sampling factors: %dx%d,%dx%d,%dx%d",
2195 jpeg_info.comp_info[0].h_samp_factor,
2196 jpeg_info.comp_info[0].v_samp_factor,
2197 jpeg_info.comp_info[1].h_samp_factor,
2198 jpeg_info.comp_info[1].v_samp_factor,
2199 jpeg_info.comp_info[2].h_samp_factor,
2200 jpeg_info.comp_info[2].v_samp_factor);
2203 case YCbCrColorspace:
2204 case Rec601YCbCrColorspace:
2205 case Rec709YCbCrColorspace:
2207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2208 "Colorspace: YCbCr");
2209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2210 "Sampling factors: %dx%d,%dx%d,%dx%d",
2211 jpeg_info.comp_info[0].h_samp_factor,
2212 jpeg_info.comp_info[0].v_samp_factor,
2213 jpeg_info.comp_info[1].h_samp_factor,
2214 jpeg_info.comp_info[1].v_samp_factor,
2215 jpeg_info.comp_info[2].h_samp_factor,
2216 jpeg_info.comp_info[2].v_samp_factor);
2221 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2224 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2225 jpeg_info.comp_info[0].h_samp_factor,
2226 jpeg_info.comp_info[0].v_samp_factor,
2227 jpeg_info.comp_info[1].h_samp_factor,
2228 jpeg_info.comp_info[1].v_samp_factor,
2229 jpeg_info.comp_info[2].h_samp_factor,
2230 jpeg_info.comp_info[2].v_samp_factor,
2231 jpeg_info.comp_info[3].h_samp_factor,
2232 jpeg_info.comp_info[3].v_samp_factor);
2238 Write JPEG profiles.
2240 value=GetImageProperty(image,"comment",exception);
2241 if (value != (char *) NULL)
2242 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2243 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2244 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2245 if (image->profiles != (void *) NULL)
2246 WriteProfile(&jpeg_info,image);
2248 Convert MIFF to JPEG raster pixels.
2250 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2251 jpeg_info.input_components*sizeof(*jpeg_pixels));
2252 if (jpeg_pixels == (JSAMPLE *) NULL)
2253 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2254 if (setjmp(error_manager.error_recovery) != 0)
2256 jpeg_destroy_compress(&jpeg_info);
2257 if (jpeg_pixels != (unsigned char *) NULL)
2258 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2259 (void) CloseBlob(image);
2260 return(MagickFalse);
2262 scanline[0]=(JSAMPROW) jpeg_pixels;
2263 if (jpeg_info.data_precision <= 8)
2265 if ((jpeg_info.in_color_space == JCS_RGB) ||
2266 (jpeg_info.in_color_space == JCS_YCbCr))
2267 for (y=0; y < (ssize_t) image->rows; y++)
2269 register const Quantum
2275 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2276 if (p == (const Quantum *) NULL)
2279 for (x=0; x < (ssize_t) image->columns; x++)
2281 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2282 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2283 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2284 p+=GetPixelChannels(image);
2286 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2287 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2289 if (status == MagickFalse)
2293 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2294 for (y=0; y < (ssize_t) image->rows; y++)
2296 register const Quantum
2302 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2303 if (p == (const Quantum *) NULL)
2306 for (x=0; x < (ssize_t) image->columns; x++)
2308 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2309 p+=GetPixelChannels(image);
2311 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2312 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2314 if (status == MagickFalse)
2318 for (y=0; y < (ssize_t) image->rows; y++)
2320 register const Quantum
2326 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2327 if (p == (const Quantum *) NULL)
2330 for (x=0; x < (ssize_t) image->columns; x++)
2333 Convert DirectClass packets to contiguous CMYK scanlines.
2335 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2336 GetPixelRed(image,p))));
2337 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2338 GetPixelGreen(image,p))));
2339 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2340 GetPixelBlue(image,p))));
2341 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2342 GetPixelBlack(image,p))));
2343 p+=GetPixelChannels(image);
2345 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2346 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2348 if (status == MagickFalse)
2353 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2354 for (y=0; y < (ssize_t) image->rows; y++)
2356 register const Quantum
2362 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2363 if (p == (const Quantum *) NULL)
2366 for (x=0; x < (ssize_t) image->columns; x++)
2368 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2370 p+=GetPixelChannels(image);
2372 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2373 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2375 if (status == MagickFalse)
2379 if ((jpeg_info.in_color_space == JCS_RGB) ||
2380 (jpeg_info.in_color_space == JCS_YCbCr))
2381 for (y=0; y < (ssize_t) image->rows; y++)
2383 register const Quantum
2389 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2390 if (p == (const Quantum *) NULL)
2393 for (x=0; x < (ssize_t) image->columns; x++)
2395 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2396 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2397 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2398 p+=GetPixelChannels(image);
2400 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2401 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2403 if (status == MagickFalse)
2407 for (y=0; y < (ssize_t) image->rows; y++)
2409 register const Quantum
2415 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2416 if (p == (const Quantum *) NULL)
2419 for (x=0; x < (ssize_t) image->columns; x++)
2422 Convert DirectClass packets to contiguous CMYK scanlines.
2424 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2425 GetPixelRed(image,p)) >> 4));
2426 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2427 GetPixelGreen(image,p)) >> 4));
2428 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2429 GetPixelBlue(image,p)) >> 4));
2430 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2431 GetPixelBlack(image,p)) >> 4));
2432 p+=GetPixelChannels(image);
2434 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2435 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2437 if (status == MagickFalse)
2440 if (y == (ssize_t) image->rows)
2441 jpeg_finish_compress(&jpeg_info);
2443 Relinquish resources.
2445 jpeg_destroy_compress(&jpeg_info);
2446 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2447 (void) CloseBlob(image);