Skip to content

Instantly share code, notes, and snippets.

@Alrecenk
Last active August 29, 2015 14:02
Show Gist options
  • Save Alrecenk/c7ac3a789ca916e090b0 to your computer and use it in GitHub Desktop.
Save Alrecenk/c7ac3a789ca916e090b0 to your computer and use it in GitHub Desktop.
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
}else{
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]);
if(intersectarea>0.000001){
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