5 #include <SDL/SDL_image.h>
7 enum eCompressionModes {
16 int main(int argc, char *argv[]);
17 size_t CompressRLE1x32(void *Dest, const void *Src, size_t Size);
18 size_t CompressRLE4x8(void *Dest, const void *Src, size_t Size);
19 size_t RLE1_7(void *Dest, const void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength);
20 uint32_t GetARGB(SDL_Surface *srf, int x, int y);
23 int main(int argc, char *argv[])
27 enum eCompressionModes comp = COMP_AUTO;
30 uint32_t *buffer, *buffer2;
32 const char *input_file = NULL, *output_file = NULL;
34 for( int i = 1; i < argc; i ++ )
36 if( argv[i][0] != '-' ) {
39 else if( !output_file )
40 output_file = argv[i];
45 else if( argv[i][1] != '-' ) {
50 if( strcmp(argv[i], "--uncompressed") == 0 ) {
51 // Force compression mode to '0'
54 else if( strcmp(argv[i], "--rle4x8") == 0 ) {
57 else if( strcmp(argv[i], "--rle1x32") == 0 ) {
65 if( !input_file || !output_file ) {
66 fprintf(stderr, "Usage: %s <infile> <outfile>\n", argv[0]);
72 SDL_Surface *img = IMG_Load(input_file);
78 buffer = malloc( pixel_count * 4 );
80 for( int y = 0, i = 0; y < img->h; y++ )
82 for( int x = 0; x < img->w; x ++ )
84 buffer[i++] = GetARGB(img, x, y);
90 if( comp == COMP_AUTO )
92 // Try encoding using a single RLE stream
93 size_t rle32length = CompressRLE1x32(NULL, buffer, pixel_count);
94 // Try encoding using separate RLE streams for each channel
95 size_t rle4x8length = CompressRLE4x8(NULL, buffer, pixel_count);
97 // printf("raw length = %i\n", pixel_count * 4);
98 // printf("rle32length = %u\n", (unsigned int)rle32length);
99 // printf("rle4x8length = %u\n", (unsigned int)rle4x8length);
101 if( rle32length <= rle4x8length ) {
102 comp = COMP_RLE1x32; // 32-bit RLE
105 comp = COMP_RLE4x8; // 4x8 bit RLE
112 bufLen = pixel_count*4;
117 bufLen = CompressRLE1x32(NULL, buffer, pixel_count);
118 buffer2 = malloc(bufLen);
119 bufLen = CompressRLE1x32(buffer2, buffer, pixel_count);
122 bufLen = CompressRLE4x8(NULL, buffer, pixel_count);
123 buffer2 = malloc(bufLen);
124 bufLen = CompressRLE4x8(buffer2, buffer, pixel_count);
127 fprintf(stderr, "Unknown compresion %i\n", comp);
134 fp = fopen(output_file, "w");
138 word = 0x51F0; fwrite(&word, 2, 1, fp);
139 word = comp&7; fwrite(&word, 2, 1, fp);
140 word = w; fwrite(&word, 2, 1, fp);
141 word = h; fwrite(&word, 2, 1, fp);
143 fwrite(buffer2, bufLen, 1, fp);
150 size_t CompressRLE1x32(void *Dest, const void *Src, size_t Size)
152 return RLE1_7(Dest, Src, Size, 4, 4, 2);
154 size_t CompressRLE4x8(void *Dest, const void *Src, size_t Size)
157 ret += RLE1_7(Dest ? Dest + ret : NULL, Src+0, Size, 1, 4, 3);
158 ret += RLE1_7(Dest ? Dest + ret : NULL, Src+1, Size, 1, 4, 3);
159 ret += RLE1_7(Dest ? Dest + ret : NULL, Src+2, Size, 1, 4, 3);
160 ret += RLE1_7(Dest ? Dest + ret : NULL, Src+3, Size, 1, 4, 3);
164 #define USE_VERBATIM 1
167 * \brief Run Length Encode a data stream
168 * \param Dest Destination buffer (can be NULL)
169 * \param Src Source data
170 * \param Size Size of source data
171 * \param BlockSize Size of a data element (in bytes)
172 * \param BlockStep Separation of the beginning of each data element (must be > 0 and should be >= BlockSize)
173 * \param MinRunLength Minimum run length for RLE to be used (must be be >= 1)
175 * This function produces a RLE stream encoded with a 7-bit size and a
176 * verbatim flag (allowing strings of non-rle data to be included in the
177 * data for efficiency) of the data blocks from \a Src. Each block is
178 * \a BlockSize bytes in size.
180 * \a BlockStep allows this function to encode data that is interlaced with
181 * other data that you may not want to RLE together (for example, different
182 * colour channels in an image).
184 size_t RLE1_7(void *Dest, const void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength)
186 const uint8_t *src = Src;
187 uint8_t *dest = Dest;
189 int nVerb = 0, nRLE = 0; // Debugging
191 //printf("RLE1_7: (Dest=%p, Src=%p, Size=%lu, BlockSize=%i, BlockStep=%i, MinRunLength=%i)\n",
192 // Dest, Src, Size, BlockSize, BlockStep, MinRunLength);
195 if( Size < BlockSize ) return -1;
196 if( !Src ) return -1;
197 if( BlockSize <= 0 || BlockStep <= 0 ) return -1;
198 if( MinRunLength < 1 ) return -1;
200 // Scan through the data stream
201 for( int i = 0; i < Size; i ++ )
203 //printf("i = %i, ", i);
205 // Check forward for and get the "run length"
206 for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
208 // Check for equality
209 if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
214 // Check for a verbatim range (runlength of `MinRunLength` or less)
215 if( runlen <= MinRunLength )
218 // Get the length of the verbatim run
219 for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
221 // Check for equality
222 if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
229 if( nSame > MinRunLength ) {
239 dest[ret++] = runlen | 0x80; // Length (with high bit set)
241 for( int k = 0; k < runlen; k ++ )
243 memcpy( &dest[ret], &src[(i+k)*BlockStep], BlockSize );
248 ret += 1 + runlen*BlockSize;
255 #endif // USE_VERBATIM
257 dest[ret++] = runlen; // Length (with high bit unset)
258 memcpy(&dest[ret], &src[i*BlockStep], BlockSize);
262 ret += 1 + BlockSize;
273 //printf("nVerb = %i, nRLE = %i\n", nVerb, nRLE);
277 uint32_t GetARGB(SDL_Surface *srf, int x, int y)
281 *(uint32_t*)( srf->pixels + srf->format->BytesPerPixel*x + y * srf->pitch ),
282 srf->format, &r, &g, &b, &a
284 return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b);