- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/src-IL/src/il_pcx.c

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Sources
    00004 // Copyright (C) 2000-2002 by Denton Woods
    00005 // Last modified: 09/01/2003 <--Y2K Compliant! =]
    00006 //
    00007 // Filename: src-IL/src/il_pcx.c
    00008 //
    00009 // Description: Reads and writes from/to a .pcx file.
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 #include "il_internal.h"
    00015 #ifndef IL_NO_PCX
    00016 #include "il_pcx.h"
    00017 #include "il_manip.h"
    00018
    00019
    00021 ILboolean ilIsValidPcx(ILconst_string FileName)
    00022 {
    00023         ILHANDLE        PcxFile;
    00024         ILboolean       bPcx = IL_FALSE;
    00025
    00026         if (!iCheckExtension(FileName, IL_TEXT("pcx"))) {
    00027                 ilSetError(IL_INVALID_EXTENSION);
    00028                 return bPcx;
    00029         }
    00030
    00031         PcxFile = iopenr(FileName);
    00032         if (PcxFile == NULL) {
    00033                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00034                 return bPcx;
    00035         }
    00036
    00037         bPcx = ilIsValidPcxF(PcxFile);
    00038         icloser(PcxFile);
    00039
    00040         return bPcx;
    00041 }
    00042
    00043
    00045 ILboolean ilIsValidPcxF(ILHANDLE File)
    00046 {
    00047         ILuint          FirstPos;
    00048         ILboolean       bRet;
    00049
    00050         iSetInputFile(File);
    00051         FirstPos = itell();
    00052         bRet = iIsValidPcx();
    00053         iseek(FirstPos, IL_SEEK_SET);
    00054
    00055         return bRet;
    00056 }
    00057
    00058
    00060 ILboolean ilIsValidPcxL(const void *Lump, ILuint Size)
    00061 {
    00062         iSetInputLump(Lump, Size);
    00063         return iIsValidPcx();
    00064 }
    00065
    00066
    00067 // Internal function obtain the .pcx header from the current file.
    00068 ILboolean iGetPcxHead(PCXHEAD *Head)
    00069 {
    00070         Head->Manufacturer = igetc();
    00071         Head->Version = igetc();
    00072         Head->Encoding = igetc();
    00073         Head->Bpp = igetc();
    00074         Head->Xmin = GetLittleUShort();
    00075         Head->Ymin = GetLittleUShort();
    00076         Head->Xmax = GetLittleUShort();
    00077         Head->Ymax = GetLittleUShort();
    00078         Head->HDpi = GetLittleUShort();
    00079         Head->VDpi = GetLittleUShort();
    00080         iread(Head->ColMap, 1, 48);
    00081         Head->Reserved = igetc();
    00082         Head->NumPlanes = igetc();
    00083         Head->Bps = GetLittleUShort();
    00084         Head->PaletteInfo = GetLittleUShort();
    00085         Head->HScreenSize = GetLittleUShort();
    00086         Head->VScreenSize = GetLittleUShort();
    00087         iread(Head->Filler, 1, 54);
    00088
    00089         return IL_TRUE;
    00090 }
    00091
    00092
    00093 // Internal function to get the header and check it.
    00094 ILboolean iIsValidPcx()
    00095 {
    00096         PCXHEAD Head;
    00097
    00098         if (!iGetPcxHead(&Head))
    00099                 return IL_FALSE;
    00100         iseek(-(ILint)sizeof(PCXHEAD), IL_SEEK_CUR);
    00101
    00102         return iCheckPcx(&Head);
    00103 }
    00104
    00105
    00106 // Internal function used to check if the HEADER is a valid .pcx header.
    00107 // Should we also do a check on Header->Bpp?
    00108 ILboolean iCheckPcx(PCXHEAD *Header)
    00109 {
    00110         ILuint  Test;
    00111
    00112         //      Got rid of the Reserved check, because I've seen some .pcx files with invalid values in it.
    00113         if (Header->Manufacturer != 10 || Header->Encoding != 1/* || Header->Reserved != 0*/)
    00114                 return IL_FALSE;
    00115
    00116         // Try to support all pcx versions, as they only differ in allowed formats...
    00117         // Let's hope it works.
    00118         if(Header->Version != 5 && Header->Version != 0 && Header->Version != 2 &&
    00119                  Header->VDpi != 3 && Header->VDpi != 4)
    00120                 return IL_FALSE;
    00121
    00122         // See if the padding size is correct
    00123         Test = Header->Xmax - Header->Xmin + 1;
    00124         if (Header->Bpp >= 8) {
    00125                 if (Test & 1) {
    00126                         if (Header->Bps != Test + 1)
    00127                                 return IL_FALSE;
    00128                 }
    00129                 else {
    00130                         if (Header->Bps != Test)  // No padding
    00131                                 return IL_FALSE;
    00132                 }
    00133         }
    00134
    00135         /* for (i = 0; i < 54; i++) { useless check
    00136                 if (Header->Filler[i] != 0)
    00137                         return IL_FALSE;
    00138         } */
    00139
    00140         return IL_TRUE;
    00141 }
    00142
    00143
    00145 ILboolean ilLoadPcx(ILconst_string FileName)
    00146 {
    00147         ILHANDLE        PcxFile;
    00148         ILboolean       bPcx = IL_FALSE;
    00149
    00150         PcxFile = iopenr(FileName);
    00151         if (PcxFile == NULL) {
    00152                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00153                 return bPcx;
    00154         }
    00155
    00156         bPcx = ilLoadPcxF(PcxFile);
    00157         icloser(PcxFile);
    00158
    00159         return bPcx;
    00160 }
    00161
    00162
    00164 ILboolean ilLoadPcxF(ILHANDLE File)
    00165 {
    00166         ILuint          FirstPos;
    00167         ILboolean       bRet;
    00168
    00169         iSetInputFile(File);
    00170         FirstPos = itell();
    00171         bRet = iLoadPcxInternal();
    00172         iseek(FirstPos, IL_SEEK_SET);
    00173
    00174         return bRet;
    00175 }
    00176
    00177
    00179 ILboolean ilLoadPcxL(const void *Lump, ILuint Size)
    00180 {
    00181         iSetInputLump(Lump, Size);
    00182         return iLoadPcxInternal();
    00183 }
    00184
    00185
    00186 // Internal function used to load the .pcx.
    00187 ILboolean iLoadPcxInternal()
    00188 {
    00189         PCXHEAD Header;
    00190         ILboolean bPcx = IL_FALSE;
    00191
    00192         if (iCurImage == NULL) {
    00193                 ilSetError(IL_ILLEGAL_OPERATION);
    00194                 return bPcx;
    00195         }
    00196
    00197         if (!iGetPcxHead(&Header))
    00198                 return IL_FALSE;
    00199         if (!iCheckPcx(&Header)) {
    00200                 ilSetError(IL_INVALID_FILE_HEADER);
    00201                 return IL_FALSE;
    00202         }
    00203
    00204         bPcx = iUncompressPcx(&Header);
    00205
    00206         ilFixImage();
    00207
    00208         return bPcx;
    00209 }
    00210
    00211
    00212 // Internal function to uncompress the .pcx (all .pcx files are rle compressed)
    00213 ILboolean iUncompressPcx(PCXHEAD *Header)
    00214 {
    00215         //changed decompression loop 2003-09-01
    00216         //From the pcx spec: "There should always
    00217         //be a decoding break at the end of each scan line.
    00218         //But there will not be a decoding break at the end of
    00219         //each plane within each scan line."
    00220         //This is now handled correctly (hopefully ;) )
    00221
    00222         ILubyte ByteHead, Colour, *ScanLine /* For all planes */;
    00223         ILuint ScanLineSize;
    00224         ILuint  c, i, x, y;
    00225
    00226         if (Header->Bpp < 8) {
    00227                 /*ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00228                 return IL_FALSE;*/
    00229                 return iUncompressSmall(Header);
    00230         }
    00231
    00232         if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL))
    00233                 return IL_FALSE;
    00234         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
    00235
    00236         switch (iCurImage->Bpp)
    00237         {
    00238                 case 1:
    00239                         iCurImage->Format = IL_COLOUR_INDEX;
    00240                         iCurImage->Pal.PalType = IL_PAL_RGB24;
    00241                         iCurImage->Pal.PalSize = 256 * 3;  // Need to find out for sure...
    00242                         iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
    00243                         if (iCurImage->Pal.Palette == NULL) {
    00244                                 return IL_FALSE;
    00245                         }
    00246                         break;
    00247                 //case 2:  // No 16-bit images in the pcx format!
    00248                 case 3:
    00249                         iCurImage->Format = IL_RGB;
    00250                         iCurImage->Pal.Palette = NULL;
    00251                         iCurImage->Pal.PalSize = 0;
    00252                         iCurImage->Pal.PalType = IL_PAL_NONE;
    00253                         break;
    00254                 case 4:
    00255                         iCurImage->Format = IL_RGBA;
    00256                         iCurImage->Pal.Palette = NULL;
    00257                         iCurImage->Pal.PalSize = 0;
    00258                         iCurImage->Pal.PalType = IL_PAL_NONE;
    00259                         break;
    00260
    00261                 default:
    00262                         ilSetError(IL_ILLEGAL_FILE_VALUE);
    00263                         return IL_FALSE;
    00264         }
    00265
    00266         ScanLineSize = iCurImage->Bpp*Header->Bps;
    00267         ScanLine = (ILubyte*)ialloc(ScanLineSize);
    00268         if (ScanLine == NULL) {
    00269                 return IL_FALSE;
    00270         }
    00271
    00272
    00273         //changed 2003-09-01
    00274         //having the decoding code twice is error-prone,
    00275         //so I made iUnCache() smart enough to grasp
    00276         //if iPreCache() wasn't called and call it
    00277         //anyways.
    00278         if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
    00279                 iPreCache(iCurImage->SizeOfData / 4);
    00280
    00281         for (y = 0; y < iCurImage->Height; y++) {
    00282                 x = 0;
    00283                 //read scanline
    00284                 while (x < ScanLineSize) {
    00285                         if (iread(&ByteHead, 1, 1) != 1) {
    00286                                 iUnCache();
    00287                                 goto file_read_error;
    00288                         }
    00289                         if ((ByteHead & 0xC0) == 0xC0) {
    00290                                 ByteHead &= 0x3F;
    00291                                 if (iread(&Colour, 1, 1) != 1) {
    00292                                         iUnCache();
    00293                                         goto file_read_error;
    00294                                 }
    00295                                 if (x + ByteHead > ScanLineSize) {
    00296                                         iUnCache();
    00297                                         goto file_read_error;
    00298                                 }
    00299                                 for (i = 0; i < ByteHead; i++) {
    00300                                         ScanLine[x++] = Colour;
    00301                                 }
    00302                         }
    00303                         else {
    00304                                 ScanLine[x++] = ByteHead;
    00305                         }
    00306                 }
    00307
    00308                 //convert plane-separated scanline into index, rgb or rgba pixels.
    00309                 //there might be a padding byte at the end of each scanline...
    00310                 for (x = 0; x < iCurImage->Width; x++) {
    00311                         for(c = 0; c < iCurImage->Bpp; c++) {
    00312                                 iCurImage->Data[y * iCurImage->Bps + x * iCurImage->Bpp + c] =
    00313                                                 ScanLine[x + c * Header->Bps];
    00314                         }
    00315                 }
    00316         }
    00317
    00318         iUnCache();
    00319
    00320         // Read in the palette
    00321         if (Header->Version == 5 && iCurImage->Bpp == 1) {
    00322                 x = itell();
    00323                 if (iread(&ByteHead, 1, 1) == 0) {  // If true, assume that we have a luminance image.
    00324                         ilGetError();  // Get rid of the IL_FILE_READ_ERROR.
    00325                         iCurImage->Format = IL_LUMINANCE;
    00326                         if (iCurImage->Pal.Palette)
    00327                                 ifree(iCurImage->Pal.Palette);
    00328                         iCurImage->Pal.PalSize = 0;
    00329                         iCurImage->Pal.PalType = IL_PAL_NONE;
    00330                 }
    00331                 else {
    00332                         if (ByteHead != 12)  // Some Quake2 .pcx files don't have this byte for some reason.
    00333                                 iseek(-1, IL_SEEK_CUR);
    00334                         if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
    00335                                 goto file_read_error;
    00336                 }
    00337         }
    00338
    00339         ifree(ScanLine);
    00340
    00341         return IL_TRUE;
    00342
    00343 file_read_error:
    00344         ifree(ScanLine);
    00345
    00346         //added 2003-09-01
    00347         ilSetError(IL_FILE_READ_ERROR);
    00348         return IL_FALSE;
    00349 }
    00350
    00351
    00352 ILboolean iUncompressSmall(PCXHEAD *Header)
    00353 {
    00354         ILuint  i = 0, j, k, c, d, x, y, Bps;
    00355         ILubyte HeadByte, Colour, Data = 0, *ScanLine;
    00356
    00357         if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) {
    00358                 return IL_FALSE;
    00359         }
    00360         iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
    00361
    00362         switch (Header->NumPlanes)
    00363         {
    00364                 case 1:
    00365                         iCurImage->Format = IL_LUMINANCE;
    00366                         break;
    00367                 case 4:
    00368                         iCurImage->Format = IL_COLOUR_INDEX;
    00369                         break;
    00370                 default:
    00371                         ilSetError(IL_ILLEGAL_FILE_VALUE);
    00372                         return IL_FALSE;
    00373         }
    00374
    00375         if (Header->NumPlanes == 1 && Header->Bpp == 1) {
    00376                 for (j = 0; j < iCurImage->Height; j++) {
    00377                         i = 0; //number of written pixels
    00378                         while (i < iCurImage->Width) {
    00379                                 if (iread(&HeadByte, 1, 1) != 1)
    00380                                         return IL_FALSE;
    00381                                 if (HeadByte >= 192) {
    00382                                         HeadByte -= 192;
    00383                                         if (iread(&Data, 1, 1) != 1)
    00384                                                 return IL_FALSE;
    00385
    00386                                         for (c = 0; c < HeadByte; c++) {
    00387                                                 k = 128;
    00388                                                 for (d = 0; d < 8 && i < iCurImage->Width; d++) {
    00389                                                         iCurImage->Data[j * iCurImage->Width + i++] = ((Data & k) != 0 ? 255 : 0);
    00390                                                         k >>= 1;
    00391                                                 }
    00392                                         }
    00393                                 }
    00394                                 else {
    00395                                         k = 128;
    00396                                         for (c = 0; c < 8 && i < iCurImage->Width; c++) {
    00397                                                 iCurImage->Data[j * iCurImage->Width + i++] = ((HeadByte & k) != 0 ? 255 : 0);
    00398                                                 k >>= 1;
    00399                                         }
    00400                                 }
    00401                         }
    00402
    00403                         //if(Data != 0)
    00404                         //changed 2003-09-01:
    00405                         //There has to be an even number of bytes per line in a pcx.
    00406                         //One byte can hold up to 8 bits, so Width/8 bytes
    00407                         //are needed to hold a 1 bit per pixel image line.
    00408                         //If Width/8 is even no padding is needed,
    00409                         //one pad byte has to be read otherwise.
    00410                         //(let's hope the above is true ;-))
    00411                         if(!((iCurImage->Width >> 3) & 0x1))
    00412                                 igetc();        // Skip pad byte
    00413                 }
    00414         }
    00415         else if (Header->NumPlanes == 4 && Header->Bpp == 1){   // 4-bit images
    00416                 //changed decoding 2003-09-10 (was buggy)...could need a speedup
    00417
    00418                 Bps = Header->Bps * Header->NumPlanes * 8;
    00419                 iCurImage->Pal.Palette = (ILubyte*)ialloc(16 * 3);  // Size of palette always (48 bytes).
    00420                 ScanLine = (ILubyte*)ialloc(Bps);
    00421                 if (iCurImage->Pal.Palette == NULL || ScanLine == NULL) {
    00422                         ifree(ScanLine);
    00423                         ifree(iCurImage->Pal.Palette);
    00424                         return IL_FALSE;
    00425                 }
    00426                 memcpy(iCurImage->Pal.Palette, Header->ColMap, 16 * 3);
    00427                 iCurImage->Pal.PalSize = 16 * 3;
    00428                 iCurImage->Pal.PalType = IL_PAL_RGB24;
    00429
    00430                 memset(iCurImage->Data, 0, iCurImage->SizeOfData);
    00431
    00432                 if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
    00433                         iPreCache(iCurImage->SizeOfData / 4);
    00434                 for (y = 0; y < iCurImage->Height; y++) {
    00435                         x = 0;
    00436                         while (x < Bps) {
    00437                                 if (iread(&HeadByte, 1, 1) != 1) {
    00438                                         iUnCache();
    00439                                         ifree(ScanLine);
    00440                                         return IL_FALSE;
    00441                                 }
    00442                                 if ((HeadByte & 0xC0) == 0xC0) {
    00443                                         HeadByte &= 0x3F;
    00444                                         if (iread(&Colour, 1, 1) != 1) {
    00445                                                 iUnCache();
    00446                                                 ifree(ScanLine);
    00447                                                 return IL_FALSE;
    00448                                         }
    00449                                         for (i = 0; i < HeadByte; i++) {
    00450                                                 k = 128;
    00451                                                 for (j = 0; j < 8 && x < Bps; j++) {
    00452                                                         ScanLine[x++] = (Colour & k)?1:0;
    00453                                                         k >>= 1;
    00454                                                 }
    00455                                         }
    00456                                 }
    00457                                 else {
    00458                                         k = 128;
    00459                                         for (j = 0; j < 8 && x < Bps; j++) {
    00460                                                 ScanLine[x++] = (HeadByte & k)?1:0;
    00461                                                 k >>= 1;
    00462                                         }
    00463                                 }
    00464                         }
    00465
    00466                         for (x = 0; x < iCurImage->Width; x++) {  // 'Cleverly' ignores the pad bytes. ;)
    00467                                 for(c = 0; c < Header->NumPlanes; c++)
    00468                                         iCurImage->Data[y * iCurImage->Width + x] |= ScanLine[x + c*Header->Bps*8] << c;
    00469                         }
    00470                 }
    00471                 iUnCache();
    00472                 ifree(ScanLine);
    00473         }
    00474         else {
    00475                 ilSetError(IL_FORMAT_NOT_SUPPORTED);
    00476                 return IL_FALSE;
    00477         }
    00478
    00479         return IL_TRUE;
    00480 }
    00481
    00482
    00484 ILboolean ilSavePcx(const ILstring FileName)
    00485 {
    00486         ILHANDLE        PcxFile;
    00487         ILuint          PcxSize;
    00488
    00489         if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
    00490                 if (iFileExists(FileName)) {
    00491                         ilSetError(IL_FILE_ALREADY_EXISTS);
    00492                         return IL_FALSE;
    00493                 }
    00494         }
    00495
    00496         PcxFile = iopenw(FileName);
    00497         if (PcxFile == NULL) {
    00498                 ilSetError(IL_COULD_NOT_OPEN_FILE);
    00499                 return IL_FALSE;
    00500         }
    00501
    00502         PcxSize = ilSavePcxF(PcxFile);
    00503         iclosew(PcxFile);
    00504
    00505         if (PcxSize == 0)
    00506                 return IL_FALSE;
    00507         return IL_TRUE;
    00508 }
    00509
    00510
    00512 ILuint ilSavePcxF(ILHANDLE File)
    00513 {
    00514         ILuint Pos;
    00515         iSetOutputFile(File);
    00516         Pos = itellw();
    00517         if (iSavePcxInternal() == IL_FALSE)
    00518                 return 0;  // Error occurred
    00519         return itellw() - Pos;  // Return the number of bytes written.
    00520 }
    00521
    00522
    00524 ILuint ilSavePcxL(void *Lump, ILuint Size)
    00525 {
    00526         ILuint Pos = itellw();
    00527         iSetOutputLump(Lump, Size);
    00528         if (iSavePcxInternal() == IL_FALSE)
    00529                 return 0;  // Error occurred
    00530         return itellw() - Pos;  // Return the number of bytes written.
    00531 }
    00532
    00533
    00534 // Internal function used to save the .pcx.
    00535 ILboolean iSavePcxInternal()
    00536 {
    00537         ILuint  i, c, PalSize;
    00538         ILpal   *TempPal;
    00539         ILimage *TempImage = iCurImage;
    00540         ILubyte *TempData;
    00541
    00542         if (iCurImage == NULL) {
    00543                 ilSetError(IL_ILLEGAL_OPERATION);
    00544                 return IL_FALSE;
    00545         }
    00546
    00547         switch (iCurImage->Format)
    00548         {
    00549                 case IL_LUMINANCE:
    00550                         TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
    00551                         if (TempImage == NULL)
    00552                                 return IL_FALSE;
    00553                         break;
    00554
    00555                 case IL_BGR:
    00556                         TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
    00557                         if (TempImage == NULL)
    00558                                 return IL_FALSE;
    00559                         break;
    00560
    00561                 case IL_BGRA:
    00562                         TempImage = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
    00563                         if (TempImage == NULL)
    00564                                 return IL_FALSE;
    00565                         break;
    00566
    00567                 default:
    00568                         if (iCurImage->Bpc > 1) {
    00569                                 TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
    00570                                 if (TempImage == NULL)
    00571                                         return IL_FALSE;
    00572                         }
    00573         }
    00574
    00575         if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
    00576                 TempData = iGetFlipped(TempImage);
    00577                 if (TempData == NULL) {
    00578                         if (TempImage != iCurImage) {
    00579                                 ilCloseImage(TempImage);
    00580                         }
    00581                         return IL_FALSE;
    00582                 }
    00583         }
    00584         else {
    00585                 TempData = TempImage->Data;
    00586         }
    00587
    00588
    00589         iputc(0xA);  // Manufacturer - always 10
    00590         iputc(0x5);  // Version Number - always 5
    00591         iputc(0x1);  // Encoding - always 1
    00592         iputc(0x8);  // Bits per channel
    00593         SaveLittleUShort(0);  // X Minimum
    00594         SaveLittleUShort(0);  // Y Minimum
    00595         SaveLittleUShort((ILushort)(iCurImage->Width - 1));
    00596         SaveLittleUShort((ILushort)(iCurImage->Height - 1));
    00597         SaveLittleUShort(0);
    00598         SaveLittleUShort(0);
    00599
    00600         // Useless palette info?
    00601         for (i = 0; i < 48; i++) {
    00602                 iputc(0);
    00603         }
    00604         iputc(0x0);  // Reserved - always 0
    00605
    00606         iputc(iCurImage->Bpp);  // Number of planes - only 1 is supported right now
    00607
    00608         SaveLittleUShort((ILushort)(iCurImage->Width & 1 ? iCurImage->Width + 1 : iCurImage->Width));  // Bps
    00609         SaveLittleUShort(0x1);  // Palette type - ignored?
    00610
    00611         // Mainly filler info
    00612         for (i = 0; i < 58; i++) {
    00613                 iputc(0x0);
    00614         }
    00615
    00616         // Output data
    00617         for (i = 0; i < TempImage->Height; i++) {
    00618                 for (c = 0; c < TempImage->Bpp; c++) {
    00619                         encLine(TempData + TempImage->Bps * i + c, TempImage->Width, (ILubyte)(TempImage->Bpp - 1));
    00620                 }
    00621         }
    00622
    00623         // Automatically assuming we have a palette...dangerous!
    00624         //      Also assuming 3 bpp palette
    00625         iputc(0xC);  // Pad byte must have this value
    00626
    00627         // If the current image has a palette, take care of it
    00628         if (TempImage->Format == IL_COLOUR_INDEX) {
    00629                 // If the palette in .pcx format, write it directly
    00630                 if (TempImage->Pal.PalType == IL_PAL_RGB24) {
    00631                         iwrite(TempImage->Pal.Palette, 1, TempImage->Pal.PalSize);
    00632                 }
    00633                 else {
    00634                         TempPal = iConvertPal(&TempImage->Pal, IL_PAL_RGB24);
    00635                         if (TempPal == NULL) {
    00636                                 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
    00637                                         ifree(TempData);
    00638                                 if (TempImage != iCurImage)
    00639                                         ilCloseImage(TempImage);
    00640                                 return IL_FALSE;
    00641                         }
    00642
    00643                         iwrite(TempPal->Palette, 1, TempPal->PalSize);
    00644                         ifree(TempPal->Palette);
    00645                         ifree(TempPal);
    00646                 }
    00647         }
    00648
    00649         // If the palette is not all 256 colours, we have to pad it.
    00650         PalSize = 768 - iCurImage->Pal.PalSize;
    00651         for (i = 0; i < PalSize; i++) {
    00652                 iputc(0x0);
    00653         }
    00654
    00655         if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
    00656                 ifree(TempData);
    00657         if (TempImage != iCurImage)
    00658                 ilCloseImage(TempImage);
    00659
    00660         return IL_TRUE;
    00661 }
    00662
    00663
    00664 // Routine used from ZSoft's pcx documentation
    00665 ILuint encput(ILubyte byt, ILubyte cnt)
    00666 {
    00667         if (cnt) {
    00668                 if ((cnt == 1) && (0xC0 != (0xC0 & byt))) {
    00669                         if (IL_EOF == iputc(byt))
    00670                                 return(0);     /* disk write error (probably full) */
    00671                         return(1);
    00672                 }
    00673                 else {
    00674                         if (IL_EOF == iputc((ILubyte)((ILuint)0xC0 | cnt)))
    00675                                 return (0);      /* disk write error */
    00676                         if (IL_EOF == iputc(byt))
    00677                                 return (0);      /* disk write error */
    00678                         return (2);
    00679                 }
    00680         }
    00681
    00682         return (0);
    00683 }
    00684
    00685 // This subroutine encodes one scanline and writes it to a file.
    00686 //  It returns number of bytes written into outBuff, 0 if failed.
    00687 ILuint encLine(ILubyte *inBuff, ILint inLen, ILubyte Stride)
    00688 {
    00689         ILubyte _this, last;
    00690         ILint srcIndex, i;
    00691         ILint total;
    00692         ILubyte runCount;     // max single runlength is 63
    00693         total = 0;
    00694         runCount = 1;
    00695         last = *(inBuff);
    00696
    00697         // Find the pixel dimensions of the image by calculating
    00698         //[XSIZE = Xmax - Xmin + 1] and [YSIZE = Ymax - Ymin + 1].
    00699         //Then calculate how many bytes are in a "run"
    00700
    00701         for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
    00702                 inBuff += Stride;
    00703                 _this = *(++inBuff);
    00704                 if (_this == last) {  // There is a "run" in the data, encode it
    00705                         runCount++;
    00706                         if (runCount == 63) {
    00707                                 if (! (i = encput(last, runCount)))
    00708                                                 return (0);
    00709                                 total += i;
    00710                                 runCount = 0;
    00711                         }
    00712                 }
    00713                 else {  // No "run"  -  _this != last
    00714                         if (runCount) {
    00715                                 if (! (i = encput(last, runCount)))
    00716                                         return(0);
    00717                                 total += i;
    00718                         }
    00719                         last = _this;
    00720                         runCount = 1;
    00721                 }
    00722         }  // endloop
    00723
    00724         if (runCount) {  // finish up
    00725                 if (! (i = encput(last, runCount)))
    00726                         return (0);
    00727                 if (inLen % 2)
    00728                         iputc(0);
    00729                 return (total + i);
    00730         }
    00731         else {
    00732                 if (inLen % 2)
    00733                         iputc(0);
    00734         }
    00735
    00736         return (total);
    00737 }
    00738
    00739 #endif//IL_NO_PCX