常规使用java进行图片裁剪或压缩的时候, 比如使用ImageIO.read()读取图片信息的时候, 或者使用Thumb nails框架进行压缩时, 都会调用DataBufferByte类的下面这个方法:

1
2
3
4
5
6
7
8
9
10
public DataBuffe
rByte(int size, int numBanks) {
super(STABLE, TYPE_BYTE, size, numBanks);
bankdata = new byte[numBanks][];
for (int i= 0; i < numBanks; i++) {
// 构造数组
bankdata[i] = new byte[size];
}
data = bankdata[0];
}

当图片像素很大时, size的值会很大, 此时构造这个数据就有可能会出现oom,比如当一张6.4M的图片, 宽高是5472*7296, size的值是114M。

基于此, 可以基于采样的方式进行, 不需要引用任何第三方库, 具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public static byte[] resize(byte[] srcFileData, int width, int height) {
ImageInputStream input = null;
ImageReader reader = null;
try {
input = ImageIO.createImageInputStream(new ByteArrayInputStream(srcFileData));
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
reader = readers.next();
reader.setInput(input);
//原始图像的长和宽
int srcWidth = reader.getWidth(0);
int srcHeight = reader.getHeight(0);

ImageReadParam param = reader.getDefaultReadParam();
int sampling = Math.min(srcWidth/width, srcHeight/height);
//采样压缩, 其中sampling的值表示每隔多少个像素点取一个像素
param.setSourceSubsampling(sampling, sampling, 0, 0);
// 裁剪
param.setSourceRegion(new Rectangle(0, 0, srcWidth, srcHeight));
BufferedImage bufferedImage = reader.read(0, param);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", outputStream);
return outputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
input.close();
if (reader != null){
reader.dispose();
}
} catch (IOException e) {
e.printStackTrace();
}

}
return new byte[]{};

}