]>
Commit | Line | Data |
---|---|---|
56c66755 GRG |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: imagpcx.cpp | |
3 | // Purpose: wxImage PCX handler | |
4 | // Author: Guillermo Rodriguez Garcia <guille@iies.es> | |
5 | // Version: 1.00 | |
4df78dc3 GRG |
6 | // CVS-ID: $Id$ |
7 | // Copyright: (c) 1999 Guillermo Rodriguez Garcia | |
56c66755 GRG |
8 | // Licence: wxWindows licence |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | /* | |
12 | We don't put pragma implement in this file because it is already present in | |
13 | src/common/image.cpp | |
14 | */ | |
15 | ||
16 | // For compilers that support precompilation, includes "wx.h". | |
17 | #include "wx/wxprec.h" | |
18 | ||
19 | #ifdef __BORLANDC__ | |
20 | #pragma hdrstop | |
21 | #endif | |
22 | ||
b9b32d5c GRG |
23 | #ifndef WX_PRECOMP |
24 | # include "wx/defs.h" | |
25 | #endif | |
26 | ||
995612e2 | 27 | #if wxUSE_STREAMS && wxUSE_PCX |
b9b32d5c | 28 | |
56c66755 GRG |
29 | #include "wx/image.h" |
30 | #include "wx/wfstream.h" | |
31 | #include "wx/module.h" | |
32 | #include "wx/log.h" | |
f6b77239 | 33 | #include "wx/intl.h" |
1044a386 | 34 | |
4df78dc3 GRG |
35 | //----------------------------------------------------------------------------- |
36 | // PCX decoding | |
37 | //----------------------------------------------------------------------------- | |
38 | ||
5e0201ea | 39 | void RLEencode(unsigned char *WXUNUSED(p), unsigned int WXUNUSED(size), wxOutputStream& WXUNUSED(s)) |
4df78dc3 GRG |
40 | { |
41 | } | |
42 | ||
43 | void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s) | |
44 | { | |
45 | unsigned int i, data, cont; | |
46 | ||
47 | // Read 'size' bytes. The PCX official specs say there will be | |
48 | // a decoding break at the end of each scanline (but not at the | |
49 | // end of each plane inside a scanline). Only use this function | |
50 | // to read one or more _complete_ scanlines. Else, more than | |
51 | // 'size' bytes might be read and the buffer might overflow. | |
52 | // | |
53 | while (size > 0) | |
54 | { | |
55 | data = (unsigned char)s.GetC(); | |
56 | ||
57 | // If ((data & 0xC0) != 0xC0), then the value read is a data | |
58 | // byte. Else, it is a counter (cont = val & 0x3F) and the | |
59 | // next byte is the data byte. | |
60 | // | |
61 | if ((data & 0xC0) != 0xC0) | |
62 | { | |
63 | *(p++) = data; | |
64 | size--; | |
65 | } | |
66 | else | |
67 | { | |
68 | cont = data & 0x3F; | |
69 | data = (unsigned char)s.GetC(); | |
70 | for (i = 1; i <= cont; i++) | |
71 | *(p++) = data; | |
72 | size -= cont; | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | ||
78 | /* PCX header */ | |
995612e2 | 79 | #define HDR_VERSION 1 |
4df78dc3 GRG |
80 | #define HDR_ENCODING 2 |
81 | #define HDR_BITSPERPIXEL 3 | |
82 | #define HDR_XMIN 4 | |
83 | #define HDR_YMIN 6 | |
995612e2 | 84 | #define HDR_XMAX 8 |
4df78dc3 GRG |
85 | #define HDR_YMAX 10 |
86 | #define HDR_NPLANES 65 | |
87 | #define HDR_BYTESPERLINE 66 | |
88 | ||
e4b8154a GRG |
89 | // image formats |
90 | enum { | |
91 | wxPCX_8BIT, // 8 bpp, 1 plane (8 bit) | |
92 | wxPCX_24BIT // 8 bpp, 3 planes (24 bit) | |
93 | }; | |
94 | ||
95 | // error codes | |
96 | enum { | |
97 | wxPCX_OK = 0, // everything was OK | |
98 | wxPCX_INVFORMAT = 1, // error in pcx file format | |
99 | wxPCX_MEMERR = 2, // error allocating memory | |
100 | wxPCX_VERERR = 3 // error in pcx version number | |
101 | }; | |
4df78dc3 GRG |
102 | |
103 | // ReadPCX: | |
104 | // Loads a PCX file into the wxImage object pointed by image. | |
e4b8154a GRG |
105 | // Returns wxPCX_OK on success, or an error code otherwise |
106 | // (see above for error codes) | |
4df78dc3 GRG |
107 | // |
108 | int ReadPCX(wxImage *image, wxInputStream& stream) | |
109 | { | |
110 | unsigned char hdr[128]; // PCX header | |
111 | unsigned char pal[768]; // palette for 8 bit images | |
112 | unsigned char *p; // space to store one scanline | |
113 | unsigned char *dst; // pointer into wxImage data | |
114 | unsigned int width, height; // size of the image | |
115 | unsigned int bytesperline; // bytes per line (each plane) | |
116 | int bitsperpixel; // bits per pixel (each plane) | |
117 | int nplanes; // number of planes | |
118 | int encoding; // is the image RLE encoded? | |
119 | int format; // image format (8 bit, 24 bit) | |
120 | unsigned int i; | |
121 | off_t pos; | |
122 | ||
123 | // Read PCX header and check the version number (it must | |
124 | // be at least 5 or higher for 8 bit and 24 bit images). | |
125 | // | |
126 | stream.Read(hdr, 128); | |
127 | ||
e4b8154a | 128 | if (hdr[HDR_VERSION] < 5) return wxPCX_VERERR; |
4df78dc3 GRG |
129 | |
130 | // Extract all image info from the PCX header. | |
131 | // | |
132 | encoding = hdr[HDR_ENCODING]; | |
133 | nplanes = hdr[HDR_NPLANES]; | |
134 | bitsperpixel = hdr[HDR_BITSPERPIXEL]; | |
135 | bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1]; | |
136 | width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) - | |
137 | (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1; | |
138 | height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) - | |
139 | (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1; | |
140 | ||
141 | // Check image format. Currently supported formats are | |
142 | // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). | |
143 | // | |
144 | if ((nplanes == 3) && (bitsperpixel == 8)) | |
e4b8154a | 145 | format = wxPCX_24BIT; |
4df78dc3 | 146 | else if ((nplanes == 1) && (bitsperpixel == 8)) |
e4b8154a | 147 | format = wxPCX_8BIT; |
4df78dc3 | 148 | else |
e4b8154a | 149 | return wxPCX_INVFORMAT; |
4df78dc3 | 150 | |
e4b8154a | 151 | // If the image is of type wxPCX_8BIT, then there is a |
4df78dc3 GRG |
152 | // palette at the end of the file. Read it now before |
153 | // proceeding. | |
154 | // | |
e4b8154a | 155 | if (format == wxPCX_8BIT) |
f0d922cf GRG |
156 | { |
157 | pos = stream.TellI(); | |
158 | stream.SeekI(-769, wxFromEnd); | |
4df78dc3 | 159 | |
f0d922cf | 160 | if (stream.GetC() != 12) |
e4b8154a | 161 | return wxPCX_INVFORMAT; |
4df78dc3 | 162 | |
f0d922cf GRG |
163 | stream.Read(pal, 768); |
164 | stream.SeekI(pos, wxFromStart); | |
165 | } | |
4df78dc3 GRG |
166 | |
167 | // Allocate memory for a scanline and resize the image. | |
168 | // | |
169 | image->Create(width, height); | |
170 | ||
171 | if (!image->Ok()) | |
e4b8154a | 172 | return wxPCX_MEMERR; |
4df78dc3 GRG |
173 | |
174 | if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) | |
e4b8154a | 175 | return wxPCX_MEMERR; |
4df78dc3 GRG |
176 | |
177 | // Now start reading the file, line by line, and store | |
178 | // the data in the format required by wxImage. | |
179 | // | |
180 | dst = image->GetData(); | |
181 | ||
182 | for (; height; height--) | |
183 | { | |
184 | if (encoding) | |
185 | RLEdecode(p, bytesperline * nplanes, stream); | |
186 | else | |
187 | stream.Read(p, bytesperline * nplanes); | |
188 | ||
189 | switch (format) | |
190 | { | |
e4b8154a | 191 | case wxPCX_8BIT: |
4df78dc3 GRG |
192 | { |
193 | for (i = 0; i < width; i++) | |
194 | { | |
195 | *(dst++) = pal[ 3 * (p[i]) ]; | |
196 | *(dst++) = pal[ 3 * (p[i]) + 1]; | |
197 | *(dst++) = pal[ 3 * (p[i]) + 2]; | |
198 | } | |
199 | break; | |
200 | } | |
e4b8154a | 201 | case wxPCX_24BIT: |
4df78dc3 GRG |
202 | { |
203 | for (i = 0; i < width; i++) | |
204 | { | |
205 | *(dst++) = p[i]; | |
206 | *(dst++) = p[i + bytesperline]; | |
995612e2 | 207 | *(dst++) = p[i + 2 * bytesperline]; |
4df78dc3 GRG |
208 | } |
209 | break; | |
210 | } | |
211 | } | |
212 | } | |
213 | ||
214 | free(p); | |
215 | ||
e4b8154a | 216 | return wxPCX_OK; |
4df78dc3 GRG |
217 | } |
218 | ||
219 | ||
56c66755 GRG |
220 | //----------------------------------------------------------------------------- |
221 | // wxPCXHandler | |
222 | //----------------------------------------------------------------------------- | |
223 | ||
224 | #if !USE_SHARED_LIBRARIES | |
225 | IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler) | |
226 | #endif | |
227 | ||
700ec454 | 228 | bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) |
56c66755 | 229 | { |
4df78dc3 GRG |
230 | int error; |
231 | ||
232 | if (!CanRead(stream)) | |
233 | { | |
234 | if (verbose) | |
58c837a4 | 235 | wxLogError(_("PCX: this is not a PCX file.")); |
4df78dc3 GRG |
236 | |
237 | return FALSE; | |
238 | } | |
239 | ||
56c66755 GRG |
240 | image->Destroy(); |
241 | ||
e4b8154a | 242 | if ((error = ReadPCX(image, stream)) != wxPCX_OK) |
4df78dc3 GRG |
243 | { |
244 | if (verbose) | |
245 | { | |
246 | switch (error) | |
247 | { | |
e4b8154a GRG |
248 | case wxPCX_INVFORMAT: wxLogError(_("wxPCXHandler: image format unsupported")); break; |
249 | case wxPCX_MEMERR: wxLogError(_("wxPCXHandler: couldn't allocate memory")); break; | |
250 | case wxPCX_VERERR: wxLogError(_("wxPCXHandler: version number too low")); break; | |
251 | default: wxLogError(_("wxPCXHandler: unknown error !!!")); | |
4df78dc3 GRG |
252 | } |
253 | } | |
254 | image->Destroy(); | |
255 | return FALSE; | |
256 | } | |
56c66755 | 257 | |
4df78dc3 | 258 | return TRUE; |
56c66755 GRG |
259 | } |
260 | ||
5e0201ea | 261 | bool wxPCXHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool verbose ) |
56c66755 | 262 | { |
58c837a4 | 263 | wxFAIL_MSG(wxT("wxPCXHandler::SaveFile still not implemented")); |
56c66755 GRG |
264 | |
265 | return FALSE; | |
266 | } | |
267 | ||
995612e2 | 268 | bool wxPCXHandler::DoCanRead( wxInputStream& stream ) |
56c66755 | 269 | { |
4df78dc3 | 270 | unsigned char c; |
4df78dc3 | 271 | |
4df78dc3 | 272 | c = stream.GetC(); |
a05da1b6 | 273 | stream.SeekI(-1, wxFromCurrent); |
4df78dc3 GRG |
274 | |
275 | // not very safe, but this is all we can get from PCX header :-( | |
276 | return (c == 10); | |
56c66755 GRG |
277 | } |
278 | ||
b9b32d5c | 279 | #endif // wxUSE_STREAMS && wxUSE_PCX |
56c66755 | 280 |