Issue
I have a question regarding cutting the blank space in image (or just croping it). I want to have a method like this:
public BufferedImage crop(BufferedImage input) {
return output;
}
And it should do this:
href="https://i.stack.imgur.com/IGTRS.png" rel="nofollow noreferrer">
I know that I could go through all the pixels to get new bounds, but for exapmle with image 1024x768 I would have to go through 1024*768 = 786432 (times 2 because I must go through first time to get height bounds and second time to get width bounds) pixels. And this is not a good way. Is there any ideas how to do this quickly? (I don't want to use neihter any additional threads nor any additional frameworks if this is possible)
Thank you!
Solution
I was thinking a lot and came up with this method how to do this.
public static BufferedImage crop(BufferedImage image) {
int minY = 0, maxY = 0, minX = Integer.MAX_VALUE, maxX = 0;
boolean isBlank, minYIsDefined = false;
Raster raster = image.getRaster();
for (int y = 0; y < image.getHeight(); y++) {
isBlank = true;
for (int x = 0; x < image.getWidth(); x++) {
//Change condition to (raster.getSample(x, y, 3) != 0)
//for better performance
if (raster.getPixel(x, y, (int[]) null)[3] != 0) {
isBlank = false;
if (x < minX) minX = x;
if (x > maxX) maxX = x;
}
}
if (!isBlank) {
if (!minYIsDefined) {
minY = y;
minYIsDefined = true;
} else {
if (y > maxY) maxY = y;
}
}
}
return image.getSubimage(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
This method works only with alpha. To work with "jpg" you need to change the condition here (true here means that current pixel is not blank):
if (raster.getPixel(x, y, (int[]) null)[3] != 0)
I was surpirsed but this method works very fast (to crop an 1024x768 image it tooks 70-100 milliseconds). Also I tested it on 5000x5000 image and unfortunately this method was very slow in this case (1000-1500 milliseconds).
It divides an image into vertical lines for each y-coordinate. Then it looks for not blank pixel in this line. If not blank pixel wasn't found it goes to the next line, but if it was found it looks for minX and maxX. Also if minY wasn't defined yet it defines it and bool "minYIsDefined" makes true. But if minY was defined already it defines maxY.
EDIT:
As was suggested in coments (thx FiReTiTi), with using 'getSample()' method we can go even faster. It's because 'getPixel()' method uses 'getSample()' method to make it's array 3-4 times (depends on image type). So the new condition will looke like this:
if (raster.getSample(x, y, 3) != 0)
My tests showed that the time that was taken for croping 1024x768 image was 10-30 ms. In cases with 5000x5000 image time was 100-300 ms.
Hope it will help someone :)
Answered By - GV_FiQst
Answer Checked By - Terry (JavaFixing Volunteer)