2012-04-20 32 views
46

tengo una imagen que puedo cambiar el tamaño:Java tamaño de imagen, mantener la relación de aspecto

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 puedo cambiar 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 también que necesito para mantener aspecto proporción. Es decir, necesito la nueva imagen 200/200 para contener la nueva imagen a escala. Algo como esto: enter image description here

He intentado algunas cosas, pero no funcionó como se esperaba. Se agradece cualquier ayuda. Muchas gracias.

Respuesta

70

Aquí vamos:

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

función para devolver el nuevo tamaño dependiendo de la frontera

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 necesita cambiar el tamaño de la imagen de código, here is a decent solution.

Si no está seguro acerca de la solución anterior there are different ways para lograr el mismo resultado.

+1

Utilicé la misma lógica para cambiar el tamaño de los mapas de bits en Android :) –

+2

La respuesta de @Ozzy es correcta, excepto cuando no se requiere escala (o más específicamente cuando el ancho original es menor que el límite). La inicialización de 'new_width' y' new_height' to a 'original_width' y' original_height' corrige el problema. –

+1

Esta respuesta acaba de hacer mi día. : D –

1

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

} 

}

3

Traducido del 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 utilizar imgscalr cambiar el tamaño de las imágenes mientras se 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); 
-1

Sólo tiene que añadir una más bloques de código de Ozzy así que lo ve 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); 
} 
+0

Literalmente simplemente copió el primer condicional y lo pegó después del segundo ... -_- – Zach

0

Ésta 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); 
} 
0

Todas las demás respuestas muestran cómo calcular la nueva altura de la imagen en función de la nueva anchura de la imagen o viceversa y cómo cambiar el tamaño de la imagen utilizando Jav una API de imagen. 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 exemple a continuación utiliza 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.* 
0

Cargar imagen:

BufferedImage bufferedImage = ImageIO.read(file); 

cambiar su 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 biblioteca Scalr:

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

he encontrado la respuesta seleccionada a tener problemas con ampliación de la escala, y por lo que he hecho (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 la terminología Android :-)

como para 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)); 
} 
Cuestiones relacionadas