Java图像resize,保持纵横比

我有一个我resize的图像:

if((width != null) || (height != null)) { try{ // scale image on disk BufferedImage originalImage = ImageIO.read(file); int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType(); BufferedImage resizeImageJpg = resizeImage(originalImage, type, 200, 200); ImageIO.write(resizeImageJpg, "jpg", file); } catch(IOException e) { System.out.println(e.getMessage()); } } 

这是我调整图像的方式:

 private static BufferedImage resizeImage(BufferedImage originalImage, int type, Integer img_width, Integer img_height) { BufferedImage resizedImage = new BufferedImage(img_width, img_height, type); Graphics2D g = resizedImage.createGraphics(); g.drawImage(originalImage, 0, 0, img_width, img_height, null); g.dispose(); return resizedImage; } 

现在的问题是我也需要保持宽高比。 也就是说,我需要新的200/200图像来包含缩放后的新图像。 像这样的东西: 在这里输入图像说明

我尝试了一些东西,但没有按预期工作。 任何帮助表示赞赏。 非常感谢。

开始了:

 Dimension imgSize = new Dimension(500, 100); Dimension boundary = new Dimension(200, 200); 

函数根据边界返回新的大小

 public static Dimension getScaledDimension(Dimension imgSize, Dimension boundary) { int original_width = imgSize.width; int original_height = imgSize.height; int bound_width = boundary.width; int bound_height = boundary.height; int new_width = original_width; int new_height = original_height; // first check if we need to scale width if (original_width > bound_width) { //scale width to fit new_width = bound_width; //scale height to maintain aspect ratio new_height = (new_width * original_height) / original_width; } // then check if we need to scale even with the new height if (new_height > bound_height) { //scale height to fit instead new_height = bound_height; //scale width to maintain aspect ratio new_width = (new_height * original_width) / original_height; } return new Dimension(new_width, new_height); } 

如果任何人还需要图像resize的代码, 这是一个体面的解决scheme 。

如果您不确定上述解决scheme,有不同的方法可以达到相同的结果。

你会想看看这个答案Image.getScaledInstance() ,和更多: 如何提高g.drawImage()方法调整图像的性能

翻译从这里 :

 Dimension getScaledDimension(Dimension imageSize, Dimension boundary) { double widthRatio = boundary.getWidth() / imageSize.getWidth(); double heightRatio = boundary.getHeight() / imageSize.getHeight(); double ratio = Math.min(widthRatio, heightRatio); return new Dimension((int) (imageSize.width * ratio), (int) (imageSize.height * ratio)); } 

您还可以使用imgscalr调整图像大小,同时保持宽高比:

 BufferedImage resizeMe = ImageIO.read(new File("orig.jpg")); Dimension newMaxSize = new Dimension(255, 255); BufferedImage resizedImg = Scalr.resize(resizeMe, Method.QUALITY, newMaxSize.width, newMaxSize.height); 

尝试这个

 float rateX = (float)jpDisplayImagen.getWidth()/(float)img.getWidth(); float rateY = (float)jpDisplayImagen.getHeight()/(float)img.getHeight(); if (rateX>rateY){ int W=(int)(img.getWidth()*rateY); int H=(int)(img.getHeight()*rateY); jpDisplayImagen.getGraphics().drawImage(img, 0, 0,W,H, null); } else{ int W=(int)(img.getWidth()*rateX); int H=(int)(img.getHeight()*rateX); jpDisplayImagen.getGraphics().drawImage(img, 0, 0,W,H, null); } 
 public class ImageTransformation { public static final String PNG = "png"; public static byte[] resize(FileItem fileItem, int width, int height) { try { ResampleOp resampleOp = new ResampleOp(width, height); BufferedImage scaledImage = resampleOp.filter(ImageIO.read(fileItem.getInputStream()), null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(scaledImage, PNG, baos); return baos.toByteArray(); } catch (Exception ex) { throw new MapsException("An error occured during image resizing.", ex); } } public static byte[] resizeAdjustMax(FileItem fileItem, int maxWidth, int maxHeight) { try { BufferedInputStream bis = new BufferedInputStream(fileItem.getInputStream()); BufferedImage bufimg = ImageIO.read(bis); //check size of image int img_width = bufimg.getWidth(); int img_height = bufimg.getHeight(); if(img_width > maxWidth || img_height > maxHeight) { float factx = (float) img_width / maxWidth; float facty = (float) img_height / maxHeight; float fact = (factx>facty) ? factx : facty; img_width = (int) ((int) img_width / fact); img_height = (int) ((int) img_height / fact); } return resize(fileItem,img_width, img_height); } catch (Exception ex) { throw new MapsException("An error occured during image resizing.", ex); } } 

}

这是我的解决scheme:

 /* Change dimension of Image */ public static Image resizeImage(Image image, int scaledWidth, int scaledHeight, boolean preserveRatio) { if (preserveRatio) { double imageHeight = image.getHeight(); double imageWidth = image.getWidth(); if (imageHeight/scaledHeight > imageWidth/scaledWidth) { scaledWidth = (int) (scaledHeight * imageWidth / imageHeight); } else { scaledHeight = (int) (scaledWidth * imageHeight / imageWidth); } } BufferedImage inputBufImage = SwingFXUtils.fromFXImage(image, null); // creates output image BufferedImage outputBufImage = new BufferedImage(scaledWidth, scaledHeight, inputBufImage.getType()); // scales the input image to the output image Graphics2D g2d = outputBufImage.createGraphics(); g2d.drawImage(inputBufImage, 0, 0, scaledWidth, scaledHeight, null); g2d.dispose(); return SwingFXUtils.toFXImage(outputBufImage, null); } 

所有其他答案显示了如何计算新图像宽度的新图像高度,反之亦然,以及如何使用Java Image API调整图像大小。 对于那些正在寻找一个简单的解决scheme的人,我推荐任何一个可以在一行中完成的Javaimage processing框架。

下面的例子使用Marvin框架 :

 // 300 is the new width. The height is calculated to maintain aspect. scale(image.clone(), image, 300); 

必要的import:

 import static marvin.MarvinPluginCollection.* 

加载图片:

 BufferedImage bufferedImage = ImageIO.read(file); 

调整它的大小:

 private BufferedImage resizeAndCrop(BufferedImage bufferedImage, Integer width, Integer height) { Mode mode = (double) width / (double) height >= (double) bufferedImage.getWidth() / (double) bufferedImage.getHeight() ? Scalr.Mode.FIT_TO_WIDTH : Scalr.Mode.FIT_TO_HEIGHT; bufferedImage = Scalr.resize(bufferedImage, Scalr.Method.ULTRA_QUALITY, mode, width, height); int x = 0; int y = 0; if (mode == Scalr.Mode.FIT_TO_WIDTH) { y = (bufferedImage.getHeight() - height) / 2; } else if (mode == Scalr.Mode.FIT_TO_HEIGHT) { x = (bufferedImage.getWidth() - width) / 2; } bufferedImage = Scalr.crop(bufferedImage, x, y, width, height); return bufferedImage; } 

使用Scalr库:

 <dependency> <groupId>org.imgscalr</groupId> <artifactId>imgscalr-lib</artifactId> <version>4.2</version> </dependency> 

我发现选定的答案在升级方面有问题,所以我已经制作了另一个版本(我已经testing过):

 public static Point scaleFit(Point src, Point bounds) { int newWidth = src.x; int newHeight = src.y; double boundsAspectRatio = bounds.y / (double) bounds.x; double srcAspectRatio = src.y / (double) src.x; // first check if we need to scale width if (boundsAspectRatio < srcAspectRatio) { // scale width to fit newWidth = bounds.x; //scale height to maintain aspect ratio newHeight = (newWidth * src.y) / src.x; } else { //scale height to fit instead newHeight = bounds.y; //scale width to maintain aspect ratio newWidth = (newHeight * src.x) / src.y; } return new Point(newWidth, newHeight); } 

用Android术语撰写:-)

至于testing:

 @Test public void scaleFit() throws Exception { final Point displaySize = new Point(1080, 1920); assertEquals(displaySize, Util.scaleFit(displaySize, displaySize)); assertEquals(displaySize, Util.scaleFit(new Point(displaySize.x / 2, displaySize.y / 2), displaySize)); assertEquals(displaySize, Util.scaleFit(new Point(displaySize.x * 2, displaySize.y * 2), displaySize)); assertEquals(new Point(displaySize.x, displaySize.y * 2), Util.scaleFit(new Point(displaySize.x / 2, displaySize.y), displaySize)); assertEquals(new Point(displaySize.x * 2, displaySize.y), Util.scaleFit(new Point(displaySize.x, displaySize.y / 2), displaySize)); assertEquals(new Point(displaySize.x, displaySize.y * 3 / 2), Util.scaleFit(new Point(displaySize.x / 3, displaySize.y / 2), displaySize)); } 

只需添加一个块到Ozzy的代码,所以事情看起来像这样:

 public static Dimension getScaledDimension(Dimension imgSize,Dimension boundary) { int original_width = imgSize.width; int original_height = imgSize.height; int bound_width = boundary.width; int bound_height = boundary.height; int new_width = original_width; int new_height = original_height; // first check if we need to scale width if (original_width > bound_width) { //scale width to fit new_width = bound_width; //scale height to maintain aspect ratio new_height = (new_width * original_height) / original_width; } // then check if we need to scale even with the new height if (new_height > bound_height) { //scale height to fit instead new_height = bound_height; //scale width to maintain aspect ratio new_width = (new_height * original_width) / original_height; } // upscale if original is smaller if (original_width < bound_width) { //scale width to fit new_width = bound_width; //scale height to maintain aspect ratio new_height = (new_width * original_height) / original_width; } return new Dimension(new_width, new_height); }