1 /*
2 % Copyright (C) 2003-2020 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
5 %
6 % This program is covered by multiple licenses, which are described in
7 % Copyright.txt. You should have received a copy of Copyright.txt with this
8 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9 %
10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 % %
12 % %
13 % %
14 % JJJJJ PPPP EEEEE GGGG %
15 % J P P E G %
16 % J PPPP EEE G GG %
17 % J J P E G G %
18 % JJJ P EEEEE GGG %
19 % %
20 % %
21 % Read/Write JPEG Image Format. %
22 % %
23 % %
24 % Software Design %
25 % John Cristy %
26 % July 1992 %
27 % %
28 % %
29 % %
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31 %
32 % This software is based in part on the work of the Independent JPEG Group.
33 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
34 % licensing restrictions. Blob support contributed by Glenn Randers-Pehrson.
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/analyze.h"
44 #include "magick/attribute.h"
45 #include "magick/blob.h"
46 #include "magick/colormap.h"
47 #include "magick/enum_strings.h"
48 #include "magick/log.h"
49 #include "magick/magick.h"
50 #include "magick/monitor.h"
51 #include "magick/pixel_cache.h"
52 #include "magick/profile.h"
53 #include "magick/resource.h"
54 #include "magick/utility.h"
55
56 /*
57 Forward declarations.
58 */
59 static unsigned int
60 WriteJPEGImage(const ImageInfo *,Image *);
61
62 /*
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 % %
65 % %
66 % %
67 % I s J P E G %
68 % %
69 % %
70 % %
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %
73 % Method IsJPEG returns True if the image format type, identified by the
74 % magick string, is JPEG.
75 %
76 % The format of the IsJPEG method is:
77 %
78 % unsigned int IsJPEG(const unsigned char *magick,const size_t length)
79 %
80 % A description of each parameter follows:
81 %
82 % o status: Method IsJPEG returns True if the image format type is JPEG.
83 %
84 % o magick: This string is generally the first few bytes of an image file
85 % or blob.
86 %
87 % o length: Specifies the length of the magick string.
88 %
89 %
90 */
IsJPEG(const unsigned char * magick,const size_t length)91 static unsigned int IsJPEG(const unsigned char *magick,const size_t length)
92 {
93 if (length < 3)
94 return(False);
95 if (memcmp(magick,"\377\330\377",3) == 0)
96 return(True);
97 return(False);
98 }
99
100 #if defined(HasJPEG)
101 #define JPEG_INTERNAL_OPTIONS
102 /*
103 Avoid conflicting typedef for INT32
104 */
105 #if defined(__MINGW32__)
106 # define XMD_H 1
107 #endif
108 /*
109 The JPEG headers have the annoying problem that they define
110 HAVE_STDLIB_H and we do too. The define isn't actually used
111 so just undef it.
112 */
113 #undef HAVE_STDLIB_H
114 #include <setjmp.h>
115 #include "jpeglib.h"
116 #include "jerror.h"
117
118 /*
119 Define declarations.
120 */
121 #define ICC_MARKER (JPEG_APP0+2)
122 #define IPTC_MARKER (JPEG_APP0+13)
123 #define XML_MARKER (JPEG_APP0+1)
124 #define MaxBufferExtent 8192
125 #define JPEG_MARKER_MAX_SIZE 65533
126 #define MaxWarningCount 3
127
128 /*
129 Set to 1 to use libjpeg callback for progress indication. This is
130 not enabled by default since it outputs multiple progress
131 indications, which may be confusing for the user. However, the
132 libjpeg method provides more detailed progress.
133 */
134 #define USE_LIBJPEG_PROGRESS 0 /* Use libjpeg callback for progress */
135
136 static const char xmp_std_header[]="http://ns.adobe.com/xap/1.0/";
137
138
139 typedef struct _DestinationManager
140 {
141 struct jpeg_destination_mgr
142 manager;
143
144 Image
145 *image;
146
147 JOCTET
148 *buffer;
149
150 } DestinationManager;
151
152 typedef struct _ErrorManager
153 {
154 Image
155 *image;
156
157 MagickBool
158 ping;
159
160 MagickBool
161 completed;
162
163 jmp_buf
164 error_recovery;
165
166 unsigned int
167 max_warning_count;
168
169 magick_uint16_t
170 warning_counts[JMSG_LASTMSGCODE];
171
172 int
173 max_scan_number;
174
175 unsigned char
176 buffer[65537+200];
177
178 } ErrorManager;
179
180 typedef struct _SourceManager
181 {
182 struct jpeg_source_mgr
183 manager;
184
185 Image
186 *image;
187
188 JOCTET
189 *buffer;
190
191 boolean
192 start_of_blob;
193 } SourceManager;
194
195 /*
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 % %
198 % %
199 % %
200 % R e a d J P E G I m a g e %
201 % %
202 % %
203 % %
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %
206 % Method ReadJPEGImage reads a JPEG image file and returns it. It allocates
207 % the memory necessary for the new Image structure and returns a pointer to
208 % the new image.
209 %
210 % The format of the ReadJPEGImage method is:
211 %
212 % Image *ReadJPEGImage(const ImageInfo *image_info,
213 % ExceptionInfo *exception)
214 %
215 % A description of each parameter follows:
216 %
217 % o image: Method ReadJPEGImage returns a pointer to the image after
218 % reading. A null image is returned if there is a memory shortage or
219 % if the image cannot be read.
220 %
221 % o image_info: Specifies a pointer to a ImageInfo structure.
222 %
223 % o exception: return any errors or warnings in this structure.
224 %
225 %
226 */
227
228
229 /*
230 Format a libjpeg warning or trace event while decoding. Warnings
231 are converted to GraphicsMagick warning exceptions while traces are
232 optionally logged.
233
234 JPEG message codes range from 0 to JMSG_LASTMSGCODE
235 */
JPEGDecodeMessageHandler(j_common_ptr jpeg_info,int msg_level)236 static void JPEGDecodeMessageHandler(j_common_ptr jpeg_info,int msg_level)
237 {
238 char
239 message[JMSG_LENGTH_MAX];
240
241 struct jpeg_error_mgr
242 *err;
243
244 ErrorManager
245 *error_manager;
246
247 Image
248 *image;
249
250 message[0]='\0';
251 err=jpeg_info->err;
252 error_manager=(ErrorManager *) jpeg_info->client_data;
253 image=error_manager->image;
254 /* msg_level is -1 for warnings, 0 and up for trace messages. */
255 if (msg_level < 0)
256 {
257 unsigned int strikes = 0;
258 /* A warning */
259 (err->format_message)(jpeg_info,message);
260
261 if ((err->msg_code >= 0) &&
262 ((size_t) err->msg_code < ArraySize(error_manager->warning_counts)))
263 {
264 error_manager->warning_counts[err->msg_code]++;
265 strikes=error_manager->warning_counts[err->msg_code];
266 }
267
268 if (image->logging)
269 {
270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
271 "[%s] JPEG Warning[%u]: \"%s\""
272 " (code=%d "
273 "parms=0x%02x,0x%02x,"
274 "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)",
275 image->filename,
276 strikes,
277 message,err->msg_code,
278 err->msg_parm.i[0], err->msg_parm.i[1],
279 err->msg_parm.i[2], err->msg_parm.i[3],
280 err->msg_parm.i[4], err->msg_parm.i[5],
281 err->msg_parm.i[6], err->msg_parm.i[7]);
282 }
283 if (strikes > error_manager->max_warning_count)
284 {
285 ThrowException2(&image->exception,CorruptImageError,(char *) message,
286 image->filename);
287 longjmp(error_manager->error_recovery,1);
288 }
289
290 if ((err->num_warnings == 0) ||
291 (err->trace_level >= 3))
292 ThrowException2(&image->exception,CorruptImageWarning,message,
293 image->filename);
294 /* JWRN_JPEG_EOF - "Premature end of JPEG file" */
295 err->num_warnings++;
296 return /* False */;
297 }
298 else
299 {
300 /* A trace message */
301 if ((image->logging) && (msg_level >= err->trace_level))
302 {
303 (err->format_message)(jpeg_info,message);
304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
305 "[%s] JPEG Trace: \"%s\"",image->filename,
306 message);
307 }
308 }
309 return /* True */;
310 }
311
JPEGDecodeProgressMonitor(j_common_ptr cinfo)312 static void JPEGDecodeProgressMonitor(j_common_ptr cinfo)
313 {
314 ErrorManager *error_manager = (ErrorManager *) cinfo->client_data;
315 Image *image = error_manager->image;
316 const int max_scan_number = error_manager->max_scan_number;
317
318 #if USE_LIBJPEG_PROGRESS
319 {
320 struct jpeg_progress_mgr *p = cinfo->progress;
321
322 #if 0
323 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
324 "Progress: pass_counter=%ld, pass_limit=%ld,"
325 " completed_passes=%d, total_passes=%d, filename=%s",
326 p->pass_counter, p->pass_limit,
327 p->completed_passes, p->total_passes, image->filename);
328 #endif
329
330 if (QuantumTick(p->pass_counter,p->pass_limit))
331 if (!MagickMonitorFormatted(p->pass_counter,p->pass_limit,&image->exception,
332 "[%s] Loading image: %lux%lu (pass %d of %d)... ",
333 image->filename,
334 image->columns,image->rows,
335 p->completed_passes+1, p->total_passes))
336 {
337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
338 "Quitting due to progress monitor");
339 longjmp(error_manager->error_recovery,1);
340 }
341 }
342 #endif /* USE_LIBJPEG_PROGRESS */
343
344 if (cinfo->is_decompressor)
345 {
346 int scan_no = ((j_decompress_ptr) cinfo)->input_scan_number;
347
348 if (scan_no > max_scan_number)
349 {
350 char message[MaxTextExtent];
351 FormatString(message,"Scan number %d exceeds maximum scans (%d)",
352 scan_no, max_scan_number);
353 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s", message);
354 ThrowException2(&image->exception,CorruptImageError,(char *) message,
355 image->filename);
356 longjmp(error_manager->error_recovery,1);
357 }
358 }
359 }
360
FillInputBuffer(j_decompress_ptr cinfo)361 static boolean FillInputBuffer(j_decompress_ptr cinfo)
362 {
363 SourceManager
364 *source;
365
366 source=(SourceManager *) cinfo->src;
367 source->manager.bytes_in_buffer=
368 ReadBlob(source->image,MaxBufferExtent,(char *) source->buffer);
369 if (source->manager.bytes_in_buffer == 0)
370 {
371 if (source->start_of_blob)
372 ERREXIT(cinfo,JERR_INPUT_EMPTY);
373 WARNMS(cinfo,JWRN_JPEG_EOF);
374 source->buffer[0]=(JOCTET) 0xff;
375 source->buffer[1]=(JOCTET) JPEG_EOI;
376 source->manager.bytes_in_buffer=2;
377 }
378 source->manager.next_input_byte=source->buffer;
379 source->start_of_blob=FALSE;
380 return(TRUE);
381 }
382
GetCharacter(j_decompress_ptr jpeg_info)383 static int GetCharacter(j_decompress_ptr jpeg_info)
384 {
385 if (jpeg_info->src->bytes_in_buffer == 0)
386 if ((!((*jpeg_info->src->fill_input_buffer)(jpeg_info))) ||
387 (jpeg_info->src->bytes_in_buffer == 0))
388 return EOF;
389 jpeg_info->src->bytes_in_buffer--;
390 return(GETJOCTET(*jpeg_info->src->next_input_byte++));
391 }
392
InitializeSource(j_decompress_ptr cinfo)393 static void InitializeSource(j_decompress_ptr cinfo)
394 {
395 SourceManager
396 *source;
397
398 source=(SourceManager *) cinfo->src;
399 source->start_of_blob=TRUE;
400 }
401
402 /*
403 Format and report a libjpeg error event. Errors are reported via a
404 GraphicsMagick error exception. The function terminates with
405 longjmp() so it never returns to the caller.
406 */
407 static void JPEGErrorHandler(j_common_ptr jpeg_info) MAGICK_FUNC_NORETURN;
408
JPEGErrorHandler(j_common_ptr jpeg_info)409 static void JPEGErrorHandler(j_common_ptr jpeg_info)
410 {
411 char
412 message[JMSG_LENGTH_MAX];
413
414 struct jpeg_error_mgr
415 *err;
416
417 ErrorManager
418 *error_manager;
419
420 Image
421 *image;
422
423 message[0]='\0';
424 err=jpeg_info->err;
425 error_manager=(ErrorManager *) jpeg_info->client_data;
426 image=error_manager->image;
427 (err->format_message)(jpeg_info,message);
428 if (image->logging)
429 {
430 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
431 "[%s] JPEG Error: \"%s\" (code=%d, "
432 "parms=0x%02x,0x%02x,"
433 "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)",
434 image->filename,message,err->msg_code,
435 err->msg_parm.i[0], err->msg_parm.i[1],
436 err->msg_parm.i[2], err->msg_parm.i[3],
437 err->msg_parm.i[4], err->msg_parm.i[5],
438 err->msg_parm.i[6], err->msg_parm.i[7]);
439 }
440 if (error_manager->completed)
441 ThrowException2(&image->exception,CoderWarning,(char *) message,
442 image->filename);
443 else
444 ThrowException2(&image->exception,CoderError,(char *) message,
445 image->filename);
446 longjmp(error_manager->error_recovery,1);
447 }
448
449 #define GetProfileLength(jpeg_info, length) \
450 do { \
451 int \
452 _c; \
453 \
454 if (((_c = GetCharacter(jpeg_info)) != EOF) && (_c >= 0)) \
455 { \
456 length=_c*256; \
457 if (((_c = GetCharacter(jpeg_info)) != EOF) && (_c >= 0)) \
458 length+=_c; \
459 else \
460 length=0; \
461 } \
462 else \
463 { \
464 length=0; \
465 } \
466 } while(0)
467
ReadComment(j_decompress_ptr jpeg_info)468 static boolean ReadComment(j_decompress_ptr jpeg_info)
469 {
470 char
471 *comment;
472
473 ErrorManager
474 *error_manager;
475
476 Image
477 *image;
478
479 register char
480 *p;
481
482 size_t
483 i,
484 length;
485
486 int
487 c;
488
489 /*
490 Determine length of comment.
491 */
492 error_manager=(ErrorManager *) jpeg_info->client_data;
493 image=error_manager->image;
494 GetProfileLength(jpeg_info, length);
495 if (length <= 2)
496 return(True);
497 length-=2;
498 comment=(char *) error_manager->buffer;
499 /*
500 Read comment.
501 */
502 p=comment;
503 for (i=0; i < length; i++)
504 {
505 if ((c=GetCharacter(jpeg_info)) == EOF)
506 break;
507 *p=c;
508 p++;
509 }
510 *p='\0';
511 (void) SetImageAttribute(image,"comment",comment);
512 return(True);
513 }
514
ReadGenericProfile(j_decompress_ptr jpeg_info)515 static boolean ReadGenericProfile(j_decompress_ptr jpeg_info)
516 {
517 ErrorManager
518 *error_manager;
519
520 Image
521 *image;
522
523 size_t
524 header_length=0,
525 length;
526
527 register size_t
528 i;
529
530 char
531 profile_name[MaxTextExtent];
532
533 unsigned char
534 *profile;
535
536 int
537 c,
538 marker;
539
540 /*
541 Determine length of generic profile.
542 */
543 GetProfileLength(jpeg_info, length);
544 if (length <= 2)
545 return(True);
546 length-=2;
547
548 marker=jpeg_info->unread_marker-JPEG_APP0;
549
550 /*
551 Compute generic profile name.
552 */
553 FormatString(profile_name,"APP%d",marker);
554
555 /*
556 Obtain Image.
557 */
558 error_manager=(ErrorManager *) jpeg_info->client_data;
559 image=error_manager->image;
560
561 /*
562 Copy profile from JPEG to allocated memory.
563 */
564 profile=error_manager->buffer;
565
566 for (i=0 ; i < length ; i++)
567 {
568 if ((c=GetCharacter(jpeg_info)) != EOF)
569 profile[i]=c;
570 else
571 break;
572 }
573 if (i != length)
574 return True;
575
576 /*
577 Detect EXIF and XMP profiles.
578 */
579 if ((marker == 1) && (length > 4) &&
580 (strncmp((char *) profile,"Exif",4) == 0))
581 {
582 FormatString(profile_name,"EXIF");
583 }
584 else if (((marker == 1) && (length > strlen(xmp_std_header)+1)) &&
585 (memcmp(profile, xmp_std_header, strlen(xmp_std_header)+1) == 0))
586 {
587 /*
588 XMP is required to fit in one 64KB chunk. Strip off its JPEG
589 namespace header.
590 */
591 header_length=strlen(xmp_std_header)+1;
592 FormatString((char *) profile_name,"XMP");
593 }
594
595 /*
596 Store profile in Image.
597 */
598 (void) AppendImageProfile(image,profile_name,profile+header_length,
599 length-header_length);
600
601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
602 "Profile: %s, header %" MAGICK_SIZE_T_F "u bytes, "
603 "data %" MAGICK_SIZE_T_F "u bytes",
604 profile_name, (MAGICK_SIZE_T) header_length,
605 (MAGICK_SIZE_T) length-header_length);
606
607 return (True);
608 }
609
ReadICCProfile(j_decompress_ptr jpeg_info)610 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
611 {
612 char
613 magick[12];
614
615 ErrorManager
616 *error_manager;
617
618 Image
619 *image;
620
621 unsigned char
622 *profile;
623
624 long
625 length;
626
627 register long
628 i;
629
630 int
631 c;
632
633 /*
634 Determine length of color profile.
635 */
636 GetProfileLength(jpeg_info, length);
637 length-=2;
638 if (length <= 14)
639 {
640 while (--length >= 0)
641 (void) GetCharacter(jpeg_info);
642 return(True);
643 }
644 for (i=0; i < 12; i++)
645 magick[i]=GetCharacter(jpeg_info);
646 if (LocaleCompare(magick,"ICC_PROFILE") != 0)
647 {
648 /*
649 Not a ICC profile, return.
650 */
651 for (i=0; i < length-12; i++)
652 (void) GetCharacter(jpeg_info);
653 return(True);
654 }
655 (void) GetCharacter(jpeg_info); /* id */
656 (void) GetCharacter(jpeg_info); /* markers */
657 length-=14;
658 error_manager=(ErrorManager *) jpeg_info->client_data;
659 image=error_manager->image;
660
661 /*
662 Read color profile.
663 */
664 profile=error_manager->buffer;
665
666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
667 "ICC profile chunk: %ld bytes",
668 length);
669
670 for (i=0 ; i < length; i++)
671 {
672 if ((c=GetCharacter(jpeg_info)) != EOF)
673 profile[i]=c;
674 else
675 break;
676 }
677 if (i == length)
678 (void) AppendImageProfile(image,"ICM",profile,length);
679
680 return(True);
681 }
682
ReadIPTCProfile(j_decompress_ptr jpeg_info)683 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
684 {
685 ErrorManager
686 *error_manager;
687
688 Image
689 *image;
690
691 long
692 length,
693 tag_length;
694
695 unsigned char
696 *profile;
697
698 register long
699 i;
700
701 #ifdef GET_ONLY_IPTC_DATA
702 unsigned char
703 tag[MaxTextExtent];
704 #endif
705
706 int
707 c;
708
709 /*
710 Determine length of binary data stored here.
711 */
712 GetProfileLength(jpeg_info, length);
713 length-=2;
714 if (length <= 0)
715 return(True);
716 tag_length=0;
717 #ifdef GET_ONLY_IPTC_DATA
718 *tag='\0';
719 #endif
720 error_manager=(ErrorManager *) jpeg_info->client_data;
721 image=error_manager->image;
722 #ifdef GET_ONLY_IPTC_DATA
723 /*
724 Find the beginning of the IPTC portion of the binary data.
725 */
726 for (*tag='\0'; length > 0; )
727 {
728 *tag=GetCharacter(jpeg_info);
729 *(tag+1)=GetCharacter(jpeg_info);
730 length-=2;
731 if ((*tag == 0x1c) && (*(tag+1) == 0x02))
732 break;
733 }
734 tag_length=2;
735 #else
736 /*
737 Validate that this was written as a Photoshop resource format slug.
738 */
739 {
740 char
741 magick[MaxTextExtent];
742
743 for (i=0; i < 10; i++)
744 magick[i]=GetCharacter(jpeg_info);
745 magick[10]='\0';
746 length-=10;
747 if (LocaleCompare(magick,"Photoshop ") != 0)
748 {
749 /*
750 Not a ICC profile, return.
751 */
752 for (i=0; i < length; i++)
753 (void) GetCharacter(jpeg_info);
754 return(True);
755 }
756 }
757 /*
758 Remove the version number.
759 */
760 for (i=0; i < 4; i++)
761 (void) GetCharacter(jpeg_info);
762 length-=4;
763 tag_length=0;
764 #endif
765 if (length <= 0)
766 return(True);
767
768 if ((size_t) length+tag_length > sizeof(error_manager->buffer))
769 ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
770 (char *) NULL);
771 profile=error_manager->buffer;
772 /*
773 Read the payload of this binary data.
774 */
775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776 "Profile: IPTC, %ld bytes",
777 length);
778
779 for (i=0; i < length; i++)
780 {
781 if ((c=GetCharacter(jpeg_info)) != EOF)
782 profile[i]=c;
783 else
784 break;
785 }
786 if (i == length)
787 (void) AppendImageProfile(image,"IPTC",profile,length);
788
789 return(True);
790 }
791
SkipInputData(j_decompress_ptr cinfo,long number_bytes)792 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
793 {
794 SourceManager
795 *source;
796
797 if (number_bytes <= 0)
798 return;
799 source=(SourceManager *) cinfo->src;
800 while (number_bytes > (long) source->manager.bytes_in_buffer)
801 {
802 number_bytes-=(long) source->manager.bytes_in_buffer;
803 (void) FillInputBuffer(cinfo);
804 }
805 source->manager.next_input_byte+=(size_t) number_bytes;
806 source->manager.bytes_in_buffer-=(size_t) number_bytes;
807 }
808
TerminateSource(j_decompress_ptr cinfo)809 static void TerminateSource(j_decompress_ptr cinfo)
810 {
811 (void) cinfo;
812 }
813
JPEGSourceManager(j_decompress_ptr cinfo,Image * image)814 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
815 {
816 SourceManager
817 *source;
818
819 cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
820 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
821 source=(SourceManager *) cinfo->src;
822 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
823 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
824 source=(SourceManager *) cinfo->src;
825 source->manager.init_source=InitializeSource;
826 source->manager.fill_input_buffer=FillInputBuffer;
827 source->manager.skip_input_data=SkipInputData;
828 source->manager.resync_to_restart=jpeg_resync_to_restart;
829 source->manager.term_source=TerminateSource;
830 source->manager.bytes_in_buffer=0;
831 source->manager.next_input_byte=NULL;
832 source->image=image;
833 }
834
835 /*
836 Estimate the IJG quality factor used when saving the file.
837 */
838 static int
EstimateJPEGQuality(const struct jpeg_decompress_struct * jpeg_info,Image * image)839 EstimateJPEGQuality(const struct jpeg_decompress_struct *jpeg_info,
840 Image *image)
841 {
842 int
843 save_quality;
844
845 register long
846 i;
847
848 save_quality=0;
849 #ifdef D_LOSSLESS_SUPPORTED
850 if (image->compression==LosslessJPEGCompression)
851 {
852 save_quality=100;
853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
854 "Quality: 100 (lossless)");
855 }
856 else
857 #endif
858
859 {
860 int
861 hashval,
862 sum;
863
864 /*
865 Log the JPEG quality that was used for compression.
866 */
867 sum=0;
868 for (i=0; i < NUM_QUANT_TBLS; i++)
869 {
870 int
871 j;
872
873 if (jpeg_info->quant_tbl_ptrs[i] != NULL)
874 for (j=0; j < DCTSIZE2; j++)
875 {
876 UINT16 *c;
877 c=jpeg_info->quant_tbl_ptrs[i]->quantval;
878 sum+=c[j];
879 }
880 }
881 if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
882 (jpeg_info->quant_tbl_ptrs[1] != NULL))
883 {
884 int
885 hash[] =
886 {
887 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
888 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
889 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
890 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
891 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
892 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
893 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
894 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
895 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
896 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
897 0
898 };
899
900 int
901 sums[] =
902 {
903 32640,32635,32266,31495,30665,29804,29146,28599,28104,27670,
904 27225,26725,26210,25716,25240,24789,24373,23946,23572,22846,
905 21801,20842,19949,19121,18386,17651,16998,16349,15800,15247,
906 14783,14321,13859,13535,13081,12702,12423,12056,11779,11513,
907 11135,10955,10676,10392,10208, 9928, 9747, 9564, 9369, 9193,
908 9017, 8822, 8639, 8458, 8270, 8084, 7896, 7710, 7527, 7347,
909 7156, 6977, 6788, 6607, 6422, 6236, 6054, 5867, 5684, 5495,
910 5305, 5128, 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698,
911 3509, 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
912 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201, 128,
913 0
914 };
915
916 hashval=(jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
917 jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
918 jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
919 jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
920 for (i=0; i < 100; i++)
921 {
922 if ((hashval >= hash[i]) || (sum >= sums[i]))
923 {
924 save_quality=i+1;
925 if (image->logging)
926 {
927 if ((hashval > hash[i]) || (sum > sums[i]))
928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
929 "Quality: %d (approximate)",
930 save_quality);
931 else
932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
933 "Quality: %d",save_quality);
934 }
935 break;
936 }
937 }
938 }
939 else
940 if (jpeg_info->quant_tbl_ptrs[0] != NULL)
941 {
942 int
943 bwhash[] =
944 {
945 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
946 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
947 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
948 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
949 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
950 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
951 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
952 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
953 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
954 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
955 0
956 };
957
958 int
959 bwsum[] =
960 {
961 16320,16315,15946,15277,14655,14073,13623,13230,12859,12560,
962 12240,11861,11456,11081,10714,10360,10027, 9679, 9368, 9056,
963 8680, 8331, 7995, 7668, 7376, 7084, 6823, 6562, 6345, 6125,
964 5939, 5756, 5571, 5421, 5240, 5086, 4976, 4829, 4719, 4616,
965 4463, 4393, 4280, 4166, 4092, 3980, 3909, 3835, 3755, 3688,
966 3621, 3541, 3467, 3396, 3323, 3247, 3170, 3096, 3021, 2952,
967 2874, 2804, 2727, 2657, 2583, 2509, 2437, 2362, 2290, 2211,
968 2136, 2068, 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477,
969 1398, 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
970 667, 592, 518, 441, 369, 292, 221, 151, 86, 64,
971 0
972 };
973
974 hashval=(jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
975 jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
976 for (i=0; i < 100; i++)
977 {
978 if ((hashval >= bwhash[i]) || (sum >= bwsum[i]))
979 {
980 save_quality=i+1;
981 if (image->logging)
982 {
983 if ((hashval > bwhash[i]) || (sum > bwsum[i]))
984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
985 "Quality: %ld (approximate)",
986 i+1);
987 else
988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
989 "Quality: %ld",i+1);
990 }
991 break;
992 }
993 }
994 }
995 }
996
997 return save_quality;
998 }
999
1000 /*
1001 Format JPEG color space to a string.
1002 */
1003 static void
FormatJPEGColorSpace(const J_COLOR_SPACE colorspace,char * colorspace_name)1004 FormatJPEGColorSpace(const J_COLOR_SPACE colorspace,
1005 char *colorspace_name)
1006 {
1007 const char
1008 *s = NULL;
1009
1010 switch (colorspace)
1011 {
1012 default:
1013 case JCS_UNKNOWN:
1014 s = "UNKNOWN";
1015 break;
1016 case JCS_GRAYSCALE:
1017 s = "GRAYSCALE";
1018 break;
1019 case JCS_RGB:
1020 s = "RGB";
1021 break;
1022 case JCS_YCbCr:
1023 s = "YCbCr";
1024 break;
1025 case JCS_CMYK:
1026 s = "CMYK";
1027 break;
1028 case JCS_YCCK:
1029 s = "YCCK";
1030 break;
1031 }
1032 (void) strlcpy(colorspace_name,s,MaxTextExtent);
1033 }
1034
1035 /*
1036 Format JPEG sampling factors to a string.
1037 */
1038 static void
FormatJPEGSamplingFactors(const struct jpeg_decompress_struct * jpeg_info,char * sampling_factors)1039 FormatJPEGSamplingFactors(const struct jpeg_decompress_struct *jpeg_info,
1040 char *sampling_factors)
1041 {
1042 switch (jpeg_info->out_color_space)
1043 {
1044 case JCS_CMYK:
1045 {
1046 (void) FormatString(sampling_factors,"%dx%d,%dx%d,%dx%d,%dx%d",
1047 jpeg_info->comp_info[0].h_samp_factor,
1048 jpeg_info->comp_info[0].v_samp_factor,
1049 jpeg_info->comp_info[1].h_samp_factor,
1050 jpeg_info->comp_info[1].v_samp_factor,
1051 jpeg_info->comp_info[2].h_samp_factor,
1052 jpeg_info->comp_info[2].v_samp_factor,
1053 jpeg_info->comp_info[3].h_samp_factor,
1054 jpeg_info->comp_info[3].v_samp_factor);
1055 break;
1056 }
1057 case JCS_GRAYSCALE:
1058 {
1059 (void) FormatString(sampling_factors,"%dx%d",
1060 jpeg_info->comp_info[0].h_samp_factor,
1061 jpeg_info->comp_info[0].v_samp_factor);
1062 break;
1063 }
1064 case JCS_RGB:
1065 {
1066 (void) FormatString(sampling_factors,"%dx%d,%dx%d,%dx%d",
1067 jpeg_info->comp_info[0].h_samp_factor,
1068 jpeg_info->comp_info[0].v_samp_factor,
1069 jpeg_info->comp_info[1].h_samp_factor,
1070 jpeg_info->comp_info[1].v_samp_factor,
1071 jpeg_info->comp_info[2].h_samp_factor,
1072 jpeg_info->comp_info[2].v_samp_factor);
1073 break;
1074 }
1075 default:
1076 {
1077 (void) FormatString(sampling_factors,"%dx%d,%dx%d,%dx%d,%dx%d",
1078 jpeg_info->comp_info[0].h_samp_factor,
1079 jpeg_info->comp_info[0].v_samp_factor,
1080 jpeg_info->comp_info[1].h_samp_factor,
1081 jpeg_info->comp_info[1].v_samp_factor,
1082 jpeg_info->comp_info[2].h_samp_factor,
1083 jpeg_info->comp_info[2].v_samp_factor,
1084 jpeg_info->comp_info[3].h_samp_factor,
1085 jpeg_info->comp_info[3].v_samp_factor);
1086 break;
1087 }
1088 }
1089 }
1090
1091 static MagickBool
IsITUFax(const Image * image)1092 IsITUFax(const Image* image)
1093 {
1094 size_t
1095 profile_length;
1096
1097 const unsigned char
1098 *profile;
1099
1100 MagickBool
1101 status;
1102
1103 status=MagickFalse;
1104 if ((profile=GetImageProfile(image,"APP1",&profile_length)) &&
1105 (profile_length >= 5))
1106 {
1107 if (profile[0] == 0x47 &&
1108 profile[1] == 0x33 &&
1109 profile[2] == 0x46 &&
1110 profile[3] == 0x41 &&
1111 profile[4] == 0x58)
1112 status=MagickTrue;
1113 }
1114
1115 return status;
1116 }
1117
ReadJPEGImage(const ImageInfo * image_info,ExceptionInfo * exception)1118 static Image *ReadJPEGImage(const ImageInfo *image_info,
1119 ExceptionInfo *exception)
1120 {
1121 Image
1122 *image;
1123
1124 ErrorManager
1125 error_manager;
1126
1127 IndexPacket
1128 index;
1129
1130 long
1131 y;
1132
1133 JSAMPLE
1134 *jpeg_pixels;
1135
1136 JSAMPROW
1137 scanline[1];
1138
1139 const char
1140 *value;
1141
1142 register long
1143 i;
1144
1145 struct jpeg_error_mgr
1146 jpeg_error;
1147
1148 struct jpeg_progress_mgr
1149 jpeg_progress;
1150
1151 struct jpeg_decompress_struct
1152 jpeg_info;
1153
1154 register JSAMPLE
1155 *p;
1156
1157 MagickPassFail
1158 status;
1159
1160 unsigned long
1161 number_pixels;
1162
1163 /*
1164 Open image file.
1165 */
1166 assert(image_info != (const ImageInfo *) NULL);
1167 assert(image_info->signature == MagickSignature);
1168 assert(exception != (ExceptionInfo *) NULL);
1169 assert(exception->signature == MagickSignature);
1170 image=AllocateImage(image_info);
1171 if (image == (Image *) NULL)
1172 ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1173 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1174 if (status == MagickFail)
1175 ThrowReaderException(FileOpenError,UnableToOpenFile,image);
1176 if (BlobIsSeekable(image) && GetBlobSize(image) < 107)
1177 ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
1178 /*
1179 Initialize structures.
1180 */
1181 (void) memset(&error_manager,0,sizeof(error_manager));
1182 (void) memset(&jpeg_progress,0,sizeof(jpeg_progress));
1183 (void) memset(&jpeg_info,0,sizeof(jpeg_info));
1184 (void) memset(&jpeg_error,0,sizeof(jpeg_error));
1185 jpeg_info.err=jpeg_std_error(&jpeg_error);
1186 jpeg_info.err->emit_message=/*(void (*)(j_common_ptr,int))*/ JPEGDecodeMessageHandler;
1187 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1188 jpeg_pixels=(JSAMPLE *) NULL;
1189 error_manager.image=image;
1190 error_manager.ping=image_info->ping;
1191 error_manager.max_scan_number=100;
1192 error_manager.max_warning_count=MaxWarningCount;
1193
1194 /*
1195 Allow the user to set how many warnings of any given type are
1196 allowed before promotion of the warning to a hard error.
1197 */
1198 if ((value=AccessDefinition(image_info,"jpeg","max-warnings")))
1199 error_manager.max_warning_count=strtol(value,(char **) NULL, 10);
1200
1201 /*
1202 Set initial longjmp based error handler.
1203 */
1204 if (setjmp(error_manager.error_recovery))
1205 {
1206 jpeg_destroy_decompress(&jpeg_info);
1207 GetImageException(image,exception);
1208 CloseBlob(image);
1209 if (exception->severity < ErrorException)
1210 return(image);
1211 DestroyImage(image);
1212 return((Image *) NULL);
1213 }
1214 jpeg_info.client_data=(void *) &error_manager;
1215
1216 jpeg_create_decompress(&jpeg_info);
1217 /*
1218 Specify a memory limit for libjpeg which is 1/5th the absolute
1219 limit. Don't actually consume the resource since we don't know
1220 how much libjpeg will actually consume.
1221 */
1222 jpeg_info.mem->max_memory_to_use=(long) (GetMagickResourceLimit(MemoryResource) -
1223 GetMagickResource(MemoryResource))/5U;
1224 if (image->logging)
1225 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1226 "Memory capped to %ld bytes", jpeg_info.mem->max_memory_to_use);
1227 /*
1228 Register our progress monitor
1229 */
1230 jpeg_progress.progress_monitor=(void (*)(j_common_ptr)) JPEGDecodeProgressMonitor;
1231 jpeg_info.progress=&jpeg_progress;
1232
1233 JPEGSourceManager(&jpeg_info,image);
1234 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1235 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1236 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1237 for (i=1; i < 16; i++)
1238 if ((i != 2) && (i != 13) && (i != 14))
1239 jpeg_set_marker_processor(&jpeg_info,JPEG_APP0+i,ReadGenericProfile);
1240 if (image->logging)
1241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1242 "Reading JPEG header...");
1243 i=jpeg_read_header(&jpeg_info,True);
1244 if (image->logging)
1245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1246 "Done with reading JPEG header");
1247 if (IsITUFax(image))
1248 {
1249 if (image->logging)
1250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1251 "Image colorspace set to LAB");
1252 image->colorspace=LABColorspace;
1253 jpeg_info.out_color_space = JCS_YCbCr;
1254 }
1255 else if (jpeg_info.out_color_space == JCS_CMYK)
1256 {
1257 if (image->logging)
1258 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1259 "Image colorspace set to CMYK");
1260 image->colorspace=CMYKColorspace;
1261 }
1262 if (jpeg_info.saw_JFIF_marker)
1263 {
1264 if ((jpeg_info.X_density != 1U) && (jpeg_info.Y_density != 1U))
1265 {
1266 /*
1267 Set image resolution.
1268 */
1269 image->x_resolution=jpeg_info.X_density;
1270 image->y_resolution=jpeg_info.Y_density;
1271 if (jpeg_info.density_unit == 1)
1272 image->units=PixelsPerInchResolution;
1273 if (jpeg_info.density_unit == 2)
1274 image->units=PixelsPerCentimeterResolution;
1275 if (image->logging)
1276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1277 "Image resolution set to %gx%g %s",
1278 image->x_resolution,
1279 image->y_resolution,
1280 ResolutionTypeToString(image->units));
1281 }
1282 }
1283
1284 /*
1285 If the desired image size is pre-set (e.g. by using -size), then
1286 let the JPEG library subsample for us.
1287 */
1288 number_pixels=image->columns*image->rows;
1289 if (number_pixels != 0)
1290 {
1291 double
1292 scale_factor;
1293
1294
1295 if (image->logging)
1296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1297 "Requested Geometry: %lux%lu",
1298 image->columns,image->rows);
1299 jpeg_calc_output_dimensions(&jpeg_info);
1300 image->magick_columns=jpeg_info.output_width;
1301 image->magick_rows=jpeg_info.output_height;
1302 if (image->logging)
1303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1304 "magick_geometry=%lux%lu",
1305 image->magick_columns, image->magick_rows);
1306 scale_factor=(double) jpeg_info.output_width/image->columns;
1307 if (scale_factor > ((double) jpeg_info.output_height/image->rows))
1308 scale_factor=(double) jpeg_info.output_height/image->rows;
1309 jpeg_info.scale_denom *=(unsigned int) scale_factor;
1310 jpeg_calc_output_dimensions(&jpeg_info);
1311 if (image->logging)
1312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1313 "Original Geometry: %lux%lu,"
1314 " Scale_factor: %ld (scale_num=%d,"
1315 " scale_denom=%d)",
1316 image->magick_columns, image->magick_rows,
1317 (long) scale_factor,
1318 jpeg_info.scale_num,jpeg_info.scale_denom);
1319 }
1320 #if 0
1321 /*
1322 The subrange parameter is set by the filename array syntax similar
1323 to the way an image is requested from a list (e.g. myfile.jpg[2]).
1324 Argument values other than zero are used to scale the image down
1325 by that factor. IJG JPEG 62 (6b) supports values of 1,2,4, or 8
1326 while IJG JPEG 70 supports all values in the range 1-16. This
1327 feature is useful in case you want to view all of the images with
1328 a consistent ratio. Unfortunately, it uses the same syntax as
1329 list member access.
1330 */
1331 else if (image_info->subrange != 0)
1332 {
1333 jpeg_info.scale_denom *=(int) image_info->subrange;
1334 jpeg_calc_output_dimensions(&jpeg_info);
1335 if (image->logging)
1336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1337 "Requested Scaling Denominator: %d "
1338 "(scale_num=%d, scale_denom=%d)",
1339 (int) image_info->subrange,
1340 jpeg_info.scale_num,jpeg_info.scale_denom);
1341
1342 }
1343 #endif
1344 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1345 #ifdef D_LOSSLESS_SUPPORTED
1346 image->interlace=
1347 jpeg_info.process == JPROC_PROGRESSIVE ? LineInterlace : NoInterlace;
1348 image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1349 LosslessJPEGCompression : JPEGCompression;
1350 if (jpeg_info.data_precision > 8)
1351 MagickError2(OptionError,
1352 "12-bit JPEG not supported. Reducing pixel data to 8 bits",
1353 (char *) NULL);
1354 #else
1355 image->interlace=jpeg_info.progressive_mode ? LineInterlace : NoInterlace;
1356 image->compression=JPEGCompression;
1357 #endif
1358 #else
1359 image->compression=JPEGCompression;
1360 image->interlace=LineInterlace;
1361 #endif
1362
1363 /*
1364 Allow the user to enable/disable block smoothing.
1365 */
1366 if ((value=AccessDefinition(image_info,"jpeg","block-smoothing")))
1367 {
1368 if (LocaleCompare(value,"FALSE") == 0)
1369 jpeg_info.do_block_smoothing=False;
1370 else
1371 jpeg_info.do_block_smoothing=True;
1372 }
1373
1374 /*
1375 Allow the user to select the DCT decoding algorithm.
1376 */
1377 if ((value=AccessDefinition(image_info,"jpeg","dct-method")))
1378 {
1379 if (LocaleCompare(value,"ISLOW") == 0)
1380 jpeg_info.dct_method=JDCT_ISLOW;
1381 else if (LocaleCompare(value,"IFAST") == 0)
1382 jpeg_info.dct_method=JDCT_IFAST;
1383 else if (LocaleCompare(value,"FLOAT") == 0)
1384 jpeg_info.dct_method=JDCT_FLOAT;
1385 else if (LocaleCompare(value,"DEFAULT") == 0)
1386 jpeg_info.dct_method=JDCT_DEFAULT;
1387 else if (LocaleCompare(value,"FASTEST") == 0)
1388 jpeg_info.dct_method=JDCT_FASTEST;
1389 }
1390
1391 /*
1392 Allow the user to enable/disable fancy upsampling.
1393 */
1394 if ((value=AccessDefinition(image_info,"jpeg","fancy-upsampling")))
1395 {
1396 if (LocaleCompare(value,"FALSE") == 0)
1397 jpeg_info.do_fancy_upsampling=False;
1398 else
1399 jpeg_info.do_fancy_upsampling=True;
1400 }
1401
1402 /*
1403 Allow the user to adjust the maximum JPEG scan number
1404 */
1405 if ((value=AccessDefinition(image_info,"jpeg","max-scan-number")))
1406 {
1407 error_manager.max_scan_number=strtol(value,(char **) NULL, 10);
1408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1409 "JPEG max-scan-number set to %d",
1410 error_manager.max_scan_number);
1411 }
1412
1413 jpeg_calc_output_dimensions(&jpeg_info);
1414 image->columns=jpeg_info.output_width;
1415 image->rows=jpeg_info.output_height;
1416 image->storage_class = jpeg_info.output_components == 1 ? PseudoClass : DirectClass;
1417 image->depth=Min(jpeg_info.data_precision,QuantumDepth);
1418
1419 if (image->logging)
1420 {
1421 if (image->interlace == LineInterlace)
1422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1423 "Interlace: progressive");
1424 else
1425 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1426 "Interlace: nonprogressive");
1427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1428 (int) jpeg_info.data_precision);
1429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Components: %d",
1430 (int) jpeg_info.output_components);
1431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1432 (int) jpeg_info.output_width,
1433 (int) jpeg_info.output_height);
1434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"DCT Method: %d",
1435 jpeg_info.dct_method);
1436 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Fancy Upsampling: %s",
1437 (jpeg_info.do_fancy_upsampling ? "true" : "false"));
1438 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Block Smoothing: %s",
1439 (jpeg_info.do_block_smoothing ? "true" : "false"));
1440 }
1441
1442 if (CheckImagePixelLimits(image, exception) != MagickPass)
1443 {
1444 jpeg_destroy_decompress(&jpeg_info);
1445 ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1446 }
1447
1448 if (image->logging)
1449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1450 "Starting JPEG decompression...");
1451 (void) jpeg_start_decompress(&jpeg_info);
1452 image->columns=jpeg_info.output_width;
1453 image->rows=jpeg_info.output_height;
1454 {
1455 char
1456 attribute[MaxTextExtent];
1457
1458 /*
1459 Estimate and retain JPEG properties as attributes.
1460 */
1461 FormatString(attribute,"%d",EstimateJPEGQuality(&jpeg_info,image));
1462 (void) SetImageAttribute(image,"JPEG-Quality",attribute);
1463
1464 FormatString(attribute,"%ld",(long)jpeg_info.out_color_space);
1465 (void) SetImageAttribute(image,"JPEG-Colorspace",attribute);
1466
1467 FormatJPEGColorSpace(jpeg_info.out_color_space,attribute);
1468 (void) SetImageAttribute(image,"JPEG-Colorspace-Name",attribute);
1469 if (image->logging)
1470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1471 "Colorspace: %s (%d)", attribute,
1472 jpeg_info.out_color_space);
1473
1474 FormatJPEGSamplingFactors(&jpeg_info,attribute);
1475 (void) SetImageAttribute(image,"JPEG-Sampling-factors",attribute);
1476 if (image->logging)
1477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1478 "Sampling Factors: %s", attribute);
1479 }
1480
1481 image->depth=Min(jpeg_info.data_precision,QuantumDepth);
1482 if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1483 if (!AllocateImageColormap(image,1 << image->depth))
1484 {
1485 jpeg_destroy_decompress(&jpeg_info);
1486 ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1487 }
1488 if (image_info->ping)
1489 {
1490 jpeg_destroy_decompress(&jpeg_info);
1491 CloseBlob(image);
1492 return(image);
1493 }
1494 if (CheckImagePixelLimits(image, exception) != MagickPass)
1495 {
1496 jpeg_destroy_decompress(&jpeg_info);
1497 ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1498 }
1499
1500 /*
1501 Verify that we support the number of output components.
1502 */
1503 if ((jpeg_info.output_components != 1) &&
1504 (jpeg_info.output_components != 3) &&
1505 (jpeg_info.output_components != 4))
1506 {
1507 jpeg_destroy_decompress(&jpeg_info);
1508 ThrowReaderException(CoderError,ImageTypeNotSupported,image);
1509 }
1510 /*
1511 Verify that file size is reasonable (if we can)
1512 */
1513 if (BlobIsSeekable(image))
1514 {
1515 magick_off_t
1516 blob_size;
1517
1518 double
1519 ratio = 0;
1520
1521 blob_size = GetBlobSize(image);
1522
1523 if (blob_size != 0)
1524 {
1525 /* magick columns/rows are only set if size was specified! */
1526 if (image->magick_columns && image->magick_rows)
1527 ratio = ((double) image->magick_columns*image->magick_rows*
1528 jpeg_info.output_components/blob_size);
1529 else
1530 ratio = ((double) image->columns*image->rows*
1531 jpeg_info.output_components/blob_size);
1532 }
1533
1534 /* All-black JPEG can produce tremendous compression ratios.
1535 Allow for it. */
1536 if ((blob_size == 0) || (ratio > 2500.0))
1537 {
1538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1539 "Unreasonable dimensions: "
1540 "geometry=%lux%lu,"
1541 " magick_geometry=%lux%lu,"
1542 " components=%d, "
1543 "blob size=%" MAGICK_OFF_F "d bytes, "
1544 "compression ratio %g",
1545 image->columns, image->rows,
1546 image->magick_columns, image->magick_rows,
1547 jpeg_info.output_components, blob_size, ratio);
1548
1549 jpeg_destroy_decompress(&jpeg_info);
1550 ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
1551 }
1552 }
1553
1554 jpeg_pixels=MagickAllocateResourceLimitedArray(JSAMPLE *,
1555 jpeg_info.output_components,
1556 MagickArraySize(image->columns,
1557 sizeof(JSAMPLE)));
1558 if (jpeg_pixels == (JSAMPLE *) NULL)
1559 {
1560 jpeg_destroy_decompress(&jpeg_info);
1561 ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1562 }
1563 (void) memset(jpeg_pixels,0,MagickArraySize(jpeg_info.output_components,
1564 MagickArraySize(image->columns,
1565 sizeof(JSAMPLE))));
1566
1567 /*
1568 Extended longjmp-based error handler (with jpeg_pixels)
1569 */
1570 if (setjmp(error_manager.error_recovery))
1571 {
1572 /* Error handling code executed if longjmp was invoked */
1573 MagickFreeResourceLimitedMemory(jpeg_pixels);
1574 jpeg_destroy_decompress(&jpeg_info);
1575 if (image->exception.severity > exception->severity)
1576 CopyException(exception,&image->exception);
1577 CloseBlob(image);
1578 number_pixels=image->columns*image->rows;
1579 if (number_pixels != 0)
1580 return(image);
1581 DestroyImage(image);
1582 return((Image *) NULL);
1583 }
1584
1585 /*
1586 Convert JPEG pixels to pixel packets.
1587 */
1588 scanline[0]=(JSAMPROW) jpeg_pixels;
1589 for (y=0; y < (long) image->rows; y++)
1590 {
1591 register IndexPacket
1592 *indexes;
1593
1594 register long
1595 x;
1596
1597 register PixelPacket
1598 *q;
1599
1600 /*
1601 Read scanlines. Stop at first serious error.
1602 */
1603 if ((jpeg_read_scanlines(&jpeg_info,scanline,1) != 1) ||
1604 (image->exception.severity >= ErrorException))
1605 {
1606 status=MagickFail;
1607 break;
1608 }
1609
1610 q=SetImagePixels(image,0,y,image->columns,1);
1611 if (q == (PixelPacket *) NULL)
1612 {
1613 status=MagickFail;
1614 break;
1615 }
1616 indexes=AccessMutableIndexes(image);
1617
1618 p=jpeg_pixels;
1619
1620 if (jpeg_info.output_components == 1)
1621 {
1622 for (x=0; x < (long) image->columns; x++)
1623 {
1624 index=(IndexPacket) (GETJSAMPLE(*p++));
1625 VerifyColormapIndex(image,index);
1626 indexes[x]=index;
1627 *q++=image->colormap[index];
1628 }
1629 }
1630 else if ((jpeg_info.output_components == 3) ||
1631 (jpeg_info.output_components == 4))
1632 {
1633 if (jpeg_info.data_precision > 8)
1634 {
1635 unsigned int
1636 scale_short;
1637
1638 scale_short=65535U/MaxValueGivenBits(jpeg_info.data_precision);
1639 for (x=0; x < (long) image->columns; x++)
1640 {
1641 q->red=ScaleShortToQuantum(scale_short*GETJSAMPLE(*p++));
1642 q->green=ScaleShortToQuantum(scale_short*GETJSAMPLE(*p++));
1643 q->blue=ScaleShortToQuantum(scale_short*GETJSAMPLE(*p++));
1644 if (jpeg_info.output_components > 3)
1645 q->opacity=ScaleShortToQuantum(scale_short*GETJSAMPLE(*p++));
1646 else
1647 q->opacity=OpaqueOpacity;
1648 q++;
1649 }
1650 }
1651 else
1652 {
1653 for (x=0; x < (long) image->columns; x++)
1654 {
1655 q->red=ScaleCharToQuantum(GETJSAMPLE(*p++));
1656 q->green=ScaleCharToQuantum(GETJSAMPLE(*p++));
1657 q->blue=ScaleCharToQuantum(GETJSAMPLE(*p++));
1658 if (jpeg_info.output_components > 3)
1659 q->opacity=ScaleCharToQuantum(GETJSAMPLE(*p++));
1660 else
1661 q->opacity=OpaqueOpacity;
1662 q++;
1663 }
1664 }
1665 if (image->colorspace == CMYKColorspace)
1666 {
1667 /*
1668 CMYK pixels are inverted.
1669 */
1670 q=AccessMutablePixels(image);
1671 for (x=0; x < (long) image->columns; x++)
1672 {
1673 q->red=MaxRGB-q->red;
1674 q->green=MaxRGB-q->green;
1675 q->blue=MaxRGB-q->blue;
1676 q->opacity=MaxRGB-q->opacity;
1677 q++;
1678 }
1679 }
1680 }
1681 if (!SyncImagePixels(image))
1682 {
1683 status=MagickFail;
1684 break;
1685 }
1686 #if !USE_LIBJPEG_PROGRESS
1687 if (QuantumTick(y,image->rows))
1688 if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
1689 image->filename,
1690 image->columns,image->rows))
1691 {
1692 status=MagickFail;
1693 jpeg_abort_decompress(&jpeg_info);
1694 break;
1695 }
1696 #endif /* !USE_LIBJPEG_PROGRESS */
1697 }
1698 /*
1699 Free jpeg resources.
1700 */
1701 if (status == MagickPass)
1702 {
1703 /*
1704 jpeg_finish_decompress() may throw an exception while it is
1705 finishing the remainder of the JPEG file. At this point we
1706 have already decoded the image so we handle exceptions from
1707 jpeg_finish_decompress() specially, mapping reported
1708 exceptions as warnings rather than errors. We try using
1709 jpeg_finish_decompress() and if it results in a longjmp(),
1710 then we skip over it again.
1711 */
1712 error_manager.completed=MagickTrue;
1713 if (!setjmp(error_manager.error_recovery))
1714 (void) jpeg_finish_decompress(&jpeg_info);
1715 }
1716 jpeg_destroy_decompress(&jpeg_info);
1717 MagickFreeResourceLimitedMemory(jpeg_pixels);
1718 CloseBlob(image);
1719
1720 /*
1721 Retrieve image orientation from EXIF (if present) and store in
1722 image.
1723
1724 EXIF orienation enumerations match TIFF enumerations, which happen
1725 to match the enumeration values used by GraphicsMagick.
1726 */
1727 if (status == MagickPass)
1728 {
1729 const ImageAttribute
1730 *attribute;
1731
1732 attribute = GetImageAttribute(image,"EXIF:Orientation");
1733 if ((attribute != (const ImageAttribute *) NULL) &&
1734 (attribute->value != (char *) NULL))
1735 {
1736 int
1737 orientation;
1738
1739 orientation=MagickAtoI(attribute->value);
1740 if ((orientation > UndefinedOrientation) &&
1741 (orientation <= LeftBottomOrientation))
1742 image->orientation=(OrientationType) orientation;
1743 }
1744 }
1745 if (image->logging)
1746 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"return");
1747 GetImageException(image,exception);
1748 StopTimer(&image->timer);
1749 return(image);
1750 }
1751 #endif
1752
1753 /*
1754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755 % %
1756 % %
1757 % %
1758 % R e g i s t e r J P E G I m a g e %
1759 % %
1760 % %
1761 % %
1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763 %
1764 % Method RegisterJPEGImage adds attributes for the JPEG image format to
1765 % the list of supported formats. The attributes include the image format
1766 % tag, a method to read and/or write the format, whether the format
1767 % supports the saving of more than one frame to the same file or blob,
1768 % whether the format supports native in-memory I/O, and a brief
1769 % description of the format.
1770 %
1771 % The format of the RegisterJPEGImage method is:
1772 %
1773 % RegisterJPEGImage(void)
1774 %
1775 */
RegisterJPEGImage(void)1776 ModuleExport void RegisterJPEGImage(void)
1777 {
1778 static const char
1779 description[]="Joint Photographic Experts Group JFIF format";
1780
1781 #if defined(HasJPEG) && defined(JPEG_LIB_VERSION)
1782 static const char
1783 version[] = "IJG JPEG " DefineValueToString(JPEG_LIB_VERSION);
1784 #define HAVE_JPEG_VERSION
1785 #endif
1786
1787 MagickInfo
1788 *entry;
1789
1790 MagickBool
1791 thread_support;
1792
1793 #if defined(SETJMP_IS_THREAD_SAFE) && (SETJMP_IS_THREAD_SAFE)
1794 thread_support=MagickTrue; /* libjpeg is thread safe */
1795 #else
1796 thread_support=MagickFalse; /* libjpeg is not thread safe */
1797 #endif
1798
1799 entry=SetMagickInfo("JPEG");
1800 entry->thread_support=thread_support;
1801 #if defined(HasJPEG)
1802 entry->decoder=(DecoderHandler) ReadJPEGImage;
1803 entry->encoder=(EncoderHandler) WriteJPEGImage;
1804 #endif
1805 entry->magick=(MagickHandler) IsJPEG;
1806 entry->adjoin=False;
1807 entry->description=description;
1808 #if defined(HAVE_JPEG_VERSION)
1809 entry->version=version;
1810 #endif
1811 entry->module="JPEG";
1812 entry->coder_class=PrimaryCoderClass;
1813 (void) RegisterMagickInfo(entry);
1814
1815 entry=SetMagickInfo("JPG");
1816 entry->thread_support=thread_support;
1817 #if defined(HasJPEG)
1818 entry->decoder=(DecoderHandler) ReadJPEGImage;
1819 entry->encoder=(EncoderHandler) WriteJPEGImage;
1820 #endif
1821 entry->adjoin=False;
1822 entry->description=description;
1823 #if defined(HAVE_JPEG_VERSION)
1824 entry->version=version;
1825 #endif
1826 entry->module="JPEG";
1827 entry->coder_class=PrimaryCoderClass;
1828 (void) RegisterMagickInfo(entry);
1829 }
1830
1831 /*
1832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833 % %
1834 % %
1835 % %
1836 % U n r e g i s t e r J P E G I m a g e %
1837 % %
1838 % %
1839 % %
1840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841 %
1842 % Method UnregisterJPEGImage removes format registrations made by the
1843 % JPEG module from the list of supported formats.
1844 %
1845 % The format of the UnregisterJPEGImage method is:
1846 %
1847 % UnregisterJPEGImage(void)
1848 %
1849 */
UnregisterJPEGImage(void)1850 ModuleExport void UnregisterJPEGImage(void)
1851 {
1852 (void) UnregisterMagickInfo("JPEG");
1853 (void) UnregisterMagickInfo("JPG");
1854 }
1855
1856 #if defined(HasJPEG)
1857 /*
1858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1859 % %
1860 % %
1861 % %
1862 % W r i t e J P E G I m a g e %
1863 % %
1864 % %
1865 % %
1866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867 %
1868 % Method WriteJPEGImage writes a JPEG image file and returns it. It
1869 % allocates the memory necessary for the new Image structure and returns a
1870 % pointer to the new image.
1871 %
1872 % The format of the WriteJPEGImage method is:
1873 %
1874 % unsigned int WriteJPEGImage(const ImageInfo *image_info,Image *image)
1875 %
1876 % A description of each parameter follows:
1877 %
1878 % o status: Method WriteJPEGImage return True if the image is written.
1879 % False is returned is there is of a memory shortage or if the image
1880 % file cannot be opened for writing.
1881 %
1882 % o image_info: Specifies a pointer to a ImageInfo structure.
1883 %
1884 % o jpeg_image: A pointer to an Image structure.
1885 %
1886 %
1887 */
1888
EmptyOutputBuffer(j_compress_ptr cinfo)1889 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1890 {
1891 DestinationManager
1892 *destination;
1893
1894 destination=(DestinationManager *) cinfo->dest;
1895 destination->manager.free_in_buffer=WriteBlob(destination->image,
1896 MaxBufferExtent,(char *) destination->buffer);
1897 if (destination->manager.free_in_buffer != MaxBufferExtent)
1898 ERREXIT(cinfo,JERR_FILE_WRITE);
1899 destination->manager.next_output_byte=destination->buffer;
1900 return(TRUE);
1901 }
1902
InitializeDestination(j_compress_ptr cinfo)1903 static void InitializeDestination(j_compress_ptr cinfo)
1904 {
1905 DestinationManager
1906 *destination;
1907
1908 destination=(DestinationManager *) cinfo->dest;
1909 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1910 ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1911 destination->manager.next_output_byte=destination->buffer;
1912 destination->manager.free_in_buffer=MaxBufferExtent;
1913 }
1914
TerminateDestination(j_compress_ptr cinfo)1915 static void TerminateDestination(j_compress_ptr cinfo)
1916 {
1917 DestinationManager
1918 *destination;
1919
1920 destination=(DestinationManager *) cinfo->dest;
1921 if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1922 {
1923 size_t
1924 number_bytes;
1925
1926 number_bytes=WriteBlob(destination->image,MaxBufferExtent-
1927 destination->manager.free_in_buffer,(char *) destination->buffer);
1928 if (number_bytes != (MaxBufferExtent-destination->manager.free_in_buffer))
1929 ERREXIT(cinfo,JERR_FILE_WRITE);
1930 }
1931 }
1932
1933 /*
1934 Output generic APPN profile
1935 */
WriteAPPNProfile(j_compress_ptr jpeg_info,const unsigned char * profile,const size_t profile_length,const char * profile_name)1936 static void WriteAPPNProfile(j_compress_ptr jpeg_info,
1937 const unsigned char *profile,
1938 const size_t profile_length,
1939 const char * profile_name)
1940 {
1941 size_t
1942 j;
1943
1944 int
1945 marker_id;
1946
1947 marker_id=JPEG_APP0+(int) MagickAtoL(profile_name+3);
1948 for (j=0; j < profile_length; j+=65533L)
1949 jpeg_write_marker(jpeg_info,marker_id,
1950 profile+j,(int)
1951 Min(profile_length-j,65533L));
1952 }
1953
1954 /*
1955 Output EXIF profile
1956 */
WriteEXIFProfile(j_compress_ptr jpeg_info,const unsigned char * profile,const size_t profile_length)1957 static void WriteEXIFProfile(j_compress_ptr jpeg_info,
1958 const unsigned char *profile,
1959 const size_t profile_length)
1960 {
1961 size_t
1962 j;
1963
1964 for (j=0; j < profile_length; j+=65533L)
1965 jpeg_write_marker(jpeg_info,JPEG_APP0+1,
1966 profile+j,(int)
1967 Min(profile_length-j,65533L));
1968 }
1969
1970 /*
1971 Output ICC color profile as a APP marker.
1972 */
WriteICCProfile(j_compress_ptr jpeg_info,const unsigned char * color_profile,const size_t profile_length)1973 static void WriteICCProfile(j_compress_ptr jpeg_info,
1974 const unsigned char *color_profile,
1975 const size_t profile_length)
1976 {
1977 register long
1978 i,
1979 j;
1980
1981 for (i=0; i < (long) profile_length; i+=65519)
1982 {
1983 unsigned char
1984 *profile;
1985
1986 size_t
1987 length=0;
1988
1989
1990 length=Min(profile_length-i,65519);
1991 profile=MagickAllocateResourceLimitedMemory(unsigned char *,length+14);
1992 if (profile == (unsigned char *) NULL)
1993 break;
1994 (void) strcpy((char *) profile,"ICC_PROFILE");
1995 profile[12]=(unsigned char) ((i/65519)+1);
1996 profile[13]=(unsigned char) ((profile_length/65519)+1);
1997 for (j=0; j < (long) length; j++)
1998 profile[j+14]=color_profile[i+j];
1999 jpeg_write_marker(jpeg_info,ICC_MARKER,profile,(unsigned int) length+14);
2000 MagickFreeResourceLimitedMemory(profile);
2001 }
2002 }
2003
2004 /*
2005 Output binary Photoshop resource data using an APP marker.
2006 */
WriteIPTCProfile(j_compress_ptr jpeg_info,const unsigned char * iptc_profile,const size_t profile_length)2007 static void WriteIPTCProfile(j_compress_ptr jpeg_info,
2008 const unsigned char *iptc_profile,
2009 const size_t profile_length)
2010 {
2011 register long
2012 i;
2013
2014 unsigned long
2015 roundup,
2016 tag_length;
2017
2018 #ifdef GET_ONLY_IPTC_DATA
2019 tag_length=26;
2020 #else
2021 tag_length=14;
2022 #endif
2023 for (i=0; i < (long) profile_length; i+=65500)
2024 {
2025 size_t
2026 length;
2027
2028 unsigned char
2029 *profile;
2030
2031 length=Min(profile_length-i,65500);
2032 roundup=(length & 0x01); /* round up for Photoshop */
2033 profile=MagickAllocateResourceLimitedMemory(unsigned char *,length+roundup+tag_length);
2034 if (profile == (unsigned char *) NULL)
2035 break;
2036 #ifdef GET_ONLY_IPTC_DATA
2037 (void) memcpy(profile,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2038 profile[13]=0x00;
2039 profile[24]=length >> 8;
2040 profile[25]=length & 0xff;
2041 #else
2042 (void) memcpy(profile,"Photoshop 3.0 ",14);
2043 profile[13]=0x00;
2044 #endif
2045 (void) memcpy(&(profile[tag_length]),&(iptc_profile[i]),length);
2046 if (roundup)
2047 profile[length+tag_length]=0;
2048 jpeg_write_marker(jpeg_info,IPTC_MARKER,profile,(unsigned int)
2049 (length+roundup+tag_length));
2050 MagickFreeResourceLimitedMemory(profile);
2051 }
2052 }
2053
2054 /*
2055 Output Adobe XMP XML profile.
2056 */
WriteXMPProfile(j_compress_ptr jpeg_info,const unsigned char * profile,const size_t profile_length)2057 static void WriteXMPProfile(j_compress_ptr jpeg_info,
2058 const unsigned char *profile,
2059 const size_t profile_length)
2060 {
2061 size_t
2062 count,
2063 index,
2064 header_length,
2065 total_length;
2066
2067 unsigned int
2068 marker_length,
2069 remaining;
2070
2071 header_length=strlen(xmp_std_header)+1; /* Include terminating null */
2072 total_length=header_length+profile_length;
2073 /* XMP profile must be no larger than range of 'unsigned int' */
2074 remaining=(unsigned int) Min(UINT_MAX,total_length);
2075
2076 marker_length=Min(remaining,JPEG_MARKER_MAX_SIZE);
2077 jpeg_write_m_header(jpeg_info,XML_MARKER,marker_length);
2078 count=marker_length;
2079 {
2080 for (index=0 ; index < header_length; index++)
2081 {
2082 jpeg_write_m_byte(jpeg_info,xmp_std_header[index]);
2083 --remaining;
2084 --count;
2085 }
2086 }
2087
2088 for (index=0; remaining > 0; --remaining)
2089 {
2090 if (count == 0)
2091 {
2092 marker_length=Min(remaining,JPEG_MARKER_MAX_SIZE);
2093 jpeg_write_m_header(jpeg_info,XML_MARKER,marker_length);
2094 count=marker_length;
2095 }
2096 jpeg_write_m_byte(jpeg_info,profile[index]);
2097 index++;
2098 count--;
2099 }
2100 }
2101
2102 /*
2103 Output profiles to JPEG stream.
2104 */
WriteProfiles(j_compress_ptr jpeg_info,Image * image)2105 static void WriteProfiles(j_compress_ptr jpeg_info,Image *image)
2106 {
2107 const char
2108 *profile_name;
2109
2110 const unsigned char *
2111 profile;
2112
2113 ImageProfileIterator
2114 profile_iterator;
2115
2116 size_t
2117 profile_length=0;
2118
2119 profile_iterator=AllocateImageProfileIterator(image);
2120 while(NextImageProfile(profile_iterator,&profile_name,&profile,
2121 &profile_length) != MagickFail)
2122 {
2123 if (LocaleNCompare(profile_name,"APP",3) == 0)
2124 {
2125 WriteAPPNProfile(jpeg_info, profile, profile_length, profile_name);
2126 }
2127 else if (LocaleCompare(profile_name,"EXIF") == 0)
2128 {
2129 WriteEXIFProfile(jpeg_info, profile, profile_length);
2130 }
2131 else if ((LocaleCompare(profile_name,"ICM") == 0) ||
2132 (LocaleCompare(profile_name,"ICC") == 0))
2133 {
2134 WriteICCProfile(jpeg_info, profile, profile_length);
2135 }
2136 else if ((LocaleCompare(profile_name,"IPTC") == 0) ||
2137 (LocaleCompare(profile_name,"8BIM") == 0))
2138 {
2139 WriteIPTCProfile(jpeg_info, profile, profile_length);
2140 }
2141 else if (LocaleCompare(profile_name,"XMP") == 0)
2142 {
2143 WriteXMPProfile(jpeg_info, profile, profile_length);
2144 }
2145 else
2146 {
2147 /*
2148 Skip unknown profile type
2149 */
2150 if (image->logging)
2151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2152 "Skipped Profile: %s, %"
2153 MAGICK_SIZE_T_F "u bytes",
2154 profile_name,
2155 (MAGICK_SIZE_T) profile_length);
2156 continue;
2157 }
2158
2159 if (image->logging)
2160 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2161 "Wrote Profile: %s, %"
2162 MAGICK_SIZE_T_F "u bytes",profile_name,
2163 (MAGICK_SIZE_T) profile_length);
2164 }
2165 DeallocateImageProfileIterator(profile_iterator);
2166 }
2167
JPEGDestinationManager(j_compress_ptr cinfo,Image * image)2168 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2169 {
2170 DestinationManager
2171 *destination;
2172
2173 cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2174 ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2175 destination=(DestinationManager *) cinfo->dest;
2176 destination->manager.init_destination=InitializeDestination;
2177 destination->manager.empty_output_buffer=EmptyOutputBuffer;
2178 destination->manager.term_destination=TerminateDestination;
2179 destination->image=image;
2180 }
2181
2182 /*
2183 Format a libjpeg warning or trace event while encoding. Warnings
2184 are converted to GraphicsMagick warning exceptions while traces are
2185 optionally logged.
2186
2187 JPEG message codes range from 0 to JMSG_LASTMSGCODE
2188 */
JPEGEncodeMessageHandler(j_common_ptr jpeg_info,int msg_level)2189 static void JPEGEncodeMessageHandler(j_common_ptr jpeg_info,int msg_level)
2190 {
2191 char
2192 message[JMSG_LENGTH_MAX];
2193
2194 struct jpeg_error_mgr
2195 *err;
2196
2197 ErrorManager
2198 *error_manager;
2199
2200 Image
2201 *image;
2202
2203 message[0]='\0';
2204 err=jpeg_info->err;
2205 error_manager=(ErrorManager *) jpeg_info->client_data;
2206 image=error_manager->image;
2207 /* msg_level is -1 for warnings, 0 and up for trace messages. */
2208 if (msg_level < 0)
2209 {
2210 unsigned int strikes = 0;
2211 /* A warning */
2212 (err->format_message)(jpeg_info,message);
2213
2214 if ((err->msg_code >= 0) &&
2215 ((size_t) err->msg_code < ArraySize(error_manager->warning_counts)))
2216 {
2217 error_manager->warning_counts[err->msg_code]++;
2218 strikes=error_manager->warning_counts[err->msg_code];
2219 }
2220
2221 if (image->logging)
2222 {
2223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2224 "[%s] JPEG Warning[%u]: \"%s\""
2225 " (code=%d "
2226 "parms=0x%02x,0x%02x,"
2227 "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)",
2228 image->filename,
2229 strikes,
2230 message,err->msg_code,
2231 err->msg_parm.i[0], err->msg_parm.i[1],
2232 err->msg_parm.i[2], err->msg_parm.i[3],
2233 err->msg_parm.i[4], err->msg_parm.i[5],
2234 err->msg_parm.i[6], err->msg_parm.i[7]);
2235 }
2236 /*
2237 if (strikes > error_manager->max_warning_count)
2238 {
2239 ThrowException2(&image->exception,CorruptImageError,(char *) message,
2240 image->filename);
2241 longjmp(error_manager->error_recovery,1);
2242 }
2243
2244 if ((err->num_warnings == 0) ||
2245 (err->trace_level >= 3))
2246 ThrowException2(&image->exception,CorruptImageWarning,message,
2247 image->filename);
2248 */
2249 /* JWRN_JPEG_EOF - "Premature end of JPEG file" */
2250 err->num_warnings++;
2251 return /* False */;
2252 }
2253 else
2254 {
2255 /* A trace message */
2256 if ((image->logging) && (msg_level >= err->trace_level))
2257 {
2258 (err->format_message)(jpeg_info,message);
2259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2260 "[%s] JPEG Trace: \"%s\"",image->filename,
2261 message);
2262 }
2263 }
2264 return /* True */;
2265 }
2266
2267
JPEGEncodeProgressMonitor(j_common_ptr cinfo)2268 static void JPEGEncodeProgressMonitor(j_common_ptr cinfo)
2269 {
2270 #if USE_LIBJPEG_PROGRESS
2271 struct jpeg_progress_mgr *p = cinfo->progress;
2272 ErrorManager *error_manager = (ErrorManager *) cinfo->client_data;
2273 Image *image = error_manager->image;
2274
2275 #if 0
2276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2277 "Progress: pass_counter=%ld, pass_limit=%ld,"
2278 " completed_passes=%d, total_passes=%d, filename=%s",
2279 p->pass_counter, p->pass_limit,
2280 p->completed_passes, p->total_passes, image->filename);
2281 #endif
2282
2283 if (QuantumTick(p->pass_counter,p->pass_limit))
2284 if (!MagickMonitorFormatted(p->pass_counter,p->pass_limit,&image->exception,
2285 "[%s] Saving image: %lux%lu (pass %d of %d)... ",
2286 image->filename,
2287 image->columns,image->rows,
2288 p->completed_passes+1, p->total_passes))
2289 {
2290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2291 "Quitting due to progress monitor");
2292 longjmp(error_manager->error_recovery,1);
2293 }
2294 #else
2295 (void) cinfo;
2296 #endif /* USE_LIBJPEG_PROGRESS */
2297 }
2298
2299
WriteJPEGImage(const ImageInfo * image_info,Image * imagep)2300 static MagickPassFail WriteJPEGImage(const ImageInfo *image_info,Image *imagep)
2301 {
2302 Image
2303 * volatile imagev = imagep, /* volatile to avoid "clobber" */
2304 *image;
2305
2306 ErrorManager
2307 error_manager;
2308
2309 const ImageAttribute
2310 *attribute;
2311
2312 JSAMPLE
2313 *jpeg_pixels;
2314
2315 JSAMPROW
2316 scanline[1];
2317
2318 char
2319 *sampling_factors,
2320 *preserve_settings;
2321
2322 const char
2323 *value;
2324
2325 long
2326 y;
2327
2328 register const PixelPacket
2329 *p;
2330
2331 register JSAMPLE
2332 *q;
2333
2334 register long
2335 i,
2336 x;
2337
2338 struct jpeg_error_mgr
2339 jpeg_error;
2340
2341 struct jpeg_progress_mgr
2342 jpeg_progress;
2343
2344 struct jpeg_compress_struct
2345 jpeg_info;
2346
2347 MagickPassFail
2348 status;
2349
2350 unsigned long
2351 input_colorspace;
2352
2353 unsigned long
2354 quality;
2355
2356 magick_int64_t
2357 huffman_memory;
2358
2359 ImageCharacteristics
2360 characteristics;
2361
2362 /*
2363 Open image file.
2364 */
2365 assert(image_info != (const ImageInfo *) NULL);
2366 assert(image_info->signature == MagickSignature);
2367 assert(imagep != (Image *) NULL);
2368 assert(imagep->signature == MagickSignature);
2369 status=OpenBlob(image_info,imagev,WriteBinaryBlobMode,&imagev->exception);
2370 if (status == False)
2371 ThrowWriterException(FileOpenError,UnableToOpenFile,imagev);
2372
2373 (void) memset(&error_manager,0,sizeof(error_manager));
2374 (void) memset(&jpeg_progress,0,sizeof(jpeg_progress));
2375 (void) memset(&jpeg_info,0,sizeof(jpeg_info));
2376 (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2377
2378 /*
2379 Set initial longjmp based error handler.
2380 */
2381 jpeg_info.client_data=(void *) imagev;
2382 jpeg_info.err=jpeg_std_error(&jpeg_error);
2383 jpeg_info.err->emit_message=/*(void (*)(j_common_ptr,int))*/ JPEGEncodeMessageHandler;
2384 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2385 error_manager.image=imagev;
2386 error_manager.max_warning_count=MaxWarningCount;
2387 /*
2388 Allow the user to set how many warnings of any given type are
2389 allowed before promotion of the warning to a hard error.
2390 */
2391 if ((value=AccessDefinition(image_info,"jpeg","max-warnings")))
2392 error_manager.max_warning_count=strtol(value,(char **) NULL, 10);
2393 jpeg_info.client_data=(void *) &error_manager;
2394 if (setjmp(error_manager.error_recovery))
2395 {
2396 jpeg_destroy_compress(&jpeg_info);
2397 CloseBlob(imagev);
2398 return MagickFail ;
2399 }
2400 image=imagev; /* Use 'image' after this point for optimization */
2401
2402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2403 " Write JPEG Image: image->orientation = %d",image->orientation);
2404
2405 /*
2406 Transform image to user-requested colorspace.
2407 */
2408 if (UndefinedColorspace != image_info->colorspace)
2409 {
2410 (void) TransformColorspace(image,image_info->colorspace);
2411 }
2412 /*
2413 Convert RGB-compatible colorspaces (e.g. CineonLog) to RGB by
2414 default. User can still override it by explicitly specifying the
2415 desired colorspace.
2416 */
2417 else if (IsRGBCompatibleColorspace(image->colorspace) &&
2418 !IsRGBColorspace(image->colorspace))
2419 {
2420 (void) TransformColorspace(image,RGBColorspace);
2421 }
2422
2423 /*
2424 Analyze image to be written.
2425 */
2426 if (!GetImageCharacteristics(image,&characteristics,
2427 (OptimizeType == image_info->type),
2428 &image->exception))
2429 {
2430 CloseBlob(image);
2431 return MagickFail;
2432 }
2433
2434 jpeg_create_compress(&jpeg_info);
2435 JPEGDestinationManager(&jpeg_info,image);
2436 jpeg_info.image_width=(unsigned int) image->columns;
2437 jpeg_info.image_height=(unsigned int) image->rows;
2438 jpeg_info.input_components=3;
2439 jpeg_info.in_color_space=JCS_RGB;
2440
2441 /*
2442 Register our progress monitor
2443 */
2444 jpeg_progress.progress_monitor=(void (*)(j_common_ptr)) JPEGEncodeProgressMonitor;
2445 jpeg_info.progress=&jpeg_progress;
2446
2447 /*
2448 Set JPEG colorspace as per user request.
2449 */
2450 {
2451 MagickBool
2452 colorspace_set=MagickFalse;
2453
2454 if (IsCMYKColorspace(image_info->colorspace))
2455 {
2456 jpeg_info.input_components=4;
2457 jpeg_info.in_color_space=JCS_CMYK;
2458 colorspace_set=MagickTrue;
2459 }
2460 else if (IsYCbCrColorspace(image_info->colorspace))
2461 {
2462 jpeg_info.input_components=3;
2463 jpeg_info.in_color_space=JCS_YCbCr;
2464 colorspace_set=MagickTrue;
2465 }
2466 else if (IsGrayColorspace(image_info->colorspace))
2467 {
2468 jpeg_info.input_components=1;
2469 jpeg_info.in_color_space=JCS_GRAYSCALE;
2470 colorspace_set=MagickTrue;
2471 }
2472
2473 if (!colorspace_set)
2474 {
2475 if (IsCMYKColorspace(image->colorspace))
2476 {
2477 jpeg_info.input_components=4;
2478 jpeg_info.in_color_space=JCS_CMYK;
2479 }
2480 else if (IsYCbCrColorspace(image->colorspace))
2481 {
2482 jpeg_info.input_components=3;
2483 jpeg_info.in_color_space=JCS_YCbCr;
2484 }
2485 else if ((IsGrayColorspace(image->colorspace) ||
2486 (characteristics.grayscale)))
2487 {
2488 jpeg_info.input_components=1;
2489 jpeg_info.in_color_space=JCS_GRAYSCALE;
2490 }
2491 else
2492 {
2493 jpeg_info.input_components=3;
2494 jpeg_info.in_color_space=JCS_RGB;
2495 }
2496 }
2497 }
2498
2499 input_colorspace=UndefinedColorspace;
2500 quality=image_info->quality;
2501 /* Check for -define jpeg:preserve-settings */
2502 /* ImageMagick:
2503 GetImageOption();
2504 */
2505 /* GraphicsMagick */
2506 preserve_settings=(char *) AccessDefinition(image_info,"jpeg",
2507 "preserve-settings");
2508
2509 sampling_factors=image_info->sampling_factor;
2510
2511 if (preserve_settings)
2512 {
2513 if (image->logging)
2514 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2515 " JPEG:preserve-settings flag is defined.");
2516
2517 /* Retrieve input file quality */
2518 attribute=GetImageAttribute(image,"JPEG-Quality");
2519 if ((attribute != (const ImageAttribute *) NULL) &&
2520 (attribute->value != (char *) NULL))
2521 {
2522 (void) sscanf(attribute->value,"%lu",&quality);
2523 if (image->logging)
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525 " Input quality=%lu",quality);
2526 }
2527
2528 /* Retrieve input file colorspace */
2529 attribute=GetImageAttribute(image,"JPEG-Colorspace");
2530 if ((attribute != (const ImageAttribute *) NULL) &&
2531 (attribute->value != (char *) NULL))
2532 {
2533 (void) sscanf(attribute->value,"%lu",&input_colorspace);
2534 if (image->logging)
2535 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2536 " Input colorspace=%lu",input_colorspace);
2537 }
2538
2539 if (input_colorspace == (unsigned long) jpeg_info.in_color_space)
2540 {
2541 /* Retrieve input sampling factors */
2542 attribute=GetImageAttribute(image,"JPEG-Sampling-factors");
2543 if ((attribute != (const ImageAttribute *) NULL) &&
2544 (attribute->value != (char *) NULL))
2545 {
2546 sampling_factors=attribute->value;
2547 if (image->logging)
2548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549 " Input sampling-factors=%s",sampling_factors);
2550 }
2551 }
2552 else
2553 {
2554 if (image->logging)
2555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2556 " Input colorspace (%lu) != Output colorspace (%d)",
2557 input_colorspace,jpeg_info.in_color_space);
2558 }
2559 }
2560
2561 jpeg_set_defaults(&jpeg_info);
2562
2563 /*
2564 Determine bit depth.
2565 */
2566 {
2567 int
2568 sample_size;
2569
2570 sample_size=sizeof(JSAMPLE)*8;
2571 if (sample_size > 8)
2572 sample_size=12;
2573 if ((jpeg_info.data_precision != 12) &&
2574 (image->depth <= 8))
2575 sample_size=8;
2576 jpeg_info.data_precision=sample_size;
2577 }
2578 if ((image->x_resolution == 0) || (image->y_resolution == 0))
2579 {
2580 image->x_resolution=72.0;
2581 image->y_resolution=72.0;
2582 image->units=PixelsPerInchResolution;
2583 }
2584 if (image_info->density != (char *) NULL)
2585 {
2586 int
2587 count;
2588
2589 /* FIXME: density should not be set via image_info->density
2590 but removing this support may break some applications. */
2591 count=GetMagickDimension(image_info->density,&image->x_resolution,
2592 &image->y_resolution,NULL,NULL);
2593 if (count == 1 )
2594 image->y_resolution=image->x_resolution;
2595 }
2596 jpeg_info.density_unit=1; /* default to DPI */
2597 if (image->logging)
2598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2599 "Image resolution: %ld,%ld",(long) image->x_resolution,
2600 (long) image->y_resolution);
2601 if ((image->x_resolution != 0) && (image->y_resolution != 0))
2602 {
2603 /*
2604 Set image resolution.
2605 */
2606 jpeg_info.write_JFIF_header=True;
2607 jpeg_info.X_density=(short) image->x_resolution;
2608 jpeg_info.Y_density=(short) image->y_resolution;
2609 if (image->units == PixelsPerInchResolution)
2610 jpeg_info.density_unit=1;
2611 if (image->units == PixelsPerCentimeterResolution)
2612 jpeg_info.density_unit=2;
2613 }
2614
2615 {
2616 const char
2617 *value;
2618
2619 /*
2620 Allow the user to select the DCT encoding algorithm.
2621 */
2622 if ((value=AccessDefinition(image_info,"jpeg","dct-method")))
2623 {
2624 if (LocaleCompare(value,"ISLOW") == 0)
2625 jpeg_info.dct_method=JDCT_ISLOW;
2626 else if (LocaleCompare(value,"IFAST") == 0)
2627 jpeg_info.dct_method=JDCT_IFAST;
2628 else if (LocaleCompare(value,"FLOAT") == 0)
2629 jpeg_info.dct_method=JDCT_FLOAT;
2630 else if (LocaleCompare(value,"DEFAULT") == 0)
2631 jpeg_info.dct_method=JDCT_DEFAULT;
2632 else if (LocaleCompare(value,"FASTEST") == 0)
2633 jpeg_info.dct_method=JDCT_FASTEST;
2634 }
2635 }
2636
2637 {
2638 const char
2639 *value;
2640
2641 huffman_memory=0;
2642 if ((value=AccessDefinition(image_info,"jpeg","optimize-coding")))
2643 {
2644 if (LocaleCompare(value,"FALSE") == 0)
2645 jpeg_info.optimize_coding=MagickFalse;
2646 else
2647 jpeg_info.optimize_coding=MagickTrue;
2648 }
2649 else
2650 {
2651 /*
2652 Huffman optimization requires that the whole image be buffered in
2653 memory. Since this is such a large consumer, obtain a memory
2654 resource for the memory to be consumed. If the memory resource
2655 fails to be acquired, then don't enable huffman optimization.
2656 */
2657 huffman_memory=(magick_int64_t) jpeg_info.input_components*
2658 image->columns*image->rows*sizeof(JSAMPLE);
2659 jpeg_info.optimize_coding=AcquireMagickResource(MemoryResource,
2660 huffman_memory);
2661 }
2662 if (!jpeg_info.optimize_coding)
2663 huffman_memory=0;
2664 if (image->logging)
2665 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2666 "Huffman optimization is %s",
2667 (jpeg_info.optimize_coding ? "enabled" : "disabled"));
2668 }
2669
2670 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2671 if (image_info->interlace == LineInterlace)
2672 jpeg_simple_progression(&jpeg_info);
2673 if (image->logging)
2674 {
2675 if (image_info->interlace == LineInterlace)
2676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2677 "Interlace: progressive");
2678 else
2679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2680 "Interlace: nonprogressive");
2681 }
2682 #else
2683 if (image->logging)
2684 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2685 "Interlace: nonprogressive");
2686 #endif
2687 if ((image->compression == LosslessJPEGCompression) ||
2688 (quality > 100))
2689 {
2690 #if defined(C_LOSSLESS_SUPPORTED)
2691 if (quality < 100)
2692 ThrowException(&image->exception,CoderWarning,
2693 LosslessToLossyJPEGConversion,(char *) NULL);
2694 else
2695 {
2696 int
2697 point_transform,
2698 predictor;
2699
2700 predictor=quality/100; /* range 1-7 */
2701 point_transform=quality % 20; /* range 0-15 */
2702 jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2703 if (image->logging)
2704 {
2705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2706 "Compression: lossless");
2707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2708 "Predictor: %d",predictor);
2709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2710 "Point Transform: %d",point_transform);
2711 }
2712 }
2713 #else
2714 {
2715 jpeg_set_quality(&jpeg_info,100,True);
2716 if (image->logging)
2717 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2718 }
2719 #endif
2720 }
2721 else
2722 {
2723 jpeg_set_quality(&jpeg_info,(int) quality,True);
2724 if (image->logging)
2725 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
2726 quality);
2727 }
2728 if (sampling_factors != (char *) NULL)
2729 {
2730 double
2731 hs[4]={1.0, 1.0, 1.0, 1.0},
2732 vs[4]={1.0, 1.0, 1.0, 1.0};
2733
2734 long
2735 count;
2736
2737 /*
2738 Set sampling factors.
2739 */
2740 count=sscanf(sampling_factors,"%lfx%lf,%lfx%lf,%lfx%lf,%lfx%lf",
2741 &hs[0],&vs[0],&hs[1],&vs[1],&hs[2],&vs[2],&hs[3],&vs[3]);
2742
2743 if (count%2 == 1)
2744 vs[count/2]=hs[count/2];
2745
2746 for (i=0; i < 4; i++)
2747 {
2748 jpeg_info.comp_info[i].h_samp_factor=(int) hs[i];
2749 jpeg_info.comp_info[i].v_samp_factor=(int) vs[i];
2750 }
2751 for (; i < MAX_COMPONENTS; i++)
2752 {
2753 jpeg_info.comp_info[i].h_samp_factor=1;
2754 jpeg_info.comp_info[i].v_samp_factor=1;
2755 }
2756 }
2757 else
2758 {
2759 if (quality >= 90)
2760 for (i=0; i < MAX_COMPONENTS; i++)
2761 {
2762 jpeg_info.comp_info[i].h_samp_factor=1;
2763 jpeg_info.comp_info[i].v_samp_factor=1;
2764 }
2765 }
2766
2767 if (image->logging)
2768 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2769 "Starting JPEG compression");
2770 jpeg_start_compress(&jpeg_info,True);
2771 if (image->logging)
2772 {
2773 if (image->storage_class == PseudoClass)
2774 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2775 "Storage class: PseudoClass");
2776 else
2777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2778 "Storage class: DirectClass");
2779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %u",
2780 image->depth);
2781 if (image->colors)
2782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2783 "Number of colors: %u",image->colors);
2784 else
2785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2786 "Number of colors: unspecified");
2787 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2788 "JPEG data precision: %d",(int) jpeg_info.data_precision);
2789 if (IsCMYKColorspace(image_info->colorspace))
2790 {
2791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2792 "Storage class: DirectClass");
2793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2794 "Colorspace: CMYK");
2795 }
2796 else if (IsYCbCrColorspace(image_info->colorspace))
2797 {
2798 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2799 "Colorspace: YCbCr");
2800 }
2801 if (IsCMYKColorspace(image->colorspace))
2802 {
2803 /* A CMYK space */
2804 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2805 "Colorspace: CMYK");
2806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2807 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2808 jpeg_info.comp_info[0].h_samp_factor,
2809 jpeg_info.comp_info[0].v_samp_factor,
2810 jpeg_info.comp_info[1].h_samp_factor,
2811 jpeg_info.comp_info[1].v_samp_factor,
2812 jpeg_info.comp_info[2].h_samp_factor,
2813 jpeg_info.comp_info[2].v_samp_factor,
2814 jpeg_info.comp_info[3].h_samp_factor,
2815 jpeg_info.comp_info[3].v_samp_factor);
2816 }
2817 else if (IsGrayColorspace(image->colorspace))
2818 {
2819 /* A gray space */
2820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2821 "Colorspace: GRAY");
2822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2823 "Sampling factors: %dx%d",
2824 jpeg_info.comp_info[0].h_samp_factor,
2825 jpeg_info.comp_info[0].v_samp_factor);
2826 }
2827 else if (IsRGBCompatibleColorspace(image->colorspace))
2828 {
2829 /* An RGB space */
2830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2831 " Image colorspace is RGB");
2832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2833 "Sampling factors: %dx%d,%dx%d,%dx%d",
2834 jpeg_info.comp_info[0].h_samp_factor,
2835 jpeg_info.comp_info[0].v_samp_factor,
2836 jpeg_info.comp_info[1].h_samp_factor,
2837 jpeg_info.comp_info[1].v_samp_factor,
2838 jpeg_info.comp_info[2].h_samp_factor,
2839 jpeg_info.comp_info[2].v_samp_factor);
2840 }
2841 else if (IsYCbCrColorspace(image->colorspace))
2842 {
2843 /* A YCbCr space */
2844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2845 "Colorspace: YCbCr");
2846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2847 "Sampling factors: %dx%d,%dx%d,%dx%d",
2848 jpeg_info.comp_info[0].h_samp_factor,
2849 jpeg_info.comp_info[0].v_samp_factor,
2850 jpeg_info.comp_info[1].h_samp_factor,
2851 jpeg_info.comp_info[1].v_samp_factor,
2852 jpeg_info.comp_info[2].h_samp_factor,
2853 jpeg_info.comp_info[2].v_samp_factor);
2854 }
2855 else
2856 {
2857 /* Some other color space */
2858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2859 image->colorspace);
2860 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2861 "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2862 jpeg_info.comp_info[0].h_samp_factor,
2863 jpeg_info.comp_info[0].v_samp_factor,
2864 jpeg_info.comp_info[1].h_samp_factor,
2865 jpeg_info.comp_info[1].v_samp_factor,
2866 jpeg_info.comp_info[2].h_samp_factor,
2867 jpeg_info.comp_info[2].v_samp_factor,
2868 jpeg_info.comp_info[3].h_samp_factor,
2869 jpeg_info.comp_info[3].v_samp_factor);
2870 }
2871 }
2872 /*
2873 Write JPEG profiles.
2874 */
2875 attribute=GetImageAttribute(image,"comment");
2876 if ((attribute != (const ImageAttribute *) NULL) &&
2877 (attribute->value != (char *) NULL))
2878 for (i=0; i < (long) strlen(attribute->value); i+=65533L)
2879 jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) attribute->value+
2880 i,(int) Min(strlen(attribute->value+i),65533L));
2881 #if 0
2882 WriteICCProfile(&jpeg_info,image);
2883 WriteIPTCProfile(&jpeg_info,image);
2884 WriteXMPProfile(&jpeg_info,image);
2885 #endif
2886 WriteProfiles(&jpeg_info,image);
2887 /*
2888 Convert MIFF to JPEG raster pixels.
2889 */
2890 jpeg_pixels=MagickAllocateResourceLimitedArray(JSAMPLE *,
2891 jpeg_info.input_components*image->columns,sizeof(JSAMPLE));
2892 if (jpeg_pixels == (JSAMPLE *) NULL)
2893 {
2894 if (huffman_memory)
2895 LiberateMagickResource(MemoryResource,huffman_memory);
2896 ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
2897 }
2898 scanline[0]=(JSAMPROW) jpeg_pixels;
2899 if (jpeg_info.data_precision > 8)
2900 {
2901 unsigned int
2902 scale_short;
2903
2904 scale_short=65535U/MaxValueGivenBits(jpeg_info.data_precision);
2905
2906 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2907 {
2908 if (image->logging)
2909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2910 "Writing %d bit JCS_GRAYSCALE samples",
2911 jpeg_info.data_precision);
2912 for (y=0; y < (long) image->rows; y++)
2913 {
2914 p=AcquireImagePixels(image,0,y,image->columns,1,
2915 &image->exception);
2916 if (p == (const PixelPacket *) NULL)
2917 break;
2918 q=jpeg_pixels;
2919 if (image->is_grayscale)
2920 {
2921 for (x=0; x < (long) image->columns; x++)
2922 {
2923 *q++=(JSAMPLE) (ScaleQuantumToShort(GetGraySample(p))/
2924 scale_short);
2925 p++;
2926 }
2927 }
2928 else
2929 {
2930 for (x=0; x < (long) image->columns; x++)
2931 {
2932 *q++=(JSAMPLE)
2933 (ScaleQuantumToShort(PixelIntensityToQuantum(p))/scale_short);
2934 p++;
2935 }
2936 }
2937 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2938 #if !USE_LIBJPEG_PROGRESS
2939 if (QuantumTick(y,image->rows))
2940 if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2941 SaveImageText,image->filename,
2942 image->columns,image->rows))
2943 break;
2944 #endif /* !USE_LIBJPEG_PROGRESS */
2945 }
2946 }
2947 else
2948 if ((jpeg_info.in_color_space == JCS_RGB) ||
2949 (jpeg_info.in_color_space == JCS_YCbCr))
2950 {
2951 if (image->logging)
2952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2953 "Writing %d bit JCS_RGB or "
2954 "JCS_YCbCr samples",
2955 jpeg_info.data_precision);
2956 for (y=0; y < (long) image->rows; y++)
2957 {
2958 p=AcquireImagePixels(image,0,y,image->columns,1,
2959 &image->exception);
2960 if (p == (const PixelPacket *) NULL)
2961 break;
2962 q=jpeg_pixels;
2963 for (x=0; x < (long) image->columns; x++)
2964 {
2965 *q++=(JSAMPLE) (ScaleQuantumToShort(p->red)/16);
2966 *q++=(JSAMPLE) (ScaleQuantumToShort(p->green)/16);
2967 *q++=(JSAMPLE) (ScaleQuantumToShort(p->blue)/16);
2968 p++;
2969 }
2970 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2971 #if !USE_LIBJPEG_PROGRESS
2972 if (QuantumTick(y,image->rows))
2973 if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2974 SaveImageText,image->filename,
2975 image->columns,image->rows))
2976 break;
2977 #endif /* !USE_LIBJPEG_PROGRESS */
2978 }
2979 }
2980 else
2981 {
2982 if (image->logging)
2983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2984 "Writing %d bit JCS_CMYK samples",
2985 jpeg_info.data_precision);
2986 for (y=0; y < (long) image->rows; y++)
2987 {
2988 p=AcquireImagePixels(image,0,y,image->columns,1,
2989 &image->exception);
2990 if (p == (const PixelPacket *) NULL)
2991 break;
2992 q=jpeg_pixels;
2993 for (x=0; x < (long) image->columns; x++)
2994 {
2995 /*
2996 Convert DirectClass packets to contiguous CMYK scanlines.
2997 */
2998 *q++=(JSAMPLE) (4095-ScaleQuantumToShort(p->red)/16);
2999 *q++=(JSAMPLE) (4095-ScaleQuantumToShort(p->green)/16);
3000 *q++=(JSAMPLE) (4095-ScaleQuantumToShort(p->blue)/16);
3001 *q++=(JSAMPLE) (4095-ScaleQuantumToShort(p->opacity)/16);
3002 p++;
3003 }
3004 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
3005 #if !USE_LIBJPEG_PROGRESS
3006 if (QuantumTick(y,image->rows))
3007 if (!MagickMonitorFormatted(y,image->rows,&image->exception,
3008 SaveImageText,image->filename,
3009 image->columns,image->rows))
3010 break;
3011 #endif /* !USE_LIBJPEG_PROGRESS */
3012 }
3013 }
3014 }
3015 else
3016 if (jpeg_info.in_color_space == JCS_GRAYSCALE)
3017 {
3018 if (image->logging)
3019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3020 "Writing %d bit JCS_GRAYSCALE samples",
3021 jpeg_info.data_precision);
3022 for (y=0; y < (long) image->rows; y++)
3023 {
3024 p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
3025 if (p == (const PixelPacket *) NULL)
3026 break;
3027 q=jpeg_pixels;
3028 if (image->is_grayscale)
3029 {
3030 for (x=0; x < (long) image->columns; x++)
3031 {
3032 *q++=(JSAMPLE) ScaleQuantumToChar(GetGraySample(p));
3033 p++;
3034 }
3035 }
3036 else
3037 {
3038 for (x=0; x < (long) image->columns; x++)
3039 {
3040 *q++=(JSAMPLE)
3041 ScaleQuantumToChar(PixelIntensityToQuantum(p));
3042 p++;
3043 }
3044 }
3045 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
3046 #if !USE_LIBJPEG_PROGRESS
3047 if (QuantumTick(y,image->rows))
3048 if (!MagickMonitorFormatted(y,image->rows,&image->exception,
3049 SaveImageText,image->filename,
3050 image->columns,image->rows))
3051 break;
3052 #endif /* !USE_LIBJPEG_PROGRESS */
3053 }
3054 }
3055 else
3056 if ((jpeg_info.in_color_space == JCS_RGB) ||
3057 (jpeg_info.in_color_space == JCS_YCbCr))
3058 {
3059 if (image->logging)
3060 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3061 "Writing %d bit JCS_RGB or JCS_YCbCr samples",
3062 jpeg_info.data_precision);
3063 for (y=0; y < (long) image->rows; y++)
3064 {
3065 p=AcquireImagePixels(image,0,y,image->columns,1,
3066 &image->exception);
3067 if (p == (const PixelPacket *) NULL)
3068 break;
3069 q=jpeg_pixels;
3070 for (x=0; x < (long) image->columns; x++)
3071 {
3072 *q++=(JSAMPLE) ScaleQuantumToChar(p->red);
3073 *q++=(JSAMPLE) ScaleQuantumToChar(p->green);
3074 *q++=(JSAMPLE) ScaleQuantumToChar(p->blue);
3075 p++;
3076 }
3077 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
3078 #if !USE_LIBJPEG_PROGRESS
3079 if (QuantumTick(y,image->rows))
3080 if (!MagickMonitorFormatted(y,image->rows,&image->exception,
3081 SaveImageText,image->filename,
3082 image->columns,image->rows))
3083 break;
3084 #endif /* !USE_LIBJPEG_PROGRESS */
3085 }
3086 }
3087 else
3088 {
3089 if (image->logging)
3090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3091 "Writing %d bit JCS_CMYK samples",
3092 jpeg_info.data_precision);
3093 for (y=0; y < (long) image->rows; y++)
3094 {
3095 p=AcquireImagePixels(image,0,y,image->columns,1,
3096 &image->exception);
3097 if (p == (const PixelPacket *) NULL)
3098 break;
3099 q=jpeg_pixels;
3100 for (x=0; x < (long) image->columns; x++)
3101 {
3102 /*
3103 Convert DirectClass packets to contiguous CMYK scanlines.
3104 */
3105 *q++=(JSAMPLE) (ScaleQuantumToChar(MaxRGB-p->red));
3106 *q++=(JSAMPLE) (ScaleQuantumToChar(MaxRGB-p->green));
3107 *q++=(JSAMPLE) (ScaleQuantumToChar(MaxRGB-p->blue));
3108 *q++=(JSAMPLE) (ScaleQuantumToChar(MaxRGB-p->opacity));
3109 p++;
3110 }
3111 (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
3112 #if !USE_LIBJPEG_PROGRESS
3113 if (QuantumTick(y,image->rows))
3114 if (!MagickMonitorFormatted(y,image->rows,&image->exception,
3115 SaveImageText,image->filename,
3116 image->columns,image->rows))
3117 break;
3118 #endif /* !USE_LIBJPEG_PROGRESS */
3119 }
3120 }
3121 if (image->logging)
3122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3123 "Finishing JPEG compression");
3124 jpeg_finish_compress(&jpeg_info);
3125 /*
3126 Free memory.
3127 */
3128 if (huffman_memory)
3129 LiberateMagickResource(MemoryResource,huffman_memory);
3130 jpeg_destroy_compress(&jpeg_info);
3131 MagickFreeResourceLimitedMemory(jpeg_pixels);
3132 CloseBlob(image);
3133 return(True);
3134 }
3135 #endif
3136