]>
git.saurik.com Git - wxWidgets.git/blob - src/common/imagpcx.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxImage PCX handler 
   4 // Author:      Guillermo Rodriguez Garcia <guille@iies.es> 
   7 // Copyright:   (c) 1999 Guillermo Rodriguez Garcia 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  12 #pragma implementation "imagpcx.h" 
  15 // For compilers that support precompilation, includes "wx.h". 
  16 #include "wx/wxprec.h" 
  26 #if wxUSE_IMAGE && wxUSE_STREAMS && wxUSE_PCX 
  28 #include "wx/imagpcx.h" 
  29 #include "wx/wfstream.h" 
  30 #include "wx/module.h" 
  36 #include "wx/object.h" 
  38 //----------------------------------------------------------------------------- 
  39 // RLE encoding and decoding 
  40 //----------------------------------------------------------------------------- 
  42 void RLEencode(unsigned char *p
, unsigned int size
, wxOutputStream
& s
) 
  44     unsigned int data
, last
, cont
; 
  46     // Write 'size' bytes. The PCX official specs say there will be 
  47     // a decoding break at the end of each scanline, so in order to 
  48     // force this decoding break use this function to write, at most, 
  49     // _one_ complete scanline at a time. 
  51     last 
= (unsigned char) *(p
++); 
  57         data 
= (unsigned char) *(p
++); 
  59         // Up to 63 bytes with the same value can be stored using 
  60         // a single { cont, value } pair. 
  62         if ((data 
== last
) && (cont 
< 63)) 
  68             // need to write a 'counter' byte? 
  69             if ((cont 
> 1) || ((last 
& 0xC0) == 0xC0)) 
  70                 s
.PutC((char) (cont 
| 0xC0)); 
  78     // write the last one and return; 
  79     if ((cont 
> 1) || ((last 
& 0xC0) == 0xC0)) 
  80         s
.PutC((char) (cont 
| 0xC0)); 
  85 void RLEdecode(unsigned char *p
, unsigned int size
, wxInputStream
& s
) 
  87     unsigned int i
, data
, cont
; 
  89     // Read 'size' bytes. The PCX official specs say there will be 
  90     // a decoding break at the end of each scanline (but not at the 
  91     // end of each plane inside a scanline). Only use this function 
  92     // to read one or more _complete_ scanlines. Else, more than 
  93     // 'size' bytes might be read and the buffer might overflow. 
  97         data 
= (unsigned char)s
.GetC(); 
  99         // If ((data & 0xC0) != 0xC0), then the value read is a data 
 100         // byte. Else, it is a counter (cont = val & 0x3F) and the 
 101         // next byte is the data byte. 
 103         if ((data 
& 0xC0) != 0xC0) 
 105             *(p
++) = (unsigned char)data
; 
 111             data 
= (unsigned char)s
.GetC(); 
 112             for (i 
= 1; i 
<= cont
; i
++) 
 113                 *(p
++) = (unsigned char)data
; 
 120 //----------------------------------------------------------------------------- 
 121 // PCX reading and saving 
 122 //----------------------------------------------------------------------------- 
 125 #define HDR_MANUFACTURER    0 
 126 #define HDR_VERSION         1 
 127 #define HDR_ENCODING        2 
 128 #define HDR_BITSPERPIXEL    3 
 133 #define HDR_NPLANES         65 
 134 #define HDR_BYTESPERLINE    66 
 135 #define HDR_PALETTEINFO     68 
 139     wxPCX_8BIT
,             // 8 bpp, 1 plane (8 bit) 
 140     wxPCX_24BIT             
// 8 bpp, 3 planes (24 bit) 
 145     wxPCX_OK 
= 0,           // everything was OK 
 146     wxPCX_INVFORMAT 
= 1,    // error in pcx file format 
 147     wxPCX_MEMERR 
= 2,       // error allocating memory 
 148     wxPCX_VERERR 
= 3        // error in pcx version number 
 153 //  Loads a PCX file into the wxImage object pointed by image. 
 154 //  Returns wxPCX_OK on success, or an error code otherwise 
 155 //  (see above for error codes) 
 157 int ReadPCX(wxImage 
*image
, wxInputStream
& stream
) 
 159     unsigned char hdr
[128];         // PCX header 
 160     unsigned char pal
[768];         // palette for 8 bit images 
 161     unsigned char *p
;               // space to store one scanline 
 162     unsigned char *dst
;             // pointer into wxImage data 
 163     unsigned int width
, height
;     // size of the image 
 164     unsigned int bytesperline
;      // bytes per line (each plane) 
 165     int bitsperpixel
;               // bits per pixel (each plane) 
 166     int nplanes
;                    // number of planes 
 167     int encoding
;                   // is the image RLE encoded? 
 168     int format
;                     // image format (8 bit, 24 bit) 
 171     // Read PCX header and check the version number (it must 
 172     // be at least 5 or higher for 8 bit and 24 bit images). 
 174     stream
.Read(hdr
, 128); 
 176     if (hdr
[HDR_VERSION
] < 5) return wxPCX_VERERR
; 
 178     // Extract all image info from the PCX header. 
 180     encoding     
= hdr
[HDR_ENCODING
]; 
 181     nplanes      
= hdr
[HDR_NPLANES
]; 
 182     bitsperpixel 
= hdr
[HDR_BITSPERPIXEL
]; 
 183     bytesperline 
= hdr
[HDR_BYTESPERLINE
] + 256 * hdr
[HDR_BYTESPERLINE 
+ 1]; 
 184     width        
= (hdr
[HDR_XMAX
] + 256 * hdr
[HDR_XMAX 
+ 1]) - 
 185                    (hdr
[HDR_XMIN
] + 256 * hdr
[HDR_XMIN 
+ 1]) + 1; 
 186     height       
= (hdr
[HDR_YMAX
] + 256 * hdr
[HDR_YMAX 
+ 1]) - 
 187                    (hdr
[HDR_YMIN
] + 256 * hdr
[HDR_YMIN 
+ 1]) + 1; 
 189     // Check image format. Currently supported formats are 
 190     // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). 
 192     if ((nplanes 
== 3) && (bitsperpixel 
== 8)) 
 193         format 
= wxPCX_24BIT
; 
 194     else if ((nplanes 
== 1) && (bitsperpixel 
== 8)) 
 197         return wxPCX_INVFORMAT
; 
 199     // If the image is of type wxPCX_8BIT, then there is 
 200     // a palette at the end of the image data. If we were 
 201     // working with a file, we could seek at the end to the 
 202     // end (SeekI(-769, wxFromEnd) and read the palette 
 203     // before proceeding. Unfortunately, this would prevent 
 204     // loading several PCXs in a single stream, so we can't 
 205     // do it. Thus, 8-bit images will have to be decoded in 
 206     // two passes: one to read and decode the image data, 
 207     // and another to replace 'colour indexes' with RGB 
 210     // Resize the image and allocate memory for a scanline. 
 212     image
->Create(width
, height
); 
 217     if ((p 
= (unsigned char *) malloc(bytesperline 
* nplanes
)) == NULL
) 
 220     // Now start reading the file, line by line, and store 
 221     // the data in the format required by wxImage. 
 223     dst 
= image
->GetData(); 
 225     for (j 
= height
; j
; j
--) 
 228             RLEdecode(p
, bytesperline 
* nplanes
, stream
); 
 230             stream
.Read(p
, bytesperline 
* nplanes
); 
 236                 for (i 
= 0; i 
< width
; i
++) 
 238                     // first pass, just store the colour index 
 246                 for (i 
= 0; i 
< width
; i
++) 
 249                     *(dst
++) = p
[i 
+ bytesperline
]; 
 250                     *(dst
++) = p
[i 
+ 2 * bytesperline
]; 
 259     // For 8 bit images, we read the palette, and then do a second 
 260     // pass replacing indexes with their RGB values; 
 262     if (format 
== wxPCX_8BIT
) 
 266         if (stream
.GetC() != 12) 
 267             return wxPCX_INVFORMAT
; 
 269         stream
.Read(pal
, 768); 
 271         p 
= image
->GetData(); 
 272         for (unsigned long k 
= height 
* width
; k
; k
--) 
 275             *(p
++) = pal
[3 * index
]; 
 276             *(p
++) = pal
[3 * index 
+ 1]; 
 277             *(p
++) = pal
[3 * index 
+ 2]; 
 281         unsigned char r
[256]; 
 282         unsigned char g
[256]; 
 283         unsigned char b
[256]; 
 284         for (i 
= 0; i 
< 256; i
++) 
 290         image
->SetPalette(wxPalette(256, r
, g
, b
)); 
 291 #endif // wxUSE_PALETTE 
 298 //  Saves a PCX file into the wxImage object pointed by image. 
 299 //  Returns wxPCX_OK on success, or an error code otherwise 
 300 //  (see above for error codes). Will try to save as 8-bit 
 301 //  PCX if possible, and then fall back to 24-bit if there 
 302 //  are more than 256 different colours. 
 304 int SavePCX(wxImage 
*image
, wxOutputStream
& stream
) 
 306     unsigned char hdr
[128];         // PCX header 
 307     unsigned char pal
[768];         // palette for 8 bit images 
 308     unsigned char *p
;               // space to store one scanline 
 309     unsigned char *src
;             // pointer into wxImage data 
 310     unsigned int width
, height
;     // size of the image 
 311     unsigned int bytesperline
;      // bytes per line (each plane) 
 312     int nplanes 
= 3;                // number of planes 
 313     int format 
= wxPCX_24BIT
;       // image format (8 bit, 24 bit) 
 314     wxHashTable 
h(wxKEY_INTEGER
);   // image histogram 
 315     unsigned long key
;              // key in the hashtable 
 318     // See if we can save as 8 bit. 
 320     if (image
->CountColours(256) <= 256) 
 322         image
->ComputeHistogram(h
); 
 327     // Get image dimensions, calculate bytesperline (must be even, 
 328     // according to PCX specs) and allocate space for one complete 
 332         return wxPCX_INVFORMAT
; 
 334     width 
= image
->GetWidth(); 
 335     height 
= image
->GetHeight(); 
 336     bytesperline 
= width
; 
 337     if (bytesperline 
% 2) 
 340     if ((p 
= (unsigned char *) malloc(bytesperline 
* nplanes
)) == NULL
) 
 343     // Build header data and write it to the stream. Initially, 
 344     // set all bytes to zero (most values default to zero). 
 346     memset(hdr
, 0, sizeof(hdr
)); 
 348     hdr
[HDR_MANUFACTURER
]     = 10; 
 349     hdr
[HDR_VERSION
]          = 5; 
 350     hdr
[HDR_ENCODING
]         = 1; 
 351     hdr
[HDR_NPLANES
]          = nplanes
; 
 352     hdr
[HDR_BITSPERPIXEL
]     = 8; 
 353     hdr
[HDR_BYTESPERLINE
]     = (unsigned char)(bytesperline 
% 256); 
 354     hdr
[HDR_BYTESPERLINE 
+ 1] = (unsigned char)(bytesperline 
/ 256); 
 355     hdr
[HDR_XMAX
]             = (unsigned char)((width 
- 1)  % 256); 
 356     hdr
[HDR_XMAX 
+ 1]         = (unsigned char)((width 
- 1)  / 256); 
 357     hdr
[HDR_YMAX
]             = (unsigned char)((height 
- 1) % 256); 
 358     hdr
[HDR_YMAX 
+ 1]         = (unsigned char)((height 
- 1) / 256); 
 359     hdr
[HDR_PALETTEINFO
]      = 1; 
 361     stream
.Write(hdr
, 128); 
 363     // Encode image data line by line and write it to the stream 
 365     src 
= image
->GetData(); 
 367     for (; height
; height
--) 
 373                 unsigned char r
, g
, b
; 
 376                 for (i 
= 0; i 
< width
; i
++) 
 381                     key 
= (r 
<< 16) | (g 
<< 8) | b
; 
 383                     hnode 
= (wxHNode 
*) h
.Get(key
); 
 384                     p
[i
] = (unsigned char)hnode
->index
; 
 390                 for (i 
= 0; i 
< width
; i
++) 
 393                     p
[i 
+ bytesperline
] = *(src
++); 
 394                     p
[i 
+ 2 * bytesperline
] = *(src
++); 
 400         RLEencode(p
, bytesperline 
* nplanes
, stream
); 
 405     // For 8 bit images, build the palette and write it to the stream 
 407     if (format 
== wxPCX_8BIT
) 
 412         // zero unused colours 
 413         memset(pal
, 0, sizeof(pal
)); 
 416         while ((node 
= h
.Next()) != NULL
) 
 418             key 
= node
->GetKeyInteger(); 
 419             hnode 
= (wxHNode 
*) node
->GetData(); 
 421             pal
[3 * hnode
->index
]     = (unsigned char)(key 
>> 16); 
 422             pal
[3 * hnode
->index 
+ 1] = (unsigned char)(key 
>> 8); 
 423             pal
[3 * hnode
->index 
+ 2] = (unsigned char)(key
); 
 428         stream
.Write(pal
, 768); 
 434 //----------------------------------------------------------------------------- 
 436 //----------------------------------------------------------------------------- 
 438 IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler
,wxImageHandler
) 
 440 bool wxPCXHandler::LoadFile( wxImage 
*image
, wxInputStream
& stream
, bool verbose
, int WXUNUSED(index
) ) 
 444     if (!CanRead(stream
)) 
 447             wxLogError(_("PCX: this is not a PCX file.")); 
 454     if ((error 
= ReadPCX(image
, stream
)) != wxPCX_OK
) 
 460                 case wxPCX_INVFORMAT
: wxLogError(_("PCX: image format unsupported")); break; 
 461                 case wxPCX_MEMERR
:    wxLogError(_("PCX: couldn't allocate memory")); break; 
 462                 case wxPCX_VERERR
:    wxLogError(_("PCX: version number too low")); break; 
 463                 default:              wxLogError(_("PCX: unknown error !!!")); 
 473 bool wxPCXHandler::SaveFile( wxImage 
*image
, wxOutputStream
& stream
, bool verbose 
) 
 477     if ((error 
= SavePCX(image
, stream
)) != wxPCX_OK
) 
 483                 case wxPCX_INVFORMAT
: wxLogError(_("PCX: invalid image")); break; 
 484                 case wxPCX_MEMERR
:    wxLogError(_("PCX: couldn't allocate memory")); break; 
 485                 default:              wxLogError(_("PCX: unknown error !!!")); 
 490     return (error 
== wxPCX_OK
); 
 493 bool wxPCXHandler::DoCanRead( wxInputStream
& stream 
) 
 498     stream
.SeekI(-1, wxFromCurrent
); 
 500     // not very safe, but this is all we can get from PCX header :-( 
 504 #endif // wxUSE_STREAMS && wxUSE_PCX