Java如何按指定像素数裁剪/创建非矩形形状图像?
Java中实现非矩形图像裁剪或指定像素区域提取的方法
嘿,我懂你现在的痛点——BufferedImage.getSubimage()确实只能处理矩形/正方形区域,要是想搞非矩形形状,或者精准提取指定的像素集合,得换个路子。下面给你两种实用的实现方案:
方案一:创建带透明通道的非矩形图像(最常用场景)
这种方法的核心是:先创建一个支持透明的BufferedImage(带Alpha通道),然后遍历原图像的像素,把你想要保留的区域(比如圆形、多边形)的像素复制过去,不需要的区域设为完全透明。
举个创建圆形裁剪图像的代码例子:
import java.io.File; import java.io.IOException; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; public class CustomImageCrop { public static void main(String[] args) throws IOException { // 读取原图像 BufferedImage originalImg = ImageIO.read(new File("input.png")); int width = originalImg.getWidth(); int height = originalImg.getHeight(); // 创建带Alpha通道的目标图像(TYPE_INT_ARGB支持透明) BufferedImage croppedImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // 定义圆形的参数:中心坐标和半径 int centerX = width / 2; int centerY = height / 2; int radius = Math.min(width, height) / 2; // 遍历每个像素 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 判断当前像素是否在圆形内 double distanceSq = Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2); if (distanceSq <= Math.pow(radius, 2)) { // 保留原像素 croppedImg.setRGB(x, y, originalImg.getRGB(x, y)); } else { // 设置为完全透明(Alpha通道为0) croppedImg.setRGB(x, y, 0x00000000); } } } // 保存图像(必须用PNG,JPG不支持透明) ImageIO.write(croppedImg, "PNG", new File("circular_crop.png")); } }
你可以把圆形的判断逻辑换成任何你需要的形状——比如多边形的话,就用java.awt.Polygon的contains(x,y)方法来判断像素是否在区域内。
方案二:提取指定像素集合的自定义图像
如果你的需求是精准提取特定坐标的像素(比如不是规则形状,就是零散的像素点),可以先收集这些像素的坐标,然后创建一个刚好能容纳它们的图像,再逐个复制像素:
import java.io.File; import java.io.IOException; import java.awt.image.BufferedImage; import java.util.List; import java.util.ArrayList; import javax.imageio.ImageIO; public class SpecificPixelExtract { public static void main(String[] args) throws IOException { BufferedImage originalImg = ImageIO.read(new File("input.png")); // 假设你已经收集了需要提取的像素坐标(x,y) List<int[]> targetPixels = new ArrayList<>(); targetPixels.add(new int[]{10, 10}); targetPixels.add(new int[]{15, 20}); targetPixels.add(new int[]{30, 5}); // 可以继续添加更多坐标... // 计算目标图像的最小宽高(可选,也可以直接用原图像大小) int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE; int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE; for (int[] pixel : targetPixels) { minX = Math.min(minX, pixel[0]); maxX = Math.max(maxX, pixel[0]); minY = Math.min(minY, pixel[1]); maxY = Math.max(maxY, pixel[1]); } int targetWidth = maxX - minX + 1; int targetHeight = maxY - minY + 1; // 创建带透明通道的目标图像 BufferedImage extractedImg = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); // 复制指定像素到目标图像 for (int[] pixel : targetPixels) { int x = pixel[0] - minX; int y = pixel[1] - minY; extractedImg.setRGB(x, y, originalImg.getRGB(pixel[0], pixel[1])); } // 保存图像 ImageIO.write(extractedImg, "PNG", new File("specific_pixels.png")); } }
一些额外的小提示
- 处理大图像时,直接遍历像素可能有点慢,你可以考虑用
Raster或者BufferedImageOp相关的类来优化性能 - 保存非矩形图像时,一定要选择支持透明的格式(比如PNG),JPG格式会把透明区域变成黑色,达不到预期效果
内容的提问来源于stack exchange,提问作者king amada
相关产品推荐
相关产品推荐

