2012-04-20 22 views
46

Mam obrazu, które zmienić rozmiar:Java zmiany rozmiaru obrazu, utrzymać proporcje

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

ten sposób zmienić rozmiar obrazu:

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

Teraz problem jest również potrzebne do utrzymania aspekt stosunek. To znaczy, że potrzebuję nowego obrazu 200/200 do zawarcia nowego obrazu skalowanego. Coś takiego: enter image description here

Próbowałem niektórych rzeczy, ale nie działało zgodnie z oczekiwaniami. Każda pomoc jest doceniana. Wielkie dzięki.

Odpowiedz

70

Zaczynamy:

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

funkcja zwraca nowy rozmiar w zależności od granicy

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

W przypadku gdy ktoś potrzebuje także obraz kodu here is a decent solution zmiany rozmiaru.

Jeśli nie masz pewności co do powyższego rozwiązania, there are different ways, aby osiągnąć ten sam wynik.

+1

Użyłem tej samej logiki, aby zmienić rozmiar bitmap w Androidzie :) –

+2

@Ozzy's odpowiedź jest poprawna z wyjątkiem sytuacji, gdy nie jest wymagane skalowanie (lub bardziej szczegółowo, gdy pierwotna szerokość jest mniejsza niż granica). Inicjowanie 'new_width' i' new_height' do 'original_width' i' original_height' rozwiązuje problem. –

+1

Ta odpowiedź właśnie ułożyła mój dzień. : D –

1

spróbować

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

Przetłumaczone z 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)); 
} 

Można również użyć imgscalr do zmiany rozmiaru obrazów przy zachowaniu proporcji:

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

Wystarczy dodać jeszcze jeden blok kodu Ozzy, tak rzecz wygląda następująco:

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

Dosłownie skopiowałeś pierwszy warunkowy i wkleiłeś go po drugim ... -_- – Zach

0

To jest moje rozwiązanie:

/* 
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

Wszystkie pozostałe odpowiedzi pokazują, jak obliczyć nową wysokość obrazu w zależności od szerokości nowego obrazu lub odwrotnie oraz jak zmienić rozmiar obrazu za pomocą Javy interfejs API obrazu. Dla tych, którzy szukają prostego rozwiązania, zalecam dowolne środowisko przetwarzania obrazu java, które może to zrobić w pojedynczej linii.

exemple poniżej wykorzystuje Marvin Framework:

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

Niezbędne import:

import static marvin.MarvinPluginCollection.* 
0

obraz Load:

BufferedImage bufferedImage = ImageIO.read(file); 

Resize go:

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

Korzystanie Scalr biblioteka:

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

znalazłem wybraną odpowiedź na problemy ze skalowaniem, i tak zrobiłem (jeszcze) innej wersji (które ja testowałem):

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

pisemne Android terminologii :-)

jak dla testów:

@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)); 
} 
Powiązane problemy