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