00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <iostream>
00013
00014 #include "plstdpch.h"
00015 #include "plpcxdec.h"
00016 #include "plexcept.h"
00017
00018 #include "plpcx.h"
00019
00020 PLPCXDecoder::PLPCXDecoder()
00021 : PLPicDecoder()
00022
00023 {}
00024
00025
00026 PLPCXDecoder::~PLPCXDecoder()
00027 {}
00028
00029
00030 void PLPCXDecoder::DoDecode (PLBmp * pBmp, PLDataSource * pDataSrc)
00031 {
00032 LPPCXHEADER pcxHeader;
00033 int i, x, y;
00034 PLBYTE ColorMap[PCX_MAXCOLORS][3];
00035 PLBYTE * pcximage = NULL;
00036 PLBYTE * lpHead1 = NULL;
00037 PLBYTE * lpHead2 = NULL;
00038 PLBYTE * pcxplanes;
00039 PLBYTE * pcxpixels;
00040 PLBYTE c;
00041 int nbytes, count;
00042
00043 int Height, Width;
00044
00045
00046 Trace (2, "Decoding PCX.\n");
00047
00048 try
00049 {
00050 pcxHeader = (LPPCXHEADER)pDataSrc->ReadNBytes(sizeof(tagPCXHEADER));
00051
00052 if (pcxHeader->Manufacturer != PCX_MAGIC)
00053 {
00054 raiseError (PL_ERRWRONG_SIGNATURE, "Error decoding pcx: Not a PCX file.");
00055 }
00056
00057 if (pcxHeader->Encoding != 1)
00058 {
00059 raiseError (PL_ERRWRONG_SIGNATURE, "File has unknown encoding scheme.");
00060 }
00061
00062 Width = (pcxHeader->Xmax - pcxHeader->Xmin) + 1;
00063 Height = (pcxHeader->Ymax - pcxHeader->Ymin) + 1;
00064 pBmp->Create (Width, Height, 32, false);
00065
00066
00067 switch (pcxHeader->BitsPerPixel)
00068 {
00069 case 1:
00070 if (pcxHeader->ColorPlanes > 4)
00071 {
00072 raiseError(PL_ERRFORMAT_UNKNOWN, "Can't handle image with more than 4 planes.");
00073 }
00074 break;
00075 case 2:
00076 case 4:
00077 case 8:
00078 if (pcxHeader->ColorPlanes == 1 || pcxHeader->ColorPlanes == 3)
00079 break;
00080 default:
00081 raiseError(PL_ERRFORMAT_UNKNOWN, "Can't handle bits per pixel image with planes.");
00082 break;
00083 }
00084
00085 nbytes = pcxHeader->BytesPerLine * pcxHeader->ColorPlanes * Height;
00086 lpHead1 = pcximage = (PLBYTE *)malloc(nbytes);
00087 try
00088 {
00089 while (nbytes > 0)
00090 {
00091 c = ReadByte(pDataSrc);
00092 if ((c & 0XC0) != 0XC0)
00093 {
00094 *pcximage++ = c;
00095 --nbytes;
00096 continue;
00097 }
00098 count = c & 0X3F;
00099 c = ReadByte(pDataSrc);
00100 if (count > nbytes)
00101 {
00102 raiseError(PL_ERRINTERNAL, "repeat count spans end of image.");
00103 }
00104 nbytes -= count;
00105 while (--count >=0)
00106 *pcximage++ = c;
00107 }
00108 }
00109 catch (PLTextException e)
00110 {
00111
00112
00113
00114 if (e.GetCode() != PL_ERREND_OF_FILE)
00115 throw;
00116 }
00117 pcximage = lpHead1;
00118
00119 for (i = 0; i < 16; i++)
00120 {
00121 ColorMap[i][0] = pcxHeader->ColorMap[i][0];
00122 ColorMap[i][1] = pcxHeader->ColorMap[i][1];
00123 ColorMap[i][2] = pcxHeader->ColorMap[i][2];
00124 }
00125 if (pcxHeader->BitsPerPixel == 8 && pcxHeader->ColorPlanes == 1)
00126 {
00127 PLBYTE colsig = ReadByte(pDataSrc);
00128
00129
00130
00131
00132
00133
00134 for (i = 0; i < PCX_MAXCOLORS; i++)
00135 {
00136 ColorMap[i][0] = ReadByte(pDataSrc);
00137 ColorMap[i][1] = ReadByte(pDataSrc);
00138 ColorMap[i][2] = ReadByte(pDataSrc);
00139 }
00140 }
00141 if (pcxHeader->BitsPerPixel == 1 && pcxHeader->ColorPlanes == 1)
00142 {
00143 ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0;
00144 ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255;
00145 }
00146
00147 lpHead2 = pcxpixels = (PLBYTE *)malloc(Width + pcxHeader->BytesPerLine * 8);
00148
00149 pBmp->Lock(false, true);
00150 PLPixel32 ** pLineArray = pBmp->GetLineArray32();
00151 for (y = 0; y < Height; y++)
00152 {
00153 pcxpixels = lpHead2;
00154 pcxplanes = pcximage + (y * pcxHeader->BytesPerLine * pcxHeader->ColorPlanes);
00155 if (pcxHeader->ColorPlanes == 3 && pcxHeader->BitsPerPixel == 8)
00156 {
00157
00158 for (x = 0; x < Width; x++)
00159 {
00160 PLPixel32 * pPixel = pLineArray[y];
00161 pPixel[x].Set (pcxplanes[x],
00162 pcxplanes[pcxHeader->BytesPerLine + x],
00163 pcxplanes[2*pcxHeader->BytesPerLine + x],
00164 0xFF);
00165 }
00166 continue;
00167 }
00168 else if (pcxHeader->ColorPlanes == 1)
00169 {
00170 PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader->BytesPerLine, pcxHeader->ColorPlanes, pcxHeader->BitsPerPixel);
00171 }
00172 else
00173 {
00174 PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader->BytesPerLine, pcxHeader->ColorPlanes, pcxHeader->BitsPerPixel);
00175 }
00176 for (x = 0; x < Width; x++)
00177 {
00178 i = pcxpixels[x];
00179 PLPixel32 * pPixel = pLineArray[y];
00180 pPixel[x].Set (ColorMap[i][0], ColorMap[i][1],
00181 ColorMap[i][2], 0xFF);
00182 }
00183 }
00184 pBmp->SetResolution(PLPoint (pcxHeader->Hres, pcxHeader->Vres));
00185 pBmp->Unlock();
00186 }
00187
00188 catch (PLTextException)
00189 {
00190 if (lpHead1)
00191 {
00192 free(lpHead1);
00193 lpHead1 = NULL;
00194 }
00195 if (lpHead2)
00196 {
00197 free(lpHead2);
00198 lpHead2 = NULL;
00199 }
00200 throw;
00201 }
00202
00203 if (lpHead1)
00204 {
00205 free(lpHead1);
00206 lpHead1 = NULL;
00207 }
00208 if (lpHead2)
00209 {
00210 free(lpHead2);
00211 lpHead2 = NULL;
00212 }
00213 }
00214
00215
00216
00217
00218
00219 void PLPCXDecoder::PCX_PlanesToPixels(PLBYTE * pixels, PLBYTE * bitplanes,
00220 short bytesperline, short planes, short bitsperpixel)
00221 {
00222 int i, j;
00223 int npixels;
00224 PLBYTE * p;
00225 if (planes > 4)
00226 {
00227 raiseError(PL_ERRINTERNAL, "Can't handle more than 4 planes.");
00228 }
00229 if (bitsperpixel != 1)
00230 {
00231 raiseError(PL_ERRINTERNAL, "Can't handle more than 1 bit per pixel.");
00232 }
00233
00234
00235 npixels = ((bytesperline-1) * 8) / bitsperpixel;
00236 p = pixels;
00237 while (--npixels >= 0)
00238 *p++ = 0;
00239
00240
00241 for (i = 0; i < planes; i++)
00242 {
00243 int pixbit, bits, mask;
00244 p = pixels;
00245 pixbit = (1 << i);
00246 for (j = 0; j < bytesperline; j++)
00247 {
00248 bits = *bitplanes++;
00249 for (mask = 0X80; mask != 0; mask >>= 1, p++)
00250 if (bits & mask)
00251 *p |= pixbit;
00252 }
00253 }
00254 }
00255
00256
00257
00258
00259
00260
00261 void PLPCXDecoder::PCX_UnpackPixels(PLBYTE * pixels, PLBYTE * bitplanes,
00262 short bytesperline, short planes, short bitsperpixel)
00263 {
00264 register int bits;
00265 if (planes != 1)
00266 {
00267 raiseError(PL_ERRINTERNAL, "Can't handle packed pixels with more than 1 plane.");
00268 }
00269 if (bitsperpixel == 8)
00270 {
00271 while (bytesperline-- > 0)
00272 *pixels++ = *bitplanes++;
00273 }
00274 else if (bitsperpixel == 4)
00275 {
00276 while (bytesperline-- > 0)
00277 {
00278 bits = *bitplanes++;
00279 *pixels++ = (PLBYTE)((bits >> 4) & 0X0F);
00280 *pixels++ = (PLBYTE)((bits) & 0X0F);
00281 }
00282 }
00283 else if (bitsperpixel == 2)
00284 {
00285 while (bytesperline-- > 0)
00286 {
00287 bits = *bitplanes++;
00288 *pixels++ = (PLBYTE)((bits >> 6) & 0X03);
00289 *pixels++ = (PLBYTE)((bits >> 4) & 0X03);
00290 *pixels++ = (PLBYTE)((bits >> 2) & 0X03);
00291 *pixels++ = (PLBYTE)((bits) & 0X03);
00292 }
00293 }
00294 else if (bitsperpixel == 1)
00295 {
00296 while (bytesperline-- > 0)
00297 {
00298 bits = *bitplanes++;
00299 *pixels++ = ((bits & 0X80) != 0);
00300 *pixels++ = ((bits & 0X40) != 0);
00301 *pixels++ = ((bits & 0X20) != 0);
00302 *pixels++ = ((bits & 0X10) != 0);
00303 *pixels++ = ((bits & 0X08) != 0);
00304 *pixels++ = ((bits & 0X04) != 0);
00305 *pixels++ = ((bits & 0X02) != 0);
00306 *pixels++ = ((bits & 0X01) != 0);
00307 }
00308 }
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371