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