ximapcx.cpp
Upload User: kairuinn
Upload Date: 2009-02-07
Package Size: 2922k
Code Size: 14k
Category:

Graph program

Development Platform:

Visual C++

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