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