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