]> Creatis software - clitk.git/blob - utilities/CxImage/ximapcx.cpp
Debug RTStruct conversion with empty struc
[clitk.git] / utilities / CxImage / ximapcx.cpp
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 ////////////////////////////////////////////////////////////////////////////////
28 bool 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 ////////////////////////////////////////////////////////////////////////////////
172 bool 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
324 bool 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
354 bool 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  */
396 void 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 ////////////////////////////////////////////////////////////////////////////////
417 void 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 ////////////////////////////////////////////////////////////////////////////////
449 void 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 ////////////////////////////////////////////////////////////////////////////////
467 void 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