blob: 428f040d7dc664a048a24c231f0a08c8c6d55ee7 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% PPPP DDDD BBBB %
7% P P D D B B %
8% PPPP D D BBBB %
9% P D D B B %
10% P DDDD BBBB %
11% %
12% %
13% Read/Write Palm Database ImageViewer Image Format %
14% %
15% Software Design %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
Cristyf6ff9ea2016-12-05 09:53:35 -050020% Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
Cristyf19d4142017-04-24 11:34:30 -040026% https://www.imagemagick.org/script/license.php %
cristy3ed852e2009-09-05 21:47:34 +000027% %
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%
cristy98cba562014-11-20 23:46:19 +000037% 20071202 TS * rewrote RLE decoder - old version could cause buffer overflows
38% * failure of RLE decoding now thows error RLEDecoderError
39% * fixed bug in RLE decoding - now all rows are decoded, not just
40% the first one
41% * fixed bug in reader - record offsets now handled correctly
42% * fixed bug in reader - only bits 0..2 indicate compression type
43% * in writer: now using image color count instead of depth
cristy3ed852e2009-09-05 21:47:34 +000044*/
45
46/*
47 Include declarations.
48*/
cristy4c08aed2011-07-01 19:47:50 +000049#include "MagickCore/studio.h"
50#include "MagickCore/attribute.h"
51#include "MagickCore/blob.h"
52#include "MagickCore/blob-private.h"
53#include "MagickCore/cache.h"
54#include "MagickCore/colormap-private.h"
55#include "MagickCore/color-private.h"
56#include "MagickCore/colormap.h"
57#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000058#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/constitute.h"
60#include "MagickCore/exception.h"
61#include "MagickCore/exception-private.h"
62#include "MagickCore/image.h"
63#include "MagickCore/image-private.h"
64#include "MagickCore/list.h"
65#include "MagickCore/magick.h"
66#include "MagickCore/memory_.h"
67#include "MagickCore/monitor.h"
68#include "MagickCore/monitor-private.h"
69#include "MagickCore/pixel-accessor.h"
70#include "MagickCore/property.h"
71#include "MagickCore/quantum-private.h"
72#include "MagickCore/quantum-private.h"
73#include "MagickCore/static.h"
74#include "MagickCore/string_.h"
75#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000076
77/*
78 Typedef declarations.
79*/
80typedef struct _PDBInfo
81{
82 char
83 name[32];
84
85 short int
86 attributes,
87 version;
88
cristybb503372010-05-27 20:51:26 +000089 size_t
cristy3ed852e2009-09-05 21:47:34 +000090 create_time,
91 modify_time,
92 archive_time,
93 modify_number,
94 application_info,
95 sort_info;
96
97 char
98 type[4], /* database type identifier "vIMG" */
99 id[4]; /* database creator identifier "View" */
100
cristybb503372010-05-27 20:51:26 +0000101 size_t
cristy3ed852e2009-09-05 21:47:34 +0000102 seed,
103 next_record;
104
105 short int
106 number_records;
107} PDBInfo;
108
109typedef struct _PDBImage
110{
111 char
112 name[32],
dirk93b02b72013-11-16 16:03:36 +0000113 version;
cristy3ed852e2009-09-05 21:47:34 +0000114
cristybb503372010-05-27 20:51:26 +0000115 size_t
cristy3ed852e2009-09-05 21:47:34 +0000116 reserved_1,
117 note;
118
119 short int
120 x_last,
121 y_last;
122
cristybb503372010-05-27 20:51:26 +0000123 size_t
cristy3ed852e2009-09-05 21:47:34 +0000124 reserved_2;
125
126 short int
cristy3ed852e2009-09-05 21:47:34 +0000127 width,
128 height;
dirk93b02b72013-11-16 16:03:36 +0000129
130 unsigned char
131 type;
132
133 unsigned short
134 x_anchor,
135 y_anchor;
cristy3ed852e2009-09-05 21:47:34 +0000136} PDBImage;
137/*
138 Forward declarations.
139*/
140static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000141 WritePDBImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000142
143/*
144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145% %
146% %
147% %
148% D e c o d e I m a g e %
149% %
150% %
151% %
152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153%
154% DecodeImage unpacks the packed image pixels into runlength-encoded
155% pixel packets.
156%
157% The format of the DecodeImage method is:
158%
159% MagickBooleanType DecodeImage(Image *image,unsigned char *pixels,
160% const size_t length)
161%
162% A description of each parameter follows:
163%
164% o image: the address of a structure of type Image.
165%
166% o pixels: The address of a byte (8 bits) array of pixel data created by
167% the decoding process.
168%
169% o length: Number of bytes to read into buffer 'pixels'.
170%
171*/
172static MagickBooleanType DecodeImage(Image *image, unsigned char *pixels,
173 const size_t length)
174{
175#define RLE_MODE_NONE -1
176#define RLE_MODE_COPY 0
177#define RLE_MODE_RUN 1
178
cristyc5de6992009-10-06 19:19:48 +0000179 int data = 0, count = 0;
180 unsigned char *p;
181 int mode = RLE_MODE_NONE;
cristy3ed852e2009-09-05 21:47:34 +0000182
cristyc5de6992009-10-06 19:19:48 +0000183 for (p = pixels; p < pixels + length; p++) {
184 if (0 == count) {
185 data = ReadBlobByte( image );
186 if (-1 == data) return MagickFalse;
187 if (data > 128) {
188 mode = RLE_MODE_RUN;
189 count = data - 128 + 1;
190 data = ReadBlobByte( image );
191 if (-1 == data) return MagickFalse;
192 } else {
193 mode = RLE_MODE_COPY;
194 count = data + 1;
195 }
196 }
cristy3ed852e2009-09-05 21:47:34 +0000197
cristyc5de6992009-10-06 19:19:48 +0000198 if (RLE_MODE_COPY == mode) {
199 data = ReadBlobByte( image );
200 if (-1 == data) return MagickFalse;
201 }
202 *p = (unsigned char)data;
203 --count;
204 }
205 return MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000206}
207
208/*
209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210% %
211% %
212% %
213% I s P D B %
214% %
215% %
216% %
217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218%
219% IsPDB() returns MagickTrue if the image format type, identified by the
220% magick string, is PDB.
221%
222% The format of the ReadPDBImage method is:
223%
224% MagickBooleanType IsPDB(const unsigned char *magick,const size_t length)
225%
226% A description of each parameter follows:
227%
228% o magick: compare image format pattern against these bytes.
229%
230% o length: Specifies the length of the magick string.
231%
232*/
233static MagickBooleanType IsPDB(const unsigned char *magick,const size_t length)
234{
235 if (length < 68)
236 return(MagickFalse);
237 if (memcmp(magick+60,"vIMGView",8) == 0)
238 return(MagickTrue);
239 return(MagickFalse);
240}
241
242/*
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244% %
245% %
246% %
247% R e a d P D B I m a g e %
248% %
249% %
250% %
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252%
253% ReadPDBImage() reads an Pilot image file and returns it. It
254% allocates the memory necessary for the new Image structure and returns a
255% pointer to the new image.
256%
257% The format of the ReadPDBImage method is:
258%
259% Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception)
260%
261% A description of each parameter follows:
262%
263% o image_info: the image info.
264%
265% o exception: return any errors or warnings in this structure.
266%
267*/
268static Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception)
269{
270 unsigned char
cristy98cba562014-11-20 23:46:19 +0000271 attributes,
cristy3ed852e2009-09-05 21:47:34 +0000272 tag[3];
273
274 Image
275 *image;
276
cristy3ed852e2009-09-05 21:47:34 +0000277 MagickBooleanType
278 status;
279
280 PDBImage
281 pdb_image;
282
283 PDBInfo
284 pdb_info;
285
cristy4c08aed2011-07-01 19:47:50 +0000286 Quantum
287 index;
cristy3ed852e2009-09-05 21:47:34 +0000288
cristybb503372010-05-27 20:51:26 +0000289 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000290 x;
291
cristy4c08aed2011-07-01 19:47:50 +0000292 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000293 *q;
294
295 register unsigned char
296 *p;
297
cristybb503372010-05-27 20:51:26 +0000298 size_t
cristy3ed852e2009-09-05 21:47:34 +0000299 bits_per_pixel,
cristy98cba562014-11-20 23:46:19 +0000300 num_pad_bytes,
cristyeaedf062010-05-29 22:36:02 +0000301 one,
cristy3ed852e2009-09-05 21:47:34 +0000302 packets;
303
cristyaff6d802011-04-26 01:46:31 +0000304 ssize_t
305 count,
cristy98cba562014-11-20 23:46:19 +0000306 img_offset,
cristyaff6d802011-04-26 01:46:31 +0000307 comment_offset = 0,
308 y;
309
310 unsigned char
311 *pixels;
312
cristy3ed852e2009-09-05 21:47:34 +0000313 /*
314 Open image file.
315 */
316 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000317 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000318 if (image_info->debug != MagickFalse)
319 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
320 image_info->filename);
321 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000322 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000323 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000324 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
325 if (status == MagickFalse)
326 {
327 image=DestroyImageList(image);
328 return((Image *) NULL);
329 }
330 /*
331 Determine if this a PDB image file.
332 */
cristyca793d72015-01-23 13:03:55 +0000333 count=ReadBlob(image,sizeof(pdb_info.name),(unsigned char *) pdb_info.name);
334 if (count != sizeof(pdb_info.name))
335 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000336 pdb_info.attributes=(short) ReadBlobMSBShort(image);
337 pdb_info.version=(short) ReadBlobMSBShort(image);
338 pdb_info.create_time=ReadBlobMSBLong(image);
339 pdb_info.modify_time=ReadBlobMSBLong(image);
340 pdb_info.archive_time=ReadBlobMSBLong(image);
341 pdb_info.modify_number=ReadBlobMSBLong(image);
342 pdb_info.application_info=ReadBlobMSBLong(image);
343 pdb_info.sort_info=ReadBlobMSBLong(image);
cristy7e5d1da2014-12-28 00:40:02 +0000344 (void) ReadBlob(image,4,(unsigned char *) pdb_info.type);
345 (void) ReadBlob(image,4,(unsigned char *) pdb_info.id);
cristy3ed852e2009-09-05 21:47:34 +0000346 pdb_info.seed=ReadBlobMSBLong(image);
347 pdb_info.next_record=ReadBlobMSBLong(image);
348 pdb_info.number_records=(short) ReadBlobMSBShort(image);
cristy7e5d1da2014-12-28 00:40:02 +0000349 if ((memcmp(pdb_info.type,"vIMG",4) != 0) ||
350 (memcmp(pdb_info.id,"View",4) != 0))
351 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000352 if (pdb_info.next_record != 0)
353 ThrowReaderException(CoderError,"MultipleRecordListNotSupported");
354 /*
355 Read record header.
356 */
Cristy1fe0b872016-04-23 10:48:31 -0400357 img_offset=(ssize_t) ReadBlobMSBSignedLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000358 attributes=(unsigned char) ReadBlobByte(image);
cristyda16f162011-02-19 23:52:17 +0000359 (void) attributes;
cristy3ed852e2009-09-05 21:47:34 +0000360 count=ReadBlob(image,3,(unsigned char *) tag);
361 if (count != 3 || memcmp(tag,"\x6f\x80\x00",3) != 0)
362 ThrowReaderException(CorruptImageError,"CorruptImage");
cristy3ed852e2009-09-05 21:47:34 +0000363 if (pdb_info.number_records > 1)
364 {
Cristy1fe0b872016-04-23 10:48:31 -0400365 comment_offset=(ssize_t) ReadBlobMSBSignedLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000366 attributes=(unsigned char) ReadBlobByte(image);
367 count=ReadBlob(image,3,(unsigned char *) tag);
368 if (count != 3 || memcmp(tag,"\x6f\x80\x01",3) != 0)
369 ThrowReaderException(CorruptImageError,"CorruptImage");
370 }
cristybb503372010-05-27 20:51:26 +0000371 num_pad_bytes = (size_t) (img_offset - TellBlob( image ));
cristy89f839d2015-01-25 17:32:32 +0000372 while (num_pad_bytes-- != 0)
373 {
374 int
375 c;
376
377 c=ReadBlobByte(image);
378 if (c == EOF)
379 break;
380 }
cristy3ed852e2009-09-05 21:47:34 +0000381 /*
382 Read image header.
383 */
cristyca793d72015-01-23 13:03:55 +0000384 count=ReadBlob(image,sizeof(pdb_image.name),(unsigned char *) pdb_image.name);
385 if (count != sizeof(pdb_image.name))
386 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000387 pdb_image.version=ReadBlobByte(image);
Cristy1fe0b872016-04-23 10:48:31 -0400388 pdb_image.type=(unsigned char) (ReadBlobByte(image));
cristy3ed852e2009-09-05 21:47:34 +0000389 pdb_image.reserved_1=ReadBlobMSBLong(image);
390 pdb_image.note=ReadBlobMSBLong(image);
391 pdb_image.x_last=(short) ReadBlobMSBShort(image);
392 pdb_image.y_last=(short) ReadBlobMSBShort(image);
393 pdb_image.reserved_2=ReadBlobMSBLong(image);
dirk93b02b72013-11-16 16:03:36 +0000394 pdb_image.x_anchor=ReadBlobMSBShort(image);
395 pdb_image.y_anchor=ReadBlobMSBShort(image);
cristy3ed852e2009-09-05 21:47:34 +0000396 pdb_image.width=(short) ReadBlobMSBShort(image);
397 pdb_image.height=(short) ReadBlobMSBShort(image);
398 /*
399 Initialize image structure.
400 */
cristybb503372010-05-27 20:51:26 +0000401 image->columns=(size_t) pdb_image.width;
402 image->rows=(size_t) pdb_image.height;
cristy3ed852e2009-09-05 21:47:34 +0000403 image->depth=8;
404 image->storage_class=PseudoClass;
405 bits_per_pixel=pdb_image.type == 0 ? 2UL : pdb_image.type == 2 ? 4UL : 1UL;
cristyeaedf062010-05-29 22:36:02 +0000406 one=1;
cristy018f07f2011-09-04 21:15:19 +0000407 if (AcquireImageColormap(image,one << bits_per_pixel,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000408 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
409 if (image_info->ping != MagickFalse)
410 {
411 (void) CloseBlob(image);
412 return(GetFirstImageInList(image));
413 }
Cristyff9bf442016-07-06 08:51:47 -0400414 status=SetImageExtent(image,image->columns,image->rows,exception);
415 if (status == MagickFalse)
416 return(DestroyImageList(image));
cristy55a26ef2014-11-29 17:16:29 +0000417 packets=(bits_per_pixel*image->columns+7)/8;
Cristy6d202a02016-03-07 07:13:10 -0500418 pixels=(unsigned char *) AcquireQuantumMemory(packets+257UL,image->rows*
cristy3ed852e2009-09-05 21:47:34 +0000419 sizeof(*pixels));
420 if (pixels == (unsigned char *) NULL)
421 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy98cba562014-11-20 23:46:19 +0000422 switch (pdb_image.version & 0x07)
cristy3ed852e2009-09-05 21:47:34 +0000423 {
424 case 0:
425 {
426 image->compression=NoCompression;
Dirk Lemstra3690a822017-05-02 08:26:55 +0200427 count=(ssize_t) ReadBlob(image,packets*image->rows,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000428 break;
429 }
430 case 1:
431 {
432 image->compression=RLECompression;
Dirk Lemstra3690a822017-05-02 08:26:55 +0200433 if (!DecodeImage(image,pixels,packets*image->rows))
434 {
435 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
436 ThrowReaderException(CorruptImageError,"RLEDecoderError");
437 }
cristy3ed852e2009-09-05 21:47:34 +0000438 break;
439 }
440 default:
Dirk Lemstra3690a822017-05-02 08:26:55 +0200441 {
442 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
cristy3ed852e2009-09-05 21:47:34 +0000443 ThrowReaderException(CorruptImageError,
Dirk Lemstra3690a822017-05-02 08:26:55 +0200444 "UnrecognizedImageCompressionType");
445 }
cristy3ed852e2009-09-05 21:47:34 +0000446 }
447 p=pixels;
448 switch (bits_per_pixel)
449 {
450 case 1:
451 {
452 int
453 bit;
454
455 /*
456 Read 1-bit PDB image.
457 */
cristybb503372010-05-27 20:51:26 +0000458 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000459 {
460 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000461 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000462 break;
cristybb503372010-05-27 20:51:26 +0000463 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000464 {
465 for (bit=0; bit < 8; bit++)
466 {
cristy4c08aed2011-07-01 19:47:50 +0000467 index=(Quantum) (*p & (0x80 >> bit) ? 0x00 : 0x01);
468 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000469 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000470 }
471 p++;
472 }
473 if (SyncAuthenticPixels(image,exception) == MagickFalse)
474 break;
cristycee97112010-05-28 00:44:52 +0000475 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000476 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000477 if (status == MagickFalse)
478 break;
479 }
cristyea1a8aa2011-10-20 13:24:06 +0000480 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000481 break;
482 }
483 case 2:
484 {
485 /*
486 Read 2-bit PDB image.
487 */
cristybb503372010-05-27 20:51:26 +0000488 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000489 {
490 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000491 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000492 break;
cristy29d40332014-12-30 23:48:22 +0000493 for (x=0; x < (ssize_t) image->columns-3; x+=4)
cristy3ed852e2009-09-05 21:47:34 +0000494 {
cristyc82a27b2011-10-21 01:07:16 +0000495 index=ConstrainColormapIndex(image,3UL-((*p >> 6) & 0x03),exception);
cristy4c08aed2011-07-01 19:47:50 +0000496 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000497 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000498 index=ConstrainColormapIndex(image,3UL-((*p >> 4) & 0x03),exception);
cristy4c08aed2011-07-01 19:47:50 +0000499 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000500 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000501 index=ConstrainColormapIndex(image,3UL-((*p >> 2) & 0x03),exception);
cristy4c08aed2011-07-01 19:47:50 +0000502 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000503 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000504 index=ConstrainColormapIndex(image,3UL-((*p) & 0x03),exception);
cristy4c08aed2011-07-01 19:47:50 +0000505 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000506 p++;
cristyed231572011-07-14 02:18:59 +0000507 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000508 }
509 if (SyncAuthenticPixels(image,exception) == MagickFalse)
510 break;
cristycee97112010-05-28 00:44:52 +0000511 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000512 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000513 if (status == MagickFalse)
514 break;
515 }
cristyea1a8aa2011-10-20 13:24:06 +0000516 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000517 break;
518 }
519 case 4:
520 {
521 /*
522 Read 4-bit PDB image.
523 */
cristybb503372010-05-27 20:51:26 +0000524 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000525 {
526 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000527 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000528 break;
cristy29d40332014-12-30 23:48:22 +0000529 for (x=0; x < (ssize_t) image->columns-1; x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000530 {
cristyc82a27b2011-10-21 01:07:16 +0000531 index=ConstrainColormapIndex(image,15UL-((*p >> 4) & 0x0f),exception);
cristy4c08aed2011-07-01 19:47:50 +0000532 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000533 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000534 index=ConstrainColormapIndex(image,15UL-((*p) & 0x0f),exception);
cristy4c08aed2011-07-01 19:47:50 +0000535 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000536 p++;
cristyed231572011-07-14 02:18:59 +0000537 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000538 }
539 if (SyncAuthenticPixels(image,exception) == MagickFalse)
540 break;
cristycee97112010-05-28 00:44:52 +0000541 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000542 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000543 if (status == MagickFalse)
544 break;
545 }
cristyea1a8aa2011-10-20 13:24:06 +0000546 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000547 break;
548 }
549 default:
Dirk Lemstra3690a822017-05-02 08:26:55 +0200550 {
551 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
cristy3ed852e2009-09-05 21:47:34 +0000552 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
Dirk Lemstra3690a822017-05-02 08:26:55 +0200553 }
cristy3ed852e2009-09-05 21:47:34 +0000554 }
cristy3ed852e2009-09-05 21:47:34 +0000555 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
556 if (EOFBlob(image) != MagickFalse)
557 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
558 image->filename);
cristy98cba562014-11-20 23:46:19 +0000559 if (pdb_info.number_records > 1)
cristy3ed852e2009-09-05 21:47:34 +0000560 {
561 char
562 *comment;
563
564 int
565 c;
566
567 register char
568 *p;
569
cristybb503372010-05-27 20:51:26 +0000570 size_t
cristy3ed852e2009-09-05 21:47:34 +0000571 length;
572
cristybb503372010-05-27 20:51:26 +0000573 num_pad_bytes = (size_t) (comment_offset - TellBlob( image ));
cristy3ed852e2009-09-05 21:47:34 +0000574 while (num_pad_bytes--) ReadBlobByte( image );
575
576 /*
577 Read comment.
578 */
579 c=ReadBlobByte(image);
cristy151b66d2015-04-15 10:50:31 +0000580 length=MagickPathExtent;
cristy3ed852e2009-09-05 21:47:34 +0000581 comment=AcquireString((char *) NULL);
582 for (p=comment; c != EOF; p++)
583 {
cristy151b66d2015-04-15 10:50:31 +0000584 if ((size_t) (p-comment+MagickPathExtent) >= length)
cristy3ed852e2009-09-05 21:47:34 +0000585 {
586 *p='\0';
587 length<<=1;
cristy151b66d2015-04-15 10:50:31 +0000588 length+=MagickPathExtent;
589 comment=(char *) ResizeQuantumMemory(comment,length+MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +0000590 sizeof(*comment));
591 if (comment == (char *) NULL)
592 break;
593 p=comment+strlen(comment);
594 }
595 *p=c;
596 c=ReadBlobByte(image);
597 }
598 *p='\0';
599 if (comment == (char *) NULL)
600 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristyd15e6592011-10-15 00:13:06 +0000601 (void) SetImageProperty(image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +0000602 comment=DestroyString(comment);
603 }
604 (void) CloseBlob(image);
605 return(GetFirstImageInList(image));
606}
607
608/*
609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610% %
611% %
612% %
613% R e g i s t e r P D B I m a g e %
614% %
615% %
616% %
617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
618%
619% RegisterPDBImage() adds properties for the PDB image format to
620% the list of supported formats. The properties include the image format
621% tag, a method to read and/or write the format, whether the format
622% supports the saving of more than one frame to the same file or blob,
623% whether the format supports native in-memory I/O, and a brief
624% description of the format.
625%
626% The format of the RegisterPDBImage method is:
627%
cristybb503372010-05-27 20:51:26 +0000628% size_t RegisterPDBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000629%
630*/
cristybb503372010-05-27 20:51:26 +0000631ModuleExport size_t RegisterPDBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000632{
633 MagickInfo
634 *entry;
635
dirk06b627a2015-04-06 18:59:17 +0000636 entry=AcquireMagickInfo("PDB","PDB","Palm Database ImageViewer Format");
cristy3ed852e2009-09-05 21:47:34 +0000637 entry->decoder=(DecodeImageHandler *) ReadPDBImage;
638 entry->encoder=(EncodeImageHandler *) WritePDBImage;
639 entry->magick=(IsImageFormatHandler *) IsPDB;
cristy3ed852e2009-09-05 21:47:34 +0000640 (void) RegisterMagickInfo(entry);
641 return(MagickImageCoderSignature);
642}
643
644/*
645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646% %
647% %
648% %
649% U n r e g i s t e r P D B I m a g e %
650% %
651% %
652% %
653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654%
655% UnregisterPDBImage() removes format registrations made by the
656% PDB module from the list of supported formats.
657%
658% The format of the UnregisterPDBImage method is:
659%
660% UnregisterPDBImage(void)
661%
662*/
663ModuleExport void UnregisterPDBImage(void)
664{
665 (void) UnregisterMagickInfo("PDB");
666}
667
668/*
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670% %
671% %
672% %
673% W r i t e P D B I m a g e %
674% %
675% %
676% %
677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678%
679% WritePDBImage() writes an image
680%
681% The format of the WritePDBImage method is:
682%
cristy1e178e72011-08-28 19:44:34 +0000683% MagickBooleanType WritePDBImage(const ImageInfo *image_info,
684% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000685%
686% A description of each parameter follows.
687%
688% o image_info: the image info.
689%
690% o image: The image.
691%
cristy1e178e72011-08-28 19:44:34 +0000692% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000693%
694*/
695
696static unsigned char *EncodeRLE(unsigned char *destination,
cristybb503372010-05-27 20:51:26 +0000697 unsigned char *source,size_t literal,size_t repeat)
cristy3ed852e2009-09-05 21:47:34 +0000698{
699 if (literal > 0)
700 *destination++=(unsigned char) (literal-1);
701 (void) CopyMagickMemory(destination,source,literal);
702 destination+=literal;
703 if (repeat > 0)
704 {
705 *destination++=(unsigned char) (0x80 | (repeat-1));
706 *destination++=source[literal];
707 }
708 return(destination);
709}
710
cristy1e178e72011-08-28 19:44:34 +0000711static MagickBooleanType WritePDBImage(const ImageInfo *image_info,Image *image,
712 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000713{
714 const char
715 *comment;
716
717 int
718 bits;
719
cristy3ed852e2009-09-05 21:47:34 +0000720 MagickBooleanType
721 status;
722
723 PDBImage
724 pdb_image;
725
726 PDBInfo
727 pdb_info;
728
729 QuantumInfo
730 *quantum_info;
731
cristy4c08aed2011-07-01 19:47:50 +0000732 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000733 *p;
734
cristybb503372010-05-27 20:51:26 +0000735 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000736 x;
737
738 register unsigned char
739 *q;
740
741 size_t
cristyaff6d802011-04-26 01:46:31 +0000742 bits_per_pixel,
743 literal,
744 packets,
745 packet_size,
746 repeat;
747
748 ssize_t
749 y;
cristy3ed852e2009-09-05 21:47:34 +0000750
751 unsigned char
752 *buffer,
753 *runlength,
754 *scanline;
755
cristy3ed852e2009-09-05 21:47:34 +0000756 /*
757 Open output image file.
758 */
759 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000760 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000761 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000762 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000763 if (image->debug != MagickFalse)
764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000765 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000766 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000767 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000768 if (status == MagickFalse)
769 return(status);
cristyaf8d3912014-02-21 14:50:33 +0000770 (void) TransformImageColorspace(image,sRGBColorspace,exception);
dirkab4f0bb2015-07-25 11:46:32 +0000771 if (SetImageMonochrome(image,exception) != MagickFalse) {
cristy98cba562014-11-20 23:46:19 +0000772 bits_per_pixel=1;
773 } else if (image->colors <= 4) {
774 bits_per_pixel=2;
775 } else if (image->colors <= 8) {
776 bits_per_pixel=3;
cristy3ed852e2009-09-05 21:47:34 +0000777 } else {
cristy98cba562014-11-20 23:46:19 +0000778 bits_per_pixel=4;
cristy3ed852e2009-09-05 21:47:34 +0000779 }
cristy72437802015-03-23 00:42:27 +0000780 (void) ResetMagickMemory(&pdb_info,0,sizeof(pdb_info));
cristyca793d72015-01-23 13:03:55 +0000781 (void) CopyMagickString(pdb_info.name,image_info->filename,
782 sizeof(pdb_info.name));
cristy3ed852e2009-09-05 21:47:34 +0000783 pdb_info.attributes=0;
784 pdb_info.version=0;
785 pdb_info.create_time=time(NULL);
786 pdb_info.modify_time=pdb_info.create_time;
787 pdb_info.archive_time=0;
788 pdb_info.modify_number=0;
789 pdb_info.application_info=0;
790 pdb_info.sort_info=0;
791 (void) CopyMagickMemory(pdb_info.type,"vIMG",4);
792 (void) CopyMagickMemory(pdb_info.id,"View",4);
793 pdb_info.seed=0;
794 pdb_info.next_record=0;
cristyd15e6592011-10-15 00:13:06 +0000795 comment=GetImageProperty(image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +0000796 pdb_info.number_records=(comment == (const char *) NULL ? 1 : 2);
cristyca793d72015-01-23 13:03:55 +0000797 (void) WriteBlob(image,sizeof(pdb_info.name),(unsigned char *) pdb_info.name);
cristy3ed852e2009-09-05 21:47:34 +0000798 (void) WriteBlobMSBShort(image,(unsigned short) pdb_info.attributes);
799 (void) WriteBlobMSBShort(image,(unsigned short) pdb_info.version);
cristyeaedf062010-05-29 22:36:02 +0000800 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.create_time);
801 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.modify_time);
802 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.archive_time);
803 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.modify_number);
804 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.application_info);
805 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.sort_info);
cristy3ed852e2009-09-05 21:47:34 +0000806 (void) WriteBlob(image,4,(unsigned char *) pdb_info.type);
807 (void) WriteBlob(image,4,(unsigned char *) pdb_info.id);
cristyeaedf062010-05-29 22:36:02 +0000808 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.seed);
809 (void) WriteBlobMSBLong(image,(unsigned int) pdb_info.next_record);
cristy3ed852e2009-09-05 21:47:34 +0000810 (void) WriteBlobMSBShort(image,(unsigned short) pdb_info.number_records);
cristyca793d72015-01-23 13:03:55 +0000811 (void) CopyMagickString(pdb_image.name,pdb_info.name,sizeof(pdb_image.name));
cristy3ed852e2009-09-05 21:47:34 +0000812 pdb_image.version=1; /* RLE Compressed */
813 switch (bits_per_pixel)
814 {
dirk93b02b72013-11-16 16:03:36 +0000815 case 1: pdb_image.type=(unsigned char) 0xff; break; /* monochrome */
816 case 2: pdb_image.type=(unsigned char) 0x00; break; /* 2 bit gray */
817 default: pdb_image.type=(unsigned char) 0x02; /* 4 bit gray */
cristy3ed852e2009-09-05 21:47:34 +0000818 }
819 pdb_image.reserved_1=0;
820 pdb_image.note=0;
821 pdb_image.x_last=0;
822 pdb_image.y_last=0;
823 pdb_image.reserved_2=0;
dirk93b02b72013-11-16 16:03:36 +0000824 pdb_image.x_anchor=(unsigned short) 0xffff;
825 pdb_image.y_anchor=(unsigned short) 0xffff;
cristy3ed852e2009-09-05 21:47:34 +0000826 pdb_image.width=(short) image->columns;
827 if (image->columns % 16)
828 pdb_image.width=(short) (16*(image->columns/16+1));
829 pdb_image.height=(short) image->rows;
cristy7e5d1da2014-12-28 00:40:02 +0000830 packets=((bits_per_pixel*image->columns+7)/8);
Cristy7b93db12016-02-20 09:26:04 -0500831 runlength=(unsigned char *) AcquireQuantumMemory(9UL*packets,
cristy7e5d1da2014-12-28 00:40:02 +0000832 image->rows*sizeof(*runlength));
cristy3ed852e2009-09-05 21:47:34 +0000833 if (runlength == (unsigned char *) NULL)
834 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
Cristy5a34d7a2016-03-30 18:47:29 -0400835 buffer=(unsigned char *) AcquireQuantumMemory(512,sizeof(*buffer));
cristy3ed852e2009-09-05 21:47:34 +0000836 if (buffer == (unsigned char *) NULL)
837 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
Cristyeedd0c32016-08-23 17:42:10 -0400838 packet_size=(size_t) (image->depth > 8 ? 2 : 1);
cristy3ed852e2009-09-05 21:47:34 +0000839 scanline=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
840 sizeof(*scanline));
841 if (scanline == (unsigned char *) NULL)
842 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristy3d9f5ba2012-06-26 13:37:31 +0000843 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy8d951092012-02-08 18:54:56 +0000844 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000845 /*
846 Convert to GRAY raster scanline.
847 */
cristy5f766ef2014-12-14 21:12:47 +0000848 quantum_info=AcquireQuantumInfo(image_info,image);
cristy3ed852e2009-09-05 21:47:34 +0000849 if (quantum_info == (QuantumInfo *) NULL)
850 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
Cristyeedd0c32016-08-23 17:42:10 -0400851 status=SetQuantumDepth(image,quantum_info,image->depth > 8 ? 16 : 8);
cristyf9cca6a2010-06-04 23:49:28 +0000852 bits=8/(int) bits_per_pixel-1; /* start at most significant bits */
cristy3ed852e2009-09-05 21:47:34 +0000853 literal=0;
854 repeat=0;
855 q=runlength;
856 buffer[0]=0x00;
cristybb503372010-05-27 20:51:26 +0000857 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000858 {
cristy1e178e72011-08-28 19:44:34 +0000859 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000860 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000861 break;
cristy4c08aed2011-07-01 19:47:50 +0000862 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +0000863 GrayQuantum,scanline,exception);
cristy98cba562014-11-20 23:46:19 +0000864 for (x=0; x < (ssize_t) pdb_image.width; x++)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristybb503372010-05-27 20:51:26 +0000866 if (x < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000867 buffer[literal+repeat]|=(0xff-scanline[x*packet_size]) >>
868 (8-bits_per_pixel) << bits*bits_per_pixel;
869 bits--;
870 if (bits < 0)
871 {
872 if (((literal+repeat) > 0) &&
873 (buffer[literal+repeat] == buffer[literal+repeat-1]))
874 {
875 if (repeat == 0)
876 {
877 literal--;
878 repeat++;
879 }
880 repeat++;
881 if (0x7f < repeat)
882 {
883 q=EncodeRLE(q,buffer,literal,repeat);
884 literal=0;
885 repeat=0;
886 }
887 }
888 else
889 {
890 if (repeat >= 2)
891 literal+=repeat;
892 else
893 {
894 q=EncodeRLE(q,buffer,literal,repeat);
895 buffer[0]=buffer[literal+repeat];
896 literal=0;
897 }
898 literal++;
899 repeat=0;
900 if (0x7f < literal)
901 {
902 q=EncodeRLE(q,buffer,(literal < 0x80 ? literal : 0x80),0);
903 (void) CopyMagickMemory(buffer,buffer+literal+repeat,0x80);
904 literal-=0x80;
905 }
906 }
cristyf9cca6a2010-06-04 23:49:28 +0000907 bits=8/(int) bits_per_pixel-1;
cristy3ed852e2009-09-05 21:47:34 +0000908 buffer[literal+repeat]=0x00;
909 }
910 }
cristycee97112010-05-28 00:44:52 +0000911 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy98cba562014-11-20 23:46:19 +0000912 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000913 if (status == MagickFalse)
914 break;
915 }
916 q=EncodeRLE(q,buffer,literal,repeat);
917 scanline=(unsigned char *) RelinquishMagickMemory(scanline);
918 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
919 quantum_info=DestroyQuantumInfo(quantum_info);
920 /*
921 Write the Image record header.
922 */
cristyf6fe0a12010-05-30 00:44:47 +0000923 (void) WriteBlobMSBLong(image,(unsigned int)
cristy3ed852e2009-09-05 21:47:34 +0000924 (TellBlob(image)+8*pdb_info.number_records));
925 (void) WriteBlobByte(image,0x40);
926 (void) WriteBlobByte(image,0x6f);
927 (void) WriteBlobByte(image,0x80);
928 (void) WriteBlobByte(image,0);
929 if (pdb_info.number_records > 1)
930 {
931 /*
932 Write the comment record header.
933 */
cristyf6fe0a12010-05-30 00:44:47 +0000934 (void) WriteBlobMSBLong(image,(unsigned int) (TellBlob(image)+8+58+q-
cristy3ed852e2009-09-05 21:47:34 +0000935 runlength));
936 (void) WriteBlobByte(image,0x40);
937 (void) WriteBlobByte(image,0x6f);
938 (void) WriteBlobByte(image,0x80);
939 (void) WriteBlobByte(image,1);
940 }
941 /*
942 Write the Image data.
943 */
cristyca793d72015-01-23 13:03:55 +0000944 (void) WriteBlob(image,sizeof(pdb_image.name),(unsigned char *)
945 pdb_image.name);
cristy3ed852e2009-09-05 21:47:34 +0000946 (void) WriteBlobByte(image,(unsigned char) pdb_image.version);
dirk93b02b72013-11-16 16:03:36 +0000947 (void) WriteBlobByte(image,pdb_image.type);
cristyeaedf062010-05-29 22:36:02 +0000948 (void) WriteBlobMSBLong(image,(unsigned int) pdb_image.reserved_1);
949 (void) WriteBlobMSBLong(image,(unsigned int) pdb_image.note);
cristy3ed852e2009-09-05 21:47:34 +0000950 (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.x_last);
951 (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.y_last);
cristyeaedf062010-05-29 22:36:02 +0000952 (void) WriteBlobMSBLong(image,(unsigned int) pdb_image.reserved_2);
dirk93b02b72013-11-16 16:03:36 +0000953 (void) WriteBlobMSBShort(image,pdb_image.x_anchor);
954 (void) WriteBlobMSBShort(image,pdb_image.y_anchor);
cristy3ed852e2009-09-05 21:47:34 +0000955 (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.width);
956 (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.height);
957 (void) WriteBlob(image,(size_t) (q-runlength),runlength);
958 runlength=(unsigned char *) RelinquishMagickMemory(runlength);
959 if (pdb_info.number_records > 1)
960 (void) WriteBlobString(image,comment);
961 (void) CloseBlob(image);
962 return(MagickTrue);
963}