Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
734 lines
17 KiB
C
734 lines
17 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// ImageLib Sources
|
|
// Copyright (C) 2000-2002 by Denton Woods
|
|
// Last modified: 09/01/2003 <--Y2K Compliant! =]
|
|
//
|
|
// Filename: src-IL/src/il_pcx.c
|
|
//
|
|
// Description: Reads and writes from/to a .pcx file.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "il_internal.h"
|
|
#ifndef IL_NO_PCX
|
|
#include "il_pcx.h"
|
|
#include "il_manip.h"
|
|
|
|
|
|
//! Checks if the file specified in FileName is a valid .pcx file.
|
|
ILboolean ilIsValidPcx(ILconst_string FileName) {
|
|
ILHANDLE PcxFile;
|
|
ILboolean bPcx = IL_FALSE;
|
|
|
|
if (!iCheckExtension(FileName, IL_TEXT("pcx"))) {
|
|
ilSetError(IL_INVALID_EXTENSION);
|
|
return bPcx;
|
|
}
|
|
|
|
PcxFile = iopenr(FileName);
|
|
if (PcxFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bPcx;
|
|
}
|
|
|
|
bPcx = ilIsValidPcxF(PcxFile);
|
|
icloser(PcxFile);
|
|
|
|
return bPcx;
|
|
}
|
|
|
|
|
|
//! Checks if the ILHANDLE contains a valid .pcx file at the current position.
|
|
ILboolean ilIsValidPcxF(ILHANDLE File) {
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iIsValidPcx();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Checks if Lump is a valid .pcx lump.
|
|
ILboolean ilIsValidPcxL(const ILvoid *Lump, ILuint Size) {
|
|
iSetInputLump(Lump, Size);
|
|
return iIsValidPcx();
|
|
}
|
|
|
|
|
|
// Internal function obtain the .pcx header from the current file.
|
|
ILboolean iGetPcxHead(PCXHEAD *Head) {
|
|
|
|
Head->Manufacturer = igetc();
|
|
|
|
Head->Version = igetc();
|
|
|
|
Head->Encoding = igetc();
|
|
|
|
Head->Bpp = igetc();
|
|
|
|
Head->Xmin = GetLittleUShort();
|
|
|
|
Head->Ymin = GetLittleUShort();
|
|
|
|
Head->Xmax = GetLittleUShort();
|
|
|
|
Head->Ymax = GetLittleUShort();
|
|
|
|
Head->HDpi = GetLittleUShort();
|
|
|
|
Head->VDpi = GetLittleUShort();
|
|
|
|
iread(Head->ColMap, 1, 48);
|
|
|
|
Head->Reserved = igetc();
|
|
|
|
Head->NumPlanes = igetc();
|
|
|
|
Head->Bps = GetLittleUShort();
|
|
|
|
Head->PaletteInfo = GetLittleUShort();
|
|
|
|
Head->HScreenSize = GetLittleUShort();
|
|
|
|
Head->VScreenSize = GetLittleUShort();
|
|
|
|
iread(Head->Filler, 1, 54);
|
|
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
// Internal function to get the header and check it.
|
|
ILboolean iIsValidPcx() {
|
|
PCXHEAD Head;
|
|
|
|
if (!iGetPcxHead(&Head))
|
|
return IL_FALSE;
|
|
iseek(-(ILint)sizeof(PCXHEAD), IL_SEEK_CUR);
|
|
|
|
return iCheckPcx(&Head);
|
|
}
|
|
|
|
|
|
// Internal function used to check if the HEADER is a valid .pcx header.
|
|
// Should we also do a check on Header->Bpp?
|
|
ILboolean iCheckPcx(PCXHEAD *Header) {
|
|
ILuint Test;
|
|
|
|
// Got rid of the Reserved check, because I've seen some .pcx files with invalid values in it.
|
|
if (Header->Manufacturer != 10 || Header->Encoding != 1/* || Header->Reserved != 0*/)
|
|
return IL_FALSE;
|
|
|
|
// Try to support all pcx versions, as they only differ in allowed formats...
|
|
// Let's hope it works.
|
|
if(Header->Version != 5 && Header->Version != 0 && Header->Version != 2 &&
|
|
Header->VDpi != 3 && Header->VDpi != 4)
|
|
return IL_FALSE;
|
|
|
|
// See if the padding size is correct
|
|
Test = Header->Xmax - Header->Xmin + 1;
|
|
if (Header->Bpp >= 8) {
|
|
if (Test & 1) {
|
|
if (Header->Bps != Test + 1)
|
|
return IL_FALSE;
|
|
}
|
|
else {
|
|
if (Header->Bps != Test) // No padding
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
/* for (i = 0; i < 54; i++) { useless check
|
|
if (Header->Filler[i] != 0)
|
|
return IL_FALSE;
|
|
} */
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
//! Reads a .pcx file
|
|
ILboolean ilLoadPcx(ILconst_string FileName) {
|
|
ILHANDLE PcxFile;
|
|
ILboolean bPcx = IL_FALSE;
|
|
|
|
PcxFile = iopenr(FileName);
|
|
if (PcxFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bPcx;
|
|
}
|
|
|
|
bPcx = ilLoadPcxF(PcxFile);
|
|
icloser(PcxFile);
|
|
|
|
return bPcx;
|
|
}
|
|
|
|
|
|
//! Reads an already-opened .pcx file
|
|
ILboolean ilLoadPcxF(ILHANDLE File) {
|
|
ILuint FirstPos;
|
|
ILboolean bRet;
|
|
|
|
iSetInputFile(File);
|
|
FirstPos = itell();
|
|
bRet = iLoadPcxInternal();
|
|
iseek(FirstPos, IL_SEEK_SET);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//! Reads from a memory "lump" that contains a .pcx
|
|
ILboolean ilLoadPcxL(const ILvoid *Lump, ILuint Size) {
|
|
iSetInputLump(Lump, Size);
|
|
return iLoadPcxInternal();
|
|
}
|
|
|
|
|
|
// Internal function used to load the .pcx.
|
|
ILboolean iLoadPcxInternal() {
|
|
PCXHEAD Header;
|
|
ILboolean bPcx = IL_FALSE;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return bPcx;
|
|
}
|
|
|
|
if (!iGetPcxHead(&Header))
|
|
return IL_FALSE;
|
|
if (!iCheckPcx(&Header)) {
|
|
ilSetError(IL_INVALID_FILE_HEADER);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
bPcx = iUncompressPcx(&Header);
|
|
|
|
ilFixImage();
|
|
|
|
return bPcx;
|
|
}
|
|
|
|
|
|
// Internal function to uncompress the .pcx (all .pcx files are rle compressed)
|
|
ILboolean iUncompressPcx(PCXHEAD *Header) {
|
|
//changed decompression loop 2003-09-01
|
|
//From the pcx spec: "There should always
|
|
//be a decoding break at the end of each scan line.
|
|
//But there will not be a decoding break at the end of
|
|
//each plane within each scan line."
|
|
//This is now handled correctly (hopefully ;) )
|
|
|
|
ILubyte ByteHead, Colour, *ScanLine /* For all planes */;
|
|
ILuint ScanLineSize;
|
|
ILuint c, i, x, y;
|
|
|
|
if (Header->Bpp < 8) {
|
|
/*ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
return IL_FALSE;*/
|
|
return iUncompressSmall(Header);
|
|
}
|
|
|
|
if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, Header->NumPlanes, 0, IL_UNSIGNED_BYTE, NULL))
|
|
return IL_FALSE;
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
|
|
switch (iCurImage->Bpp)
|
|
{
|
|
case 1:
|
|
iCurImage->Format = IL_COLOUR_INDEX;
|
|
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
|
iCurImage->Pal.PalSize = 256 * 3; // Need to find out for sure...
|
|
iCurImage->Pal.Palette = (ILubyte*)ialloc(iCurImage->Pal.PalSize);
|
|
if (iCurImage->Pal.Palette == NULL) {
|
|
return IL_FALSE;
|
|
}
|
|
break;
|
|
//case 2: // No 16-bit images in the pcx format!
|
|
case 3:
|
|
iCurImage->Format = IL_RGB;
|
|
iCurImage->Pal.Palette = NULL;
|
|
iCurImage->Pal.PalSize = 0;
|
|
iCurImage->Pal.PalType = IL_PAL_NONE;
|
|
break;
|
|
case 4:
|
|
iCurImage->Format = IL_RGBA;
|
|
iCurImage->Pal.Palette = NULL;
|
|
iCurImage->Pal.PalSize = 0;
|
|
iCurImage->Pal.PalType = IL_PAL_NONE;
|
|
break;
|
|
|
|
default:
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
ScanLineSize = iCurImage->Bpp*Header->Bps;
|
|
ScanLine = (ILubyte*)ialloc(ScanLineSize);
|
|
if (ScanLine == NULL) {
|
|
return IL_FALSE;
|
|
}
|
|
|
|
|
|
//changed 2003-09-01
|
|
//having the decoding code twice is error-prone,
|
|
//so I made iUnCache() smart enough to grasp
|
|
//if iPreCache() wasn't called and call it
|
|
//anyways.
|
|
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
|
iPreCache(iCurImage->SizeOfData / 4);
|
|
|
|
for (y = 0; y < iCurImage->Height; y++) {
|
|
x = 0;
|
|
//read scanline
|
|
while (x < ScanLineSize) {
|
|
if (iread(&ByteHead, 1, 1) != 1) {
|
|
iUnCache();
|
|
goto file_read_error;
|
|
}
|
|
if ((ByteHead & 0xC0) == 0xC0) {
|
|
ByteHead &= 0x3F;
|
|
if (iread(&Colour, 1, 1) != 1) {
|
|
iUnCache();
|
|
goto file_read_error;
|
|
}
|
|
if (x + ByteHead > ScanLineSize) {
|
|
iUnCache();
|
|
goto file_read_error;
|
|
}
|
|
for (i = 0; i < ByteHead; i++) {
|
|
ScanLine[x++] = Colour;
|
|
}
|
|
}
|
|
else {
|
|
ScanLine[x++] = ByteHead;
|
|
}
|
|
}
|
|
|
|
//convert plane-separated scanline into index, rgb or rgba pixels.
|
|
//there might be a padding byte at the end of each scanline...
|
|
for (x = 0; x < iCurImage->Width; x++) {
|
|
for(c = 0; c < iCurImage->Bpp; c++) {
|
|
iCurImage->Data[y * iCurImage->Bps + x * iCurImage->Bpp + c] =
|
|
ScanLine[x + c * Header->Bps];
|
|
}
|
|
}
|
|
}
|
|
|
|
iUnCache();
|
|
|
|
// Read in the palette
|
|
if (Header->Version == 5 && iCurImage->Bpp == 1) {
|
|
x = itell();
|
|
if (iread(&ByteHead, 1, 1) == 0) { // If true, assume that we have a luminance image.
|
|
ilGetError(); // Get rid of the IL_FILE_READ_ERROR.
|
|
iCurImage->Format = IL_LUMINANCE;
|
|
if (iCurImage->Pal.Palette)
|
|
ifree(iCurImage->Pal.Palette);
|
|
iCurImage->Pal.PalSize = 0;
|
|
iCurImage->Pal.PalType = IL_PAL_NONE;
|
|
}
|
|
else {
|
|
if (ByteHead != 12) // Some Quake2 .pcx files don't have this byte for some reason.
|
|
iseek(-1, IL_SEEK_CUR);
|
|
if (iread(iCurImage->Pal.Palette, 1, iCurImage->Pal.PalSize) != iCurImage->Pal.PalSize)
|
|
goto file_read_error;
|
|
}
|
|
}
|
|
|
|
ifree(ScanLine);
|
|
|
|
return IL_TRUE;
|
|
|
|
file_read_error:
|
|
ifree(ScanLine);
|
|
|
|
//added 2003-09-01
|
|
ilSetError(IL_FILE_READ_ERROR);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
|
|
ILboolean iUncompressSmall(PCXHEAD *Header) {
|
|
ILuint i = 0, j, k, c, d, x, y, Bps;
|
|
ILubyte HeadByte, Colour, Data = 0, *ScanLine;
|
|
|
|
if (!ilTexImage(Header->Xmax - Header->Xmin + 1, Header->Ymax - Header->Ymin + 1, 1, 1, 0, IL_UNSIGNED_BYTE, NULL)) {
|
|
return IL_FALSE;
|
|
}
|
|
iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
|
|
|
|
switch (Header->NumPlanes)
|
|
{
|
|
case 1:
|
|
iCurImage->Format = IL_LUMINANCE;
|
|
break;
|
|
case 4:
|
|
iCurImage->Format = IL_COLOUR_INDEX;
|
|
break;
|
|
default:
|
|
ilSetError(IL_ILLEGAL_FILE_VALUE);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
if (Header->NumPlanes == 1 && Header->Bpp == 1) {
|
|
for (j = 0; j < iCurImage->Height; j++) {
|
|
i = 0; //number of written pixels
|
|
while (i < iCurImage->Width) {
|
|
if (iread(&HeadByte, 1, 1) != 1)
|
|
return IL_FALSE;
|
|
if (HeadByte >= 192) {
|
|
HeadByte -= 192;
|
|
if (iread(&Data, 1, 1) != 1)
|
|
return IL_FALSE;
|
|
|
|
for (c = 0; c < HeadByte; c++) {
|
|
k = 128;
|
|
for (d = 0; d < 8 && i < iCurImage->Width; d++) {
|
|
iCurImage->Data[j * iCurImage->Width + i++] = ((Data & k) != 0 ? 255 : 0);
|
|
k >>= 1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
k = 128;
|
|
for (c = 0; c < 8 && i < iCurImage->Width; c++) {
|
|
iCurImage->Data[j * iCurImage->Width + i++] = ((HeadByte & k) != 0 ? 255 : 0);
|
|
k >>= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//if(Data != 0)
|
|
//changed 2003-09-01:
|
|
//There has to be an even number of bytes per line in a pcx.
|
|
//One byte can hold up to 8 bits, so Width/8 bytes
|
|
//are needed to hold a 1 bit per pixel image line.
|
|
//If Width/8 is even no padding is needed,
|
|
//one pad byte has to be read otherwise.
|
|
//(let's hope the above is true ;-))
|
|
if(!((iCurImage->Width >> 3) & 0x1))
|
|
igetc(); // Skip pad byte
|
|
}
|
|
}
|
|
else if (Header->NumPlanes == 4 && Header->Bpp == 1){ // 4-bit images
|
|
//changed decoding 2003-09-10 (was buggy)...could need a speedup
|
|
|
|
Bps = Header->Bps * Header->NumPlanes * 8;
|
|
iCurImage->Pal.Palette = (ILubyte*)ialloc(16 * 3); // Size of palette always (48 bytes).
|
|
ScanLine = (ILubyte*)ialloc(Bps);
|
|
if (iCurImage->Pal.Palette == NULL || ScanLine == NULL) {
|
|
ifree(ScanLine);
|
|
ifree(iCurImage->Pal.Palette);
|
|
return IL_FALSE;
|
|
}
|
|
memcpy(iCurImage->Pal.Palette, Header->ColMap, 16 * 3);
|
|
iCurImage->Pal.PalSize = 16 * 3;
|
|
iCurImage->Pal.PalType = IL_PAL_RGB24;
|
|
|
|
memset(iCurImage->Data, 0, iCurImage->SizeOfData);
|
|
|
|
if (iGetHint(IL_MEM_SPEED_HINT) == IL_FASTEST)
|
|
iPreCache(iCurImage->SizeOfData / 4);
|
|
for (y = 0; y < iCurImage->Height; y++) {
|
|
x = 0;
|
|
while (x < Bps) {
|
|
if (iread(&HeadByte, 1, 1) != 1) {
|
|
iUnCache();
|
|
ifree(ScanLine);
|
|
return IL_FALSE;
|
|
}
|
|
if ((HeadByte & 0xC0) == 0xC0) {
|
|
HeadByte &= 0x3F;
|
|
if (iread(&Colour, 1, 1) != 1) {
|
|
iUnCache();
|
|
ifree(ScanLine);
|
|
return IL_FALSE;
|
|
}
|
|
for (i = 0; i < HeadByte; i++) {
|
|
k = 128;
|
|
for (j = 0; j < 8 && x < Bps; j++) {
|
|
ScanLine[x++] = (Colour & k)?1:0;
|
|
k >>= 1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
k = 128;
|
|
for (j = 0; j < 8 && x < Bps; j++) {
|
|
ScanLine[x++] = (HeadByte & k)?1:0;
|
|
k >>= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (x = 0; x < iCurImage->Width; x++) { // 'Cleverly' ignores the pad bytes. ;)
|
|
for(c = 0; c < Header->NumPlanes; c++)
|
|
iCurImage->Data[y * iCurImage->Width + x] |= ScanLine[x + c*Header->Bps*8] << c;
|
|
}
|
|
}
|
|
iUnCache();
|
|
ifree(ScanLine);
|
|
}
|
|
else {
|
|
ilSetError(IL_FORMAT_NOT_SUPPORTED);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
//! Writes a .pcx file
|
|
ILboolean ilSavePcx(ILconst_string FileName) {
|
|
ILHANDLE PcxFile;
|
|
ILboolean bPcx = IL_FALSE;
|
|
|
|
if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
|
|
if (iFileExists(FileName)) {
|
|
ilSetError(IL_FILE_ALREADY_EXISTS);
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
PcxFile = iopenw(FileName);
|
|
if (PcxFile == NULL) {
|
|
ilSetError(IL_COULD_NOT_OPEN_FILE);
|
|
return bPcx;
|
|
}
|
|
|
|
bPcx = ilSavePcxF(PcxFile);
|
|
iclosew(PcxFile);
|
|
|
|
return bPcx;
|
|
}
|
|
|
|
|
|
//! Writes a .pcx to an already-opened file
|
|
ILboolean ilSavePcxF(ILHANDLE File) {
|
|
iSetOutputFile(File);
|
|
return iSavePcxInternal();
|
|
}
|
|
|
|
|
|
//! Writes a .pcx to a memory "lump"
|
|
ILboolean ilSavePcxL(ILvoid *Lump, ILuint Size) {
|
|
iSetOutputLump(Lump, Size);
|
|
return iSavePcxInternal();
|
|
}
|
|
|
|
|
|
// Internal function used to save the .pcx.
|
|
ILboolean iSavePcxInternal() {
|
|
ILuint i, c, PalSize;
|
|
ILpal *TempPal;
|
|
ILimage *TempImage = iCurImage;
|
|
ILubyte *TempData;
|
|
|
|
if (iCurImage == NULL) {
|
|
ilSetError(IL_ILLEGAL_OPERATION);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
switch (iCurImage->Format)
|
|
{
|
|
case IL_LUMINANCE:
|
|
TempImage = iConvertImage(iCurImage, IL_COLOUR_INDEX, IL_UNSIGNED_BYTE);
|
|
if (TempImage == NULL)
|
|
return IL_FALSE;
|
|
break;
|
|
|
|
case IL_BGR:
|
|
TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
|
|
if (TempImage == NULL)
|
|
return IL_FALSE;
|
|
break;
|
|
|
|
case IL_BGRA:
|
|
TempImage = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
|
|
if (TempImage == NULL)
|
|
return IL_FALSE;
|
|
break;
|
|
|
|
default:
|
|
if (iCurImage->Bpc > 1) {
|
|
TempImage = iConvertImage(iCurImage, iCurImage->Format, IL_UNSIGNED_BYTE);
|
|
if (TempImage == NULL)
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
|
|
if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
|
|
TempData = iGetFlipped(TempImage);
|
|
if (TempData == NULL) {
|
|
if (TempImage != iCurImage) {
|
|
ilCloseImage(TempImage);
|
|
}
|
|
return IL_FALSE;
|
|
}
|
|
}
|
|
else {
|
|
TempData = TempImage->Data;
|
|
}
|
|
|
|
|
|
iputc(0xA); // Manufacturer - always 10
|
|
iputc(0x5); // Version Number - always 5
|
|
iputc(0x1); // Encoding - always 1
|
|
iputc(0x8); // Bits per channel
|
|
SaveLittleUShort(0); // X Minimum
|
|
SaveLittleUShort(0); // Y Minimum
|
|
SaveLittleUShort((ILushort)(iCurImage->Width - 1));
|
|
SaveLittleUShort((ILushort)(iCurImage->Height - 1));
|
|
SaveLittleUShort(0);
|
|
SaveLittleUShort(0);
|
|
|
|
// Useless palette info?
|
|
for (i = 0; i < 48; i++) {
|
|
iputc(0);
|
|
}
|
|
iputc(0x0); // Reserved - always 0
|
|
|
|
iputc(iCurImage->Bpp); // Number of planes - only 1 is supported right now
|
|
|
|
SaveLittleUShort((ILushort)(iCurImage->Width & 1 ? iCurImage->Width + 1 : iCurImage->Width)); // Bps
|
|
SaveLittleUShort(0x1); // Palette type - ignored?
|
|
|
|
// Mainly filler info
|
|
for (i = 0; i < 58; i++) {
|
|
iputc(0x0);
|
|
}
|
|
|
|
// Output data
|
|
for (i = 0; i < TempImage->Height; i++) {
|
|
for (c = 0; c < TempImage->Bpp; c++) {
|
|
encLine(TempData + TempImage->Bps * i + c, TempImage->Width, (ILubyte)(TempImage->Bpp - 1));
|
|
}
|
|
}
|
|
|
|
// Automatically assuming we have a palette...dangerous!
|
|
// Also assuming 3 bpp palette
|
|
iputc(0xC); // Pad byte must have this value
|
|
|
|
// If the current image has a palette, take care of it
|
|
if (TempImage->Format == IL_COLOUR_INDEX) {
|
|
// If the palette in .pcx format, write it directly
|
|
if (TempImage->Pal.PalType == IL_PAL_RGB24) {
|
|
iwrite(TempImage->Pal.Palette, 1, TempImage->Pal.PalSize);
|
|
}
|
|
else {
|
|
TempPal = iConvertPal(&TempImage->Pal, IL_PAL_RGB24);
|
|
if (TempPal == NULL) {
|
|
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
|
ifree(TempData);
|
|
if (TempImage != iCurImage)
|
|
ilCloseImage(TempImage);
|
|
return IL_FALSE;
|
|
}
|
|
|
|
iwrite(TempPal->Palette, 1, TempPal->PalSize);
|
|
ifree(TempPal->Palette);
|
|
ifree(TempPal);
|
|
}
|
|
}
|
|
|
|
// If the palette is not all 256 colours, we have to pad it.
|
|
PalSize = 768 - iCurImage->Pal.PalSize;
|
|
for (i = 0; i < PalSize; i++) {
|
|
iputc(0x0);
|
|
}
|
|
|
|
if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
|
|
ifree(TempData);
|
|
if (TempImage != iCurImage)
|
|
ilCloseImage(TempImage);
|
|
|
|
return IL_TRUE;
|
|
}
|
|
|
|
|
|
// Routine used from ZSoft's pcx documentation
|
|
ILuint encput(ILubyte byt, ILubyte cnt) {
|
|
if (cnt) {
|
|
if ((cnt == 1) && (0xC0 != (0xC0 & byt))) {
|
|
if (IL_EOF == iputc(byt))
|
|
return(0); /* disk write error (probably full) */
|
|
return(1);
|
|
}
|
|
else {
|
|
if (IL_EOF == iputc((ILubyte)((ILuint)0xC0 | cnt)))
|
|
return (0); /* disk write error */
|
|
if (IL_EOF == iputc(byt))
|
|
return (0); /* disk write error */
|
|
return (2);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* This subroutine encodes one scanline and writes it to a file.
|
|
It returns number of bytes written into outBuff, 0 if failed. */
|
|
|
|
ILuint encLine(ILubyte *inBuff, ILint inLen, ILubyte Stride)
|
|
{
|
|
ILubyte _this, last;
|
|
ILint srcIndex, i;
|
|
ILint total;
|
|
ILubyte runCount; // max single runlength is 63
|
|
total = 0;
|
|
runCount = 1;
|
|
last = *(inBuff);
|
|
|
|
// Find the pixel dimensions of the image by calculating
|
|
//[XSIZE = Xmax - Xmin + 1] and [YSIZE = Ymax - Ymin + 1].
|
|
//Then calculate how many bytes are in a "run"
|
|
|
|
for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
|
|
inBuff += Stride;
|
|
_this = *(++inBuff);
|
|
if (_this == last) { // There is a "run" in the data, encode it
|
|
runCount++;
|
|
if (runCount == 63) {
|
|
if (! (i = encput(last, runCount)))
|
|
return (0);
|
|
total += i;
|
|
runCount = 0;
|
|
}
|
|
}
|
|
else { // No "run" - _this != last
|
|
if (runCount) {
|
|
if (! (i = encput(last, runCount)))
|
|
return(0);
|
|
total += i;
|
|
}
|
|
last = _this;
|
|
runCount = 1;
|
|
}
|
|
} // endloop
|
|
|
|
if (runCount) { // finish up
|
|
if (! (i = encput(last, runCount)))
|
|
return (0);
|
|
if (inLen % 2)
|
|
iputc(0);
|
|
return (total + i);
|
|
}
|
|
else {
|
|
if (inLen % 2)
|
|
iputc(0);
|
|
}
|
|
|
|
return (total);
|
|
}
|
|
|
|
#endif//IL_NO_PCX
|