blob: 2ebdb902e953d192392cd85495349e3448c17b39 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy510d06a2011-07-06 23:43:54 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/constitute.h"
51#include "MagickCore/decorate.h"
cristyc53413d2011-11-17 13:04:26 +000052#include "MagickCore/distort.h"
cristy4c08aed2011-07-01 19:47:50 +000053#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"
cristy4c08aed2011-07-01 19:47:50 +000067#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"
cristy3ed852e2009-09-05 21:47:34 +000073
74/*
75 Forward declarations.
76*/
77static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000078 WritePCDImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000079
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*/
113static MagickBooleanType DecodeImage(Image *image,unsigned char *luma,
cristy018f07f2011-09-04 21:15:19 +0000114 unsigned char *chroma1,unsigned char *chroma2,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000115{
cristyc31f22e2011-10-29 01:06:32 +0000116#define IsSync(sum) ((sum & 0xffffff00UL) == 0xfffffe00UL)
cristy3ed852e2009-09-05 21:47:34 +0000117#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 } \
cristy3ed852e2009-09-05 21:47:34 +0000132}
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
cristy3ed852e2009-09-05 21:47:34 +0000147 PCDTable
148 *pcd_table[3];
149
cristybb503372010-05-27 20:51:26 +0000150 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000151 i,
152 j;
153
154 register PCDTable
155 *r;
156
157 register unsigned char
158 *p,
159 *q;
160
161 size_t
cristy3ed852e2009-09-05 21:47:34 +0000162 bits,
cristyaff6d802011-04-26 01:46:31 +0000163 length,
cristy3ed852e2009-09-05 21:47:34 +0000164 plane,
165 pcd_length[3],
166 row,
167 sum;
168
cristyaff6d802011-04-26 01:46:31 +0000169 ssize_t
170 count,
171 quantum;
172
173 unsigned char
174 *buffer;
175
cristy3ed852e2009-09-05 21:47:34 +0000176 /*
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];
cristybb503372010-05-27 20:51:26 +0000206 for (j=0; j < (ssize_t) length; j++)
cristy3ed852e2009-09-05 21:47:34 +0000207 {
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 }
cristybb503372010-05-27 20:51:26 +0000222 pcd_length[i]=(size_t) length;
cristy3ed852e2009-09-05 21:47:34 +0000223 }
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);
cristyc31f22e2011-10-29 01:06:32 +0000233 while (IsSync(sum) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000234 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 {
cristyc31f22e2011-10-29 01:06:32 +0000245 if (IsSync(sum) != 0)
cristy3ed852e2009-09-05 21:47:34 +0000246 {
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];
cristybb503372010-05-27 20:51:26 +0000292 for (i=0; ((i < (ssize_t) length) && ((sum & r->mask) != r->sequence)); i++)
cristy3ed852e2009-09-05 21:47:34 +0000293 r++;
cristy5d418802009-11-27 19:06:12 +0000294 if ((row > image->rows) || (r == (PCDTable *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000295 {
cristyc82a27b2011-10-21 01:07:16 +0000296 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +0000297 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
298 while ((sum & 0x00fff000) != 0x00fff000)
299 PCDGetBits(8);
cristyc31f22e2011-10-29 01:06:32 +0000300 while (IsSync(sum) == 0)
cristy3ed852e2009-09-05 21:47:34 +0000301 PCDGetBits(1);
302 continue;
303 }
304 if (r->key < 128)
cristybb503372010-05-27 20:51:26 +0000305 quantum=(ssize_t) (*q)+r->key;
cristy3ed852e2009-09-05 21:47:34 +0000306 else
cristybb503372010-05-27 20:51:26 +0000307 quantum=(ssize_t) (*q)+r->key-256;
cristy3ed852e2009-09-05 21:47:34 +0000308 *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
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*/
347static 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
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
384static 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
391static 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");
cristyd15e6592011-10-15 00:13:06 +0000409 (void) SetImageProperty(p,"label",DefaultTileLabel,exception);
cristy3ed852e2009-09-05 21:47:34 +0000410 }
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
cristybb503372010-05-27 20:51:26 +0000422static void Upsample(const size_t width,const size_t height,
423 const size_t scaled_width,unsigned char *pixels)
cristy3ed852e2009-09-05 21:47:34 +0000424{
cristybb503372010-05-27 20:51:26 +0000425 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000426 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);
cristybb503372010-05-27 20:51:26 +0000438 for (y=0; y < (ssize_t) height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000439 {
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));
cristybb503372010-05-27 20:51:26 +0000444 for (x=1; x < (ssize_t) width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000445 {
446 p--;
447 q-=2;
448 *q=(*p);
cristyaff6d802011-04-26 01:46:31 +0000449 *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+1))+1) >> 1);
cristy3ed852e2009-09-05 21:47:34 +0000450 }
451 }
cristybb503372010-05-27 20:51:26 +0000452 for (y=0; y < (ssize_t) (height-1); y++)
cristy3ed852e2009-09-05 21:47:34 +0000453 {
cristybb503372010-05-27 20:51:26 +0000454 p=pixels+((size_t) y << 1)*scaled_width;
cristy3ed852e2009-09-05 21:47:34 +0000455 q=p+scaled_width;
456 r=q+scaled_width;
cristybb503372010-05-27 20:51:26 +0000457 for (x=0; x < (ssize_t) (width-1); x++)
cristy3ed852e2009-09-05 21:47:34 +0000458 {
cristybb503372010-05-27 20:51:26 +0000459 *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);
cristy3ed852e2009-09-05 21:47:34 +0000462 q+=2;
463 p+=2;
464 r+=2;
465 }
cristyaff6d802011-04-26 01:46:31 +0000466 *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1);
467 *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1);
cristy3ed852e2009-09-05 21:47:34 +0000468 }
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
474static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception)
475{
476 Image
477 *image;
478
cristy3ed852e2009-09-05 21:47:34 +0000479 MagickBooleanType
480 status;
481
482 MagickOffsetType
483 offset;
484
485 MagickSizeType
486 number_pixels;
487
cristybb503372010-05-27 20:51:26 +0000488 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000489 i,
490 y;
491
cristy4c08aed2011-07-01 19:47:50 +0000492 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000493 *q;
494
495 register unsigned char
496 *c1,
497 *c2,
498 *yy;
499
cristyaff6d802011-04-26 01:46:31 +0000500 size_t
501 height,
502 number_images,
503 rotate,
504 scene,
505 width;
506
cristy3ed852e2009-09-05 21:47:34 +0000507 ssize_t
cristyaff6d802011-04-26 01:46:31 +0000508 count,
509 x;
cristy3ed852e2009-09-05 21:47:34 +0000510
511 unsigned char
512 *chroma1,
513 *chroma2,
514 *header,
515 *luma;
516
517 unsigned int
518 overview;
519
cristy3ed852e2009-09-05 21:47:34 +0000520 /*
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);
cristy9950d572011-10-01 18:22:35 +0000530 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000531 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) ||
cristyc31f22e2011-10-29 01:06:32 +0000546 ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && (overview ==0)))
cristy3ed852e2009-09-05 21:47:34 +0000547 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)
cristybb503372010-05-27 20:51:26 +0000569 scene=(size_t) MagickMin(image_info->scene,6);
cristyc31f22e2011-10-29 01:06:32 +0000570 if (overview != 0)
cristy3ed852e2009-09-05 21:47:34 +0000571 scene=1;
572 /*
573 Initialize image structure.
574 */
575 width=192;
576 height=128;
cristybb503372010-05-27 20:51:26 +0000577 for (i=1; i < (ssize_t) MagickMin(scene,3); i++)
cristy3ed852e2009-09-05 21:47:34 +0000578 {
579 width<<=1;
580 height<<=1;
581 }
582 image->columns=width;
583 image->rows=height;
584 image->depth=8;
cristybb503372010-05-27 20:51:26 +0000585 for ( ; i < (ssize_t) scene; i++)
cristy3ed852e2009-09-05 21:47:34 +0000586 {
587 image->columns<<=1;
588 image->rows<<=1;
589 }
590 /*
cristy5d418802009-11-27 19:06:12 +0000591 Allocate luma and chroma memory.
cristy3ed852e2009-09-05 21:47:34 +0000592 */
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*
cristyc31f22e2011-10-29 01:06:32 +0000597 10*sizeof(*chroma1));
cristy3ed852e2009-09-05 21:47:34 +0000598 chroma2=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
cristyc31f22e2011-10-29 01:06:32 +0000599 10*sizeof(*chroma2));
cristy3ed852e2009-09-05 21:47:34 +0000600 luma=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows*
cristyc31f22e2011-10-29 01:06:32 +0000601 10*sizeof(*luma));
cristy3ed852e2009-09-05 21:47:34 +0000602 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;
cristyc31f22e2011-10-29 01:06:32 +0000609 if (overview != 0)
cristy3ed852e2009-09-05 21:47:34 +0000610 offset=2;
611 else
612 if (scene == 2)
613 offset=20;
614 else
615 if (scene <= 1)
616 offset=1;
cristybb503372010-05-27 20:51:26 +0000617 for (i=0; i < (ssize_t) (offset*0x800); i++)
cristy3ed852e2009-09-05 21:47:34 +0000618 (void) ReadBlobByte(image);
cristyc31f22e2011-10-29 01:06:32 +0000619 if (overview != 0)
cristy3ed852e2009-09-05 21:47:34 +0000620 {
621 Image
622 *overview_image;
623
624 MagickProgressMonitor
625 progress_monitor;
626
cristybb503372010-05-27 20:51:26 +0000627 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000628 j;
629
630 /*
631 Read thumbnails from overview image.
632 */
cristybb503372010-05-27 20:51:26 +0000633 for (j=1; j <= (ssize_t) number_images; j++)
cristy3ed852e2009-09-05 21:47:34 +0000634 {
635 progress_monitor=SetImageProgressMonitor(image,
636 (MagickProgressMonitor) NULL,image->client_data);
cristyb51dff52011-05-19 16:55:47 +0000637 (void) FormatLocaleString(image->filename,MaxTextExtent,
cristyf2faecf2010-05-28 19:19:36 +0000638 "images/img%04ld.pcd",(long) j);
cristyb51dff52011-05-19 16:55:47 +0000639 (void) FormatLocaleString(image->magick_filename,MaxTextExtent,
cristyf2faecf2010-05-28 19:19:36 +0000640 "images/img%04ld.pcd",(long) j);
cristybb503372010-05-27 20:51:26 +0000641 image->scene=(size_t) j;
cristy3ed852e2009-09-05 21:47:34 +0000642 image->columns=width;
643 image->rows=height;
644 image->depth=8;
645 yy=luma;
646 c1=chroma1;
647 c2=chroma2;
cristybb503372010-05-27 20:51:26 +0000648 for (y=0; y < (ssize_t) height; y+=2)
cristy3ed852e2009-09-05 21:47:34 +0000649 {
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;
cristybb503372010-05-27 20:51:26 +0000667 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000668 {
669 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000670 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000671 break;
cristybb503372010-05-27 20:51:26 +0000672 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000673 {
cristy4c08aed2011-07-01 19:47:50 +0000674 SetPixelRed(image,ScaleCharToQuantum(*yy++),q);
675 SetPixelGreen(image,ScaleCharToQuantum(*c1++),q);
676 SetPixelBlue(image,ScaleCharToQuantum(*c2++),q);
cristyed231572011-07-14 02:18:59 +0000677 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000678 }
679 if (SyncAuthenticPixels(image,exception) == MagickFalse)
680 break;
681 }
682 image->colorspace=YCCColorspace;
683 if (LocaleCompare(image_info->magick,"PCDS") == 0)
684 image->colorspace=sRGBColorspace;
cristybb503372010-05-27 20:51:26 +0000685 if (j < (ssize_t) number_images)
cristy3ed852e2009-09-05 21:47:34 +0000686 {
687 /*
688 Allocate next image structure.
689 */
cristy9950d572011-10-01 18:22:35 +0000690 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000691 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;
cristybb503372010-05-27 20:51:26 +0000720 for (y=0; y < (ssize_t) height; y+=2)
cristy3ed852e2009-09-05 21:47:34 +0000721 {
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);
cristy018f07f2011-09-04 21:15:19 +0000742 status=DecodeImage(image,luma,chroma1,chroma2,exception);
cristy3ed852e2009-09-05 21:47:34 +0000743 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);
cristy018f07f2011-09-04 21:15:19 +0000754 status=DecodeImage(image,luma,chroma1,chroma2,exception);
cristy3ed852e2009-09-05 21:47:34 +0000755 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;
cristybb503372010-05-27 20:51:26 +0000775 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000776 {
777 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000778 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000779 break;
cristybb503372010-05-27 20:51:26 +0000780 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000781 {
cristy4c08aed2011-07-01 19:47:50 +0000782 SetPixelRed(image,ScaleCharToQuantum(*yy++),q);
783 SetPixelGreen(image,ScaleCharToQuantum(*c1++),q);
784 SetPixelBlue(image,ScaleCharToQuantum(*c2++),q);
cristyed231572011-07-14 02:18:59 +0000785 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000786 }
787 if (SyncAuthenticPixels(image,exception) == MagickFalse)
788 break;
789 if (image->previous == (Image *) NULL)
790 {
cristycee97112010-05-28 00:44:52 +0000791 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
792 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000793 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 image->colorspace=sRGBColorspace;
839 return(GetFirstImageInList(image));
840}
841
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%
cristybb503372010-05-27 20:51:26 +0000862% size_t RegisterPCDImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000863%
864*/
cristybb503372010-05-27 20:51:26 +0000865ModuleExport size_t RegisterPCDImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000866{
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;
cristyffaf9782011-04-13 19:50:51 +0000875 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000876 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;
cristyffaf9782011-04-13 19:50:51 +0000883 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000884 entry->description=ConstantString("Photo CD");
885 entry->module=ConstantString("PCD");
886 (void) RegisterMagickInfo(entry);
887 return(MagickImageCoderSignature);
888}
889
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*/
909ModuleExport void UnregisterPCDImage(void)
910{
911 (void) UnregisterMagickInfo("PCD");
912 (void) UnregisterMagickInfo("PCDS");
913}
914
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%
cristy1e178e72011-08-28 19:44:34 +0000930% MagickBooleanType WritePCDImage(const ImageInfo *image_info,
931% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000932%
933% A description of each parameter follows.
934%
935% o image_info: the image info.
936%
937% o image: The image.
938%
cristy1e178e72011-08-28 19:44:34 +0000939% o exception: return any errors or warnings in this structure.
940%
cristy3ed852e2009-09-05 21:47:34 +0000941*/
942
943static MagickBooleanType WritePCDTile(Image *image,const char *page_geometry,
cristye941a752011-10-15 01:52:48 +0000944 const char *tile_geometry,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000945{
946 GeometryInfo
947 geometry_info;
948
949 Image
950 *downsample_image,
951 *tile_image;
952
cristy3ed852e2009-09-05 21:47:34 +0000953 MagickBooleanType
954 status;
955
956 MagickStatusType
957 flags;
958
959 RectangleInfo
960 geometry;
961
cristy4c08aed2011-07-01 19:47:50 +0000962 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000963 *p,
964 *q;
965
cristybb503372010-05-27 20:51:26 +0000966 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000967 i,
968 x;
969
cristyaff6d802011-04-26 01:46:31 +0000970 ssize_t
971 y;
972
cristy3ed852e2009-09-05 21:47:34 +0000973 /*
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,
cristyc82a27b2011-10-21 01:07:16 +0000984 1.0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000985 if (tile_image == (Image *) NULL)
986 return(MagickFalse);
987 flags=ParseGeometry(page_geometry,&geometry_info);
cristybb503372010-05-27 20:51:26 +0000988 geometry.width=(size_t) geometry_info.rho;
989 geometry.height=(size_t) geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000990 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;
cristy633f0c62011-09-15 13:27:36 +00001006 bordered_image=BorderImage(tile_image,&border_info,image->compose,
cristyc82a27b2011-10-21 01:07:16 +00001007 exception);
cristy3ed852e2009-09-05 21:47:34 +00001008 if (bordered_image == (Image *) NULL)
1009 return(MagickFalse);
1010 tile_image=DestroyImage(tile_image);
1011 tile_image=bordered_image;
1012 }
cristye941a752011-10-15 01:52:48 +00001013 (void) TransformImage(&tile_image,(char *) NULL,tile_geometry,exception);
cristy510d06a2011-07-06 23:43:54 +00001014 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristye941a752011-10-15 01:52:48 +00001015 (void) TransformImageColorspace(tile_image,YCCColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001016 downsample_image=ResizeImage(tile_image,tile_image->columns/2,
cristyc82a27b2011-10-21 01:07:16 +00001017 tile_image->rows/2,TriangleFilter,1.0,exception);
cristy3ed852e2009-09-05 21:47:34 +00001018 if (downsample_image == (Image *) NULL)
1019 return(MagickFalse);
1020 /*
1021 Write tile to PCD file.
1022 */
cristybb503372010-05-27 20:51:26 +00001023 for (y=0; y < (ssize_t) tile_image->rows; y+=2)
cristy3ed852e2009-09-05 21:47:34 +00001024 {
cristyc82a27b2011-10-21 01:07:16 +00001025 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,2,exception);
cristy4c08aed2011-07-01 19:47:50 +00001026 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001027 break;
cristybb503372010-05-27 20:51:26 +00001028 for (x=0; x < (ssize_t) (tile_image->columns << 1); x++)
cristy3ed852e2009-09-05 21:47:34 +00001029 {
cristy4c08aed2011-07-01 19:47:50 +00001030 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(tile_image,p)));
cristyed231572011-07-14 02:18:59 +00001031 p+=GetPixelChannels(tile_image);
cristy3ed852e2009-09-05 21:47:34 +00001032 }
cristyc82a27b2011-10-21 01:07:16 +00001033 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1,
1034 exception);
cristyacd2ed22011-08-30 01:44:23 +00001035 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001036 break;
cristybb503372010-05-27 20:51:26 +00001037 for (x=0; x < (ssize_t) downsample_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001038 {
cristy4c08aed2011-07-01 19:47:50 +00001039 (void) WriteBlobByte(image,ScaleQuantumToChar(
1040 GetPixelGreen(tile_image,q)));
cristy3ed852e2009-09-05 21:47:34 +00001041 q++;
1042 }
cristyc82a27b2011-10-21 01:07:16 +00001043 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1,
1044 exception);
cristyacd2ed22011-08-30 01:44:23 +00001045 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001046 break;
cristybb503372010-05-27 20:51:26 +00001047 for (x=0; x < (ssize_t) downsample_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001048 {
cristy4c08aed2011-07-01 19:47:50 +00001049 (void) WriteBlobByte(image,ScaleQuantumToChar(
1050 GetPixelBlue(tile_image,q)));
cristy3ed852e2009-09-05 21:47:34 +00001051 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
cristy1e178e72011-08-28 19:44:34 +00001064static MagickBooleanType WritePCDImage(const ImageInfo *image_info,Image *image,
1065 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001066{
1067 Image
1068 *pcd_image;
1069
1070 MagickBooleanType
1071 status;
1072
cristybb503372010-05-27 20:51:26 +00001073 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001074 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 */
cristy1e178e72011-08-28 19:44:34 +00001091 rotate_image=RotateImage(image,90.0,exception);
cristy3ed852e2009-09-05 21:47:34 +00001092 if (rotate_image == (Image *) NULL)
1093 return(MagickFalse);
1094 pcd_image=rotate_image;
1095 }
1096 /*
1097 Open output image file.
1098 */
cristy1e178e72011-08-28 19:44:34 +00001099 status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001100 if (status == MagickFalse)
1101 return(status);
cristy510d06a2011-07-06 23:43:54 +00001102 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristye941a752011-10-15 01:52:48 +00001103 (void) TransformImageColorspace(pcd_image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001104 /*
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 */
cristye941a752011-10-15 01:52:48 +00001140 status=WritePCDTile(pcd_image,"768x512>","192x128",exception);
1141 status=WritePCDTile(pcd_image,"768x512>","384x256",exception);
1142 status=WritePCDTile(pcd_image,"768x512>","768x512",exception);
cristy3ed852e2009-09-05 21:47:34 +00001143 (void) CloseBlob(pcd_image);
1144 if (pcd_image != image)
1145 pcd_image=DestroyImage(pcd_image);
1146 return(status);
1147}