Tools - Added SDL_Image->.sif converter
authorJohn Hodge (sonata) <[email protected]>
Fri, 25 Jan 2013 14:53:26 +0000 (22:53 +0800)
committerJohn Hodge (sonata) <[email protected]>
Fri, 25 Jan 2013 14:53:26 +0000 (22:53 +0800)
Tools/img2sif.c [new file with mode: 0644]

diff --git a/Tools/img2sif.c b/Tools/img2sif.c
new file mode 100644 (file)
index 0000000..26ab4eb
--- /dev/null
@@ -0,0 +1,205 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+
+// === PROTOTYPES ===
+ int   main(int argc, char *argv[]);
+size_t RLE1_7(void *Dest, 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;
+       uint32_t        *buffer, *buffer2;
+       
+       img = IMG_Load(argv[1]);
+       if( !img )      return -1;
+       
+       buffer = malloc( img->w * img->h * 4 );
+       
+       i = 0;
+       for( y = 0; y < img->h; y++ )
+       {
+               for( x = 0; x < img->w; x ++ )
+               {
+                       val = GetARGB(img, x, y);
+                       buffer[i++] = val;
+               }
+       }
+       
+       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);
+       }
+       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;
+       }
+       
+       // Open and write
+       fp = fopen(argv[2], "w");
+       if( !fp )       return -1;
+       
+       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);
+       
+       fwrite(buffer2, bufLen, 1, fp);
+       
+       fclose(fp);
+       
+       return 0;
+}
+
+#define USE_VERBATIM   1
+
+/**
+ * \brief Run Length Encode a data stream
+ * \param Dest Destination buffer (can be NULL)
+ * \param Src  Source data
+ * \param Size Size of source data
+ * \param BlockSize    Size of a data element (in bytes)       
+ * \param BlockStep    Separation of the beginning of each data element (must be > 0 and should be >= BlockSize)
+ * \param MinRunLength Minimum run length for RLE to be used (must be be >= 1)
+ * 
+ * This function produces a RLE stream encoded with a 7-bit size and a
+ * verbatim flag (allowing strings of non-rle data to be included in the
+ * data for efficiency) of the data blocks from \a Src. Each block is
+ * \a BlockSize bytes in size.
+ * 
+ * \a BlockStep allows this function to encode data that is interlaced with
+ * 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)
+{
+       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",
+       //      Dest, Src, Size, BlockSize, BlockStep, MinRunLength);
+       
+       // Prevent errors
+       if( Size < BlockSize )  return -1;
+       if( !Src )      return -1;
+       if( BlockSize <= 0 || BlockStep <= 0 )  return -1;
+       if( MinRunLength < 1 )  return -1;
+       
+       // Scan through the data stream
+       for( i = 0; i < Size; i ++ )
+       {
+               //printf("i = %i, ", i);
+               // Check forward for and get the "run length"
+               for( j = i + 1; j < i + 127 && j < Size; j ++ )
+               {
+                       // 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 USE_VERBATIM
+               // Check for a verbatim range (runlength of `MinRunLength` or less)
+               if( j - i <= MinRunLength ) {
+                        int    nSame = 0;
+                       // Get the length of the verbatim run
+                       for( j = i + 1; j < i + 127 && j < Size; j ++ )
+                       {
+                               // Check for equality
+                               for( k = 0; k < BlockSize; k ++ ) {
+                                       if( src[j*BlockStep+k] != src[i*BlockStep+k] )  break;
+                               }
+                               if( k == BlockSize ) {
+                                       nSame ++;
+                                       if( nSame > MinRunLength )
+                                               break;
+                               }
+                               else {
+                                       nSame = 0;
+                               }
+                       }
+                       
+                       // Save data
+                       if( dest ) {
+                               dest[ret++] = (j - i) | 0x80;   // Length (with high bit set)
+                               // Data
+                               for( k = 0; k < (j - i)*BlockSize; k ++ )
+                                       dest[ret++] = src[i*BlockStep+k];
+                       }
+                       else {
+                               ret += 1 + BlockSize*(j - i);
+                       }
+                       
+                       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];
+                               }
+                       }
+                       else {
+                               ret += 1 + BlockSize;
+                       }
+                       
+                       nRLE ++;
+               #if USE_VERBATIM
+               }
+               #endif
+               
+               i = j;
+       }
+       
+       //printf("nVerb = %i, nRLE = %i\n", nVerb, nRLE);
+       return ret;
+}
+
+uint32_t GetARGB(SDL_Surface *srf, int x, int y)
+{
+       uint8_t r, g, b, a;
+       SDL_GetRGBA(
+               *(uint32_t*)( srf->pixels + srf->format->BytesPerPixel*x + y * srf->pitch ),
+               srf->format, &r, &g, &b, &a
+               );
+       return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b);
+}

UCC git Repository :: git.ucc.asn.au