缓冲图像调整大小

55

我想调整一个缓冲图像的大小。我已经成功地将其存储并在jframe上显示,但是似乎无法调整其大小。您有什么提示可以帮助我解决这个问题并将图像显示为一个200x200的文件呢?

private void profPic(){
    String path = factory.getString("bottle");
    BufferedImage img = ImageIO.read(new File(path));
}


public static BufferedImage resize(BufferedImage img, int newW, int newH) {  
    int w = img.getWidth();  
    int h = img.getHeight();  
    BufferedImage dimg = new BufferedImage(newW, newH, img.getType());  
    Graphics2D g = dimg.createGraphics();  
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);  
    g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);  
    g.dispose();  
    return dimg;  
}  
7个回答

80

更新的答案

我不记得为什么我的原始答案有效,但在另一个环境中测试后,我同意,原来被接受的答案不起作用(我也不记得当时为什么说它有效)。而这个,则可以起作用:

public static BufferedImage resize(BufferedImage img, int newW, int newH) { 
    Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
    BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2d = dimg.createGraphics();
    g2d.drawImage(tmp, 0, 0, null);
    g2d.dispose();

    return dimg;
}  

3
无法编译 - getScaledInstance返回的是Image而不是BufferedImage。 - I82Much
7
仍不安全 - 在我的Macbook上,例如,我遇到了一个ClassCastException - 这不是一种保证的转换。 - I82Much
4
"Write once, run anywhere"(一次编写,到处运行)......咳咳。 - TEK
2
为什么这被列为正确答案,而它却不起作用? - Jeremy
8
为什么要使用TYPE_INT_ARGB而不是img.getType() - ADTC
显示剩余5条评论

22
如果只需在resize方法中调整BufferedImage的大小,那么Thumbnailator库可以相当容易地完成此操作。
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
  return Thumbnails.of(img).size(newW, newH).asBufferedImage();
}

以上代码将重置img以适应newWnewH的尺寸,同时保持原始图像的长宽比。

如果不需要保持长宽比并且需要精确调整到给定尺寸,则可以使用forceSize方法代替size方法:

public static BufferedImage resize(BufferedImage img, int newW, int newH) {
  return Thumbnails.of(img).forceSize(newW, newH).asBufferedImage();
}

使用Image.getScaledInstance方法无法保证调整大小后的图像仍然保持原始图像的宽高比,而且通常速度非常慢。
Thumbnailator使用一种逐步调整图像大小的技术,其速度可以比Image.getScaledInstance快数倍,同时达到了通常相当的图像质量。
免责声明:我是这个库的维护者。

Thumbnailator 太棒了! - java developer

5

这里有一些用于调整缓冲图像大小的代码,简单快捷:

public static BufferedImage scale(BufferedImage src, int w, int h)
{
    BufferedImage img = 
            new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    int x, y;
    int ww = src.getWidth();
    int hh = src.getHeight();
    int[] ys = new int[h];
    for (y = 0; y < h; y++)
        ys[y] = y * hh / h;
    for (x = 0; x < w; x++) {
        int newX = x * ww / w;
        for (y = 0; y < h; y++) {
            int col = src.getRGB(newX, ys[y]);
            img.setRGB(x, y, col);
        }
    }
    return img;
}

很棒的方法,但比例不正确,当我将高度因子除以根号二时,它就正常工作了.. =) - nyx00

4

这个类会从一个文件中调整大小并获取格式名称:

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import org.apache.commons.io.IOUtils;

public class ImageResizer {

public static void main(String as[]) throws IOException{

    File f = new File("C:/Users/samsungrob/Desktop/shuttle.jpg");

    byte[] ba = resize(f, 600, 600);

    IOUtils.write(ba, new FileOutputStream( new File("C:/Users/samsungrob/Desktop/shuttle_resized.jpg") ) );

}




public static byte[] resize(File file,
                            int maxWidth, int maxHeight) throws IOException{
    int scaledWidth = 0, scaledHeight = 0;

    BufferedImage img = ImageIO.read((ImageInputStream) file );

    scaledWidth = maxWidth;
    scaledHeight = (int) (img.getHeight() * ( (double) scaledWidth / img.getWidth() ));

    if (scaledHeight> maxHeight) {
        scaledHeight = maxHeight;
        scaledWidth= (int) (img.getWidth() * ( (double) scaledHeight/ img.getHeight() ));

        if (scaledWidth > maxWidth) {
            scaledWidth = maxWidth;
            scaledHeight = maxHeight;
        }
    }

    Image resized =  img.getScaledInstance( scaledWidth, scaledHeight, Image.SCALE_SMOOTH);

    BufferedImage buffered = new BufferedImage(scaledWidth, scaledHeight, Image.SCALE_REPLICATE);

    buffered.getGraphics().drawImage(resized, 0, 0 , null);

    String formatName = getFormatName( file ) ;

    ByteArrayOutputStream out = new ByteArrayOutputStream();

    ImageIO.write(buffered,
            formatName,
            out);

    return out.toByteArray();
}


private static String getFormatName(ImageInputStream iis) {
    try { 

        // Find all image readers that recognize the image format
        Iterator iter = ImageIO.getImageReaders(iis);
        if (!iter.hasNext()) {
            // No readers found
            return null;
        }

        // Use the first reader
        ImageReader reader = (ImageReader)iter.next();

        // Close stream
        iis.close();

        // Return the format name
        return reader.getFormatName();
    } catch (IOException e) {
    }

    return null;
}

private static String getFormatName(File file) throws IOException {
    return getFormatName( ImageIO.createImageInputStream(file) );
}

private static String getFormatName(InputStream is) throws IOException {
    return getFormatName( ImageIO.createImageInputStream(is) );
}

}


4

这是imgscalr实际发生的缩短版,如果你只想使用“平衡”的平滑处理:

/**
 * Takes a BufferedImage and resizes it according to the provided targetSize
 *
 * @param src the source BufferedImage
 * @param targetSize maximum height (if portrait) or width (if landscape)
 * @return a resized version of the provided BufferedImage
 */
private BufferedImage resize(BufferedImage src, int targetSize) {
    if (targetSize <= 0) {
        return src; //this can't be resized
    }
    int targetWidth = targetSize;
    int targetHeight = targetSize;
    float ratio = ((float) src.getHeight() / (float) src.getWidth());
    if (ratio <= 1) { //square or landscape-oriented image
        targetHeight = (int) Math.ceil((float) targetWidth * ratio);
    } else { //portrait image
        targetWidth = Math.round((float) targetHeight / ratio);
    }
    BufferedImage bi = new BufferedImage(targetWidth, targetHeight, src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = bi.createGraphics();
    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); //produces a balanced resizing (fast and decent quality)
    g2d.drawImage(src, 0, 0, targetWidth, targetHeight, null);
    g2d.dispose();
    return bi;
}

3
试试imgscalr库。我找到的最好的库-非常快速,质量好,使用简单。
BufferedImage thumbnail = Scalr.resize(image, 150);

https://github.com/rkalla/imgscalr

Apache 2 许可证

1
谢谢!完美运行! - Harsha
1
那个链接通向各种可疑的互联网位置。答案很不错。 ;) - Pineechio
我会更新我的回答,但是你的评论给了我太多的快乐^^ <3 所以我认为这是正确的链接:https://github.com/rkalla/imgscalr - Alexander Sidikov Pfeif

1

看这个,它会有所帮助:

BufferedImage bImage = ImageIO.read(new File(C:\image.jpg);

BufferedImage thumbnail = Scalr.resize(bImage,  Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH,
                                       750, 150, Scalr.OP_ANTIALIAS);

1
只是补充一下,这是Imgscalr库 -> https://mvnrepository.com/artifact/org.imgscalr/imgscalr-lib - RichardK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接