source: ImageMagick/trunk/coders/jpeg.c @ 7024

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