made sprite compiler able to handle 565 formats. the assembly output
[dosdemo] / tools / csprite / src / image.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <assert.h>
7 #include <png.h>
8 #include "image.h"
9
10 int alloc_image(struct image *img, int x, int y, int bpp)
11 {
12         memset(img, 0, sizeof *img);
13         img->width = x;
14         img->height = y;
15         img->bpp = bpp;
16         img->scansz = img->pitch = x * bpp / 8;
17
18         if(!(img->pixels = malloc(y * img->scansz))) {
19                 printf("failed to allocate %dx%d (%dbpp) pixel buffer\n", x, y, bpp);
20                 return -1;
21         }
22
23         /* just a guess, assume the user will fill the details, but set up reasonable
24          * defaults just in case...
25          */
26         if(bpp <= 8) {
27                 img->nchan = 1;
28                 img->cmap_ncolors = 1 << bpp;
29         } else if(bpp <= 24) {
30                 img->nchan = 3;
31         } else {
32                 img->nchan = 4;
33         }
34         return 0;
35 }
36
37 int load_image(struct image *img, const char *fname)
38 {
39         int i;
40         FILE *fp;
41         png_struct *png;
42         png_info *info;
43         int chan_bits, color_type;
44         png_uint_32 xsz, ysz;
45         png_color *palette;
46         unsigned char **scanline;
47         unsigned char *dptr;
48
49         if(!(fp = fopen(fname, "rb"))) {
50                 printf("failed to open: %s: %s\n", fname, strerror(errno));
51                 return -1;
52         }
53
54         if(!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
55                 fclose(fp);
56                 return -1;
57         }
58         if(!(info = png_create_info_struct(png))) {
59                 fclose(fp);
60                 png_destroy_read_struct(&png, 0, 0);
61                 return -1;
62         }
63         if(setjmp(png_jmpbuf(png))) {
64                 fclose(fp);
65                 png_destroy_read_struct(&png, &info, 0);
66                 return -1;
67         }
68
69         png_init_io(png, fp);
70         png_read_png(png, info, 0, 0);
71
72         png_get_IHDR(png, info, &xsz, &ysz, &chan_bits, &color_type, 0, 0, 0);
73         img->width = xsz;
74         img->height = ysz;
75         img->nchan = png_get_channels(png, info);
76         img->bpp = img->nchan * chan_bits;
77         img->scansz = img->pitch = xsz * img->bpp / 8;
78         img->cmap_ncolors = 0;
79
80         if(color_type == PNG_COLOR_TYPE_PALETTE) {
81                 png_get_PLTE(png, info, &palette, &img->cmap_ncolors);
82                 memcpy(img->cmap, palette, img->cmap_ncolors * sizeof *img->cmap);
83         }
84
85         if(!(img->pixels = malloc(ysz * img->scansz))) {
86                 perror("failed to allocate pixel buffer");
87                 fclose(fp);
88                 png_destroy_read_struct(&png, &info, 0);
89                 return -1;
90         }
91         dptr = img->pixels;
92
93         scanline = (unsigned char**)png_get_rows(png, info);
94         for(i=0; i<ysz; i++) {
95                 memcpy(dptr, scanline[i], img->scansz);
96                 dptr += img->pitch;
97         }
98
99         fclose(fp);
100         png_destroy_read_struct(&png, &info, 0);
101         return 0;
102 }
103
104 int save_image(struct image *img, const char *fname)
105 {
106         int i, chan_bits, coltype;
107         FILE *fp;
108         png_struct *png;
109         png_info *info;
110         png_text txt;
111         unsigned char **scanline = 0;
112         unsigned char *pptr;
113
114         if(!(fp = fopen(fname, "wb"))) {
115                 printf("save_image: failed to open: %s: %s\n", fname, strerror(errno));
116                 return -1;
117         }
118
119         if(!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
120                 fclose(fp);
121                 return -1;
122         }
123         if(!(info = png_create_info_struct(png))) {
124                 png_destroy_write_struct(&png, 0);
125                 fclose(fp);
126                 return -1;
127         }
128
129         txt.compression = PNG_TEXT_COMPRESSION_NONE;
130         txt.key = "Software";
131         txt.text = "img2tiles";
132         txt.text_length = 0;
133
134         if(setjmp(png_jmpbuf(png))) {
135                 png_destroy_write_struct(&png, &info);
136                 free(scanline);
137                 fclose(fp);
138                 return -1;
139         }
140
141         switch(img->nchan) {
142         case 1:
143                 if(img->cmap_ncolors > 0) {
144                         coltype = PNG_COLOR_TYPE_PALETTE;
145                 } else {
146                         coltype = PNG_COLOR_TYPE_GRAY;
147                 }
148                 break;
149         case 2:
150                 coltype = PNG_COLOR_TYPE_GRAY_ALPHA;
151                 break;
152         case 3:
153                 coltype = PNG_COLOR_TYPE_RGB;
154                 break;
155         case 4:
156                 coltype = PNG_COLOR_TYPE_RGB_ALPHA;
157                 break;
158         }
159
160         chan_bits = img->bpp / img->nchan;
161         png_set_IHDR(png, info, img->width, img->height, chan_bits, coltype, PNG_INTERLACE_NONE,
162                         PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
163         png_set_text(png, info, &txt, 1);
164
165         if(img->cmap_ncolors > 0) {
166                 png_set_PLTE(png, info, (png_color*)img->cmap, img->cmap_ncolors);
167         }
168
169         if(!(scanline = malloc(img->height * sizeof *scanline))) {
170                 png_destroy_write_struct(&png, &info);
171                 fclose(fp);
172                 return -1;
173         }
174
175         pptr = img->pixels;
176         for(i=0; i<img->height; i++) {
177                 scanline[i] = pptr;
178                 pptr += img->pitch;
179         }
180         png_set_rows(png, info, scanline);
181
182         png_init_io(png, fp);
183         png_write_png(png, info, 0, 0);
184         png_destroy_write_struct(&png, &info);
185         free(scanline);
186         fclose(fp);
187         return 0;
188 }
189
190 int conv_image_rgb565(struct image *img16, struct image *img)
191 {
192         int i, j;
193         uint16_t *dptr;
194         unsigned char *sptr;
195
196         if(!img->cmap_ncolors && img->bpp < 24) {
197                 fprintf(stderr, "unsupported conversion from %dbpp to 16bpp 565\n", img->bpp);
198                 return -1;
199         }
200
201         img16->width = img->width;
202         img16->height = img->height;
203         img16->nchan = img->nchan;
204         img16->bpp = 16;
205         img16->scansz = img16->pitch = img->width * 2;
206         if(!(img16->pixels = malloc(img16->height * img16->scansz))) {
207                 return -1;
208         }
209
210         sptr = img->pixels;
211         dptr = (uint16_t*)img16->pixels;
212
213         for(i=0; i<img->height; i++) {
214                 for(j=0; j<img->width; j++) {
215                         unsigned int r, g, b;
216                         if(img->bpp <= 8 && img->cmap_ncolors) {
217                                 int idx = *sptr++ % img->cmap_ncolors;
218                                 r = img->cmap[idx].r >> 3;
219                                 g = img->cmap[idx].g >> 2;
220                                 b = img->cmap[idx].b >> 3;
221                         } else if(img->nchan == 1) {
222                                 g = (*sptr++ >> 2) & 0x3f;
223                                 r = b = g >> 1;
224                         } else {
225                                 r = (*sptr++ >> 3) & 0x1f;
226                                 g = (*sptr++ >> 2) & 0x3f;
227                                 b = (*sptr++ >> 3) & 0x1f;
228                         }
229                         *dptr++ = (r << 11) | (g << 5) | b;
230                 }
231         }
232         return 0;
233 }
234
235
236 int cmp_image(struct image *a, struct image *b)
237 {
238         int i;
239         unsigned char *aptr = a->pixels;
240         unsigned char *bptr = b->pixels;
241
242         if(a->width != b->width || a->height != b->height || a->bpp != b->bpp || a->nchan != b->nchan) {
243                 return -1;
244         }
245
246         for(i=0; i<a->height; i++) {
247                 if(memcmp(aptr, bptr, a->scansz) != 0) {
248                         return -1;
249                 }
250                 aptr += a->pitch;
251                 bptr += b->pitch;
252         }
253         return 0;
254 }
255
256 void blit_image(struct image *src, int sx, int sy, int w, int h, struct image *dst, int dx, int dy)
257 {
258         int i;
259         unsigned char *sptr, *dptr;
260
261         assert(src->bpp == dst->bpp);
262         assert(src->nchan == dst->nchan);
263
264         if(sx < 0) { w += sx; sx = 0; }
265         if(sy < 0) { h += sy; sy = 0; }
266         if(dx < 0) { w += dx; sx -= dx; dx = 0; }
267         if(dy < 0) { h += dy; sy -= dy; dy = 0; }
268         if(sx + w >= src->width) w = src->width - sx;
269         if(sy + h >= src->height) h = src->height - sy;
270         if(dx + w >= dst->width) w = dst->width - dx;
271         if(dy + h >= dst->height) h = dst->height - dy;
272
273         if(w <= 0 || h <= 0) return;
274
275         sptr = src->pixels + sy * src->pitch + sx * src->bpp / 8;
276         dptr = dst->pixels + dy * dst->pitch + dx * dst->bpp / 8;
277
278         for(i=0; i<h; i++) {
279                 memcpy(dptr, sptr, w * dst->bpp / 8);
280                 dptr += dst->pitch;
281                 sptr += src->pitch;
282         }
283 }
284
285 void image_color_offset(struct image *img, int offs)
286 {
287         int i, sz = img->height * img->pitch;
288         unsigned char *pptr = img->pixels;
289
290         for(i=0; i<sz; i++) {
291                 *pptr++ += offs;
292         }
293 }