bugfixes in swfc
[swftools.git] / lib / gfximage.c
blobcbe417baa6afec086bf8f8357e76295fbeca193b
1 #include <stdlib.h>
2 #include <stdbool.h>
3 #include <math.h>
4 #include <memory.h>
5 #include <assert.h>
6 #include "../config.h"
7 #include "jpeg.h"
8 #include "png.h"
9 #include "mem.h"
10 #include "gfximage.h"
11 #include "types.h"
12 #ifdef HAVE_FFTW3
13 #include <fftw3.h>
14 #endif
16 #define MOD(x,d) (((x)+(d))%(d))
18 gfximage_t*gfximage_new(int width, int height)
20 gfximage_t*i = rfx_calloc(sizeof(gfximage_t));
21 i->data = rfx_calloc(width*height*4);
22 i->width = width;
23 i->height = height;
24 return i;
27 void gfximage_save_jpeg(gfximage_t*img, const char*filename, int quality)
29 int x,y;
30 int l = img->width*img->height;
31 unsigned char*data = (unsigned char*)rfx_alloc(img->width*img->height*3);
32 int s,t;
33 for(t=0,s=0;t<l;s+=3,t++) {
34 data[s+0] = img->data[t].r;
35 data[s+1] = img->data[t].g;
36 data[s+2] = img->data[t].b;
38 jpeg_save(data, img->width, img->height, quality, filename);
39 free(data);
42 void gfximage_save_png(gfximage_t*image, const char*filename)
44 png_write(filename, (void*)image->data, image->width, image->height);
47 void gfximage_save_png_quick(gfximage_t*image, const char*filename)
49 png_write_quick(filename, (void*)image->data, image->width, image->height);
52 typedef struct scale_lookup {
53 int pos;
54 unsigned int weight;
55 } scale_lookup_t;
57 typedef struct rgba_int {
58 unsigned int r,g,b,a;
59 } rgba_int_t;
61 static int bicubic = 0;
63 static scale_lookup_t**make_scale_lookup(int width, int newwidth)
65 scale_lookup_t*lookupx = (scale_lookup_t*)rfx_alloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t));
66 scale_lookup_t**lblockx = (scale_lookup_t**)rfx_alloc((newwidth+1)*sizeof(scale_lookup_t**));
67 double fx = ((double)width)/((double)newwidth);
68 double px = 0;
69 int x;
70 scale_lookup_t*p_x = lookupx;
72 if(newwidth<=width) {
73 for(x=0;x<newwidth;x++) {
74 double ex = px + fx;
75 int fromx = (int)px;
76 int tox = (int)ex;
77 double rem = fromx+1-px;
78 int i = (int)(256/fx);
79 int xweight = (int)(rem*256/fx);
80 int xx;
81 int w = 0;
82 lblockx[x] = p_x;
83 if(tox>=width) tox = width-1;
84 for(xx=fromx;xx<=tox;xx++) {
85 if(xx==fromx && xx==tox) p_x->weight = 256;
86 else if(xx==fromx) p_x->weight = xweight;
87 else if(xx==tox) p_x->weight = 256-w;
88 else p_x->weight = i;
89 w+=p_x->weight;
90 p_x->pos = xx;
91 p_x++;
93 px = ex;
95 } else {
96 for(x=0;x<newwidth;x++) {
97 int ix1 = (int)px;
98 int ix2 = ((int)px)+1;
99 double r = px-ix1;
100 if(ix2>=width) ix2=width-1;
101 lblockx[x] = p_x;
102 if(bicubic)
103 r = -2*r*r*r+3*r*r;
104 p_x[0].weight = (int)(256*(1-r));
105 p_x[0].pos = ix1;
106 p_x[1].weight = 256-p_x[0].weight;
107 p_x[1].pos = ix2;
108 p_x+=2;
109 px += fx;
112 lblockx[newwidth] = p_x;
113 return lblockx;
116 static void encodeMonochromeImage(gfxcolor_t*data, int width, int height, gfxcolor_t*colors)
118 int t;
119 int len = width*height;
121 U32* img = (U32*)data;
122 U32 color1 = img[0];
123 U32 color2 = 0;
124 for(t=1;t<len;t++) {
125 if(img[t] != color1) {
126 color2 = img[t];
127 break;
130 *(U32*)&colors[0] = color1;
131 *(U32*)&colors[1] = color2;
132 for(t=0;t<len;t++) {
133 if(img[t] == color1) {
134 img[t] = 0;
135 } else {
136 img[t] = 0xffffffff;
141 static void decodeMonochromeImage(gfxcolor_t*data, int width, int height, gfxcolor_t*colors)
143 int t;
144 int len = width*height;
146 for(t=0;t<len;t++) {
147 U32 m = data[t].a;
148 data[t].r = (colors[0].r * (255-m) + colors[1].r * m) >> 8;
149 data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8;
150 data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8;
151 data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8;
155 void blurImage(gfxcolor_t*src, int width, int height, int r) __attribute__ ((noinline));
157 void blurImage(gfxcolor_t*src, int width, int height, int r)
159 int e = 2; // r times e is the sampling interval
160 double*gauss = (double*)rfx_alloc(r*e*sizeof(double));
161 double sum=0;
162 int x;
163 for(x=0;x<r*e;x++) {
164 double t = (x - r*e/2.0)/r;
165 gauss[x] = exp(-0.5*t*t);
166 sum += gauss[x];
168 int*weights = (int*)rfx_alloc(r*e*sizeof(int));
169 for(x=0;x<r*e;x++) {
170 weights[x] = (int)(gauss[x]*65536.0001/sum);
172 int range = r*e/2;
174 gfxcolor_t*tmp = rfx_alloc(sizeof(gfxcolor_t)*width*height);
176 int y;
177 for(y=0;y<height;y++) {
178 gfxcolor_t*s = &src[y*width];
179 gfxcolor_t*d = &tmp[y*width];
180 for(x=0;x<range && x<width;x++) {
181 d[x] = s[x];
183 for(;x<width-range;x++) {
184 int r=0;
185 int g=0;
186 int b=0;
187 int a=0;
188 int*f = weights;
189 int xx;
190 for(xx=x-range;xx<x+range;xx++) {
191 r += s[xx].r * f[0];
192 g += s[xx].g * f[0];
193 b += s[xx].b * f[0];
194 a += s[xx].a * f[0];
195 f++;
197 d[x].r = r >> 16;
198 d[x].g = g >> 16;
199 d[x].b = b >> 16;
200 d[x].a = a >> 16;
202 for(;x<width;x++) {
203 d[x] = s[x];
207 for(x=0;x<width;x++) {
208 gfxcolor_t*s = &tmp[x];
209 gfxcolor_t*d = &src[x];
210 int yy=0;
211 for(y=0;y<range&&y<height;y++) {
212 d[yy] = s[yy];
213 yy+=width;
215 for(;y<height-range;y++) {
216 int r=0;
217 int g=0;
218 int b=0;
219 int a=0;
220 int*f = weights;
221 int cy,cyy=yy-range*width;
222 for(cy=y-range;cy<y+range;cy++) {
223 r += s[cyy].r * f[0];
224 g += s[cyy].g * f[0];
225 b += s[cyy].b * f[0];
226 a += s[cyy].a * f[0];
227 cyy += width;
228 f++;
230 d[yy].r = r >> 16;
231 d[yy].g = g >> 16;
232 d[yy].b = b >> 16;
233 d[yy].a = a >> 16;
234 yy += width;
236 for(;y<height;y++) {
237 d[yy] = s[yy];
238 yy += width;
242 rfx_free(tmp);
243 rfx_free(weights);
244 rfx_free(gauss);
247 int gfximage_getNumberOfPaletteEntries(gfximage_t*img)
249 int width = img->width;
250 int height = img->height;
252 int size = width*height;
253 int t;
254 U32* data = (U32*)img->data;
255 U32 color1 = data[0];
256 U32 color2 = 0;
257 for(t=1;t<size;t++) {
258 if(data[t] != color1) {
259 color2 = data[t];
260 break;
263 if(t==size)
264 return 1;
266 for(;t<size;t++) {
267 if(data[t] != color1 && data[t] != color2) {
268 return width*height;
271 return 2;
274 gfximage_t* gfximage_rescale_old(gfximage_t*image, int newwidth, int newheight)
276 int x,y;
277 gfxcolor_t* newdata;
278 scale_lookup_t *p, **lblockx,**lblocky;
279 rgba_int_t*tmpline;
280 int monochrome = 0;
281 gfxcolor_t monochrome_colors[2];
283 if(newwidth<1)
284 newwidth=1;
285 if(newheight<1)
286 newheight=1;
288 int width = image->width;
289 int height = image->height;
290 gfxcolor_t*data = image->data;
292 if(gfximage_getNumberOfPaletteEntries(image) == 2) {
293 monochrome=1;
294 encodeMonochromeImage(data, width, height, monochrome_colors);
295 int r1 = width / newwidth;
296 int r2 = height / newheight;
297 int r = r1<r2?r1:r2;
298 if(r>4) {
299 /* high-resolution monochrome images are usually dithered, so
300 low-pass filter them first to get rid of any moire patterns */
301 blurImage(data, width, height, r+1);
305 tmpline = (rgba_int_t*)rfx_alloc(width*sizeof(rgba_int_t));
306 newdata = (gfxcolor_t*)rfx_alloc(newwidth*newheight*sizeof(gfxcolor_t));
308 lblockx = make_scale_lookup(width, newwidth);
309 lblocky = make_scale_lookup(height, newheight);
311 for(p=lblocky[0];p<lblocky[newheight];p++)
312 p->pos*=width;
314 for(y=0;y<newheight;y++) {
315 gfxcolor_t*destline = &newdata[y*newwidth];
317 /* create lookup table for y */
318 rgba_int_t*l = tmpline;
319 scale_lookup_t*p_y,*p_x;
320 memset(tmpline, 0, width*sizeof(rgba_int_t));
321 for(p_y=lblocky[y];p_y<lblocky[y+1];p_y++) {
322 gfxcolor_t*line = &data[p_y->pos];
323 scale_lookup_t*p_x;
324 int weight = p_y->weight;
325 for(x=0;x<width;x++) {
326 tmpline[x].r += line[x].r*weight;
327 tmpline[x].g += line[x].g*weight;
328 tmpline[x].b += line[x].b*weight;
329 tmpline[x].a += line[x].a*weight;
333 /* process x direction */
334 p_x = lblockx[0];
335 for(x=0;x<newwidth;x++) {
336 unsigned int r=0,g=0,b=0,a=0;
337 scale_lookup_t*p_x_to = lblockx[x+1];
338 do {
339 rgba_int_t* col = &tmpline[p_x->pos];
340 unsigned int weight = p_x->weight;
341 r += col->r*weight;
342 g += col->g*weight;
343 b += col->b*weight;
344 a += col->a*weight;
345 p_x++;
346 } while (p_x<p_x_to);
348 destline->r = r >> 16;
349 destline->g = g >> 16;
350 destline->b = b >> 16;
351 destline->a = a >> 16;
353 destline++;
357 if(monochrome)
358 decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors);
360 rfx_free(tmpline);
361 rfx_free(*lblockx);
362 rfx_free(lblockx);
363 rfx_free(*lblocky);
364 rfx_free(lblocky);
366 gfximage_t*image2 = (gfximage_t*)malloc(sizeof(gfximage_t));
367 image2->data = newdata;
368 image2->width = newwidth;
369 image2->height = newheight;
370 return image2;
373 #ifdef HAVE_FFTW3
374 gfximage_t* gfximage_rescale_fft(gfximage_t*image, int newwidth, int newheight)
376 int channel;
378 int oldwidth = image->width;
379 int oldheight = image->height;
381 unsigned char*rgba = (unsigned char*)image->data;
383 bool has_alpha = gfximage_has_alpha(image);
384 bool monochrome = 0;
385 gfxcolor_t monochrome_colors[2];
386 if(gfximage_getNumberOfPaletteEntries(image) == 2) {
387 monochrome=1;
388 encodeMonochromeImage(image->data, image->width, image->height, monochrome_colors);
391 float*data = fftwf_malloc(sizeof(float)*oldwidth*oldheight);
392 int osize = oldwidth*oldheight;
393 int nsize = newwidth*newheight;
395 assert(newwidth <= oldwidth && newheight <= oldheight);
397 gfxcolor_t*rgba_new = malloc(newwidth*newheight*sizeof(gfxcolor_t));
398 unsigned char*rgba_new_asbytes = (unsigned char*)rgba_new;
400 int oxwidth = oldwidth/2+1;
401 int oxsize = oxwidth*oldheight;
402 fftwf_complex* fft = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*oxwidth*oldheight);
403 fftwf_complex* fft2 = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*newwidth*newheight);
404 fftwf_complex* data2 = fftwf_malloc(sizeof(fftwf_complex)*newwidth*newheight);
405 fftwf_plan plan1 = fftwf_plan_dft_r2c_2d(oldheight, oldwidth, data, fft, FFTW_ESTIMATE);
406 fftwf_plan plan2 = fftwf_plan_dft_2d(newheight, newwidth, fft2, data2, FFTW_BACKWARD, FFTW_ESTIMATE);
408 double ff = 1.0/osize;
410 for(channel=0;channel<4;channel++) {
411 if(channel==0 && !has_alpha)
412 continue;
413 if(channel>=1 && monochrome)
414 continue;
415 int t;
416 for(t=0;t<osize;t++) {
417 data[t] = rgba[t*4+channel];
419 fftwf_execute(plan1);
421 int x,y;
422 int width2 = newwidth >> 2;
423 for(y=0;y<newheight;y++) {
424 fftwf_complex*from,*to;
426 int fromy = (oldheight-MOD(y-newheight/2,oldheight))%oldheight;
427 from = &fft[fromy*oxwidth + 1];
428 to = &fft2[MOD(y-newheight/2,newheight)*newwidth+newwidth-width2];
429 int x;
430 for(x=0;x<width2;x++) {
431 to[x][0] = from[width2-x-1][0]*ff;
432 to[x][1] = -from[width2-x-1][1]*ff;
435 from = &fft[MOD(y-newheight/2,oldheight)*oxwidth];
436 to = &fft2[MOD(y-newheight/2,newheight)*newwidth];
437 for(x=0;x<width2;x++) {
438 to[x][0] = from[x][0]*ff;
439 to[x][1] = from[x][1]*ff;
442 fftwf_execute(plan2);
444 for(t=0;t<nsize;t++) {
445 int f = data2[t][0];
446 rgba_new_asbytes[t*4+channel] = f<0?0:(f>255?255:f);
449 fftwf_destroy_plan(plan1);
450 fftwf_destroy_plan(plan2);
451 free(fft);
452 free(fft2);
453 if(!has_alpha) {
454 int t;
455 for(t=0;t<nsize;t++) {
456 rgba_new[t].a = 255;
460 if(monochrome)
461 decodeMonochromeImage(rgba_new, newwidth, newheight, monochrome_colors);
463 gfximage_t*image2 = (gfximage_t*)malloc(sizeof(gfximage_t));
464 image2->data = rgba_new;
465 image2->width = newwidth;
466 image2->height = newheight;
467 return image2;
469 #endif
471 #ifdef HAVE_FFTW3
472 gfximage_t* gfximage_rescale(gfximage_t*image, int newwidth, int newheight)
474 //return gfximage_rescale_fft(image, newwidth, newheight);
475 return gfximage_rescale_old(image, newwidth, newheight);
477 #else
478 gfximage_t* gfximage_rescale(gfximage_t*image, int newwidth, int newheight)
480 return gfximage_rescale_old(image, newwidth, newheight);
482 #endif
484 bool gfximage_has_alpha(gfximage_t*img)
486 int size = img->width*img->height;
487 gfxcolor_t*data = img->data;
488 int t;
489 for(t=0;t<size;t++) {
490 if(data[t].a!=255)
491 return 1;
493 return 0;
496 void gfximage_free(gfximage_t*b)
498 free(b->data);
499 b->data = 0;
500 free(b);