seed random from ruby interface
[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 || newheight<1)
259         return 0;
260
261     int width = image->width;
262     int height = image->height;
263     gfxcolor_t*data = image->data;
264
265     if(swf_ImageGetNumberOfPaletteEntries2(data, width, height) == 2) {
266         monochrome=1;
267         encodeMonochromeImage(data, width, height, monochrome_colors);
268         int r1 = width / newwidth;
269         int r2 = height / newheight;
270         int r = r1<r2?r1:r2;
271         if(r>4) {
272             /* high-resolution monochrome images are usually dithered, so 
273                low-pass filter them first to get rid of any moire patterns */
274             blurImage(data, width, height, r+1);
275         }
276     }
277
278     tmpline = (rgba_int_t*)rfx_alloc(width*sizeof(rgba_int_t));
279     newdata = (gfxcolor_t*)rfx_alloc(newwidth*newheight*sizeof(gfxcolor_t));
280   
281     lblockx = make_scale_lookup(width, newwidth);
282     lblocky = make_scale_lookup(height, newheight);
283
284     for(p=lblocky[0];p<lblocky[newheight];p++)
285         p->pos*=width;
286
287     for(y=0;y<newheight;y++) {
288         gfxcolor_t*destline = &newdata[y*newwidth];
289         
290         /* create lookup table for y */
291         rgba_int_t*l = tmpline;
292         scale_lookup_t*p_y,*p_x;
293         memset(tmpline, 0, width*sizeof(rgba_int_t));
294         for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
295             gfxcolor_t*line = &data[p_y->pos];
296             scale_lookup_t*p_x;
297             int weight = p_y->weight;
298             for(x=0;x<width;x++) {
299                 tmpline[x].r += line[x].r*weight;
300                 tmpline[x].g += line[x].g*weight;
301                 tmpline[x].b += line[x].b*weight;
302                 tmpline[x].a += line[x].a*weight;
303             }
304         }
305
306         /* process x direction */
307         p_x = lblockx[0];
308         for(x=0;x<newwidth;x++) {
309             unsigned int r=0,g=0,b=0,a=0;
310             scale_lookup_t*p_x_to = lblockx[x+1];
311             do { 
312                 rgba_int_t* col = &tmpline[p_x->pos];
313                 unsigned int weight = p_x->weight;
314                 r += col->r*weight;
315                 g += col->g*weight;
316                 b += col->b*weight;
317                 a += col->a*weight;
318                 p_x++;
319             } while (p_x<p_x_to);
320
321             destline->r = r >> 16;
322             destline->g = g >> 16;
323             destline->b = b >> 16;
324             destline->a = a >> 16;
325            
326             destline++;
327         }
328     }
329
330     if(monochrome)
331         decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);
332
333     rfx_free(tmpline);
334     rfx_free(*lblockx);
335     rfx_free(lblockx);
336     rfx_free(*lblocky);
337     rfx_free(lblocky);
338
339     gfximage_t*image2 = (gfximage_t*)malloc(sizeof(gfximage_t));
340     image2->data = newdata;
341     image2->width = newwidth;
342     image2->height = newheight;
343     return image2;
344 }
345
346 void gfximage_free(gfximage_t*b)
347 {
348     free(b->data);
349     b->data = 0;
350     free(b);
351 }
352