2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % JJJJJ PPPP EEEEE GGGG %
13 % Read/Write JPEG Image Format %
20 % Copyright 1999-2010 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 "magick/studio.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/color.h"
51 #include "magick/colormap-private.h"
52 #include "magick/color-private.h"
53 #include "magick/colormap.h"
54 #include "magick/colorspace.h"
55 #include "magick/constitute.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/geometry.h"
59 #include "magick/image.h"
60 #include "magick/image-private.h"
61 #include "magick/list.h"
62 #include "magick/log.h"
63 #include "magick/magick.h"
64 #include "magick/memory_.h"
65 #include "magick/module.h"
66 #include "magick/monitor.h"
67 #include "magick/monitor-private.h"
68 #include "magick/option.h"
69 #include "magick/profile.h"
70 #include "magick/property.h"
71 #include "magick/quantum-private.h"
72 #include "magick/resource_.h"
73 #include "magick/splay-tree.h"
74 #include "magick/static.h"
75 #include "magick/string_.h"
76 #include "magick/string-private.h"
77 #include "magick/utility.h"
79 #if defined(MAGICKCORE_JPEG_DELEGATE)
80 #define JPEG_INTERNAL_OPTIONS
81 #if defined(__MINGW32__)
82 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
83 typedef unsigned char boolean;
93 #define ICC_MARKER (JPEG_APP0+2)
94 #define ICC_PROFILE "ICC_PROFILE"
95 #define IPTC_MARKER (JPEG_APP0+13)
96 #define XML_MARKER (JPEG_APP0+1)
97 #define MaxBufferExtent 8192
100 Typedef declarations.
102 #if defined(MAGICKCORE_JPEG_DELEGATE)
103 typedef struct _DestinationManager
105 struct jpeg_destination_mgr
113 } DestinationManager;
115 typedef struct _ErrorManager
124 typedef struct _SourceManager
126 struct jpeg_source_mgr
141 Forward declarations.
143 #if defined(MAGICKCORE_JPEG_DELEGATE)
144 static MagickBooleanType
145 WriteJPEGImage(const ImageInfo *,Image *);
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 % IsJPEG() returns MagickTrue if the image format type, identified by the
160 % magick string, is JPEG.
162 % The format of the IsJPEG method is:
164 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
166 % A description of each parameter follows:
168 % o magick: compare image format pattern against these bytes.
170 % o length: Specifies the length of the magick string.
173 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
177 if (memcmp(magick,"\377\330\377",3) == 0)
182 #if defined(MAGICKCORE_JPEG_DELEGATE)
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 % R e a d J P E G I m a g e %
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
195 % the memory necessary for the new Image structure and returns a pointer to
198 % The format of the ReadJPEGImage method is:
200 % Image *ReadJPEGImage(const ImageInfo *image_info,
201 % ExceptionInfo *exception)
203 % A description of each parameter follows:
205 % o image_info: the image info.
207 % o exception: return any errors or warnings in this structure.
211 static MagickBooleanType EmitMessage(j_common_ptr jpeg_info,int level)
214 message[JMSG_LENGTH_MAX];
222 (jpeg_info->err->format_message)(jpeg_info,message);
223 error_manager=(ErrorManager *) jpeg_info->client_data;
224 image=error_manager->image;
227 if ((jpeg_info->err->num_warnings == 0) ||
228 (jpeg_info->err->trace_level >= 3))
229 ThrowBinaryException(CorruptImageWarning,(char *) message,
231 jpeg_info->err->num_warnings++;
234 if (jpeg_info->err->trace_level >= level)
235 ThrowBinaryException(CoderError,(char *) message,image->filename);
239 static boolean FillInputBuffer(j_decompress_ptr cinfo)
244 source=(SourceManager *) cinfo->src;
245 source->manager.bytes_in_buffer=(size_t)
246 ReadBlob(source->image,MaxBufferExtent,source->buffer);
247 if (source->manager.bytes_in_buffer == 0)
249 if (source->start_of_blob != 0)
250 ERREXIT(cinfo,JERR_INPUT_EMPTY);
251 WARNMS(cinfo,JWRN_JPEG_EOF);
252 source->buffer[0]=(JOCTET) 0xff;
253 source->buffer[1]=(JOCTET) JPEG_EOI;
254 source->manager.bytes_in_buffer=2;
256 source->manager.next_input_byte=source->buffer;
257 source->start_of_blob=FALSE;
261 static int GetCharacter(j_decompress_ptr jpeg_info)
263 if (jpeg_info->src->bytes_in_buffer == 0)
264 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
265 jpeg_info->src->bytes_in_buffer--;
266 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
269 static void InitializeSource(j_decompress_ptr cinfo)
274 source=(SourceManager *) cinfo->src;
275 source->start_of_blob=TRUE;
278 static MagickBooleanType IsITUFaxImage(const Image *image)
286 profile=GetImageProfile(image,"8bim");
287 if (profile == (const StringInfo *) NULL)
289 if (GetStringInfoLength(profile) < 5)
291 datum=GetStringInfoDatum(profile);
292 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
293 (datum[3] == 0x41) && (datum[4] == 0x58))
298 static void JPEGErrorHandler(j_common_ptr jpeg_info)
303 (void) EmitMessage(jpeg_info,0);
304 error_manager=(ErrorManager *) jpeg_info->client_data;
305 longjmp(error_manager->error_recovery,1);
308 static boolean ReadComment(j_decompress_ptr jpeg_info)
329 Determine length of comment.
331 error_manager=(ErrorManager *) jpeg_info->client_data;
332 image=error_manager->image;
333 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
334 length+=GetCharacter(jpeg_info);
338 comment=(char *) NULL;
339 if (~length >= MaxTextExtent)
340 comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
342 if (comment == (char *) NULL)
343 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
348 i=(ssize_t) length-1;
349 for (p=comment; i-- >= 0; p++)
350 *p=(char) GetCharacter(jpeg_info);
352 (void) SetImageProperty(image,"comment",comment);
353 comment=DestroyString(comment);
357 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
374 register unsigned char
387 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
388 length+=(size_t) GetCharacter(jpeg_info);
393 (void) GetCharacter(jpeg_info);
396 for (i=0; i < 12; i++)
397 magick[i]=(char) GetCharacter(jpeg_info);
398 if (LocaleCompare(magick,ICC_PROFILE) != 0)
401 Not a ICC profile, return.
403 for (i=0; i < (ssize_t) (length-12); i++)
404 (void) GetCharacter(jpeg_info);
407 (void) GetCharacter(jpeg_info); /* id */
408 (void) GetCharacter(jpeg_info); /* markers */
410 error_manager=(ErrorManager *) jpeg_info->client_data;
411 image=error_manager->image;
412 profile=AcquireStringInfo(length);
413 if (profile == (StringInfo *) NULL)
414 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
416 p=GetStringInfoDatum(profile);
417 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
418 *p++=(unsigned char) GetCharacter(jpeg_info);
419 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
420 if (icc_profile != (StringInfo *) NULL)
422 ConcatenateStringInfo(icc_profile,profile);
423 profile=DestroyStringInfo(profile);
427 status=SetImageProfile(image,"icc",profile);
428 profile=DestroyStringInfo(profile);
429 if (status == MagickFalse)
430 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
435 "Profile: ICC, %.20g bytes",(double) length);
439 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
442 magick[MaxTextExtent];
456 register unsigned char
467 Determine length of binary data stored here.
469 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
470 length+=(size_t) GetCharacter(jpeg_info);
475 (void) GetCharacter(jpeg_info);
479 Validate that this was written as a Photoshop resource format slug.
481 for (i=0; i < 10; i++)
482 magick[i]=(char) GetCharacter(jpeg_info);
487 if (LocaleCompare(magick,"Photoshop ") != 0)
490 Not a IPTC profile, return.
492 for (i=0; i < (ssize_t) length; i++)
493 (void) GetCharacter(jpeg_info);
497 Remove the version number.
499 for (i=0; i < 4; i++)
500 (void) GetCharacter(jpeg_info);
506 error_manager=(ErrorManager *) jpeg_info->client_data;
507 image=error_manager->image;
508 profile=AcquireStringInfo(length);
509 if (profile == (StringInfo *) NULL)
510 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
512 p=GetStringInfoDatum(profile);
513 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
514 *p++=(unsigned char) GetCharacter(jpeg_info);
515 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
516 if (iptc_profile != (StringInfo *) NULL)
518 ConcatenateStringInfo(iptc_profile,profile);
519 profile=DestroyStringInfo(profile);
523 if (strcmp((char *) GetStringInfoDatum(profile),"8BIM") != 0)
524 status=SetImageProfile(image,"iptc",profile);
526 status=SetImageProfile(image,"8BIM",profile);
527 profile=DestroyStringInfo(profile);
528 if (status == MagickFalse)
529 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
532 if (image->debug != MagickFalse)
533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
534 "Profile: iptc, %.20g bytes",(double) length);
538 static boolean ReadProfile(j_decompress_ptr jpeg_info)
558 register unsigned char
568 Read generic profile.
570 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
571 length+=(size_t) GetCharacter(jpeg_info);
575 marker=jpeg_info->unread_marker-JPEG_APP0;
576 (void) FormatMagickString(name,MaxTextExtent,"APP%d",marker);
577 error_manager=(ErrorManager *) jpeg_info->client_data;
578 image=error_manager->image;
579 profile=AcquireStringInfo(length);
580 if (profile == (StringInfo *) NULL)
581 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
583 p=GetStringInfoDatum(profile);
584 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
585 *p++=(unsigned char) GetCharacter(jpeg_info);
588 p=GetStringInfoDatum(profile);
589 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
590 (void) CopyMagickString(name,"exif",MaxTextExtent);
591 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
597 Extract namespace from XMP profile.
599 p=GetStringInfoDatum(profile);
600 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
606 if (j < (ssize_t) GetStringInfoLength(profile))
607 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
608 (void) CopyMagickString(name,"xmp",MaxTextExtent);
611 status=SetImageProfile(image,name,profile);
612 profile=DestroyStringInfo(profile);
613 if (status == MagickFalse)
614 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
616 if (image->debug != MagickFalse)
617 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
618 "Profile: %s, %.20g bytes",name,(double) length);
622 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
627 if (number_bytes <= 0)
629 source=(SourceManager *) cinfo->src;
630 while (number_bytes > (long) source->manager.bytes_in_buffer)
632 number_bytes-=(long) source->manager.bytes_in_buffer;
633 (void) FillInputBuffer(cinfo);
635 source->manager.next_input_byte+=number_bytes;
636 source->manager.bytes_in_buffer-=number_bytes;
639 static void TerminateSource(j_decompress_ptr cinfo)
644 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
649 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
650 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
651 source=(SourceManager *) cinfo->src;
652 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
653 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
654 source=(SourceManager *) cinfo->src;
655 source->manager.init_source=InitializeSource;
656 source->manager.fill_input_buffer=FillInputBuffer;
657 source->manager.skip_input_data=SkipInputData;
658 source->manager.resync_to_restart=jpeg_resync_to_restart;
659 source->manager.term_source=TerminateSource;
660 source->manager.bytes_in_buffer=0;
661 source->manager.next_input_byte=NULL;
665 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
668 image->quality=UndefinedCompressionQuality;
669 #if defined(D_PROGRESSIVE_SUPPORTED)
670 if (image->compression == LosslessJPEGCompression)
673 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
674 "Quality: 100 (lossless)");
688 Determine the JPEG compression quality from the quantization tables.
691 for (i=0; i < NUM_QUANT_TBLS; i++)
693 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
694 for (j=0; j < DCTSIZE2; j++)
695 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
697 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
698 (jpeg_info->quant_tbl_ptrs[1] != NULL))
703 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
704 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
705 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
706 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
707 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
708 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
709 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
710 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
711 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
712 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
717 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
718 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
719 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
720 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
721 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
722 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
723 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
724 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
725 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
726 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
727 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
731 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
732 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
733 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
734 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
735 for (i=0; i < 100; i++)
737 if ((qvalue < hash[i]) && (sum < sums[i]))
739 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
740 image->quality=(size_t) i+1;
741 if (image->debug != MagickFalse)
742 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
743 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
744 (sum <= sums[i]) ? "exact" : "approximate");
749 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
754 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
755 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
756 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
757 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
758 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
759 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
760 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
761 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
762 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
763 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
768 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
769 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
770 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
771 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
772 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
773 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
774 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
775 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
776 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
777 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
778 667, 592, 518, 441, 369, 292, 221, 151, 86,
782 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
783 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
784 for (i=0; i < 100; i++)
786 if ((qvalue < hash[i]) && (sum < sums[i]))
788 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
789 image->quality=(size_t) i+1;
790 if (image->debug != MagickFalse)
791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
792 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
793 (sum <= sums[i]) ? "exact" : "approximate");
800 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image)
803 sampling_factor[MaxTextExtent];
805 switch (jpeg_info->out_color_space)
809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
810 (void) FormatMagickString(sampling_factor,MaxTextExtent,
811 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
812 jpeg_info->comp_info[0].v_samp_factor,
813 jpeg_info->comp_info[1].h_samp_factor,
814 jpeg_info->comp_info[1].v_samp_factor,
815 jpeg_info->comp_info[2].h_samp_factor,
816 jpeg_info->comp_info[2].v_samp_factor,
817 jpeg_info->comp_info[3].h_samp_factor,
818 jpeg_info->comp_info[3].v_samp_factor);
823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
824 "Colorspace: GRAYSCALE");
825 (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
826 jpeg_info->comp_info[0].h_samp_factor,
827 jpeg_info->comp_info[0].v_samp_factor);
832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
833 (void) FormatMagickString(sampling_factor,MaxTextExtent,
834 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
835 jpeg_info->comp_info[0].v_samp_factor,
836 jpeg_info->comp_info[1].h_samp_factor,
837 jpeg_info->comp_info[1].v_samp_factor,
838 jpeg_info->comp_info[2].h_samp_factor,
839 jpeg_info->comp_info[2].v_samp_factor);
844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
845 jpeg_info->out_color_space);
846 (void) FormatMagickString(sampling_factor,MaxTextExtent,
847 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
848 jpeg_info->comp_info[0].v_samp_factor,
849 jpeg_info->comp_info[1].h_samp_factor,
850 jpeg_info->comp_info[1].v_samp_factor,
851 jpeg_info->comp_info[2].h_samp_factor,
852 jpeg_info->comp_info[2].v_samp_factor,
853 jpeg_info->comp_info[3].h_samp_factor,
854 jpeg_info->comp_info[3].v_samp_factor);
858 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
859 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
863 static Image *ReadJPEGImage(const ImageInfo *image_info,
864 ExceptionInfo *exception)
867 value[MaxTextExtent];
900 struct jpeg_decompress_struct
903 struct jpeg_error_mgr
916 assert(image_info != (const ImageInfo *) NULL);
917 assert(image_info->signature == MagickSignature);
918 if (image_info->debug != MagickFalse)
919 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
920 image_info->filename);
921 assert(exception != (ExceptionInfo *) NULL);
922 assert(exception->signature == MagickSignature);
923 debug=IsEventLogging();
924 image=AcquireImage(image_info);
925 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
926 if (status == MagickFalse)
928 image=DestroyImageList(image);
929 return((Image *) NULL);
932 Initialize JPEG parameters.
934 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
935 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
936 jpeg_info.err=jpeg_std_error(&jpeg_error);
937 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
938 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
939 jpeg_pixels=(JSAMPLE *) NULL;
940 error_manager.image=image;
941 if (setjmp(error_manager.error_recovery) != 0)
943 jpeg_destroy_decompress(&jpeg_info);
944 (void) CloseBlob(image);
945 number_pixels=(MagickSizeType) image->columns*image->rows;
946 if (number_pixels != 0)
947 return(GetFirstImageInList(image));
948 InheritException(exception,&image->exception);
949 return(DestroyImage(image));
951 jpeg_info.client_data=(void *) &error_manager;
952 jpeg_create_decompress(&jpeg_info);
953 JPEGSourceManager(&jpeg_info,image);
954 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
955 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
956 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
957 for (i=1; i < 16; i++)
958 if ((i != 2) && (i != 13) && (i != 14))
959 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
960 i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
961 if ((image_info->colorspace == YCbCrColorspace) ||
962 (image_info->colorspace == Rec601YCbCrColorspace) ||
963 (image_info->colorspace == Rec709YCbCrColorspace))
964 jpeg_info.out_color_space=JCS_YCbCr;
965 if (IsITUFaxImage(image) != MagickFalse)
967 image->colorspace=LabColorspace;
968 jpeg_info.out_color_space=JCS_YCbCr;
971 if (jpeg_info.out_color_space == JCS_CMYK)
972 image->colorspace=CMYKColorspace;
974 Set image resolution.
977 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
978 (jpeg_info.Y_density != 1))
980 image->x_resolution=(double) jpeg_info.X_density;
981 image->y_resolution=(double) jpeg_info.Y_density;
982 units=(size_t) jpeg_info.density_unit;
985 image->units=PixelsPerInchResolution;
987 image->units=PixelsPerCentimeterResolution;
988 number_pixels=(MagickSizeType) image->columns*image->rows;
989 option=GetImageOption(image_info,"jpeg:size");
990 if (option != (const char *) NULL)
1004 flags=ParseGeometry(option,&geometry_info);
1005 if ((flags & SigmaValue) == 0)
1006 geometry_info.sigma=geometry_info.rho;
1007 jpeg_calc_output_dimensions(&jpeg_info);
1008 image->magick_columns=jpeg_info.output_width;
1009 image->magick_rows=jpeg_info.output_height;
1011 if (geometry_info.rho != 0.0)
1012 scale_factor=jpeg_info.output_width/geometry_info.rho;
1013 if ((geometry_info.sigma != 0.0) &&
1014 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1015 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1016 jpeg_info.scale_num=1U;
1017 jpeg_info.scale_denom=(unsigned int) scale_factor;
1018 jpeg_calc_output_dimensions(&jpeg_info);
1019 if (image->debug != MagickFalse)
1020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1021 "Scale factor: %.20g",(double) scale_factor);
1023 precision=(size_t) jpeg_info.data_precision;
1024 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1025 #if defined(D_LOSSLESS_SUPPORTED)
1026 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1027 JPEGInterlace : NoInterlace;
1028 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1029 LosslessJPEGCompression : JPEGCompression;
1030 if (jpeg_info.data_precision > 8)
1031 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1032 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1034 if (jpeg_info.data_precision == 16)
1035 jpeg_info.data_precision=12;
1037 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1039 image->compression=JPEGCompression;
1042 image->compression=JPEGCompression;
1043 image->interlace=JPEGInterlace;
1045 if ((image_info->colors > 8) && (image_info->colors <= 256))
1048 Let the JPEG library quantize for us.
1050 jpeg_info.quantize_colors=MagickTrue;
1051 jpeg_info.desired_number_of_colors=(int) image_info->colors;
1053 option=GetImageOption(image_info,"jpeg:block-smoothing");
1054 if (option != (const char *) NULL)
1056 jpeg_info.do_block_smoothing=MagickFalse;
1057 if (IsMagickTrue(option) != MagickFalse)
1058 jpeg_info.do_block_smoothing=MagickTrue;
1060 option=GetImageOption(image_info,"jpeg:dct-method");
1061 if (option != (const char *) NULL)
1067 if (LocaleCompare(option,"default") == 0)
1068 jpeg_info.dct_method=JDCT_DEFAULT;
1074 if (LocaleCompare(option,"fastest") == 0)
1075 jpeg_info.dct_method=JDCT_FASTEST;
1076 if (LocaleCompare(option,"float") == 0)
1077 jpeg_info.dct_method=JDCT_FLOAT;
1083 if (LocaleCompare(option,"ifast") == 0)
1084 jpeg_info.dct_method=JDCT_IFAST;
1085 if (LocaleCompare(option,"islow") == 0)
1086 jpeg_info.dct_method=JDCT_ISLOW;
1090 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1091 if (option != (const char *) NULL)
1093 jpeg_info.do_fancy_upsampling=MagickFalse;
1094 if (IsMagickTrue(option) != MagickFalse)
1095 jpeg_info.do_fancy_upsampling=MagickTrue;
1097 (void) jpeg_start_decompress(&jpeg_info);
1098 image->columns=jpeg_info.output_width;
1099 image->rows=jpeg_info.output_height;
1100 image->depth=(size_t) jpeg_info.data_precision;
1101 if (jpeg_info.out_color_space == JCS_YCbCr)
1102 image->colorspace=YCbCrColorspace;
1103 if (jpeg_info.out_color_space == JCS_CMYK)
1104 image->colorspace=CMYKColorspace;
1105 if ((image_info->colors != 0) && (image_info->colors <= 256))
1106 if (AcquireImageColormap(image,image_info->colors) == MagickFalse)
1107 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1108 if ((jpeg_info.output_components == 1) &&
1109 (jpeg_info.quantize_colors == MagickFalse))
1114 colors=(size_t) GetQuantumRange(image->depth)+1;
1115 if (AcquireImageColormap(image,colors) == MagickFalse)
1116 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1118 if (image->debug != MagickFalse)
1120 if (image->interlace != NoInterlace)
1121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1122 "Interlace: progressive");
1124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1125 "Interlace: nonprogressive");
1126 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1127 (int) jpeg_info.data_precision);
1128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1129 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1131 JPEGSetImageQuality(&jpeg_info,image);
1132 JPEGSetImageSamplingFactor(&jpeg_info,image);
1133 (void) FormatMagickString(value,MaxTextExtent,"%.20g",(double)
1134 jpeg_info.out_color_space);
1135 (void) SetImageProperty(image,"jpeg:colorspace",value);
1136 if (image_info->ping != MagickFalse)
1138 jpeg_destroy_decompress(&jpeg_info);
1139 (void) CloseBlob(image);
1140 return(GetFirstImageInList(image));
1142 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1143 jpeg_info.output_components*sizeof(JSAMPLE));
1144 if (jpeg_pixels == (JSAMPLE *) NULL)
1145 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1147 Convert JPEG pixels to pixel packets.
1149 if (setjmp(error_manager.error_recovery) != 0)
1151 if (jpeg_pixels != (unsigned char *) NULL)
1152 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1153 jpeg_destroy_decompress(&jpeg_info);
1154 (void) CloseBlob(image);
1155 number_pixels=(MagickSizeType) image->columns*image->rows;
1156 if (number_pixels != 0)
1157 return(GetFirstImageInList(image));
1158 return(DestroyImage(image));
1160 if (jpeg_info.quantize_colors != MagickFalse)
1162 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1163 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1164 for (i=0; i < (ssize_t) image->colors; i++)
1166 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1167 image->colormap[i].green=image->colormap[i].red;
1168 image->colormap[i].blue=image->colormap[i].red;
1169 image->colormap[i].opacity=OpaqueOpacity;
1172 for (i=0; i < (ssize_t) image->colors; i++)
1174 image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1175 image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1176 image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1177 image->colormap[i].opacity=OpaqueOpacity;
1180 scanline[0]=(JSAMPROW) jpeg_pixels;
1181 for (y=0; y < (ssize_t) image->rows; y++)
1183 register IndexPacket
1189 register PixelPacket
1192 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1194 (void) ThrowMagickException(exception,GetMagickModule(),
1195 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1199 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1200 if (q == (PixelPacket *) NULL)
1202 indexes=GetAuthenticIndexQueue(image);
1203 if (jpeg_info.data_precision > 8)
1205 if (jpeg_info.output_components == 1)
1206 for (x=0; x < (ssize_t) image->columns; x++)
1211 if (precision != 16)
1212 pixel=(size_t) GETJSAMPLE(*p);
1214 pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1215 index=ConstrainColormapIndex(image,pixel);
1217 *q++=image->colormap[(int) index];
1221 if (image->colorspace != CMYKColorspace)
1222 for (x=0; x < (ssize_t) image->columns; x++)
1224 q->red=ScaleShortToQuantum((unsigned char)
1225 (GETJSAMPLE(*p++) << 4));
1226 q->green=ScaleShortToQuantum((unsigned char)
1227 (GETJSAMPLE(*p++) << 4));
1228 q->blue=ScaleShortToQuantum((unsigned char)
1229 (GETJSAMPLE(*p++) << 4));
1230 SetOpacityPixelComponent(q,OpaqueOpacity);
1234 for (x=0; x < (ssize_t) image->columns; x++)
1236 q->red=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1237 (GETJSAMPLE(*p++) << 4));
1238 q->green=(Quantum) QuantumRange-ScaleShortToQuantum(
1239 (unsigned char) (GETJSAMPLE(*p++) << 4));
1240 q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
1241 (GETJSAMPLE(*p++) << 4));
1242 SetOpacityPixelComponent(q,OpaqueOpacity);
1243 indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
1244 (unsigned char) (GETJSAMPLE(*p++) << 4));
1249 if (jpeg_info.output_components == 1)
1250 for (x=0; x < (ssize_t) image->columns; x++)
1252 index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1253 indexes[x]=(IndexPacket) index;
1254 *q++=image->colormap[(int) index];
1258 if (image->colorspace != CMYKColorspace)
1259 for (x=0; x < (ssize_t) image->columns; x++)
1261 q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1262 q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1263 q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
1264 SetOpacityPixelComponent(q,OpaqueOpacity);
1268 for (x=0; x < (ssize_t) image->columns; x++)
1270 q->red=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1272 q->green=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1274 q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
1276 SetOpacityPixelComponent(q,OpaqueOpacity);
1277 indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
1278 (unsigned char) GETJSAMPLE(*p++));
1281 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1283 if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
1287 Free jpeg resources.
1289 (void) jpeg_finish_decompress(&jpeg_info);
1290 jpeg_destroy_decompress(&jpeg_info);
1291 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1292 (void) CloseBlob(image);
1293 return(GetFirstImageInList(image));
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 % R e g i s t e r J P E G I m a g e %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % RegisterJPEGImage() adds properties for the JPEG image format to
1309 % the list of supported formats. The properties include the image format
1310 % tag, a method to read and/or write the format, whether the format
1311 % supports the saving of more than one frame to the same file or blob,
1312 % whether the format supports native in-memory I/O, and a brief
1313 % description of the format.
1315 % The format of the RegisterJPEGImage method is:
1317 % size_t RegisterJPEGImage(void)
1320 ModuleExport size_t RegisterJPEGImage(void)
1323 version[MaxTextExtent];
1329 description[] = "Joint Photographic Experts Group JFIF format";
1332 #if defined(JPEG_LIB_VERSION)
1333 (void) FormatMagickString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1335 entry=SetMagickInfo("JPEG");
1336 entry->thread_support=NoThreadSupport;
1337 #if defined(MAGICKCORE_JPEG_DELEGATE)
1338 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1339 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1341 entry->magick=(IsImageFormatHandler *) IsJPEG;
1342 entry->adjoin=MagickFalse;
1343 entry->description=ConstantString(description);
1344 if (*version != '\0')
1345 entry->version=ConstantString(version);
1346 entry->module=ConstantString("JPEG");
1347 (void) RegisterMagickInfo(entry);
1348 entry=SetMagickInfo("JPG");
1349 entry->thread_support=NoThreadSupport;
1350 #if defined(MAGICKCORE_JPEG_DELEGATE)
1351 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1352 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1354 entry->adjoin=MagickFalse;
1355 entry->description=ConstantString(description);
1356 if (*version != '\0')
1357 entry->version=ConstantString(version);
1358 entry->module=ConstantString("JPEG");
1359 (void) RegisterMagickInfo(entry);
1360 entry=SetMagickInfo("PJPEG");
1361 entry->thread_support=NoThreadSupport;
1362 #if defined(MAGICKCORE_JPEG_DELEGATE)
1363 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1364 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1366 entry->adjoin=MagickFalse;
1367 entry->description=ConstantString(description);
1368 if (*version != '\0')
1369 entry->version=ConstantString(version);
1370 entry->module=ConstantString("JPEG");
1371 (void) RegisterMagickInfo(entry);
1372 return(MagickImageCoderSignature);
1376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380 % U n r e g i s t e r J P E G I m a g e %
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 % UnregisterJPEGImage() removes format registrations made by the
1387 % JPEG module from the list of supported formats.
1389 % The format of the UnregisterJPEGImage method is:
1391 % UnregisterJPEGImage(void)
1394 ModuleExport void UnregisterJPEGImage(void)
1396 (void) UnregisterMagickInfo("PJPG");
1397 (void) UnregisterMagickInfo("JPEG");
1398 (void) UnregisterMagickInfo("JPG");
1401 #if defined(MAGICKCORE_JPEG_DELEGATE)
1403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 % W r i t e J P E G I m a g e %
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 % WriteJPEGImage() writes a JPEG image file and returns it. It
1414 % allocates the memory necessary for the new Image structure and returns a
1415 % pointer to the new image.
1417 % The format of the WriteJPEGImage method is:
1419 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,Image *image)
1421 % A description of each parameter follows:
1423 % o image_info: the image info.
1425 % o jpeg_image: The image.
1430 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1435 destination=(DestinationManager *) cinfo->dest;
1436 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1437 MaxBufferExtent,destination->buffer);
1438 if (destination->manager.free_in_buffer != MaxBufferExtent)
1439 ERREXIT(cinfo,JERR_FILE_WRITE);
1440 destination->manager.next_output_byte=destination->buffer;
1444 static void InitializeDestination(j_compress_ptr cinfo)
1449 destination=(DestinationManager *) cinfo->dest;
1450 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1451 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1452 destination->manager.next_output_byte=destination->buffer;
1453 destination->manager.free_in_buffer=MaxBufferExtent;
1456 static inline size_t MagickMin(const size_t x,const size_t y)
1463 static void TerminateDestination(j_compress_ptr cinfo)
1468 destination=(DestinationManager *) cinfo->dest;
1469 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1474 count=WriteBlob(destination->image,MaxBufferExtent-
1475 destination->manager.free_in_buffer,destination->buffer);
1476 if (count != (ssize_t)
1477 (MaxBufferExtent-destination->manager.free_in_buffer))
1478 ERREXIT(cinfo,JERR_FILE_WRITE);
1482 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1506 Save image profile as a APP marker.
1509 custom_profile=AcquireStringInfo(65535L);
1510 ResetImageProfileIterator(image);
1511 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1513 register unsigned char
1516 profile=GetImageProfile(image,name);
1517 p=GetStringInfoDatum(custom_profile);
1518 if (LocaleCompare(name,"EXIF") == 0)
1519 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1521 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1522 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1523 (unsigned int) length);
1525 if (LocaleCompare(name,"ICC") == 0)
1527 register unsigned char
1531 p=GetStringInfoDatum(custom_profile);
1532 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1533 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1535 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1536 p[12]=(unsigned char) ((i/65519L)+1);
1537 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1538 (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1540 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1541 custom_profile),(unsigned int) (length+tag_length));
1544 if (((LocaleCompare(name,"IPTC") == 0) ||
1545 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1551 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1553 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1554 roundup=(size_t) (length & 0x01);
1555 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1557 (void) memcpy(p,"Photoshop 3.0 ",14);
1562 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1564 p[24]=(unsigned char) (length >> 8);
1565 p[25]=(unsigned char) (length & 0xff);
1568 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1570 p[length+tag_length]='\0';
1571 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1572 custom_profile),(unsigned int) (length+tag_length+roundup));
1575 if (LocaleCompare(name,"XMP") == 0)
1581 Add namespace to XMP profile.
1583 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1584 ConcatenateStringInfo(xmp_profile,profile);
1585 GetStringInfoDatum(xmp_profile)[28]='\0';
1586 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1588 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1589 jpeg_write_marker(jpeg_info,XML_MARKER,
1590 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1592 xmp_profile=DestroyStringInfo(xmp_profile);
1594 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1595 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1596 name=GetNextImageProfile(image);
1598 custom_profile=DestroyStringInfo(custom_profile);
1601 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1606 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1607 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1608 destination=(DestinationManager *) cinfo->dest;
1609 destination->manager.init_destination=InitializeDestination;
1610 destination->manager.empty_output_buffer=EmptyOutputBuffer;
1611 destination->manager.term_destination=TerminateDestination;
1612 destination->image=image;
1615 static char **SamplingFactorToList(const char *text)
1632 if (text == (char *) NULL)
1633 return((char **) NULL);
1635 Convert string to an ASCII list.
1638 for (p=text; *p != '\0'; p++)
1641 textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1643 if (textlist == (char **) NULL)
1644 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1646 for (i=0; i < (ssize_t) lines; i++)
1648 for (q=(char *) p; *q != '\0'; q++)
1651 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1652 sizeof(*textlist[i]));
1653 if (textlist[i] == (char *) NULL)
1654 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1655 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1660 textlist[i]=(char *) NULL;
1664 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1693 struct jpeg_compress_struct
1696 struct jpeg_error_mgr
1702 assert(image_info != (const ImageInfo *) NULL);
1703 assert(image_info->signature == MagickSignature);
1704 assert(image != (Image *) NULL);
1705 assert(image->signature == MagickSignature);
1706 if (image->debug != MagickFalse)
1707 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1708 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1709 if (status == MagickFalse)
1712 Initialize JPEG parameters.
1714 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1715 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1716 jpeg_info.client_data=(void *) image;
1717 jpeg_info.err=jpeg_std_error(&jpeg_error);
1718 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) EmitMessage;
1719 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1720 error_manager.image=image;
1721 jpeg_pixels=(JSAMPLE *) NULL;
1722 if (setjmp(error_manager.error_recovery) != 0)
1724 jpeg_destroy_compress(&jpeg_info);
1725 (void) CloseBlob(image);
1726 return(MagickFalse);
1728 jpeg_info.client_data=(void *) &error_manager;
1729 jpeg_create_compress(&jpeg_info);
1730 JPEGDestinationManager(&jpeg_info,image);
1731 if ((image->columns != (unsigned int) image->columns) ||
1732 (image->rows != (unsigned int) image->rows))
1733 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1734 jpeg_info.image_width=(unsigned int) image->columns;
1735 jpeg_info.image_height=(unsigned int) image->rows;
1736 jpeg_info.input_components=3;
1737 jpeg_info.data_precision=8;
1738 jpeg_info.in_color_space=JCS_RGB;
1739 switch (image->colorspace)
1741 case CMYKColorspace:
1743 jpeg_info.input_components=4;
1744 jpeg_info.in_color_space=JCS_CMYK;
1747 case YCbCrColorspace:
1748 case Rec601YCbCrColorspace:
1749 case Rec709YCbCrColorspace:
1751 jpeg_info.in_color_space=JCS_YCbCr;
1754 case GRAYColorspace:
1755 case Rec601LumaColorspace:
1756 case Rec709LumaColorspace:
1758 jpeg_info.input_components=1;
1759 jpeg_info.in_color_space=JCS_GRAYSCALE;
1764 if (image->colorspace != RGBColorspace)
1765 (void) TransformImageColorspace(image,RGBColorspace);
1769 if ((image_info->type != TrueColorType) &&
1770 (IsGrayImage(image,&image->exception) != MagickFalse))
1772 jpeg_info.input_components=1;
1773 jpeg_info.in_color_space=JCS_GRAYSCALE;
1775 jpeg_set_defaults(&jpeg_info);
1776 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1777 jpeg_info.data_precision=8;
1779 if (sizeof(JSAMPLE) > 1)
1780 jpeg_info.data_precision=12;
1781 jpeg_info.density_unit=(UINT8) 1;
1782 if (image->debug != MagickFalse)
1783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1784 "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1785 floor(image->y_resolution+0.5));
1786 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1789 Set image resolution.
1791 jpeg_info.write_JFIF_header=MagickTrue;
1792 jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1793 jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1794 if (image->units == PixelsPerInchResolution)
1795 jpeg_info.density_unit=(UINT8) 1;
1796 if (image->units == PixelsPerCentimeterResolution)
1797 jpeg_info.density_unit=(UINT8) 2;
1799 option=GetImageOption(image_info,"jpeg:dct-method");
1800 if (option != (const char *) NULL)
1806 if (LocaleCompare(option,"default") == 0)
1807 jpeg_info.dct_method=JDCT_DEFAULT;
1813 if (LocaleCompare(option,"fastest") == 0)
1814 jpeg_info.dct_method=JDCT_FASTEST;
1815 if (LocaleCompare(option,"float") == 0)
1816 jpeg_info.dct_method=JDCT_FLOAT;
1822 if (LocaleCompare(option,"ifast") == 0)
1823 jpeg_info.dct_method=JDCT_IFAST;
1824 if (LocaleCompare(option,"islow") == 0)
1825 jpeg_info.dct_method=JDCT_ISLOW;
1829 option=GetImageOption(image_info,"jpeg:optimize-coding");
1830 if (option != (const char *) NULL)
1832 jpeg_info.optimize_coding=MagickFalse;
1833 if (IsMagickTrue(option) != MagickFalse)
1834 jpeg_info.optimize_coding=MagickTrue;
1841 length=(MagickSizeType) jpeg_info.input_components*image->columns*
1842 image->rows*sizeof(JSAMPLE);
1843 if (length == (MagickSizeType) ((size_t) length))
1846 Perform optimization only if available memory resources permit it.
1848 status=AcquireMagickResource(MemoryResource,length);
1849 if (status != MagickFalse)
1850 jpeg_info.optimize_coding=MagickTrue;
1851 RelinquishMagickResource(MemoryResource,length);
1854 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1855 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1856 (image_info->interlace != NoInterlace))
1858 if (image->debug != MagickFalse)
1859 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1860 "Interlace: progressive");
1861 jpeg_simple_progression(&jpeg_info);
1864 if (image->debug != MagickFalse)
1865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1866 "Interlace: non-progressive");
1868 if (image->debug != MagickFalse)
1869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1870 "Interlace: nonprogressive");
1872 option=GetImageOption(image_info,"jpeg:extent");
1873 if (option != (const char *) NULL)
1881 jpeg_info=CloneImageInfo(image_info);
1882 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1883 if (jpeg_image != (Image *) NULL)
1893 Search for compression quality that does not exceed image extent.
1895 jpeg_info->quality=0;
1896 extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1897 (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1898 (void) AcquireUniqueFilename(jpeg_image->filename);
1900 for (minimum=0; minimum != maximum; )
1902 jpeg_image->quality=minimum+(maximum-minimum)/2;
1903 status=WriteJPEGImage(jpeg_info,jpeg_image);
1904 if (GetBlobSize(jpeg_image) <= extent)
1905 minimum=jpeg_image->quality+1;
1907 maximum=jpeg_image->quality-1;
1909 (void) RelinquishUniqueFileResource(jpeg_image->filename);
1910 image->quality=minimum-1;
1911 jpeg_image=DestroyImage(jpeg_image);
1913 jpeg_info=DestroyImageInfo(jpeg_info);
1915 if ((image_info->compression != LosslessJPEGCompression) &&
1916 (image->quality <= 100))
1918 if (image->quality == UndefinedCompressionQuality)
1919 jpeg_set_quality(&jpeg_info,92,MagickTrue);
1921 jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
1922 if (image->debug != MagickFalse)
1923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
1924 (double) image->quality);
1928 #if !defined(C_LOSSLESS_SUPPORTED)
1929 jpeg_set_quality(&jpeg_info,100,MagickTrue);
1930 if (image->debug != MagickFalse)
1931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
1933 if (image->quality < 100)
1934 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1935 CoderWarning,"LosslessToLossyJPEGConversion",image->filename);
1942 predictor=image->quality/100; /* range 1-7 */
1943 point_transform=image->quality % 20; /* range 0-15 */
1944 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
1945 if (image->debug != MagickFalse)
1947 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1948 "Compression: lossless");
1949 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1950 "Predictor: %d",predictor);
1951 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1952 "Point Transform: %d",point_transform);
1957 sampling_factor=(const char *) NULL;
1958 value=GetImageProperty(image,"jpeg:sampling-factor");
1959 if (value != (char *) NULL)
1961 sampling_factor=value;
1962 if (image->debug != MagickFalse)
1963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1964 " Input sampling-factors=%s",sampling_factor);
1966 if (image_info->sampling_factor != (char *) NULL)
1967 sampling_factor=image_info->sampling_factor;
1968 if (sampling_factor == (const char *) NULL)
1970 if (image->quality >= 90)
1971 for (i=0; i < MAX_COMPONENTS; i++)
1973 jpeg_info.comp_info[i].h_samp_factor=1;
1974 jpeg_info.comp_info[i].v_samp_factor=1;
1989 Set sampling factor.
1992 factors=SamplingFactorToList(sampling_factor);
1993 if (factors != (char **) NULL)
1995 for (i=0; i < MAX_COMPONENTS; i++)
1997 if (factors[i] == (char *) NULL)
1999 flags=ParseGeometry(factors[i],&geometry_info);
2000 if ((flags & SigmaValue) == 0)
2001 geometry_info.sigma=geometry_info.rho;
2002 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2003 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2004 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2006 factors=(char **) RelinquishMagickMemory(factors);
2008 for ( ; i < MAX_COMPONENTS; i++)
2010 jpeg_info.comp_info[i].h_samp_factor=1;
2011 jpeg_info.comp_info[i].v_samp_factor=1;
2014 if (jpeg_info.input_components == 1)
2015 for (i=0; i < MAX_COMPONENTS; i++)
2017 jpeg_info.comp_info[i].h_samp_factor=1;
2018 jpeg_info.comp_info[i].v_samp_factor=1;
2020 jpeg_start_compress(&jpeg_info,MagickTrue);
2021 if (image->debug != MagickFalse)
2023 if (image->storage_class == PseudoClass)
2024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2025 "Storage class: PseudoClass");
2027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2028 "Storage class: DirectClass");
2029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2030 (double) image->depth);
2031 if (image->colors != 0)
2032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2033 "Number of colors: %.20g",(double) image->colors);
2035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2036 "Number of colors: unspecified");
2037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2038 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2039 switch (image->colorspace)
2041 case CMYKColorspace:
2043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2044 "Storage class: DirectClass");
2045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2046 "Colorspace: CMYK");
2049 case YCbCrColorspace:
2050 case Rec601YCbCrColorspace:
2051 case Rec709YCbCrColorspace:
2053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2054 "Colorspace: YCbCr");
2060 switch (image->colorspace)
2062 case CMYKColorspace:
2064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2065 "Colorspace: CMYK");
2066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2067 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2068 jpeg_info.comp_info[0].h_samp_factor,
2069 jpeg_info.comp_info[0].v_samp_factor,
2070 jpeg_info.comp_info[1].h_samp_factor,
2071 jpeg_info.comp_info[1].v_samp_factor,
2072 jpeg_info.comp_info[2].h_samp_factor,
2073 jpeg_info.comp_info[2].v_samp_factor,
2074 jpeg_info.comp_info[3].h_samp_factor,
2075 jpeg_info.comp_info[3].v_samp_factor);
2078 case GRAYColorspace:
2079 case Rec601LumaColorspace:
2080 case Rec709LumaColorspace:
2082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2083 "Colorspace: GRAY");
2084 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2085 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2086 jpeg_info.comp_info[0].v_samp_factor);
2091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2092 "Image colorspace is RGB");
2093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2094 "Sampling factors: %dx%d,%dx%d,%dx%d",
2095 jpeg_info.comp_info[0].h_samp_factor,
2096 jpeg_info.comp_info[0].v_samp_factor,
2097 jpeg_info.comp_info[1].h_samp_factor,
2098 jpeg_info.comp_info[1].v_samp_factor,
2099 jpeg_info.comp_info[2].h_samp_factor,
2100 jpeg_info.comp_info[2].v_samp_factor);
2103 case YCbCrColorspace:
2104 case Rec601YCbCrColorspace:
2105 case Rec709YCbCrColorspace:
2107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2108 "Colorspace: YCbCr");
2109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2110 "Sampling factors: %dx%d,%dx%d,%dx%d",
2111 jpeg_info.comp_info[0].h_samp_factor,
2112 jpeg_info.comp_info[0].v_samp_factor,
2113 jpeg_info.comp_info[1].h_samp_factor,
2114 jpeg_info.comp_info[1].v_samp_factor,
2115 jpeg_info.comp_info[2].h_samp_factor,
2116 jpeg_info.comp_info[2].v_samp_factor);
2121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2124 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2125 jpeg_info.comp_info[0].h_samp_factor,
2126 jpeg_info.comp_info[0].v_samp_factor,
2127 jpeg_info.comp_info[1].h_samp_factor,
2128 jpeg_info.comp_info[1].v_samp_factor,
2129 jpeg_info.comp_info[2].h_samp_factor,
2130 jpeg_info.comp_info[2].v_samp_factor,
2131 jpeg_info.comp_info[3].h_samp_factor,
2132 jpeg_info.comp_info[3].v_samp_factor);
2138 Write JPEG profiles.
2140 value=GetImageProperty(image,"comment");
2141 if (value != (char *) NULL)
2142 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2143 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2144 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2145 if (image->profiles != (void *) NULL)
2146 WriteProfile(&jpeg_info,image);
2148 Convert MIFF to JPEG raster pixels.
2150 jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2151 jpeg_info.input_components*sizeof(*jpeg_pixels));
2152 if (jpeg_pixels == (JSAMPLE *) NULL)
2153 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2154 if (setjmp(error_manager.error_recovery) != 0)
2156 jpeg_destroy_compress(&jpeg_info);
2157 if (jpeg_pixels != (unsigned char *) NULL)
2158 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2159 (void) CloseBlob(image);
2160 return(MagickFalse);
2162 scanline[0]=(JSAMPROW) jpeg_pixels;
2163 if (jpeg_info.data_precision <= 8)
2165 if ((jpeg_info.in_color_space == JCS_RGB) ||
2166 (jpeg_info.in_color_space == JCS_YCbCr))
2167 for (y=0; y < (ssize_t) image->rows; y++)
2169 register const PixelPacket
2175 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2176 if (p == (const PixelPacket *) NULL)
2179 for (x=0; x < (ssize_t) image->columns; x++)
2181 *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
2182 *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
2183 *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
2186 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2187 if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
2191 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2192 for (y=0; y < (ssize_t) image->rows; y++)
2194 register const PixelPacket
2200 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2201 if (p == (const PixelPacket *) NULL)
2204 for (x=0; x < (ssize_t) image->columns; x++)
2206 *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
2209 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2210 if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
2214 for (y=0; y < (ssize_t) image->rows; y++)
2216 register const IndexPacket
2219 register const PixelPacket
2225 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2226 if (p == (const PixelPacket *) NULL)
2229 indexes=GetVirtualIndexQueue(image);
2230 for (x=0; x < (ssize_t) image->columns; x++)
2233 Convert DirectClass packets to contiguous CMYK scanlines.
2235 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2236 GetRedPixelComponent(p))));
2237 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2238 GetGreenPixelComponent(p))));
2239 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2240 GetBluePixelComponent(p))));
2241 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2245 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2246 if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
2251 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2252 for (y=0; y < (ssize_t) image->rows; y++)
2254 register const PixelPacket
2260 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2261 if (p == (const PixelPacket *) NULL)
2264 for (x=0; x < (ssize_t) image->columns; x++)
2266 *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
2270 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2271 if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
2275 if ((jpeg_info.in_color_space == JCS_RGB) ||
2276 (jpeg_info.in_color_space == JCS_YCbCr))
2277 for (y=0; y < (ssize_t) image->rows; y++)
2279 register const PixelPacket
2285 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2286 if (p == (const PixelPacket *) NULL)
2289 for (x=0; x < (ssize_t) image->columns; x++)
2291 *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >>
2293 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >>
2295 *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >>
2299 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2300 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2302 if (status == MagickFalse)
2306 for (y=0; y < (ssize_t) image->rows; y++)
2308 register const IndexPacket
2311 register const PixelPacket
2317 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2318 if (p == (const PixelPacket *) NULL)
2321 indexes=GetVirtualIndexQueue(image);
2322 for (x=0; x < (ssize_t) image->columns; x++)
2325 Convert DirectClass packets to contiguous CMYK scanlines.
2327 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2328 GetRedPixelComponent(p)) >> 4));
2329 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2330 GetGreenPixelComponent(p)) >> 4));
2331 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2332 GetBluePixelComponent(p)) >> 4));
2333 *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
2336 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2337 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2339 if (status == MagickFalse)
2342 if (y == (ssize_t) image->rows)
2343 jpeg_finish_compress(&jpeg_info);
2345 Relinquish resources.
2347 jpeg_destroy_compress(&jpeg_info);
2348 jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2349 (void) CloseBlob(image);