1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % JJJJJ PPPP EEEEE GGGG %
7 % J P P E G %
8 % J PPPP EEE G GG %
9 % J J P E G G %
10 % JJJ P EEEEE GGG %
11 % %
12 % %
13 % Read/Write JPEG Image Format %
14 % %
15 % Software Design %
16 % John Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % http://www.imagemagick.org/script/license.php %
27 % %
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. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
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.
39 %
40 %
41 */
42
43
44 /*
45 Include declarations.
46 */
47 #include "MagickCore/studio.h"
48 #include "MagickCore/artifact.h"
49 #include "MagickCore/attribute.h"
50 #include "MagickCore/blob.h"
51 #include "MagickCore/blob-private.h"
52 #include "MagickCore/cache.h"
53 #include "MagickCore/color.h"
54 #include "MagickCore/colormap-private.h"
55 #include "MagickCore/color-private.h"
56 #include "MagickCore/colormap.h"
57 #include "MagickCore/colorspace.h"
58 #include "MagickCore/colorspace-private.h"
59 #include "MagickCore/constitute.h"
60 #include "MagickCore/exception.h"
61 #include "MagickCore/exception-private.h"
62 #include "MagickCore/geometry.h"
63 #include "MagickCore/image.h"
64 #include "MagickCore/image-private.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/magick.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/option-private.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/splay-tree.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/string_.h"
83 #include "MagickCore/string-private.h"
84 #include "MagickCore/token.h"
85 #include "MagickCore/utility.h"
86 #include "MagickCore/xml-tree.h"
87 #include "MagickCore/xml-tree-private.h"
88 #include <setjmp.h>
89 #if defined(MAGICKCORE_JPEG_DELEGATE)
90 #define JPEG_INTERNAL_OPTIONS
91 #if defined(__MINGW32__) || defined(__MINGW64__)
92 # define XMD_H 1 /* Avoid conflicting typedef for INT32 */
93 #endif
94 #undef HAVE_STDLIB_H
95 #include "jpeglib.h"
96 #include "jerror.h"
97 #endif
98
99 /*
100 Define declarations.
101 */
102 #define ICC_MARKER (JPEG_APP0+2)
103 #define ICC_PROFILE "ICC_PROFILE"
104 #define IPTC_MARKER (JPEG_APP0+13)
105 #define XML_MARKER (JPEG_APP0+1)
106 #define MaxBufferExtent 16384
107
108 /*
109 Typedef declarations.
110 */
111 #if defined(MAGICKCORE_JPEG_DELEGATE)
112 typedef struct _DestinationManager
113 {
114 struct jpeg_destination_mgr
115 manager;
116
117 Image
118 *image;
119
120 JOCTET
121 *buffer;
122 } DestinationManager;
123
124 typedef struct _ErrorManager
125 {
126 ExceptionInfo
127 *exception;
128
129 Image
130 *image;
131
132 MagickBooleanType
133 finished;
134
135 StringInfo
136 *profile;
137
138 jmp_buf
139 error_recovery;
140 } ErrorManager;
141
142 typedef struct _SourceManager
143 {
144 struct jpeg_source_mgr
145 manager;
146
147 Image
148 *image;
149
150 JOCTET
151 *buffer;
152
153 boolean
154 start_of_blob;
155 } SourceManager;
156 #endif
157
158 typedef struct _QuantizationTable
159 {
160 char
161 *slot,
162 *description;
163
164 size_t
165 width,
166 height;
167
168 double
169 divisor;
170
171 unsigned int
172 *levels;
173 } QuantizationTable;
174
175 /*
176 Forward declarations.
177 */
178 #if defined(MAGICKCORE_JPEG_DELEGATE)
179 static MagickBooleanType
180 WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
181 #endif
182
183 /*
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 % %
186 % %
187 % %
188 % I s J P E G %
189 % %
190 % %
191 % %
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 %
194 % IsJPEG() returns MagickTrue if the image format type, identified by the
195 % magick string, is JPEG.
196 %
197 % The format of the IsJPEG method is:
198 %
199 % MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
200 %
201 % A description of each parameter follows:
202 %
203 % o magick: compare image format pattern against these bytes.
204 %
205 % o length: Specifies the length of the magick string.
206 %
207 */
IsJPEG(const unsigned char * magick,const size_t length)208 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
209 {
210 if (length < 3)
211 return(MagickFalse);
212 if (memcmp(magick,"\377\330\377",3) == 0)
213 return(MagickTrue);
214 return(MagickFalse);
215 }
216
217 #if defined(MAGICKCORE_JPEG_DELEGATE)
218 /*
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 % %
221 % %
222 % %
223 % R e a d J P E G I m a g e %
224 % %
225 % %
226 % %
227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228 %
229 % ReadJPEGImage() reads a JPEG image file and returns it. It allocates
230 % the memory necessary for the new Image structure and returns a pointer to
231 % the new image.
232 %
233 % The format of the ReadJPEGImage method is:
234 %
235 % Image *ReadJPEGImage(const ImageInfo *image_info,
236 % ExceptionInfo *exception)
237 %
238 % A description of each parameter follows:
239 %
240 % o image_info: the image info.
241 %
242 % o exception: return any errors or warnings in this structure.
243 %
244 */
245
FillInputBuffer(j_decompress_ptr cinfo)246 static boolean FillInputBuffer(j_decompress_ptr cinfo)
247 {
248 SourceManager
249 *source;
250
251 source=(SourceManager *) cinfo->src;
252 source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
253 MaxBufferExtent,source->buffer);
254 if (source->manager.bytes_in_buffer == 0)
255 {
256 if (source->start_of_blob != FALSE)
257 ERREXIT(cinfo,JERR_INPUT_EMPTY);
258 WARNMS(cinfo,JWRN_JPEG_EOF);
259 source->buffer[0]=(JOCTET) 0xff;
260 source->buffer[1]=(JOCTET) JPEG_EOI;
261 source->manager.bytes_in_buffer=2;
262 }
263 source->manager.next_input_byte=source->buffer;
264 source->start_of_blob=FALSE;
265 return(TRUE);
266 }
267
GetCharacter(j_decompress_ptr jpeg_info)268 static int GetCharacter(j_decompress_ptr jpeg_info)
269 {
270 if (jpeg_info->src->bytes_in_buffer == 0)
271 (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
272 jpeg_info->src->bytes_in_buffer--;
273 return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
274 }
275
InitializeSource(j_decompress_ptr cinfo)276 static void InitializeSource(j_decompress_ptr cinfo)
277 {
278 SourceManager
279 *source;
280
281 source=(SourceManager *) cinfo->src;
282 source->start_of_blob=TRUE;
283 }
284
IsITUFaxImage(const Image * image)285 static MagickBooleanType IsITUFaxImage(const Image *image)
286 {
287 const StringInfo
288 *profile;
289
290 const unsigned char
291 *datum;
292
293 profile=GetImageProfile(image,"8bim");
294 if (profile == (const StringInfo *) NULL)
295 return(MagickFalse);
296 if (GetStringInfoLength(profile) < 5)
297 return(MagickFalse);
298 datum=GetStringInfoDatum(profile);
299 if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
300 (datum[3] == 0x41) && (datum[4] == 0x58))
301 return(MagickTrue);
302 return(MagickFalse);
303 }
304
JPEGErrorHandler(j_common_ptr jpeg_info)305 static void JPEGErrorHandler(j_common_ptr jpeg_info)
306 {
307 char
308 message[JMSG_LENGTH_MAX];
309
310 ErrorManager
311 *error_manager;
312
313 ExceptionInfo
314 *exception;
315
316 Image
317 *image;
318
319 *message='\0';
320 error_manager=(ErrorManager *) jpeg_info->client_data;
321 image=error_manager->image;
322 exception=error_manager->exception;
323 (jpeg_info->err->format_message)(jpeg_info,message);
324 if (image->debug != MagickFalse)
325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
326 "[%s] JPEG Trace: \"%s\"",image->filename,message);
327 if (error_manager->finished != MagickFalse)
328 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
329 (char *) message,"`%s'",image->filename);
330 else
331 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
332 (char *) message,"`%s'",image->filename);
333 longjmp(error_manager->error_recovery,1);
334 }
335
JPEGWarningHandler(j_common_ptr jpeg_info,int level)336 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
337 {
338 #define JPEGExcessiveWarnings 1000
339
340 char
341 message[JMSG_LENGTH_MAX];
342
343 ErrorManager
344 *error_manager;
345
346 ExceptionInfo
347 *exception;
348
349 Image
350 *image;
351
352 *message='\0';
353 error_manager=(ErrorManager *) jpeg_info->client_data;
354 exception=error_manager->exception;
355 image=error_manager->image;
356 if (level < 0)
357 {
358 /*
359 Process warning message.
360 */
361 (jpeg_info->err->format_message)(jpeg_info,message);
362 if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
363 JPEGErrorHandler(jpeg_info);
364 ThrowBinaryException(CorruptImageWarning,(char *) message,
365 image->filename);
366 }
367 else
368 if ((image->debug != MagickFalse) &&
369 (level >= jpeg_info->err->trace_level))
370 {
371 /*
372 Process trace message.
373 */
374 (jpeg_info->err->format_message)(jpeg_info,message);
375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
376 "[%s] JPEG Trace: \"%s\"",image->filename,message);
377 }
378 return(MagickTrue);
379 }
380
ReadComment(j_decompress_ptr jpeg_info)381 static boolean ReadComment(j_decompress_ptr jpeg_info)
382 {
383 ErrorManager
384 *error_manager;
385
386 ExceptionInfo
387 *exception;
388
389 Image
390 *image;
391
392 register unsigned char
393 *p;
394
395 register ssize_t
396 i;
397
398 size_t
399 length;
400
401 StringInfo
402 *comment;
403
404 /*
405 Determine length of comment.
406 */
407 error_manager=(ErrorManager *) jpeg_info->client_data;
408 exception=error_manager->exception;
409 image=error_manager->image;
410 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
411 length+=GetCharacter(jpeg_info);
412 if (length <= 2)
413 return(TRUE);
414 length-=2;
415 comment=BlobToStringInfo((const void *) NULL,length);
416 if (comment == (StringInfo *) NULL)
417 {
418 (void) ThrowMagickException(exception,GetMagickModule(),
419 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
420 return(FALSE);
421 }
422 /*
423 Read comment.
424 */
425 error_manager->profile=comment;
426 p=GetStringInfoDatum(comment);
427 for (i=0; i < (ssize_t) GetStringInfoLength(comment); i++)
428 *p++=(unsigned char) GetCharacter(jpeg_info);
429 *p='\0';
430 error_manager->profile=NULL;
431 p=GetStringInfoDatum(comment);
432 (void) SetImageProperty(image,"comment",(const char *) p,exception);
433 comment=DestroyStringInfo(comment);
434 return(TRUE);
435 }
436
ReadICCProfile(j_decompress_ptr jpeg_info)437 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
438 {
439 char
440 magick[12];
441
442 ErrorManager
443 *error_manager;
444
445 ExceptionInfo
446 *exception;
447
448 Image
449 *image;
450
451 MagickBooleanType
452 status;
453
454 register ssize_t
455 i;
456
457 register unsigned char
458 *p;
459
460 size_t
461 length;
462
463 StringInfo
464 *icc_profile,
465 *profile;
466
467 /*
468 Read color profile.
469 */
470 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
471 length+=(size_t) GetCharacter(jpeg_info);
472 length-=2;
473 if (length <= 14)
474 {
475 while (length-- > 0)
476 (void) GetCharacter(jpeg_info);
477 return(TRUE);
478 }
479 for (i=0; i < 12; i++)
480 magick[i]=(char) GetCharacter(jpeg_info);
481 if (LocaleCompare(magick,ICC_PROFILE) != 0)
482 {
483 /*
484 Not a ICC profile, return.
485 */
486 for (i=0; i < (ssize_t) (length-12); i++)
487 (void) GetCharacter(jpeg_info);
488 return(TRUE);
489 }
490 (void) GetCharacter(jpeg_info); /* id */
491 (void) GetCharacter(jpeg_info); /* markers */
492 length-=14;
493 error_manager=(ErrorManager *) jpeg_info->client_data;
494 exception=error_manager->exception;
495 image=error_manager->image;
496 profile=BlobToStringInfo((const void *) NULL,length);
497 if (profile == (StringInfo *) NULL)
498 {
499 (void) ThrowMagickException(exception,GetMagickModule(),
500 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
501 return(FALSE);
502 }
503 error_manager->profile=profile;
504 p=GetStringInfoDatum(profile);
505 for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
506 *p++=(unsigned char) GetCharacter(jpeg_info);
507 error_manager->profile=NULL;
508 icc_profile=(StringInfo *) GetImageProfile(image,"icc");
509 if (icc_profile != (StringInfo *) NULL)
510 {
511 ConcatenateStringInfo(icc_profile,profile);
512 profile=DestroyStringInfo(profile);
513 }
514 else
515 {
516 status=SetImageProfile(image,"icc",profile,exception);
517 profile=DestroyStringInfo(profile);
518 if (status == MagickFalse)
519 {
520 (void) ThrowMagickException(exception,GetMagickModule(),
521 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
522 return(FALSE);
523 }
524 }
525 if (image->debug != MagickFalse)
526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
527 "Profile: ICC, %.20g bytes",(double) length);
528 return(TRUE);
529 }
530
ReadIPTCProfile(j_decompress_ptr jpeg_info)531 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
532 {
533 char
534 magick[MagickPathExtent];
535
536 ErrorManager
537 *error_manager;
538
539 ExceptionInfo
540 *exception;
541
542 Image
543 *image;
544
545 MagickBooleanType
546 status;
547
548 register ssize_t
549 i;
550
551 register unsigned char
552 *p;
553
554 size_t
555 length;
556
557 StringInfo
558 *iptc_profile,
559 *profile;
560
561 /*
562 Determine length of binary data stored here.
563 */
564 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
565 length+=(size_t) GetCharacter(jpeg_info);
566 length-=2;
567 if (length <= 14)
568 {
569 while (length-- > 0)
570 (void) GetCharacter(jpeg_info);
571 return(TRUE);
572 }
573 /*
574 Validate that this was written as a Photoshop resource format slug.
575 */
576 for (i=0; i < 10; i++)
577 magick[i]=(char) GetCharacter(jpeg_info);
578 magick[10]='\0';
579 length-=10;
580 if (length <= 10)
581 return(TRUE);
582 if (LocaleCompare(magick,"Photoshop ") != 0)
583 {
584 /*
585 Not a IPTC profile, return.
586 */
587 for (i=0; i < (ssize_t) length; i++)
588 (void) GetCharacter(jpeg_info);
589 return(TRUE);
590 }
591 /*
592 Remove the version number.
593 */
594 for (i=0; i < 4; i++)
595 (void) GetCharacter(jpeg_info);
596 if (length <= 11)
597 return(TRUE);
598 length-=4;
599 error_manager=(ErrorManager *) jpeg_info->client_data;
600 exception=error_manager->exception;
601 image=error_manager->image;
602 profile=BlobToStringInfo((const void *) NULL,length);
603 if (profile == (StringInfo *) NULL)
604 {
605 (void) ThrowMagickException(exception,GetMagickModule(),
606 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
607 return(FALSE);
608 }
609 error_manager->profile=profile;
610 p=GetStringInfoDatum(profile);
611 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
612 *p++=(unsigned char) GetCharacter(jpeg_info);
613 error_manager->profile=NULL;
614 iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
615 if (iptc_profile != (StringInfo *) NULL)
616 {
617 ConcatenateStringInfo(iptc_profile,profile);
618 profile=DestroyStringInfo(profile);
619 }
620 else
621 {
622 status=SetImageProfile(image,"8bim",profile,exception);
623 profile=DestroyStringInfo(profile);
624 if (status == MagickFalse)
625 {
626 (void) ThrowMagickException(exception,GetMagickModule(),
627 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
628 return(FALSE);
629 }
630 }
631 if (image->debug != MagickFalse)
632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
633 "Profile: iptc, %.20g bytes",(double) length);
634 return(TRUE);
635 }
636
ReadProfile(j_decompress_ptr jpeg_info)637 static boolean ReadProfile(j_decompress_ptr jpeg_info)
638 {
639 char
640 name[MagickPathExtent];
641
642 const StringInfo
643 *previous_profile;
644
645 ErrorManager
646 *error_manager;
647
648 ExceptionInfo
649 *exception;
650
651 Image
652 *image;
653
654 int
655 marker;
656
657 MagickBooleanType
658 status;
659
660 register ssize_t
661 i;
662
663 register unsigned char
664 *p;
665
666 size_t
667 length;
668
669 StringInfo
670 *profile;
671
672 /*
673 Read generic profile.
674 */
675 length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
676 length+=(size_t) GetCharacter(jpeg_info);
677 if (length <= 2)
678 return(TRUE);
679 length-=2;
680 marker=jpeg_info->unread_marker-JPEG_APP0;
681 (void) FormatLocaleString(name,MagickPathExtent,"APP%d",marker);
682 error_manager=(ErrorManager *) jpeg_info->client_data;
683 exception=error_manager->exception;
684 image=error_manager->image;
685 profile=BlobToStringInfo((const void *) NULL,length);
686 if (profile == (StringInfo *) NULL)
687 {
688 (void) ThrowMagickException(exception,GetMagickModule(),
689 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
690 return(FALSE);
691 }
692 error_manager->profile=profile;
693 p=GetStringInfoDatum(profile);
694 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i++)
695 *p++=(unsigned char) GetCharacter(jpeg_info);
696 error_manager->profile=NULL;
697 if (marker == 1)
698 {
699 p=GetStringInfoDatum(profile);
700 if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
701 (void) CopyMagickString(name,"exif",MagickPathExtent);
702 if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
703 {
704 ssize_t
705 j;
706
707 /*
708 Extract namespace from XMP profile.
709 */
710 p=GetStringInfoDatum(profile);
711 for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
712 {
713 if (*p == '\0')
714 break;
715 p++;
716 }
717 if (j < (ssize_t) GetStringInfoLength(profile))
718 (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
719 (void) CopyMagickString(name,"xmp",MagickPathExtent);
720 }
721 }
722 previous_profile=GetImageProfile(image,name);
723 if (previous_profile != (const StringInfo *) NULL)
724 {
725 size_t
726 profile_length;
727
728 profile_length=GetStringInfoLength(profile);
729 SetStringInfoLength(profile,GetStringInfoLength(profile)+
730 GetStringInfoLength(previous_profile));
731 (void) memmove(GetStringInfoDatum(profile)+
732 GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
733 profile_length);
734 (void) memcpy(GetStringInfoDatum(profile),
735 GetStringInfoDatum(previous_profile),
736 GetStringInfoLength(previous_profile));
737 }
738 status=SetImageProfile(image,name,profile,exception);
739 profile=DestroyStringInfo(profile);
740 if (status == MagickFalse)
741 {
742 (void) ThrowMagickException(exception,GetMagickModule(),
743 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
744 return(FALSE);
745 }
746 if (image->debug != MagickFalse)
747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
748 "Profile: %s, %.20g bytes",name,(double) length);
749 return(TRUE);
750 }
751
SkipInputData(j_decompress_ptr cinfo,long number_bytes)752 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
753 {
754 SourceManager
755 *source;
756
757 if (number_bytes <= 0)
758 return;
759 source=(SourceManager *) cinfo->src;
760 while (number_bytes > (long) source->manager.bytes_in_buffer)
761 {
762 number_bytes-=(long) source->manager.bytes_in_buffer;
763 (void) FillInputBuffer(cinfo);
764 }
765 source->manager.next_input_byte+=number_bytes;
766 source->manager.bytes_in_buffer-=number_bytes;
767 }
768
TerminateSource(j_decompress_ptr cinfo)769 static void TerminateSource(j_decompress_ptr cinfo)
770 {
771 (void) cinfo;
772 }
773
JPEGSourceManager(j_decompress_ptr cinfo,Image * image)774 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
775 {
776 SourceManager
777 *source;
778
779 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
780 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
781 source=(SourceManager *) cinfo->src;
782 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
783 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
784 source=(SourceManager *) cinfo->src;
785 source->manager.init_source=InitializeSource;
786 source->manager.fill_input_buffer=FillInputBuffer;
787 source->manager.skip_input_data=SkipInputData;
788 source->manager.resync_to_restart=jpeg_resync_to_restart;
789 source->manager.term_source=TerminateSource;
790 source->manager.bytes_in_buffer=0;
791 source->manager.next_input_byte=NULL;
792 source->image=image;
793 }
794
JPEGSetImageQuality(struct jpeg_decompress_struct * jpeg_info,Image * image)795 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
796 Image *image)
797 {
798 image->quality=UndefinedCompressionQuality;
799 #if defined(D_PROGRESSIVE_SUPPORTED)
800 if (image->compression == LosslessJPEGCompression)
801 {
802 image->quality=100;
803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
804 "Quality: 100 (lossless)");
805 }
806 else
807 #endif
808 {
809 ssize_t
810 j,
811 qvalue,
812 sum;
813
814 register ssize_t
815 i;
816
817 /*
818 Determine the JPEG compression quality from the quantization tables.
819 */
820 sum=0;
821 for (i=0; i < NUM_QUANT_TBLS; i++)
822 {
823 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
824 for (j=0; j < DCTSIZE2; j++)
825 sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
826 }
827 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
828 (jpeg_info->quant_tbl_ptrs[1] != NULL))
829 {
830 ssize_t
831 hash[101] =
832 {
833 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
834 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
835 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
836 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
837 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
838 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
839 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
840 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
841 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
842 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
843 0
844 },
845 sums[101] =
846 {
847 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
848 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
849 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
850 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
851 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
852 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458,
853 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788,
854 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128,
855 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509,
856 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
857 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201,
858 128, 0
859 };
860
861 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
862 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
863 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
864 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
865 for (i=0; i < 100; i++)
866 {
867 if ((qvalue < hash[i]) && (sum < sums[i]))
868 continue;
869 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
870 image->quality=(size_t) i+1;
871 if (image->debug != MagickFalse)
872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
873 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
874 (sum <= sums[i]) ? "exact" : "approximate");
875 break;
876 }
877 }
878 else
879 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
880 {
881 ssize_t
882 hash[101] =
883 {
884 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
885 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
886 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
887 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
888 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
889 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
890 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
891 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
892 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
893 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
894 0
895 },
896 sums[101] =
897 {
898 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
899 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679,
900 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823,
901 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086,
902 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092,
903 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396,
904 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727,
905 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068,
906 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398,
907 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
908 667, 592, 518, 441, 369, 292, 221, 151, 86,
909 64, 0
910 };
911
912 qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
913 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
914 for (i=0; i < 100; i++)
915 {
916 if ((qvalue < hash[i]) && (sum < sums[i]))
917 continue;
918 if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
919 image->quality=(size_t)i+1;
920 if (image->debug != MagickFalse)
921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
922 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
923 (sum <= sums[i]) ? "exact" : "approximate");
924 break;
925 }
926 }
927 }
928 }
929
JPEGSetImageSamplingFactor(struct jpeg_decompress_struct * jpeg_info,Image * image,ExceptionInfo * exception)930 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info, Image *image,ExceptionInfo *exception)
931 {
932 char
933 sampling_factor[MagickPathExtent];
934
935 switch (jpeg_info->out_color_space)
936 {
937 case JCS_CMYK:
938 {
939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
940 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
941 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
942 jpeg_info->comp_info[0].v_samp_factor,
943 jpeg_info->comp_info[1].h_samp_factor,
944 jpeg_info->comp_info[1].v_samp_factor,
945 jpeg_info->comp_info[2].h_samp_factor,
946 jpeg_info->comp_info[2].v_samp_factor,
947 jpeg_info->comp_info[3].h_samp_factor,
948 jpeg_info->comp_info[3].v_samp_factor);
949 break;
950 }
951 case JCS_GRAYSCALE:
952 {
953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
954 "Colorspace: GRAYSCALE");
955 (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d",
956 jpeg_info->comp_info[0].h_samp_factor,
957 jpeg_info->comp_info[0].v_samp_factor);
958 break;
959 }
960 case JCS_RGB:
961 {
962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
963 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
964 "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
965 jpeg_info->comp_info[0].v_samp_factor,
966 jpeg_info->comp_info[1].h_samp_factor,
967 jpeg_info->comp_info[1].v_samp_factor,
968 jpeg_info->comp_info[2].h_samp_factor,
969 jpeg_info->comp_info[2].v_samp_factor);
970 break;
971 }
972 default:
973 {
974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
975 jpeg_info->out_color_space);
976 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
977 "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
978 jpeg_info->comp_info[0].v_samp_factor,
979 jpeg_info->comp_info[1].h_samp_factor,
980 jpeg_info->comp_info[1].v_samp_factor,
981 jpeg_info->comp_info[2].h_samp_factor,
982 jpeg_info->comp_info[2].v_samp_factor,
983 jpeg_info->comp_info[3].h_samp_factor,
984 jpeg_info->comp_info[3].v_samp_factor);
985 break;
986 }
987 }
988 (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
989 exception);
990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
991 sampling_factor);
992 }
993
ReadJPEGImage(const ImageInfo * image_info,ExceptionInfo * exception)994 static Image *ReadJPEGImage(const ImageInfo *image_info,
995 ExceptionInfo *exception)
996 {
997 char
998 value[MagickPathExtent];
999
1000 const char
1001 *option;
1002
1003 ErrorManager
1004 error_manager;
1005
1006 Image
1007 *image;
1008
1009 JSAMPLE
1010 *volatile jpeg_pixels;
1011
1012 JSAMPROW
1013 scanline[1];
1014
1015 MagickBooleanType
1016 debug,
1017 status;
1018
1019 MagickSizeType
1020 number_pixels;
1021
1022 MemoryInfo
1023 *memory_info;
1024
1025 Quantum
1026 index;
1027
1028 register ssize_t
1029 i;
1030
1031 struct jpeg_decompress_struct
1032 jpeg_info;
1033
1034 struct jpeg_error_mgr
1035 jpeg_error;
1036
1037 register JSAMPLE
1038 *p;
1039
1040 size_t
1041 units;
1042
1043 ssize_t
1044 y;
1045
1046 /*
1047 Open image file.
1048 */
1049 assert(image_info != (const ImageInfo *) NULL);
1050 assert(image_info->signature == MagickCoreSignature);
1051 if (image_info->debug != MagickFalse)
1052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1053 image_info->filename);
1054 assert(exception != (ExceptionInfo *) NULL);
1055 assert(exception->signature == MagickCoreSignature);
1056 debug=IsEventLogging();
1057 (void) debug;
1058 image=AcquireImage(image_info,exception);
1059 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1060 if (status == MagickFalse)
1061 {
1062 image=DestroyImageList(image);
1063 return((Image *) NULL);
1064 }
1065 /*
1066 Initialize JPEG parameters.
1067 */
1068 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1069 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1070 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1071 jpeg_info.err=jpeg_std_error(&jpeg_error);
1072 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1073 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1074 memory_info=(MemoryInfo *) NULL;
1075 error_manager.exception=exception;
1076 error_manager.image=image;
1077 if (setjmp(error_manager.error_recovery) != 0)
1078 {
1079 jpeg_destroy_decompress(&jpeg_info);
1080 if (error_manager.profile != (StringInfo *) NULL)
1081 error_manager.profile=DestroyStringInfo(error_manager.profile);
1082 (void) CloseBlob(image);
1083 number_pixels=(MagickSizeType) image->columns*image->rows;
1084 if (number_pixels != 0)
1085 return(GetFirstImageInList(image));
1086 return(DestroyImage(image));
1087 }
1088 jpeg_info.client_data=(void *) &error_manager;
1089 jpeg_create_decompress(&jpeg_info);
1090 JPEGSourceManager(&jpeg_info,image);
1091 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1092 option=GetImageOption(image_info,"profile:skip");
1093 if (IsOptionMember("ICC",option) == MagickFalse)
1094 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1095 if (IsOptionMember("IPTC",option) == MagickFalse)
1096 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1097 for (i=1; i < 16; i++)
1098 if ((i != 2) && (i != 13) && (i != 14))
1099 if (IsOptionMember("APP",option) == MagickFalse)
1100 jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1101 i=(ssize_t) jpeg_read_header(&jpeg_info,TRUE);
1102 if ((image_info->colorspace == YCbCrColorspace) ||
1103 (image_info->colorspace == Rec601YCbCrColorspace) ||
1104 (image_info->colorspace == Rec709YCbCrColorspace))
1105 jpeg_info.out_color_space=JCS_YCbCr;
1106 /*
1107 Set image resolution.
1108 */
1109 units=0;
1110 if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1111 (jpeg_info.Y_density != 1))
1112 {
1113 image->resolution.x=(double) jpeg_info.X_density;
1114 image->resolution.y=(double) jpeg_info.Y_density;
1115 units=(size_t) jpeg_info.density_unit;
1116 }
1117 if (units == 1)
1118 image->units=PixelsPerInchResolution;
1119 if (units == 2)
1120 image->units=PixelsPerCentimeterResolution;
1121 number_pixels=(MagickSizeType) image->columns*image->rows;
1122 option=GetImageOption(image_info,"jpeg:size");
1123 if ((option != (const char *) NULL) &&
1124 (jpeg_info.out_color_space != JCS_YCbCr))
1125 {
1126 double
1127 scale_factor;
1128
1129 GeometryInfo
1130 geometry_info;
1131
1132 MagickStatusType
1133 flags;
1134
1135 /*
1136 Scale the image.
1137 */
1138 flags=ParseGeometry(option,&geometry_info);
1139 if ((flags & SigmaValue) == 0)
1140 geometry_info.sigma=geometry_info.rho;
1141 jpeg_calc_output_dimensions(&jpeg_info);
1142 image->magick_columns=jpeg_info.output_width;
1143 image->magick_rows=jpeg_info.output_height;
1144 scale_factor=1.0;
1145 if (geometry_info.rho != 0.0)
1146 scale_factor=jpeg_info.output_width/geometry_info.rho;
1147 if ((geometry_info.sigma != 0.0) &&
1148 (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1149 scale_factor=jpeg_info.output_height/geometry_info.sigma;
1150 jpeg_info.scale_num=1U;
1151 jpeg_info.scale_denom=(unsigned int) scale_factor;
1152 jpeg_calc_output_dimensions(&jpeg_info);
1153 if (image->debug != MagickFalse)
1154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1155 "Scale factor: %.20g",(double) scale_factor);
1156 }
1157 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1158 #if defined(D_LOSSLESS_SUPPORTED)
1159 image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1160 JPEGInterlace : NoInterlace;
1161 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1162 LosslessJPEGCompression : JPEGCompression;
1163 if (jpeg_info.data_precision > 8)
1164 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1165 "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1166 image->filename);
1167 if (jpeg_info.data_precision == 16)
1168 jpeg_info.data_precision=12;
1169 #else
1170 image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1171 NoInterlace;
1172 image->compression=JPEGCompression;
1173 #endif
1174 #else
1175 image->compression=JPEGCompression;
1176 image->interlace=JPEGInterlace;
1177 #endif
1178 option=GetImageOption(image_info,"jpeg:colors");
1179 if (option != (const char *) NULL)
1180 {
1181 /*
1182 Let the JPEG library quantize the image.
1183 */
1184 jpeg_info.quantize_colors=TRUE;
1185 jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1186 }
1187 option=GetImageOption(image_info,"jpeg:block-smoothing");
1188 if (option != (const char *) NULL)
1189 jpeg_info.do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1190 FALSE;
1191 jpeg_info.dct_method=JDCT_FLOAT;
1192 option=GetImageOption(image_info,"jpeg:dct-method");
1193 if (option != (const char *) NULL)
1194 switch (*option)
1195 {
1196 case 'D':
1197 case 'd':
1198 {
1199 if (LocaleCompare(option,"default") == 0)
1200 jpeg_info.dct_method=JDCT_DEFAULT;
1201 break;
1202 }
1203 case 'F':
1204 case 'f':
1205 {
1206 if (LocaleCompare(option,"fastest") == 0)
1207 jpeg_info.dct_method=JDCT_FASTEST;
1208 if (LocaleCompare(option,"float") == 0)
1209 jpeg_info.dct_method=JDCT_FLOAT;
1210 break;
1211 }
1212 case 'I':
1213 case 'i':
1214 {
1215 if (LocaleCompare(option,"ifast") == 0)
1216 jpeg_info.dct_method=JDCT_IFAST;
1217 if (LocaleCompare(option,"islow") == 0)
1218 jpeg_info.dct_method=JDCT_ISLOW;
1219 break;
1220 }
1221 }
1222 option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1223 if (option != (const char *) NULL)
1224 jpeg_info.do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1225 FALSE;
1226 (void) jpeg_start_decompress(&jpeg_info);
1227 image->columns=jpeg_info.output_width;
1228 image->rows=jpeg_info.output_height;
1229 image->depth=(size_t) jpeg_info.data_precision;
1230 switch (jpeg_info.out_color_space)
1231 {
1232 case JCS_RGB:
1233 default:
1234 {
1235 (void) SetImageColorspace(image,sRGBColorspace,exception);
1236 break;
1237 }
1238 case JCS_GRAYSCALE:
1239 {
1240 (void) SetImageColorspace(image,GRAYColorspace,exception);
1241 break;
1242 }
1243 case JCS_YCbCr:
1244 {
1245 (void) SetImageColorspace(image,YCbCrColorspace,exception);
1246 break;
1247 }
1248 case JCS_CMYK:
1249 {
1250 (void) SetImageColorspace(image,CMYKColorspace,exception);
1251 break;
1252 }
1253 }
1254 if (IsITUFaxImage(image) != MagickFalse)
1255 {
1256 (void) SetImageColorspace(image,LabColorspace,exception);
1257 jpeg_info.out_color_space=JCS_YCbCr;
1258 }
1259 option=GetImageOption(image_info,"jpeg:colors");
1260 if (option != (const char *) NULL)
1261 if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1262 == MagickFalse)
1263 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1264 if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0))
1265 {
1266 size_t
1267 colors;
1268
1269 colors=(size_t) GetQuantumRange(image->depth)+1;
1270 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1271 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1272 }
1273 if (image->debug != MagickFalse)
1274 {
1275 if (image->interlace != NoInterlace)
1276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1277 "Interlace: progressive");
1278 else
1279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1280 "Interlace: nonprogressive");
1281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1282 (int) jpeg_info.data_precision);
1283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1284 (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1285 }
1286 JPEGSetImageQuality(&jpeg_info,image);
1287 JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1288 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
1289 jpeg_info.out_color_space);
1290 (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1291 if (image_info->ping != MagickFalse)
1292 {
1293 jpeg_destroy_decompress(&jpeg_info);
1294 (void) CloseBlob(image);
1295 return(GetFirstImageInList(image));
1296 }
1297 status=SetImageExtent(image,image->columns,image->rows,exception);
1298 if (status == MagickFalse)
1299 {
1300 jpeg_destroy_decompress(&jpeg_info);
1301 return(DestroyImageList(image));
1302 }
1303 if ((jpeg_info.output_components != 1) &&
1304 (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1305 {
1306 jpeg_destroy_decompress(&jpeg_info);
1307 ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1308 }
1309 memory_info=AcquireVirtualMemory((size_t) image->columns,
1310 jpeg_info.output_components*sizeof(*jpeg_pixels));
1311 if (memory_info == (MemoryInfo *) NULL)
1312 {
1313 jpeg_destroy_decompress(&jpeg_info);
1314 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1315 }
1316 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1317 /*
1318 Convert JPEG pixels to pixel packets.
1319 */
1320 if (setjmp(error_manager.error_recovery) != 0)
1321 {
1322 if (memory_info != (MemoryInfo *) NULL)
1323 memory_info=RelinquishVirtualMemory(memory_info);
1324 jpeg_destroy_decompress(&jpeg_info);
1325 (void) CloseBlob(image);
1326 number_pixels=(MagickSizeType) image->columns*image->rows;
1327 if (number_pixels != 0)
1328 return(GetFirstImageInList(image));
1329 return(DestroyImage(image));
1330 }
1331 if (jpeg_info.quantize_colors != 0)
1332 {
1333 image->colors=(size_t) jpeg_info.actual_number_of_colors;
1334 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1335 for (i=0; i < (ssize_t) image->colors; i++)
1336 {
1337 image->colormap[i].red=(double) ScaleCharToQuantum(
1338 jpeg_info.colormap[0][i]);
1339 image->colormap[i].green=image->colormap[i].red;
1340 image->colormap[i].blue=image->colormap[i].red;
1341 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1342 }
1343 else
1344 for (i=0; i < (ssize_t) image->colors; i++)
1345 {
1346 image->colormap[i].red=(double) ScaleCharToQuantum(
1347 jpeg_info.colormap[0][i]);
1348 image->colormap[i].green=(double) ScaleCharToQuantum(
1349 jpeg_info.colormap[1][i]);
1350 image->colormap[i].blue=(double) ScaleCharToQuantum(
1351 jpeg_info.colormap[2][i]);
1352 image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1353 }
1354 }
1355 scanline[0]=(JSAMPROW) jpeg_pixels;
1356 for (y=0; y < (ssize_t) image->rows; y++)
1357 {
1358 register ssize_t
1359 x;
1360
1361 register Quantum
1362 *magick_restrict q;
1363
1364 if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1365 {
1366 (void) ThrowMagickException(exception,GetMagickModule(),
1367 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1368 continue;
1369 }
1370 p=jpeg_pixels;
1371 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1372 if (q == (Quantum *) NULL)
1373 break;
1374 if (jpeg_info.data_precision > 8)
1375 {
1376 unsigned short
1377 scale;
1378
1379 scale=65535/(unsigned short) GetQuantumRange((size_t)
1380 jpeg_info.data_precision);
1381 if (jpeg_info.output_components == 1)
1382 for (x=0; x < (ssize_t) image->columns; x++)
1383 {
1384 ssize_t
1385 pixel;
1386
1387 pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1388 index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1389 SetPixelIndex(image,index,q);
1390 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1391 p++;
1392 q+=GetPixelChannels(image);
1393 }
1394 else
1395 if (image->colorspace != CMYKColorspace)
1396 for (x=0; x < (ssize_t) image->columns; x++)
1397 {
1398 SetPixelRed(image,ScaleShortToQuantum(
1399 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1400 SetPixelGreen(image,ScaleShortToQuantum(
1401 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1402 SetPixelBlue(image,ScaleShortToQuantum(
1403 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1404 SetPixelAlpha(image,OpaqueAlpha,q);
1405 q+=GetPixelChannels(image);
1406 }
1407 else
1408 for (x=0; x < (ssize_t) image->columns; x++)
1409 {
1410 SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1411 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1412 SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1413 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1414 SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1415 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1416 SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1417 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1418 SetPixelAlpha(image,OpaqueAlpha,q);
1419 q+=GetPixelChannels(image);
1420 }
1421 }
1422 else
1423 if (jpeg_info.output_components == 1)
1424 for (x=0; x < (ssize_t) image->columns; x++)
1425 {
1426 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) GETJSAMPLE(*p),
1427 exception);
1428 SetPixelIndex(image,index,q);
1429 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1430 p++;
1431 q+=GetPixelChannels(image);
1432 }
1433 else
1434 if (image->colorspace != CMYKColorspace)
1435 for (x=0; x < (ssize_t) image->columns; x++)
1436 {
1437 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1438 GETJSAMPLE(*p++)),q);
1439 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1440 GETJSAMPLE(*p++)),q);
1441 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1442 GETJSAMPLE(*p++)),q);
1443 SetPixelAlpha(image,OpaqueAlpha,q);
1444 q+=GetPixelChannels(image);
1445 }
1446 else
1447 for (x=0; x < (ssize_t) image->columns; x++)
1448 {
1449 SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1450 (unsigned char) GETJSAMPLE(*p++)),q);
1451 SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1452 (unsigned char) GETJSAMPLE(*p++)),q);
1453 SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1454 (unsigned char) GETJSAMPLE(*p++)),q);
1455 SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1456 (unsigned char) GETJSAMPLE(*p++)),q);
1457 SetPixelAlpha(image,OpaqueAlpha,q);
1458 q+=GetPixelChannels(image);
1459 }
1460 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1461 break;
1462 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1463 image->rows);
1464 if (status == MagickFalse)
1465 {
1466 jpeg_abort_decompress(&jpeg_info);
1467 break;
1468 }
1469 }
1470 if (status != MagickFalse)
1471 {
1472 error_manager.finished=MagickTrue;
1473 if (setjmp(error_manager.error_recovery) == 0)
1474 (void) jpeg_finish_decompress(&jpeg_info);
1475 }
1476 /*
1477 Free jpeg resources.
1478 */
1479 jpeg_destroy_decompress(&jpeg_info);
1480 memory_info=RelinquishVirtualMemory(memory_info);
1481 (void) CloseBlob(image);
1482 return(GetFirstImageInList(image));
1483 }
1484 #endif
1485
1486 /*
1487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1488 % %
1489 % %
1490 % %
1491 % R e g i s t e r J P E G I m a g e %
1492 % %
1493 % %
1494 % %
1495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 %
1497 % RegisterJPEGImage() adds properties for the JPEG image format to
1498 % the list of supported formats. The properties include the image format
1499 % tag, a method to read and/or write the format, whether the format
1500 % supports the saving of more than one frame to the same file or blob,
1501 % whether the format supports native in-memory I/O, and a brief
1502 % description of the format.
1503 %
1504 % The format of the RegisterJPEGImage method is:
1505 %
1506 % size_t RegisterJPEGImage(void)
1507 %
1508 */
RegisterJPEGImage(void)1509 ModuleExport size_t RegisterJPEGImage(void)
1510 {
1511 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1512
1513 char
1514 version[MagickPathExtent];
1515
1516 MagickInfo
1517 *entry;
1518
1519 *version='\0';
1520 #if defined(JPEG_LIB_VERSION)
1521 (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION);
1522 #endif
1523 entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1524 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1525 entry->flags^=CoderDecoderThreadSupportFlag;
1526 #endif
1527 #if defined(MAGICKCORE_JPEG_DELEGATE)
1528 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1529 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1530 #endif
1531 entry->magick=(IsImageFormatHandler *) IsJPEG;
1532 entry->flags^=CoderAdjoinFlag;
1533 entry->flags^=CoderUseExtensionFlag;
1534 if (*version != '\0')
1535 entry->version=ConstantString(version);
1536 entry->mime_type=ConstantString("image/jpeg");
1537 (void) RegisterMagickInfo(entry);
1538 entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1539 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1540 entry->flags^=CoderDecoderThreadSupportFlag;
1541 #endif
1542 #if defined(MAGICKCORE_JPEG_DELEGATE)
1543 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1544 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1545 #endif
1546 entry->magick=(IsImageFormatHandler *) IsJPEG;
1547 entry->flags^=CoderAdjoinFlag;
1548 if (*version != '\0')
1549 entry->version=ConstantString(version);
1550 entry->mime_type=ConstantString("image/jpeg");
1551 (void) RegisterMagickInfo(entry);
1552 entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1553 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1554 entry->flags^=CoderDecoderThreadSupportFlag;
1555 #endif
1556 #if defined(MAGICKCORE_JPEG_DELEGATE)
1557 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1558 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1559 #endif
1560 entry->flags^=CoderAdjoinFlag;
1561 entry->flags^=CoderUseExtensionFlag;
1562 if (*version != '\0')
1563 entry->version=ConstantString(version);
1564 entry->mime_type=ConstantString("image/jpeg");
1565 (void) RegisterMagickInfo(entry);
1566 entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1567 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1568 entry->flags^=CoderDecoderThreadSupportFlag;
1569 #endif
1570 #if defined(MAGICKCORE_JPEG_DELEGATE)
1571 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1572 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1573 #endif
1574 entry->flags^=CoderAdjoinFlag;
1575 entry->flags^=CoderUseExtensionFlag;
1576 if (*version != '\0')
1577 entry->version=ConstantString(version);
1578 entry->mime_type=ConstantString("image/jpeg");
1579 (void) RegisterMagickInfo(entry);
1580 entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1581 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1582 entry->flags^=CoderDecoderThreadSupportFlag;
1583 #endif
1584 #if defined(MAGICKCORE_JPEG_DELEGATE)
1585 entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1586 entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1587 #endif
1588 entry->flags^=CoderAdjoinFlag;
1589 entry->flags^=CoderUseExtensionFlag;
1590 if (*version != '\0')
1591 entry->version=ConstantString(version);
1592 entry->mime_type=ConstantString("image/jpeg");
1593 (void) RegisterMagickInfo(entry);
1594 return(MagickImageCoderSignature);
1595 }
1596
1597 /*
1598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599 % %
1600 % %
1601 % %
1602 % U n r e g i s t e r J P E G I m a g e %
1603 % %
1604 % %
1605 % %
1606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607 %
1608 % UnregisterJPEGImage() removes format registrations made by the
1609 % JPEG module from the list of supported formats.
1610 %
1611 % The format of the UnregisterJPEGImage method is:
1612 %
1613 % UnregisterJPEGImage(void)
1614 %
1615 */
UnregisterJPEGImage(void)1616 ModuleExport void UnregisterJPEGImage(void)
1617 {
1618 (void) UnregisterMagickInfo("PJPG");
1619 (void) UnregisterMagickInfo("JPS");
1620 (void) UnregisterMagickInfo("JPG");
1621 (void) UnregisterMagickInfo("JPEG");
1622 (void) UnregisterMagickInfo("JPE");
1623 }
1624
1625 #if defined(MAGICKCORE_JPEG_DELEGATE)
1626 /*
1627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628 % %
1629 % %
1630 % %
1631 % W r i t e J P E G I m a g e %
1632 % %
1633 % %
1634 % %
1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 %
1637 % WriteJPEGImage() writes a JPEG image file and returns it. It
1638 % allocates the memory necessary for the new Image structure and returns a
1639 % pointer to the new image.
1640 %
1641 % The format of the WriteJPEGImage method is:
1642 %
1643 % MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1644 % Image *image,ExceptionInfo *exception)
1645 %
1646 % A description of each parameter follows:
1647 %
1648 % o image_info: the image info.
1649 %
1650 % o jpeg_image: The image.
1651 %
1652 % o exception: return any errors or warnings in this structure.
1653 %
1654 */
1655
DestroyQuantizationTable(QuantizationTable * table)1656 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1657 {
1658 assert(table != (QuantizationTable *) NULL);
1659 if (table->slot != (char *) NULL)
1660 table->slot=DestroyString(table->slot);
1661 if (table->description != (char *) NULL)
1662 table->description=DestroyString(table->description);
1663 if (table->levels != (unsigned int *) NULL)
1664 table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1665 table=(QuantizationTable *) RelinquishMagickMemory(table);
1666 return(table);
1667 }
1668
EmptyOutputBuffer(j_compress_ptr cinfo)1669 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1670 {
1671 DestinationManager
1672 *destination;
1673
1674 destination=(DestinationManager *) cinfo->dest;
1675 destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1676 MaxBufferExtent,destination->buffer);
1677 if (destination->manager.free_in_buffer != MaxBufferExtent)
1678 ERREXIT(cinfo,JERR_FILE_WRITE);
1679 destination->manager.next_output_byte=destination->buffer;
1680 return(TRUE);
1681 }
1682
GetQuantizationTable(const char * filename,const char * slot,ExceptionInfo * exception)1683 static QuantizationTable *GetQuantizationTable(const char *filename,
1684 const char *slot,ExceptionInfo *exception)
1685 {
1686 char
1687 *p,
1688 *xml;
1689
1690 const char
1691 *attribute,
1692 *content;
1693
1694 double
1695 value;
1696
1697 register ssize_t
1698 i;
1699
1700 ssize_t
1701 j;
1702
1703 QuantizationTable
1704 *table;
1705
1706 size_t
1707 length;
1708
1709 XMLTreeInfo
1710 *description,
1711 *levels,
1712 *quantization_tables,
1713 *table_iterator;
1714
1715 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1716 "Loading quantization tables \"%s\" ...",filename);
1717 table=(QuantizationTable *) NULL;
1718 xml=FileToString(filename,~0UL,exception);
1719 if (xml == (char *) NULL)
1720 return(table);
1721 quantization_tables=NewXMLTree(xml,exception);
1722 if (quantization_tables == (XMLTreeInfo *) NULL)
1723 {
1724 xml=DestroyString(xml);
1725 return(table);
1726 }
1727 for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1728 table_iterator != (XMLTreeInfo *) NULL;
1729 table_iterator=GetNextXMLTreeTag(table_iterator))
1730 {
1731 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1732 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1733 break;
1734 attribute=GetXMLTreeAttribute(table_iterator,"alias");
1735 if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1736 break;
1737 }
1738 if (table_iterator == (XMLTreeInfo *) NULL)
1739 {
1740 xml=DestroyString(xml);
1741 return(table);
1742 }
1743 description=GetXMLTreeChild(table_iterator,"description");
1744 if (description == (XMLTreeInfo *) NULL)
1745 {
1746 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1747 "XmlMissingElement","<description>, slot \"%s\"",slot);
1748 quantization_tables=DestroyXMLTree(quantization_tables);
1749 xml=DestroyString(xml);
1750 return(table);
1751 }
1752 levels=GetXMLTreeChild(table_iterator,"levels");
1753 if (levels == (XMLTreeInfo *) NULL)
1754 {
1755 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1756 "XmlMissingElement","<levels>, slot \"%s\"",slot);
1757 quantization_tables=DestroyXMLTree(quantization_tables);
1758 xml=DestroyString(xml);
1759 return(table);
1760 }
1761 table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1762 if (table == (QuantizationTable *) NULL)
1763 ThrowFatalException(ResourceLimitFatalError,
1764 "UnableToAcquireQuantizationTable");
1765 table->slot=(char *) NULL;
1766 table->description=(char *) NULL;
1767 table->levels=(unsigned int *) NULL;
1768 attribute=GetXMLTreeAttribute(table_iterator,"slot");
1769 if (attribute != (char *) NULL)
1770 table->slot=ConstantString(attribute);
1771 content=GetXMLTreeContent(description);
1772 if (content != (char *) NULL)
1773 table->description=ConstantString(content);
1774 attribute=GetXMLTreeAttribute(levels,"width");
1775 if (attribute == (char *) NULL)
1776 {
1777 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1778 "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1779 quantization_tables=DestroyXMLTree(quantization_tables);
1780 table=DestroyQuantizationTable(table);
1781 xml=DestroyString(xml);
1782 return(table);
1783 }
1784 table->width=StringToUnsignedLong(attribute);
1785 if (table->width == 0)
1786 {
1787 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1788 "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1789 quantization_tables=DestroyXMLTree(quantization_tables);
1790 table=DestroyQuantizationTable(table);
1791 xml=DestroyString(xml);
1792 return(table);
1793 }
1794 attribute=GetXMLTreeAttribute(levels,"height");
1795 if (attribute == (char *) NULL)
1796 {
1797 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1798 "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1799 quantization_tables=DestroyXMLTree(quantization_tables);
1800 table=DestroyQuantizationTable(table);
1801 xml=DestroyString(xml);
1802 return(table);
1803 }
1804 table->height=StringToUnsignedLong(attribute);
1805 if (table->height == 0)
1806 {
1807 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1808 "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1809 quantization_tables=DestroyXMLTree(quantization_tables);
1810 table=DestroyQuantizationTable(table);
1811 xml=DestroyString(xml);
1812 return(table);
1813 }
1814 attribute=GetXMLTreeAttribute(levels,"divisor");
1815 if (attribute == (char *) NULL)
1816 {
1817 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1818 "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1819 quantization_tables=DestroyXMLTree(quantization_tables);
1820 table=DestroyQuantizationTable(table);
1821 xml=DestroyString(xml);
1822 return(table);
1823 }
1824 table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1825 if (table->divisor == 0.0)
1826 {
1827 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1828 "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1829 quantization_tables=DestroyXMLTree(quantization_tables);
1830 table=DestroyQuantizationTable(table);
1831 xml=DestroyString(xml);
1832 return(table);
1833 }
1834 content=GetXMLTreeContent(levels);
1835 if (content == (char *) NULL)
1836 {
1837 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1838 "XmlMissingContent","<levels>, table \"%s\"",slot);
1839 quantization_tables=DestroyXMLTree(quantization_tables);
1840 table=DestroyQuantizationTable(table);
1841 xml=DestroyString(xml);
1842 return(table);
1843 }
1844 length=(size_t) table->width*table->height;
1845 if (length < 64)
1846 length=64;
1847 table->levels=(unsigned int *) AcquireQuantumMemory(length,
1848 sizeof(*table->levels));
1849 if (table->levels == (unsigned int *) NULL)
1850 ThrowFatalException(ResourceLimitFatalError,
1851 "UnableToAcquireQuantizationTable");
1852 for (i=0; i < (ssize_t) (table->width*table->height); i++)
1853 {
1854 table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1855 table->divisor+0.5);
1856 while (isspace((int) ((unsigned char) *p)) != 0)
1857 p++;
1858 if (*p == ',')
1859 p++;
1860 content=p;
1861 }
1862 value=InterpretLocaleValue(content,&p);
1863 (void) value;
1864 if (p != content)
1865 {
1866 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1867 "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1868 quantization_tables=DestroyXMLTree(quantization_tables);
1869 table=DestroyQuantizationTable(table);
1870 xml=DestroyString(xml);
1871 return(table);
1872 }
1873 for (j=i; j < 64; j++)
1874 table->levels[j]=table->levels[j-1];
1875 quantization_tables=DestroyXMLTree(quantization_tables);
1876 xml=DestroyString(xml);
1877 return(table);
1878 }
1879
InitializeDestination(j_compress_ptr cinfo)1880 static void InitializeDestination(j_compress_ptr cinfo)
1881 {
1882 DestinationManager
1883 *destination;
1884
1885 destination=(DestinationManager *) cinfo->dest;
1886 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1887 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1888 destination->manager.next_output_byte=destination->buffer;
1889 destination->manager.free_in_buffer=MaxBufferExtent;
1890 }
1891
TerminateDestination(j_compress_ptr cinfo)1892 static void TerminateDestination(j_compress_ptr cinfo)
1893 {
1894 DestinationManager
1895 *destination;
1896
1897 destination=(DestinationManager *) cinfo->dest;
1898 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1899 {
1900 ssize_t
1901 count;
1902
1903 count=WriteBlob(destination->image,MaxBufferExtent-
1904 destination->manager.free_in_buffer,destination->buffer);
1905 if (count != (ssize_t)
1906 (MaxBufferExtent-destination->manager.free_in_buffer))
1907 ERREXIT(cinfo,JERR_FILE_WRITE);
1908 }
1909 }
1910
WriteProfile(j_compress_ptr jpeg_info,Image * image)1911 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1912 {
1913 const char
1914 *name;
1915
1916 const StringInfo
1917 *profile;
1918
1919 MagickBooleanType
1920 iptc;
1921
1922 register ssize_t
1923 i;
1924
1925 size_t
1926 length,
1927 tag_length;
1928
1929 StringInfo
1930 *custom_profile;
1931
1932 /*
1933 Save image profile as a APP marker.
1934 */
1935 iptc=MagickFalse;
1936 custom_profile=AcquireStringInfo(65535L);
1937 ResetImageProfileIterator(image);
1938 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1939 {
1940 profile=GetImageProfile(image,name);
1941 if (LocaleCompare(name,"EXIF") == 0)
1942 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1943 {
1944 length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1945 jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1946 (unsigned int) length);
1947 }
1948 if (LocaleCompare(name,"ICC") == 0)
1949 {
1950 register unsigned char
1951 *p;
1952
1953 tag_length=strlen(ICC_PROFILE);
1954 p=GetStringInfoDatum(custom_profile);
1955 (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1956 p[tag_length]='\0';
1957 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1958 {
1959 length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1960 p[12]=(unsigned char) ((i/65519L)+1);
1961 p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1962 (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1963 length);
1964 jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1965 custom_profile),(unsigned int) (length+tag_length+3));
1966 }
1967 }
1968 if (((LocaleCompare(name,"IPTC") == 0) ||
1969 (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1970 {
1971 register unsigned char
1972 *p;
1973
1974 size_t
1975 roundup;
1976
1977 iptc=MagickTrue;
1978 p=GetStringInfoDatum(custom_profile);
1979 for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1980 {
1981 length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1982 roundup=(size_t) (length & 0x01);
1983 if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1984 {
1985 (void) memcpy(p,"Photoshop 3.0 ",14);
1986 tag_length=14;
1987 }
1988 else
1989 {
1990 (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1991 tag_length=26;
1992 p[24]=(unsigned char) (length >> 8);
1993 p[25]=(unsigned char) (length & 0xff);
1994 }
1995 p[13]=0x00;
1996 (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1997 if (roundup != 0)
1998 p[length+tag_length]='\0';
1999 jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2000 custom_profile),(unsigned int) (length+tag_length+roundup));
2001 }
2002 }
2003 if (LocaleCompare(name,"XMP") == 0)
2004 {
2005 StringInfo
2006 *xmp_profile;
2007
2008 /*
2009 Add namespace to XMP profile.
2010 */
2011 xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2012 if (xmp_profile != (StringInfo *) NULL)
2013 {
2014 if (profile != (StringInfo *) NULL)
2015 ConcatenateStringInfo(xmp_profile,profile);
2016 GetStringInfoDatum(xmp_profile)[28]='\0';
2017 for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2018 {
2019 length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2020 jpeg_write_marker(jpeg_info,XML_MARKER,
2021 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2022 }
2023 xmp_profile=DestroyStringInfo(xmp_profile);
2024 }
2025 }
2026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2027 "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2028 name=GetNextImageProfile(image);
2029 }
2030 custom_profile=DestroyStringInfo(custom_profile);
2031 }
2032
JPEGDestinationManager(j_compress_ptr cinfo,Image * image)2033 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2034 {
2035 DestinationManager
2036 *destination;
2037
2038 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2039 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2040 destination=(DestinationManager *) cinfo->dest;
2041 destination->manager.init_destination=InitializeDestination;
2042 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2043 destination->manager.term_destination=TerminateDestination;
2044 destination->image=image;
2045 }
2046
SamplingFactorToList(const char * text)2047 static char **SamplingFactorToList(const char *text)
2048 {
2049 char
2050 **textlist;
2051
2052 register char
2053 *q;
2054
2055 register const char
2056 *p;
2057
2058 register ssize_t
2059 i;
2060
2061 if (text == (char *) NULL)
2062 return((char **) NULL);
2063 /*
2064 Convert string to an ASCII list.
2065 */
2066 textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2067 sizeof(*textlist));
2068 if (textlist == (char **) NULL)
2069 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2070 p=text;
2071 for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2072 {
2073 for (q=(char *) p; *q != '\0'; q++)
2074 if (*q == ',')
2075 break;
2076 textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2077 sizeof(*textlist[i]));
2078 if (textlist[i] == (char *) NULL)
2079 ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2080 (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2081 if (*q == '\r')
2082 q++;
2083 if (*q == '\0')
2084 break;
2085 p=q+1;
2086 }
2087 for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2088 textlist[i]=ConstantString("1x1");
2089 return(textlist);
2090 }
2091
WriteJPEGImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)2092 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2093 Image *image,ExceptionInfo *exception)
2094 {
2095 const char
2096 *option,
2097 *sampling_factor,
2098 *value;
2099
2100 ErrorManager
2101 error_manager;
2102
2103 Image
2104 *volatile volatile_image;
2105
2106 int
2107 colorspace,
2108 quality;
2109
2110 JSAMPLE
2111 *volatile jpeg_pixels;
2112
2113 JSAMPROW
2114 scanline[1];
2115
2116 MagickBooleanType
2117 status;
2118
2119 MemoryInfo
2120 *memory_info;
2121
2122 register JSAMPLE
2123 *q;
2124
2125 register ssize_t
2126 i;
2127
2128 ssize_t
2129 y;
2130
2131 struct jpeg_compress_struct
2132 jpeg_info;
2133
2134 struct jpeg_error_mgr
2135 jpeg_error;
2136
2137 unsigned short
2138 scale;
2139
2140 /*
2141 Open image file.
2142 */
2143 assert(image_info != (const ImageInfo *) NULL);
2144 assert(image_info->signature == MagickCoreSignature);
2145 assert(image != (Image *) NULL);
2146 assert(image->signature == MagickCoreSignature);
2147 if (image->debug != MagickFalse)
2148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2149 assert(exception != (ExceptionInfo *) NULL);
2150 assert(exception->signature == MagickCoreSignature);
2151 if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2152 (image->next != (Image *) NULL))
2153 image=AppendImages(image,MagickFalse,exception);
2154 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2155 if (status == MagickFalse)
2156 return(status);
2157 /*
2158 Initialize JPEG parameters.
2159 */
2160 (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2161 (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2162 (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2163 volatile_image=image;
2164 jpeg_info.client_data=(void *) volatile_image;
2165 jpeg_info.err=jpeg_std_error(&jpeg_error);
2166 jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2167 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2168 error_manager.exception=exception;
2169 error_manager.image=volatile_image;
2170 memory_info=(MemoryInfo *) NULL;
2171 if (setjmp(error_manager.error_recovery) != 0)
2172 {
2173 jpeg_destroy_compress(&jpeg_info);
2174 (void) CloseBlob(volatile_image);
2175 return(MagickFalse);
2176 }
2177 jpeg_info.client_data=(void *) &error_manager;
2178 jpeg_create_compress(&jpeg_info);
2179 JPEGDestinationManager(&jpeg_info,image);
2180 if ((image->columns != (unsigned int) image->columns) ||
2181 (image->rows != (unsigned int) image->rows))
2182 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2183 jpeg_info.image_width=(unsigned int) image->columns;
2184 jpeg_info.image_height=(unsigned int) image->rows;
2185 jpeg_info.input_components=3;
2186 jpeg_info.data_precision=8;
2187 jpeg_info.in_color_space=JCS_RGB;
2188 switch (image->colorspace)
2189 {
2190 case CMYKColorspace:
2191 {
2192 jpeg_info.input_components=4;
2193 jpeg_info.in_color_space=JCS_CMYK;
2194 break;
2195 }
2196 case YCbCrColorspace:
2197 case Rec601YCbCrColorspace:
2198 case Rec709YCbCrColorspace:
2199 {
2200 jpeg_info.in_color_space=JCS_YCbCr;
2201 break;
2202 }
2203 case GRAYColorspace:
2204 {
2205 if (image_info->type == TrueColorType)
2206 break;
2207 jpeg_info.input_components=1;
2208 jpeg_info.in_color_space=JCS_GRAYSCALE;
2209 break;
2210 }
2211 default:
2212 {
2213 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2214 if (image_info->type == TrueColorType)
2215 break;
2216 if (SetImageGray(image,exception) != MagickFalse)
2217 {
2218 jpeg_info.input_components=1;
2219 jpeg_info.in_color_space=JCS_GRAYSCALE;
2220 }
2221 break;
2222 }
2223 }
2224 jpeg_set_defaults(&jpeg_info);
2225 if (jpeg_info.in_color_space == JCS_CMYK)
2226 jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2227 if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2228 jpeg_info.data_precision=8;
2229 else
2230 jpeg_info.data_precision=BITS_IN_JSAMPLE;
2231 if (image->debug != MagickFalse)
2232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2233 "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2234 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2235 {
2236 /*
2237 Set image resolution.
2238 */
2239 jpeg_info.write_JFIF_header=TRUE;
2240 jpeg_info.X_density=(UINT16) image->resolution.x;
2241 jpeg_info.Y_density=(UINT16) image->resolution.y;
2242 /*
2243 Set image resolution units.
2244 */
2245 if (image->units == PixelsPerInchResolution)
2246 jpeg_info.density_unit=(UINT8) 1;
2247 if (image->units == PixelsPerCentimeterResolution)
2248 jpeg_info.density_unit=(UINT8) 2;
2249 }
2250 jpeg_info.dct_method=JDCT_FLOAT;
2251 option=GetImageOption(image_info,"jpeg:dct-method");
2252 if (option != (const char *) NULL)
2253 switch (*option)
2254 {
2255 case 'D':
2256 case 'd':
2257 {
2258 if (LocaleCompare(option,"default") == 0)
2259 jpeg_info.dct_method=JDCT_DEFAULT;
2260 break;
2261 }
2262 case 'F':
2263 case 'f':
2264 {
2265 if (LocaleCompare(option,"fastest") == 0)
2266 jpeg_info.dct_method=JDCT_FASTEST;
2267 if (LocaleCompare(option,"float") == 0)
2268 jpeg_info.dct_method=JDCT_FLOAT;
2269 break;
2270 }
2271 case 'I':
2272 case 'i':
2273 {
2274 if (LocaleCompare(option,"ifast") == 0)
2275 jpeg_info.dct_method=JDCT_IFAST;
2276 if (LocaleCompare(option,"islow") == 0)
2277 jpeg_info.dct_method=JDCT_ISLOW;
2278 break;
2279 }
2280 }
2281 option=GetImageOption(image_info,"jpeg:optimize-coding");
2282 if (option != (const char *) NULL)
2283 jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2284 FALSE;
2285 else
2286 {
2287 MagickSizeType
2288 length;
2289
2290 length=(MagickSizeType) jpeg_info.input_components*image->columns*
2291 image->rows*sizeof(JSAMPLE);
2292 if (length == (MagickSizeType) ((size_t) length))
2293 {
2294 /*
2295 Perform optimization only if available memory resources permit it.
2296 */
2297 status=AcquireMagickResource(MemoryResource,length);
2298 RelinquishMagickResource(MemoryResource,length);
2299 jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2300 }
2301 }
2302 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2303 if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2304 (image_info->interlace != NoInterlace))
2305 {
2306 if (image->debug != MagickFalse)
2307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2308 "Interlace: progressive");
2309 jpeg_simple_progression(&jpeg_info);
2310 }
2311 else
2312 if (image->debug != MagickFalse)
2313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2314 "Interlace: non-progressive");
2315 #else
2316 if (image->debug != MagickFalse)
2317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2318 "Interlace: nonprogressive");
2319 #endif
2320 quality=92;
2321 if ((image_info->compression != LosslessJPEGCompression) &&
2322 (image->quality <= 100))
2323 {
2324 if (image->quality != UndefinedCompressionQuality)
2325 quality=(int) image->quality;
2326 if (image->debug != MagickFalse)
2327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2328 (double) image->quality);
2329 }
2330 else
2331 {
2332 #if !defined(C_LOSSLESS_SUPPORTED)
2333 quality=100;
2334 if (image->debug != MagickFalse)
2335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2336 #else
2337 if (image->quality < 100)
2338 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2339 "LosslessToLossyJPEGConversion",image->filename);
2340 else
2341 {
2342 int
2343 point_transform,
2344 predictor;
2345
2346 predictor=image->quality/100; /* range 1-7 */
2347 point_transform=image->quality % 20; /* range 0-15 */
2348 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2349 if (image->debug != MagickFalse)
2350 {
2351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2352 "Compression: lossless");
2353 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2354 "Predictor: %d",predictor);
2355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2356 "Point Transform: %d",point_transform);
2357 }
2358 }
2359 #endif
2360 }
2361 option=GetImageOption(image_info,"jpeg:extent");
2362 if (option != (const char *) NULL)
2363 {
2364 Image
2365 *jpeg_image;
2366
2367 ImageInfo
2368 *extent_info;
2369
2370 extent_info=CloneImageInfo(image_info);
2371 extent_info->blob=NULL;
2372 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2373 if (jpeg_image != (Image *) NULL)
2374 {
2375 MagickSizeType
2376 extent;
2377
2378 size_t
2379 maximum,
2380 minimum;
2381
2382 /*
2383 Search for compression quality that does not exceed image extent.
2384 */
2385 extent_info->quality=0;
2386 extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2387 (void) DeleteImageOption(extent_info,"jpeg:extent");
2388 (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2389 maximum=image_info->quality;
2390 if (maximum < 2)
2391 maximum=101;
2392 for (minimum=2; minimum < maximum; )
2393 {
2394 (void) AcquireUniqueFilename(jpeg_image->filename);
2395 jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2396 status=WriteJPEGImage(extent_info,jpeg_image,exception);
2397 if (GetBlobSize(jpeg_image) <= extent)
2398 minimum=jpeg_image->quality+1;
2399 else
2400 maximum=jpeg_image->quality-1;
2401 (void) RelinquishUniqueFileResource(jpeg_image->filename);
2402 }
2403 quality=(int) minimum-1;
2404 jpeg_image=DestroyImage(jpeg_image);
2405 }
2406 extent_info=DestroyImageInfo(extent_info);
2407 }
2408 jpeg_set_quality(&jpeg_info,quality,TRUE);
2409 #if (JPEG_LIB_VERSION >= 70)
2410 option=GetImageOption(image_info,"quality");
2411 if (option != (const char *) NULL)
2412 {
2413 GeometryInfo
2414 geometry_info;
2415
2416 int
2417 flags;
2418
2419 /*
2420 Set quality scaling for luminance and chrominance separately.
2421 */
2422 flags=ParseGeometry(option,&geometry_info);
2423 if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2424 {
2425 jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2426 (geometry_info.rho+0.5));
2427 jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2428 (geometry_info.sigma+0.5));
2429 jpeg_default_qtables(&jpeg_info,TRUE);
2430 }
2431 }
2432 #endif
2433 colorspace=jpeg_info.in_color_space;
2434 value=GetImageOption(image_info,"jpeg:colorspace");
2435 if (value == (char *) NULL)
2436 value=GetImageProperty(image,"jpeg:colorspace",exception);
2437 if (value != (char *) NULL)
2438 colorspace=StringToInteger(value);
2439 sampling_factor=(const char *) NULL;
2440 if (colorspace == jpeg_info.in_color_space)
2441 {
2442 value=GetImageOption(image_info,"jpeg:sampling-factor");
2443 if (value == (char *) NULL)
2444 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2445 if (value != (char *) NULL)
2446 {
2447 sampling_factor=value;
2448 if (image->debug != MagickFalse)
2449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2450 " Input sampling-factors=%s",sampling_factor);
2451 }
2452 }
2453 value=GetImageOption(image_info,"jpeg:sampling-factor");
2454 if (image_info->sampling_factor != (char *) NULL)
2455 sampling_factor=image_info->sampling_factor;
2456 if (sampling_factor == (const char *) NULL)
2457 {
2458 if (quality >= 90)
2459 for (i=0; i < MAX_COMPONENTS; i++)
2460 {
2461 jpeg_info.comp_info[i].h_samp_factor=1;
2462 jpeg_info.comp_info[i].v_samp_factor=1;
2463 }
2464 }
2465 else
2466 {
2467 char
2468 **factors;
2469
2470 GeometryInfo
2471 geometry_info;
2472
2473 MagickStatusType
2474 flags;
2475
2476 /*
2477 Set sampling factor.
2478 */
2479 i=0;
2480 factors=SamplingFactorToList(sampling_factor);
2481 if (factors != (char **) NULL)
2482 {
2483 for (i=0; i < MAX_COMPONENTS; i++)
2484 {
2485 if (factors[i] == (char *) NULL)
2486 break;
2487 flags=ParseGeometry(factors[i],&geometry_info);
2488 if ((flags & SigmaValue) == 0)
2489 geometry_info.sigma=geometry_info.rho;
2490 jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2491 jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2492 factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2493 }
2494 factors=(char **) RelinquishMagickMemory(factors);
2495 }
2496 for ( ; i < MAX_COMPONENTS; i++)
2497 {
2498 jpeg_info.comp_info[i].h_samp_factor=1;
2499 jpeg_info.comp_info[i].v_samp_factor=1;
2500 }
2501 }
2502 option=GetImageOption(image_info,"jpeg:q-table");
2503 if (option != (const char *) NULL)
2504 {
2505 QuantizationTable
2506 *table;
2507
2508 /*
2509 Custom quantization tables.
2510 */
2511 table=GetQuantizationTable(option,"0",exception);
2512 if (table != (QuantizationTable *) NULL)
2513 {
2514 for (i=0; i < MAX_COMPONENTS; i++)
2515 jpeg_info.comp_info[i].quant_tbl_no=0;
2516 jpeg_add_quant_table(&jpeg_info,0,table->levels,
2517 jpeg_quality_scaling(quality),0);
2518 table=DestroyQuantizationTable(table);
2519 }
2520 table=GetQuantizationTable(option,"1",exception);
2521 if (table != (QuantizationTable *) NULL)
2522 {
2523 for (i=1; i < MAX_COMPONENTS; i++)
2524 jpeg_info.comp_info[i].quant_tbl_no=1;
2525 jpeg_add_quant_table(&jpeg_info,1,table->levels,
2526 jpeg_quality_scaling(quality),0);
2527 table=DestroyQuantizationTable(table);
2528 }
2529 table=GetQuantizationTable(option,"2",exception);
2530 if (table != (QuantizationTable *) NULL)
2531 {
2532 for (i=2; i < MAX_COMPONENTS; i++)
2533 jpeg_info.comp_info[i].quant_tbl_no=2;
2534 jpeg_add_quant_table(&jpeg_info,2,table->levels,
2535 jpeg_quality_scaling(quality),0);
2536 table=DestroyQuantizationTable(table);
2537 }
2538 table=GetQuantizationTable(option,"3",exception);
2539 if (table != (QuantizationTable *) NULL)
2540 {
2541 for (i=3; i < MAX_COMPONENTS; i++)
2542 jpeg_info.comp_info[i].quant_tbl_no=3;
2543 jpeg_add_quant_table(&jpeg_info,3,table->levels,
2544 jpeg_quality_scaling(quality),0);
2545 table=DestroyQuantizationTable(table);
2546 }
2547 }
2548 jpeg_start_compress(&jpeg_info,TRUE);
2549 if (image->debug != MagickFalse)
2550 {
2551 if (image->storage_class == PseudoClass)
2552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2553 "Storage class: PseudoClass");
2554 else
2555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2556 "Storage class: DirectClass");
2557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2558 (double) image->depth);
2559 if (image->colors != 0)
2560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2561 "Number of colors: %.20g",(double) image->colors);
2562 else
2563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2564 "Number of colors: unspecified");
2565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2566 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2567 switch (image->colorspace)
2568 {
2569 case CMYKColorspace:
2570 {
2571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2572 "Storage class: DirectClass");
2573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2574 "Colorspace: CMYK");
2575 break;
2576 }
2577 case YCbCrColorspace:
2578 case Rec601YCbCrColorspace:
2579 case Rec709YCbCrColorspace:
2580 {
2581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2582 "Colorspace: YCbCr");
2583 break;
2584 }
2585 default:
2586 break;
2587 }
2588 switch (image->colorspace)
2589 {
2590 case CMYKColorspace:
2591 {
2592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2593 "Colorspace: CMYK");
2594 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2595 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2596 jpeg_info.comp_info[0].h_samp_factor,
2597 jpeg_info.comp_info[0].v_samp_factor,
2598 jpeg_info.comp_info[1].h_samp_factor,
2599 jpeg_info.comp_info[1].v_samp_factor,
2600 jpeg_info.comp_info[2].h_samp_factor,
2601 jpeg_info.comp_info[2].v_samp_factor,
2602 jpeg_info.comp_info[3].h_samp_factor,
2603 jpeg_info.comp_info[3].v_samp_factor);
2604 break;
2605 }
2606 case GRAYColorspace:
2607 {
2608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2609 "Colorspace: GRAY");
2610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2611 "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2612 jpeg_info.comp_info[0].v_samp_factor);
2613 break;
2614 }
2615 case sRGBColorspace:
2616 case RGBColorspace:
2617 {
2618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2619 "Image colorspace is RGB");
2620 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2621 "Sampling factors: %dx%d,%dx%d,%dx%d",
2622 jpeg_info.comp_info[0].h_samp_factor,
2623 jpeg_info.comp_info[0].v_samp_factor,
2624 jpeg_info.comp_info[1].h_samp_factor,
2625 jpeg_info.comp_info[1].v_samp_factor,
2626 jpeg_info.comp_info[2].h_samp_factor,
2627 jpeg_info.comp_info[2].v_samp_factor);
2628 break;
2629 }
2630 case YCbCrColorspace:
2631 case Rec601YCbCrColorspace:
2632 case Rec709YCbCrColorspace:
2633 {
2634 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2635 "Colorspace: YCbCr");
2636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2637 "Sampling factors: %dx%d,%dx%d,%dx%d",
2638 jpeg_info.comp_info[0].h_samp_factor,
2639 jpeg_info.comp_info[0].v_samp_factor,
2640 jpeg_info.comp_info[1].h_samp_factor,
2641 jpeg_info.comp_info[1].v_samp_factor,
2642 jpeg_info.comp_info[2].h_samp_factor,
2643 jpeg_info.comp_info[2].v_samp_factor);
2644 break;
2645 }
2646 default:
2647 {
2648 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2649 image->colorspace);
2650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2651 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2652 jpeg_info.comp_info[0].h_samp_factor,
2653 jpeg_info.comp_info[0].v_samp_factor,
2654 jpeg_info.comp_info[1].h_samp_factor,
2655 jpeg_info.comp_info[1].v_samp_factor,
2656 jpeg_info.comp_info[2].h_samp_factor,
2657 jpeg_info.comp_info[2].v_samp_factor,
2658 jpeg_info.comp_info[3].h_samp_factor,
2659 jpeg_info.comp_info[3].v_samp_factor);
2660 break;
2661 }
2662 }
2663 }
2664 /*
2665 Write JPEG profiles.
2666 */
2667 value=GetImageProperty(image,"comment",exception);
2668 if (value != (char *) NULL)
2669 for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2670 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2671 (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2672 if (image->profiles != (void *) NULL)
2673 WriteProfile(&jpeg_info,image);
2674 /*
2675 Convert MIFF to JPEG raster pixels.
2676 */
2677 memory_info=AcquireVirtualMemory((size_t) image->columns,
2678 jpeg_info.input_components*sizeof(*jpeg_pixels));
2679 if (memory_info == (MemoryInfo *) NULL)
2680 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2681 jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2682 if (setjmp(error_manager.error_recovery) != 0)
2683 {
2684 jpeg_destroy_compress(&jpeg_info);
2685 if (memory_info != (MemoryInfo *) NULL)
2686 memory_info=RelinquishVirtualMemory(memory_info);
2687 (void) CloseBlob(image);
2688 return(MagickFalse);
2689 }
2690 scanline[0]=(JSAMPROW) jpeg_pixels;
2691 scale=65535/(unsigned short) GetQuantumRange((size_t)
2692 jpeg_info.data_precision);
2693 if (scale == 0)
2694 scale=1;
2695 if (jpeg_info.data_precision <= 8)
2696 {
2697 if ((jpeg_info.in_color_space == JCS_RGB) ||
2698 (jpeg_info.in_color_space == JCS_YCbCr))
2699 for (y=0; y < (ssize_t) image->rows; y++)
2700 {
2701 register const Quantum
2702 *p;
2703
2704 register ssize_t
2705 x;
2706
2707 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2708 if (p == (const Quantum *) NULL)
2709 break;
2710 q=jpeg_pixels;
2711 for (x=0; x < (ssize_t) image->columns; x++)
2712 {
2713 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2714 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2715 *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2716 p+=GetPixelChannels(image);
2717 }
2718 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2719 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2720 image->rows);
2721 if (status == MagickFalse)
2722 break;
2723 }
2724 else
2725 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2726 for (y=0; y < (ssize_t) image->rows; y++)
2727 {
2728 register const Quantum
2729 *p;
2730
2731 register ssize_t
2732 x;
2733
2734 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2735 if (p == (const Quantum *) NULL)
2736 break;
2737 q=jpeg_pixels;
2738 for (x=0; x < (ssize_t) image->columns; x++)
2739 {
2740 *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2741 image,p)));
2742 p+=GetPixelChannels(image);
2743 }
2744 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2745 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2746 image->rows);
2747 if (status == MagickFalse)
2748 break;
2749 }
2750 else
2751 for (y=0; y < (ssize_t) image->rows; y++)
2752 {
2753 register const Quantum
2754 *p;
2755
2756 register ssize_t
2757 x;
2758
2759 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2760 if (p == (const Quantum *) NULL)
2761 break;
2762 q=jpeg_pixels;
2763 for (x=0; x < (ssize_t) image->columns; x++)
2764 {
2765 /*
2766 Convert DirectClass packets to contiguous CMYK scanlines.
2767 */
2768 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2769 GetPixelCyan(image,p))));
2770 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2771 GetPixelMagenta(image,p))));
2772 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2773 GetPixelYellow(image,p))));
2774 *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2775 GetPixelBlack(image,p))));
2776 p+=GetPixelChannels(image);
2777 }
2778 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2779 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2780 image->rows);
2781 if (status == MagickFalse)
2782 break;
2783 }
2784 }
2785 else
2786 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2787 for (y=0; y < (ssize_t) image->rows; y++)
2788 {
2789 register const Quantum
2790 *p;
2791
2792 register ssize_t
2793 x;
2794
2795 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2796 if (p == (const Quantum *) NULL)
2797 break;
2798 q=jpeg_pixels;
2799 for (x=0; x < (ssize_t) image->columns; x++)
2800 {
2801 *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2802 p)))/scale);
2803 p+=GetPixelChannels(image);
2804 }
2805 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2806 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2807 image->rows);
2808 if (status == MagickFalse)
2809 break;
2810 }
2811 else
2812 if ((jpeg_info.in_color_space == JCS_RGB) ||
2813 (jpeg_info.in_color_space == JCS_YCbCr))
2814 for (y=0; y < (ssize_t) image->rows; y++)
2815 {
2816 register const Quantum
2817 *p;
2818
2819 register ssize_t
2820 x;
2821
2822 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2823 if (p == (const Quantum *) NULL)
2824 break;
2825 q=jpeg_pixels;
2826 for (x=0; x < (ssize_t) image->columns; x++)
2827 {
2828 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2829 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2830 *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2831 p+=GetPixelChannels(image);
2832 }
2833 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2834 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2835 image->rows);
2836 if (status == MagickFalse)
2837 break;
2838 }
2839 else
2840 for (y=0; y < (ssize_t) image->rows; y++)
2841 {
2842 register const Quantum
2843 *p;
2844
2845 register ssize_t
2846 x;
2847
2848 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2849 if (p == (const Quantum *) NULL)
2850 break;
2851 q=jpeg_pixels;
2852 for (x=0; x < (ssize_t) image->columns; x++)
2853 {
2854 /*
2855 Convert DirectClass packets to contiguous CMYK scanlines.
2856 */
2857 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2858 image,p))/scale);
2859 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2860 image,p))/scale);
2861 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2862 image,p))/scale);
2863 *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2864 image,p))/scale);
2865 p+=GetPixelChannels(image);
2866 }
2867 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2868 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2869 image->rows);
2870 if (status == MagickFalse)
2871 break;
2872 }
2873 if (y == (ssize_t) image->rows)
2874 jpeg_finish_compress(&jpeg_info);
2875 /*
2876 Relinquish resources.
2877 */
2878 jpeg_destroy_compress(&jpeg_info);
2879 memory_info=RelinquishVirtualMemory(memory_info);
2880 (void) CloseBlob(image);
2881 return(MagickTrue);
2882 }
2883 #endif
2884