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