c4226d21992cd2686caef0cddca2e4d3c879ca87
[tpg/acess2.git] / Tools / img2sif.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <SDL/SDL.h>
5 #include <SDL/SDL_image.h>
6
7 // === PROTOTYPES ===
8  int    main(int argc, char *argv[]);
9 size_t  RLE1_7(void *Dest, void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength);
10 uint32_t        GetARGB(SDL_Surface *srf, int x, int y);
11
12 // === CODE ===
13 int main(int argc, char *argv[])
14 {
15         FILE    *fp;
16         size_t  rle32length, rle4x8length;
17          int    bufLen;
18          int    comp;
19          int    w, h;
20          int    pixel_count;
21         uint32_t        *buffer, *buffer2;
22
23         if( argc != 3 ) {
24                 fprintf(stderr, "Usage: %s <input> <output>\n", argv[0]);
25                 return 1;
26         }
27         
28         // Read image
29         {
30                 SDL_Surface *img = IMG_Load(argv[1]);
31                 if( !img )      return -1;
32                 
33                 w = img->w;
34                 h = img->h;
35                 pixel_count = w * h;
36                 buffer = malloc( pixel_count * 4 );
37                 
38                 for( int y = 0, i = 0; y < img->h; y++ )
39                 {
40                         for( int x = 0; x < img->w; x ++ )
41                         {
42                                 buffer[i++] = GetARGB(img, x, y);
43                         }
44                 }
45                 SDL_FreeSurface(img);
46         }
47         
48         // Try encoding using a single RLE stream
49         rle32length = RLE1_7(NULL, buffer, pixel_count, 4, 4, 3);
50         
51         // Try encoding using separate RLE streams for each channel
52         rle4x8length  = RLE1_7(NULL, buffer, pixel_count, 1, 4, 2);
53         rle4x8length += RLE1_7(NULL, ((uint8_t*)buffer)+1, pixel_count, 1, 4, 2);
54         rle4x8length += RLE1_7(NULL, ((uint8_t*)buffer)+2, pixel_count, 1, 4, 2);
55         rle4x8length += RLE1_7(NULL, ((uint8_t*)buffer)+3, pixel_count, 1, 4, 2);
56         
57 //      printf("raw length = %i\n", pixel_count * 4);
58 //      printf("rle32length = %u\n", (unsigned int)rle32length);
59 //      printf("rle4x8length = %u\n", (unsigned int)rle4x8length);
60         
61         if( rle32length < rle4x8length ) {
62                 comp = 1;       // 32-bit RLE
63                 buffer2 = malloc( rle32length );
64                 bufLen = RLE1_7(buffer2, buffer, pixel_count, 4, 4, 2);
65         }
66         else {
67                 comp = 3;       // 4x8 bit RLE
68                 buffer2 = malloc( rle4x8length );
69                 rle4x8length  = RLE1_7(buffer2, buffer, pixel_count, 1, 4, 3);
70                 rle4x8length += RLE1_7(buffer2+rle4x8length, ((uint8_t*)buffer)+1, pixel_count, 1, 4, 3);
71                 rle4x8length += RLE1_7(buffer2+rle4x8length, ((uint8_t*)buffer)+2, pixel_count, 1, 4, 3);
72                 rle4x8length += RLE1_7(buffer2+rle4x8length, ((uint8_t*)buffer)+3, pixel_count, 1, 4, 3);
73                 bufLen = rle4x8length;
74         }
75         free(buffer);
76         
77         // Open and write
78         fp = fopen(argv[2], "w");
79         if( !fp )       return -1;
80         
81         uint16_t        word;
82         word = 0x51F0;  fwrite(&word, 2, 1, fp);
83         word = comp&7;  fwrite(&word, 2, 1, fp);
84         word = w;       fwrite(&word, 2, 1, fp);
85         word = h;       fwrite(&word, 2, 1, fp);
86         
87         fwrite(buffer2, bufLen, 1, fp);
88         free(buffer2);
89         fclose(fp);
90         
91         return 0;
92 }
93
94 #define USE_VERBATIM    1
95
96 /**
97  * \brief Run Length Encode a data stream
98  * \param Dest  Destination buffer (can be NULL)
99  * \param Src   Source data
100  * \param Size  Size of source data
101  * \param BlockSize     Size of a data element (in bytes)       
102  * \param BlockStep     Separation of the beginning of each data element (must be > 0 and should be >= BlockSize)
103  * \param MinRunLength  Minimum run length for RLE to be used (must be be >= 1)
104  * 
105  * This function produces a RLE stream encoded with a 7-bit size and a
106  * verbatim flag (allowing strings of non-rle data to be included in the
107  * data for efficiency) of the data blocks from \a Src. Each block is
108  * \a BlockSize bytes in size.
109  * 
110  * \a BlockStep allows this function to encode data that is interlaced with
111  * other data that you may not want to RLE together (for example, different
112  * colour channels in an image).
113  */
114 size_t RLE1_7(void *Dest, void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength)
115 {
116         uint8_t *src = Src;
117         uint8_t *dest = Dest;
118          int    ret = 0;
119          int    nVerb = 0, nRLE = 0;    // Debugging
120         
121         //printf("RLE1_7: (Dest=%p, Src=%p, Size=%lu, BlockSize=%i, BlockStep=%i, MinRunLength=%i)\n",
122         //      Dest, Src, Size, BlockSize, BlockStep, MinRunLength);
123         
124         // Prevent errors
125         if( Size < BlockSize )  return -1;
126         if( !Src )      return -1;
127         if( BlockSize <= 0 || BlockStep <= 0 )  return -1;
128         if( MinRunLength < 1 )  return -1;
129         
130         // Scan through the data stream
131         for( int i = 0; i < Size; i ++ )
132         {
133                 //printf("i = %i, ", i);
134                  int    runlen;
135                 // Check forward for and get the "run length"
136                 for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
137                 {
138                         // Check for equality
139                         if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
140                                 break;
141                 }
142                 
143                 #if USE_VERBATIM
144                 // Check for a verbatim range (runlength of `MinRunLength` or less)
145                 if( runlen <= MinRunLength )
146                 {
147                          int    nSame = 0;
148                         // Get the length of the verbatim run
149                         for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
150                         {
151                                 // Check for equality
152                                 if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
153                                 {
154                                         nSame = 0;
155                                 }
156                                 else
157                                 {
158                                         nSame ++;
159                                         if( nSame > MinRunLength ) {
160                                                 runlen -= nSame-1;
161                                                 break;
162                                         }
163                                 }
164                         }
165                         
166                         // Save data
167                         if( dest )
168                         {
169                                 dest[ret++] = runlen | 0x80;    // Length (with high bit set)
170                                 // Data
171                                 for( int k = 0; k < runlen; k ++ )
172                                 {
173                                         memcpy( &dest[ret], &src[(i+k)*BlockStep], BlockSize );
174                                         ret += BlockSize;
175                                 }
176                         }
177                         else {
178                                 ret += 1 + runlen*BlockSize;
179                         }
180                         
181                         nVerb ++;
182                 }
183                 // RLE Range
184                 else {
185                 #endif  // USE_VERBATIM
186                         if( dest ) {
187                                 dest[ret++] = runlen;   // Length (with high bit unset)
188                                 memcpy(&dest[ret], &src[i*BlockStep], BlockSize);
189                                 ret += BlockSize;
190                         }
191                         else {
192                                 ret += 1 + BlockSize;
193                         }
194                         
195                         nRLE ++;
196                 #if USE_VERBATIM
197                 }
198                 #endif
199                 
200                 i += runlen-1;
201         }
202         
203         //printf("nVerb = %i, nRLE = %i\n", nVerb, nRLE);
204         return ret;
205 }
206
207 uint32_t GetARGB(SDL_Surface *srf, int x, int y)
208 {
209         uint8_t r, g, b, a;
210         SDL_GetRGBA(
211                 *(uint32_t*)( srf->pixels + srf->format->BytesPerPixel*x + y * srf->pitch ),
212                 srf->format, &r, &g, &b, &a
213                 );
214         return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b);
215 }

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