Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                            PPPP    CCCC  DDDD                               %
      7 %                            P   P  C      D   D                              %
      8 %                            PPPP   C      D   D                              %
      9 %                            P      C      D   D                              %
     10 %                            P       CCCC  DDDD                               %
     11 %                                                                             %
     12 %                                                                             %
     13 %                     Read/Write Photo CD Image Format                        %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1992                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 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 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/property.h"
     45 #include "MagickCore/blob.h"
     46 #include "MagickCore/blob-private.h"
     47 #include "MagickCore/cache.h"
     48 #include "MagickCore/client.h"
     49 #include "MagickCore/colorspace.h"
     50 #include "MagickCore/colorspace-private.h"
     51 #include "MagickCore/constitute.h"
     52 #include "MagickCore/decorate.h"
     53 #include "MagickCore/distort.h"
     54 #include "MagickCore/exception.h"
     55 #include "MagickCore/exception-private.h"
     56 #include "MagickCore/gem.h"
     57 #include "MagickCore/geometry.h"
     58 #include "MagickCore/image.h"
     59 #include "MagickCore/image-private.h"
     60 #include "MagickCore/list.h"
     61 #include "MagickCore/magick.h"
     62 #include "MagickCore/memory_.h"
     63 #include "MagickCore/monitor.h"
     64 #include "MagickCore/monitor-private.h"
     65 #include "MagickCore/montage.h"
     66 #include "MagickCore/pixel-accessor.h"
     67 #include "MagickCore/resize.h"
     68 #include "MagickCore/quantum-private.h"
     69 #include "MagickCore/static.h"
     70 #include "MagickCore/string_.h"
     71 #include "MagickCore/module.h"
     72 #include "MagickCore/utility.h"
     73 
     74 /*
     76   Forward declarations.
     77 */
     78 static MagickBooleanType
     79   WritePCDImage(const ImageInfo *,Image *,ExceptionInfo *);
     80 
     81 /*
     83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     84 %                                                                             %
     85 %                                                                             %
     86 %                                                                             %
     87 %   D e c o d e I m a g e                                                     %
     88 %                                                                             %
     89 %                                                                             %
     90 %                                                                             %
     91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     92 %
     93 %  DecodeImage recovers the Huffman encoded luminance and chrominance
     94 %  deltas.
     95 %
     96 %  The format of the DecodeImage method is:
     97 %
     98 %      MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
     99 %        unsigned char *chroma1,unsigned char *chroma2)
    100 %
    101 %  A description of each parameter follows:
    102 %
    103 %    o image: the address of a structure of type Image.
    104 %
    105 %    o luma: the address of a character buffer that contains the
    106 %      luminance information.
    107 %
    108 %    o chroma1: the address of a character buffer that contains the
    109 %      chrominance information.
    110 %
    111 %    o chroma2: the address of a character buffer that contains the
    112 %      chrominance information.
    113 %
    114 */
    115 static MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
    116   unsigned char *chroma1,unsigned char *chroma2,ExceptionInfo *exception)
    117 {
    118 #define IsSync(sum)  ((sum & 0xffffff00UL) == 0xfffffe00UL)
    119 #define PCDGetBits(n) \
    120 {  \
    121   sum=(sum << n) & 0xffffffff; \
    122   bits-=n; \
    123   while (bits <= 24) \
    124   { \
    125     if (p >= (buffer+0x800)) \
    126       { \
    127         count=ReadBlob(image,0x800,buffer); \
    128         p=buffer; \
    129       } \
    130     sum|=((unsigned int) (*p) << (24-bits)); \
    131     bits+=8; \
    132     p++; \
    133   } \
    134 }
    135 
    136   typedef struct PCDTable
    137   {
    138     unsigned int
    139       length,
    140       sequence;
    141 
    142     MagickStatusType
    143       mask;
    144 
    145     unsigned char
    146       key;
    147   } PCDTable;
    148 
    149   PCDTable
    150     *pcd_table[3];
    151 
    152   register ssize_t
    153     i,
    154     j;
    155 
    156   register PCDTable
    157     *r;
    158 
    159   register unsigned char
    160     *p,
    161     *q;
    162 
    163   size_t
    164     bits,
    165     length,
    166     plane,
    167     pcd_length[3],
    168     row,
    169     sum;
    170 
    171   ssize_t
    172     count,
    173     quantum;
    174 
    175   unsigned char
    176     *buffer;
    177 
    178   /*
    179     Initialize Huffman tables.
    180   */
    181   assert(image != (const Image *) NULL);
    182   assert(image->signature == MagickCoreSignature);
    183   if (image->debug != MagickFalse)
    184     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    185   assert(luma != (unsigned char *) NULL);
    186   assert(chroma1 != (unsigned char *) NULL);
    187   assert(chroma2 != (unsigned char *) NULL);
    188   buffer=(unsigned char *) AcquireQuantumMemory(0x800,sizeof(*buffer));
    189   if (buffer == (unsigned char *) NULL)
    190     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
    191       image->filename);
    192   sum=0;
    193   bits=32;
    194   p=buffer+0x800;
    195   for (i=0; i < 3; i++)
    196   {
    197     pcd_table[i]=(PCDTable *) NULL;
    198     pcd_length[i]=0;
    199   }
    200   for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
    201   {
    202     PCDGetBits(8);
    203     length=(sum & 0xff)+1;
    204     pcd_table[i]=(PCDTable *) AcquireQuantumMemory(length,
    205       sizeof(*pcd_table[i]));
    206     if (pcd_table[i] == (PCDTable *) NULL)
    207       {
    208         buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    209         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
    210           image->filename);
    211       }
    212     r=pcd_table[i];
    213     for (j=0; j < (ssize_t) length; j++)
    214     {
    215       PCDGetBits(8);
    216       r->length=(unsigned int) (sum & 0xff)+1;
    217       if (r->length > 16)
    218         {
    219           buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    220           return(MagickFalse);
    221         }
    222       PCDGetBits(16);
    223       r->sequence=(unsigned int) (sum & 0xffff) << 16;
    224       PCDGetBits(8);
    225       r->key=(unsigned char) (sum & 0xff);
    226       r->mask=(~((1U << (32-r->length))-1));
    227       r++;
    228     }
    229     pcd_length[i]=(size_t) length;
    230   }
    231   /*
    232     Search for Sync byte.
    233   */
    234   for (i=0; i < 1; i++)
    235     PCDGetBits(16);
    236   for (i=0; i < 1; i++)
    237     PCDGetBits(16);
    238   while ((sum & 0x00fff000UL) != 0x00fff000UL)
    239     PCDGetBits(8);
    240   while (IsSync(sum) == 0)
    241     PCDGetBits(1);
    242   /*
    243     Recover the Huffman encoded luminance and chrominance deltas.
    244   */
    245   count=0;
    246   length=0;
    247   plane=0;
    248   row=0;
    249   q=luma;
    250   for ( ; ; )
    251   {
    252     if (IsSync(sum) != 0)
    253       {
    254         /*
    255           Determine plane and row number.
    256         */
    257         PCDGetBits(16);
    258         row=((sum >> 9) & 0x1fff);
    259         if (row == image->rows)
    260           break;
    261         PCDGetBits(8);
    262         plane=sum >> 30;
    263         PCDGetBits(16);
    264         switch (plane)
    265         {
    266           case 0:
    267           {
    268             q=luma+row*image->columns;
    269             count=(ssize_t) image->columns;
    270             break;
    271           }
    272           case 2:
    273           {
    274             q=chroma1+(row >> 1)*image->columns;
    275             count=(ssize_t) (image->columns >> 1);
    276             plane--;
    277             break;
    278           }
    279           case 3:
    280           {
    281             q=chroma2+(row >> 1)*image->columns;
    282             count=(ssize_t) (image->columns >> 1);
    283             plane--;
    284             break;
    285           }
    286           default:
    287           {
    288             ThrowBinaryException(CorruptImageError,"CorruptImage",
    289               image->filename);
    290           }
    291         }
    292         length=pcd_length[plane];
    293         continue;
    294       }
    295     /*
    296       Decode luminance or chrominance deltas.
    297     */
    298     r=pcd_table[plane];
    299     for (i=0; ((i < (ssize_t) length) && ((sum & r->mask) != r->sequence)); i++)
    300       r++;
    301     if ((row > image->rows) || (r == (PCDTable *) NULL))
    302       {
    303         (void) ThrowMagickException(exception,GetMagickModule(),
    304           CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
    305         while ((sum & 0x00fff000) != 0x00fff000)
    306           PCDGetBits(8);
    307         while (IsSync(sum) == 0)
    308           PCDGetBits(1);
    309         continue;
    310       }
    311     if (r->key < 128)
    312       quantum=(ssize_t) (*q)+r->key;
    313     else
    314       quantum=(ssize_t) (*q)+r->key-256;
    315     *q=(unsigned char) ((quantum < 0) ? 0 : (quantum > 255) ? 255 : quantum);
    316     q++;
    317     PCDGetBits(r->length);
    318     count--;
    319   }
    320   /*
    321     Relinquish resources.
    322   */
    323   for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
    324     pcd_table[i]=(PCDTable *) RelinquishMagickMemory(pcd_table[i]);
    325   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    326   return(MagickTrue);
    327 }
    328 
    329 /*
    331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    332 %                                                                             %
    333 %                                                                             %
    334 %                                                                             %
    335 %   I s P C D                                                                 %
    336 %                                                                             %
    337 %                                                                             %
    338 %                                                                             %
    339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    340 %
    341 %  IsPCD() returns MagickTrue if the image format type, identified by the
    342 %  magick string, is PCD.
    343 %
    344 %  The format of the IsPCD method is:
    345 %
    346 %      MagickBooleanType IsPCD(const unsigned char *magick,const size_t length)
    347 %
    348 %  A description of each parameter follows:
    349 %
    350 %    o magick: compare image format pattern against these bytes.
    351 %
    352 %    o length: Specifies the length of the magick string.
    353 %
    354 */
    355 static MagickBooleanType IsPCD(const unsigned char *magick,const size_t length)
    356 {
    357   if (length < 2052)
    358     return(MagickFalse);
    359   if (LocaleNCompare((const char *) magick+2048,"PCD_",4) == 0)
    360     return(MagickTrue);
    361   return(MagickFalse);
    362 }
    363 
    364 /*
    366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    367 %                                                                             %
    368 %                                                                             %
    369 %                                                                             %
    370 %   R e a d P C D I m a g e                                                   %
    371 %                                                                             %
    372 %                                                                             %
    373 %                                                                             %
    374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    375 %
    376 %  ReadPCDImage() reads a Photo CD image file and returns it.  It
    377 %  allocates the memory necessary for the new Image structure and returns a
    378 %  pointer to the new image.  Much of the PCD decoder was derived from
    379 %  the program hpcdtoppm(1) by Hadmut Danisch.
    380 %
    381 %  The format of the ReadPCDImage method is:
    382 %
    383 %      image=ReadPCDImage(image_info)
    384 %
    385 %  A description of each parameter follows:
    386 %
    387 %    o image_info: the image info.
    388 %
    389 %    o exception: return any errors or warnings in this structure.
    390 %
    391 */
    392 static Image *OverviewImage(const ImageInfo *image_info,Image *image,
    393   ExceptionInfo *exception)
    394 {
    395   Image
    396     *montage_image;
    397 
    398   MontageInfo
    399     *montage_info;
    400 
    401   register Image
    402     *p;
    403 
    404   /*
    405     Create the PCD Overview image.
    406   */
    407   for (p=image; p != (Image *) NULL; p=p->next)
    408   {
    409     (void) DeleteImageProperty(p,"label");
    410     (void) SetImageProperty(p,"label",DefaultTileLabel,exception);
    411   }
    412   montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL);
    413   (void) CopyMagickString(montage_info->filename,image_info->filename,
    414     MagickPathExtent);
    415   montage_image=MontageImageList(image_info,montage_info,image,exception);
    416   montage_info=DestroyMontageInfo(montage_info);
    417   if (montage_image == (Image *) NULL)
    418     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    419   image=DestroyImage(image);
    420   return(montage_image);
    421 }
    422 
    423 static void Upsample(const size_t width,const size_t height,
    424   const size_t scaled_width,unsigned char *pixels)
    425 {
    426   register ssize_t
    427     x,
    428     y;
    429 
    430   register unsigned char
    431     *p,
    432     *q,
    433     *r;
    434 
    435   /*
    436     Create a new image that is a integral size greater than an existing one.
    437   */
    438   assert(pixels != (unsigned char *) NULL);
    439   for (y=0; y < (ssize_t) height; y++)
    440   {
    441     p=pixels+(height-1-y)*scaled_width+(width-1);
    442     q=pixels+((height-1-y) << 1)*scaled_width+((width-1) << 1);
    443     *q=(*p);
    444     *(q+1)=(*(p));
    445     for (x=1; x < (ssize_t) width; x++)
    446     {
    447       p--;
    448       q-=2;
    449       *q=(*p);
    450       *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+1))+1) >> 1);
    451     }
    452   }
    453   for (y=0; y < (ssize_t) (height-1); y++)
    454   {
    455     p=pixels+((size_t) y << 1)*scaled_width;
    456     q=p+scaled_width;
    457     r=q+scaled_width;
    458     for (x=0; x < (ssize_t) (width-1); x++)
    459     {
    460       *q=(unsigned char) ((((size_t) *p)+((size_t) *r)+1) >> 1);
    461       *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+2))+
    462         ((size_t) *r)+((size_t) *(r+2))+2) >> 2);
    463       q+=2;
    464       p+=2;
    465       r+=2;
    466     }
    467     *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1);
    468     *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1);
    469   }
    470   p=pixels+(2*height-2)*scaled_width;
    471   q=pixels+(2*height-1)*scaled_width;
    472   (void) CopyMagickMemory(q,p,(size_t) (2*width));
    473 }
    474 
    475 static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception)
    476 {
    477   Image
    478     *image;
    479 
    480   MagickBooleanType
    481     status;
    482 
    483   MagickOffsetType
    484     offset;
    485 
    486   MagickSizeType
    487     number_pixels;
    488 
    489   register ssize_t
    490     i,
    491     y;
    492 
    493   register Quantum
    494     *q;
    495 
    496   register unsigned char
    497     *c1,
    498     *c2,
    499     *yy;
    500 
    501   size_t
    502     height,
    503     number_images,
    504     rotate,
    505     scene,
    506     width;
    507 
    508   ssize_t
    509     count,
    510     x;
    511 
    512   unsigned char
    513     *chroma1,
    514     *chroma2,
    515     *header,
    516     *luma;
    517 
    518   unsigned int
    519     overview;
    520 
    521   /*
    522     Open image file.
    523   */
    524   assert(image_info != (const ImageInfo *) NULL);
    525   assert(image_info->signature == MagickCoreSignature);
    526   if (image_info->debug != MagickFalse)
    527     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    528       image_info->filename);
    529   assert(exception != (ExceptionInfo *) NULL);
    530   assert(exception->signature == MagickCoreSignature);
    531   image=AcquireImage(image_info,exception);
    532   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    533   if (status == MagickFalse)
    534     {
    535       image=DestroyImageList(image);
    536       return((Image *) NULL);
    537     }
    538   /*
    539     Determine if this a PCD file.
    540   */
    541   header=(unsigned char *) AcquireQuantumMemory(0x800,3UL*sizeof(*header));
    542   if (header == (unsigned char *) NULL)
    543     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    544   count=ReadBlob(image,3*0x800,header);
    545   overview=LocaleNCompare((char *) header,"PCD_OPA",7) == 0;
    546   if ((count != (3*0x800)) ||
    547       ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && (overview ==0)))
    548     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    549   rotate=header[0x0e02] & 0x03;
    550   number_images=(header[10] << 8) | header[11];
    551   if (number_images > 65535)
    552     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    553   header=(unsigned char *) RelinquishMagickMemory(header);
    554   /*
    555     Determine resolution by scene specification.
    556   */
    557   if ((image->columns == 0) || (image->rows == 0))
    558     scene=3;
    559   else
    560     {
    561       width=192;
    562       height=128;
    563       for (scene=1; scene < 6; scene++)
    564       {
    565         if ((width >= image->columns) && (height >= image->rows))
    566           break;
    567         width<<=1;
    568         height<<=1;
    569       }
    570     }
    571   if (image_info->number_scenes != 0)
    572     scene=(size_t) MagickMin(image_info->scene,6);
    573   if (overview != 0)
    574     scene=1;
    575   /*
    576     Initialize image structure.
    577   */
    578   width=192;
    579   height=128;
    580   for (i=1; i < (ssize_t) MagickMin(scene,3); i++)
    581   {
    582     width<<=1;
    583     height<<=1;
    584   }
    585   image->columns=width;
    586   image->rows=height;
    587   image->depth=8;
    588   for ( ; i < (ssize_t) scene; i++)
    589   {
    590     image->columns<<=1;
    591     image->rows<<=1;
    592   }
    593   status=SetImageExtent(image,image->columns,image->rows,exception);
    594   if (status == MagickFalse)
    595     return(DestroyImageList(image));
    596   /*
    597     Allocate luma and chroma memory.
    598   */
    599   number_pixels=(MagickSizeType) image->columns*image->rows;
    600   if (number_pixels != (size_t) number_pixels)
    601     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    602   chroma1=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
    603     10*sizeof(*chroma1));
    604   chroma2=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
    605     10*sizeof(*chroma2));
    606   luma=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
    607     10*sizeof(*luma));
    608   if ((chroma1 == (unsigned char *) NULL) ||
    609       (chroma2 == (unsigned char *) NULL) || (luma == (unsigned char *) NULL))
    610     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    611   /*
    612     Advance to image data.
    613   */
    614   offset=93;
    615   if (overview != 0)
    616     offset=2;
    617   else
    618     if (scene == 2)
    619       offset=20;
    620     else
    621       if (scene <= 1)
    622         offset=1;
    623   for (i=0; i < (ssize_t) (offset*0x800); i++)
    624     (void) ReadBlobByte(image);
    625   if (overview != 0)
    626     {
    627       Image
    628         *overview_image;
    629 
    630       MagickProgressMonitor
    631         progress_monitor;
    632 
    633       register ssize_t
    634         j;
    635 
    636       /*
    637         Read thumbnails from overview image.
    638       */
    639       for (j=1; j <= (ssize_t) number_images; j++)
    640       {
    641         progress_monitor=SetImageProgressMonitor(image,
    642           (MagickProgressMonitor) NULL,image->client_data);
    643         (void) FormatLocaleString(image->filename,MagickPathExtent,
    644           "images/img%04ld.pcd",(long) j);
    645         (void) FormatLocaleString(image->magick_filename,MagickPathExtent,
    646           "images/img%04ld.pcd",(long) j);
    647         image->scene=(size_t) j;
    648         image->columns=width;
    649         image->rows=height;
    650         image->depth=8;
    651         yy=luma;
    652         c1=chroma1;
    653         c2=chroma2;
    654         for (y=0; y < (ssize_t) height; y+=2)
    655         {
    656           count=ReadBlob(image,width,yy);
    657           yy+=image->columns;
    658           count=ReadBlob(image,width,yy);
    659           yy+=image->columns;
    660           count=ReadBlob(image,width >> 1,c1);
    661           c1+=image->columns;
    662           count=ReadBlob(image,width >> 1,c2);
    663           c2+=image->columns;
    664         }
    665         Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
    666         Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
    667         /*
    668           Transfer luminance and chrominance channels.
    669         */
    670         yy=luma;
    671         c1=chroma1;
    672         c2=chroma2;
    673         for (y=0; y < (ssize_t) image->rows; y++)
    674         {
    675           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    676           if (q == (Quantum *) NULL)
    677             break;
    678           for (x=0; x < (ssize_t) image->columns; x++)
    679           {
    680             SetPixelRed(image,ScaleCharToQuantum(*yy++),q);
    681             SetPixelGreen(image,ScaleCharToQuantum(*c1++),q);
    682             SetPixelBlue(image,ScaleCharToQuantum(*c2++),q);
    683             q+=GetPixelChannels(image);
    684           }
    685           if (SyncAuthenticPixels(image,exception) == MagickFalse)
    686             break;
    687         }
    688         image->colorspace=YCCColorspace;
    689         if (LocaleCompare(image_info->magick,"PCDS") == 0)
    690           SetImageColorspace(image,sRGBColorspace,exception);
    691         if (j < (ssize_t) number_images)
    692           {
    693             /*
    694               Allocate next image structure.
    695             */
    696             AcquireNextImage(image_info,image,exception);
    697             if (GetNextImageInList(image) == (Image *) NULL)
    698               {
    699                 image=DestroyImageList(image);
    700                 return((Image *) NULL);
    701               }
    702             image=SyncNextImageInList(image);
    703           }
    704         (void) SetImageProgressMonitor(image,progress_monitor,
    705           image->client_data);
    706         if (image->previous == (Image *) NULL)
    707           {
    708             status=SetImageProgress(image,LoadImageTag,j-1,number_images);
    709             if (status == MagickFalse)
    710               break;
    711           }
    712       }
    713       chroma2=(unsigned char *) RelinquishMagickMemory(chroma2);
    714       chroma1=(unsigned char *) RelinquishMagickMemory(chroma1);
    715       luma=(unsigned char *) RelinquishMagickMemory(luma);
    716       image=GetFirstImageInList(image);
    717       overview_image=OverviewImage(image_info,image,exception);
    718       return(overview_image);
    719     }
    720   /*
    721     Read interleaved image.
    722   */
    723   yy=luma;
    724   c1=chroma1;
    725   c2=chroma2;
    726   for (y=0; y < (ssize_t) height; y+=2)
    727   {
    728     count=ReadBlob(image,width,yy);
    729     yy+=image->columns;
    730     count=ReadBlob(image,width,yy);
    731     yy+=image->columns;
    732     count=ReadBlob(image,width >> 1,c1);
    733     c1+=image->columns;
    734     count=ReadBlob(image,width >> 1,c2);
    735     c2+=image->columns;
    736   }
    737   if (scene >= 4)
    738     {
    739       /*
    740         Recover luminance deltas for 1536x1024 image.
    741       */
    742       Upsample(768,512,image->columns,luma);
    743       Upsample(384,256,image->columns,chroma1);
    744       Upsample(384,256,image->columns,chroma2);
    745       image->rows=1024;
    746       for (i=0; i < (4*0x800); i++)
    747         (void) ReadBlobByte(image);
    748       status=DecodeImage(image,luma,chroma1,chroma2,exception);
    749       if ((scene >= 5) && status)
    750         {
    751           /*
    752             Recover luminance deltas for 3072x2048 image.
    753           */
    754           Upsample(1536,1024,image->columns,luma);
    755           Upsample(768,512,image->columns,chroma1);
    756           Upsample(768,512,image->columns,chroma2);
    757           image->rows=2048;
    758           offset=TellBlob(image)/0x800+12;
    759           offset=SeekBlob(image,offset*0x800,SEEK_SET);
    760           status=DecodeImage(image,luma,chroma1,chroma2,exception);
    761           if ((scene >= 6) && (status != MagickFalse))
    762             {
    763               /*
    764                 Recover luminance deltas for 6144x4096 image (vaporware).
    765               */
    766               Upsample(3072,2048,image->columns,luma);
    767               Upsample(1536,1024,image->columns,chroma1);
    768               Upsample(1536,1024,image->columns,chroma2);
    769               image->rows=4096;
    770             }
    771         }
    772     }
    773   Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
    774   Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
    775   /*
    776     Transfer luminance and chrominance channels.
    777   */
    778   yy=luma;
    779   c1=chroma1;
    780   c2=chroma2;
    781   for (y=0; y < (ssize_t) image->rows; y++)
    782   {
    783     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    784     if (q == (Quantum *) NULL)
    785       break;
    786     for (x=0; x < (ssize_t) image->columns; x++)
    787     {
    788       SetPixelRed(image,ScaleCharToQuantum(*yy++),q);
    789       SetPixelGreen(image,ScaleCharToQuantum(*c1++),q);
    790       SetPixelBlue(image,ScaleCharToQuantum(*c2++),q);
    791       q+=GetPixelChannels(image);
    792     }
    793     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    794       break;
    795     if (image->previous == (Image *) NULL)
    796       {
    797         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    798                 image->rows);
    799         if (status == MagickFalse)
    800           break;
    801       }
    802   }
    803   chroma2=(unsigned char *) RelinquishMagickMemory(chroma2);
    804   chroma1=(unsigned char *) RelinquishMagickMemory(chroma1);
    805   luma=(unsigned char *) RelinquishMagickMemory(luma);
    806   if (EOFBlob(image) != MagickFalse)
    807     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
    808       image->filename);
    809   (void) CloseBlob(image);
    810   if (image_info->ping == MagickFalse)
    811     if ((rotate == 1) || (rotate == 3))
    812       {
    813         double
    814           degrees;
    815 
    816         Image
    817           *rotate_image;
    818 
    819         /*
    820           Rotate image.
    821         */
    822         degrees=rotate == 1 ? -90.0 : 90.0;
    823         rotate_image=RotateImage(image,degrees,exception);
    824         if (rotate_image != (Image *) NULL)
    825           {
    826             image=DestroyImage(image);
    827             image=rotate_image;
    828           }
    829       }
    830   /*
    831     Set CCIR 709 primaries with a D65 white point.
    832   */
    833   image->chromaticity.red_primary.x=0.6400f;
    834   image->chromaticity.red_primary.y=0.3300f;
    835   image->chromaticity.green_primary.x=0.3000f;
    836   image->chromaticity.green_primary.y=0.6000f;
    837   image->chromaticity.blue_primary.x=0.1500f;
    838   image->chromaticity.blue_primary.y=0.0600f;
    839   image->chromaticity.white_point.x=0.3127f;
    840   image->chromaticity.white_point.y=0.3290f;
    841   image->gamma=1.000f/2.200f;
    842   image->colorspace=YCCColorspace;
    843   if (LocaleCompare(image_info->magick,"PCDS") == 0)
    844     SetImageColorspace(image,sRGBColorspace,exception);
    845   return(GetFirstImageInList(image));
    846 }
    847 
    848 /*
    850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    851 %                                                                             %
    852 %                                                                             %
    853 %                                                                             %
    854 %   R e g i s t e r P C D I m a g e                                           %
    855 %                                                                             %
    856 %                                                                             %
    857 %                                                                             %
    858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    859 %
    860 %  RegisterPCDImage() adds attributes for the PCD image format to
    861 %  the list of supported formats.  The attributes include the image format
    862 %  tag, a method to read and/or write the format, whether the format
    863 %  supports the saving of more than one frame to the same file or blob,
    864 %  whether the format supports native in-memory I/O, and a brief
    865 %  description of the format.
    866 %
    867 %  The format of the RegisterPCDImage method is:
    868 %
    869 %      size_t RegisterPCDImage(void)
    870 %
    871 */
    872 ModuleExport size_t RegisterPCDImage(void)
    873 {
    874   MagickInfo
    875     *entry;
    876 
    877   entry=AcquireMagickInfo("PCD","PCD","Photo CD");
    878   entry->decoder=(DecodeImageHandler *) ReadPCDImage;
    879   entry->encoder=(EncodeImageHandler *) WritePCDImage;
    880   entry->magick=(IsImageFormatHandler *) IsPCD;
    881   entry->flags^=CoderAdjoinFlag;
    882   entry->flags|=CoderSeekableStreamFlag;
    883   (void) RegisterMagickInfo(entry);
    884   entry=AcquireMagickInfo("PCD","PCDS","Photo CD");
    885   entry->decoder=(DecodeImageHandler *) ReadPCDImage;
    886   entry->encoder=(EncodeImageHandler *) WritePCDImage;
    887   entry->flags^=CoderAdjoinFlag;
    888   entry->flags|=CoderSeekableStreamFlag;
    889   (void) RegisterMagickInfo(entry);
    890   return(MagickImageCoderSignature);
    891 }
    892 
    893 /*
    895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    896 %                                                                             %
    897 %                                                                             %
    898 %                                                                             %
    899 %   U n r e g i s t e r P C D I m a g e                                       %
    900 %                                                                             %
    901 %                                                                             %
    902 %                                                                             %
    903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    904 %
    905 %  UnregisterPCDImage() removes format registrations made by the
    906 %  PCD module from the list of supported formats.
    907 %
    908 %  The format of the UnregisterPCDImage method is:
    909 %
    910 %      UnregisterPCDImage(void)
    911 %
    912 */
    913 ModuleExport void UnregisterPCDImage(void)
    914 {
    915   (void) UnregisterMagickInfo("PCD");
    916   (void) UnregisterMagickInfo("PCDS");
    917 }
    918 
    919 /*
    921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    922 %                                                                             %
    923 %                                                                             %
    924 %                                                                             %
    925 %   W r i t e P C D I m a g e                                                 %
    926 %                                                                             %
    927 %                                                                             %
    928 %                                                                             %
    929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    930 %
    931 %  WritePCDImage() writes an image in the Photo CD encoded image format.
    932 %
    933 %  The format of the WritePCDImage method is:
    934 %
    935 %      MagickBooleanType WritePCDImage(const ImageInfo *image_info,
    936 %        Image *image,ExceptionInfo *exception)
    937 %
    938 %  A description of each parameter follows.
    939 %
    940 %    o image_info: the image info.
    941 %
    942 %    o image:  The image.
    943 %
    944 %    o exception: return any errors or warnings in this structure.
    945 %
    946 */
    947 
    948 static MagickBooleanType WritePCDTile(Image *image,const char *page_geometry,
    949   const size_t tile_columns,const size_t tile_rows,ExceptionInfo *exception)
    950 {
    951   GeometryInfo
    952     geometry_info;
    953 
    954   Image
    955     *downsample_image,
    956     *tile_image;
    957 
    958   MagickBooleanType
    959     status;
    960 
    961   MagickStatusType
    962     flags;
    963 
    964   RectangleInfo
    965     geometry;
    966 
    967   register const Quantum
    968     *p,
    969     *q;
    970 
    971   register ssize_t
    972     i,
    973     x;
    974 
    975   ssize_t
    976     y;
    977 
    978   /*
    979     Scale image to tile size.
    980   */
    981   SetGeometry(image,&geometry);
    982   (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
    983     &geometry.width,&geometry.height);
    984   if ((geometry.width % 2) != 0)
    985     geometry.width--;
    986   if ((geometry.height % 2) != 0)
    987     geometry.height--;
    988   tile_image=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
    989     exception);
    990   if (tile_image == (Image *) NULL)
    991     return(MagickFalse);
    992   flags=ParseGeometry(page_geometry,&geometry_info);
    993   geometry.width=(size_t) geometry_info.rho;
    994   geometry.height=(size_t) geometry_info.sigma;
    995   if ((flags & SigmaValue) == 0)
    996     geometry.height=geometry.width;
    997   if ((tile_image->columns != geometry.width) ||
    998       (tile_image->rows != geometry.height))
    999     {
   1000       Image
   1001         *bordered_image;
   1002 
   1003       RectangleInfo
   1004         border_info;
   1005 
   1006       /*
   1007         Put a border around the image.
   1008       */
   1009       border_info.width=(geometry.width-tile_image->columns+1) >> 1;
   1010       border_info.height=(geometry.height-tile_image->rows+1) >> 1;
   1011       bordered_image=BorderImage(tile_image,&border_info,image->compose,
   1012         exception);
   1013       if (bordered_image == (Image *) NULL)
   1014         return(MagickFalse);
   1015       tile_image=DestroyImage(tile_image);
   1016       tile_image=bordered_image;
   1017     }
   1018   if ((tile_image->columns != tile_columns) || (tile_image->rows != tile_rows))
   1019     {
   1020       Image
   1021         *resize_image;
   1022 
   1023       resize_image=ResizeImage(tile_image,tile_columns,tile_rows,
   1024         tile_image->filter,exception);
   1025       if (resize_image != (Image *) NULL)
   1026         {
   1027           tile_image=DestroyImage(tile_image);
   1028           tile_image=resize_image;
   1029         }
   1030     }
   1031   (void) TransformImageColorspace(tile_image,YCCColorspace,exception);
   1032   downsample_image=ResizeImage(tile_image,tile_image->columns/2,
   1033     tile_image->rows/2,TriangleFilter,exception);
   1034   if (downsample_image == (Image *) NULL)
   1035     return(MagickFalse);
   1036   /*
   1037     Write tile to PCD file.
   1038   */
   1039   for (y=0; y < (ssize_t) tile_image->rows; y+=2)
   1040   {
   1041     p=GetVirtualPixels(tile_image,0,y,tile_image->columns,2,exception);
   1042     if (p == (const Quantum *) NULL)
   1043       break;
   1044     for (x=0; x < (ssize_t) (tile_image->columns << 1); x++)
   1045     {
   1046       (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(tile_image,p)));
   1047       p+=GetPixelChannels(tile_image);
   1048     }
   1049     q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1,
   1050       exception);
   1051     if (q == (Quantum *) NULL)
   1052       break;
   1053     for (x=0; x < (ssize_t) downsample_image->columns; x++)
   1054     {
   1055       (void) WriteBlobByte(image,ScaleQuantumToChar(
   1056         GetPixelGreen(tile_image,q)));
   1057       q++;
   1058     }
   1059     q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1,
   1060       exception);
   1061     if (q == (Quantum *) NULL)
   1062       break;
   1063     for (x=0; x < (ssize_t) downsample_image->columns; x++)
   1064     {
   1065       (void) WriteBlobByte(image,ScaleQuantumToChar(
   1066         GetPixelBlue(tile_image,q)));
   1067       q++;
   1068     }
   1069     status=SetImageProgress(image,SaveImageTag,y,tile_image->rows);
   1070     if (status == MagickFalse)
   1071       break;
   1072   }
   1073   for (i=0; i < 0x800; i++)
   1074     (void) WriteBlobByte(image,'\0');
   1075   downsample_image=DestroyImage(downsample_image);
   1076   tile_image=DestroyImage(tile_image);
   1077   return(MagickTrue);
   1078 }
   1079 
   1080 static MagickBooleanType WritePCDImage(const ImageInfo *image_info,Image *image,
   1081   ExceptionInfo *exception)
   1082 {
   1083   Image
   1084     *pcd_image;
   1085 
   1086   MagickBooleanType
   1087     status;
   1088 
   1089   register ssize_t
   1090     i;
   1091 
   1092   assert(image_info != (const ImageInfo *) NULL);
   1093   assert(image_info->signature == MagickCoreSignature);
   1094   assert(image != (Image *) NULL);
   1095   assert(image->signature == MagickCoreSignature);
   1096   if (image->debug != MagickFalse)
   1097     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1098   pcd_image=image;
   1099   if (image->columns < image->rows)
   1100     {
   1101       Image
   1102         *rotate_image;
   1103 
   1104       /*
   1105         Rotate portrait to landscape.
   1106       */
   1107       rotate_image=RotateImage(image,90.0,exception);
   1108       if (rotate_image == (Image *) NULL)
   1109         return(MagickFalse);
   1110       pcd_image=rotate_image;
   1111     }
   1112   /*
   1113     Open output image file.
   1114   */
   1115   status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,exception);
   1116   if (status == MagickFalse)
   1117     return(status);
   1118   if (IssRGBCompatibleColorspace(pcd_image->colorspace) == MagickFalse)
   1119     (void) TransformImageColorspace(pcd_image,sRGBColorspace,exception);
   1120   /*
   1121     Write PCD image header.
   1122   */
   1123   for (i=0; i < 32; i++)
   1124     (void) WriteBlobByte(pcd_image,0xff);
   1125   for (i=0; i < 4; i++)
   1126     (void) WriteBlobByte(pcd_image,0x0e);
   1127   for (i=0; i < 8; i++)
   1128     (void) WriteBlobByte(pcd_image,'\0');
   1129   for (i=0; i < 4; i++)
   1130     (void) WriteBlobByte(pcd_image,0x01);
   1131   for (i=0; i < 4; i++)
   1132     (void) WriteBlobByte(pcd_image,0x05);
   1133   for (i=0; i < 8; i++)
   1134     (void) WriteBlobByte(pcd_image,'\0');
   1135   for (i=0; i < 4; i++)
   1136     (void) WriteBlobByte(pcd_image,0x0A);
   1137   for (i=0; i < 36; i++)
   1138     (void) WriteBlobByte(pcd_image,'\0');
   1139   for (i=0; i < 4; i++)
   1140     (void) WriteBlobByte(pcd_image,0x01);
   1141   for (i=0; i < 1944; i++)
   1142     (void) WriteBlobByte(pcd_image,'\0');
   1143   (void) WriteBlob(pcd_image,7,(const unsigned char *) "PCD_IPI");
   1144   (void) WriteBlobByte(pcd_image,0x06);
   1145   for (i=0; i < 1530; i++)
   1146     (void) WriteBlobByte(pcd_image,'\0');
   1147   if (image->columns < image->rows)
   1148     (void) WriteBlobByte(pcd_image,'\1');
   1149   else
   1150     (void) WriteBlobByte(pcd_image,'\0');
   1151   for (i=0; i < (3*0x800-1539); i++)
   1152     (void) WriteBlobByte(pcd_image,'\0');
   1153   /*
   1154     Write PCD tiles.
   1155   */
   1156   status=WritePCDTile(pcd_image,"768x512>",192,128,exception);
   1157   status=WritePCDTile(pcd_image,"768x512>",384,256,exception);
   1158   status=WritePCDTile(pcd_image,"768x512>",768,512,exception);
   1159   (void) CloseBlob(pcd_image);
   1160   if (pcd_image != image)
   1161     pcd_image=DestroyImage(pcd_image);
   1162   return(status);
   1163 }
   1164