2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Photo CD Image Format %
20 % Copyright 1999-2009 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 "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"
75 static MagickBooleanType
76 WritePCDImage(const ImageInfo *,Image *);
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 % D e c o d e I m a g e %
87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 % DecodeImage recovers the Huffman encoded luminance and chrominance
92 % The format of the DecodeImage method is:
94 % MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
95 % unsigned char *chroma1,unsigned char *chroma2)
97 % A description of each parameter follows:
99 % o image: the address of a structure of type Image.
101 % o luma: the address of a character buffer that contains the
102 % luminance information.
104 % o chroma1: the address of a character buffer that contains the
105 % chrominance information.
107 % o chroma2: the address of a character buffer that contains the
108 % chrominance information.
111 static MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
112 unsigned char *chroma1,unsigned char *chroma2)
114 #define IsSync ((sum & 0xffffff00UL) == 0xfffffe00UL)
115 #define PCDGetBits(n) \
117 sum=(sum << n) & 0xffffffff; \
121 if (p >= (buffer+0x800)) \
123 count=ReadBlob(image,0x800,buffer); \
126 sum|=((unsigned int) (*p) << (24-bits)); \
130 if (EOFBlob(image) != MagickFalse) \
134 typedef struct PCDTable
160 register unsigned char
181 Initialize Huffman tables.
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",
197 for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
200 length=(sum & 0xff)+1;
201 pcd_table[i]=(PCDTable *) AcquireQuantumMemory(length,
202 sizeof(*pcd_table[i]));
203 if (pcd_table[i] == (PCDTable *) NULL)
205 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
206 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
210 for (j=0; j < (long) length; j++)
213 r->length=(unsigned int) (sum & 0xff)+1;
216 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
220 r->sequence=(unsigned int) (sum & 0xffff) << 16;
222 r->key=(unsigned char) (sum & 0xff);
223 r->mask=(~((1U << (32-r->length))-1));
226 pcd_length[i]=(unsigned long) length;
229 Search for Sync byte.
231 for (i=0; i < 1; i++)
233 for (i=0; i < 1; i++)
235 while ((sum & 0x00fff000UL) != 0x00fff000UL)
240 Recover the Huffman encoded luminance and chrominance deltas.
252 Determine plane and row number.
255 row=((sum >> 9) & 0x1fff);
256 if (row == image->rows)
265 q=luma+row*image->columns;
266 count=(ssize_t) image->columns;
271 q=chroma1+(row >> 1)*image->columns;
272 count=(ssize_t) (image->columns >> 1);
278 q=chroma2+(row >> 1)*image->columns;
279 count=(ssize_t) (image->columns >> 1);
285 ThrowBinaryException(CorruptImageError,"CorruptImage",
289 length=pcd_length[plane];
293 Decode luminance or chrominance deltas.
296 for (i=0; ((i < (long) length) && ((sum & r->mask) != r->sequence)); i++)
298 if ((row > image->rows) || (r == (PCDTable *) NULL) ||
299 ((size_t) (q-luma) > (image->columns*image->rows)))
301 (void) ThrowMagickException(&image->exception,GetMagickModule(),
302 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
303 while ((sum & 0x00fff000) != 0x00fff000)
310 quantum=(long) (*q)+r->key;
312 quantum=(long) (*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.
389 static inline size_t MagickMin(const size_t x,const size_t y)
396 static Image *OverviewImage(const ImageInfo *image_info,Image *image,
397 ExceptionInfo *exception)
409 Create the PCD Overview image.
411 for (p=image; p != (Image *) NULL; p=p->next)
413 (void) DeleteImageProperty(p,"label");
414 (void) SetImageProperty(p,"label",DefaultTileLabel);
416 montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL);
417 (void) CopyMagickString(montage_info->filename,image_info->filename,
419 montage_image=MontageImageList(image_info,montage_info,image,exception);
420 montage_info=DestroyMontageInfo(montage_info);
421 if (montage_image == (Image *) NULL)
422 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
423 image=DestroyImage(image);
424 return(montage_image);
427 static void Upsample(const unsigned long width,const unsigned long height,
428 const unsigned long scaled_width,unsigned char *pixels)
434 register unsigned char
440 Create a new image that is a integral size greater than an existing one.
442 assert(pixels != (unsigned char *) NULL);
443 for (y=0; y < (long) height; y++)
445 p=pixels+(height-1-y)*scaled_width+(width-1);
446 q=pixels+((height-1-y) << 1)*scaled_width+((width-1) << 1);
449 for (x=1; x < (long) width; x++)
454 *(q+1)=(unsigned char) ((((unsigned long) *p)+
455 ((unsigned long) *(p+1))+1) >> 1);
458 for (y=0; y < (long) (height-1); y++)
460 p=pixels+((unsigned long) y << 1)*scaled_width;
463 for (x=0; x < (long) (width-1); x++)
465 *q=(unsigned char) ((((unsigned long) *p)+((unsigned long) *r)+1) >> 1);
466 *(q+1)=(unsigned char) ((((unsigned long) *p)+((unsigned long) *(p+2))+
467 ((unsigned long) *r)+((unsigned long) *(r+2))+2) >> 2);
472 *q++=(unsigned char) ((((unsigned long) *p++)+
473 ((unsigned long) *r++)+1) >> 1);
474 *q++=(unsigned char) ((((unsigned long) *p++)+
475 ((unsigned long) *r++)+1) >> 1);
477 p=pixels+(2*height-2)*scaled_width;
478 q=pixels+(2*height-1)*scaled_width;
479 (void) CopyMagickMemory(q,p,(size_t) (2*width));
482 static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception)
506 register unsigned char
533 assert(image_info != (const ImageInfo *) NULL);
534 assert(image_info->signature == MagickSignature);
535 if (image_info->debug != MagickFalse)
536 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
537 image_info->filename);
538 assert(exception != (ExceptionInfo *) NULL);
539 assert(exception->signature == MagickSignature);
540 image=AcquireImage(image_info);
541 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
542 if (status == MagickFalse)
544 image=DestroyImageList(image);
545 return((Image *) NULL);
548 Determine if this a PCD file.
550 header=(unsigned char *) AcquireQuantumMemory(0x800,3UL*sizeof(*header));
551 if (header == (unsigned char *) NULL)
552 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
553 count=ReadBlob(image,3*0x800,header);
554 overview=LocaleNCompare((char *) header,"PCD_OPA",7) == 0;
556 ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && !overview))
557 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
558 rotate=header[0x0e02] & 0x03;
559 number_images=(header[10] << 8) | header[11];
560 header=(unsigned char *) RelinquishMagickMemory(header);
562 Determine resolution by scene specification.
564 if ((image->columns == 0) || (image->rows == 0))
570 for (scene=1; scene < 6; scene++)
572 if ((width >= image->columns) && (height >= image->rows))
578 if (image_info->number_scenes != 0)
579 scene=(unsigned long) MagickMin(image_info->scene,6);
583 Initialize image structure.
587 for (i=1; i < (long) MagickMin(scene,3); i++)
592 image->columns=width;
595 for ( ; i < (long) scene; i++)
601 Allocate lumand chroma memory.
603 number_pixels=(MagickSizeType) image->columns*image->rows;
604 if (number_pixels != (size_t) number_pixels)
605 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
606 chroma1=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
608 chroma2=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
610 luma=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
612 if ((chroma1 == (unsigned char *) NULL) ||
613 (chroma2 == (unsigned char *) NULL) || (luma == (unsigned char *) NULL))
614 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
616 Advance to image data.
627 for (i=0; i < (long) (offset*0x800); i++)
628 (void) ReadBlobByte(image);
634 MagickProgressMonitor
641 Read thumbnails from overview image.
643 for (j=1; j <= (long) number_images; j++)
645 progress_monitor=SetImageProgressMonitor(image,
646 (MagickProgressMonitor) NULL,image->client_data);
647 (void) FormatMagickString(image->filename,MaxTextExtent,
648 "images/img%04ld.pcd",j);
649 (void) FormatMagickString(image->magick_filename,MaxTextExtent,
650 "images/img%04ld.pcd",j);
651 image->scene=(unsigned long) j;
652 image->columns=width;
658 for (y=0; y < (long) height; y+=2)
660 count=ReadBlob(image,width,yy);
662 count=ReadBlob(image,width,yy);
664 count=ReadBlob(image,width >> 1,c1);
666 count=ReadBlob(image,width >> 1,c2);
669 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
670 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
672 Transfer luminance and chrominance channels.
677 for (y=0; y < (long) image->rows; y++)
679 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
680 if (q == (PixelPacket *) NULL)
682 for (x=0; x < (long) image->columns; x++)
684 q->red=ScaleCharToQuantum(*yy++);
685 q->green=ScaleCharToQuantum(*c1++);
686 q->blue=ScaleCharToQuantum(*c2++);
689 if (SyncAuthenticPixels(image,exception) == MagickFalse)
692 image->colorspace=YCCColorspace;
693 if (LocaleCompare(image_info->magick,"PCDS") == 0)
694 image->colorspace=sRGBColorspace;
695 if (j < (long) number_images)
698 Allocate next image structure.
700 AcquireNextImage(image_info,image);
701 if (GetNextImageInList(image) == (Image *) NULL)
703 image=DestroyImageList(image);
704 return((Image *) NULL);
706 image=SyncNextImageInList(image);
708 (void) SetImageProgressMonitor(image,progress_monitor,
710 if (image->previous == (Image *) NULL)
712 status=SetImageProgress(image,LoadImageTag,j-1,number_images);
713 if (status == MagickFalse)
717 chroma2=(unsigned char *) RelinquishMagickMemory(chroma2);
718 chroma1=(unsigned char *) RelinquishMagickMemory(chroma1);
719 luma=(unsigned char *) RelinquishMagickMemory(luma);
720 image=GetFirstImageInList(image);
721 overview_image=OverviewImage(image_info,image,exception);
722 return(overview_image);
725 Read interleaved image.
730 for (y=0; y < (long) height; y+=2)
732 count=ReadBlob(image,width,yy);
734 count=ReadBlob(image,width,yy);
736 count=ReadBlob(image,width >> 1,c1);
738 count=ReadBlob(image,width >> 1,c2);
744 Recover luminance deltas for 1536x1024 image.
746 Upsample(768,512,image->columns,luma);
747 Upsample(384,256,image->columns,chroma1);
748 Upsample(384,256,image->columns,chroma2);
750 for (i=0; i < (4*0x800); i++)
751 (void) ReadBlobByte(image);
752 status=DecodeImage(image,luma,chroma1,chroma2);
753 if ((scene >= 5) && status)
756 Recover luminance deltas for 3072x2048 image.
758 Upsample(1536,1024,image->columns,luma);
759 Upsample(768,512,image->columns,chroma1);
760 Upsample(768,512,image->columns,chroma2);
762 offset=TellBlob(image)/0x800+12;
763 offset=SeekBlob(image,offset*0x800,SEEK_SET);
764 status=DecodeImage(image,luma,chroma1,chroma2);
765 if ((scene >= 6) && (status != MagickFalse))
768 Recover luminance deltas for 6144x4096 image (vaporware).
770 Upsample(3072,2048,image->columns,luma);
771 Upsample(1536,1024,image->columns,chroma1);
772 Upsample(1536,1024,image->columns,chroma2);
777 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
778 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
780 Transfer luminance and chrominance channels.
785 for (y=0; y < (long) image->rows; y++)
787 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
788 if (q == (PixelPacket *) NULL)
790 for (x=0; x < (long) image->columns; x++)
792 q->red=ScaleCharToQuantum(*yy++);
793 q->green=ScaleCharToQuantum(*c1++);
794 q->blue=ScaleCharToQuantum(*c2++);
797 if (SyncAuthenticPixels(image,exception) == MagickFalse)
799 if (image->previous == (Image *) NULL)
801 status=SetImageProgress(image,LoadImageTag,y,image->rows);
802 if (status == MagickFalse)
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",
812 (void) CloseBlob(image);
813 if (image_info->ping == MagickFalse)
814 if ((rotate == 1) || (rotate == 3))
825 degrees=rotate == 1 ? -90.0 : 90.0;
826 rotate_image=RotateImage(image,degrees,exception);
827 if (rotate_image != (Image *) NULL)
829 image=DestroyImage(image);
834 Set CCIR 709 primaries with a D65 white point.
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));
852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 % R e g i s t e r P C D I m a g e %
860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
869 % The format of the RegisterPCDImage method is:
871 % unsigned long RegisterPCDImage(void)
874 ModuleExport unsigned long RegisterPCDImage(void)
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);
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 % U n r e g i s t e r P C D I m a g e %
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 % UnregisterPCDImage() removes format registrations made by the
909 % PCD module from the list of supported formats.
911 % The format of the UnregisterPCDImage method is:
913 % UnregisterPCDImage(void)
916 ModuleExport void UnregisterPCDImage(void)
918 (void) UnregisterMagickInfo("PCD");
919 (void) UnregisterMagickInfo("PCDS");
923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927 % W r i t e P C D I m a g e %
931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933 % WritePCDImage() writes an image in the Photo CD encoded image format.
935 % The format of the WritePCDImage method is:
937 % MagickBooleanType WritePCDImage(const ImageInfo *image_info,Image *image)
939 % A description of each parameter follows.
941 % o image_info: the image info.
943 % o image: The image.
947 static MagickBooleanType WritePCDTile(Image *image,const char *page_geometry,
948 const char *tile_geometry)
969 register const PixelPacket
978 Scale image to tile size.
980 SetGeometry(image,&geometry);
981 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y,
982 &geometry.width,&geometry.height);
983 if ((geometry.width % 2) != 0)
985 if ((geometry.height % 2) != 0)
987 tile_image=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
988 1.0,&image->exception);
989 if (tile_image == (Image *) NULL)
991 flags=ParseGeometry(page_geometry,&geometry_info);
992 geometry.width=(unsigned long) geometry_info.rho;
993 geometry.height=(unsigned long) 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))
1006 Put a border around the image.
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;
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);
1024 Write tile to PCD file.
1026 for (y=0; y < (long) tile_image->rows; y+=2)
1028 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,2,
1029 &tile_image->exception);
1030 if (p == (const PixelPacket *) NULL)
1032 for (x=0; x < (long) (tile_image->columns << 1); x++)
1034 (void) WriteBlobByte(image,ScaleQuantumToChar(p->red));
1037 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,
1038 1,&downsample_image->exception);
1039 if (q == (const PixelPacket *) NULL)
1041 for (x=0; x < (long) downsample_image->columns; x++)
1043 (void) WriteBlobByte(image,ScaleQuantumToChar(q->green));
1046 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,
1047 1,&downsample_image->exception);
1048 if (q == (const PixelPacket *) NULL)
1050 for (x=0; x < (long) downsample_image->columns; x++)
1052 (void) WriteBlobByte(image,ScaleQuantumToChar(q->blue));
1055 status=SetImageProgress(image,SaveImageTag,y,tile_image->rows);
1056 if (status == MagickFalse)
1059 for (i=0; i < 0x800; i++)
1060 (void) WriteBlobByte(image,'\0');
1061 downsample_image=DestroyImage(downsample_image);
1062 tile_image=DestroyImage(tile_image);
1066 static MagickBooleanType WritePCDImage(const ImageInfo *image_info,Image *image)
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);
1084 if (image->columns < image->rows)
1090 Rotate portrait to landscape.
1092 rotate_image=RotateImage(image,90.0,&image->exception);
1093 if (rotate_image == (Image *) NULL)
1094 return(MagickFalse);
1095 pcd_image=rotate_image;
1098 Open output image file.
1100 status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,&image->exception);
1101 if (status == MagickFalse)
1103 if (image->colorspace != RGBColorspace)
1104 (void) TransformImageColorspace(pcd_image,RGBColorspace);
1106 Write PCD image header.
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');
1135 (void) WriteBlobByte(pcd_image,'\0');
1136 for (i=0; i < (3*0x800-1539); i++)
1137 (void) WriteBlobByte(pcd_image,'\0');
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);