Created
February 13, 2025 12:03
-
-
Save asdf913/c8fabd451c994b407fce746fa629767e to your computer and use it in GitHub Desktop.
Chop Image by Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.image.BufferedImage; | |
import java.io.ByteArrayInputStream; | |
import java.io.File; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.nio.file.Files; | |
import java.util.Base64; | |
import java.util.Base64.Decoder; | |
import java.util.Collection; | |
import java.util.function.ObjIntConsumer; | |
import java.util.function.Predicate; | |
import javax.imageio.ImageIO; | |
import org.apache.commons.collections4.IterableUtils; | |
import org.apache.commons.lang3.ObjectUtils; | |
import org.apache.commons.lang3.function.FailableConsumer; | |
import org.d2ab.collection.ints.IntCollection; | |
import org.d2ab.collection.ints.IntList; | |
import org.d2ab.function.ObjIntPredicate; | |
public class ChopImage { | |
public static void main(final String[] args) throws IOException { | |
// | |
final Decoder decoder = Base64.getDecoder(); | |
// | |
final byte[] bs = decoder != null ? decoder.decode( | |
"iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAIAAADzBuo/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCA1LjEuM4y7MyAAAAC2ZVhJZklJKgAIAAAABQAaAQUAAQAAAEoAAAAbAQUAAQAAAFIAAAAoAQMAAQAAAAIAAAAxAQIAEAAAAFoAAABphwQAAQAAAGoAAAAAAAAAYAAAAAEAAABgAAAAAQAAAFBhaW50Lk5FVCA1LjEuMwADAACQBwAEAAAAMDIzMAGgAwABAAAAAQAAAAWgBAABAAAAlAAAAAAAAAACAAEAAgAEAAAAUjk4AAIABwAEAAAAMDEwMAAAAAAOmhdjvMuD8gAAACRJREFUGFdj/P//PwNuAJVmZGSE8OEAIs4E4eACBKTx2s3AAAC16Qv//9Y5UgAAAABJRU5ErkJggg==" | |
.getBytes()) | |
: null; | |
// | |
File file = new File("source.png"); | |
// | |
Files.write(file.toPath(), bs); | |
// | |
try (final InputStream is = new ByteArrayInputStream(bs)) { | |
// | |
BufferedImage bufferedImage = ImageIO.read(is); | |
// | |
System.out.println("source =" + file.getAbsolutePath()); | |
// | |
System.out.println("source.width =" + getWidth(bufferedImage)); | |
// | |
System.out.println("source.height=" + getHeight(bufferedImage)); | |
// | |
ImageIO.write(bufferedImage = chop(bufferedImage), "png", file = new File("result.png")); | |
// | |
System.out.println("result =" + file.getAbsolutePath()); | |
// | |
System.out.println("result.width =" + getWidth(bufferedImage)); | |
// | |
System.out.println("result.height=" + getHeight(bufferedImage)); | |
// | |
} // try | |
// | |
} | |
private static BufferedImage chop(final BufferedImage bi) { | |
// | |
Integer rgb = null; | |
// | |
IntList ilx = null; | |
// | |
IntList ily = null; | |
// | |
final FailableConsumer<IntList, RuntimeException> failableConsumer = a -> { | |
// | |
sortInts(a); | |
// | |
for (int i = IterableUtils.size(a) - 2; i > 0; i--) { | |
// | |
a.remove(i); | |
// | |
} // for | |
// | |
}; | |
// | |
for (int x = 0; x < intValue(getWidth(bi), 0); x++) { | |
// | |
for (int y = 0; y < intValue(getHeight(bi), 0); y++) { | |
// | |
if (rgb == null && bi != null) { | |
// | |
rgb = Integer.valueOf(bi.getRGB(x, y)); | |
// | |
} else if (rgb != null && rgb.intValue() != bi.getRGB(x, y)) { | |
// | |
// ilx | |
// | |
testAndAccept((a, b) -> !contains(a, b), ilx = ObjectUtils.getIfNull(ilx, IntList::create), x, | |
ChopImage::addInt); | |
// | |
testAndAccept(a -> IterableUtils.size(a) > 2, ilx, failableConsumer); | |
// | |
// ily | |
// | |
testAndAccept((a, b) -> !contains(a, b), ily = ObjectUtils.getIfNull(ily, IntList::create), y, | |
ChopImage::addInt); | |
// | |
testAndAccept(a -> IterableUtils.size(a) > 2, ily, failableConsumer); | |
// | |
} // if | |
// | |
} // for | |
// | |
} // for | |
// | |
sortInts(ilx); | |
// | |
sortInts(ily); | |
// | |
final int sizeIlx = IterableUtils.size(ilx); | |
// | |
final int sizeIly = IterableUtils.size(ily); | |
// | |
if (Boolean.logicalAnd(sizeIlx > 1, sizeIly > 1)) { | |
// | |
final int firstX = getInt(ilx, 0, 0); | |
// | |
final int firstY = getInt(ily, 0, 0); | |
// | |
return ObjectUtils.defaultIfNull(getSubimage(bi, firstX, firstY, getInt(ilx, sizeIlx - 1, 0) - firstX + 1, | |
getInt(ily, sizeIly - 1, 0) - firstY + 1), bi); | |
// | |
} // if | |
// | |
return bi; | |
// | |
} | |
private static BufferedImage getSubimage(final BufferedImage instance, final int x, final int y, final int w, | |
final int h) { | |
return instance != null ? instance.getSubimage(x, y, w, h) : null; | |
} | |
private static int getInt(final IntList instance, final int index, final int defaultValue) { | |
return instance != null ? instance.getInt(index) : defaultValue; | |
} | |
private static <T, E extends Throwable> void testAndAccept(final Predicate<T> predicate, final T value, | |
final FailableConsumer<T, E> consumer) throws E { | |
if (predicate != null && predicate.test(value) && consumer != null) { | |
consumer.accept(value); | |
} | |
} | |
private static boolean contains(final Collection<?> items, final Object item) { | |
return items != null && items.contains(item); | |
} | |
private static <T> void testAndAccept(final ObjIntPredicate<T> predicate, final T t, final int i, | |
final ObjIntConsumer<T> consumer) { | |
if (predicate != null && predicate.test(t, i) && consumer != null) { | |
consumer.accept(t, i); | |
} | |
} | |
private static void addInt(final IntCollection a, final int i) { | |
if (a != null) { | |
a.addInt(i); | |
} | |
} | |
private static Integer getHeight(final BufferedImage instance) { | |
return instance != null ? Integer.valueOf(instance.getHeight()) : null; | |
} | |
private static Integer getWidth(final BufferedImage instance) { | |
return instance != null ? Integer.valueOf(instance.getWidth()) : null; | |
} | |
private static int intValue(final Number instance, final int defaultValue) { | |
return instance != null ? instance.intValue() : defaultValue; | |
} | |
private static void sortInts(final IntList instance) { | |
if (instance != null) { | |
instance.sortInts(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --> | |
<dependency> | |
<groupId>org.apache.commons</groupId> | |
<artifactId>commons-collections4</artifactId> | |
<version>4.4</version> | |
</dependency> | |
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> | |
<dependency> | |
<groupId>org.apache.commons</groupId> | |
<artifactId>commons-lang3</artifactId> | |
<version>3.17.0</version> | |
</dependency> | |
<!--https://mvnrepository.com/artifact/org.d2ab/sequence --> | |
<dependency> | |
<groupId>org.d2ab</groupId> | |
<artifactId>sequence</artifactId> | |
<version>2.3.0</version> | |
</dependency> |
Sample Output code
source =C:\source.png
source.width =10
source.height=5
result =C:\result.png
result.width =6
result.height=3
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Read the RGB of the first pixel (x=0,y=0), then first the minimum XY coordinate which has a different RGB value and the maximum XY coordinate. Then chop the image with minimum XY coordinate and maximum XY coordinate.