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