AcessNative - Add _SysTimestamp (based off gettimeofday)
[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 enum eCompressionModes {
8         COMP_NONE,
9         COMP_RLE1x32,
10         COMP_ZLIB,
11         COMP_RLE4x8,
12         COMP_AUTO = 8
13 };
14
15 // === PROTOTYPES ===
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);
21
22 // === CODE ===
23 int main(int argc, char *argv[])
24 {
25         FILE    *fp;
26          int    bufLen;
27         enum eCompressionModes  comp = COMP_AUTO;
28          int    w, h;
29          int    pixel_count;
30         uint32_t        *buffer, *buffer2;
31         
32         const char      *input_file = NULL, *output_file = NULL;
33
34         for( int i = 1; i < argc; i ++ )
35         {
36                 if( argv[i][0] != '-' ) {
37                         if( !input_file )
38                                 input_file = argv[i];
39                         else if( !output_file )
40                                 output_file = argv[i];
41                         else {
42                                 // Error
43                         }
44                 }
45                 else if( argv[i][1] != '-' ) {
46                         // Single char args
47                 }
48                 else {
49                         // Long args
50                         if( strcmp(argv[i], "--uncompressed") == 0 ) {
51                                 // Force compression mode to '0'
52                                 comp = COMP_NONE;
53                         }
54                         else if( strcmp(argv[i], "--rle4x8") == 0 ) {
55                                 comp = COMP_RLE4x8;
56                         }
57                         else if( strcmp(argv[i], "--rle1x32") == 0 ) {
58                                 comp = COMP_RLE1x32;
59                         }
60                         else {
61                                 // Error
62                         }
63                 }
64         }
65         if( !input_file || !output_file ) {
66                 fprintf(stderr, "Usage: %s <infile> <outfile>\n", argv[0]);
67                 return 1;
68         }
69         
70         // Read image
71         {
72                 SDL_Surface *img = IMG_Load(input_file);
73                 if( !img )      return -1;
74                 
75                 w = img->w;
76                 h = img->h;
77                 pixel_count = w * h;
78                 buffer = malloc( pixel_count * 4 );
79                 
80                 for( int y = 0, i = 0; y < img->h; y++ )
81                 {
82                         for( int x = 0; x < img->w; x ++ )
83                         {
84                                 buffer[i++] = GetARGB(img, x, y);
85                         }
86                 }
87                 SDL_FreeSurface(img);
88         }
89         
90         if( comp == COMP_AUTO ) 
91         {
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);
96                 
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);
100                 
101                 if( rle32length <= rle4x8length ) {
102                         comp = COMP_RLE1x32;    // 32-bit RLE
103                 }
104                 else {
105                         comp = COMP_RLE4x8;     // 4x8 bit RLE
106                 }
107         }
108
109         switch(comp)
110         {
111         case COMP_NONE:
112                 bufLen = pixel_count*4;
113                 buffer2 = buffer;
114                 buffer = NULL;
115                 break;
116         case COMP_RLE1x32:
117                 bufLen = CompressRLE1x32(NULL, buffer, pixel_count);
118                 buffer2 = malloc(bufLen);
119                 bufLen = CompressRLE1x32(buffer2, buffer, pixel_count);
120                 break;
121         case COMP_RLE4x8:
122                 bufLen = CompressRLE4x8(NULL, buffer, pixel_count);
123                 buffer2 = malloc(bufLen);
124                 bufLen = CompressRLE4x8(buffer2, buffer, pixel_count);
125                 break;
126         default:
127                 fprintf(stderr, "Unknown compresion %i\n", comp);
128                 return 2;
129         }
130
131         free(buffer);
132         
133         // Open and write
134         fp = fopen(output_file, "w");
135         if( !fp )       return -1;
136         
137         uint16_t        word;
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);
142         
143         fwrite(buffer2, bufLen, 1, fp);
144         free(buffer2);
145         fclose(fp);
146         
147         return 0;
148 }
149
150 size_t CompressRLE1x32(void *Dest, const void *Src, size_t Size)
151 {
152         return RLE1_7(Dest, Src, Size, 4, 4, 2);
153 }
154 size_t CompressRLE4x8(void *Dest, const void *Src, size_t Size)
155 {
156         size_t  ret = 0;
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);
161         return ret;
162 }
163
164 #define USE_VERBATIM    1
165
166 /**
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)
174  * 
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.
179  * 
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).
183  */
184 size_t RLE1_7(void *Dest, const void *Src, size_t Size, int BlockSize, int BlockStep, int MinRunLength)
185 {
186         const uint8_t   *src = Src;
187         uint8_t *dest = Dest;
188          int    ret = 0;
189          int    nVerb = 0, nRLE = 0;    // Debugging
190         
191         //printf("RLE1_7: (Dest=%p, Src=%p, Size=%lu, BlockSize=%i, BlockStep=%i, MinRunLength=%i)\n",
192         //      Dest, Src, Size, BlockSize, BlockStep, MinRunLength);
193         
194         // Prevent errors
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;
199         
200         // Scan through the data stream
201         for( int i = 0; i < Size; i ++ )
202         {
203                 //printf("i = %i, ", i);
204                  int    runlen;
205                 // Check forward for and get the "run length"
206                 for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
207                 {
208                         // Check for equality
209                         if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
210                                 break;
211                 }
212                 
213                 #if USE_VERBATIM
214                 // Check for a verbatim range (runlength of `MinRunLength` or less)
215                 if( runlen <= MinRunLength )
216                 {
217                          int    nSame = 0;
218                         // Get the length of the verbatim run
219                         for( runlen = 1; runlen < 127 && i+runlen < Size; runlen ++ )
220                         {
221                                 // Check for equality
222                                 if( memcmp(&src[i*BlockStep], &src[(i+runlen)*BlockStep], BlockSize) != 0 )
223                                 {
224                                         nSame = 0;
225                                 }
226                                 else
227                                 {
228                                         nSame ++;
229                                         if( nSame > MinRunLength ) {
230                                                 runlen -= nSame-1;
231                                                 break;
232                                         }
233                                 }
234                         }
235                         
236                         // Save data
237                         if( dest )
238                         {
239                                 dest[ret++] = runlen | 0x80;    // Length (with high bit set)
240                                 // Data
241                                 for( int k = 0; k < runlen; k ++ )
242                                 {
243                                         memcpy( &dest[ret], &src[(i+k)*BlockStep], BlockSize );
244                                         ret += BlockSize;
245                                 }
246                         }
247                         else {
248                                 ret += 1 + runlen*BlockSize;
249                         }
250                         
251                         nVerb ++;
252                 }
253                 // RLE Range
254                 else {
255                 #endif  // USE_VERBATIM
256                         if( dest ) {
257                                 dest[ret++] = runlen;   // Length (with high bit unset)
258                                 memcpy(&dest[ret], &src[i*BlockStep], BlockSize);
259                                 ret += BlockSize;
260                         }
261                         else {
262                                 ret += 1 + BlockSize;
263                         }
264                         
265                         nRLE ++;
266                 #if USE_VERBATIM
267                 }
268                 #endif
269                 
270                 i += runlen-1;
271         }
272         
273         //printf("nVerb = %i, nRLE = %i\n", nVerb, nRLE);
274         return ret;
275 }
276
277 uint32_t GetARGB(SDL_Surface *srf, int x, int y)
278 {
279         uint8_t r, g, b, a;
280         SDL_GetRGBA(
281                 *(uint32_t*)( srf->pixels + srf->format->BytesPerPixel*x + y * srf->pitch ),
282                 srf->format, &r, &g, &b, &a
283                 );
284         return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b);
285 }

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