2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Photo CD Image Format %
20 % Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
77 static MagickBooleanType
78 WritePCDImage(const ImageInfo *,Image *,ExceptionInfo *);
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 % D e c o d e I m a g e %
89 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91 % DecodeImage recovers the Huffman encoded luminance and chrominance
94 % The format of the DecodeImage method is:
96 % MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
97 % unsigned char *chroma1,unsigned char *chroma2)
99 % A description of each parameter follows:
101 % o image: the address of a structure of type Image.
103 % o luma: the address of a character buffer that contains the
104 % luminance information.
106 % o chroma1: the address of a character buffer that contains the
107 % chrominance information.
109 % o chroma2: the address of a character buffer that contains the
110 % chrominance information.
113 static MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
114 unsigned char *chroma1,unsigned char *chroma2,ExceptionInfo *exception)
116 #define IsSync(sum) ((sum & 0xffffff00UL) == 0xfffffe00UL)
117 #define PCDGetBits(n) \
119 sum=(sum << n) & 0xffffffff; \
123 if (p >= (buffer+0x800)) \
125 count=ReadBlob(image,0x800,buffer); \
128 sum|=((unsigned int) (*p) << (24-bits)); \
134 typedef struct PCDTable
157 register unsigned char
177 Initialize Huffman tables.
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",
193 for (i=0; i < 3; i++)
195 pcd_table[i]=(PCDTable *) NULL;
198 for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
201 length=(sum & 0xff)+1;
202 pcd_table[i]=(PCDTable *) AcquireQuantumMemory(length,
203 sizeof(*pcd_table[i]));
204 if (pcd_table[i] == (PCDTable *) NULL)
206 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
207 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
211 for (j=0; j < (ssize_t) length; j++)
214 r->length=(unsigned int) (sum & 0xff)+1;
217 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
221 r->sequence=(unsigned int) (sum & 0xffff) << 16;
223 r->key=(unsigned char) (sum & 0xff);
224 r->mask=(~((1U << (32-r->length))-1));
227 pcd_length[i]=(size_t) length;
230 Search for Sync byte.
232 for (i=0; i < 1; i++)
234 for (i=0; i < 1; i++)
236 while ((sum & 0x00fff000UL) != 0x00fff000UL)
238 while (IsSync(sum) == 0)
241 Recover the Huffman encoded luminance and chrominance deltas.
250 if (IsSync(sum) != 0)
253 Determine plane and row number.
256 row=((sum >> 9) & 0x1fff);
257 if (row == image->rows)
266 q=luma+row*image->columns;
267 count=(ssize_t) image->columns;
272 q=chroma1+(row >> 1)*image->columns;
273 count=(ssize_t) (image->columns >> 1);
279 q=chroma2+(row >> 1)*image->columns;
280 count=(ssize_t) (image->columns >> 1);
286 ThrowBinaryException(CorruptImageError,"CorruptImage",
290 length=pcd_length[plane];
294 Decode luminance or chrominance deltas.
297 for (i=0; ((i < (ssize_t) length) && ((sum & r->mask) != r->sequence)); i++)
299 if ((row > image->rows) || (r == (PCDTable *) NULL))
301 (void) ThrowMagickException(exception,GetMagickModule(),
302 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
303 while ((sum & 0x00fff000) != 0x00fff000)
305 while (IsSync(sum) == 0)
310 quantum=(ssize_t) (*q)+r->key;
312 quantum=(ssize_t) (*q)+r->key-256;
313 *q=(unsigned char) ((quantum < 0) ? 0 : (quantum > 255) ? 255 : quantum);
315 PCDGetBits(r->length);
319 Relinquish resources.
321 for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
322 pcd_table[i]=(PCDTable *) RelinquishMagickMemory(pcd_table[i]);
323 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338 % IsPCD() returns MagickTrue if the image format type, identified by the
339 % magick string, is PCD.
341 % The format of the IsPCD method is:
343 % MagickBooleanType IsPCD(const unsigned char *magick,const size_t length)
345 % A description of each parameter follows:
347 % o magick: compare image format pattern against these bytes.
349 % o length: Specifies the length of the magick string.
352 static MagickBooleanType IsPCD(const unsigned char *magick,const size_t length)
356 if (LocaleNCompare((const char *) magick+2048,"PCD_",4) == 0)
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 % R e a d P C D I m a g e %
370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372 % ReadPCDImage() reads a Photo CD image file and returns it. It
373 % allocates the memory necessary for the new Image structure and returns a
374 % pointer to the new image. Much of the PCD decoder was derived from
375 % the program hpcdtoppm(1) by Hadmut Danisch.
377 % The format of the ReadPCDImage method is:
379 % image=ReadPCDImage(image_info)
381 % A description of each parameter follows:
383 % o image_info: the image info.
385 % o exception: return any errors or warnings in this structure.
388 static Image *OverviewImage(const ImageInfo *image_info,Image *image,
389 ExceptionInfo *exception)
401 Create the PCD Overview image.
403 for (p=image; p != (Image *) NULL; p=p->next)
405 (void) DeleteImageProperty(p,"label");
406 (void) SetImageProperty(p,"label",DefaultTileLabel,exception);
408 montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL);
409 (void) CopyMagickString(montage_info->filename,image_info->filename,
411 montage_image=MontageImageList(image_info,montage_info,image,exception);
412 montage_info=DestroyMontageInfo(montage_info);
413 if (montage_image == (Image *) NULL)
414 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
415 image=DestroyImage(image);
416 return(montage_image);
419 static void Upsample(const size_t width,const size_t height,
420 const size_t scaled_width,unsigned char *pixels)
426 register unsigned char
432 Create a new image that is a integral size greater than an existing one.
434 assert(pixels != (unsigned char *) NULL);
435 for (y=0; y < (ssize_t) height; y++)
437 p=pixels+(height-1-y)*scaled_width+(width-1);
438 q=pixels+((height-1-y) << 1)*scaled_width+((width-1) << 1);
441 for (x=1; x < (ssize_t) width; x++)
446 *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+1))+1) >> 1);
449 for (y=0; y < (ssize_t) (height-1); y++)
451 p=pixels+((size_t) y << 1)*scaled_width;
454 for (x=0; x < (ssize_t) (width-1); x++)
456 *q=(unsigned char) ((((size_t) *p)+((size_t) *r)+1) >> 1);
457 *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+2))+
458 ((size_t) *r)+((size_t) *(r+2))+2) >> 2);
463 *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1);
464 *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1);
466 p=pixels+(2*height-2)*scaled_width;
467 q=pixels+(2*height-1)*scaled_width;
468 (void) CopyMagickMemory(q,p,(size_t) (2*width));
471 static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception)
492 register unsigned char
520 assert(image_info != (const ImageInfo *) NULL);
521 assert(image_info->signature == MagickSignature);
522 if (image_info->debug != MagickFalse)
523 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
524 image_info->filename);
525 assert(exception != (ExceptionInfo *) NULL);
526 assert(exception->signature == MagickSignature);
527 image=AcquireImage(image_info,exception);
528 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
529 if (status == MagickFalse)
531 image=DestroyImageList(image);
532 return((Image *) NULL);
535 Determine if this a PCD file.
537 header=(unsigned char *) AcquireQuantumMemory(0x800,3UL*sizeof(*header));
538 if (header == (unsigned char *) NULL)
539 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
540 count=ReadBlob(image,3*0x800,header);
541 overview=LocaleNCompare((char *) header,"PCD_OPA",7) == 0;
542 if ((count != (3*0x800)) ||
543 ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && (overview ==0)))
544 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
545 rotate=header[0x0e02] & 0x03;
546 number_images=(header[10] << 8) | header[11];
547 if (number_images > 65535)
548 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
549 header=(unsigned char *) RelinquishMagickMemory(header);
551 Determine resolution by scene specification.
553 if ((image->columns == 0) || (image->rows == 0))
559 for (scene=1; scene < 6; scene++)
561 if ((width >= image->columns) && (height >= image->rows))
567 if (image_info->number_scenes != 0)
568 scene=(size_t) MagickMin(image_info->scene,6);
572 Initialize image structure.
576 for (i=1; i < (ssize_t) MagickMin(scene,3); i++)
581 image->columns=width;
584 for ( ; i < (ssize_t) scene; i++)
589 status=SetImageExtent(image,image->columns,image->rows,exception);
590 if (status == MagickFalse)
591 return(DestroyImageList(image));
593 Allocate luma and chroma memory.
595 number_pixels=(MagickSizeType) image->columns*image->rows;
596 if (number_pixels != (size_t) number_pixels)
597 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
598 chroma1=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
599 10*sizeof(*chroma1));
600 chroma2=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
601 10*sizeof(*chroma2));
602 luma=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
604 if ((chroma1 == (unsigned char *) NULL) ||
605 (chroma2 == (unsigned char *) NULL) || (luma == (unsigned char *) NULL))
606 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
608 Advance to image data.
619 for (i=0; i < (ssize_t) (offset*0x800); i++)
620 (void) ReadBlobByte(image);
626 MagickProgressMonitor
633 Read thumbnails from overview image.
635 for (j=1; j <= (ssize_t) number_images; j++)
637 progress_monitor=SetImageProgressMonitor(image,
638 (MagickProgressMonitor) NULL,image->client_data);
639 (void) FormatLocaleString(image->filename,MagickPathExtent,
640 "images/img%04ld.pcd",(long) j);
641 (void) FormatLocaleString(image->magick_filename,MagickPathExtent,
642 "images/img%04ld.pcd",(long) j);
643 image->scene=(size_t) j;
644 image->columns=width;
650 for (y=0; y < (ssize_t) height; y+=2)
652 count=ReadBlob(image,width,yy);
654 count=ReadBlob(image,width,yy);
656 count=ReadBlob(image,width >> 1,c1);
658 count=ReadBlob(image,width >> 1,c2);
661 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
662 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
664 Transfer luminance and chrominance channels.
669 for (y=0; y < (ssize_t) image->rows; y++)
671 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
672 if (q == (Quantum *) NULL)
674 for (x=0; x < (ssize_t) image->columns; x++)
676 SetPixelRed(image,ScaleCharToQuantum(*yy++),q);
677 SetPixelGreen(image,ScaleCharToQuantum(*c1++),q);
678 SetPixelBlue(image,ScaleCharToQuantum(*c2++),q);
679 q+=GetPixelChannels(image);
681 if (SyncAuthenticPixels(image,exception) == MagickFalse)
684 image->colorspace=YCCColorspace;
685 if (LocaleCompare(image_info->magick,"PCDS") == 0)
686 SetImageColorspace(image,sRGBColorspace,exception);
687 if (j < (ssize_t) number_images)
690 Allocate next image structure.
692 AcquireNextImage(image_info,image,exception);
693 if (GetNextImageInList(image) == (Image *) NULL)
695 image=DestroyImageList(image);
696 return((Image *) NULL);
698 image=SyncNextImageInList(image);
700 (void) SetImageProgressMonitor(image,progress_monitor,
702 if (image->previous == (Image *) NULL)
704 status=SetImageProgress(image,LoadImageTag,j-1,number_images);
705 if (status == MagickFalse)
709 chroma2=(unsigned char *) RelinquishMagickMemory(chroma2);
710 chroma1=(unsigned char *) RelinquishMagickMemory(chroma1);
711 luma=(unsigned char *) RelinquishMagickMemory(luma);
712 image=GetFirstImageInList(image);
713 overview_image=OverviewImage(image_info,image,exception);
714 return(overview_image);
717 Read interleaved image.
722 for (y=0; y < (ssize_t) height; y+=2)
724 count=ReadBlob(image,width,yy);
726 count=ReadBlob(image,width,yy);
728 count=ReadBlob(image,width >> 1,c1);
730 count=ReadBlob(image,width >> 1,c2);
736 Recover luminance deltas for 1536x1024 image.
738 Upsample(768,512,image->columns,luma);
739 Upsample(384,256,image->columns,chroma1);
740 Upsample(384,256,image->columns,chroma2);
742 for (i=0; i < (4*0x800); i++)
743 (void) ReadBlobByte(image);
744 status=DecodeImage(image,luma,chroma1,chroma2,exception);
745 if ((scene >= 5) && status)
748 Recover luminance deltas for 3072x2048 image.
750 Upsample(1536,1024,image->columns,luma);
751 Upsample(768,512,image->columns,chroma1);
752 Upsample(768,512,image->columns,chroma2);
754 offset=TellBlob(image)/0x800+12;
755 offset=SeekBlob(image,offset*0x800,SEEK_SET);
756 status=DecodeImage(image,luma,chroma1,chroma2,exception);
757 if ((scene >= 6) && (status != MagickFalse))
760 Recover luminance deltas for 6144x4096 image (vaporware).
762 Upsample(3072,2048,image->columns,luma);
763 Upsample(1536,1024,image->columns,chroma1);
764 Upsample(1536,1024,image->columns,chroma2);
769 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
770 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
772 Transfer luminance and chrominance channels.
777 for (y=0; y < (ssize_t) image->rows; y++)
779 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
780 if (q == (Quantum *) NULL)
782 for (x=0; x < (ssize_t) image->columns; x++)
784 SetPixelRed(image,ScaleCharToQuantum(*yy++),q);
785 SetPixelGreen(image,ScaleCharToQuantum(*c1++),q);
786 SetPixelBlue(image,ScaleCharToQuantum(*c2++),q);
787 q+=GetPixelChannels(image);
789 if (SyncAuthenticPixels(image,exception) == MagickFalse)
791 if (image->previous == (Image *) NULL)
793 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
795 if (status == MagickFalse)
799 chroma2=(unsigned char *) RelinquishMagickMemory(chroma2);
800 chroma1=(unsigned char *) RelinquishMagickMemory(chroma1);
801 luma=(unsigned char *) RelinquishMagickMemory(luma);
802 if (EOFBlob(image) != MagickFalse)
803 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
805 (void) CloseBlob(image);
806 if (image_info->ping == MagickFalse)
807 if ((rotate == 1) || (rotate == 3))
818 degrees=rotate == 1 ? -90.0 : 90.0;
819 rotate_image=RotateImage(image,degrees,exception);
820 if (rotate_image != (Image *) NULL)
822 image=DestroyImage(image);
827 Set CCIR 709 primaries with a D65 white point.
829 image->chromaticity.red_primary.x=0.6400f;
830 image->chromaticity.red_primary.y=0.3300f;
831 image->chromaticity.green_primary.x=0.3000f;
832 image->chromaticity.green_primary.y=0.6000f;
833 image->chromaticity.blue_primary.x=0.1500f;
834 image->chromaticity.blue_primary.y=0.0600f;
835 image->chromaticity.white_point.x=0.3127f;
836 image->chromaticity.white_point.y=0.3290f;
837 image->gamma=1.000f/2.200f;
838 image->colorspace=YCCColorspace;
839 if (LocaleCompare(image_info->magick,"PCDS") == 0)
840 SetImageColorspace(image,sRGBColorspace,exception);
841 return(GetFirstImageInList(image));
845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
849 % R e g i s t e r P C D I m a g e %
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855 % RegisterPCDImage() adds attributes for the PCD image format to
856 % the list of supported formats. The attributes include the image format
857 % tag, a method to read and/or write the format, whether the format
858 % supports the saving of more than one frame to the same file or blob,
859 % whether the format supports native in-memory I/O, and a brief
860 % description of the format.
862 % The format of the RegisterPCDImage method is:
864 % size_t RegisterPCDImage(void)
867 ModuleExport size_t RegisterPCDImage(void)
872 entry=AcquireMagickInfo("PCD","PCD","Photo CD");
873 entry->decoder=(DecodeImageHandler *) ReadPCDImage;
874 entry->encoder=(EncodeImageHandler *) WritePCDImage;
875 entry->magick=(IsImageFormatHandler *) IsPCD;
876 entry->flags^=CoderAdjoinFlag;
877 entry->flags|=CoderSeekableStreamFlag;
878 (void) RegisterMagickInfo(entry);
879 entry=AcquireMagickInfo("PCD","PCDS","Photo CD");
880 entry->decoder=(DecodeImageHandler *) ReadPCDImage;
881 entry->encoder=(EncodeImageHandler *) WritePCDImage;
882 entry->flags^=CoderAdjoinFlag;
883 entry->flags|=CoderSeekableStreamFlag;
884 (void) RegisterMagickInfo(entry);
885 return(MagickImageCoderSignature);
889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893 % U n r e g i s t e r P C D I m a g e %
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899 % UnregisterPCDImage() removes format registrations made by the
900 % PCD module from the list of supported formats.
902 % The format of the UnregisterPCDImage method is:
904 % UnregisterPCDImage(void)
907 ModuleExport void UnregisterPCDImage(void)
909 (void) UnregisterMagickInfo("PCD");
910 (void) UnregisterMagickInfo("PCDS");
914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918 % W r i t e P C D I m a g e %
922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 % WritePCDImage() writes an image in the Photo CD encoded image format.
926 % The format of the WritePCDImage method is:
928 % MagickBooleanType WritePCDImage(const ImageInfo *image_info,
929 % Image *image,ExceptionInfo *exception)
931 % A description of each parameter follows.
933 % o image_info: the image info.
935 % o image: The image.
937 % o exception: return any errors or warnings in this structure.
941 static MagickBooleanType WritePCDTile(Image *image,const char *page_geometry,
942 const char *tile_geometry,ExceptionInfo *exception)
960 register const Quantum
972 Scale image to tile size.
974 SetGeometry(image,&geometry);
975 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
976 &geometry.width,&geometry.height);
977 if ((geometry.width % 2) != 0)
979 if ((geometry.height % 2) != 0)
981 tile_image=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
983 if (tile_image == (Image *) NULL)
985 flags=ParseGeometry(page_geometry,&geometry_info);
986 geometry.width=(size_t) geometry_info.rho;
987 geometry.height=(size_t) geometry_info.sigma;
988 if ((flags & SigmaValue) == 0)
989 geometry.height=geometry.width;
990 if ((tile_image->columns != geometry.width) ||
991 (tile_image->rows != geometry.height))
1000 Put a border around the image.
1002 border_info.width=(geometry.width-tile_image->columns+1) >> 1;
1003 border_info.height=(geometry.height-tile_image->rows+1) >> 1;
1004 bordered_image=BorderImage(tile_image,&border_info,image->compose,
1006 if (bordered_image == (Image *) NULL)
1007 return(MagickFalse);
1008 tile_image=DestroyImage(tile_image);
1009 tile_image=bordered_image;
1011 (void) TransformImage(&tile_image,(char *) NULL,tile_geometry,exception);
1012 (void) TransformImageColorspace(tile_image,YCCColorspace,exception);
1013 downsample_image=ResizeImage(tile_image,tile_image->columns/2,
1014 tile_image->rows/2,TriangleFilter,exception);
1015 if (downsample_image == (Image *) NULL)
1016 return(MagickFalse);
1018 Write tile to PCD file.
1020 for (y=0; y < (ssize_t) tile_image->rows; y+=2)
1022 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,2,exception);
1023 if (p == (const Quantum *) NULL)
1025 for (x=0; x < (ssize_t) (tile_image->columns << 1); x++)
1027 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(tile_image,p)));
1028 p+=GetPixelChannels(tile_image);
1030 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1,
1032 if (q == (Quantum *) NULL)
1034 for (x=0; x < (ssize_t) downsample_image->columns; x++)
1036 (void) WriteBlobByte(image,ScaleQuantumToChar(
1037 GetPixelGreen(tile_image,q)));
1040 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1,
1042 if (q == (Quantum *) NULL)
1044 for (x=0; x < (ssize_t) downsample_image->columns; x++)
1046 (void) WriteBlobByte(image,ScaleQuantumToChar(
1047 GetPixelBlue(tile_image,q)));
1050 status=SetImageProgress(image,SaveImageTag,y,tile_image->rows);
1051 if (status == MagickFalse)
1054 for (i=0; i < 0x800; i++)
1055 (void) WriteBlobByte(image,'\0');
1056 downsample_image=DestroyImage(downsample_image);
1057 tile_image=DestroyImage(tile_image);
1061 static MagickBooleanType WritePCDImage(const ImageInfo *image_info,Image *image,
1062 ExceptionInfo *exception)
1073 assert(image_info != (const ImageInfo *) NULL);
1074 assert(image_info->signature == MagickSignature);
1075 assert(image != (Image *) NULL);
1076 assert(image->signature == MagickSignature);
1077 if (image->debug != MagickFalse)
1078 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1080 if (image->columns < image->rows)
1086 Rotate portrait to landscape.
1088 rotate_image=RotateImage(image,90.0,exception);
1089 if (rotate_image == (Image *) NULL)
1090 return(MagickFalse);
1091 pcd_image=rotate_image;
1094 Open output image file.
1096 status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,exception);
1097 if (status == MagickFalse)
1099 if (IssRGBCompatibleColorspace(pcd_image->colorspace) == MagickFalse)
1100 (void) TransformImageColorspace(pcd_image,sRGBColorspace,exception);
1102 Write PCD image header.
1104 for (i=0; i < 32; i++)
1105 (void) WriteBlobByte(pcd_image,0xff);
1106 for (i=0; i < 4; i++)
1107 (void) WriteBlobByte(pcd_image,0x0e);
1108 for (i=0; i < 8; i++)
1109 (void) WriteBlobByte(pcd_image,'\0');
1110 for (i=0; i < 4; i++)
1111 (void) WriteBlobByte(pcd_image,0x01);
1112 for (i=0; i < 4; i++)
1113 (void) WriteBlobByte(pcd_image,0x05);
1114 for (i=0; i < 8; i++)
1115 (void) WriteBlobByte(pcd_image,'\0');
1116 for (i=0; i < 4; i++)
1117 (void) WriteBlobByte(pcd_image,0x0A);
1118 for (i=0; i < 36; i++)
1119 (void) WriteBlobByte(pcd_image,'\0');
1120 for (i=0; i < 4; i++)
1121 (void) WriteBlobByte(pcd_image,0x01);
1122 for (i=0; i < 1944; i++)
1123 (void) WriteBlobByte(pcd_image,'\0');
1124 (void) WriteBlob(pcd_image,7,(const unsigned char *) "PCD_IPI");
1125 (void) WriteBlobByte(pcd_image,0x06);
1126 for (i=0; i < 1530; i++)
1127 (void) WriteBlobByte(pcd_image,'\0');
1128 if (image->columns < image->rows)
1129 (void) WriteBlobByte(pcd_image,'\1');
1131 (void) WriteBlobByte(pcd_image,'\0');
1132 for (i=0; i < (3*0x800-1539); i++)
1133 (void) WriteBlobByte(pcd_image,'\0');
1137 status=WritePCDTile(pcd_image,"768x512>","192x128",exception);
1138 status=WritePCDTile(pcd_image,"768x512>","384x256",exception);
1139 status=WritePCDTile(pcd_image,"768x512>","768x512",exception);
1140 (void) CloseBlob(pcd_image);
1141 if (pcd_image != image)
1142 pcd_image=DestroyImage(pcd_image);