/src/graphicsmagick/coders/pcd.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % PPPP CCCC DDDD % |
15 | | % P P C D D % |
16 | | % PPPP C D D % |
17 | | % P C D D % |
18 | | % P CCCC DDDD % |
19 | | % % |
20 | | % % |
21 | | % Read/Write Photo CD Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % John Cristy % |
26 | | % July 1992 % |
27 | | % % |
28 | | % % |
29 | | % % |
30 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
31 | | % |
32 | | % |
33 | | */ |
34 | | |
35 | | /* |
36 | | Include declarations. |
37 | | */ |
38 | | #include "magick/studio.h" |
39 | | #include "magick/attribute.h" |
40 | | #include "magick/blob.h" |
41 | | #include "magick/pixel_cache.h" |
42 | | #include "magick/decorate.h" |
43 | | #include "magick/gem.h" |
44 | | #include "magick/log.h" |
45 | | #include "magick/magick.h" |
46 | | #include "magick/monitor.h" |
47 | | #include "magick/montage.h" |
48 | | #include "magick/resize.h" |
49 | | #include "magick/shear.h" |
50 | | #include "magick/transform.h" |
51 | | #include "magick/utility.h" |
52 | | #include "magick/static.h" |
53 | | |
54 | | /* |
55 | | Forward declarations. |
56 | | */ |
57 | | static unsigned int |
58 | | WritePCDImage(const ImageInfo *,Image *); |
59 | | |
60 | | /* |
61 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
62 | | % % |
63 | | % % |
64 | | % % |
65 | | % U p s a m p l e % |
66 | | % % |
67 | | % % |
68 | | % % |
69 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
70 | | % |
71 | | % Upsample() doubles the size of the image. |
72 | | % |
73 | | % The format of the Upsample method is: |
74 | | % |
75 | | % void Upsample(const unsigned long width,const unsigned long height, |
76 | | % const unsigned long scaled_width,unsigned char *pixels) |
77 | | % |
78 | | % A description of each parameter follows: |
79 | | % |
80 | | % o width,height: Unsigned values representing the width and height of |
81 | | % the image pixel array. |
82 | | % |
83 | | % o scaled_width: Specifies the final width of the upsampled pixel array. |
84 | | % |
85 | | % o pixels: An unsigned char containing the pixel data. On output the |
86 | | % upsampled pixels are returned here. |
87 | | % |
88 | | % |
89 | | */ |
90 | | static void Upsample(const unsigned long width,const unsigned long height, |
91 | | const unsigned long scaled_width,unsigned char *pixels) |
92 | 5.04k | { |
93 | 5.04k | register long |
94 | 5.04k | x, |
95 | 5.04k | y; |
96 | | |
97 | 5.04k | register unsigned char |
98 | 5.04k | *p, |
99 | 5.04k | *q, |
100 | 5.04k | *r; |
101 | | |
102 | | /* |
103 | | Create a new image that is a integral size greater than an existing one. |
104 | | */ |
105 | 5.04k | assert(pixels != (unsigned char *) NULL); |
106 | 327k | for (y=0; y < (long) height; y++) |
107 | 322k | { |
108 | 322k | p=pixels+((size_t)height-1-y)*scaled_width+((size_t)width-1); |
109 | 322k | q=pixels+(((size_t)height-1-y) << 1)*(size_t)scaled_width+(((size_t)width-1) << 1); |
110 | 322k | *q=(*p); |
111 | 322k | *(q+1)=(*(p)); |
112 | 30.9M | for (x=1; x < (long) width; x++) |
113 | 30.6M | { |
114 | 30.6M | p--; |
115 | 30.6M | q-=2; |
116 | 30.6M | *q=(*p); |
117 | 30.6M | *(q+1)=(unsigned char) ((((long) *p)+((long) *(p+1))+1) >> 1); |
118 | 30.6M | } |
119 | 322k | } |
120 | 322k | for (y=0; y < (long) ((size_t)height-1); y++) |
121 | 317k | { |
122 | 317k | p=pixels+((size_t)y << 1)*scaled_width; |
123 | 317k | q=p+(size_t)scaled_width; |
124 | 317k | r=q+ (size_t)scaled_width; |
125 | 30.4M | for (x=0; x < (long) (width-1); x++) |
126 | 30.1M | { |
127 | 30.1M | *q=(unsigned char) ((((long) *p)+((long) *r)+1) >> 1); |
128 | 30.1M | *(q+1)=(unsigned char) |
129 | 30.1M | ((((long) *p)+((long) *(p+2))+((long) *r)+((long) *(r+2))+2) >> 2); |
130 | 30.1M | q+=2; |
131 | 30.1M | p+=2; |
132 | 30.1M | r+=2; |
133 | 30.1M | } |
134 | 317k | *q++=(unsigned char) ((((long) *p++)+((long) *r++)+1) >> 1); |
135 | 317k | *q++=(unsigned char) ((((long) *p++)+((long) *r++)+1) >> 1); |
136 | 317k | } |
137 | 5.04k | p=pixels+(2*(size_t)height-2)* (size_t)scaled_width; |
138 | 5.04k | q=pixels+(2*(size_t)height-1)* (size_t)scaled_width; |
139 | 5.04k | (void) memcpy(q,p,2*(size_t)width); |
140 | 5.04k | } |
141 | | |
142 | | /* |
143 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
144 | | % % |
145 | | % % |
146 | | % % |
147 | | % D e c o d e I m a g e % |
148 | | % % |
149 | | % % |
150 | | % % |
151 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
152 | | % |
153 | | % Method DecodeImage recovers the Huffman encoded luminance and chrominance |
154 | | % deltas. |
155 | | % |
156 | | % The format of the DecodeImage method is: |
157 | | % |
158 | | % static unsigned int DecodeImage(Image *image,unsigned char *luma, |
159 | | % unsigned char *chroma1,unsigned char *chroma2) |
160 | | % |
161 | | % A description of each parameter follows: |
162 | | % |
163 | | % o status: Method DecodeImage returns True if all the deltas are |
164 | | % recovered without error, otherwise False. |
165 | | % |
166 | | % o image: The address of a structure of type Image. |
167 | | % |
168 | | % o luma: The address of a character buffer that contains the |
169 | | % luminance information. |
170 | | % |
171 | | % o chroma1: The address of a character buffer that contains the |
172 | | % chrominance information. |
173 | | % |
174 | | % o chroma2: The address of a character buffer that contains the |
175 | | % chrominance information. |
176 | | % |
177 | | % |
178 | | % |
179 | | */ |
180 | 0 | #define IsSync ((sum & 0xffffff00) == 0xfffffe00) |
181 | 0 | #define DecodeImageText "[%s] PCD decode image..." |
182 | 0 | #define PCDGetBits(n) \ |
183 | 0 | { \ |
184 | 0 | sum=(sum << n) & 0xffffffff; \ |
185 | 0 | bits-=n; \ |
186 | 0 | while (bits <= 24) \ |
187 | 0 | { \ |
188 | 0 | if (p >= (buffer+0x800)) \ |
189 | 0 | { \ |
190 | 0 | if (ReadBlob(image,0x800,(char *) buffer) != 0x800) \ |
191 | 0 | break; \ |
192 | 0 | p=buffer; \ |
193 | 0 | } \ |
194 | 0 | sum|=(((unsigned int) (*p)) << (24-bits)); \ |
195 | 0 | bits+=8; \ |
196 | 0 | p++; \ |
197 | 0 | } \ |
198 | 0 | if (EOFBlob(image)) \ |
199 | 0 | break; \ |
200 | 0 | } |
201 | | static MagickPassFail DecodeImage(Image *image,unsigned char *luma, |
202 | | unsigned char *chroma1,unsigned char *chroma2) |
203 | 0 | { |
204 | 0 | typedef struct PCDTable |
205 | 0 | { |
206 | 0 | unsigned int |
207 | 0 | length, |
208 | 0 | sequence; |
209 | |
|
210 | 0 | unsigned int |
211 | 0 | mask; |
212 | |
|
213 | 0 | unsigned char |
214 | 0 | key; |
215 | 0 | } PCDTable; |
216 | |
|
217 | 0 | long |
218 | | /* count, */ |
219 | 0 | quantum; |
220 | |
|
221 | 0 | PCDTable |
222 | 0 | *pcd_table[3]; |
223 | |
|
224 | 0 | register long |
225 | 0 | i, |
226 | 0 | j; |
227 | |
|
228 | 0 | register PCDTable |
229 | 0 | *r; |
230 | |
|
231 | 0 | register unsigned char |
232 | 0 | *p, |
233 | 0 | *q; |
234 | |
|
235 | 0 | size_t |
236 | 0 | length; |
237 | |
|
238 | 0 | unsigned char |
239 | 0 | *buffer; |
240 | |
|
241 | 0 | unsigned int |
242 | 0 | bits, |
243 | 0 | plane, |
244 | 0 | pcd_length[3], |
245 | 0 | row, |
246 | 0 | sum; |
247 | |
|
248 | 0 | unsigned int |
249 | 0 | status = MagickPass; |
250 | | |
251 | | /* |
252 | | Initialize Huffman tables. |
253 | | */ |
254 | 0 | assert(image != (const Image *) NULL); |
255 | 0 | assert(image->signature == MagickSignature); |
256 | 0 | assert(luma != (unsigned char *) NULL); |
257 | 0 | assert(chroma1 != (unsigned char *) NULL); |
258 | 0 | assert(chroma2 != (unsigned char *) NULL); |
259 | 0 | if (image->logging) |
260 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
261 | 0 | "Huffman decode image %lux%lu (%u tables)", |
262 | 0 | image->columns, image->rows, |
263 | 0 | (image->columns > 1536 ? 3U : 1U)); |
264 | 0 | pcd_table[2]=pcd_table[1]=pcd_table[0]=(PCDTable *) NULL; |
265 | 0 | pcd_length[2]=pcd_length[1]=pcd_length[0]=0; |
266 | 0 | buffer=MagickAllocateResourceLimitedMemory(unsigned char *,0x800); |
267 | 0 | if (buffer == (unsigned char *) NULL) |
268 | 0 | ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed, |
269 | 0 | (char *) NULL); |
270 | 0 | sum=0; |
271 | 0 | bits=32; |
272 | 0 | p=buffer+0x800; |
273 | 0 | for (i=0; i < (image->columns > 1536 ? 3 : 1); i++) |
274 | 0 | { |
275 | 0 | PCDGetBits(8); |
276 | 0 | length=(size_t)(sum & 0xff)+1; |
277 | 0 | pcd_table[i]=MagickAllocateResourceLimitedArray(PCDTable *,length,sizeof(PCDTable)); |
278 | 0 | if (pcd_table[i] == (PCDTable *) NULL) |
279 | 0 | { |
280 | 0 | ThrowException(&image->exception,ResourceLimitError, |
281 | 0 | MemoryAllocationFailed,image->filename); |
282 | 0 | status=MagickFail; |
283 | 0 | goto decode_image_error; |
284 | 0 | } |
285 | 0 | r=pcd_table[i]; |
286 | 0 | for (j=0; j < (long) length; j++) |
287 | 0 | { |
288 | 0 | PCDGetBits(8); |
289 | 0 | r->length=(sum & 0xff)+1; |
290 | 0 | if (r->length > 16) |
291 | 0 | { |
292 | 0 | if (image->logging) |
293 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
294 | 0 | "Excessive length %" MAGICK_SIZE_T_F "u!", |
295 | 0 | (MAGICK_SIZE_T) length); |
296 | 0 | ThrowException(&image->exception,CorruptImageError, |
297 | 0 | UnableToUncompressImage,image->filename); |
298 | 0 | status=MagickFail; |
299 | 0 | goto decode_image_error; |
300 | 0 | } |
301 | 0 | PCDGetBits(16); |
302 | 0 | r->sequence=(sum & 0xffff) << 16; |
303 | 0 | PCDGetBits(8); |
304 | 0 | r->key=(unsigned char) (sum & 0xff); |
305 | 0 | r->mask=(~((((unsigned int) 1) << (32-r->length))-1)); |
306 | 0 | r++; |
307 | 0 | } |
308 | 0 | pcd_length[i]=(unsigned int) length; |
309 | 0 | } |
310 | 0 | if (EOFBlob(image)) |
311 | 0 | { |
312 | 0 | status=MagickFail; |
313 | 0 | goto decode_image_error; |
314 | 0 | } |
315 | | |
316 | | /* |
317 | | Search for Sync byte. |
318 | | */ |
319 | 0 | for (i=0; i < 1; i++) |
320 | 0 | PCDGetBits(16); |
321 | 0 | for (i=0; i < 1; i++) |
322 | 0 | PCDGetBits(16); |
323 | 0 | while ((sum & 0x00fff000) != 0x00fff000) |
324 | 0 | PCDGetBits(8); |
325 | 0 | while (!IsSync) |
326 | 0 | PCDGetBits(1); |
327 | | /* |
328 | | Recover the Huffman encoded luminance and chrominance deltas. |
329 | | */ |
330 | | /* count=0; */ |
331 | 0 | length=0; |
332 | 0 | plane=0; |
333 | 0 | row=0; |
334 | 0 | q=luma; |
335 | 0 | for ( ; ; ) |
336 | 0 | { |
337 | 0 | if (IsSync) |
338 | 0 | { |
339 | | /* |
340 | | Determine plane and row number. |
341 | | */ |
342 | 0 | PCDGetBits(16); |
343 | 0 | row=((sum >> 9) & 0x1fff); |
344 | 0 | if (row == image->rows) |
345 | 0 | break; |
346 | 0 | PCDGetBits(8); |
347 | 0 | plane=sum >> 30; |
348 | 0 | PCDGetBits(16); |
349 | 0 | switch (plane) |
350 | 0 | { |
351 | 0 | case 0: |
352 | 0 | { |
353 | 0 | q=luma+row*(size_t)image->columns; |
354 | | /* count=(long) image->columns; */ |
355 | 0 | break; |
356 | 0 | } |
357 | 0 | case 2: |
358 | 0 | { |
359 | 0 | q=chroma1+(row >> 1)*(size_t)image->columns; |
360 | | /* count=(long) (image->columns >> 1); */ |
361 | 0 | plane--; |
362 | 0 | break; |
363 | 0 | } |
364 | 0 | case 3: |
365 | 0 | { |
366 | 0 | q=chroma2+(row >> 1)*(size_t)image->columns; |
367 | | /* count=(long) (image->columns >> 1); */ |
368 | 0 | plane--; |
369 | 0 | break; |
370 | 0 | } |
371 | 0 | default: |
372 | 0 | { |
373 | 0 | if (image->logging) |
374 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
375 | 0 | "Unhandled plane %u!", plane); |
376 | 0 | ThrowException(&image->exception,CorruptImageError, |
377 | 0 | UnableToUncompressImage,image->filename); |
378 | 0 | status=MagickFail; |
379 | 0 | goto decode_image_error; |
380 | 0 | } |
381 | 0 | } |
382 | 0 | length=pcd_length[plane]; |
383 | 0 | if (QuantumTick(row,image->rows)) |
384 | 0 | if (!MagickMonitorFormatted(row,image->rows,&image->exception, |
385 | 0 | DecodeImageText,image->filename)) |
386 | 0 | { |
387 | 0 | status=MagickFail; |
388 | 0 | goto decode_image_error; |
389 | 0 | } |
390 | 0 | continue; |
391 | 0 | } |
392 | | /* |
393 | | Decode luminance or chrominance deltas. |
394 | | */ |
395 | 0 | r=pcd_table[plane]; |
396 | 0 | for (i=1; ((i < (long) length) && ((sum & r->mask) != r->sequence)); i++) |
397 | 0 | r++; |
398 | 0 | if ((row > image->rows) || (r == (PCDTable *) NULL)) |
399 | 0 | { |
400 | 0 | ThrowException(&image->exception,CorruptImageWarning,SkipToSyncByte, |
401 | 0 | image->filename); |
402 | 0 | while ((sum & 0x00fff000) != 0x00fff000) |
403 | 0 | PCDGetBits(8); |
404 | 0 | while (!IsSync) |
405 | 0 | PCDGetBits(1); |
406 | 0 | continue; |
407 | 0 | } |
408 | 0 | if (r->key < 128U) |
409 | 0 | quantum=(long) (*q)+r->key; |
410 | 0 | else |
411 | 0 | quantum=(long) (*q)+r->key-256; |
412 | 0 | *q=(unsigned char) ((quantum < 0L) ? 0U : |
413 | 0 | (quantum > 255L) ? 255U : |
414 | 0 | (unsigned char) quantum); |
415 | 0 | q++; |
416 | 0 | PCDGetBits(r->length); |
417 | | /* count--; */ |
418 | 0 | } |
419 | 0 | decode_image_error: |
420 | | /* |
421 | | Free memory. |
422 | | */ |
423 | 0 | for (i=0; i < (image->columns > 1536 ? 3 : 1); i++) |
424 | 0 | MagickFreeResourceLimitedMemory(PCDTable *,pcd_table[i]); |
425 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,buffer); |
426 | 0 | return(status); |
427 | 0 | } |
428 | | |
429 | | /* |
430 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
431 | | % % |
432 | | % % |
433 | | % % |
434 | | % I s P C D % |
435 | | % % |
436 | | % % |
437 | | % % |
438 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
439 | | % |
440 | | % Method IsPCD returns True if the image format type, identified by the |
441 | | % magick string, is PCD. |
442 | | % |
443 | | % The format of the IsPCD method is: |
444 | | % |
445 | | % unsigned int IsPCD(const unsigned char *magick,const size_t length) |
446 | | % |
447 | | % A description of each parameter follows: |
448 | | % |
449 | | % o status: Method IsPCD returns True if the image format type is PCD. |
450 | | % |
451 | | % o magick: This string is generally the first few bytes of an image file |
452 | | % or blob. |
453 | | % |
454 | | % o length: Specifies the length of the magick string. |
455 | | % |
456 | | % |
457 | | */ |
458 | | static unsigned int IsPCD(const unsigned char *magick,const size_t length) |
459 | 0 | { |
460 | 0 | if (length < 2052) |
461 | 0 | return(False); |
462 | 0 | if (LocaleNCompare((char *) magick+2048,"PCD_",4) == 0) |
463 | 0 | return(True); |
464 | 0 | return(False); |
465 | 0 | } |
466 | | |
467 | | /* |
468 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
469 | | % % |
470 | | % % |
471 | | % % |
472 | | % R e a d P C D I m a g e % |
473 | | % % |
474 | | % % |
475 | | % % |
476 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
477 | | % |
478 | | % Method ReadPCDImage reads a Photo CD image file and returns it. It |
479 | | % allocates the memory necessary for the new Image structure and returns a |
480 | | % pointer to the new image. Much of the PCD decoder was derived from |
481 | | % the program hpcdtoppm(1) by Hadmut Danisch. |
482 | | % |
483 | | % The format of the ReadPCDImage method is: |
484 | | % |
485 | | % image=ReadPCDImage(image_info) |
486 | | % |
487 | | % A description of each parameter follows: |
488 | | % |
489 | | % o image: Method ReadPCDImage returns a pointer to the image after |
490 | | % reading. A null image is returned if there is a memory shortage or |
491 | | % if the image cannot be read. |
492 | | % |
493 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
494 | | % |
495 | | % o exception: return any errors or warnings in this structure. |
496 | | % |
497 | | % |
498 | | */ |
499 | | |
500 | | static Image *OverviewImage(const ImageInfo *image_info,Image *images, |
501 | | ExceptionInfo *exception) |
502 | 60 | { |
503 | 60 | Image |
504 | 60 | *montage_image; |
505 | | |
506 | 60 | MontageInfo |
507 | 60 | *montage_info; |
508 | | |
509 | | /* |
510 | | Label image tiles. |
511 | | */ |
512 | 60 | { |
513 | 60 | Image |
514 | 60 | *label_image; |
515 | | |
516 | 704 | for( label_image=GetFirstImageInList(images); label_image != 0; |
517 | 644 | label_image=GetNextImageInList(label_image) ) |
518 | 644 | (void) SetImageAttribute(label_image, "label", DefaultTileLabel); |
519 | 60 | } |
520 | | |
521 | | /* |
522 | | Create the PCD Overview image. |
523 | | */ |
524 | 60 | montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL); |
525 | 60 | (void) strlcpy(montage_info->filename,image_info->filename,MaxTextExtent); |
526 | 60 | montage_image=MontageImages(images,montage_info,exception); |
527 | 60 | DestroyMontageInfo(montage_info); |
528 | 60 | DestroyImageList(images); |
529 | 60 | return(montage_image); |
530 | 60 | } |
531 | | |
532 | | #define ThrowPCDReaderException(code_,reason_,image_) \ |
533 | 1.47k | { \ |
534 | 1.47k | MagickFreeResourceLimitedMemory(unsigned char *,chroma1); \ |
535 | 1.47k | MagickFreeResourceLimitedMemory(unsigned char *,chroma2); \ |
536 | 1.47k | MagickFreeResourceLimitedMemory(unsigned char *,luma); \ |
537 | 1.47k | ThrowReaderException(code_,reason_,image_); \ |
538 | 0 | } |
539 | | |
540 | | static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception) |
541 | 1.51k | { |
542 | 1.51k | Image |
543 | 1.51k | *image; |
544 | | |
545 | 1.51k | long |
546 | 1.51k | x; |
547 | | |
548 | 1.51k | ExtendedSignedIntegralType |
549 | 1.51k | offset; |
550 | | |
551 | 1.51k | register long |
552 | 1.51k | y; |
553 | | |
554 | 1.51k | register PixelPacket |
555 | 1.51k | *q; |
556 | | |
557 | 1.51k | register long |
558 | 1.51k | i; |
559 | | |
560 | 1.51k | register unsigned char |
561 | 1.51k | *c1, |
562 | 1.51k | *c2, |
563 | 1.51k | *yy; |
564 | | |
565 | 1.51k | size_t |
566 | 1.51k | number_pixels, |
567 | 1.51k | count; |
568 | | |
569 | 1.51k | unsigned char |
570 | 1.51k | *chroma1 = NULL, |
571 | 1.51k | *chroma2 = NULL, |
572 | 1.51k | header[3*0x800], |
573 | 1.51k | *luma = NULL; |
574 | | |
575 | 1.51k | unsigned int |
576 | 1.51k | overview, |
577 | 1.51k | rotate, |
578 | 1.51k | status; |
579 | | |
580 | 1.51k | unsigned long |
581 | 1.51k | height, |
582 | 1.51k | number_images, |
583 | 1.51k | subimage, |
584 | 1.51k | width; |
585 | | |
586 | | /* |
587 | | Open image file. |
588 | | */ |
589 | 1.51k | assert(image_info != (const ImageInfo *) NULL); |
590 | 1.51k | assert(image_info->signature == MagickSignature); |
591 | 1.51k | assert(exception != (ExceptionInfo *) NULL); |
592 | 1.51k | assert(exception->signature == MagickSignature); |
593 | 1.51k | image=AllocateImage(image_info); |
594 | 1.51k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
595 | 1.51k | if (status == False) |
596 | 1.51k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
597 | | /* |
598 | | Determine if this is a PCD file. |
599 | | */ |
600 | 1.51k | if ((count=ReadBlob(image,3*0x800,(char *) header)) != 3*0x800) |
601 | 1.32k | ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
602 | 1.32k | overview=LocaleNCompare((char *) header,"PCD_OPA",7) == 0; |
603 | 1.32k | if ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && !overview) |
604 | 1.27k | ThrowPCDReaderException(CorruptImageError,ImproperImageHeader,image); |
605 | 1.27k | rotate=header[0x0e02] & 0x03; |
606 | 1.27k | number_images=((header[10] << 8) | header[11]) & 0xFFFF; |
607 | | /* |
608 | | Determine resolution by subimage specification. |
609 | | */ |
610 | 1.27k | number_pixels= (size_t)image->columns*image->rows; |
611 | 1.27k | if (number_pixels == 0) |
612 | 1.27k | { |
613 | 1.27k | subimage=3; |
614 | 1.27k | } |
615 | 0 | else |
616 | 0 | { |
617 | 0 | width=192; |
618 | 0 | height=128; |
619 | 0 | for (subimage=1; subimage < 6; subimage++) |
620 | 0 | { |
621 | 0 | if ((width >= image->columns) && (height >= image->rows)) |
622 | 0 | break; |
623 | 0 | width<<=1; |
624 | 0 | height<<=1; |
625 | 0 | } |
626 | 0 | } |
627 | 1.27k | if (image_info->subrange != 0) |
628 | 1.27k | subimage=Min(image_info->subimage,6); |
629 | 1.27k | if (overview) |
630 | 428 | subimage=1; |
631 | | /* |
632 | | Initialize image structure. |
633 | | */ |
634 | 1.27k | width=192; |
635 | 1.27k | height=128; |
636 | 1.27k | for (i=1; i < (long) Min(subimage,3); i++) |
637 | 0 | { |
638 | 0 | width<<=1; |
639 | 0 | height<<=1; |
640 | 0 | } |
641 | 1.27k | image->columns=width; |
642 | 1.27k | image->rows=height; |
643 | 1.27k | image->depth=8; |
644 | 1.27k | for ( ; i < (long) subimage; i++) |
645 | 0 | { |
646 | 0 | image->columns<<=1; |
647 | 0 | image->rows<<=1; |
648 | 0 | } |
649 | 1.27k | if (image->logging) |
650 | 1.27k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
651 | 1.27k | "Decode PCD %simage geometry %lux%lu", |
652 | 1.27k | (overview ? "(with overview) " : ""), |
653 | 1.27k | image->columns,image->rows); |
654 | | |
655 | 1.27k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
656 | 717 | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
657 | | |
658 | | /* |
659 | | Allocate luma and chroma memory. |
660 | | */ |
661 | 717 | number_pixels=MagickArraySize(image->columns,image->rows); |
662 | 717 | if (number_pixels == 0 || number_pixels+1 < number_pixels) |
663 | 717 | ThrowPCDReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
664 | 717 | chroma1=MagickAllocateResourceLimitedMemory(unsigned char *,number_pixels+1); |
665 | 717 | chroma2=MagickAllocateResourceLimitedMemory(unsigned char *,number_pixels+1); |
666 | 717 | luma=MagickAllocateResourceLimitedMemory(unsigned char *,number_pixels+1); |
667 | 717 | if ((chroma1 == (unsigned char *) NULL) || |
668 | 717 | (chroma2 == (unsigned char *) NULL) || |
669 | 717 | (luma == (unsigned char *) NULL)) |
670 | 717 | ThrowPCDReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
671 | | /* |
672 | | Advance to image data. |
673 | | */ |
674 | 717 | offset=93; |
675 | 717 | if (overview) |
676 | 427 | offset=2; |
677 | 290 | else |
678 | 290 | if (subimage == 2) |
679 | 0 | offset=20; |
680 | 290 | else |
681 | 290 | if (subimage <= 1) |
682 | 290 | offset=1; |
683 | 2.09M | for (i=0; i < (long) (offset*0x800); i++) |
684 | 2.09M | if (ReadBlobByte(image) == EOF) |
685 | 639 | ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
686 | 639 | if (overview) |
687 | 367 | { |
688 | 367 | MonitorHandler |
689 | 367 | handler; |
690 | | |
691 | 367 | register long |
692 | 367 | j; |
693 | | |
694 | | /* |
695 | | Read thumbnails from overview image. |
696 | | */ |
697 | 2.75k | for (j=1; j <= (long) number_images; j++) |
698 | 2.69k | { |
699 | 2.69k | handler=SetMonitorHandler((MonitorHandler) NULL); |
700 | 2.69k | MagickFormatString(image->filename,sizeof(image->filename),"images/img%04ld.pcd",j); |
701 | 2.69k | MagickFormatString(image->magick_filename,sizeof(image->magick_filename),"images/img%04ld.pcd",j); |
702 | 2.69k | image->scene=j; |
703 | 2.69k | image->columns=width; |
704 | 2.69k | image->rows=height; |
705 | 2.69k | image->depth=8; |
706 | 2.69k | yy=luma; |
707 | 2.69k | c1=chroma1; |
708 | 2.69k | c2=chroma2; |
709 | 159k | for (y=0; y < (long) height; y+=2) |
710 | 156k | { |
711 | 156k | if (ReadBlob(image,width,(char *) yy) != width) |
712 | 146 | break; |
713 | 156k | yy+=image->columns; |
714 | 156k | if (ReadBlob(image,width,(char *) yy) != width) |
715 | 61 | break; |
716 | 156k | yy+=image->columns; |
717 | 156k | if (ReadBlob(image,width >> 1,(char *) c1) != (width >> 1)) |
718 | 56 | break; |
719 | 156k | c1+=image->columns; |
720 | 156k | if (ReadBlob(image,width >> 1,(char *) c2) != (width >> 1)) |
721 | 44 | break; |
722 | 156k | c2+=image->columns; |
723 | 156k | } |
724 | 2.69k | if (EOFBlob(image)) |
725 | 2.38k | ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
726 | 2.38k | Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1); |
727 | 2.38k | Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2); |
728 | | /* |
729 | | Transfer luminance and chrominance channels. |
730 | | */ |
731 | 2.38k | yy=luma; |
732 | 2.38k | c1=chroma1; |
733 | 2.38k | c2=chroma2; |
734 | 307k | for (y=0; y < (long) image->rows; y++) |
735 | 305k | { |
736 | 305k | q=SetImagePixels(image,0,y,image->columns,1); |
737 | 305k | if (q == (PixelPacket *) NULL) |
738 | 0 | break; |
739 | 58.8M | for (x=0; x < (long) image->columns; x++) |
740 | 58.5M | { |
741 | 58.5M | q->red=ScaleCharToQuantum(*yy++); |
742 | 58.5M | q->green=ScaleCharToQuantum(*c1++); |
743 | 58.5M | q->blue=ScaleCharToQuantum(*c2++); |
744 | 58.5M | q++; |
745 | 58.5M | } |
746 | 305k | if (!SyncImagePixels(image)) |
747 | 0 | break; |
748 | 305k | } |
749 | 2.38k | if (LocaleCompare(image_info->magick,"PCDS") == 0) |
750 | 1.20k | image->colorspace=sRGBColorspace; |
751 | 1.18k | else |
752 | 1.18k | image->colorspace=YCCColorspace; |
753 | 2.38k | if (TransformColorspace(image,RGBColorspace) != MagickPass) |
754 | 0 | break; |
755 | 2.38k | StopTimer(&image->timer); |
756 | 2.38k | if (j < (long) number_images) |
757 | 2.32k | { |
758 | | /* |
759 | | Allocate next image structure. |
760 | | */ |
761 | 2.32k | AllocateNextImage(image_info,image); |
762 | 2.32k | if (image->next == (Image *) NULL) |
763 | 2.32k | ThrowPCDReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
764 | 2.32k | image=SyncNextImageInList(image); |
765 | 2.32k | } |
766 | 2.38k | (void) SetMonitorHandler(handler); |
767 | 2.38k | if (!MagickMonitorFormatted((size_t)j-1,number_images,&image->exception, |
768 | 2.38k | LoadImageText,image->filename, |
769 | 2.38k | image->columns,image->rows)) |
770 | 0 | break; |
771 | 2.38k | } |
772 | 60 | MagickFreeResourceLimitedMemory(unsigned char *,chroma2); |
773 | 60 | MagickFreeResourceLimitedMemory(unsigned char *,chroma1); |
774 | 60 | MagickFreeResourceLimitedMemory(unsigned char *,luma); |
775 | 644 | while (image->previous != (Image *) NULL) |
776 | 584 | image=image->previous; |
777 | 60 | CloseBlob(image); |
778 | | /* OverviewImage destroys image list before returning */ |
779 | 60 | return OverviewImage(image_info,image,exception); |
780 | 367 | } |
781 | | /* |
782 | | Read interleaved image. |
783 | | */ |
784 | 272 | yy=luma; |
785 | 272 | c1=chroma1; |
786 | 272 | c2=chroma2; |
787 | 10.1k | for (y=0; y < (long) height; y+=2) |
788 | 9.97k | { |
789 | 9.97k | if (ReadBlob(image,width,(char *) yy) != width) |
790 | 38 | break; |
791 | 9.94k | yy+=image->columns; |
792 | 9.94k | if (ReadBlob(image,width,(char *) yy) != width) |
793 | 21 | break; |
794 | 9.92k | yy+=image->columns; |
795 | 9.92k | if (ReadBlob(image,width >> 1,(char *) c1) != (width >> 1)) |
796 | 42 | break; |
797 | 9.87k | c1+=image->columns; |
798 | 9.87k | if (ReadBlob(image,width >> 1,(char *) c2) != (width >> 1)) |
799 | 34 | break; |
800 | 9.84k | c2+=image->columns; |
801 | 9.84k | } |
802 | 272 | if (EOFBlob(image)) |
803 | 137 | ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
804 | 137 | if (subimage >= 4) |
805 | 0 | { |
806 | | /* |
807 | | Recover luminance deltas for 1536x1024 image. |
808 | | */ |
809 | 0 | Upsample(768,512,image->columns,luma); |
810 | 0 | Upsample(384,256,image->columns,chroma1); |
811 | 0 | Upsample(384,256,image->columns,chroma2); |
812 | 0 | image->rows=1024; |
813 | 0 | for (i=0; i < (4*0x800); i++) |
814 | 0 | (void) ReadBlobByte(image); |
815 | 0 | status=DecodeImage(image,luma,chroma1,chroma2); |
816 | 0 | if ((subimage >= 5) && status) |
817 | 0 | { |
818 | | /* |
819 | | Recover luminance deltas for 3072x2048 image. |
820 | | */ |
821 | 0 | Upsample(1536,1024,image->columns,luma); |
822 | 0 | Upsample(768,512,image->columns,chroma1); |
823 | 0 | Upsample(768,512,image->columns,chroma2); |
824 | 0 | image->rows=2048; |
825 | 0 | offset=TellBlob(image)/0x800+12; |
826 | 0 | (void) SeekBlob(image,offset*0x800,SEEK_SET); |
827 | 0 | status=DecodeImage(image,luma,chroma1,chroma2); |
828 | 0 | if ((subimage >= 6) && status) |
829 | 0 | { |
830 | | /* |
831 | | Recover luminance deltas for 6144x4096 image (vaporware). |
832 | | */ |
833 | 0 | Upsample(3072,2048,image->columns,luma); |
834 | 0 | Upsample(1536,1024,image->columns,chroma1); |
835 | 0 | Upsample(1536,1024,image->columns,chroma2); |
836 | 0 | image->rows=4096; |
837 | 0 | } |
838 | 0 | } |
839 | 0 | } |
840 | 137 | if (EOFBlob(image)) |
841 | 137 | ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
842 | | |
843 | 137 | CloseBlob(image); |
844 | | |
845 | 137 | Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1); |
846 | 137 | Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2); |
847 | | /* |
848 | | Transfer luminance and chrominance channels. |
849 | | */ |
850 | 137 | yy=luma; |
851 | 137 | c1=chroma1; |
852 | 137 | c2=chroma2; |
853 | 17.6k | for (y=0; y < (long) image->rows; y++) |
854 | 17.5k | { |
855 | 17.5k | q=SetImagePixels(image,0,y,image->columns,1); |
856 | 17.5k | if (q == (PixelPacket *) NULL) |
857 | 0 | break; |
858 | 3.38M | for (x=0; x < (long) image->columns; x++) |
859 | 3.36M | { |
860 | 3.36M | q->red=ScaleCharToQuantum(*yy++); |
861 | 3.36M | q->green=ScaleCharToQuantum(*c1++); |
862 | 3.36M | q->blue=ScaleCharToQuantum(*c2++); |
863 | 3.36M | q++; |
864 | 3.36M | } |
865 | 17.5k | if (!SyncImagePixels(image)) |
866 | 0 | break; |
867 | 17.5k | if (QuantumTick(y,image->rows)) |
868 | 17.5k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
869 | 17.5k | image->filename, |
870 | 17.5k | image->columns,image->rows)) |
871 | 0 | break; |
872 | 17.5k | } |
873 | 137 | MagickFreeResourceLimitedMemory(unsigned char *,chroma2); |
874 | 137 | MagickFreeResourceLimitedMemory(unsigned char *,chroma1); |
875 | 137 | MagickFreeResourceLimitedMemory(unsigned char *,luma); |
876 | 137 | if (LocaleCompare(image_info->magick,"PCDS") == 0) |
877 | 70 | image->colorspace=sRGBColorspace; |
878 | 67 | else |
879 | 67 | image->colorspace=YCCColorspace; |
880 | | /* FIXME: YCCColorspace transform is broken! 1.1 is ok! */ |
881 | 137 | if (TransformColorspace(image,RGBColorspace) == MagickFail) |
882 | 0 | ThrowException(exception,CoderError,UnableToTransformColorspace, |
883 | 137 | image->filename); |
884 | 137 | if ((rotate == 1) || (rotate == 3)) |
885 | 83 | { |
886 | 83 | double |
887 | 83 | degrees; |
888 | | |
889 | 83 | Image |
890 | 83 | *rotated_image; |
891 | | |
892 | | /* |
893 | | Rotate image. |
894 | | */ |
895 | 83 | degrees=rotate == 1 ? -90.0 : 90.0; |
896 | 83 | rotated_image=RotateImage(image,degrees,exception); |
897 | 83 | if (rotated_image != (Image *) NULL) |
898 | 83 | { |
899 | 83 | DestroyBlob(rotated_image); |
900 | 83 | rotated_image->blob=ReferenceBlob(image->blob); |
901 | 83 | DestroyImage(image); |
902 | 83 | image=rotated_image; |
903 | 83 | } |
904 | 83 | } |
905 | | |
906 | | /* |
907 | | Set CCIR 709 primaries with a D65 white point. |
908 | | */ |
909 | 137 | image->chromaticity.red_primary.x=0.6400f; |
910 | 137 | image->chromaticity.red_primary.y=0.3300f; |
911 | 137 | image->chromaticity.green_primary.x=0.3000f; |
912 | 137 | image->chromaticity.green_primary.y=0.6000f; |
913 | 137 | image->chromaticity.blue_primary.x=0.1500f; |
914 | 137 | image->chromaticity.blue_primary.y=0.0600f; |
915 | 137 | image->chromaticity.white_point.x=0.3127f; |
916 | 137 | image->chromaticity.white_point.y=0.3290f; |
917 | 137 | image->gamma=1.000f/2.200f; |
918 | 137 | StopTimer(&image->timer); |
919 | 137 | return(image); |
920 | 137 | } |
921 | | |
922 | | /* |
923 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
924 | | % % |
925 | | % % |
926 | | % % |
927 | | % R e g i s t e r P C D I m a g e % |
928 | | % % |
929 | | % % |
930 | | % % |
931 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
932 | | % |
933 | | % Method RegisterPCDImage adds attributes for the PCD image format to |
934 | | % the list of supported formats. The attributes include the image format |
935 | | % tag, a method to read and/or write the format, whether the format |
936 | | % supports the saving of more than one frame to the same file or blob, |
937 | | % whether the format supports native in-memory I/O, and a brief |
938 | | % description of the format. |
939 | | % |
940 | | % The format of the RegisterPCDImage method is: |
941 | | % |
942 | | % RegisterPCDImage(void) |
943 | | % |
944 | | */ |
945 | | ModuleExport void RegisterPCDImage(void) |
946 | 5 | { |
947 | 5 | MagickInfo |
948 | 5 | *entry; |
949 | | |
950 | 5 | entry=SetMagickInfo("PCD"); |
951 | 5 | entry->decoder=(DecoderHandler) ReadPCDImage; |
952 | 5 | entry->encoder=(EncoderHandler) WritePCDImage; |
953 | 5 | entry->magick=(MagickHandler) IsPCD; |
954 | 5 | entry->adjoin=False; |
955 | 5 | entry->description="Photo CD"; |
956 | 5 | entry->seekable_stream=MagickTrue; |
957 | 5 | entry->module="PCD"; |
958 | 5 | (void) RegisterMagickInfo(entry); |
959 | | |
960 | 5 | entry=SetMagickInfo("PCDS"); |
961 | 5 | entry->decoder=(DecoderHandler) ReadPCDImage; |
962 | 5 | entry->encoder=(EncoderHandler) WritePCDImage; |
963 | 5 | entry->adjoin=False; |
964 | 5 | entry->description="Photo CD"; |
965 | 5 | entry->seekable_stream=MagickTrue; |
966 | 5 | entry->module="PCD"; |
967 | 5 | (void) RegisterMagickInfo(entry); |
968 | 5 | } |
969 | | |
970 | | /* |
971 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
972 | | % % |
973 | | % % |
974 | | % % |
975 | | % U n r e g i s t e r P C D I m a g e % |
976 | | % % |
977 | | % % |
978 | | % % |
979 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
980 | | % |
981 | | % Method UnregisterPCDImage removes format registrations made by the |
982 | | % PCD module from the list of supported formats. |
983 | | % |
984 | | % The format of the UnregisterPCDImage method is: |
985 | | % |
986 | | % UnregisterPCDImage(void) |
987 | | % |
988 | | */ |
989 | | ModuleExport void UnregisterPCDImage(void) |
990 | 0 | { |
991 | 0 | (void) UnregisterMagickInfo("PCD"); |
992 | 0 | (void) UnregisterMagickInfo("PCDS"); |
993 | 0 | } |
994 | | |
995 | | /* |
996 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
997 | | % % |
998 | | % % |
999 | | % % |
1000 | | % W r i t e P C D I m a g e % |
1001 | | % % |
1002 | | % % |
1003 | | % % |
1004 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1005 | | % |
1006 | | % Method WritePCDImage writes an image in the Photo CD encoded image |
1007 | | % format. |
1008 | | % |
1009 | | % The format of the WritePCDImage method is: |
1010 | | % |
1011 | | % unsigned int WritePCDImage(const ImageInfo *image_info,Image *image) |
1012 | | % |
1013 | | % A description of each parameter follows. |
1014 | | % |
1015 | | % o status: Method WritePCDImage return True if the image is written. |
1016 | | % False is returned is there is a memory shortage or if the image file |
1017 | | % fails to write. |
1018 | | % |
1019 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
1020 | | % |
1021 | | % o image: A pointer to an Image structure. |
1022 | | % |
1023 | | % |
1024 | | */ |
1025 | | |
1026 | | static unsigned int WritePCDTile(const ImageInfo *image_info, |
1027 | | Image *image,char *page_geometry,char *tile_geometry) |
1028 | 411 | { |
1029 | 411 | Image |
1030 | 411 | *downsample_image, |
1031 | 411 | *tile_image; |
1032 | | |
1033 | 411 | long |
1034 | 411 | y; |
1035 | | |
1036 | 411 | RectangleInfo |
1037 | 411 | geometry; |
1038 | | |
1039 | 411 | register const PixelPacket |
1040 | 411 | *p, |
1041 | 411 | *q; |
1042 | | |
1043 | 411 | register long |
1044 | 411 | i, |
1045 | 411 | x; |
1046 | | |
1047 | 411 | ARG_NOT_USED(image_info); |
1048 | | |
1049 | | /* |
1050 | | Scale image to tile size. |
1051 | | */ |
1052 | 411 | SetGeometry(image,&geometry); |
1053 | 411 | (void) GetMagickGeometry(page_geometry,&geometry.x,&geometry.y, |
1054 | 411 | &geometry.width,&geometry.height); |
1055 | 411 | if ((geometry.width % 2) != 0) |
1056 | 0 | geometry.width = geometry.width > 1 ? geometry.width-1 : geometry.width+1 ; |
1057 | 411 | if ((geometry.height % 2) != 0) |
1058 | 0 | geometry.height = geometry.height > 1 ? geometry.height-1 : geometry.height+1; |
1059 | 411 | tile_image=ResizeImage(image,geometry.width,geometry.height,TriangleFilter, |
1060 | 411 | 1.0,&image->exception); |
1061 | 411 | if (tile_image == (Image *) NULL) |
1062 | 0 | return(False); |
1063 | 411 | (void) sscanf(page_geometry,"%lux%lu",&geometry.width,&geometry.height); |
1064 | 411 | if ((tile_image->columns != geometry.width) || |
1065 | 0 | (tile_image->rows != geometry.height)) |
1066 | 411 | { |
1067 | 411 | Image |
1068 | 411 | *bordered_image; |
1069 | | |
1070 | 411 | RectangleInfo |
1071 | 411 | border_info; |
1072 | | |
1073 | | /* |
1074 | | Put a border around the image. |
1075 | | */ |
1076 | 411 | border_info.width=(geometry.width-tile_image->columns+1) >> 1; |
1077 | 411 | border_info.height=(geometry.height-tile_image->rows+1) >> 1; |
1078 | 411 | if (image->logging) |
1079 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1080 | 0 | "Adding %lux%lu border to %lux%lu tile ", |
1081 | 0 | border_info.width, border_info.height, |
1082 | 0 | image->columns, image->rows); |
1083 | 411 | bordered_image=BorderImage(tile_image,&border_info,&image->exception); |
1084 | 411 | DestroyImage(tile_image); |
1085 | 411 | tile_image=(Image *) NULL; |
1086 | 411 | if (bordered_image == (Image *) NULL) |
1087 | 0 | return(MagickFail); |
1088 | 411 | tile_image=bordered_image; |
1089 | 411 | } |
1090 | 411 | if (image->logging) |
1091 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1092 | 0 | "Transforming tile to %s from %lux%lu", |
1093 | 0 | tile_geometry, |
1094 | 0 | image->columns, image->rows); |
1095 | 411 | (void) TransformImage(&tile_image,(char *) NULL,tile_geometry); |
1096 | 411 | if (TransformColorspace(tile_image,YCCColorspace) == MagickFail) |
1097 | 0 | { |
1098 | 0 | ThrowException(&image->exception,CoderError,UnableToTransformColorspace, |
1099 | 0 | image->filename); |
1100 | 0 | DestroyImage(tile_image); |
1101 | 0 | return(MagickFail); |
1102 | 0 | } |
1103 | 411 | downsample_image=ResizeImage(tile_image,tile_image->columns/2, |
1104 | 411 | tile_image->rows/2,TriangleFilter,1.0,&image->exception); |
1105 | 411 | if (downsample_image == (Image *) NULL) |
1106 | 0 | { |
1107 | 0 | DestroyImage(tile_image); |
1108 | 0 | return(MagickFail); |
1109 | 0 | } |
1110 | | /* |
1111 | | Write tile to PCD file. |
1112 | | */ |
1113 | 61.7k | for (y=0; y < (long) tile_image->rows; y+=2) |
1114 | 61.3k | { |
1115 | 61.3k | p=AcquireImagePixels(tile_image,0,y,tile_image->columns,2, |
1116 | 61.3k | &tile_image->exception); |
1117 | 61.3k | if (p == (const PixelPacket *) NULL) |
1118 | 0 | break; |
1119 | 70.7M | for (x=0; x < (long) (tile_image->columns << 1); x++) |
1120 | 70.7M | { |
1121 | 70.7M | (void) WriteBlobByte(image,ScaleQuantumToChar(p->red)); |
1122 | 70.7M | p++; |
1123 | 70.7M | } |
1124 | 61.3k | q=AcquireImagePixels(downsample_image,0,y >> 1,downsample_image->columns, |
1125 | 61.3k | 1,&downsample_image->exception); |
1126 | 61.3k | if (q == (const PixelPacket *) NULL) |
1127 | 0 | break; |
1128 | 17.7M | for (x=0; x < (long) downsample_image->columns; x++) |
1129 | 17.6M | { |
1130 | 17.6M | (void) WriteBlobByte(image,ScaleQuantumToChar(q->green)); |
1131 | 17.6M | q++; |
1132 | 17.6M | } |
1133 | 61.3k | q=AcquireImagePixels(downsample_image,0,y >> 1,downsample_image->columns, |
1134 | 61.3k | 1,&downsample_image->exception); |
1135 | 61.3k | if (q == (const PixelPacket *) NULL) |
1136 | 0 | break; |
1137 | 17.7M | for (x=0; x < (long) downsample_image->columns; x++) |
1138 | 17.6M | { |
1139 | 17.6M | (void) WriteBlobByte(image,ScaleQuantumToChar(q->blue)); |
1140 | 17.6M | q++; |
1141 | 17.6M | } |
1142 | 61.3k | if (QuantumTick(y,tile_image->rows)) |
1143 | 33.4k | if (!MagickMonitorFormatted(y,tile_image->rows,&image->exception, |
1144 | 33.4k | SaveImageText,image->filename, |
1145 | 33.4k | image->columns,image->rows)) |
1146 | 0 | break; |
1147 | 61.3k | } |
1148 | 842k | for (i=0; i < 0x800; i++) |
1149 | 841k | (void) WriteBlobByte(image,'\0'); |
1150 | 411 | DestroyImage(downsample_image); |
1151 | 411 | DestroyImage(tile_image); |
1152 | 411 | return(MagickPass); |
1153 | 411 | } |
1154 | | |
1155 | | static MagickPassFail WritePCDImage(const ImageInfo *image_info,Image *image) |
1156 | 137 | { |
1157 | 137 | Image |
1158 | 137 | *pcd_image; |
1159 | | |
1160 | 137 | register long |
1161 | 137 | i; |
1162 | | |
1163 | 137 | unsigned int |
1164 | 137 | status; |
1165 | | |
1166 | 137 | assert(image_info != (const ImageInfo *) NULL); |
1167 | 137 | assert(image_info->signature == MagickSignature); |
1168 | 137 | assert(image != (Image *) NULL); |
1169 | 137 | assert(image->signature == MagickSignature); |
1170 | 137 | pcd_image=image; |
1171 | 137 | if (image->columns < image->rows) |
1172 | 83 | { |
1173 | 83 | Image |
1174 | 83 | *rotated_image; |
1175 | | |
1176 | | /* |
1177 | | Rotate portrait to landscape. |
1178 | | */ |
1179 | 83 | rotated_image=RotateImage(image,90.0,&image->exception); |
1180 | 83 | if (rotated_image == (Image *) NULL) |
1181 | 0 | return(False); |
1182 | 83 | pcd_image=rotated_image; |
1183 | 83 | DestroyBlob(rotated_image); |
1184 | 83 | pcd_image->blob=ReferenceBlob(image->blob); |
1185 | 83 | } |
1186 | | /* |
1187 | | Open output image file. |
1188 | | */ |
1189 | 137 | status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,&image->exception); |
1190 | 137 | if (status == False) |
1191 | 137 | ThrowWriterException(FileOpenError,UnableToOpenFile,pcd_image); |
1192 | 137 | if (TransformColorspace(pcd_image,RGBColorspace) == MagickFail) |
1193 | 137 | ThrowWriterException(CoderError,UnableToTransformColorspace,pcd_image); |
1194 | | /* |
1195 | | Write PCD image header. |
1196 | | */ |
1197 | 4.52k | for (i=0; i < 32; i++) |
1198 | 4.38k | (void) WriteBlobByte(pcd_image,0xff); |
1199 | 685 | for (i=0; i < 4; i++) |
1200 | 548 | (void) WriteBlobByte(pcd_image,0x0e); |
1201 | 1.23k | for (i=0; i < 8; i++) |
1202 | 1.09k | (void) WriteBlobByte(pcd_image,'\0'); |
1203 | 685 | for (i=0; i < 4; i++) |
1204 | 548 | (void) WriteBlobByte(pcd_image,0x01); |
1205 | 685 | for (i=0; i < 4; i++) |
1206 | 548 | (void) WriteBlobByte(pcd_image,0x05); |
1207 | 1.23k | for (i=0; i < 8; i++) |
1208 | 1.09k | (void) WriteBlobByte(pcd_image,'\0'); |
1209 | 685 | for (i=0; i < 4; i++) |
1210 | 548 | (void) WriteBlobByte(pcd_image,0x0A); |
1211 | 5.06k | for (i=0; i < 36; i++) |
1212 | 4.93k | (void) WriteBlobByte(pcd_image,'\0'); |
1213 | 685 | for (i=0; i < 4; i++) |
1214 | 548 | (void) WriteBlobByte(pcd_image,0x01); |
1215 | 266k | for (i=0; i < 1944; i++) |
1216 | 266k | (void) WriteBlobByte(pcd_image,'\0'); |
1217 | 137 | (void) WriteBlob(pcd_image,7,"PCD_IPI"); |
1218 | 137 | (void) WriteBlobByte(pcd_image,0x06); |
1219 | 209k | for (i=0; i < 1530; i++) |
1220 | 209k | (void) WriteBlobByte(pcd_image,'\0'); |
1221 | 137 | if (image->columns < image->rows) |
1222 | 83 | (void) WriteBlobByte(pcd_image,'\1'); |
1223 | 54 | else |
1224 | 54 | (void) WriteBlobByte(pcd_image,'\0'); |
1225 | 631k | for (i=0; i < (3*0x800-1539); i++) |
1226 | 630k | (void) WriteBlobByte(pcd_image,'\0'); |
1227 | | /* |
1228 | | Write PCD tiles. |
1229 | | */ |
1230 | 137 | status=WritePCDTile(image_info,pcd_image,(char *) "768x512>", |
1231 | 137 | (char *) "192x128"); |
1232 | 137 | status&=WritePCDTile(image_info,pcd_image,(char *) "768x512>", |
1233 | 137 | (char *) "384x256"); |
1234 | 137 | status&=WritePCDTile(image_info,pcd_image,(char *) "768x512>", |
1235 | 137 | (char *) "768x512"); |
1236 | 137 | if (GetBlobStatus(pcd_image) != 0) |
1237 | 0 | status=MagickFail; |
1238 | 137 | status &= CloseBlob(pcd_image); |
1239 | 137 | if (pcd_image != image) |
1240 | 83 | DestroyImage(pcd_image); |
1241 | 137 | return(status); |
1242 | 137 | } |