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/constitute.h"
57 #include "MagickCore/exception.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/image.h"
61 #include "MagickCore/image-private.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/log.h"
64 #include "MagickCore/magick.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/module.h"
67 #include "MagickCore/monitor.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/option.h"
70 #include "MagickCore/pixel-accessor.h"
71 #include "MagickCore/profile.h"
72 #include "MagickCore/property.h"
73 #include "MagickCore/quantum-private.h"
74 #include "MagickCore/resource_.h"
75 #include "MagickCore/splay-tree.h"
76 #include "MagickCore/static.h"
77 #include "MagickCore/string_.h"
78 #include "MagickCore/string-private.h"
79 #include "MagickCore/utility.h"
81 #if defined(MAGICKCORE_JPEG_DELEGATE)
82 #define JPEG_INTERNAL_OPTIONS
83 #if defined(__MINGW32__)
84 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
85 typedef unsigned char boolean;
96 #define ICC_MARKER (JPEG_APP0+2)
97 #define ICC_PROFILE "ICC_PROFILE"
98 #define IPTC_MARKER (JPEG_APP0+13)
99 #define XML_MARKER (JPEG_APP0+1)
100 #define MaxBufferExtent 8192
103 Typedef declarations.
105 #if defined(MAGICKCORE_JPEG_DELEGATE)
106 typedef struct _DestinationManager
108 struct jpeg_destination_mgr
116 } DestinationManager;
118 typedef struct _ErrorManager
130 typedef struct _SourceManager
132 struct jpeg_source_mgr
147 Forward declarations.
149 #if defined(MAGICKCORE_JPEG_DELEGATE)
150 static MagickBooleanType
151 WriteJPEGImage(const ImageInfo *,Image *);
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165 % IsJPEG() returns MagickTrue if the image format type, identified by the
166 % magick string, is JPEG.
168 % The format of the IsJPEG method is:
170 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
172 % A description of each parameter follows:
174 % o magick: compare image format pattern against these bytes.
176 % o length: Specifies the length of the magick string.
179 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
183 if (memcmp(magick,"\377\330\377",3) == 0)
188 #if defined(MAGICKCORE_JPEG_DELEGATE)
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 % R e a d J P E G I m a g e %
198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
201 % the memory necessary for the new Image structure and returns a pointer to
204 % The format of the ReadJPEGImage method is:
206 % Image *ReadJPEGImage(const ImageInfo *image_info,
207 % ExceptionInfo *exception)
209 % A description of each parameter follows:
211 % o image_info: the image info.
213 % o exception: return any errors or warnings in this structure.
217 static boolean FillInputBuffer(j_decompress_ptr cinfo)
222 source=(SourceManager *) cinfo->src;
223 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
224 MaxBufferExtent,source->buffer);
225 if (source->manager.bytes_in_buffer == 0)
227 if (source->start_of_blob != 0)
228 ERREXIT(cinfo,JERR_INPUT_EMPTY);
229 WARNMS(cinfo,JWRN_JPEG_EOF);
230 source->buffer[0]=(JOCTET) 0xff;
231 source->buffer[1]=(JOCTET) JPEG_EOI;
232 source->manager.bytes_in_buffer=2;
234 source->manager.next_input_byte=source->buffer;
235 source->start_of_blob=FALSE;
239 static int GetCharacter(j_decompress_ptr jpeg_info)
241 if (jpeg_info->src->bytes_in_buffer == 0)
242 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
243 jpeg_info->src->bytes_in_buffer--;
244 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
247 static void InitializeSource(j_decompress_ptr cinfo)
252 source=(SourceManager *) cinfo->src;
253 source->start_of_blob=TRUE;
256 static MagickBooleanType IsITUFaxImage(const Image *image)
264 profile=GetImageProfile(image,"8bim");
265 if (profile == (const StringInfo *) NULL)
267 if (GetStringInfoLength(profile) < 5)
269 datum=GetStringInfoDatum(profile);
270 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
271 (datum[3] == 0x41) && (datum[4] == 0x58))
276 static MagickBooleanType JPEGErrorHandler(j_common_ptr jpeg_info)
279 message[JMSG_LENGTH_MAX];
288 error_manager=(ErrorManager *) jpeg_info->client_data;
289 image=error_manager->image;
290 (jpeg_info->err->format_message)(jpeg_info,message);
291 if (image->debug != MagickFalse)
292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
293 "[%s] JPEG Trace: \"%s\"",image->filename,message);
294 if (error_manager->finished != MagickFalse)
295 (void) ThrowMagickException(&image->exception,GetMagickModule(),
296 CorruptImageWarning,(char *) message,image->filename);
298 (void) ThrowMagickException(&image->exception,GetMagickModule(),
299 CorruptImageError,(char *) message,image->filename);
300 longjmp(error_manager->error_recovery,1);
303 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
306 message[JMSG_LENGTH_MAX];
315 error_manager=(ErrorManager *) jpeg_info->client_data;
316 image=error_manager->image;
320 Process warning message.
322 (jpeg_info->err->format_message)(jpeg_info,message);
323 if ((jpeg_info->err->num_warnings == 0) ||
324 (jpeg_info->err->trace_level >= 3))
325 ThrowBinaryException(CorruptImageWarning,(char *) message,
327 jpeg_info->err->num_warnings++;
330 if ((image->debug != MagickFalse) &&
331 (level >= jpeg_info->err->trace_level))
334 Process trace message.
336 (jpeg_info->err->format_message)(jpeg_info,message);
337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
338 "[%s] JPEG Trace: \"%s\"",image->filename,message);
343 static boolean ReadComment(j_decompress_ptr jpeg_info)
364 Determine length of comment.
366 error_manager=(ErrorManager *) jpeg_info->client_data;
367 image=error_manager->image;
368 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
369 length+=GetCharacter(jpeg_info);
373 comment=(char *) NULL;
374 if (~length >= (MaxTextExtent-1))
375 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
377 if (comment == (char *) NULL)
378 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
383 i=(ssize_t) length-1;
384 for (p=comment; i-- >= 0; p++)
385 *p=(char) GetCharacter(jpeg_info);
387 (void) SetImageProperty(image,"comment",comment);
388 comment=DestroyString(comment);
392 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
409 register unsigned char
422 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
423 length+=(size_t) GetCharacter(jpeg_info);
428 (void) GetCharacter(jpeg_info);
431 for (i=0; i < 12; i++)
432 magick[i]=(char) GetCharacter(jpeg_info);
433 if (LocaleCompare(magick,ICC_PROFILE) != 0)
436 Not a ICC profile, return.
438 for (i=0; i < (ssize_t) (length-12); i++)
439 (void) GetCharacter(jpeg_info);
442 (void) GetCharacter(jpeg_info); /* id */
443 (void) GetCharacter(jpeg_info); /* markers */
445 error_manager=(ErrorManager *) jpeg_info->client_data;
446 image=error_manager->image;
447 profile=AcquireStringInfo(length);
448 if (profile == (StringInfo *) NULL)
449 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
451 p=GetStringInfoDatum(profile);
452 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
453 *p++=(unsigned char) GetCharacter(jpeg_info);
454 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
455 if (icc_profile != (StringInfo *) NULL)
457 ConcatenateStringInfo(icc_profile,profile);
458 profile=DestroyStringInfo(profile);
462 status=SetImageProfile(image,"icc",profile);
463 profile=DestroyStringInfo(profile);
464 if (status == MagickFalse)
465 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
468 if (image->debug != MagickFalse)
469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
470 "Profile: ICC, %.20g bytes",(double) length);
474 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
477 magick[MaxTextExtent];
491 register unsigned char
502 Determine length of binary data stored here.
504 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
505 length+=(size_t) GetCharacter(jpeg_info);
510 (void) GetCharacter(jpeg_info);
514 Validate that this was written as a Photoshop resource format slug.
516 for (i=0; i < 10; i++)
517 magick[i]=(char) GetCharacter(jpeg_info);
522 if (LocaleCompare(magick,"Photoshop ") != 0)
525 Not a IPTC profile, return.
527 for (i=0; i < (ssize_t) length; i++)
528 (void) GetCharacter(jpeg_info);
532 Remove the version number.
534 for (i=0; i < 4; i++)
535 (void) GetCharacter(jpeg_info);
541 error_manager=(ErrorManager *) jpeg_info->client_data;
542 image=error_manager->image;
543 profile=AcquireStringInfo(length);
544 if (profile == (StringInfo *) NULL)
545 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
547 p=GetStringInfoDatum(profile);
548 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
549 *p++=(unsigned char) GetCharacter(jpeg_info);
550 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
551 if (iptc_profile != (StringInfo *) NULL)
553 ConcatenateStringInfo(iptc_profile,profile);
554 profile=DestroyStringInfo(profile);
558 status=SetImageProfile(image,"8bim",profile);
559 profile=DestroyStringInfo(profile);
560 if (status == MagickFalse)
561 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
564 if (image->debug != MagickFalse)
565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
566 "Profile: iptc, %.20g bytes",(double) length);
570 static boolean ReadProfile(j_decompress_ptr jpeg_info)
590 register unsigned char
600 Read generic profile.
602 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
603 length+=(size_t) GetCharacter(jpeg_info);
607 marker=jpeg_info->unread_marker-JPEG_APP0;
608 (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
609 error_manager=(ErrorManager *) jpeg_info->client_data;
610 image=error_manager->image;
611 profile=AcquireStringInfo(length);
612 if (profile == (StringInfo *) NULL)
613 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
615 p=GetStringInfoDatum(profile);
616 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
617 *p++=(unsigned char) GetCharacter(jpeg_info);
620 p=GetStringInfoDatum(profile);
621 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
622 (void) CopyMagickString(name,"exif",MaxTextExtent);
623 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
629 Extract namespace from XMP profile.
631 p=GetStringInfoDatum(profile);
632 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
638 if (j < (ssize_t) GetStringInfoLength(profile))
639 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
640 (void) CopyMagickString(name,"xmp",MaxTextExtent);
643 status=SetImageProfile(image,name,profile);
644 profile=DestroyStringInfo(profile);
645 if (status == MagickFalse)
646 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
648 if (image->debug != MagickFalse)
649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
650 "Profile: %s, %.20g bytes",name,(double) length);
654 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
659 if (number_bytes <= 0)
661 source=(SourceManager *) cinfo->src;
662 while (number_bytes > (long) source->manager.bytes_in_buffer)
664 number_bytes-=(long) source->manager.bytes_in_buffer;
665 (void) FillInputBuffer(cinfo);
667 source->manager.next_input_byte+=number_bytes;
668 source->manager.bytes_in_buffer-=number_bytes;
671 static void TerminateSource(j_decompress_ptr cinfo)
676 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
681 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
682 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
683 source=(SourceManager *) cinfo->src;
684 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
685 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
686 source=(SourceManager *) cinfo->src;
687 source->manager.init_source=InitializeSource;
688 source->manager.fill_input_buffer=FillInputBuffer;
689 source->manager.skip_input_data=SkipInputData;
690 source->manager.resync_to_restart=jpeg_resync_to_restart;
691 source->manager.term_source=TerminateSource;
692 source->manager.bytes_in_buffer=0;
693 source->manager.next_input_byte=NULL;
697 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
700 image->quality=UndefinedCompressionQuality;
701 #if defined(D_PROGRESSIVE_SUPPORTED)
702 if (image->compression == LosslessJPEGCompression)
705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
706 "Quality: 100 (lossless)");
720 Determine the JPEG compression quality from the quantization tables.
723 for (i=0; i < NUM_QUANT_TBLS; i++)
725 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
726 for (j=0; j < DCTSIZE2; j++)
727 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
729 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
730 (jpeg_info->quant_tbl_ptrs[1] != NULL))
735 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
736 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
737 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
738 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
739 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
740 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
741 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
742 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
743 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
744 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
749 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
750 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
751 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
752 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
753 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
754 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
755 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
756 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
757 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
758 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
759 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
763 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
764 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
765 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
766 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
767 for (i=0; i < 100; i++)
769 if ((qvalue < hash[i]) && (sum < sums[i]))
771 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
772 image->quality=(size_t) i+1;
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
775 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
776 (sum <= sums[i]) ? "exact" : "approximate");
781 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
786 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
787 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
788 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
789 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
790 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
791 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
792 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
793 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
794 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
795 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
800 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
801 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
802 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
803 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
804 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
805 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
806 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
807 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
808 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
809 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
810 667, 592, 518, 441, 369, 292, 221, 151, 86,
814 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
815 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
816 for (i=0; i < 100; i++)
818 if ((qvalue < hash[i]) && (sum < sums[i]))
820 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
821 image->quality=(size_t) i+1;
822 if (image->debug != MagickFalse)
823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
824 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
825 (sum <= sums[i]) ? "exact" : "approximate");
832 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
835 sampling_factor[MaxTextExtent];
837 switch (jpeg_info->out_color_space)
841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
842 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
843 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
844 jpeg_info->comp_info[0].v_samp_factor,
845 jpeg_info->comp_info[1].h_samp_factor,
846 jpeg_info->comp_info[1].v_samp_factor,
847 jpeg_info->comp_info[2].h_samp_factor,
848 jpeg_info->comp_info[2].v_samp_factor,
849 jpeg_info->comp_info[3].h_samp_factor,
850 jpeg_info->comp_info[3].v_samp_factor);
855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
856 "Colorspace: GRAYSCALE");
857 (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
858 jpeg_info->comp_info[0].h_samp_factor,
859 jpeg_info->comp_info[0].v_samp_factor);
864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
865 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
866 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
867 jpeg_info->comp_info[0].v_samp_factor,
868 jpeg_info->comp_info[1].h_samp_factor,
869 jpeg_info->comp_info[1].v_samp_factor,
870 jpeg_info->comp_info[2].h_samp_factor,
871 jpeg_info->comp_info[2].v_samp_factor);
876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
877 jpeg_info->out_color_space);
878 (void) FormatLocaleString(sampling_factor,MaxTextExtent,
879 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
880 jpeg_info->comp_info[0].v_samp_factor,
881 jpeg_info->comp_info[1].h_samp_factor,
882 jpeg_info->comp_info[1].v_samp_factor,
883 jpeg_info->comp_info[2].h_samp_factor,
884 jpeg_info->comp_info[2].v_samp_factor,
885 jpeg_info->comp_info[3].h_samp_factor,
886 jpeg_info->comp_info[3].v_samp_factor);
890 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
891 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
895 static Image *ReadJPEGImage(const ImageInfo *image_info,
896 ExceptionInfo *exception)
899 value[MaxTextExtent];
929 struct jpeg_decompress_struct
932 struct jpeg_error_mgr
948 assert(image_info != (const ImageInfo *) NULL);
949 assert(image_info->signature == MagickSignature);
950 if (image_info->debug != MagickFalse)
951 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
952 image_info->filename);
953 assert(exception != (ExceptionInfo *) NULL);
954 assert(exception->signature == MagickSignature);
955 debug=IsEventLogging();
957 image=AcquireImage(image_info);
958 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
959 if (status == MagickFalse)
961 image=DestroyImageList(image);
962 return((Image *) NULL);
965 Initialize JPEG parameters.
967 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
968 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
969 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
970 jpeg_info.err=jpeg_std_error(&jpeg_error);
971 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
972 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
973 jpeg_pixels=(JSAMPLE *) NULL;
974 error_manager.image=image;
975 if (setjmp(error_manager.error_recovery) != 0)
977 jpeg_destroy_decompress(&jpeg_info);
978 (void) CloseBlob(image);
979 number_pixels=(MagickSizeType) image->columns*image->rows;
980 if (number_pixels != 0)
981 return(GetFirstImageInList(image));
982 InheritException(exception,&image->exception);
983 return(DestroyImage(image));
985 jpeg_info.client_data=(void *) &error_manager;
986 jpeg_create_decompress(&jpeg_info);
987 JPEGSourceManager(&jpeg_info,image);
988 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
989 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
990 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
991 for (i=1; i < 16; i++)
992 if ((i != 2) && (i != 13) && (i != 14))
993 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
994 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
995 if ((image_info->colorspace == YCbCrColorspace) ||
996 (image_info->colorspace == Rec601YCbCrColorspace) ||
997 (image_info->colorspace == Rec709YCbCrColorspace))
998 jpeg_info.out_color_space=JCS_YCbCr;
999 if (IsITUFaxImage(image) != MagickFalse)
1001 image->colorspace=LabColorspace;
1002 jpeg_info.out_color_space=JCS_YCbCr;
1005 if (jpeg_info.out_color_space == JCS_CMYK)
1006 image->colorspace=CMYKColorspace;
1008 Set image resolution.
1011 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1012 (jpeg_info.Y_density != 1))
1014 image->x_resolution=(double) jpeg_info.X_density;
1015 image->y_resolution=(double) jpeg_info.Y_density;
1016 units=(size_t) jpeg_info.density_unit;
1019 image->units=PixelsPerInchResolution;
1021 image->units=PixelsPerCentimeterResolution;
1022 number_pixels=(MagickSizeType) image->columns*image->rows;
1023 option=GetImageOption(image_info,"jpeg:size");
1024 if (option != (const char *) NULL)
1038 flags=ParseGeometry(option,&geometry_info);
1039 if ((flags & SigmaValue) == 0)
1040 geometry_info.sigma=geometry_info.rho;
1041 jpeg_calc_output_dimensions(&jpeg_info);
1042 image->magick_columns=jpeg_info.output_width;
1043 image->magick_rows=jpeg_info.output_height;
1045 if (geometry_info.rho != 0.0)
1046 scale_factor=jpeg_info.output_width/geometry_info.rho;
1047 if ((geometry_info.sigma != 0.0) &&
1048 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1049 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1050 jpeg_info.scale_num=1U;
1051 jpeg_info.scale_denom=(unsigned int) scale_factor;
1052 jpeg_calc_output_dimensions(&jpeg_info);
1053 if (image->debug != MagickFalse)
1054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1055 "Scale factor: %.20g",(double) scale_factor);
1057 precision=(size_t) jpeg_info.data_precision;
1058 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1059 #if defined(D_LOSSLESS_SUPPORTED)
1060 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1061 JPEGInterlace : NoInterlace;
1062 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1063 LosslessJPEGCompression : JPEGCompression;
1064 if (jpeg_info.data_precision > 8)
1065 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1066 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1068 if (jpeg_info.data_precision == 16)
1069 jpeg_info.data_precision=12;
1071 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1073 image->compression=JPEGCompression;
1076 image->compression=JPEGCompression;
1077 image->interlace=JPEGInterlace;
1079 if ((image_info->colors > 8) && (image_info->colors <= 256))
1082 Let the JPEG library quantize for us.
1084 jpeg_info.quantize_colors=MagickTrue;
1085 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1087 option=GetImageOption(image_info,"jpeg:block-smoothing");
1088 if (option != (const char *) NULL)
1090 jpeg_info.do_block_smoothing=MagickFalse;
1091 if (IsMagickTrue(option) != MagickFalse)
1092 jpeg_info.do_block_smoothing=MagickTrue;
1094 option=GetImageOption(image_info,"jpeg:dct-method");
1095 if (option != (const char *) NULL)
1101 if (LocaleCompare(option,"default") == 0)
1102 jpeg_info.dct_method=JDCT_DEFAULT;
1108 if (LocaleCompare(option,"fastest") == 0)
1109 jpeg_info.dct_method=JDCT_FASTEST;
1110 if (LocaleCompare(option,"float") == 0)
1111 jpeg_info.dct_method=JDCT_FLOAT;
1117 if (LocaleCompare(option,"ifast") == 0)
1118 jpeg_info.dct_method=JDCT_IFAST;
1119 if (LocaleCompare(option,"islow") == 0)
1120 jpeg_info.dct_method=JDCT_ISLOW;
1124 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1125 if (option != (const char *) NULL)
1127 jpeg_info.do_fancy_upsampling=MagickFalse;
1128 if (IsMagickTrue(option) != MagickFalse)
1129 jpeg_info.do_fancy_upsampling=MagickTrue;
1131 (void) jpeg_start_decompress(&jpeg_info);
1132 image->columns=jpeg_info.output_width;
1133 image->rows=jpeg_info.output_height;
1134 image->depth=(size_t) jpeg_info.data_precision;
1135 if (jpeg_info.out_color_space == JCS_YCbCr)
1136 image->colorspace=YCbCrColorspace;
1137 if (jpeg_info.out_color_space == JCS_CMYK)
1138 image->colorspace=CMYKColorspace;
1139 if ((image_info->colors != 0) && (image_info->colors <= 256))
1140 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1141 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1142 if ((jpeg_info.output_components == 1) &&
1143 (jpeg_info.quantize_colors == MagickFalse))
1148 colors=(size_t) GetQuantumRange(image->depth)+1;
1149 if (AcquireImageColormap(image,colors) == MagickFalse)
1150 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1152 if (image->debug != MagickFalse)
1154 if (image->interlace != NoInterlace)
1155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1156 "Interlace: progressive");
1158 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1159 "Interlace: nonprogressive");
1160 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1161 (int) jpeg_info.data_precision);
1162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1163 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1165 JPEGSetImageQuality(&jpeg_info,image);
1166 JPEGSetImageSamplingFactor(&jpeg_info,image);
1167 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1168 jpeg_info.out_color_space);
1169 (void) SetImageProperty(image,"jpeg:colorspace",value);
1170 if (image_info->ping != MagickFalse)
1172 jpeg_destroy_decompress(&jpeg_info);
1173 (void) CloseBlob(image);
1174 return(GetFirstImageInList(image));
1176 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1177 jpeg_info.output_components*sizeof(JSAMPLE));
1178 if (jpeg_pixels == (JSAMPLE *) NULL)
1179 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1181 Convert JPEG pixels to pixel packets.
1183 if (setjmp(error_manager.error_recovery) != 0)
1185 if (jpeg_pixels != (unsigned char *) NULL)
1186 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1187 jpeg_destroy_decompress(&jpeg_info);
1188 (void) CloseBlob(image);
1189 number_pixels=(MagickSizeType) image->columns*image->rows;
1190 if (number_pixels != 0)
1191 return(GetFirstImageInList(image));
1192 return(DestroyImage(image));
1194 if (jpeg_info.quantize_colors != MagickFalse)
1196 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1197 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1198 for (i=0; i < (ssize_t) image->colors; i++)
1200 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1201 image->colormap[i].green=image->colormap[i].red;
1202 image->colormap[i].blue=image->colormap[i].red;
1203 image->colormap[i].alpha=OpaqueAlpha;
1206 for (i=0; i < (ssize_t) image->colors; i++)
1208 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1209 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1210 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1211 image->colormap[i].alpha=OpaqueAlpha;
1214 scanline[0]=(JSAMPROW) jpeg_pixels;
1215 for (y=0; y < (ssize_t) image->rows; y++)
1223 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1225 (void) ThrowMagickException(exception,GetMagickModule(),
1226 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1230 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1231 if (q == (const Quantum *) NULL)
1233 if (jpeg_info.data_precision > 8)
1235 if (jpeg_info.output_components == 1)
1236 for (x=0; x < (ssize_t) image->columns; x++)
1241 if (precision != 16)
1242 pixel=(size_t) GETJSAMPLE(*p);
1244 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1245 index=ConstrainColormapIndex(image,pixel);
1246 SetPixelIndex(image,index,q);
1247 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1249 q+=GetPixelChannels(image);
1252 if (image->colorspace != CMYKColorspace)
1253 for (x=0; x < (ssize_t) image->columns; x++)
1255 SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1256 (GETJSAMPLE(*p++) << 4)),q);
1257 SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1258 (GETJSAMPLE(*p++) << 4)),q);
1259 SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1260 (GETJSAMPLE(*p++) << 4)),q);
1261 SetPixelAlpha(image,OpaqueAlpha,q);
1262 q+=GetPixelChannels(image);
1265 for (x=0; x < (ssize_t) image->columns; x++)
1267 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1268 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1269 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1270 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1271 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1272 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1273 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1274 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1275 SetPixelAlpha(image,OpaqueAlpha,q);
1276 q+=GetPixelChannels(image);
1280 if (jpeg_info.output_components == 1)
1281 for (x=0; x < (ssize_t) image->columns; x++)
1283 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1284 SetPixelIndex(image,index,q);
1285 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1287 q+=GetPixelChannels(image);
1290 if (image->colorspace != CMYKColorspace)
1291 for (x=0; x < (ssize_t) image->columns; x++)
1293 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1294 GETJSAMPLE(*p++)),q);
1295 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1296 GETJSAMPLE(*p++)),q);
1297 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1298 GETJSAMPLE(*p++)),q);
1299 SetPixelAlpha(image,OpaqueAlpha,q);
1300 q+=GetPixelChannels(image);
1303 for (x=0; x < (ssize_t) image->columns; x++)
1305 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1306 (unsigned char) GETJSAMPLE(*p++)),q);
1307 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1308 (unsigned char) GETJSAMPLE(*p++)),q);
1309 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1310 (unsigned char) GETJSAMPLE(*p++)),q);
1311 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1312 (unsigned char) GETJSAMPLE(*p++)),q);
1313 SetPixelAlpha(image,OpaqueAlpha,q);
1314 q+=GetPixelChannels(image);
1316 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1318 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1320 if (status == MagickFalse)
1322 jpeg_abort_decompress(&jpeg_info);
1326 if (status != MagickFalse)
1328 error_manager.finished=MagickTrue;
1329 if (setjmp(error_manager.error_recovery) == 0)
1330 (void) jpeg_finish_decompress(&jpeg_info);
1333 Free jpeg resources.
1335 jpeg_destroy_decompress(&jpeg_info);
1336 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1337 (void) CloseBlob(image);
1338 return(GetFirstImageInList(image));
1343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 % R e g i s t e r J P E G I m a g e %
1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 % RegisterJPEGImage() adds properties for the JPEG image format to
1354 % the list of supported formats. The properties include the image format
1355 % tag, a method to read and/or write the format, whether the format
1356 % supports the saving of more than one frame to the same file or blob,
1357 % whether the format supports native in-memory I/O, and a brief
1358 % description of the format.
1360 % The format of the RegisterJPEGImage method is:
1362 % size_t RegisterJPEGImage(void)
1365 ModuleExport size_t RegisterJPEGImage(void)
1368 version[MaxTextExtent];
1374 description[] = "Joint Photographic Experts Group JFIF format";
1377 #if defined(JPEG_LIB_VERSION)
1378 (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1380 entry=SetMagickInfo("JPEG");
1381 entry->thread_support=NoThreadSupport;
1382 #if defined(MAGICKCORE_JPEG_DELEGATE)
1383 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1384 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1386 entry->magick=(IsImageFormatHandler *) IsJPEG;
1387 entry->adjoin=MagickFalse;
1388 entry->description=ConstantString(description);
1389 if (*version != '\0')
1390 entry->version=ConstantString(version);
1391 entry->module=ConstantString("JPEG");
1392 (void) RegisterMagickInfo(entry);
1393 entry=SetMagickInfo("JPG");
1394 entry->thread_support=NoThreadSupport;
1395 #if defined(MAGICKCORE_JPEG_DELEGATE)
1396 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1397 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1399 entry->adjoin=MagickFalse;
1400 entry->description=ConstantString(description);
1401 if (*version != '\0')
1402 entry->version=ConstantString(version);
1403 entry->module=ConstantString("JPEG");
1404 (void) RegisterMagickInfo(entry);
1405 entry=SetMagickInfo("PJPEG");
1406 entry->thread_support=NoThreadSupport;
1407 #if defined(MAGICKCORE_JPEG_DELEGATE)
1408 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1409 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1411 entry->adjoin=MagickFalse;
1412 entry->description=ConstantString(description);
1413 if (*version != '\0')
1414 entry->version=ConstantString(version);
1415 entry->module=ConstantString("JPEG");
1416 (void) RegisterMagickInfo(entry);
1417 return(MagickImageCoderSignature);
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425 % U n r e g i s t e r J P E G I m a g e %
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1431 % UnregisterJPEGImage() removes format registrations made by the
1432 % JPEG module from the list of supported formats.
1434 % The format of the UnregisterJPEGImage method is:
1436 % UnregisterJPEGImage(void)
1439 ModuleExport void UnregisterJPEGImage(void)
1441 (void) UnregisterMagickInfo("PJPG");
1442 (void) UnregisterMagickInfo("JPEG");
1443 (void) UnregisterMagickInfo("JPG");
1446 #if defined(MAGICKCORE_JPEG_DELEGATE)
1448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452 % W r i t e J P E G I m a g e %
1456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458 % WriteJPEGImage() writes a JPEG image file and returns it. It
1459 % allocates the memory necessary for the new Image structure and returns a
1460 % pointer to the new image.
1462 % The format of the WriteJPEGImage method is:
1464 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1467 % A description of each parameter follows:
1469 % o image_info: the image info.
1471 % o jpeg_image: The image.
1476 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1481 destination=(DestinationManager *) cinfo->dest;
1482 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1483 MaxBufferExtent,destination->buffer);
1484 if (destination->manager.free_in_buffer != MaxBufferExtent)
1485 ERREXIT(cinfo,JERR_FILE_WRITE);
1486 destination->manager.next_output_byte=destination->buffer;
1490 static void InitializeDestination(j_compress_ptr cinfo)
1495 destination=(DestinationManager *) cinfo->dest;
1496 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1497 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1498 destination->manager.next_output_byte=destination->buffer;
1499 destination->manager.free_in_buffer=MaxBufferExtent;
1502 static inline size_t MagickMin(const size_t x,const size_t y)
1509 static void TerminateDestination(j_compress_ptr cinfo)
1514 destination=(DestinationManager *) cinfo->dest;
1515 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1520 count=WriteBlob(destination->image,MaxBufferExtent-
1521 destination->manager.free_in_buffer,destination->buffer);
1522 if (count != (ssize_t)
1523 (MaxBufferExtent-destination->manager.free_in_buffer))
1524 ERREXIT(cinfo,JERR_FILE_WRITE);
1528 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1550 Save image profile as a APP marker.
1553 custom_profile=AcquireStringInfo(65535L);
1554 ResetImageProfileIterator(image);
1555 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1557 register unsigned char
1560 profile=GetImageProfile(image,name);
1561 p=GetStringInfoDatum(custom_profile);
1562 if (LocaleCompare(name,"EXIF") == 0)
1563 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1565 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1566 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1567 (unsigned int) length);
1569 if (LocaleCompare(name,"ICC") == 0)
1571 register unsigned char
1575 p=GetStringInfoDatum(custom_profile);
1576 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1577 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1579 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1580 p[12]=(unsigned char) ((i/65519L)+1);
1581 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1582 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1584 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1585 custom_profile),(unsigned int) (length+tag_length));
1588 if (((LocaleCompare(name,"IPTC") == 0) ||
1589 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1595 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1597 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1598 roundup=(size_t) (length & 0x01);
1599 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1601 (void) memcpy(p,"Photoshop 3.0 ",14);
1606 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1608 p[24]=(unsigned char) (length >> 8);
1609 p[25]=(unsigned char) (length & 0xff);
1612 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1614 p[length+tag_length]='\0';
1615 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1616 custom_profile),(unsigned int) (length+tag_length+roundup));
1619 if (LocaleCompare(name,"XMP") == 0)
1625 Add namespace to XMP profile.
1627 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1628 ConcatenateStringInfo(xmp_profile,profile);
1629 GetStringInfoDatum(xmp_profile)[28]='\0';
1630 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1632 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1633 jpeg_write_marker(jpeg_info,XML_MARKER,
1634 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1636 xmp_profile=DestroyStringInfo(xmp_profile);
1638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1639 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1640 name=GetNextImageProfile(image);
1642 custom_profile=DestroyStringInfo(custom_profile);
1645 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1650 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1651 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1652 destination=(DestinationManager *) cinfo->dest;
1653 destination->manager.init_destination=InitializeDestination;
1654 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1655 destination->manager.term_destination=TerminateDestination;
1656 destination->image=image;
1659 static char **SamplingFactorToList(const char *text)
1676 if (text == (char *) NULL)
1677 return((char **) NULL);
1679 Convert string to an ASCII list.
1682 for (p=text; *p != '\0'; p++)
1685 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1687 if (textlist == (char **) NULL)
1688 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1690 for (i=0; i < (ssize_t) lines; i++)
1692 for (q=(char *) p; *q != '\0'; q++)
1695 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1696 sizeof(*textlist[i]));
1697 if (textlist[i] == (char *) NULL)
1698 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1699 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1704 textlist[i]=(char *) NULL;
1708 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1737 struct jpeg_compress_struct
1740 struct jpeg_error_mgr
1746 assert(image_info != (const ImageInfo *) NULL);
1747 assert(image_info->signature == MagickSignature);
1748 assert(image != (Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 if (image->debug != MagickFalse)
1751 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1752 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1753 if (status == MagickFalse)
1756 Initialize JPEG parameters.
1758 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1759 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1760 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1761 jpeg_info.client_data=(void *) image;
1762 jpeg_info.err=jpeg_std_error(&jpeg_error);
1763 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1764 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1765 error_manager.image=image;
1766 jpeg_pixels=(JSAMPLE *) NULL;
1767 if (setjmp(error_manager.error_recovery) != 0)
1769 jpeg_destroy_compress(&jpeg_info);
1770 (void) CloseBlob(image);
1771 return(MagickFalse);
1773 jpeg_info.client_data=(void *) &error_manager;
1774 jpeg_create_compress(&jpeg_info);
1775 JPEGDestinationManager(&jpeg_info,image);
1776 if ((image->columns != (unsigned int) image->columns) ||
1777 (image->rows != (unsigned int) image->rows))
1778 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1779 jpeg_info.image_width=(unsigned int) image->columns;
1780 jpeg_info.image_height=(unsigned int) image->rows;
1781 jpeg_info.input_components=3;
1782 jpeg_info.data_precision=8;
1783 jpeg_info.in_color_space=JCS_RGB;
1784 switch (image->colorspace)
1786 case CMYKColorspace:
1788 jpeg_info.input_components=4;
1789 jpeg_info.in_color_space=JCS_CMYK;
1792 case YCbCrColorspace:
1793 case Rec601YCbCrColorspace:
1794 case Rec709YCbCrColorspace:
1796 jpeg_info.in_color_space=JCS_YCbCr;
1799 case GRAYColorspace:
1800 case Rec601LumaColorspace:
1801 case Rec709LumaColorspace:
1803 jpeg_info.input_components=1;
1804 jpeg_info.in_color_space=JCS_GRAYSCALE;
1809 if (image->colorspace != RGBColorspace)
1810 (void) TransformImageColorspace(image,RGBColorspace);
1814 if ((image_info->type != TrueColorType) &&
1815 (IsImageGray(image,&image->exception) != MagickFalse))
1817 jpeg_info.input_components=1;
1818 jpeg_info.in_color_space=JCS_GRAYSCALE;
1820 jpeg_set_defaults(&jpeg_info);
1821 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1822 jpeg_info.data_precision=8;
1824 if (sizeof(JSAMPLE) > 1)
1825 jpeg_info.data_precision=12;
1826 jpeg_info.density_unit=(UINT8) 1;
1827 if (image->debug != MagickFalse)
1828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1829 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1830 floor(image->y_resolution+0.5));
1831 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1834 Set image resolution.
1836 jpeg_info.write_JFIF_header=MagickTrue;
1837 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1838 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1839 if (image->units == PixelsPerInchResolution)
1840 jpeg_info.density_unit=(UINT8) 1;
1841 if (image->units == PixelsPerCentimeterResolution)
1842 jpeg_info.density_unit=(UINT8) 2;
1844 option=GetImageOption(image_info,"jpeg:dct-method");
1845 if (option != (const char *) NULL)
1851 if (LocaleCompare(option,"default") == 0)
1852 jpeg_info.dct_method=JDCT_DEFAULT;
1858 if (LocaleCompare(option,"fastest") == 0)
1859 jpeg_info.dct_method=JDCT_FASTEST;
1860 if (LocaleCompare(option,"float") == 0)
1861 jpeg_info.dct_method=JDCT_FLOAT;
1867 if (LocaleCompare(option,"ifast") == 0)
1868 jpeg_info.dct_method=JDCT_IFAST;
1869 if (LocaleCompare(option,"islow") == 0)
1870 jpeg_info.dct_method=JDCT_ISLOW;
1874 option=GetImageOption(image_info,"jpeg:optimize-coding");
1875 if (option != (const char *) NULL)
1877 jpeg_info.optimize_coding=MagickFalse;
1878 if (IsMagickTrue(option) != MagickFalse)
1879 jpeg_info.optimize_coding=MagickTrue;
1886 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1887 image->rows*sizeof(JSAMPLE);
1888 if (length == (MagickSizeType) ((size_t) length))
1891 Perform optimization only if available memory resources permit it.
1893 status=AcquireMagickResource(MemoryResource,length);
1894 if (status != MagickFalse)
1895 jpeg_info.optimize_coding=MagickTrue;
1896 RelinquishMagickResource(MemoryResource,length);
1899 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1900 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1901 (image_info->interlace != NoInterlace))
1903 if (image->debug != MagickFalse)
1904 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1905 "Interlace: progressive");
1906 jpeg_simple_progression(&jpeg_info);
1909 if (image->debug != MagickFalse)
1910 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1911 "Interlace: non-progressive");
1913 if (image->debug != MagickFalse)
1914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1915 "Interlace: nonprogressive");
1917 option=GetImageOption(image_info,"jpeg:extent");
1918 if (option != (const char *) NULL)
1926 jpeg_info=CloneImageInfo(image_info);
1927 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1928 if (jpeg_image != (Image *) NULL)
1938 Search for compression quality that does not exceed image extent.
1940 jpeg_info->quality=0;
1941 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1942 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1943 (void) AcquireUniqueFilename(jpeg_image->filename);
1945 for (minimum=0; minimum != maximum; )
1947 jpeg_image->quality=minimum+(maximum-minimum)/2;
1948 status=WriteJPEGImage(jpeg_info,jpeg_image);
1949 if (GetBlobSize(jpeg_image) <= extent)
1950 minimum=jpeg_image->quality+1;
1952 maximum=jpeg_image->quality-1;
1954 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1955 image->quality=minimum-1;
1956 jpeg_image=DestroyImage(jpeg_image);
1958 jpeg_info=DestroyImageInfo(jpeg_info);
1960 if ((image_info->compression != LosslessJPEGCompression) &&
1961 (image->quality <= 100))
1963 if (image->quality == UndefinedCompressionQuality)
1964 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1966 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1967 if (image->debug != MagickFalse)
1968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
1969 (double) image->quality);
1973 #if !defined(C_LOSSLESS_SUPPORTED)
1974 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1975 if (image->debug != MagickFalse)
1976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1978 if (image->quality < 100)
1979 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1980 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1987 predictor=image->quality/100; /* range 1-7 */
1988 point_transform=image->quality % 20; /* range 0-15 */
1989 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1990 if (image->debug != MagickFalse)
1992 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1993 "Compression: lossless");
1994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1995 "Predictor: %d",predictor);
1996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1997 "Point Transform: %d",point_transform);
2002 sampling_factor=(const char *) NULL;
2003 value=GetImageProperty(image,"jpeg:sampling-factor");
2004 if (value != (char *) NULL)
2006 sampling_factor=value;
2007 if (image->debug != MagickFalse)
2008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2009 " Input sampling-factors=%s",sampling_factor);
2011 if (image_info->sampling_factor != (char *) NULL)
2012 sampling_factor=image_info->sampling_factor;
2013 if (sampling_factor == (const char *) NULL)
2015 if (image->quality >= 90)
2016 for (i=0; i < MAX_COMPONENTS; i++)
2018 jpeg_info.comp_info[i].h_samp_factor=1;
2019 jpeg_info.comp_info[i].v_samp_factor=1;
2034 Set sampling factor.
2037 factors=SamplingFactorToList(sampling_factor);
2038 if (factors != (char **) NULL)
2040 for (i=0; i < MAX_COMPONENTS; i++)
2042 if (factors[i] == (char *) NULL)
2044 flags=ParseGeometry(factors[i],&geometry_info);
2045 if ((flags & SigmaValue) == 0)
2046 geometry_info.sigma=geometry_info.rho;
2047 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2048 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2049 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2051 factors=(char **) RelinquishMagickMemory(factors);
2053 for ( ; i < MAX_COMPONENTS; i++)
2055 jpeg_info.comp_info[i].h_samp_factor=1;
2056 jpeg_info.comp_info[i].v_samp_factor=1;
2059 if (jpeg_info.input_components == 1)
2060 for (i=0; i < MAX_COMPONENTS; i++)
2062 jpeg_info.comp_info[i].h_samp_factor=1;
2063 jpeg_info.comp_info[i].v_samp_factor=1;
2065 jpeg_start_compress(&jpeg_info,MagickTrue);
2066 if (image->debug != MagickFalse)
2068 if (image->storage_class == PseudoClass)
2069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2070 "Storage class: PseudoClass");
2072 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2073 "Storage class: DirectClass");
2074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2075 (double) image->depth);
2076 if (image->colors != 0)
2077 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2078 "Number of colors: %.20g",(double) image->colors);
2080 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2081 "Number of colors: unspecified");
2082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2083 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2084 switch (image->colorspace)
2086 case CMYKColorspace:
2088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2089 "Storage class: DirectClass");
2090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2091 "Colorspace: CMYK");
2094 case YCbCrColorspace:
2095 case Rec601YCbCrColorspace:
2096 case Rec709YCbCrColorspace:
2098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2099 "Colorspace: YCbCr");
2105 switch (image->colorspace)
2107 case CMYKColorspace:
2109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2110 "Colorspace: CMYK");
2111 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2112 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2113 jpeg_info.comp_info[0].h_samp_factor,
2114 jpeg_info.comp_info[0].v_samp_factor,
2115 jpeg_info.comp_info[1].h_samp_factor,
2116 jpeg_info.comp_info[1].v_samp_factor,
2117 jpeg_info.comp_info[2].h_samp_factor,
2118 jpeg_info.comp_info[2].v_samp_factor,
2119 jpeg_info.comp_info[3].h_samp_factor,
2120 jpeg_info.comp_info[3].v_samp_factor);
2123 case GRAYColorspace:
2124 case Rec601LumaColorspace:
2125 case Rec709LumaColorspace:
2127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2128 "Colorspace: GRAY");
2129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2130 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2131 jpeg_info.comp_info[0].v_samp_factor);
2136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2137 "Image colorspace is RGB");
2138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2139 "Sampling factors: %dx%d,%dx%d,%dx%d",
2140 jpeg_info.comp_info[0].h_samp_factor,
2141 jpeg_info.comp_info[0].v_samp_factor,
2142 jpeg_info.comp_info[1].h_samp_factor,
2143 jpeg_info.comp_info[1].v_samp_factor,
2144 jpeg_info.comp_info[2].h_samp_factor,
2145 jpeg_info.comp_info[2].v_samp_factor);
2148 case YCbCrColorspace:
2149 case Rec601YCbCrColorspace:
2150 case Rec709YCbCrColorspace:
2152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2153 "Colorspace: YCbCr");
2154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2155 "Sampling factors: %dx%d,%dx%d,%dx%d",
2156 jpeg_info.comp_info[0].h_samp_factor,
2157 jpeg_info.comp_info[0].v_samp_factor,
2158 jpeg_info.comp_info[1].h_samp_factor,
2159 jpeg_info.comp_info[1].v_samp_factor,
2160 jpeg_info.comp_info[2].h_samp_factor,
2161 jpeg_info.comp_info[2].v_samp_factor);
2166 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2168 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2169 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2170 jpeg_info.comp_info[0].h_samp_factor,
2171 jpeg_info.comp_info[0].v_samp_factor,
2172 jpeg_info.comp_info[1].h_samp_factor,
2173 jpeg_info.comp_info[1].v_samp_factor,
2174 jpeg_info.comp_info[2].h_samp_factor,
2175 jpeg_info.comp_info[2].v_samp_factor,
2176 jpeg_info.comp_info[3].h_samp_factor,
2177 jpeg_info.comp_info[3].v_samp_factor);
2183 Write JPEG profiles.
2185 value=GetImageProperty(image,"comment");
2186 if (value != (char *) NULL)
2187 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2188 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2189 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2190 if (image->profiles != (void *) NULL)
2191 WriteProfile(&jpeg_info,image);
2193 Convert MIFF to JPEG raster pixels.
2195 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2196 jpeg_info.input_components*sizeof(*jpeg_pixels));
2197 if (jpeg_pixels == (JSAMPLE *) NULL)
2198 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2199 if (setjmp(error_manager.error_recovery) != 0)
2201 jpeg_destroy_compress(&jpeg_info);
2202 if (jpeg_pixels != (unsigned char *) NULL)
2203 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2204 (void) CloseBlob(image);
2205 return(MagickFalse);
2207 scanline[0]=(JSAMPROW) jpeg_pixels;
2208 if (jpeg_info.data_precision <= 8)
2210 if ((jpeg_info.in_color_space == JCS_RGB) ||
2211 (jpeg_info.in_color_space == JCS_YCbCr))
2212 for (y=0; y < (ssize_t) image->rows; y++)
2214 register const Quantum
2220 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2221 if (p == (const Quantum *) NULL)
2224 for (x=0; x < (ssize_t) image->columns; x++)
2226 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2227 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2228 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2229 p+=GetPixelChannels(image);
2231 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2232 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2234 if (status == MagickFalse)
2238 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2239 for (y=0; y < (ssize_t) image->rows; y++)
2241 register const Quantum
2247 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2248 if (p == (const Quantum *) NULL)
2251 for (x=0; x < (ssize_t) image->columns; x++)
2253 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2254 p+=GetPixelChannels(image);
2256 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2257 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2259 if (status == MagickFalse)
2263 for (y=0; y < (ssize_t) image->rows; y++)
2265 register const Quantum
2271 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2272 if (p == (const Quantum *) NULL)
2275 for (x=0; x < (ssize_t) image->columns; x++)
2278 Convert DirectClass packets to contiguous CMYK scanlines.
2280 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2281 GetPixelRed(image,p))));
2282 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2283 GetPixelGreen(image,p))));
2284 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2285 GetPixelBlue(image,p))));
2286 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2287 GetPixelBlack(image,p))));
2288 p+=GetPixelChannels(image);
2290 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2291 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2293 if (status == MagickFalse)
2298 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2299 for (y=0; y < (ssize_t) image->rows; y++)
2301 register const Quantum
2307 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2308 if (p == (const Quantum *) NULL)
2311 for (x=0; x < (ssize_t) image->columns; x++)
2313 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2315 p+=GetPixelChannels(image);
2317 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2318 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2320 if (status == MagickFalse)
2324 if ((jpeg_info.in_color_space == JCS_RGB) ||
2325 (jpeg_info.in_color_space == JCS_YCbCr))
2326 for (y=0; y < (ssize_t) image->rows; y++)
2328 register const Quantum
2334 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2335 if (p == (const Quantum *) NULL)
2338 for (x=0; x < (ssize_t) image->columns; x++)
2340 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2341 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2342 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2343 p+=GetPixelChannels(image);
2345 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2346 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2348 if (status == MagickFalse)
2352 for (y=0; y < (ssize_t) image->rows; y++)
2354 register const Quantum
2360 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2361 if (p == (const Quantum *) NULL)
2364 for (x=0; x < (ssize_t) image->columns; x++)
2367 Convert DirectClass packets to contiguous CMYK scanlines.
2369 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2370 GetPixelRed(image,p)) >> 4));
2371 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2372 GetPixelGreen(image,p)) >> 4));
2373 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2374 GetPixelBlue(image,p)) >> 4));
2375 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2376 GetPixelBlack(image,p)) >> 4));
2377 p+=GetPixelChannels(image);
2379 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2380 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2382 if (status == MagickFalse)
2385 if (y == (ssize_t) image->rows)
2386 jpeg_finish_compress(&jpeg_info);
2388 Relinquish resources.
2390 jpeg_destroy_compress(&jpeg_info);
2391 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2392 (void) CloseBlob(image);