source: liacs/MIR2010/SourceCode/cximage/ximapcx.cpp@ 379

Last change on this file since 379 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 14.8 KB
RevLine 
[95]1/*
2 * File: ximapcx.cpp
3 * Purpose: Platform Independent PCX Image Class Loader and Writer
4 * 05/Jan/2002 Davide Pizzolato - www.xdp.it
5 * CxImage version 6.0.0 02/Feb/2008
6 *
7 * based on ppmtopcx.c - convert a portable pixmap to PCX
8 * Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
9 * based on ppmtopcx.c by Michael Davidson
10 */
11
12#include "ximapcx.h"
13
14#if CXIMAGE_SUPPORT_PCX
15
16#include "xmemfile.h"
17
18#define PCX_MAGIC 0X0A // PCX magic number
19#define PCX_256_COLORS 0X0C // magic number for 256 colors
20#define PCX_HDR_SIZE 128 // size of PCX header
21#define PCX_MAXCOLORS 256
22#define PCX_MAXPLANES 4
23#define PCX_MAXVAL 255
24
25////////////////////////////////////////////////////////////////////////////////
26#if CXIMAGE_SUPPORT_DECODE
27////////////////////////////////////////////////////////////////////////////////
28bool CxImagePCX::Decode(CxFile *hFile)
29{
30 if (hFile == NULL) return false;
31
32 PCXHEADER pcxHeader;
33 int i, x, y, y2, nbytes, count, Height, Width;
34 BYTE c, ColorMap[PCX_MAXCOLORS][3];
35 BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL;
36 BYTE *pcxplanes, *pcxpixels;
37
38 cx_try
39 {
40 if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image");
41
42 PCX_toh(&pcxHeader);
43
44 if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file");
45 // Check for PCX run length encoding
46 if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme");
47
48 Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1;
49 Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1;
50 info.xDPI = pcxHeader.Hres;
51 info.yDPI = pcxHeader.Vres;
52
53 if (info.nEscape == -1){
54 head.biWidth = Width;
55 head.biHeight= Height;
56 info.dwType = CXIMAGE_FORMAT_PCX;
57 return true;
58 }
59
60 // Check that we can handle this image format
61 if (pcxHeader.ColorPlanes > 4)
62 cx_throw("Can't handle image with more than 4 planes");
63
64 // Create the image
65 if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){
66 Create (Width, Height, 24, CXIMAGE_FORMAT_PCX);
67#if CXIMAGE_SUPPORT_ALPHA
68 if (pcxHeader.ColorPlanes==4) AlphaCreate();
69#endif //CXIMAGE_SUPPORT_ALPHA
70 } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1)
71 Create (Width, Height, 4, CXIMAGE_FORMAT_PCX);
72 else
73 Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX);
74
75 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
76
77 //Read the image and check if it's ok
78 nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height;
79 lpHead1 = pcximage = (BYTE*)malloc(nbytes);
80 while (nbytes > 0){
81 if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX");
82
83 hFile->Read(&c,1,1);
84 if ((c & 0XC0) != 0XC0){ // Repeated group
85 *pcximage++ = c;
86 --nbytes;
87 continue;
88 }
89 count = c & 0X3F; // extract count
90 hFile->Read(&c,1,1);
91 if (count > nbytes) cx_throw("repeat count spans end of image");
92
93 nbytes -= count;
94 while (--count >=0) *pcximage++ = c;
95 }
96 pcximage = lpHead1;
97
98 //store the palette
99 for (i = 0; i < 16; i++){
100 ColorMap[i][0] = pcxHeader.ColorMap[i][0];
101 ColorMap[i][1] = pcxHeader.ColorMap[i][1];
102 ColorMap[i][2] = pcxHeader.ColorMap[i][2];
103 }
104 if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){
105 hFile->Read(&c,1,1);
106 if (c != PCX_256_COLORS) cx_throw("bad color map signature");
107
108 for (i = 0; i < PCX_MAXCOLORS; i++){
109 hFile->Read(&ColorMap[i][0],1,1);
110 hFile->Read(&ColorMap[i][1],1,1);
111 hFile->Read(&ColorMap[i][2],1,1);
112 }
113 }
114 if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){
115 ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0;
116 ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255;
117 }
118
119 for (DWORD idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((BYTE)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]);
120
121 lpHead2 = pcxpixels = (BYTE *)malloc(Width + pcxHeader.BytesPerLine * 8);
122 // Convert the image
123 for (y = 0; y < Height; y++){
124
125 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
126
127 y2=Height-1-y;
128 pcxpixels = lpHead2;
129 pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes);
130
131 if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){
132 // Deal with 24 bit color image
133 for (x = 0; x < Width; x++){
134 SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));
135 }
136 continue;
137#if CXIMAGE_SUPPORT_ALPHA
138 } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){
139 for (x = 0; x < Width; x++){
140 SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));
141 AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]);
142 }
143 continue;
144#endif //CXIMAGE_SUPPORT_ALPHA
145 } else if (pcxHeader.ColorPlanes == 1) {
146 if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){
147 cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane");
148 }
149 } else {
150 if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){
151 cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel");
152 }
153 }
154 for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]);
155 }
156
157 } cx_catch {
158 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
159 if (lpHead1){ free(lpHead1); lpHead1 = NULL; }
160 if (lpHead2){ free(lpHead2); lpHead2 = NULL; }
161 return false;
162 }
163 if (lpHead1){ free(lpHead1); lpHead1 = NULL; }
164 if (lpHead2){ free(lpHead2); lpHead2 = NULL; }
165 return true;
166}
167////////////////////////////////////////////////////////////////////////////////
168#endif //CXIMAGE_SUPPORT_DECODE
169////////////////////////////////////////////////////////////////////////////////
170#if CXIMAGE_SUPPORT_ENCODE
171////////////////////////////////////////////////////////////////////////////////
172bool CxImagePCX::Encode(CxFile * hFile)
173{
174 if (EncodeSafeCheck(hFile)) return false;
175
176 cx_try
177 {
178 PCXHEADER pcxHeader;
179 memset(&pcxHeader,0,sizeof(pcxHeader));
180 pcxHeader.Manufacturer = PCX_MAGIC;
181 pcxHeader.Version = 5;
182 pcxHeader.Encoding = 1;
183 pcxHeader.Xmin = 0;
184 pcxHeader.Ymin = 0;
185 pcxHeader.Xmax = (WORD)head.biWidth-1;
186 pcxHeader.Ymax = (WORD)head.biHeight-1;
187 pcxHeader.Hres = (WORD)info.xDPI;
188 pcxHeader.Vres = (WORD)info.yDPI;
189 pcxHeader.Reserved = 0;
190 pcxHeader.PaletteType = head.biClrUsed==0;
191
192 switch(head.biBitCount){
193 case 24:
194 case 8:
195 {
196 pcxHeader.BitsPerPixel = 8;
197 pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1;
198#if CXIMAGE_SUPPORT_ALPHA
199 if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4;
200#endif //CXIMAGE_SUPPORT_ALPHA
201 pcxHeader.BytesPerLine = (WORD)head.biWidth;
202 break;
203 }
204 default: //(4 1)
205 pcxHeader.BitsPerPixel = 1;
206 pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1;
207 pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3);
208 }
209
210 if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){
211 pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0;
212 pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255;
213 }
214 if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){
215 RGBQUAD c;
216 for (int i = 0; i < 16; i++){
217 c=GetPaletteColor(i);
218 pcxHeader.ColorMap[i][0] = c.rgbRed;
219 pcxHeader.ColorMap[i][1] = c.rgbGreen;
220 pcxHeader.ColorMap[i][2] = c.rgbBlue;
221 }
222 }
223
224 pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1);
225
226 PCX_toh(&pcxHeader);
227 if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 )
228 cx_throw("cannot write PCX header");
229 PCX_toh(&pcxHeader);
230
231 CxMemFile buffer;
232 buffer.Open();
233
234 BYTE c,n;
235 long x,y;
236 if (head.biClrUsed==0){
237 for (y = head.biHeight-1; y >=0 ; y--){
238 for (int p=0; p<pcxHeader.ColorPlanes; p++){
239 c=n=0;
240 for (x = 0; x<head.biWidth; x++){
241 if (p==0)
242 PCX_PackPixels(BlindGetPixelColor(x,y).rgbRed,c,n,buffer);
243 else if (p==1)
244 PCX_PackPixels(BlindGetPixelColor(x,y).rgbGreen,c,n,buffer);
245 else if (p==2)
246 PCX_PackPixels(BlindGetPixelColor(x,y).rgbBlue,c,n,buffer);
247#if CXIMAGE_SUPPORT_ALPHA
248 else if (p==3)
249 PCX_PackPixels(BlindAlphaGet(x,y),c,n,buffer);
250#endif //CXIMAGE_SUPPORT_ALPHA
251 }
252 PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);
253 }
254 }
255
256 hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
257
258 } else if (head.biBitCount==8) {
259
260 for (y = head.biHeight-1; y >=0 ; y--){
261 c=n=0;
262 for (x = 0; x<head.biWidth; x++){
263 PCX_PackPixels(GetPixelIndex(x,y),c,n,buffer);
264 }
265 PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);
266 }
267
268 hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
269
270 if (head.biBitCount == 8){
271 hFile->PutC(0x0C);
272 BYTE* pal = (BYTE*)malloc(768);
273 RGBQUAD c;
274 for (int i=0;i<256;i++){
275 c=GetPaletteColor(i);
276 pal[3*i+0] = c.rgbRed;
277 pal[3*i+1] = c.rgbGreen;
278 pal[3*i+2] = c.rgbBlue;
279 }
280 hFile->Write(pal,768,1);
281 free(pal);
282 }
283 } else { //(head.biBitCount==4) || (head.biBitCount==1)
284
285 RGBQUAD *rgb = GetPalette();
286 bool binvert = false;
287 if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1);
288
289 BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine);
290 BYTE* raw = (BYTE*)malloc(head.biWidth);
291
292 for(y = head.biHeight-1; y >=0 ; y--) {
293
294 for( x = 0; x < head.biWidth; x++) raw[x] = (BYTE)GetPixelIndex(x,y);
295
296 if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x];
297
298 for( x = 0; x < pcxHeader.ColorPlanes; x++ ) {
299 PCX_PixelsToPlanes(raw, head.biWidth, plane, x);
300 PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer);
301 }
302 }
303
304 free(plane);
305 free(raw);
306
307 hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
308
309 }
310
311 } cx_catch {
312 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
313 return false;
314 }
315 return true;
316}
317////////////////////////////////////////////////////////////////////////////////
318#endif // CXIMAGE_SUPPORT_ENCODE
319////////////////////////////////////////////////////////////////////////////////
320// Convert multi-plane format into 1 pixel per byte
321// from unpacked file data bitplanes[] into pixel row pixels[]
322// image Height rows, with each row having planes image planes each
323// bytesperline bytes
324bool CxImagePCX::PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)
325{
326 int i, j, npixels;
327 BYTE * p;
328 if (planes > 4) return false;
329 if (bitsperpixel != 1) return false;
330
331 // Clear the pixel buffer
332 npixels = (bytesperline * 8) / bitsperpixel;
333 p = pixels;
334 while (--npixels >= 0) *p++ = 0;
335
336 // Do the format conversion
337 for (i = 0; i < planes; i++){
338 int pixbit, bits, mask;
339 p = pixels;
340 pixbit = (1 << i); // pixel bit for this plane
341 for (j = 0; j < bytesperline; j++){
342 bits = *bitplanes++;
343 for (mask = 0X80; mask != 0; mask >>= 1, p++)
344 if (bits & mask) *p |= pixbit;
345 }
346 }
347 return true;
348}
349////////////////////////////////////////////////////////////////////////////////
350// convert packed pixel format into 1 pixel per byte
351// from unpacked file data bitplanes[] into pixel row pixels[]
352// image Height rows, with each row having planes image planes each
353// bytesperline bytes
354bool CxImagePCX::PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)
355{
356 register int bits;
357 if (planes != 1) return false;
358
359 if (bitsperpixel == 8){ // 8 bits/pixels, no unpacking needed
360 while (bytesperline-- > 0) *pixels++ = *bitplanes++;
361 } else if (bitsperpixel == 4){ // 4 bits/pixel, two pixels per byte
362 while (bytesperline-- > 0){
363 bits = *bitplanes++;
364 *pixels++ = (BYTE)((bits >> 4) & 0X0F);
365 *pixels++ = (BYTE)((bits) & 0X0F);
366 }
367 } else if (bitsperpixel == 2){ // 2 bits/pixel, four pixels per byte
368 while (bytesperline-- > 0){
369 bits = *bitplanes++;
370 *pixels++ = (BYTE)((bits >> 6) & 0X03);
371 *pixels++ = (BYTE)((bits >> 4) & 0X03);
372 *pixels++ = (BYTE)((bits >> 2) & 0X03);
373 *pixels++ = (BYTE)((bits) & 0X03);
374 }
375 } else if (bitsperpixel == 1){ // 1 bits/pixel, 8 pixels per byte
376 while (bytesperline-- > 0){
377 bits = *bitplanes++;
378 *pixels++ = ((bits & 0X80) != 0);
379 *pixels++ = ((bits & 0X40) != 0);
380 *pixels++ = ((bits & 0X20) != 0);
381 *pixels++ = ((bits & 0X10) != 0);
382 *pixels++ = ((bits & 0X08) != 0);
383 *pixels++ = ((bits & 0X04) != 0);
384 *pixels++ = ((bits & 0X02) != 0);
385 *pixels++ = ((bits & 0X01) != 0);
386 }
387 }
388 return true;
389}
390////////////////////////////////////////////////////////////////////////////////
391/* PCX_PackPixels(const long p,BYTE &c, BYTE &n, long &l, CxFile &f)
392 * p = current pixel (-1 ends the line -2 ends odd line)
393 * c = previous pixel
394 * n = number of consecutive pixels
395 */
396void CxImagePCX::PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f)
397{
398 if (p!=c && n){
399 if (n==1 && c<0xC0){
400 f.PutC(c);
401 } else {
402 f.PutC(0xC0|n);
403 f.PutC(c);
404 }
405 n=0;
406 }
407 if (n==0x3F) {
408 f.PutC(0xFF);
409 f.PutC(c);
410 n=0;
411 }
412 if (p==-2) f.PutC(0);
413 c=(BYTE)p;
414 n++;
415}
416////////////////////////////////////////////////////////////////////////////////
417void CxImagePCX::PCX_PackPlanes(BYTE* buff, const long size, CxFile &f)
418{
419 BYTE *start,*end;
420 BYTE c, previous, count;
421
422 start = buff;
423 end = buff + size;
424 previous = *start++;
425 count = 1;
426
427 while (start < end) {
428 c = *start++;
429 if (c == previous && count < 63) {
430 ++count;
431 continue;
432 }
433
434 if (count > 1 || (previous & 0xc0) == 0xc0) {
435 f.PutC( count | 0xc0 );
436 }
437 f.PutC(previous);
438 previous = c;
439 count = 1;
440 }
441
442 if (count > 1 || (previous & 0xc0) == 0xc0) {
443 count |= 0xc0;
444 f.PutC(count);
445 }
446 f.PutC(previous);
447}
448////////////////////////////////////////////////////////////////////////////////
449void CxImagePCX::PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane)
450{
451 int cbit, x, mask;
452 unsigned char *cp = buf-1;
453
454 mask = 1 << plane;
455 cbit = -1;
456 for( x = 0; x < width; x++ ) {
457 if( cbit < 0 ) {
458 cbit = 7;
459 *++cp = 0;
460 }
461 if( raw[x] & mask )
462 *cp |= (1<<cbit);
463 --cbit;
464 }
465}
466////////////////////////////////////////////////////////////////////////////////
467void CxImagePCX::PCX_toh(PCXHEADER* p)
468{
469 p->Xmin = ntohs(p->Xmin);
470 p->Ymin = ntohs(p->Ymin);
471 p->Xmax = ntohs(p->Xmax);
472 p->Ymax = ntohs(p->Ymax);
473 p->Hres = ntohs(p->Hres);
474 p->Vres = ntohs(p->Vres);
475 p->BytesPerLine = ntohs(p->BytesPerLine);
476 p->PaletteType = ntohs(p->PaletteType);
477}
478////////////////////////////////////////////////////////////////////////////////
479#endif // CXIMAGE_SUPPORT_PCX
Note: See TracBrowser for help on using the repository browser.