change java image rescale

change - resize bufferedimage java



Cambiar el tamaño de la imagen de Java, mantener la relación de aspecto (10)

Tengo una imagen que cambio de tamaño:

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()); } }

Así es como cambio el tamaño de la imagen:

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; }

Ahora el problema es que también necesito mantener la relación de aspecto. Es decir, necesito la nueva imagen 200/200 para contener la nueva imagen a escala. Algo como esto:

Probé algunas cosas pero no funcionaron como se esperaba. Cualquier ayuda es apreciada. Muchas gracias.


Aquí vamos:

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

Función para devolver el nuevo tamaño según el límite

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); }

En caso de que alguien también necesite el código de cambio de tamaño de la imagen, aquí hay una solución decente .

Si no está seguro acerca de la solución anterior, existen diferentes formas de lograr el mismo resultado.


Cargar imagen:

BufferedImage bufferedImage = ImageIO.read(file);

Cambiar el tamaño:

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; }

Usando la biblioteca Scalr:

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



Esta es mi solución:

/* 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); }


He encontrado que la respuesta seleccionada tiene problemas con la ampliación, por lo que he creado (todavía) otra versión (que he probado):

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); }

Escrito en terminología de Android :-)

en cuanto a las pruebas:

@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)); }


Solo agregue un bloque más al código de Ozzy para que la cosa se vea así:

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); }


Todas las otras respuestas muestran cómo calcular la nueva altura de la imagen en función del ancho de la nueva imagen o viceversa y cómo cambiar el tamaño de la imagen utilizando la API de imagen de Java. Para aquellas personas que buscan una solución directa, recomiendo cualquier marco de procesamiento de imágenes de Java que pueda hacer esto en una sola línea.

El siguiente ejemplo usa Marvin Framework :

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

Importación necesaria:

import static marvin.MarvinPluginCollection.*


Traducido de here :

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)); }

También puede usar imgscalr para cambiar el tamaño de las imágenes mientras mantiene la relación de aspecto:

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);


prueba esto

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); } }

}