/src/graphicsmagick/coders/pdb.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % |
5 | | % This program is covered by multiple licenses, which are described in |
6 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
7 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
8 | | % |
9 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10 | | % % |
11 | | % % |
12 | | % % |
13 | | % PPPP DDDD BBBB % |
14 | | % P P D D B B % |
15 | | % PPPP D D BBBB % |
16 | | % P D D B B % |
17 | | % P DDDD BBBB % |
18 | | % % |
19 | | % % |
20 | | % Read/Write Palm Database ImageViewer Image Format. % |
21 | | % % |
22 | | % % |
23 | | % Software Design % |
24 | | % John Cristy % |
25 | | % July 1992 % |
26 | | % % |
27 | | % % |
28 | | % % |
29 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
30 | | % |
31 | | % |
32 | | */ |
33 | | /* |
34 | | Some information on this format may be found at |
35 | | http://fileformats.archiveteam.org/wiki/Palm_Database_ImageViewer |
36 | | |
37 | | Round-trip tests do not pass so this format is not included in the |
38 | | test suite. |
39 | | */ |
40 | | |
41 | | /* |
42 | | Include declarations. |
43 | | */ |
44 | | #include "magick/studio.h" |
45 | | #include "magick/analyze.h" |
46 | | #include "magick/attribute.h" |
47 | | #include "magick/blob.h" |
48 | | #include "magick/colormap.h" |
49 | | #include "magick/constitute.h" |
50 | | #include "magick/log.h" |
51 | | #include "magick/magick.h" |
52 | | #include "magick/monitor.h" |
53 | | #include "magick/pixel_cache.h" |
54 | | #include "magick/utility.h" |
55 | | #include "magick/static.h" |
56 | | |
57 | | /* |
58 | | Typedef declarations. |
59 | | */ |
60 | | typedef struct _PDBInfo |
61 | | { |
62 | | char |
63 | | name[32]; |
64 | | |
65 | | short int |
66 | | attributes, |
67 | | version; |
68 | | |
69 | | unsigned long |
70 | | create_time, |
71 | | modify_time, |
72 | | archive_time, |
73 | | modify_number, |
74 | | application_info, |
75 | | sort_info; |
76 | | |
77 | | char |
78 | | type[4], /* database type identifier "vIMG" */ |
79 | | id[4]; /* database creator identifier "View" */ |
80 | | |
81 | | unsigned long |
82 | | seed, |
83 | | next_record; |
84 | | |
85 | | short int |
86 | | number_records; |
87 | | } PDBInfo; |
88 | | |
89 | | typedef struct _PDBImage |
90 | | { |
91 | | char |
92 | | name[32], |
93 | | version, |
94 | | type; |
95 | | |
96 | | unsigned long |
97 | | reserved_1, |
98 | | note; |
99 | | |
100 | | unsigned short int |
101 | | x_last, |
102 | | y_last; |
103 | | |
104 | | unsigned long |
105 | | reserved_2; |
106 | | |
107 | | unsigned short int |
108 | | x_anchor, |
109 | | y_anchor, |
110 | | width, |
111 | | height; |
112 | | } PDBImage; |
113 | | /* |
114 | | Forward declarations. |
115 | | */ |
116 | | static unsigned int |
117 | | WritePDBImage(const ImageInfo *,Image *); |
118 | | |
119 | | static void LogPDPInfo(const PDBInfo *info) |
120 | 20.8k | { |
121 | 20.8k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
122 | 20.8k | "PDP Info:\n" |
123 | 20.8k | " name : %.32s\n" |
124 | 20.8k | " attributes : %d\n" |
125 | 20.8k | " version : %d\n" |
126 | 20.8k | " create_time : %lu\n" |
127 | 20.8k | " modify_time : %lu\n" |
128 | 20.8k | " archive_time : %lu\n" |
129 | 20.8k | " modify_number : %lu\n" |
130 | 20.8k | " application_info: %lu\n" |
131 | 20.8k | " sort_info : %lu\n" |
132 | 20.8k | " type : %.4s\n" |
133 | 20.8k | " id : %.4s\n" |
134 | 20.8k | " seed : %lu\n" |
135 | 20.8k | " next_record : %lu\n" |
136 | 20.8k | " number_records : %u", |
137 | 20.8k | info->name, |
138 | 20.8k | info->attributes, |
139 | 20.8k | info->version, |
140 | 20.8k | info->create_time, |
141 | 20.8k | info->modify_time, |
142 | 20.8k | info->archive_time, |
143 | 20.8k | info->modify_number, |
144 | 20.8k | info->application_info, |
145 | 20.8k | info->sort_info, |
146 | 20.8k | info->type, |
147 | 20.8k | info->id, |
148 | 20.8k | info->seed, |
149 | 20.8k | info->next_record, |
150 | 20.8k | info->number_records); |
151 | 20.8k | } |
152 | | |
153 | | static void LogPDPImage(const PDBImage *image) |
154 | 4.59k | { |
155 | 4.59k | static const char *type_string; |
156 | 4.59k | switch(image->type) |
157 | 4.59k | { |
158 | 2.61k | case 0: type_string = "2 bit gray"; break; |
159 | 104 | case 2: type_string = "4 bit gray"; break; |
160 | 1.86k | default: type_string = "monochrome"; break; |
161 | 4.59k | } |
162 | | |
163 | 4.59k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
164 | 4.59k | "PDP Image:\n" |
165 | 4.59k | " name: %.32s\n" |
166 | 4.59k | " version: %d\n" |
167 | 4.59k | " type: %d (%s)\n" |
168 | 4.59k | " reserved_1: %lu\n" |
169 | 4.59k | " note: %lu\n" |
170 | 4.59k | " x_last: %u\n" |
171 | 4.59k | " y_last: %u\n" |
172 | 4.59k | " reserved_2: %lu\n" |
173 | 4.59k | " x_anchor: %u\n" |
174 | 4.59k | " y_anchor: %u\n" |
175 | 4.59k | " width: %u\n" |
176 | 4.59k | " height: %u", |
177 | 4.59k | image->name, |
178 | 4.59k | image->version, |
179 | 4.59k | image->type, type_string, |
180 | 4.59k | image->reserved_1, |
181 | 4.59k | image->note, |
182 | 4.59k | image->x_last, |
183 | 4.59k | image->y_last, |
184 | 4.59k | image->reserved_2, |
185 | 4.59k | image->x_anchor, |
186 | 4.59k | image->y_anchor, |
187 | 4.59k | image->width, |
188 | 4.59k | image->height |
189 | 4.59k | ); |
190 | 4.59k | } |
191 | | |
192 | | /* |
193 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
194 | | % % |
195 | | % % |
196 | | % % |
197 | | % D e c o d e I m a g e % |
198 | | % % |
199 | | % % |
200 | | % % |
201 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
202 | | % |
203 | | % Method DecodeImage unpacks the packed image pixels into runlength-encoded |
204 | | % pixel packets. |
205 | | % |
206 | | % The format of the DecodeImage method is: |
207 | | % |
208 | | % unsigned int DecodeImage(Image *image,unsigned char *pixels, |
209 | | % const size_t length) |
210 | | % |
211 | | % A description of each parameter follows: |
212 | | % |
213 | | % o status: Method DecodeImage returns True if all the pixels are |
214 | | % uncompressed without error, otherwise False. |
215 | | % |
216 | | % o image: The address of a structure of type Image. |
217 | | % |
218 | | % o pixels: The address of a byte (8 bits) array of pixel data created by |
219 | | % the decoding process. |
220 | | % |
221 | | % |
222 | | */ |
223 | | static MagickPassFail DecodeImage(Image *image,unsigned char *pixels, |
224 | | const size_t length) |
225 | 454 | { |
226 | 454 | int |
227 | 454 | c, |
228 | 454 | count, |
229 | 454 | pixel; |
230 | | |
231 | 454 | register long |
232 | 454 | i; |
233 | | |
234 | 454 | register unsigned char |
235 | 454 | *p; |
236 | | |
237 | 454 | MagickPassFail |
238 | 454 | status = MagickPass; |
239 | | |
240 | 454 | p=pixels; |
241 | 939k | while (p < (pixels+length)) |
242 | 938k | { |
243 | 938k | if ((pixel=ReadBlobByte(image)) == EOF) |
244 | 38 | { |
245 | 38 | status = MagickFail; |
246 | 38 | goto decode_image_quit; |
247 | 38 | } |
248 | 938k | if (pixel <= 0x80) |
249 | 426k | { |
250 | 426k | count=pixel+1; |
251 | 10.2M | for (i=0; i < count; i++) |
252 | 9.78M | { |
253 | 9.78M | if ((c = ReadBlobByte(image)) == EOF) |
254 | 29 | { |
255 | 29 | status = MagickFail; |
256 | 29 | goto decode_image_quit; |
257 | 29 | } |
258 | 9.78M | *p++ = (unsigned char) c; |
259 | 9.78M | } |
260 | 426k | continue; |
261 | 426k | } |
262 | 512k | count=pixel+1-0x80; |
263 | 512k | if ((pixel=ReadBlobByte(image)) == EOF) |
264 | 13 | { |
265 | 13 | status = MagickFail; |
266 | 13 | goto decode_image_quit; |
267 | 13 | } |
268 | | |
269 | 40.0M | for (i=0; i < count; i++) |
270 | 39.5M | *p++=(unsigned char) pixel; |
271 | 512k | } |
272 | 454 | decode_image_quit:; |
273 | | |
274 | 454 | return(status); |
275 | 454 | } |
276 | | |
277 | | /* |
278 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
279 | | % % |
280 | | % % |
281 | | % % |
282 | | % I s P D B % |
283 | | % % |
284 | | % % |
285 | | % % |
286 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
287 | | % |
288 | | % Method IsPDB returns True if the image format type, identified by the |
289 | | % magick string, is PDB. |
290 | | % |
291 | | % The format of the ReadPDBImage method is: |
292 | | % |
293 | | % unsigned int IsPDB(const unsigned char *magick,const size_t length) |
294 | | % |
295 | | % A description of each parameter follows: |
296 | | % |
297 | | % o status: Method IsPDB returns True if the image format type is PDB. |
298 | | % |
299 | | % o magick: This string is generally the first few bytes of an image file |
300 | | % or blob. |
301 | | % |
302 | | % o length: Specifies the length of the magick string. |
303 | | % |
304 | | % |
305 | | */ |
306 | | static unsigned int IsPDB(const unsigned char *magick,const size_t length) |
307 | 0 | { |
308 | 0 | if (length < 68) |
309 | 0 | return(False); |
310 | 0 | if (memcmp(magick+60,"vIMGView",8) == 0) |
311 | 0 | return(True); |
312 | 0 | return(False); |
313 | 0 | } |
314 | | |
315 | | /* |
316 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
317 | | % % |
318 | | % % |
319 | | % % |
320 | | % R e a d P D B I m a g e % |
321 | | % % |
322 | | % % |
323 | | % % |
324 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
325 | | % |
326 | | % Method ReadPDBImage reads an Pilot image file and returns it. It |
327 | | % allocates the memory necessary for the new Image structure and returns a |
328 | | % pointer to the new image. |
329 | | % |
330 | | % The format of the ReadPDBImage method is: |
331 | | % |
332 | | % Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception) |
333 | | % |
334 | | % A description of each parameter follows: |
335 | | % |
336 | | % o image: Method ReadPDBImage returns a pointer to the image after |
337 | | % reading. A null image is returned if there is a memory shortage or if |
338 | | % the image cannot be read. |
339 | | % |
340 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
341 | | % |
342 | | % o exception: return any errors or warnings in this structure. |
343 | | % |
344 | | % |
345 | | */ |
346 | | #define ThrowPDBReaderException(code_,reason_,image_) \ |
347 | 16.0k | { \ |
348 | 16.0k | MagickFreeResourceLimitedMemory(unsigned char *,pixels); \ |
349 | 16.0k | ThrowReaderException(code_,reason_,image_); \ |
350 | 0 | } |
351 | | |
352 | | static Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception) |
353 | 20.9k | { |
354 | 20.9k | int |
355 | 20.9k | record_type; |
356 | | |
357 | 20.9k | char |
358 | 20.9k | tag[3]; |
359 | | |
360 | 20.9k | Image |
361 | 20.9k | *image; |
362 | | |
363 | 20.9k | IndexPacket |
364 | 20.9k | index; |
365 | | |
366 | 20.9k | long |
367 | 20.9k | offset; |
368 | | |
369 | 20.9k | PDBImage |
370 | 20.9k | pdb_image; |
371 | | |
372 | 20.9k | PDBInfo |
373 | 20.9k | pdb_info; |
374 | | |
375 | 20.9k | register IndexPacket |
376 | 20.9k | *indexes; |
377 | | |
378 | 20.9k | unsigned long |
379 | 20.9k | y; |
380 | | |
381 | 20.9k | register unsigned long |
382 | 20.9k | x; |
383 | | |
384 | 20.9k | register PixelPacket |
385 | 20.9k | *q; |
386 | | |
387 | 20.9k | register unsigned char |
388 | 20.9k | *p; |
389 | | |
390 | 20.9k | size_t |
391 | 20.9k | count; |
392 | | |
393 | 20.9k | unsigned char |
394 | 20.9k | *pixels = (unsigned char *) NULL; |
395 | | |
396 | 20.9k | unsigned int |
397 | 20.9k | bits_per_pixel, |
398 | 20.9k | status; |
399 | | |
400 | 20.9k | size_t |
401 | 20.9k | packets; |
402 | | |
403 | | /* |
404 | | Open image file. |
405 | | */ |
406 | 20.9k | assert(image_info != (const ImageInfo *) NULL); |
407 | 20.9k | assert(image_info->signature == MagickSignature); |
408 | 20.9k | assert(exception != (ExceptionInfo *) NULL); |
409 | 20.9k | assert(exception->signature == MagickSignature); |
410 | 20.9k | image=AllocateImage(image_info); |
411 | 20.9k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
412 | 20.9k | if (status == False) |
413 | 20.9k | ThrowPDBReaderException(FileOpenError,UnableToOpenFile,image); |
414 | | /* |
415 | | Determine if this is a PDB image file. |
416 | | */ |
417 | 20.9k | count=ReadBlob(image,32,pdb_info.name); |
418 | 20.9k | if (count != 32) |
419 | 20.9k | ThrowPDBReaderException(CorruptImageError,ImproperImageHeader,image); |
420 | 20.9k | pdb_info.name[sizeof(pdb_info.name)-1]='\0'; |
421 | 20.9k | pdb_info.attributes=ReadBlobMSBShort(image); |
422 | 20.9k | pdb_info.version=ReadBlobMSBShort(image); |
423 | 20.9k | pdb_info.create_time=ReadBlobMSBLong(image); |
424 | 20.9k | pdb_info.modify_time=ReadBlobMSBLong(image); |
425 | 20.9k | pdb_info.archive_time=ReadBlobMSBLong(image); |
426 | 20.9k | pdb_info.modify_number=ReadBlobMSBLong(image); |
427 | 20.9k | pdb_info.application_info=ReadBlobMSBLong(image); |
428 | 20.9k | pdb_info.sort_info=ReadBlobMSBLong(image); |
429 | 20.9k | if ((ReadBlob(image,4,pdb_info.type) != 4) || |
430 | 20.9k | (ReadBlob(image,4,pdb_info.id) != 4)) |
431 | 20.8k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
432 | 20.8k | pdb_info.seed=ReadBlobMSBLong(image); |
433 | 20.8k | pdb_info.next_record=ReadBlobMSBLong(image); |
434 | 20.8k | pdb_info.number_records=ReadBlobMSBShort(image); |
435 | 20.8k | if (image->logging) |
436 | 20.8k | LogPDPInfo(&pdb_info); |
437 | 20.8k | if ((memcmp(pdb_info.type,"vIMG",4) != 0) || |
438 | 20.8k | (memcmp(pdb_info.id,"View",4) != 0)) |
439 | 20.8k | ThrowPDBReaderException(CorruptImageError,ImproperImageHeader,image); |
440 | 20.8k | if (pdb_info.next_record != 0) |
441 | 18.2k | ThrowPDBReaderException(CoderError,MultipleRecordListNotSupported,image); |
442 | | /* |
443 | | Read record header. |
444 | | */ |
445 | 18.2k | offset=(long) ReadBlobMSBLong(image); |
446 | 18.2k | if (ReadBlob(image,3,tag) != 3) |
447 | 14.0k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
448 | 14.0k | record_type=ReadBlobByte(image); |
449 | 14.0k | if (((record_type != 0x00) && (record_type != 0x01)) || |
450 | 13.9k | (memcmp(tag,"\x40\x6f\x80",3) != 0)) |
451 | 7.88k | ThrowPDBReaderException(CorruptImageError,CorruptImage,image); |
452 | 7.88k | if ((offset-TellBlob(image)) == 6) |
453 | 9 | { |
454 | 9 | (void) ReadBlobByte(image); |
455 | 9 | (void) ReadBlobByte(image); |
456 | 9 | } |
457 | 7.88k | if (pdb_info.number_records > 1) |
458 | 4.63k | { |
459 | 4.63k | offset=(long) ReadBlobMSBLong(image); |
460 | 4.63k | (void) ReadBlob(image,3,tag); |
461 | 4.63k | record_type=ReadBlobByte(image); |
462 | 4.63k | if (((record_type != 0x00) && (record_type != 0x01)) || |
463 | 3.96k | (memcmp(tag,"\x40\x6f\x80",3) != 0)) |
464 | 3.29k | ThrowPDBReaderException(CorruptImageError,CorruptImage,image); |
465 | 1.34k | if ((offset-TellBlob(image)) == 6) |
466 | 38 | { |
467 | 38 | (void) ReadBlobByte(image); |
468 | 38 | (void) ReadBlobByte(image); |
469 | 38 | } |
470 | 1.34k | } |
471 | | /* |
472 | | Read image header. |
473 | | */ |
474 | 4.59k | (void) ReadBlob(image,32,pdb_image.name); |
475 | 4.59k | pdb_image.version=ReadBlobByte(image); |
476 | 4.59k | pdb_image.type=ReadBlobByte(image); |
477 | 4.59k | pdb_image.reserved_1=ReadBlobMSBLong(image); |
478 | 4.59k | pdb_image.note=ReadBlobMSBLong(image); |
479 | 4.59k | pdb_image.x_last=ReadBlobMSBShort(image); |
480 | 4.59k | pdb_image.y_last=ReadBlobMSBShort(image); |
481 | 4.59k | pdb_image.reserved_2=ReadBlobMSBLong(image); |
482 | 4.59k | pdb_image.x_anchor=ReadBlobMSBShort(image); |
483 | 4.59k | pdb_image.y_anchor=ReadBlobMSBShort(image); |
484 | 4.59k | pdb_image.width=ReadBlobMSBShort(image); |
485 | 4.59k | pdb_image.height=ReadBlobMSBShort(image); |
486 | 4.59k | if (image->logging) |
487 | 4.59k | LogPDPImage(&pdb_image); |
488 | | /* |
489 | | Initialize image structure. |
490 | | */ |
491 | 4.59k | image->columns=pdb_image.width; |
492 | 4.59k | image->rows=pdb_image.height; |
493 | 4.59k | image->depth=8; |
494 | 4.59k | image->storage_class=PseudoClass; |
495 | 4.59k | bits_per_pixel=pdb_image.type == 0 ? 2 : pdb_image.type == 2 ? 4 : 1; |
496 | 4.59k | if (!AllocateImageColormap(image,1 << bits_per_pixel)) |
497 | 4.59k | ThrowPDBReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
498 | 4.59k | if (image_info->ping) |
499 | 0 | { |
500 | 0 | CloseBlob(image); |
501 | 0 | StopTimer(&image->timer); |
502 | 0 | return(image); |
503 | 0 | } |
504 | | |
505 | 4.59k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
506 | 3.81k | ThrowPDBReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
507 | | |
508 | 775 | packets=MagickArraySize(MagickArraySize(bits_per_pixel,image->columns)/8, |
509 | 775 | image->rows); |
510 | 775 | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,packets + (packets != 0 ? 256 : 0)); |
511 | 775 | if (pixels == (unsigned char *) NULL) |
512 | 773 | ThrowPDBReaderException(ResourceLimitWarning,MemoryAllocationFailed,image); |
513 | 773 | (void) memset(pixels,0,packets+256); |
514 | 773 | switch (pdb_image.version) |
515 | 773 | { |
516 | 315 | case 0: |
517 | 315 | { |
518 | 315 | image->compression=NoCompression; |
519 | 315 | if (ReadBlob(image,packets,(char *) pixels) != packets) |
520 | 115 | { |
521 | 115 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
522 | 115 | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
523 | 0 | } |
524 | 200 | break; |
525 | 315 | } |
526 | 454 | case 1: |
527 | 454 | { |
528 | 454 | image->compression=RLECompression; |
529 | 454 | if (DecodeImage(image,pixels,packets) == MagickFail) |
530 | 374 | ThrowPDBReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
531 | 374 | break; |
532 | 454 | } |
533 | 4 | default: |
534 | 4 | { |
535 | 4 | ThrowPDBReaderException(CorruptImageError,UnrecognizedImageCompression,image); |
536 | 0 | } |
537 | 773 | } |
538 | 574 | p=pixels; |
539 | 574 | switch (bits_per_pixel) |
540 | 574 | { |
541 | 128 | case 1: |
542 | 128 | { |
543 | 128 | int |
544 | 128 | bit; |
545 | | |
546 | | /* |
547 | | Read 1-bit PDB image. |
548 | | */ |
549 | 52.6k | for (y=0; y < image->rows; y++) |
550 | 52.5k | { |
551 | 52.5k | q=SetImagePixels(image,0,y,image->columns,1); |
552 | 52.5k | if (q == (PixelPacket *) NULL) |
553 | 0 | break; |
554 | 52.5k | indexes=AccessMutableIndexes(image); |
555 | 52.5k | bit=0; |
556 | 25.1M | for (x=0; x < image->columns; x++) |
557 | 25.0M | { |
558 | 25.0M | index=(*p & (0x80U >> bit) ? 0x00U : 0x01U); |
559 | 25.0M | indexes[x]=index; |
560 | 25.0M | *q++=image->colormap[index]; |
561 | 25.0M | bit++; |
562 | 25.0M | if (bit == 8) |
563 | 3.11M | { |
564 | 3.11M | p++; |
565 | 3.11M | bit=0; |
566 | 3.11M | } |
567 | 25.0M | } |
568 | 52.5k | if (!SyncImagePixels(image)) |
569 | 0 | break; |
570 | 52.5k | if (QuantumTick(y,image->rows)) |
571 | 7.99k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
572 | 7.99k | image->filename, |
573 | 7.99k | image->columns,image->rows)) |
574 | 0 | break; |
575 | 52.5k | } |
576 | 128 | break; |
577 | 0 | } |
578 | 372 | case 2: |
579 | 372 | { |
580 | | /* |
581 | | Read 2-bit PDB image. |
582 | | */ |
583 | 372 | unsigned int |
584 | 372 | shift; |
585 | | |
586 | 223k | for (y=0; y < image->rows; y++) |
587 | 223k | { |
588 | 223k | q=SetImagePixels(image,0,y,image->columns,1); |
589 | 223k | if (q == (PixelPacket *) NULL) |
590 | 0 | break; |
591 | 223k | indexes=AccessMutableIndexes(image); |
592 | 223k | shift = 8; |
593 | 177M | for (x=0; x < image->columns; x++) |
594 | 177M | { |
595 | 177M | shift -= 2; |
596 | 177M | index=(IndexPacket) (3-((*p >> shift) & 0x03)); |
597 | 177M | VerifyColormapIndex(status,image,index); |
598 | 177M | indexes[x]=index; |
599 | 177M | *q++=image->colormap[index]; |
600 | 177M | if (shift == 0) |
601 | 44.3M | { |
602 | 44.3M | shift = 8; |
603 | 44.3M | p++; |
604 | 44.3M | } |
605 | 177M | } |
606 | 223k | if (!SyncImagePixels(image)) |
607 | 0 | break; |
608 | 223k | if (QuantumTick(y,image->rows)) |
609 | 18.4k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
610 | 18.4k | image->filename, |
611 | 18.4k | image->columns,image->rows)) |
612 | 0 | break; |
613 | 223k | } |
614 | 372 | break; |
615 | 0 | } |
616 | 74 | case 4: |
617 | 74 | { |
618 | | /* |
619 | | Read 4-bit PDB image. |
620 | | */ |
621 | 74 | unsigned int |
622 | 74 | shift; |
623 | | |
624 | 27.1k | for (y=0; y < image->rows; y++) |
625 | 27.0k | { |
626 | 27.0k | q=SetImagePixels(image,0,y,image->columns,1); |
627 | 27.0k | if (q == (PixelPacket *) NULL) |
628 | 0 | break; |
629 | 27.0k | indexes=AccessMutableIndexes(image); |
630 | 27.0k | shift = 8; |
631 | 171k | for (x=0; x < image->columns; x++) |
632 | 144k | { |
633 | 144k | shift -= 4; |
634 | 144k | index=(IndexPacket) (15-((*p >> shift) & 0x0f)); |
635 | 144k | VerifyColormapIndex(status,image,index); |
636 | 144k | indexes[x]=index; |
637 | 144k | *q++=image->colormap[index]; |
638 | 144k | if (shift == 0) |
639 | 66.1k | { |
640 | 66.1k | shift = 8; |
641 | 66.1k | p++; |
642 | 66.1k | } |
643 | 144k | } |
644 | 27.0k | if (!SyncImagePixels(image)) |
645 | 0 | break; |
646 | 27.0k | if (QuantumTick(y,image->rows)) |
647 | 5.55k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
648 | 5.55k | image->filename, |
649 | 5.55k | image->columns,image->rows)) |
650 | 0 | break; |
651 | 27.0k | } |
652 | 74 | break; |
653 | 0 | } |
654 | 0 | default: |
655 | 0 | { |
656 | 0 | ThrowPDBReaderException(CorruptImageError,ImproperImageHeader,image); |
657 | 0 | } |
658 | 574 | } |
659 | 574 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
660 | 574 | if (EOFBlob(image)) |
661 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
662 | 574 | image->filename); |
663 | 574 | if ((offset-TellBlob(image)) == 0) |
664 | 163 | { |
665 | 163 | char |
666 | 163 | *comment; |
667 | | |
668 | 163 | int |
669 | 163 | c; |
670 | | |
671 | 163 | size_t |
672 | 163 | length; |
673 | | |
674 | | /* |
675 | | Read comment. |
676 | | */ |
677 | 163 | c=ReadBlobByte(image); |
678 | 163 | length=MaxTextExtent; |
679 | 163 | comment=MagickAllocateResourceLimitedMemory(char *,length+1); |
680 | 163 | if (comment != (char *) NULL) |
681 | 163 | { |
682 | 163 | register char |
683 | 163 | *p=comment; |
684 | | |
685 | 163 | p[0]='\0'; |
686 | 19.7M | for ( ; c != EOF; p++) |
687 | 19.7M | { |
688 | 19.7M | if ((size_t) (p-comment) >= length) |
689 | 9.21k | { |
690 | 9.21k | char |
691 | 9.21k | *new_comment; |
692 | | |
693 | 9.21k | length+=MaxTextExtent; |
694 | 9.21k | new_comment=MagickReallocateResourceLimitedMemory(char *,comment,length+1); |
695 | 9.21k | if (new_comment == (char *) NULL) |
696 | 0 | { |
697 | 0 | MagickFreeResourceLimitedMemory(char *,comment); |
698 | 0 | break; |
699 | 0 | } |
700 | 9.21k | comment=new_comment; |
701 | 9.21k | p=comment+strlen(comment); |
702 | 9.21k | } |
703 | 19.7M | *p=c; |
704 | 19.7M | *(p+1)='\0'; |
705 | 19.7M | c=ReadBlobByte(image); |
706 | 19.7M | } |
707 | 163 | } |
708 | 163 | if (comment == (char *) NULL) |
709 | 163 | ThrowPDBReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
710 | 163 | (void) SetImageAttribute(image,"comment",comment); |
711 | 163 | MagickFreeResourceLimitedMemory(char *,comment); |
712 | 163 | } |
713 | 574 | CloseBlob(image); |
714 | 574 | StopTimer(&image->timer); |
715 | 574 | return(image); |
716 | 574 | } |
717 | | |
718 | | /* |
719 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
720 | | % % |
721 | | % % |
722 | | % % |
723 | | % R e g i s t e r P D B I m a g e % |
724 | | % % |
725 | | % % |
726 | | % % |
727 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
728 | | % |
729 | | % Method RegisterPDBImage adds attributes for the PDB image format to |
730 | | % the list of supported formats. The attributes include the image format |
731 | | % tag, a method to read and/or write the format, whether the format |
732 | | % supports the saving of more than one frame to the same file or blob, |
733 | | % whether the format supports native in-memory I/O, and a brief |
734 | | % description of the format. |
735 | | % |
736 | | % The format of the RegisterPDBImage method is: |
737 | | % |
738 | | % RegisterPDBImage(void) |
739 | | % |
740 | | */ |
741 | | ModuleExport void RegisterPDBImage(void) |
742 | 4 | { |
743 | 4 | MagickInfo |
744 | 4 | *entry; |
745 | | |
746 | 4 | entry=SetMagickInfo("PDB"); |
747 | 4 | entry->decoder=(DecoderHandler) ReadPDBImage; |
748 | 4 | entry->encoder=(EncoderHandler) WritePDBImage; |
749 | 4 | entry->magick=(MagickHandler) IsPDB; |
750 | 4 | entry->description="Palm Database ImageViewer Format"; |
751 | 4 | entry->module="PDB"; |
752 | 4 | entry->coder_class=UnstableCoderClass; |
753 | 4 | (void) RegisterMagickInfo(entry); |
754 | 4 | } |
755 | | |
756 | | /* |
757 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
758 | | % % |
759 | | % % |
760 | | % % |
761 | | % U n r e g i s t e r P D B I m a g e % |
762 | | % % |
763 | | % % |
764 | | % % |
765 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
766 | | % |
767 | | % Method UnregisterPDBImage removes format registrations made by the |
768 | | % PDB module from the list of supported formats. |
769 | | % |
770 | | % The format of the UnregisterPDBImage method is: |
771 | | % |
772 | | % UnregisterPDBImage(void) |
773 | | % |
774 | | */ |
775 | | ModuleExport void UnregisterPDBImage(void) |
776 | 0 | { |
777 | 0 | (void) UnregisterMagickInfo("PDB"); |
778 | 0 | } |
779 | | |
780 | | /* |
781 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
782 | | % % |
783 | | % % |
784 | | % % |
785 | | % W r i t e P D B I m a g e % |
786 | | % % |
787 | | % % |
788 | | % % |
789 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
790 | | % |
791 | | % Method WritePDBImage writes an image |
792 | | % |
793 | | % The format of the WritePDBImage method is: |
794 | | % |
795 | | % unsigned int WritePDBImage(const ImageInfo *image_info,Image *image) |
796 | | % |
797 | | % A description of each parameter follows. |
798 | | % |
799 | | % o status: Method WritePDBImage return True if the image is written. |
800 | | % False is returned is there is a memory shortage or if the image file |
801 | | % fails to write. |
802 | | % |
803 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
804 | | % |
805 | | % o image: A pointer to an Image structure. |
806 | | % |
807 | | % |
808 | | */ |
809 | | |
810 | | static unsigned char *EncodeRLE(unsigned char *destination, |
811 | | unsigned char *source,unsigned int literal,unsigned int repeat) |
812 | 9.62M | { |
813 | 9.62M | if (literal != 0) |
814 | 8.97M | *destination++=literal-1; |
815 | 9.62M | (void) memcpy(destination,source,literal); |
816 | 9.62M | destination+=literal; |
817 | 9.62M | if (repeat != 0) |
818 | 322k | { |
819 | 322k | *destination++=0x80 | (repeat-1); |
820 | 322k | *destination++=source[literal]; |
821 | 322k | } |
822 | 9.62M | return(destination); |
823 | 9.62M | } |
824 | | |
825 | | #define ThrowPDBWriterException(code_,reason_,image_) \ |
826 | 0 | { \ |
827 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,buffer); \ |
828 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,p); \ |
829 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,scanline); \ |
830 | 0 | ThrowWriterException(code_,reason_,image_); \ |
831 | 0 | } |
832 | | |
833 | | static unsigned int WritePDBImage(const ImageInfo *image_info,Image *image) |
834 | 571 | { |
835 | 571 | int |
836 | 571 | bits; |
837 | | |
838 | 571 | unsigned long |
839 | 571 | y; |
840 | | |
841 | 571 | PDBImage |
842 | 571 | pdb_image; |
843 | | |
844 | 571 | PDBInfo |
845 | 571 | pdb_info; |
846 | | |
847 | 571 | register long |
848 | 571 | x; |
849 | | |
850 | 571 | unsigned char |
851 | 571 | *buffer = (unsigned char *) NULL, |
852 | 571 | *p = (unsigned char *) NULL, |
853 | 571 | *q, |
854 | 571 | *scanline = (unsigned char *) NULL; |
855 | | |
856 | 571 | unsigned int |
857 | 571 | bits_per_pixel, |
858 | 571 | packet_size, |
859 | 571 | status; |
860 | | |
861 | 571 | size_t |
862 | 571 | packets; |
863 | | |
864 | 571 | unsigned long |
865 | 571 | literal, |
866 | 571 | repeat; |
867 | | |
868 | 571 | const ImageAttribute |
869 | 571 | *comment; |
870 | | |
871 | 571 | if (image->logging) |
872 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
873 | 0 | "Dimensions: %lux%lu", |
874 | 0 | image->columns,image->rows); |
875 | | |
876 | | /* |
877 | | Open output image file. |
878 | | */ |
879 | 571 | assert(image_info != (const ImageInfo *) NULL); |
880 | 571 | assert(image_info->signature == MagickSignature); |
881 | 571 | assert(image != (Image *) NULL); |
882 | 571 | assert(image->signature == MagickSignature); |
883 | | |
884 | 571 | if (TransformColorspace(image,RGBColorspace) == MagickFail) |
885 | 0 | return MagickFail; |
886 | 571 | if (SetImageType(image,GrayscaleType) == MagickFail) |
887 | 0 | return MagickFail; |
888 | | |
889 | 571 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
890 | 571 | if (status == False) |
891 | 571 | ThrowPDBWriterException(FileOpenError,UnableToOpenFile,image); |
892 | 571 | bits_per_pixel=image->depth; |
893 | 571 | if (GetImageType(image,&image->exception) == BilevelType) |
894 | 128 | bits_per_pixel=1; |
895 | 571 | if ((bits_per_pixel != 1) && (bits_per_pixel != 2)) |
896 | 443 | bits_per_pixel=4; |
897 | 571 | (void) memset(&pdb_info,0,sizeof(pdb_info)); |
898 | 571 | (void) strlcpy(pdb_info.name,image_info->filename,sizeof(pdb_info.name)); |
899 | 571 | pdb_info.attributes=0; |
900 | 571 | pdb_info.version=0; |
901 | 571 | pdb_info.create_time=time(NULL); |
902 | 571 | pdb_info.modify_time=pdb_info.create_time; |
903 | 571 | pdb_info.archive_time=0; |
904 | 571 | pdb_info.modify_number=0; |
905 | 571 | pdb_info.application_info=0; |
906 | 571 | pdb_info.sort_info=0; |
907 | 571 | (void) memcpy(pdb_info.type,"vIMG",4); |
908 | 571 | (void) memcpy(pdb_info.id,"View",4); |
909 | 571 | pdb_info.seed=0; |
910 | 571 | pdb_info.next_record=0; |
911 | 571 | comment=GetImageAttribute(image,"comment"); |
912 | 571 | pdb_info.number_records=1; |
913 | 571 | if ((comment != (ImageAttribute *) NULL) && (comment->value != (char *) NULL)) |
914 | 160 | pdb_info.number_records++; |
915 | 571 | if (image->logging) |
916 | 0 | LogPDPInfo(&pdb_info); |
917 | 571 | (void) WriteBlob(image,32,pdb_info.name); |
918 | 571 | (void) WriteBlobMSBShort(image,pdb_info.attributes); |
919 | 571 | (void) WriteBlobMSBShort(image,pdb_info.version); |
920 | 571 | (void) WriteBlobMSBLong(image,pdb_info.create_time); |
921 | 571 | (void) WriteBlobMSBLong(image,pdb_info.modify_time); |
922 | 571 | (void) WriteBlobMSBLong(image,pdb_info.archive_time); |
923 | 571 | (void) WriteBlobMSBLong(image,pdb_info.modify_number); |
924 | 571 | (void) WriteBlobMSBLong(image,pdb_info.application_info); |
925 | 571 | (void) WriteBlobMSBLong(image,pdb_info.sort_info); |
926 | 571 | (void) WriteBlob(image,4,pdb_info.type); |
927 | 571 | (void) WriteBlob(image,4,pdb_info.id); |
928 | 571 | (void) WriteBlobMSBLong(image,pdb_info.seed); |
929 | 571 | (void) WriteBlobMSBLong(image,pdb_info.next_record); |
930 | 571 | (void) WriteBlobMSBShort(image,pdb_info.number_records); |
931 | 571 | (void) memset(&pdb_image,0,sizeof(pdb_image)); |
932 | 571 | (void) strlcpy(pdb_image.name,pdb_info.name,sizeof(pdb_image.name)); |
933 | 571 | pdb_image.version=1; /* RLE Compressed */ |
934 | 571 | switch(bits_per_pixel) |
935 | 571 | { |
936 | 128 | case 1: pdb_image.type=0xffU; break; /* monochrome */ |
937 | 0 | case 2: pdb_image.type=0x00U; break; /* 2 bit gray */ |
938 | 443 | default: pdb_image.type=0x02U; /* 4 bit gray */ |
939 | 571 | } |
940 | 571 | pdb_image.reserved_1=0; |
941 | 571 | pdb_image.note=0; |
942 | 571 | pdb_image.x_last=0; |
943 | 571 | pdb_image.y_last=0; |
944 | 571 | pdb_image.reserved_2=0; |
945 | 571 | pdb_image.x_anchor=(short) 0xffff; |
946 | 571 | pdb_image.y_anchor=(short) 0xffff; |
947 | 571 | pdb_image.width=(short) image->columns; |
948 | 571 | if (image->columns % 16) |
949 | 540 | pdb_image.width=(short) (16*(image->columns/16+1)); |
950 | 571 | pdb_image.height=(short) image->rows; |
951 | 571 | if (image->logging) |
952 | 0 | LogPDPImage(&pdb_image); |
953 | 571 | if ((pdb_image.width < image->columns) || |
954 | 571 | (pdb_image.height != image->rows)) |
955 | 571 | ThrowPDBWriterException(CoderError,ImageColumnOrRowSizeIsNotSupported, image); |
956 | 571 | packets=MagickArraySize(MagickArraySize(MagickArraySize(bits_per_pixel, |
957 | 571 | pdb_image.width)/8, |
958 | 571 | pdb_image.height),2); |
959 | 571 | p=MagickAllocateResourceLimitedMemory(unsigned char *,packets); |
960 | 571 | if (p == (unsigned char *) NULL) |
961 | 571 | ThrowPDBWriterException(ResourceLimitWarning,MemoryAllocationFailed,image); |
962 | 571 | buffer=MagickAllocateResourceLimitedMemory(unsigned char *,512); |
963 | 571 | if (buffer == (unsigned char *) NULL) |
964 | 571 | ThrowPDBWriterException(ResourceLimitWarning,MemoryAllocationFailed,image); |
965 | 571 | (void) memset(buffer,0,512); |
966 | 571 | packet_size=bits_per_pixel > 8 ? 2: 1; |
967 | 571 | scanline=MagickAllocateResourceLimitedArray(unsigned char *,image->columns,packet_size); |
968 | 571 | if (scanline == (unsigned char *) NULL) |
969 | 571 | ThrowPDBWriterException(ResourceLimitWarning,MemoryAllocationFailed,image); |
970 | 571 | if (TransformColorspace(image,RGBColorspace) == MagickFail) |
971 | 571 | ThrowPDBWriterException(CoderError,UnableToTransformColorspace,image); |
972 | | /* |
973 | | Convert to GRAY raster scanline. |
974 | | */ |
975 | 571 | bits=8/(long) bits_per_pixel-1; /* start at most significant bits */ |
976 | 571 | literal=0; |
977 | 571 | repeat=0; |
978 | 571 | q=p; |
979 | 571 | buffer[0]=0x00; |
980 | 303k | for (y=0; y < image->rows; y++) |
981 | 302k | { |
982 | 302k | if (!AcquireImagePixels(image,0,y,image->columns,1,&image->exception)) |
983 | 0 | break; |
984 | 302k | (void) memset(scanline,0, (size_t) image->columns*packet_size); /* FIXME: remove */ |
985 | 302k | (void) ExportImagePixelArea(image,GrayQuantum,bits_per_pixel,scanline,0,0); |
986 | 205M | for (x=0; x < pdb_image.width; x++) |
987 | 205M | { |
988 | 205M | if (x < (long) image->columns) |
989 | 202M | buffer[literal+repeat]|=(0xff-scanline[x*packet_size]) >> |
990 | 202M | (8-bits_per_pixel) << bits*bits_per_pixel; |
991 | 205M | bits--; |
992 | 205M | if (bits < 0) |
993 | 93.1M | { |
994 | 93.1M | if (((literal+repeat) > 0) && |
995 | 92.7M | (buffer[literal+repeat] == buffer[literal+repeat-1])) |
996 | 82.5M | { |
997 | 82.5M | if (repeat == 0) |
998 | 1.73M | { |
999 | 1.73M | literal--; |
1000 | 1.73M | repeat++; |
1001 | 1.73M | } |
1002 | 82.5M | repeat++; |
1003 | 82.5M | if (0x7f < repeat) |
1004 | 321k | { |
1005 | 321k | q=EncodeRLE(q,buffer,literal,repeat); |
1006 | 321k | literal=0; |
1007 | 321k | repeat=0; |
1008 | 321k | } |
1009 | 82.5M | } |
1010 | 10.5M | else |
1011 | 10.5M | { |
1012 | 10.5M | if (repeat >= 2) |
1013 | 1.41M | literal+=repeat; |
1014 | 9.13M | else |
1015 | 9.13M | { |
1016 | 9.13M | q=EncodeRLE(q,buffer,literal,repeat); |
1017 | 9.13M | buffer[0]=buffer[literal+repeat]; |
1018 | 9.13M | literal=0; |
1019 | 9.13M | } |
1020 | 10.5M | literal++; |
1021 | 10.5M | repeat=0; |
1022 | 10.5M | if (0x7f < literal) |
1023 | 162k | { |
1024 | 162k | q=EncodeRLE(q,buffer,(literal < 0x80 ? literal : 0x80),0); |
1025 | 162k | (void) memmove(buffer,buffer+literal+repeat,0x80); |
1026 | 162k | literal-=0x80; |
1027 | 162k | } |
1028 | 10.5M | } |
1029 | 93.1M | bits=8/(long) bits_per_pixel-1; |
1030 | 93.1M | buffer[literal+repeat]=0x00; |
1031 | 93.1M | } |
1032 | 205M | } |
1033 | 302k | if (QuantumTick(y,image->rows)) |
1034 | 31.9k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1035 | 31.9k | SaveImageText,image->filename, |
1036 | 31.9k | image->columns,image->rows)) |
1037 | 0 | break; |
1038 | 302k | } |
1039 | 571 | q=EncodeRLE(q,buffer,literal,repeat); |
1040 | 571 | MagickFreeResourceLimitedMemory(unsigned char *,scanline); |
1041 | 571 | MagickFreeResourceLimitedMemory(unsigned char *,buffer); |
1042 | | /* |
1043 | | Write the Image record header. |
1044 | | */ |
1045 | 571 | (void) WriteBlobMSBLong(image,(magick_uint32_t) |
1046 | 571 | (TellBlob(image)+(size_t)8*pdb_info.number_records)); |
1047 | 571 | (void) WriteBlobByte(image,0x40); |
1048 | 571 | (void) WriteBlobByte(image,0x6f); |
1049 | 571 | (void) WriteBlobByte(image,0x80); |
1050 | 571 | (void) WriteBlobByte(image,0); |
1051 | 571 | if (pdb_info.number_records > 1) |
1052 | 160 | { |
1053 | | /* |
1054 | | Write the comment record header. |
1055 | | */ |
1056 | 160 | (void) WriteBlobMSBLong(image,TellBlob(image)+8+58+q-p); |
1057 | 160 | (void) WriteBlobByte(image,0x40); |
1058 | 160 | (void) WriteBlobByte(image,0x6f); |
1059 | 160 | (void) WriteBlobByte(image,0x80); |
1060 | 160 | (void) WriteBlobByte(image,1); |
1061 | 160 | } |
1062 | | /* |
1063 | | Write the Image data. |
1064 | | */ |
1065 | 571 | (void) WriteBlob(image,32,pdb_image.name); |
1066 | 571 | (void) WriteBlobByte(image,pdb_image.version); |
1067 | 571 | (void) WriteBlobByte(image,pdb_image.type); |
1068 | 571 | (void) WriteBlobMSBLong(image,pdb_image.reserved_1); |
1069 | 571 | (void) WriteBlobMSBLong(image,pdb_image.note); |
1070 | 571 | (void) WriteBlobMSBShort(image,pdb_image.x_last); |
1071 | 571 | (void) WriteBlobMSBShort(image,pdb_image.y_last); |
1072 | 571 | (void) WriteBlobMSBLong(image,pdb_image.reserved_2); |
1073 | 571 | (void) WriteBlobMSBShort(image,pdb_image.x_anchor); |
1074 | 571 | (void) WriteBlobMSBShort(image,pdb_image.y_anchor); |
1075 | 571 | (void) WriteBlobMSBShort(image,pdb_image.width); |
1076 | 571 | (void) WriteBlobMSBShort(image,pdb_image.height); |
1077 | 571 | (void) WriteBlob(image,q-p,p); |
1078 | 571 | MagickFreeResourceLimitedMemory(unsigned char *,p); |
1079 | 571 | if ((comment != (ImageAttribute *) NULL) && (comment->value != (char *) NULL)) |
1080 | 160 | (void) WriteBlobString(image,comment->value); |
1081 | 571 | status &= CloseBlob(image); |
1082 | 571 | return(status); |
1083 | 571 | } |