#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
+enum eCompressionModes {
+ COMP_NONE,
+ COMP_RLE1x32,
+ COMP_ZLIB,
+ COMP_RLE4x8,
+ COMP_AUTO = 8
+};
+
// === PROTOTYPES ===
int main(int argc, char *argv[]);
-size_t RLE1_7(void *Dest, void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength);
+size_t CompressRLE1x32(void *Dest, const void *Src, size_t Size);
+size_t CompressRLE4x8(void *Dest, const void *Src, size_t Size);
+size_t RLE1_7(void *Dest, const void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength);
uint32_t GetARGB(SDL_Surface *srf, int x, int y);
// === CODE ===
int main(int argc, char *argv[])
{
FILE *fp;
- SDL_Surface *img;
- uint16_t word;
- uint32_t val;
- int y, x, i;
- int rle32length, rle4x8length;
int bufLen;
+ enum eCompressionModes comp = COMP_AUTO;
+ int w, h;
+ int pixel_count;
uint32_t *buffer, *buffer2;
- img = IMG_Load(argv[1]);
- if( !img ) return -1;
-
- buffer = malloc( img->w * img->h * 4 );
+ const char *input_file = NULL, *output_file = NULL;
+
+ for( int i = 1; i < argc; i ++ )
+ {
+ if( argv[i][0] != '-' ) {
+ if( !input_file )
+ input_file = argv[i];
+ else if( !output_file )
+ output_file = argv[i];
+ else {
+ // Error
+ }
+ }
+ else if( argv[i][1] != '-' ) {
+ // Single char args
+ }
+ else {
+ // Long args
+ if( strcmp(argv[i], "--uncompressed") == 0 ) {
+ // Force compression mode to '0'
+ comp = COMP_NONE;
+ }
+ else if( strcmp(argv[i], "--rle4x8") == 0 ) {
+ comp = COMP_RLE4x8;
+ }
+ else if( strcmp(argv[i], "--rle1x32") == 0 ) {
+ comp = COMP_RLE1x32;
+ }
+ else {
+ // Error
+ }
+ }
+ }
+ if( !input_file || !output_file ) {
+ fprintf(stderr, "Usage: %s <infile> <outfile>\n", argv[0]);
+ return 1;
+ }
- i = 0;
- for( y = 0; y < img->h; y++ )
+ // Read image
{
- for( x = 0; x < img->w; x ++ )
+ SDL_Surface *img = IMG_Load(input_file);
+ if( !img ) return -1;
+
+ w = img->w;
+ h = img->h;
+ pixel_count = w * h;
+ buffer = malloc( pixel_count * 4 );
+
+ for( int y = 0, i = 0; y < img->h; y++ )
{
- val = GetARGB(img, x, y);
- buffer[i++] = val;
+ for( int x = 0; x < img->w; x ++ )
+ {
+ buffer[i++] = GetARGB(img, x, y);
+ }
}
+ SDL_FreeSurface(img);
}
- SDL_FreeSurface(img);
-
- // Try encoding using a single RLE stream
- rle32length = RLE1_7(NULL, buffer, img->w * img->h, 4, 4, 3);
-
- // Try encoding using separate RLE streams for each channel
- rle4x8length = RLE1_7(NULL, buffer, img->w * img->h, 1, 4, 2);
- rle4x8length += RLE1_7(NULL, ((uint8_t*)buffer)+1, img->w * img->h, 1, 4, 2);
- rle4x8length += RLE1_7(NULL, ((uint8_t*)buffer)+2, img->w * img->h, 1, 4, 2);
- rle4x8length += RLE1_7(NULL, ((uint8_t*)buffer)+3, img->w * img->h, 1, 4, 2);
-
- printf("raw length = %i\n", img->w * img->h * 4);
- printf("rle32length = %i\n", rle32length);
- printf("rle4x8length = %i\n", rle4x8length);
-
- if( rle32length < rle4x8length ) {
- comp = 1; // 32-bit RLE
- buffer2 = malloc( rle32length );
- bufLen = RLE1_7(buffer2, buffer, img->w * img->h, 4, 4, 2);
+ if( comp == COMP_AUTO )
+ {
+ // Try encoding using a single RLE stream
+ size_t rle32length = CompressRLE1x32(NULL, buffer, pixel_count);
+ // Try encoding using separate RLE streams for each channel
+ size_t rle4x8length = CompressRLE4x8(NULL, buffer, pixel_count);
+
+ // printf("raw length = %i\n", pixel_count * 4);
+ // printf("rle32length = %u\n", (unsigned int)rle32length);
+ // printf("rle4x8length = %u\n", (unsigned int)rle4x8length);
+
+ if( rle32length <= rle4x8length ) {
+ comp = COMP_RLE1x32; // 32-bit RLE
+ }
+ else {
+ comp = COMP_RLE4x8; // 4x8 bit RLE
+ }
}
- else {
- comp = 3; // 4x8 bit RLE
- buffer2 = malloc( rle4x8length );
- rle4x8length = RLE1_7(buffer2, buffer, img->w * img->h, 1, 4, 3);
- rle4x8length += RLE1_7(buffer2+rle4x8length, ((uint8_t*)buffer)+1, img->w * img->h, 1, 4, 3);
- rle4x8length += RLE1_7(buffer2+rle4x8length, ((uint8_t*)buffer)+2, img->w * img->h, 1, 4, 3);
- rle4x8length += RLE1_7(buffer2+rle4x8length, ((uint8_t*)buffer)+3, img->w * img->h, 1, 4, 3);
- bufLen = rle4x8length;
+
+ switch(comp)
+ {
+ case COMP_NONE:
+ bufLen = pixel_count*4;
+ buffer2 = buffer;
+ buffer = NULL;
+ break;
+ case COMP_RLE1x32:
+ bufLen = CompressRLE1x32(NULL, buffer, pixel_count);
+ buffer2 = malloc(bufLen);
+ bufLen = CompressRLE1x32(buffer2, buffer, pixel_count);
+ break;
+ case COMP_RLE4x8:
+ bufLen = CompressRLE4x8(NULL, buffer, pixel_count);
+ buffer2 = malloc(bufLen);
+ bufLen = CompressRLE4x8(buffer2, buffer, pixel_count);
+ break;
+ default:
+ fprintf(stderr, "Unknown compresion %i\n", comp);
+ return 2;
}
+
+ free(buffer);
// Open and write
- fp = fopen(argv[2], "w");
+ fp = fopen(output_file, "w");
if( !fp ) return -1;
+ uint16_t word;
word = 0x51F0; fwrite(&word, 2, 1, fp);
word = comp&7; fwrite(&word, 2, 1, fp);
- word = img->w; fwrite(&word, 2, 1, fp);
- word = img->h; fwrite(&word, 2, 1, fp);
+ word = w; fwrite(&word, 2, 1, fp);
+ word = h; fwrite(&word, 2, 1, fp);
fwrite(buffer2, bufLen, 1, fp);
-
+ free(buffer2);
fclose(fp);
return 0;
}
+size_t CompressRLE1x32(void *Dest, const void *Src, size_t Size)
+{
+ return RLE1_7(Dest, Src, Size, 4, 4, 2);
+}
+size_t CompressRLE4x8(void *Dest, const void *Src, size_t Size)
+{
+ size_t ret = 0;
+ ret += RLE1_7(Dest ? Dest + ret : NULL, Src+0, Size, 1, 4, 3);
+ ret += RLE1_7(Dest ? Dest + ret : NULL, Src+1, Size, 1, 4, 3);
+ ret += RLE1_7(Dest ? Dest + ret : NULL, Src+2, Size, 1, 4, 3);
+ ret += RLE1_7(Dest ? Dest + ret : NULL, Src+3, Size, 1, 4, 3);
+ return ret;
+}
+
#define USE_VERBATIM 1
/**
* other data that you may not want to RLE together (for example, different
* colour channels in an image).
*/
-size_t RLE1_7(void *Dest, void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength)
+size_t RLE1_7(void *Dest, const void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength)
{
- uint8_t *src = Src;
+ const uint8_t *src = Src;
uint8_t *dest = Dest;
int ret = 0;
- int i, j, k;
int nVerb = 0, nRLE = 0; // Debugging
//printf("RLE1_7: (Dest=%p, Src=%p, Size=%lu, BlockSize=%i, BlockStep=%i, MinRunLength=%i)\n",
if( MinRunLength < 1 ) return -1;
// Scan through the data stream
- for( i = 0; i < Size; i ++ )
+ for( int i = 0; i < Size; i ++ )
{
//printf("i = %i, ", i);
+ int runlen;
// Check forward for and get the "run length"
- for( j = i + 1; j < i + 127 && j < Size; j ++ )
+ for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
{
// Check for equality
- for( k = 0; k < BlockSize; k ++ ) {
- if( src[j*BlockStep+k] != src[i*BlockStep+k] ) break;
- }
- // If not, break
- if( k < BlockSize ) break;
+ if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
+ break;
}
#if USE_VERBATIM
// Check for a verbatim range (runlength of `MinRunLength` or less)
- if( j - i <= MinRunLength ) {
+ if( runlen <= MinRunLength )
+ {
int nSame = 0;
// Get the length of the verbatim run
- for( j = i + 1; j < i + 127 && j < Size; j ++ )
+ for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
{
// Check for equality
- for( k = 0; k < BlockSize; k ++ ) {
- if( src[j*BlockStep+k] != src[i*BlockStep+k] ) break;
+ if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
+ {
+ nSame = 0;
}
- if( k == BlockSize ) {
+ else
+ {
nSame ++;
- if( nSame > MinRunLength )
+ if( nSame > MinRunLength ) {
+ runlen -= nSame-1;
break;
- }
- else {
- nSame = 0;
+ }
}
}
// Save data
- if( dest ) {
- dest[ret++] = (j - i) | 0x80; // Length (with high bit set)
+ if( dest )
+ {
+ dest[ret++] = runlen | 0x80; // Length (with high bit set)
// Data
- for( k = 0; k < (j - i)*BlockSize; k ++ )
- dest[ret++] = src[i*BlockStep+k];
+ for( int k = 0; k < runlen; k ++ )
+ {
+ memcpy( &dest[ret], &src[(i+k)*BlockStep], BlockSize );
+ ret += BlockSize;
+ }
}
else {
- ret += 1 + BlockSize*(j - i);
+ ret += 1 + runlen*BlockSize;
}
nVerb ++;
// RLE Range
else {
#endif // USE_VERBATIM
- // length = j - i (maxes out at 127)
if( dest ) {
- dest[ret++] = j - i; // Length (with high bit unset)
- for( k = 0; k < BlockSize; k ++ ) {
- dest[ret++] = src[i*BlockStep+k];
- }
+ dest[ret++] = runlen; // Length (with high bit unset)
+ memcpy(&dest[ret], &src[i*BlockStep], BlockSize);
+ ret += BlockSize;
}
else {
ret += 1 + BlockSize;
}
#endif
- i = j;
+ i += runlen-1;
}
//printf("nVerb = %i, nRLE = %i\n", nVerb, nRLE);