#include #include #include #include #include #include "../config.h" #include "jpeg.h" #include "png.h" #include "mem.h" #include "gfximage.h" #include "types.h" #ifdef HAVE_FFTW3 #include #endif #define MOD(x,d) (((x)+(d))%(d)) gfximage_t*gfximage_new(int width, int height) { gfximage_t*i = rfx_calloc(sizeof(gfximage_t)); i->data = rfx_calloc(width*height*4); i->width = width; i->height = height; return i; } void gfximage_save_jpeg(gfximage_t*img, const char*filename, int quality) { int x,y; int l = img->width*img->height; unsigned char*data = (unsigned char*)rfx_alloc(img->width*img->height*3); int s,t; for(t=0,s=0;tdata[t].r; data[s+1] = img->data[t].g; data[s+2] = img->data[t].b; } jpeg_save(data, img->width, img->height, quality, filename); free(data); } void gfximage_save_png(gfximage_t*image, const char*filename) { png_write(filename, (void*)image->data, image->width, image->height); } void gfximage_save_png_quick(gfximage_t*image, const char*filename) { png_write_quick(filename, (void*)image->data, image->width, image->height); } typedef struct scale_lookup { int pos; unsigned int weight; } scale_lookup_t; typedef struct rgba_int { unsigned int r,g,b,a; } rgba_int_t; static int bicubic = 0; static scale_lookup_t**make_scale_lookup(int width, int newwidth) { scale_lookup_t*lookupx = (scale_lookup_t*)rfx_alloc((width>newwidth?width:newwidth)*2*sizeof(scale_lookup_t)); scale_lookup_t**lblockx = (scale_lookup_t**)rfx_alloc((newwidth+1)*sizeof(scale_lookup_t**)); double fx = ((double)width)/((double)newwidth); double px = 0; int x; scale_lookup_t*p_x = lookupx; if(newwidth<=width) { for(x=0;x=width) tox = width-1; for(xx=fromx;xx<=tox;xx++) { if(xx==fromx && xx==tox) p_x->weight = 256; else if(xx==fromx) p_x->weight = xweight; else if(xx==tox) p_x->weight = 256-w; else p_x->weight = i; w+=p_x->weight; p_x->pos = xx; p_x++; } px = ex; } } else { for(x=0;x=width) ix2=width-1; lblockx[x] = p_x; if(bicubic) r = -2*r*r*r+3*r*r; p_x[0].weight = (int)(256*(1-r)); p_x[0].pos = ix1; p_x[1].weight = 256-p_x[0].weight; p_x[1].pos = ix2; p_x+=2; px += fx; } } lblockx[newwidth] = p_x; return lblockx; } static void encodeMonochromeImage(gfxcolor_t*data, int width, int height, gfxcolor_t*colors) { int t; int len = width*height; U32* img = (U32*)data; U32 color1 = img[0]; U32 color2 = 0; for(t=1;t> 8; data[t].g = (colors[0].g * (255-m) + colors[1].g * m) >> 8; data[t].b = (colors[0].b * (255-m) + colors[1].b * m) >> 8; data[t].a = (colors[0].a * (255-m) + colors[1].a * m) >> 8; } } void blurImage(gfxcolor_t*src, int width, int height, int r) __attribute__ ((noinline)); void blurImage(gfxcolor_t*src, int width, int height, int r) { int e = 2; // r times e is the sampling interval double*gauss = (double*)rfx_alloc(r*e*sizeof(double)); double sum=0; int x; for(x=0;x> 16; d[x].g = g >> 16; d[x].b = b >> 16; d[x].a = a >> 16; } for(;x> 16; d[yy].g = g >> 16; d[yy].b = b >> 16; d[yy].a = a >> 16; yy += width; } for(;ywidth; int height = img->height; int size = width*height; int t; U32* data = (U32*)img->data; U32 color1 = data[0]; U32 color2 = 0; for(t=1;twidth; int height = image->height; gfxcolor_t*data = image->data; if(gfximage_getNumberOfPaletteEntries(image) == 2) { monochrome=1; encodeMonochromeImage(data, width, height, monochrome_colors); int r1 = width / newwidth; int r2 = height / newheight; int r = r14) { /* high-resolution monochrome images are usually dithered, so low-pass filter them first to get rid of any moire patterns */ blurImage(data, width, height, r+1); } } tmpline = (rgba_int_t*)rfx_alloc(width*sizeof(rgba_int_t)); newdata = (gfxcolor_t*)rfx_alloc(newwidth*newheight*sizeof(gfxcolor_t)); lblockx = make_scale_lookup(width, newwidth); lblocky = make_scale_lookup(height, newheight); for(p=lblocky[0];ppos*=width; for(y=0;ypos]; scale_lookup_t*p_x; int weight = p_y->weight; for(x=0;xpos]; unsigned int weight = p_x->weight; r += col->r*weight; g += col->g*weight; b += col->b*weight; a += col->a*weight; p_x++; } while (p_xr = r >> 16; destline->g = g >> 16; destline->b = b >> 16; destline->a = a >> 16; destline++; } } if(monochrome) decodeMonochromeImage(newdata, newwidth, newheight, monochrome_colors); rfx_free(tmpline); rfx_free(*lblockx); rfx_free(lblockx); rfx_free(*lblocky); rfx_free(lblocky); gfximage_t*image2 = (gfximage_t*)malloc(sizeof(gfximage_t)); image2->data = newdata; image2->width = newwidth; image2->height = newheight; return image2; } #ifdef HAVE_FFTW3 gfximage_t* gfximage_rescale_fft(gfximage_t*image, int newwidth, int newheight) { int channel; int oldwidth = image->width; int oldheight = image->height; unsigned char*rgba = (unsigned char*)image->data; bool has_alpha = gfximage_has_alpha(image); bool monochrome = 0; gfxcolor_t monochrome_colors[2]; if(gfximage_getNumberOfPaletteEntries(image) == 2) { monochrome=1; encodeMonochromeImage(image->data, image->width, image->height, monochrome_colors); } float*data = fftwf_malloc(sizeof(float)*oldwidth*oldheight); int osize = oldwidth*oldheight; int nsize = newwidth*newheight; assert(newwidth <= oldwidth && newheight <= oldheight); gfxcolor_t*rgba_new = malloc(newwidth*newheight*sizeof(gfxcolor_t)); unsigned char*rgba_new_asbytes = (unsigned char*)rgba_new; int oxwidth = oldwidth/2+1; int oxsize = oxwidth*oldheight; fftwf_complex* fft = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*oxwidth*oldheight); fftwf_complex* fft2 = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*newwidth*newheight); fftwf_complex* data2 = fftwf_malloc(sizeof(fftwf_complex)*newwidth*newheight); fftwf_plan plan1 = fftwf_plan_dft_r2c_2d(oldheight, oldwidth, data, fft, FFTW_ESTIMATE); fftwf_plan plan2 = fftwf_plan_dft_2d(newheight, newwidth, fft2, data2, FFTW_BACKWARD, FFTW_ESTIMATE); double ff = 1.0/osize; for(channel=0;channel<4;channel++) { if(channel==0 && !has_alpha) continue; if(channel>=1 && monochrome) continue; int t; for(t=0;t> 2; for(y=0;y255?255:f); } } fftwf_destroy_plan(plan1); fftwf_destroy_plan(plan2); free(fft); free(fft2); if(!has_alpha) { int t; for(t=0;tdata = rgba_new; image2->width = newwidth; image2->height = newheight; return image2; } #endif #ifdef HAVE_FFTW3 gfximage_t* gfximage_rescale(gfximage_t*image, int newwidth, int newheight) { //return gfximage_rescale_fft(image, newwidth, newheight); return gfximage_rescale_old(image, newwidth, newheight); } #else gfximage_t* gfximage_rescale(gfximage_t*image, int newwidth, int newheight) { return gfximage_rescale_old(image, newwidth, newheight); } #endif bool gfximage_has_alpha(gfximage_t*img) { int size = img->width*img->height; gfxcolor_t*data = img->data; int t; for(t=0;tdata); b->data = 0; free(b); }