What's the easiest way to auto crop the white border out of an image in java? Thanks in advance...
Asked
Active
Viewed 1.5k times
10
-
1Try this http://stackoverflow.com/questions/273530/java-image-library-to-deskew-and-crop-images – May 20 '12 at 23:30
4 Answers
24
Here's a way to crop all 4 sides, using the color from the very top-left pixel as the baseline, and allow for a tolerance of color variation so that noise in the image won't make the crop useless
public BufferedImage getCroppedImage(BufferedImage source, double tolerance) {
// Get our top-left pixel color as our "baseline" for cropping
int baseColor = source.getRGB(0, 0);
int width = source.getWidth();
int height = source.getHeight();
int topY = Integer.MAX_VALUE, topX = Integer.MAX_VALUE;
int bottomY = -1, bottomX = -1;
for(int y=0; y<height; y++) {
for(int x=0; x<width; x++) {
if (colorWithinTolerance(baseColor, source.getRGB(x, y), tolerance)) {
if (x < topX) topX = x;
if (y < topY) topY = y;
if (x > bottomX) bottomX = x;
if (y > bottomY) bottomY = y;
}
}
}
BufferedImage destination = new BufferedImage( (bottomX-topX+1),
(bottomY-topY+1), BufferedImage.TYPE_INT_ARGB);
destination.getGraphics().drawImage(source, 0, 0,
destination.getWidth(), destination.getHeight(),
topX, topY, bottomX, bottomY, null);
return destination;
}
private boolean colorWithinTolerance(int a, int b, double tolerance) {
int aAlpha = (int)((a & 0xFF000000) >>> 24); // Alpha level
int aRed = (int)((a & 0x00FF0000) >>> 16); // Red level
int aGreen = (int)((a & 0x0000FF00) >>> 8); // Green level
int aBlue = (int)(a & 0x000000FF); // Blue level
int bAlpha = (int)((b & 0xFF000000) >>> 24); // Alpha level
int bRed = (int)((b & 0x00FF0000) >>> 16); // Red level
int bGreen = (int)((b & 0x0000FF00) >>> 8); // Green level
int bBlue = (int)(b & 0x000000FF); // Blue level
double distance = Math.sqrt((aAlpha-bAlpha)*(aAlpha-bAlpha) +
(aRed-bRed)*(aRed-bRed) +
(aGreen-bGreen)*(aGreen-bGreen) +
(aBlue-bBlue)*(aBlue-bBlue));
// 510.0 is the maximum distance between two colors
// (0,0,0,0 -> 255,255,255,255)
double percentAway = distance / 510.0d;
return (percentAway > tolerance);
}

Todd
- 1,822
- 15
- 18
-
-
The tolerance allows for images without a perfectly solid background color to still be cropped. For example, if you scan a drawing from a sheet of paper, the paper won't show up as an exact white, but rather will consist of a range of colors close to white. If you tried to crop just by matching one specific color of white, little (if anything) would be cropped. By allowing for some variation in the color of the background being cropped, it can remove all the unnecessary surrounding background and leave you with just the drawing. – Todd Sep 17 '13 at 15:54
-
@Todd what should be the acceptable value of tolerance in function getCroppedImage ? – Vinod Louis Nov 30 '16 at 02:02
-
1@VinodLouis it depends on your use case and expected images. For me, I use 2.0, which means colors up to 2% away from the color of the top-left pixel are tolerated as being something to crop. 100% would crop everything, 0% would only crop away the exact color of the top-left pixel. – Todd Dec 06 '16 at 22:34
-
1I think the cropped image area is 1px to small in each dimension and thus scaled incorrectly: `destination.getGraphics().drawImage(source, ... , topX, topY, bottomX + 1, bottomY + 1, null);` This produces the correct result in my case. – Roben Mar 23 '17 at 11:57
7
If you want the white parts to be invisible, best way is to use image filters and make white pixels transparent, it is discussed here by @PhiLho with some good samples, if you want to resize your image so it's borders won't have white colors, you can do it with four simple loops, this little method that I've write for you does the trick, note that it just crop upper part of image, you can write the rest,
private Image getCroppedImage(String address) throws IOException{
BufferedImage source = ImageIO.read(new File(address)) ;
boolean flag = false ;
int upperBorder = -1 ;
do{
upperBorder ++ ;
for (int c1 =0 ; c1 < source.getWidth() ; c1++){
if(source.getRGB(c1, upperBorder) != Color.white.getRGB() ){
flag = true;
break ;
}
}
if (upperBorder >= source.getHeight())
flag = true ;
}while(!flag) ;
BufferedImage destination = new BufferedImage(source.getWidth(), source.getHeight() - upperBorder, BufferedImage.TYPE_INT_ARGB) ;
destination.getGraphics().drawImage(source, 0, upperBorder*-1, null) ;
return destination ;
}

Community
- 1
- 1

fahim ayat
- 312
- 5
- 10
0
And here just another Example
private static BufferedImage autoCrop(BufferedImage sourceImage) {
int left = 0;
int right = 0;
int top = 0;
int bottom = 0;
boolean firstFind = true;
for (int x = 0; x < sourceImage.getWidth(); x++) {
for (int y = 0; y < sourceImage.getWidth(); y++) {
// pixel is not empty
if (sourceImage.getRGB(x, y) != 0) {
// we walk from left to right, thus x can be applied as left on first finding
if (firstFind) {
left = x;
}
// update right on each finding, because x can grow only
right = x;
// on first find apply y as top
if (firstFind) {
top = y;
} else {
// on each further find apply y to top only if a lower has been found
top = Math.min(top, y);
}
// on first find apply y as bottom
if (bottom == 0) {
bottom = y;
} else {
// on each further find apply y to bottom only if a higher has been found
bottom = Math.max(bottom, y);
}
firstFind = false;
}
}
}
return sourceImage.getSubimage(left, top, right - left, bottom - top);
}

wutzebaer
- 14,365
- 19
- 99
- 170
-2
img is original image source BufferedImage subImg = img.getSubimage(0, 0, img.getWidth() - 1, img.getHeight() - 1);

Diego Ibañez
- 37
- 2