]> git.saurik.com Git - wxWidgets.git/blob - src/common/imagpcx.cpp
slight bug in waitconnection
[wxWidgets.git] / src / common / imagpcx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: imagpcx.cpp
3 // Purpose: wxImage PCX handler
4 // Author: Guillermo Rodriguez Garcia <guille@iies.es>
5 // Version: 1.00
6 // CVS-ID: $Id$
7 // Copyright: (c) 1999 Guillermo Rodriguez Garcia
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #ifdef __GNUG__
12 #pragma implementation "imagpcx.h"
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #ifndef WX_PRECOMP
23 # include "wx/defs.h"
24 #endif
25
26 #if wxUSE_STREAMS && wxUSE_PCX
27
28 #include "wx/imagpcx.h"
29 #include "wx/wfstream.h"
30 #include "wx/module.h"
31 #include "wx/log.h"
32 #include "wx/intl.h"
33
34 #include "wx/hash.h"
35 #include "wx/list.h"
36 #include "wx/object.h"
37
38 //-----------------------------------------------------------------------------
39 // RLE encoding and decoding
40 //-----------------------------------------------------------------------------
41
42 void RLEencode(unsigned char *p, unsigned int size, wxOutputStream& s)
43 {
44 unsigned int data, last, cont;
45
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.
50
51 last = (unsigned char) *(p++);
52 cont = 1;
53 size--;
54
55 while (size-- > 0)
56 {
57 data = (unsigned char) *(p++);
58
59 // Up to 63 bytes with the same value can be stored using a
60 // single { cont, value } pair.
61 //
62 if ((data == last) && (cont < 63))
63 {
64 cont++;
65 }
66 else
67 {
68 // Need to write a 'counter' byte?
69 //
70 if ((cont > 1) || ((last & 0xC0) == 0xC0))
71 s.PutC((char) (cont | 0xC0));
72
73 s.PutC((char) last);
74 last = data;
75 cont = 1;
76 }
77 }
78
79 // Write the last one and return;
80 //
81 if ((cont > 1) || ((last & 0xC0) == 0xC0))
82 s.PutC((char) (cont | 0xC0));
83
84 s.PutC((char) last);
85 }
86
87 void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s)
88 {
89 unsigned int i, data, cont;
90
91 // Read 'size' bytes. The PCX official specs say there will be
92 // a decoding break at the end of each scanline (but not at the
93 // end of each plane inside a scanline). Only use this function
94 // to read one or more _complete_ scanlines. Else, more than
95 // 'size' bytes might be read and the buffer might overflow.
96 //
97 while (size > 0)
98 {
99 data = (unsigned char)s.GetC();
100
101 // If ((data & 0xC0) != 0xC0), then the value read is a data
102 // byte. Else, it is a counter (cont = val & 0x3F) and the
103 // next byte is the data byte.
104 //
105 if ((data & 0xC0) != 0xC0)
106 {
107 *(p++) = data;
108 size--;
109 }
110 else
111 {
112 cont = data & 0x3F;
113 data = (unsigned char)s.GetC();
114 for (i = 1; i <= cont; i++)
115 *(p++) = data;
116 size -= cont;
117 }
118 }
119 }
120
121
122 //-----------------------------------------------------------------------------
123 // PCX reading and saving
124 //-----------------------------------------------------------------------------
125
126 // PCX header
127 #define HDR_MANUFACTURER 0
128 #define HDR_VERSION 1
129 #define HDR_ENCODING 2
130 #define HDR_BITSPERPIXEL 3
131 #define HDR_XMIN 4
132 #define HDR_YMIN 6
133 #define HDR_XMAX 8
134 #define HDR_YMAX 10
135 #define HDR_NPLANES 65
136 #define HDR_BYTESPERLINE 66
137 #define HDR_PALETTEINFO 68
138
139 // image formats
140 enum {
141 wxPCX_8BIT, // 8 bpp, 1 plane (8 bit)
142 wxPCX_24BIT // 8 bpp, 3 planes (24 bit)
143 };
144
145 // error codes
146 enum {
147 wxPCX_OK = 0, // everything was OK
148 wxPCX_INVFORMAT = 1, // error in pcx file format
149 wxPCX_MEMERR = 2, // error allocating memory
150 wxPCX_VERERR = 3 // error in pcx version number
151 };
152
153
154 // ReadPCX:
155 // Loads a PCX file into the wxImage object pointed by image.
156 // Returns wxPCX_OK on success, or an error code otherwise
157 // (see above for error codes)
158 //
159 int ReadPCX(wxImage *image, wxInputStream& stream)
160 {
161 unsigned char hdr[128]; // PCX header
162 unsigned char pal[768]; // palette for 8 bit images
163 unsigned char *p; // space to store one scanline
164 unsigned char *dst; // pointer into wxImage data
165 unsigned int width, height; // size of the image
166 unsigned int bytesperline; // bytes per line (each plane)
167 int bitsperpixel; // bits per pixel (each plane)
168 int nplanes; // number of planes
169 int encoding; // is the image RLE encoded?
170 int format; // image format (8 bit, 24 bit)
171 unsigned int i;
172 off_t pos;
173
174 // Read PCX header and check the version number (it must
175 // be at least 5 or higher for 8 bit and 24 bit images).
176 //
177 stream.Read(hdr, 128);
178
179 if (hdr[HDR_VERSION] < 5) return wxPCX_VERERR;
180
181 // Extract all image info from the PCX header.
182 //
183 encoding = hdr[HDR_ENCODING];
184 nplanes = hdr[HDR_NPLANES];
185 bitsperpixel = hdr[HDR_BITSPERPIXEL];
186 bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1];
187 width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) -
188 (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1;
189 height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) -
190 (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1;
191
192 // Check image format. Currently supported formats are
193 // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes).
194 //
195 if ((nplanes == 3) && (bitsperpixel == 8))
196 format = wxPCX_24BIT;
197 else if ((nplanes == 1) && (bitsperpixel == 8))
198 format = wxPCX_8BIT;
199 else
200 return wxPCX_INVFORMAT;
201
202 // If the image is of type wxPCX_8BIT, then there is a
203 // palette at the end of the file. Read it now before
204 // proceeding.
205 //
206 if (format == wxPCX_8BIT)
207 {
208 pos = stream.TellI();
209 stream.SeekI(-769, wxFromEnd);
210
211 if (stream.GetC() != 12)
212 return wxPCX_INVFORMAT;
213
214 stream.Read(pal, 768);
215 stream.SeekI(pos, wxFromStart);
216 }
217
218 // Allocate memory for a scanline and resize the image.
219 //
220 image->Create(width, height);
221
222 if (!image->Ok())
223 return wxPCX_MEMERR;
224
225 if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL)
226 return wxPCX_MEMERR;
227
228 // Now start reading the file, line by line, and store
229 // the data in the format required by wxImage.
230 //
231 dst = image->GetData();
232
233 for (; height; height--)
234 {
235 if (encoding)
236 RLEdecode(p, bytesperline * nplanes, stream);
237 else
238 stream.Read(p, bytesperline * nplanes);
239
240 switch (format)
241 {
242 case wxPCX_8BIT:
243 {
244 for (i = 0; i < width; i++)
245 {
246 *(dst++) = pal[ 3 * (p[i]) ];
247 *(dst++) = pal[ 3 * (p[i]) + 1];
248 *(dst++) = pal[ 3 * (p[i]) + 2];
249 }
250 break;
251 }
252 case wxPCX_24BIT:
253 {
254 for (i = 0; i < width; i++)
255 {
256 *(dst++) = p[i];
257 *(dst++) = p[i + bytesperline];
258 *(dst++) = p[i + 2 * bytesperline];
259 }
260 break;
261 }
262 }
263 }
264
265 free(p);
266
267 return wxPCX_OK;
268 }
269
270 // SavePCX:
271 // Saves a PCX file into the wxImage object pointed by image.
272 // Returns wxPCX_OK on success, or an error code otherwise
273 // (see above for error codes). Currently, always saves images
274 // in 24 bit format. XXX
275 //
276 int SavePCX(wxImage *image, wxOutputStream& stream)
277 {
278 unsigned char hdr[128]; // PCX header
279 unsigned char pal[768]; // palette for 8 bit images
280 unsigned char *p; // space to store one scanline
281 unsigned char *src; // pointer into wxImage data
282 unsigned int width, height; // size of the image
283 unsigned int bytesperline; // bytes per line (each plane)
284 int nplanes = 3; // number of planes
285 int format = wxPCX_24BIT; // image format (8 bit, 24 bit)
286 wxHashTable h(wxKEY_INTEGER); // image histogram
287 unsigned long key; // key in the hashtable
288 unsigned int i;
289
290 // See if we can save as 8 bit.
291 //
292 if (image->CountColours(256) <= 256)
293 {
294 image->ComputeHistogram(h);
295 format = wxPCX_8BIT;
296 nplanes = 1;
297 }
298
299 // Get image dimensions, calculate bytesperline (must be even,
300 // according to PCX specs) and allocate space for one complete
301 // scanline.
302 //
303 if (!image->Ok())
304 return wxPCX_INVFORMAT;
305
306 width = image->GetWidth();
307 height = image->GetHeight();
308 bytesperline = width;
309 if (bytesperline % 2)
310 bytesperline++;
311
312 if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL)
313 return wxPCX_MEMERR;
314
315 // Build header data and write it to the stream. Initially,
316 // set all bytes to zero (most values default to zero).
317 //
318 memset(hdr, 0, sizeof(hdr));
319
320 hdr[HDR_MANUFACTURER] = 10;
321 hdr[HDR_VERSION] = 5;
322 hdr[HDR_ENCODING] = 1;
323 hdr[HDR_NPLANES] = nplanes;
324 hdr[HDR_BITSPERPIXEL] = 8;
325 hdr[HDR_BYTESPERLINE] = bytesperline % 256;
326 hdr[HDR_BYTESPERLINE + 1] = bytesperline / 256;
327 hdr[HDR_XMAX] = (width - 1) % 256;
328 hdr[HDR_XMAX + 1] = (width - 1) / 256;
329 hdr[HDR_YMAX] = (height - 1) % 256;
330 hdr[HDR_YMAX + 1] = (height - 1) / 256;
331 hdr[HDR_PALETTEINFO] = 1;
332
333 stream.Write(hdr, 128);
334
335 // Encode image data line by line and write it to the stream
336 //
337 src = image->GetData();
338
339 for (; height; height--)
340 {
341 switch (format)
342 {
343 case wxPCX_8BIT:
344 {
345 unsigned char r, g, b;
346 wxHNode *hnode;
347
348 for (i = 0; i < width; i++)
349 {
350 r = *(src++);
351 g = *(src++);
352 b = *(src++);
353 key = (r << 16) | (g << 8) | b;
354
355 hnode = (wxHNode *) h.Get(key);
356 p[i] = hnode->index;
357 }
358 break;
359 }
360 case wxPCX_24BIT:
361 {
362 for (i = 0; i < width; i++)
363 {
364 p[i] = *(src++);
365 p[i + bytesperline] = *(src++);
366 p[i + 2 * bytesperline] = *(src++);
367 }
368 break;
369 }
370 }
371
372 RLEencode(p, bytesperline * nplanes, stream);
373 }
374
375 free(p);
376
377 // For 8 bit images, build the palette and write it to the stream
378 //
379 if (format == wxPCX_8BIT)
380 {
381 wxNode *node;
382 wxHNode *hnode;
383
384 // zero unused colours
385 memset(pal, 0, sizeof(pal));
386
387 h.BeginFind();
388 while ((node = h.Next()) != NULL)
389 {
390 key = node->GetKeyInteger();
391 hnode = (wxHNode *) node->GetData();
392
393 pal[3 * hnode->index] = (unsigned char)(key >> 16);
394 pal[3 * hnode->index + 1] = (unsigned char)(key >> 8);
395 pal[3 * hnode->index + 2] = (unsigned char)(key);
396 delete hnode;
397 }
398
399 stream.PutC(12);
400 stream.Write(pal, 768);
401 }
402
403 return wxPCX_OK;
404 }
405
406 //-----------------------------------------------------------------------------
407 // wxPCXHandler
408 //-----------------------------------------------------------------------------
409
410 IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler)
411
412 bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
413 {
414 int error;
415
416 if (!CanRead(stream))
417 {
418 if (verbose)
419 wxLogError(_("PCX: this is not a PCX file."));
420
421 return FALSE;
422 }
423
424 image->Destroy();
425
426 if ((error = ReadPCX(image, stream)) != wxPCX_OK)
427 {
428 if (verbose)
429 {
430 switch (error)
431 {
432 case wxPCX_INVFORMAT: wxLogError(_("wxPCXHandler: image format unsupported")); break;
433 case wxPCX_MEMERR: wxLogError(_("wxPCXHandler: couldn't allocate memory")); break;
434 case wxPCX_VERERR: wxLogError(_("wxPCXHandler: version number too low")); break;
435 default: wxLogError(_("wxPCXHandler: unknown error !!!"));
436 }
437 }
438 image->Destroy();
439 return FALSE;
440 }
441
442 return TRUE;
443 }
444
445 bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
446 {
447 int error;
448
449 if ((error = SavePCX(image, stream)) != wxPCX_OK)
450 {
451 if (verbose)
452 {
453 switch (error)
454 {
455 case wxPCX_INVFORMAT: wxLogError(_("wxPCXHandler: invalid image")); break;
456 case wxPCX_MEMERR: wxLogError(_("wxPCXHandler: couldn't allocate memory")); break;
457 default: wxLogError(_("wxPCXHandler: unknown error !!!"));
458 }
459 }
460 }
461
462 return (error == wxPCX_OK);
463 }
464
465 bool wxPCXHandler::DoCanRead( wxInputStream& stream )
466 {
467 unsigned char c;
468
469 c = stream.GetC();
470 stream.SeekI(-1, wxFromCurrent);
471
472 // not very safe, but this is all we can get from PCX header :-(
473 return (c == 10);
474 }
475
476 #endif // wxUSE_STREAMS && wxUSE_PCX
477