root / ImageMagick / trunk / coders / pdb.c

Revision 12035, 30.1 kB (checked in by cristy, 6 weeks ago)
Line 
1/*
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                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37    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
44*/
45
46/*
47  Include declarations.
48*/
49#include "magick/studio.h"
50#include "magick/blob.h"
51#include "magick/blob-private.h"
52#include "magick/color-private.h"
53#include "magick/colorspace.h"
54#include "magick/constitute.h"
55#include "magick/exception.h"
56#include "magick/exception-private.h"
57#include "magick/image.h"
58#include "magick/image-private.h"
59#include "magick/list.h"
60#include "magick/magick.h"
61#include "magick/memory_.h"
62#include "magick/monitor.h"
63#include "magick/monitor-private.h"
64#include "magick/property.h"
65#include "magick/quantum-private.h"
66#include "magick/quantum-private.h"
67#include "magick/static.h"
68#include "magick/string_.h"
69#include "magick/module.h"
70
71/*
72  Typedef declarations.
73*/
74typedef struct _PDBInfo
75{
76  char
77    name[32];
78
79  short int
80    attributes,
81    version;
82
83  unsigned long
84    create_time,
85    modify_time,
86    archive_time,
87    modify_number,
88    application_info,
89    sort_info;
90
91  char
92    type[4],  /* database type identifier "vIMG" */
93    id[4];    /* database creator identifier "View" */
94
95  unsigned long
96    seed,
97    next_record;
98
99  short int
100    number_records;
101} PDBInfo;
102
103typedef struct _PDBImage
104{
105  char
106    name[32],
107    version,
108    type;
109
110  unsigned long
111    reserved_1,
112    note;
113
114  short int
115    x_last,
116    y_last;
117
118  unsigned long
119    reserved_2;
120
121  short int
122    x_anchor,
123    y_anchor,
124    width,
125    height;
126} PDBImage;
127/*
128  Forward declarations.
129*/
130static MagickBooleanType
131  WritePDBImage(const ImageInfo *,Image *);
132
133/*
134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135%                                                                             %
136%                                                                             %
137%                                                                             %
138%   D e c o d e I m a g e                                                     %
139%                                                                             %
140%                                                                             %
141%                                                                             %
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143%
144%  DecodeImage unpacks the packed image pixels into runlength-encoded
145%  pixel packets.
146%
147%  The format of the DecodeImage method is:
148%
149%      MagickBooleanType DecodeImage(Image *image,unsigned char *pixels,
150%        const size_t length)
151%
152%  A description of each parameter follows:
153%
154%    o image: the address of a structure of type Image.
155%
156%    o pixels:  The address of a byte (8 bits) array of pixel data created by
157%      the decoding process.
158%
159%    o length:  Number of bytes to read into buffer 'pixels'.
160%
161*/
162static MagickBooleanType DecodeImage(Image *image, unsigned char *pixels,
163  const size_t length)
164{
165#define RLE_MODE_NONE -1
166#define RLE_MODE_COPY  0
167#define RLE_MODE_RUN   1
168
169        int           data = 0, count = 0;
170        unsigned char *p;
171        int           mode = RLE_MODE_NONE;
172
173        for (p = pixels; p < pixels + length; p++) {
174                if (0 == count) {
175                        data = ReadBlobByte( image );
176                        if (-1 == data) return MagickFalse;
177                        if (data > 128) {
178                                mode  = RLE_MODE_RUN;
179                                count = data - 128 + 1;
180                                data  = ReadBlobByte( image );
181                                if (-1 == data) return MagickFalse;
182                        } else {
183                                mode  = RLE_MODE_COPY;
184                                count = data + 1;
185                        }
186                }
187
188                if (RLE_MODE_COPY == mode) {
189                        data = ReadBlobByte( image );
190                        if (-1 == data) return MagickFalse;
191                }
192                *p = (unsigned char)data;
193                --count;
194        }
195        return MagickTrue;
196}
197
198/*
199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200%                                                                             %
201%                                                                             %
202%                                                                             %
203%   I s P D B                                                                 %
204%                                                                             %
205%                                                                             %
206%                                                                             %
207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208%
209%  IsPDB() returns MagickTrue if the image format type, identified by the
210%  magick string, is PDB.
211%
212%  The format of the ReadPDBImage method is:
213%
214%      MagickBooleanType IsPDB(const unsigned char *magick,const size_t length)
215%
216%  A description of each parameter follows:
217%
218%    o magick: This string is generally the first few bytes of an image file
219%      or blob.
220%
221%    o length: Specifies the length of the magick string.
222%
223*/
224static MagickBooleanType IsPDB(const unsigned char *magick,const size_t length)
225{
226  if (length < 68)
227    return(MagickFalse);
228  if (memcmp(magick+60,"vIMGView",8) == 0)
229    return(MagickTrue);
230  return(MagickFalse);
231}
232
233/*
234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235%                                                                             %
236%                                                                             %
237%                                                                             %
238%   R e a d P D B I m a g e                                                   %
239%                                                                             %
240%                                                                             %
241%                                                                             %
242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243%
244%  ReadPDBImage() reads an Pilot image file and returns it.  It
245%  allocates the memory necessary for the new Image structure and returns a
246%  pointer to the new image.
247%
248%  The format of the ReadPDBImage method is:
249%
250%      Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception)
251%
252%  A description of each parameter follows:
253%
254%    o image_info: the image info.
255%
256%    o exception: return any errors or warnings in this structure.
257%
258*/
259static Image *ReadPDBImage(const ImageInfo *image_info,ExceptionInfo *exception)
260{
261  unsigned char
262    attributes, /* TS */
263    tag[3];
264
265  Image
266    *image;
267
268  IndexPacket
269    index;
270
271  long
272    img_offset, /* TS */
273    comment_offset = 0,
274    y;
275
276  MagickBooleanType
277    status;
278
279  PDBImage
280    pdb_image;
281
282  PDBInfo
283    pdb_info;
284
285  register IndexPacket
286    *indexes;
287
288  register long
289    x;
290
291  register PixelPacket
292    *q;
293
294  register unsigned char
295    *p;
296
297  ssize_t
298    count;
299
300  unsigned char
301    *pixels;
302
303  unsigned long
304    num_pad_bytes, /* TS */
305    bits_per_pixel,
306    packets;
307
308  /*
309    Open image file.
310  */
311  assert(image_info != (const ImageInfo *) NULL);
312  assert(image_info->signature == MagickSignature);
313  if (image_info->debug != MagickFalse)
314    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
315      image_info->filename);
316  assert(exception != (ExceptionInfo *) NULL);
317  assert(exception->signature == MagickSignature);
318  image=AcquireImage(image_info);
319  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
320  if (status == MagickFalse)
321    {
322      image=DestroyImageList(image);
323      return((Image *) NULL);
324    }
325  /*
326    Determine if this a PDB image file.
327  */
328  count=ReadBlob(image,32,(unsigned char *) pdb_info.name);
329  pdb_info.attributes=(short) ReadBlobMSBShort(image);
330  pdb_info.version=(short) ReadBlobMSBShort(image);
331  pdb_info.create_time=ReadBlobMSBLong(image);
332  pdb_info.modify_time=ReadBlobMSBLong(image);
333  pdb_info.archive_time=ReadBlobMSBLong(image);
334  pdb_info.modify_number=ReadBlobMSBLong(image);
335  pdb_info.application_info=ReadBlobMSBLong(image);
336  pdb_info.sort_info=ReadBlobMSBLong(image);
337  count=ReadBlob(image,4,(unsigned char *) pdb_info.type);
338  count=ReadBlob(image,4,(unsigned char *) pdb_info.id);
339  if ((count == 0) || (memcmp(pdb_info.type,"vIMG",4) != 0) ||
340      (memcmp(pdb_info.id,"View",4) != 0))
341    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
342  pdb_info.seed=ReadBlobMSBLong(image);
343  pdb_info.next_record=ReadBlobMSBLong(image);
344  pdb_info.number_records=(short) ReadBlobMSBShort(image);
345  if (pdb_info.next_record != 0)
346    ThrowReaderException(CoderError,"MultipleRecordListNotSupported");
347  /*
348    Read record header.
349  */
350  img_offset=(long) ReadBlobMSBLong(image); /* TS */
351  attributes=(unsigned char) ReadBlobByte(image);
352  count=ReadBlob(image,3,(unsigned char *) tag);
353  if (count != 3  ||  memcmp(tag,"\x6f\x80\x00",3) != 0)
354    ThrowReaderException(CorruptImageError,"CorruptImage");
355
356  if (pdb_info.number_records > 1)
357    {
358      comment_offset=(long) ReadBlobMSBLong(image);
359      attributes=(unsigned char) ReadBlobByte(image);
360      count=ReadBlob(image,3,(unsigned char *) tag);
361      if (count != 3  ||  memcmp(tag,"\x6f\x80\x01",3) != 0)
362        ThrowReaderException(CorruptImageError,"CorruptImage");
363    }
364
365  num_pad_bytes = (unsigned long) (img_offset - TellBlob( image ));
366  while (num_pad_bytes--) ReadBlobByte( image );
367  /*
368    Read image header.
369  */
370  count=ReadBlob(image,32,(unsigned char *) pdb_image.name);
371  pdb_image.version=ReadBlobByte(image);
372  pdb_image.type=ReadBlobByte(image);
373  pdb_image.reserved_1=ReadBlobMSBLong(image);
374  pdb_image.note=ReadBlobMSBLong(image);
375  pdb_image.x_last=(short) ReadBlobMSBShort(image);
376  pdb_image.y_last=(short) ReadBlobMSBShort(image);
377  pdb_image.reserved_2=ReadBlobMSBLong(image);
378  pdb_image.x_anchor=(short) ReadBlobMSBShort(image);
379  pdb_image.y_anchor=(short) ReadBlobMSBShort(image);
380  pdb_image.width=(short) ReadBlobMSBShort(image);
381  pdb_image.height=(short) ReadBlobMSBShort(image);
382  /*
383    Initialize image structure.
384  */
385  image->columns=(unsigned long) pdb_image.width;
386  image->rows=(unsigned long) pdb_image.height;
387  image->depth=8;
388  image->storage_class=PseudoClass;
389  bits_per_pixel=pdb_image.type == 0 ? 2UL : pdb_image.type == 2 ? 4UL : 1UL;
390  if (AcquireImageColormap(image,1 << bits_per_pixel) == MagickFalse)
391    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
392  if (image_info->ping != MagickFalse)
393    {
394      (void) CloseBlob(image);
395      return(GetFirstImageInList(image));
396    }
397  if (SetImageExtent(image,0,0) == MagickFalse)
398    {
399      InheritException(exception,&image->exception);
400      return(DestroyImageList(image));
401    }
402  packets=bits_per_pixel*image->columns/8;
403  pixels=(unsigned char *) AcquireQuantumMemory(packets+256UL,image->rows*
404    sizeof(*pixels));
405  if (pixels == (unsigned char *) NULL)
406    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
407
408  switch (pdb_image.version & 7) /* TS */
409  {
410    case 0:
411    {
412      image->compression=NoCompression;
413      count=(ssize_t) ReadBlob(image, packets * image -> rows, pixels);
414      break;
415    }
416    case 1:
417    {
418      image->compression=RLECompression;
419      if (!DecodeImage(image, pixels, packets * image -> rows))
420        ThrowReaderException( CorruptImageError, "RLEDecoderError" ); /* TS */
421      break;
422    }
423    default:
424      ThrowReaderException(CorruptImageError,
425                           "UnrecognizedImageCompressionType" );
426  }
427  p=pixels;
428  switch (bits_per_pixel)
429  {
430    case 1:
431    {
432      int
433        bit;
434
435      /*
436        Read 1-bit PDB image.
437      */
438      for (y=0; y < (long) image->rows; y++)
439      {
440        q=SetImagePixels(image,0,y,image->columns,1);
441        if (q == (PixelPacket *) NULL)
442          break;
443        indexes=GetIndexes(image);
444        for (x=0; x < ((long) image->columns-7); x+=8)
445        {
446          for (bit=0; bit < 8; bit++)
447          {
448            index=(IndexPacket) (*p & (0x80 >> bit) ? 0x00 : 0x01);
449            indexes[x+bit]=index;
450            *q++=image->colormap[(long) index];
451          }
452          p++;
453        }
454        if (SyncImagePixels(image) == MagickFalse)
455          break;
456        status=SetImageProgress(image,LoadImageTag,y,image->rows);
457        if (status == MagickFalse)
458          break;
459      }
460      break;
461    }
462    case 2:
463    {
464      /*
465        Read 2-bit PDB image.
466      */
467      for (y=0; y < (long) image->rows; y++)
468      {
469        q=SetImagePixels(image,0,y,image->columns,1);
470        if (q == (PixelPacket *) NULL)
471          break;
472        indexes=GetIndexes(image);
473        for (x=0; x < (long) image->columns; x+=4)
474        {
475          index=ConstrainColormapIndex(image,3UL-((*p >> 6) & 0x03));
476          indexes[x]=index;
477          *q++=image->colormap[(long) index];
478          index=ConstrainColormapIndex(image,3UL-((*p >> 4) & 0x03));
479          indexes[x+1]=index;
480          *q++=image->colormap[(long) index];
481          index=ConstrainColormapIndex(image,3UL-((*p >> 2) & 0x03));
482          indexes[x+2]=index;
483          *q++=image->colormap[(long) index];
484          index=ConstrainColormapIndex(image,3UL-((*p) & 0x03));
485          indexes[x+3]=index;
486          *q++=image->colormap[(long) index];
487          p++;
488        }
489        if (SyncImagePixels(image) == MagickFalse)
490          break;
491        status=SetImageProgress(image,LoadImageTag,y,image->rows);
492        if (status == MagickFalse)
493          break;
494      }
495      break;
496    }
497    case 4:
498    {
499      /*
500        Read 4-bit PDB image.
501      */
502      for (y=0; y < (long) image->rows; y++)
503      {
504        q=SetImagePixels(image,0,y,image->columns,1);
505        if (q == (PixelPacket *) NULL)
506          break;
507        indexes=GetIndexes(image);
508        for (x=0; x < (long) image->columns; x+=2)
509        {
510          index=ConstrainColormapIndex(image,15UL-((*p >> 4) & 0x0f));
511          indexes[x]=index;
512          *q++=image->colormap[(long) index];
513          index=ConstrainColormapIndex(image,15UL-((*p) & 0x0f));
514          indexes[x+1]=index;
515          *q++=image->colormap[(long) index];
516          p++;
517        }
518        if (SyncImagePixels(image) == MagickFalse)
519          break;
520        status=SetImageProgress(image,LoadImageTag,y,image->rows);
521        if (status == MagickFalse)
522          break;
523      }
524      break;
525    }
526    default:
527      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
528  }
529
530  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
531  if (EOFBlob(image) != MagickFalse)
532    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
533      image->filename);
534  if (pdb_info.number_records > 1) /* TS */
535    {
536      char
537        *comment;
538
539      int
540        c;
541
542      register char
543        *p;
544
545      unsigned long
546        length;
547
548      num_pad_bytes = (unsigned long) (comment_offset - TellBlob( image ));
549      while (num_pad_bytes--) ReadBlobByte( image );
550
551      /*
552        Read comment.
553      */
554      c=ReadBlobByte(image);
555      length=MaxTextExtent;
556      comment=AcquireString((char *) NULL);
557      for (p=comment; c != EOF; p++)
558      {
559        if ((size_t) (p-comment+MaxTextExtent) >= length)
560          {
561            *p='\0';
562            length<<=1;
563            length+=MaxTextExtent;
564            comment=(char *) ResizeQuantumMemory(comment,length+MaxTextExtent,
565              sizeof(*comment));
566            if (comment == (char *) NULL)
567              break;
568            p=comment+strlen(comment);
569          }
570        *p=c;
571        c=ReadBlobByte(image);
572      }
573      *p='\0';
574      if (comment == (char *) NULL)
575        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
576      (void) SetImageProperty(image,"comment",comment);
577      comment=DestroyString(comment);
578    }
579  (void) CloseBlob(image);
580  return(GetFirstImageInList(image));
581}
582
583/*
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585%                                                                             %
586%                                                                             %
587%                                                                             %
588%   R e g i s t e r P D B I m a g e                                           %
589%                                                                             %
590%                                                                             %
591%                                                                             %
592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593%
594%  RegisterPDBImage() adds properties for the PDB image format to
595%  the list of supported formats.  The properties include the image format
596%  tag, a method to read and/or write the format, whether the format
597%  supports the saving of more than one frame to the same file or blob,
598%  whether the format supports native in-memory I/O, and a brief
599%  description of the format.
600%
601%  The format of the RegisterPDBImage method is:
602%
603%      unsigned long RegisterPDBImage(void)
604%
605*/
606ModuleExport unsigned long RegisterPDBImage(void)
607{
608  MagickInfo
609    *entry;
610
611  entry=SetMagickInfo("PDB");
612  entry->decoder=(DecodeImageHandler *) ReadPDBImage;
613  entry->encoder=(EncodeImageHandler *) WritePDBImage;
614  entry->magick=(IsImageFormatHandler *) IsPDB;
615  entry->description=ConstantString("Palm Database ImageViewer Format");
616  entry->module=ConstantString("PDB");
617  (void) RegisterMagickInfo(entry);
618  return(MagickImageCoderSignature);
619}
620
621/*
622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623%                                                                             %
624%                                                                             %
625%                                                                             %
626%   U n r e g i s t e r P D B I m a g e                                       %
627%                                                                             %
628%                                                                             %
629%                                                                             %
630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631%
632%  UnregisterPDBImage() removes format registrations made by the
633%  PDB module from the list of supported formats.
634%
635%  The format of the UnregisterPDBImage method is:
636%
637%      UnregisterPDBImage(void)
638%
639*/
640ModuleExport void UnregisterPDBImage(void)
641{
642  (void) UnregisterMagickInfo("PDB");
643}
644
645/*
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%                                                                             %
648%                                                                             %
649%                                                                             %
650%   W r i t e P D B I m a g e                                                 %
651%                                                                             %
652%                                                                             %
653%                                                                             %
654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
655%
656%  WritePDBImage() writes an image
657%
658%  The format of the WritePDBImage method is:
659%
660%      MagickBooleanType WritePDBImage(const ImageInfo *image_info,Image *image)
661%
662%  A description of each parameter follows.
663%
664%    o image_info: the image info.
665%
666%    o image:  The image.
667%
668%
669*/
670
671static unsigned char *EncodeRLE(unsigned char *destination,
672  unsigned char *source,unsigned long literal,unsigned long repeat)
673{
674  if (literal > 0)
675    *destination++=(unsigned char) (literal-1);
676  (void) CopyMagickMemory(destination,source,literal);
677  destination+=literal;
678  if (repeat > 0)
679    {
680      *destination++=(unsigned char) (0x80 | (repeat-1));
681      *destination++=source[literal];
682    }
683  return(destination);
684}
685
686static MagickBooleanType WritePDBImage(const ImageInfo *image_info,Image *image)
687{
688  const char
689    *comment;
690
691  int
692    bits;
693
694  long
695    y;
696
697  MagickBooleanType
698    status;
699
700  PDBImage
701    pdb_image;
702
703  PDBInfo
704    pdb_info;
705
706  QuantumInfo
707    quantum_info;
708
709  register const PixelPacket
710    *p;
711
712  register long
713    x;
714
715  register unsigned char
716    *q;
717
718  size_t
719    packet_size;
720
721  unsigned char
722    *buffer,
723    *runlength,
724    *scanline;
725
726  unsigned long
727    bits_per_pixel,
728    literal,
729    packets,
730    repeat;
731
732  /*
733    Open output image file.
734  */
735  assert(image_info != (const ImageInfo *) NULL);
736  assert(image_info->signature == MagickSignature);
737  assert(image != (Image *) NULL);
738  assert(image->signature == MagickSignature);
739  if (image->debug != MagickFalse)
740    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
741  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
742  if (status == MagickFalse)
743    return(status);
744  if (image->colorspace != RGBColorspace)
745    (void) SetImageColorspace(image,RGBColorspace);
746
747  if (image -> colors <= 2  ||  GetImageType( image, &image -> exception ) == BilevelType) { /* TS */
748    bits_per_pixel = 1;
749  } else if (image -> colors <= 4) {
750    bits_per_pixel = 2;
751  } else if (image -> colors <= 8) {
752    bits_per_pixel = 3;
753  } else {
754    bits_per_pixel = 4;
755  }
756
757  (void) ResetMagickMemory(pdb_info.name,0,32);
758  (void) CopyMagickString(pdb_info.name,image_info->filename,32);
759  pdb_info.attributes=0;
760  pdb_info.version=0;
761  pdb_info.create_time=time(NULL);
762  pdb_info.modify_time=pdb_info.create_time;
763  pdb_info.archive_time=0;
764  pdb_info.modify_number=0;
765  pdb_info.application_info=0;
766  pdb_info.sort_info=0;
767  (void) CopyMagickMemory(pdb_info.type,"vIMG",4);
768  (void) CopyMagickMemory(pdb_info.id,"View",4);
769  pdb_info.seed=0;
770  pdb_info.next_record=0;
771  comment=GetImageProperty(image,"comment");
772  pdb_info.number_records=(comment == (const char *) NULL ? 1 : 2);
773  (void) WriteBlob(image,32,(unsigned char *) pdb_info.name);
774  (void) WriteBlobMSBShort(image,(unsigned short) pdb_info.attributes);
775  (void) WriteBlobMSBShort(image,(unsigned short) pdb_info.version);
776  (void) WriteBlobMSBLong(image,pdb_info.create_time);
777  (void) WriteBlobMSBLong(image,pdb_info.modify_time);
778  (void) WriteBlobMSBLong(image,pdb_info.archive_time);
779  (void) WriteBlobMSBLong(image,pdb_info.modify_number);
780  (void) WriteBlobMSBLong(image,pdb_info.application_info);
781  (void) WriteBlobMSBLong(image,pdb_info.sort_info);
782  (void) WriteBlob(image,4,(unsigned char *) pdb_info.type);
783  (void) WriteBlob(image,4,(unsigned char *) pdb_info.id);
784  (void) WriteBlobMSBLong(image,(unsigned long) pdb_info.seed);
785  (void) WriteBlobMSBLong(image,(unsigned long) pdb_info.next_record);
786  (void) WriteBlobMSBShort(image,(unsigned short) pdb_info.number_records);
787  (void) CopyMagickString(pdb_image.name,pdb_info.name,32);
788  pdb_image.version=1;  /* RLE Compressed */
789  switch (bits_per_pixel)
790  {
791    case 1: pdb_image.type=(char) 0xff; break/* monochrome */
792    case 2: pdb_image.type=(char) 0x00; break/* 2 bit gray */
793    default: pdb_image.type=(char) 0x02;  /* 4 bit gray */
794  }
795  pdb_image.reserved_1=0;
796  pdb_image.note=0;
797  pdb_image.x_last=0;
798  pdb_image.y_last=0;
799  pdb_image.reserved_2=0;
800  pdb_image.x_anchor=(short) 0xffff;
801  pdb_image.y_anchor=(short) 0xffff;
802  pdb_image.width=(short) image->columns;
803  if (image->columns % 16)
804    pdb_image.width=(short) (16*(image->columns/16+1));
805  pdb_image.height=(short) image->rows;
806  packets=(bits_per_pixel*image->columns/8)*image->rows;
807  runlength=(unsigned char *) AcquireQuantumMemory(2UL*packets,
808    sizeof(*runlength));
809  if (runlength == (unsigned char *) NULL)
810    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
811  buffer=(unsigned char *) AcquireQuantumMemory(256UL,sizeof(*buffer));
812  if (buffer == (unsigned char *) NULL)
813    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
814  packet_size=(size_t) (image->depth > 8 ? 2: 1);
815  scanline=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
816    sizeof(*scanline));
817  if (scanline == (unsigned char *) NULL)
818    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
819    if (image->colorspace != RGBColorspace)
820    (void) SetImageColorspace(image,RGBColorspace);
821  /*
822    Convert to GRAY raster scanline.
823  */
824  GetQuantumInfo(image_info,&quantum_info);
825  bits=8/(long) bits_per_pixel-1;  /* start at most significant bits */
826  literal=0;
827  repeat=0;
828  q=runlength;
829  buffer[0]=0x00;
830  for (y=0; y < (long) image->rows; y++)
831  {
832    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
833    if (p == (const PixelPacket *) NULL)
834      break;
835    (void) ExportQuantumPixels(image,&quantum_info,GrayQuantum,scanline);
836    for (x=0; x < pdb_image.width; x++)
837    {
838      if (x < (long) image->columns)
839        buffer[literal+repeat]|=(0xff-scanline[x*packet_size]) >>
840          (8-bits_per_pixel) << bits*bits_per_pixel;
841      bits--;
842      if (bits < 0)
843        {
844          if (((literal+repeat) > 0) &&
845              (buffer[literal+repeat] == buffer[literal+repeat-1]))
846            {
847              if (repeat == 0)
848                {
849                  literal--;
850                  repeat++;
851                }
852              repeat++;
853              if (0x7f < repeat)
854                {
855                  q=EncodeRLE(q,buffer,literal,repeat);
856                  literal=0;
857                  repeat=0;
858                }
859            }
860          else
861            {
862              if (repeat >= 2)
863                literal+=repeat;
864              else
865                {
866                  q=EncodeRLE(q,buffer,literal,repeat);
867                  buffer[0]=buffer[literal+repeat];
868                  literal=0;
869                }
870              literal++;
871              repeat=0;
872              if (0x7f < literal)
873                {
874                  q=EncodeRLE(q,buffer,(literal < 0x80 ? literal : 0x80),0);
875                  (void) CopyMagickMemory(buffer,buffer+literal+repeat,0x80);
876                  literal-=0x80;
877                }
878            }
879        bits=8/(long) bits_per_pixel-1;
880        buffer[literal+repeat]=0x00;
881      }
882    }
883    status=SetImageProgress(image,SaveImageTag,y,image->rows);
884    if (status == MagickFalse)
885      break;
886  }
887  q=EncodeRLE(q,buffer,literal,repeat);
888  scanline=(unsigned char *) RelinquishMagickMemory(scanline);
889  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
890  /*
891    Write the Image record header.
892  */
893  (void) WriteBlobMSBLong(image,(unsigned long)
894    (TellBlob(image)+8*pdb_info.number_records));
895  (void) WriteBlobByte(image,0x40);
896  (void) WriteBlobByte(image,0x6f);
897  (void) WriteBlobByte(image,0x80);
898  (void) WriteBlobByte(image,0);
899  if (pdb_info.number_records > 1)
900    {
901      /*
902        Write the comment record header.
903      */
904      (void) WriteBlobMSBLong(image,(unsigned long) (TellBlob(image)+8+58+q-
905        runlength));
906      (void) WriteBlobByte(image,0x40);
907      (void) WriteBlobByte(image,0x6f);
908      (void) WriteBlobByte(image,0x80);
909      (void) WriteBlobByte(image,1);
910    }
911  /*
912    Write the Image data.
913  */
914  (void) WriteBlob(image,32,(unsigned char *) pdb_image.name);
915  (void) WriteBlobByte(image,(unsigned char) pdb_image.version);
916  (void) WriteBlobByte(image,(unsigned char) pdb_image.type);
917  (void) WriteBlobMSBLong(image,pdb_image.reserved_1);
918  (void) WriteBlobMSBLong(image,pdb_image.note);
919  (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.x_last);
920  (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.y_last);
921  (void) WriteBlobMSBLong(image,pdb_image.reserved_2);
922  (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.x_anchor);
923  (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.y_anchor);
924  (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.width);
925  (void) WriteBlobMSBShort(image,(unsigned short) pdb_image.height);
926  (void) WriteBlob(image,(size_t) (q-runlength),runlength);
927  runlength=(unsigned char *) RelinquishMagickMemory(runlength);
928  if (pdb_info.number_records > 1)
929    (void) WriteBlobString(image,comment);
930  (void) CloseBlob(image);
931  return(MagickTrue);
932}
Note: See TracBrowser for help on using the browser.