Java 防止BuffereImage抛出OfMemoryError
是否可以通过逐字节创建BuffereImage来防止BuffereImage抛出内存错误异常 我正在使用此方法裁剪图像:Java 防止BuffereImage抛出OfMemoryError,java,out-of-memory,bufferedimage,Java,Out Of Memory,Bufferedimage,是否可以通过逐字节创建BuffereImage来防止BuffereImage抛出内存错误异常 我正在使用此方法裁剪图像: public static void cropImage(File originalImage, File to, int x1, int y1, int x2, int y2) { try { BufferedImage source = ImageIO.read(originalImage); String mimeType =
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,如果有人上传16000x1000图像,我将在以下位置收到OutOfMemoryError:BuffereImage source=ImageIO.read(originalImage)代码>这里是我的自我解决方案。
现在,当上传一个文件时,我会检查它是否是一个图像,在不读取所有文件的情况下获取图像大小,并检查它是否太大
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;
}
公共静态布尔isImage(字符串文件名){
Pattern Pattern=Pattern.compile(([^\\s]+(\\.(?i)(png | jpg | jpeg | gif | bmp))$);
Matcher Matcher=pattern.Matcher(文件名);
返回matcher.matches();
}
公共静态维度getImageDimension(文件){
ImageInputStream in=null;
试一试{
in=ImageIO.createImageInputStream(文件);
最终迭代器读取器=ImageIO.getImageReaders(in);
if(readers.hasNext()){
ImageReader=readers.next();
试一试{
reader.setInput(in);
返回新维度(reader.getWidth(0)、reader.getHeight(0));
}捕获(IOE异常){
e、 printStackTrace();
}最后{
reader.dispose();
}
}
}捕获(IOE异常){
e、 printStackTrace();
}最后{
如果(in!=null),请尝试{
in.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
返回null;
}
公共静态布尔值isImageTooBig(文件){
布尔isImage=isImage(file.getName());
如果(!isImage)返回false;
维度dim=getImageDimension(文件);
intmaxw=Integer.parseInt((String)Play.configuration.get(“app.upload.image.maxW”);
intmaxh=Integer.parseInt((String)Play.configuration.get(“app.upload.image.maxH”);
if(dim.getWidth()>maxW)返回true;
if(dim.getHeight()>maxH)返回true;
返回false;
}
如果您总是只对图像的一小部分感兴趣,您可以通过仅加载该区域来保留一些内存(您可以提前大致计算需要多少内存,以避免在大多数情况下出现OOME):
//输入与原始代码相同
ImageInputStream in=ImageIO.createImageInputStream(原始图像);
缓冲图像源;
试一试{
迭代器读卡器=ImageIO.getImageReaders(in);
if(readers.hasNext()){
ImageReader=readers.next();
试一试{
reader.setInput(in);
ImageReadParam param=reader.getDefaultReadParam();
参数设置震源区(x1,y1,宽度,高度);
//源大约为每像素的宽度*高度*字节
source=reader.read(0,参数);
}
最后{
reader.dispose();
}
}
}
最后{
in.close();
}
//使用旧代码存储源代码。。。
PS:永久发电机的大小通常与您看到的OOME没有多大关系。映像数据是在堆上分配的,因此您需要增加堆大小(-Xmx512m例如)。我需要完整映像和缩略图为什么?你问题中的代码总是在阅读后裁剪图像。这将创建与裁剪相同的结果,内存减少(至少50%),因为我有一个图库,可以显示裁剪后的缩略图,还有一个页面可以显示完整的图像。
// 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...