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

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