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