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);
27 void gfximage_save_jpeg(gfximage_t
*img
, const char*filename
, int quality
)
30 int l
= img
->width
*img
->height
;
31 unsigned char*data
= (unsigned char*)rfx_alloc(img
->width
*img
->height
*3);
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
);
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
{
57 typedef struct rgba_int
{
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
);
70 scale_lookup_t
*p_x
= lookupx
;
73 for(x
=0;x
<newwidth
;x
++) {
77 double rem
= fromx
+1-px
;
78 int i
= (int)(256/fx
);
79 int xweight
= (int)(rem
*256/fx
);
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
;
96 for(x
=0;x
<newwidth
;x
++) {
98 int ix2
= ((int)px
)+1;
100 if(ix2
>=width
) ix2
=width
-1;
104 p_x
[0].weight
= (int)(256*(1-r
));
106 p_x
[1].weight
= 256-p_x
[0].weight
;
112 lblockx
[newwidth
] = p_x
;
116 static void encodeMonochromeImage(gfxcolor_t
*data
, int width
, int height
, gfxcolor_t
*colors
)
119 int len
= width
*height
;
121 U32
* img
= (U32
*)data
;
125 if(img
[t
] != color1
) {
130 *(U32
*)&colors
[0] = color1
;
131 *(U32
*)&colors
[1] = color2
;
133 if(img
[t
] == color1
) {
141 static void decodeMonochromeImage(gfxcolor_t
*data
, int width
, int height
, gfxcolor_t
*colors
)
144 int len
= width
*height
;
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));
164 double t
= (x
- r
*e
/2.0)/r
;
165 gauss
[x
] = exp(-0.5*t
*t
);
168 int*weights
= (int*)rfx_alloc(r
*e
*sizeof(int));
170 weights
[x
] = (int)(gauss
[x
]*65536.0001/sum
);
174 gfxcolor_t
*tmp
= rfx_alloc(sizeof(gfxcolor_t
)*width
*height
);
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
++) {
183 for(;x
<width
-range
;x
++) {
190 for(xx
=x
-range
;xx
<x
+range
;xx
++) {
207 for(x
=0;x
<width
;x
++) {
208 gfxcolor_t
*s
= &tmp
[x
];
209 gfxcolor_t
*d
= &src
[x
];
211 for(y
=0;y
<range
&&y
<height
;y
++) {
215 for(;y
<height
-range
;y
++) {
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];
247 int gfximage_getNumberOfPaletteEntries(gfximage_t
*img
)
249 int width
= img
->width
;
250 int height
= img
->height
;
252 int size
= width
*height
;
254 U32
* data
= (U32
*)img
->data
;
255 U32 color1
= data
[0];
257 for(t
=1;t
<size
;t
++) {
258 if(data
[t
] != color1
) {
267 if(data
[t
] != color1
&& data
[t
] != color2
) {
274 gfximage_t
* gfximage_rescale_old(gfximage_t
*image
, int newwidth
, int newheight
)
278 scale_lookup_t
*p
, **lblockx
,**lblocky
;
281 gfxcolor_t monochrome_colors
[2];
288 int width
= image
->width
;
289 int height
= image
->height
;
290 gfxcolor_t
*data
= image
->data
;
292 if(gfximage_getNumberOfPaletteEntries(image
) == 2) {
294 encodeMonochromeImage(data
, width
, height
, monochrome_colors
);
295 int r1
= width
/ newwidth
;
296 int r2
= height
/ newheight
;
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
++)
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
];
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 */
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];
339 rgba_int_t
* col
= &tmpline
[p_x
->pos
];
340 unsigned int weight
= p_x
->weight
;
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;
358 decodeMonochromeImage(newdata
, newwidth
, newheight
, monochrome_colors
);
366 gfximage_t
*image2
= (gfximage_t
*)malloc(sizeof(gfximage_t
));
367 image2
->data
= newdata
;
368 image2
->width
= newwidth
;
369 image2
->height
= newheight
;
374 gfximage_t
* gfximage_rescale_fft(gfximage_t
*image
, int newwidth
, int newheight
)
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
);
385 gfxcolor_t monochrome_colors
[2];
386 if(gfximage_getNumberOfPaletteEntries(image
) == 2) {
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
)
413 if(channel
>=1 && monochrome
)
416 for(t
=0;t
<osize
;t
++) {
417 data
[t
] = rgba
[t
*4+channel
];
419 fftwf_execute(plan1
);
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
];
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
++) {
446 rgba_new_asbytes
[t
*4+channel
] = f
<0?0:(f
>255?255:f
);
449 fftwf_destroy_plan(plan1
);
450 fftwf_destroy_plan(plan2
);
455 for(t
=0;t
<nsize
;t
++) {
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
;
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
);
478 gfximage_t
* gfximage_rescale(gfximage_t
*image
, int newwidth
, int newheight
)
480 return gfximage_rescale_old(image
, newwidth
, newheight
);
484 bool gfximage_has_alpha(gfximage_t
*img
)
486 int size
= img
->width
*img
->height
;
487 gfxcolor_t
*data
= img
->data
;
489 for(t
=0;t
<size
;t
++) {
496 void gfximage_free(gfximage_t
*b
)