是否可以通过逐字节创建BufferedImage来阻止BufferedImage抛出OutOfMemoryError异常?
我正在使用此方法裁剪图片:
public static void cropImage(File originalImage, File to, int x1, int y1, int x2, int y2) {
try {
BufferedImage source = ImageIO.read(originalImage);
String mimeType = "image/jpeg";
if (to.getName().endsWith(".png")) {
mimeType = "image/png";
}
if (to.getName().endsWith(".gif")) {
mimeType = "image/gif";
}
int width = x2 - x1;
int height = y2 - y1;
// out
BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Image croppedImage = source.getSubimage(x1, y1, width, height);
Graphics graphics = dest.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
graphics.drawImage(croppedImage, 0, 0, null);
ImageWriter writer = ImageIO.getImageWritersByMIMEType(mimeType).next();
ImageWriteParam params = writer.getDefaultWriteParam();
writer.setOutput(new FileImageOutputStream(to));
IIOImage image = new IIOImage(dest, null, null);
writer.write(null, image, params);
writer.dispose();
source = null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
我的MaxPermSize为512m,如果有人上传了16000x10000图像,我会收到一个OutOfMemoryError:BufferedImage source = ImageIO.read(originalImage);
答案 0 :(得分:0)
这是我的自我解决方案。 现在,当文件上传时,我将检查它是否是图像,获取图像大小而不读取所有文件并检查它是否太大。
public static boolean isImage(String fileName){
Pattern pattern = Pattern.compile("([^\\s]+(\\.(?i)(png|jpg|jpeg|gif|bmp))$)");
Matcher matcher = pattern.matcher(fileName);
return matcher.matches();
}
public static Dimension getImageDimension(File file){
ImageInputStream in = null;
try{
in = ImageIO.createImageInputStream(file);
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
return new Dimension(reader.getWidth(0), reader.getHeight(0));
} catch (IOException e) {
e.printStackTrace();
} finally {
reader.dispose();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public static boolean isImageTooBig(File file){
boolean isImage = isImage(file.getName());
if(!isImage) return false;
Dimension dim = getImageDimension(file);
int maxW = Integer.parseInt((String) Play.configuration.get("app.upload.image.maxW"));
int maxH = Integer.parseInt((String) Play.configuration.get("app.upload.image.maxH"));
if(dim.getWidth() > maxW) return true;
if(dim.getHeight() > maxH) return true;
return false;
}
答案 1 :(得分:0)
如果你总是只对图像的一个小区域感兴趣,你可以通过只加载那个区域来保留一些内存(你可以预先计算大约需要多少内存,以避免在大多数情况下使用OOME): / p>
// Same inputs as your original code
ImageInputStream in = ImageIO.createImageInputStream(originalImage);
BufferedImage source;
try {
Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(x1, y1, width, height);
// Source will be roughly width * height * bytes per pixel
source = reader.read(0, param);
}
finally {
reader.dispose();
}
}
}
finally {
in.close();
}
// Use your old code to store source...