Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Scales down an image by an area weighted averaging of all overlapping pixels. Equivalent to infinite supersampling.
//scales an image, maintaining aspect ratio, to fit within the desired width and height
//averages color over squares weighted by overlap area to get "perfect" results when scaling down
//does not interpolate and is not designed for scaling up, only down (hence thumbnail)
public static BufferedImage makethumbnail(BufferedImage img, double desiredwidth, double desiredheight){
//System.out.println("Original Image size: " + img.getWidth(null)+ " x "+img.getHeight(null));
if(img ==null || img.getWidth(null) <1 || img.getHeight(null) <1){
return null; // something wrong with image
byte image[][][] = convertimage(img) ; // convert to byte array, first index is x, then y, then {r,g,b}
int width = image.length ;
int height = image[0].length ;
//scale uniformly to fit within the tiven size (will be smaller if aspect ratio is different)
double scale = Math.min(desiredwidth/(double)width, desiredheight/(double)height) ;
int nw = (int)(width*scale+.1), nh = (int)(height*scale+.1) ;
byte newimage[][][] = new byte[nw][nh][3];
//sample the pixels into the new image
double pixel[] = new double[4];
double xstep = width/(double)nw, ystep=height/(double)nh;
for(int x = 0 ; x < nw;x++){
for(int y = 0 ; y < nh;y++){
//get axis alignd bounding box to intersect with original image for this pixel
pixel[0] = x*xstep ;
pixel[1] = y*ystep ;
pixel[2] = pixel[0]+xstep;
pixel[3] = pixel[1]+ystep;
double c[] = colorsampled(pixel, image);
//cast back to byte, add 0.5 before truncating to get rounding
newimage[x][y][0] = (byte)(c[0]+.5);
newimage[x][y][1] = (byte)(c[1]+.5);
newimage[x][y][2] = (byte)(c[2]+.5);
BufferedImage img2 = convertimage(newimage) ;
return img2 ;
//returns the average color of an axis aligned bounding box on this image
//using no interpolation
//AABB is an axis aligned bounding box of the form{ minx,miny,maxx,maxy}
public static double[] colorsampled(double AABB[], byte image[][][]){
int width = image.length;
int height = image[1].length ;
int minx = (int)(AABB[0]) ;
int maxx = (int)(AABB[2]+1) ;
int miny = (int)(AABB[1]) ;
int maxy = (int)(AABB[3]+1) ;
//make sure AABB doesn't try to read outside of texture
if(minx<0)minx = 0 ;
if(miny<0)miny = 0;
if(maxx>width)maxx = width ;
if(maxy>height)maxy = height ;
//area*each color
double rarea = 0 ;
double barea = 0 ;
double garea = 0 ;
double area =0,a;
for(int x=minx;x<maxx;x++){
for(int y=miny;y<maxy;y++){
double[] texel = new double[]{x,y,x+1,y+1};
double intersect[] = AABBintersect(texel,AABB) ;
if(AABB[2] > AABB[0] && AABB[3] > AABB[1]){//if the AABBs intersect
double intersectarea = (AABB[2]-AABB[0])*(AABB[3]-AABB[1]);
area += intersectarea ;
rarea+= (image[x][y][0]&0xff)*intersectarea ;
garea+= (image[x][y][1]&0xff)*intersectarea ;
barea+= (image[x][y][2]&0xff)*intersectarea ;
return new double[]{rarea/area,garea/area,barea/area};
//returns an axis aligned bounding box representing the intersection of two AABBs
//where AABBs given as {xmin,ymin,xmax,ymax}
public static double[] AABBintersect(double[] a, double[] b){
return new double[]{Math.max(a[0], b[0]),Math.max(a[1], b[1]), Math.min(a[2], b[2]),Math.min(a[3], b[3])};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.