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