//----------------------------------------------------------------------------- // Description: Functions for run-length encoding //----------------------------------------------------------------------------- // RLE code from TrueVision's TGA sample code available as Tgautils.zip at // ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/PC.Version #define IL_RLE_C #include "il_internal.h" #include "il_rle.h" ILboolean ilRleCompressLine(ILubyte *p, ILuint n, ILubyte bpp, ILubyte *q, ILuint *DestWidth, ILenum CompressMode) { ILint DiffCount; // pixel count until two identical ILint SameCount; // number of identical adjacent pixels ILint RLEBufSize = 0; // count of number of bytes encoded ILint MaxRun; const ILint bmp_pad_to_even = 1 - ((ILint)q - *DestWidth) % 2; switch( CompressMode ) { case IL_TGACOMP: MaxRun = TGA_MAX_RUN; break; case IL_SGICOMP: MaxRun = SGI_MAX_RUN; break; case IL_BMPCOMP: MaxRun = BMP_MAX_RUN; break; default: ilSetError(IL_INVALID_PARAM); return IL_FALSE; } while( n > 0 ) { // Analyze pixels DiffCount = CountDiffPixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n); SameCount = CountSamePixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n); if( CompressMode == IL_BMPCOMP ) { ILint remaining_data = n - DiffCount - SameCount; if( remaining_data < 3 ) { // check if the run has gone near the end // no absolute run can be done // complete the line adding 0x01 + pixel, for each pixel while( remaining_data > 0 ) { *q++ = 0x01; *q++ = *p++; remaining_data--; } DiffCount = 0; SameCount = 0; n = 0; } } if( DiffCount > 0 ) { // create a raw packet (bmp absolute run) switch(CompressMode) { case IL_TGACOMP: *q++ = (ILbyte)(DiffCount - 1); break; case IL_BMPCOMP: *q++ = 0x00; RLEBufSize++; *q++ = (ILbyte)DiffCount; break; case IL_SGICOMP: *q++ = (ILbyte)(DiffCount | 0x80); break; } n -= DiffCount; RLEBufSize += (DiffCount * bpp) + 1; while( DiffCount > 0 ) { switch(bpp) { case 4: *q++ = *p++; case 3: *q++ = *p++; case 2: *q++ = *p++; case 1: *q++ = *p++; } DiffCount--; } if( CompressMode == IL_BMPCOMP ) { if( (size_t)q % 2 == bmp_pad_to_even ) { *q++ = 0x00; // insert padding } } } if( SameCount > 1 ) { // create a RLE packet switch(CompressMode) { case IL_TGACOMP: *q++ = (ILbyte)((SameCount - 1) | 0x80); break; case IL_SGICOMP: case IL_BMPCOMP: *q++ = (ILbyte)(SameCount); break; } n -= SameCount; RLEBufSize += bpp + 1; p += (SameCount - 1) * bpp; *q++ = *p++; switch(bpp) { case 4: *q++ = *p++; case 3: *q++ = *p++; case 2: *q++ = *p++; case 1: *q++ = *p++; } } } // write line termination code switch(CompressMode) { case IL_SGICOMP: ++RLEBufSize; *q++ = 0; break; case IL_BMPCOMP: *q++ = 0x00; RLEBufSize++; *q++ = 0x00; RLEBufSize++; break; } *DestWidth = RLEBufSize; return IL_TRUE; } // Compresses an entire image using run-length encoding ILuint ilRleCompress(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte *Dest, ILenum CompressMode, ILuint *ScanTable) { ILuint DestW = 0, i, j, LineLen, Bps = Width * Bpp, SizeOfPlane = Width * Height * Bpp; if( ScanTable ) imemclear(ScanTable,Depth*Height*sizeof(ILuint)); for( j = 0; j < Depth; j++ ) { for( i = 0; i < Height; i++ ) { if( ScanTable ) *ScanTable++ = DestW; ilRleCompressLine(Data + j * SizeOfPlane + i * Bps, Width, Bpp, Dest + DestW, &LineLen, CompressMode); DestW += LineLen; } } if( CompressMode == IL_BMPCOMP ) { // add end of image *(Data+DestW) = 0x00; DestW++; *(Data+DestW) = 0x01; DestW++; } return DestW; }