62b60c597a58b60e02d58f4ad43120a2a9f704af
[swftools.git] / lib / gfximage.c
1 #include <stdlib.h>
2 #include <math.h>
3 #include <memory.h>
4 #include "jpeg.h"
5 #include "png.h"
6 #include "mem.h"
7 #include "gfximage.h"
8 #include "types.h"
9
10 void gfximage_save_jpeg(gfximage_t*img, const char*filename, int quality)
11 {
12     int x,y;
13     int l = img->width*img->height;
14     unsigned char*data = (unsigned char*)rfx_alloc(img->width*img->height*3);
15     int s,t;
16     for(t=0,s=0;t<l;s+=3,t++) {
17         data[s+0] = img->data[t].r;
18         data[s+1] = img->data[t].g;
19         data[s+2] = img->data[t].b;
20     }
21     jpeg_save(data, img->width, img->height, quality, filename);
22     free(data);
23 }
24
25 void gfximage_save_png(gfximage_t*image, const char*filename)
26 {
27     writePNG(filename, (void*)image->data, image->width, image->height);
28 }
29
30 typedef struct scale_lookup {
31     int pos;
32     unsigned int weight;
33 } scale_lookup_t;
34
35 typedef struct rgba_int {
36     unsigned int r,g,b,a;
37 } rgba_int_t;
38
39 static int bicubic = 0;
40
41 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
42 {
43     scale_lookup_t*lookupx = (scale_lookup_t*)rfx_alloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
44     scale_lookup_t**lblockx = (scale_lookup_t**)rfx_alloc((newwidth+1)*sizeof(scale_lookup_t**));
45     double fx = ((double)width)/((double)newwidth);
46     double px = 0;
47     int x;
48     scale_lookup_t*p_x = lookupx;
49
50     if(newwidth<=width) {
51         for(x=0;x<newwidth;x++) {
52             double ex = px + fx;
53             int fromx = (int)px;
54             int tox = (int)ex;
55             double rem = fromx+1-px;
56             int i = (int)(256/fx);
57             int xweight = (int)(rem*256/fx);
58             int xx;
59             int w = 0;
60             lblockx[x] = p_x;
61             if(tox>=width) tox = width-1;
62             for(xx=fromx;xx<=tox;xx++) {
63                 if(xx==fromx && xx==tox) p_x->weight = 256;
64                 else if(xx==fromx) p_x->weight = xweight;
65                 else if(xx==tox) p_x->weight = 256-w;
66                 else p_x->weight = i;
67                 w+=p_x->weight;
68                 p_x->pos = xx;
69                 p_x++;
70             }
71             px = ex;
72         }
73     } else {
74         for(x=0;x<newwidth;x++) {
75             int ix1 = (int)px;
76             int ix2 = ((int)px)+1;
77             double r = px-ix1;
78             if(ix2>=width) ix2=width-1;
79             lblockx[x] = p_x;
80             if(bicubic)
81                 r = -2*r*r*r+3*r*r;
82             p_x[0].weight = (int)(256*(1-r));
83             p_x[0].pos = ix1;
84             p_x[1].weight = 256-p_x[0].weight;
85             p_x[1].pos = ix2;
86             p_x+=2;
87             px += fx;
88         }
89     }
90     lblockx[newwidth] = p_x;
91     return lblockx;
92 }
93
94 static void encodeMonochromeImage(gfxcolor_t*data, int width, int height, gfxcolor_t*colors)
95 {
96     int t;
97     int len = width*height;
98
99     U32* img = (U32*)data;
100     U32 color1 = img[0];
101     U32 color2 = 0;
102     for(t=1;t<len;t++) {
103         if(img[t] != color1) {
104             color2 = img[t];
105             break;
106         }
107     }
108     *(U32*)&colors[0] = color1;
109     *(U32*)&colors[1] = color2;
110     for(t=0;t<len;t++) {
111         if(img[t] == color1) {
112             img[t] = 0;
113         } else {
114             img[t] = 0xffffffff;
115         }
116     }
117 }
118
119 static void decodeMonochromeImage(gfxcolor_t*data, int width, int height, gfxcolor_t*colors)
120 {
121     int t;
122     int len = width*height;
123
124     for(t=0;t<len;t++) {
125         U32 m = data[t].r;
126         data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
127         data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
128         data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
129         data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
130     }
131 }
132
133 void blurImage(gfxcolor_t*src, int width, int height, int r)  __attribute__ ((noinline));
134
135 void blurImage(gfxcolor_t*src, int width, int height, int r)
136 {
137     int e = 2; // r times e is the sampling interval
138     double*gauss = (double*)rfx_alloc(r*e*sizeof(double));
139     double sum=0;
140     int x;
141     for(x=0;x<r*e;x++) {
142         double t = (x - r*e/2.0)/r;
143         gauss[x] = exp(-0.5*t*t);
144         sum += gauss[x];
145     }
146     int*weights = (int*)rfx_alloc(r*e*sizeof(int));
147     for(x=0;x<r*e;x++) {
148         weights[x] = (int)(gauss[x]*65536.0001/sum);
149     }
150     int range = r*e/2;
151
152     gfxcolor_t*tmp = rfx_alloc(sizeof(gfxcolor_t)*width*height);
153
154     int y;
155     for(y=0;y<height;y++) {
156         gfxcolor_t*s = &src[y*width];
157         gfxcolor_t*d = &tmp[y*width];
158         for(x=0;x<range && x<width;x++) {
159             d[x] = s[x];
160         }
161         for(;x<width-range;x++) {
162             int r=0;
163             int g=0;
164             int b=0;
165             int a=0;
166             int*f = weights;
167             int xx;
168             for(xx=x-range;xx<x+range;xx++) {
169                 r += s[xx].r * f[0];
170                 g += s[xx].g * f[0];
171                 b += s[xx].b * f[0];
172                 a += s[xx].a * f[0];
173                 f++;
174             }
175             d[x].r = r >> 16;
176             d[x].g = g >> 16;
177             d[x].b = b >> 16;
178             d[x].a = a >> 16;
179         }
180         for(;x<width;x++) {
181             d[x] = s[x];
182         }
183     }
184
185     for(x=0;x<width;x++) {
186         gfxcolor_t*s = &tmp[x];
187         gfxcolor_t*d = &src[x];
188         int yy=0;
189         for(y=0;y<range&&y<height;y++) {
190             d[yy] = s[yy];
191             yy+=width;
192         }
193         for(;y<height-range;y++) {
194             int r=0;
195             int g=0;
196             int b=0;
197             int a=0;
198             int*f = weights;
199             int cy,cyy=yy-range*width;
200             for(cy=y-range;cy<y+range;cy++) {
201                 r += s[cyy].r * f[0];
202                 g += s[cyy].g * f[0];
203                 b += s[cyy].b * f[0];
204                 a += s[cyy].a * f[0];
205                 cyy += width;
206                 f++;
207             }
208             d[yy].r = r >> 16;
209             d[yy].g = g >> 16;
210             d[yy].b = b >> 16;
211             d[yy].a = a >> 16;
212             yy += width;
213         }
214         for(;y<height;y++) {
215             d[yy] = s[yy];
216             yy += width;
217         }
218     }
219
220     rfx_free(tmp);
221     rfx_free(weights);
222     rfx_free(gauss);
223 }
224
225 int swf_ImageGetNumberOfPaletteEntries2(gfxcolor_t*_img, int width, int height)
226 {
227     int len = width*height;
228     int t;
229     U32* img = (U32*)_img;
230     U32 color1 = img[0];
231     U32 color2 = 0;
232     for(t=1;t<len;t++) {
233         if(img[t] != color1) {
234             color2 = img[t];
235             break;
236         }
237     }
238     if(t==len)
239         return 1;
240
241     for(;t<len;t++) {
242         if(img[t] != color1 && img[t] != color2) {
243             return width*height;
244         }
245     }
246     return 2;
247 }
248
249 gfximage_t* gfximage_rescale(gfximage_t*image, int newwidth, int newheight)
250 {
251     int x,y;
252     gfxcolor_t* newdata; 
253     scale_lookup_t *p, **lblockx,**lblocky;
254     rgba_int_t*tmpline;
255     int monochrome = 0;
256     gfxcolor_t monochrome_colors[2];
257    
258     if(newwidth<1)
259         newwidth=1;
260     if(newheight<1)
261         newheight=1;
262
263     int width = image->width;
264     int height = image->height;
265     gfxcolor_t*data = image->data;
266
267     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
268         monochrome=1;
269         encodeMonochromeImage(data, width, height, monochrome_colors);
270         int r1 = width / newwidth;
271         int r2 = height / newheight;
272         int r = r1<r2?r1:r2;
273         if(r>4) {
274             /* high-resolution monochrome images are usually dithered, so 
275                low-pass filter them first to get rid of any moire patterns */
276             blurImage(data, width, height, r+1);
277         }
278     }
279
280     tmpline = (rgba_int_t*)rfx_alloc(width*sizeof(rgba_int_t));
281     newdata = (gfxcolor_t*)rfx_alloc(newwidth*newheight*sizeof(gfxcolor_t));
282   
283     lblockx = make_scale_lookup(width, newwidth);
284     lblocky = make_scale_lookup(height, newheight);
285
286     for(p=lblocky[0];p<lblocky[newheight];p++)
287         p->pos*=width;
288
289     for(y=0;y<newheight;y++) {
290         gfxcolor_t*destline = &newdata[y*newwidth];
291         
292         /* create lookup table for y */
293         rgba_int_t*l = tmpline;
294         scale_lookup_t*p_y,*p_x;
295         memset(tmpline, 0, width*sizeof(rgba_int_t));
296         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
297             gfxcolor_t*line = &data[p_y->pos];
298             scale_lookup_t*p_x;
299             int weight = p_y->weight;
300             for(x=0;x<width;x++) {
301                 tmpline[x].r += line[x].r*weight;
302                 tmpline[x].g += line[x].g*weight;
303                 tmpline[x].b += line[x].b*weight;
304                 tmpline[x].a += line[x].a*weight;
305             }
306         }
307
308         /* process x direction */
309         p_x = lblockx[0];
310         for(x=0;x<newwidth;x++) {
311             unsigned int r=0,g=0,b=0,a=0;
312             scale_lookup_t*p_x_to = lblockx[x+1];
313             do { 
314                 rgba_int_t* col = &tmpline[p_x->pos];
315                 unsigned int weight = p_x->weight;
316                 r += col->r*weight;
317                 g += col->g*weight;
318                 b += col->b*weight;
319                 a += col->a*weight;
320                 p_x++;
321             } while (p_x<p_x_to);
322
323             destline->r = r >> 16;
324             destline->g = g >> 16;
325             destline->b = b >> 16;
326             destline->a = a >> 16;
327            
328             destline++;
329         }
330     }
331
332     if(monochrome)
333         decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);
334
335     rfx_free(tmpline);
336     rfx_free(*lblockx);
337     rfx_free(lblockx);
338     rfx_free(*lblocky);
339     rfx_free(lblocky);
340
341     gfximage_t*image2 = (gfximage_t*)malloc(sizeof(gfximage_t));
342     image2->data = newdata;
343     image2->width = newwidth;
344     image2->height = newheight;
345     return image2;
346 }
347
348 void gfximage_free(gfximage_t*b)
349 {
350     free(b->data);
351     b->data = 0;
352     free(b);
353 }
354