如何用Java中的JPEG创建缩略图?

时间:2009-07-01 13:19:15

标签: java image jpeg

有人可以帮助我们使用一些代码来为Java创建JPEG缩略图。

我是新手,所以一步一步的解释将不胜感激。

14 个答案:

答案 0 :(得分:69)

Image img = ImageIO.read(new File("test.jpg")).getScaledInstance(100, 100, BufferedImage.SCALE_SMOOTH);

这将创建一个100x100像素的缩略图作为Image对象。如果要将其写回磁盘,只需将代码转换为:

BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
img.createGraphics().drawImage(ImageIO.read(new File("test.jpg")).getScaledInstance(100, 100, Image.SCALE_SMOOTH),0,0,null);
ImageIO.write(img, "jpg", new File("test_thumb.jpg"));

此外,如果您担心速度问题(如果您想缩放许多图像,上述方法相当慢)请使用以下方法和声明:

private BufferedImage scale(BufferedImage source,double ratio) {
  int w = (int) (source.getWidth() * ratio);
  int h = (int) (source.getHeight() * ratio);
  BufferedImage bi = getCompatibleImage(w, h);
  Graphics2D g2d = bi.createGraphics();
  double xScale = (double) w / source.getWidth();
  double yScale = (double) h / source.getHeight();
  AffineTransform at = AffineTransform.getScaleInstance(xScale,yScale);
  g2d.drawRenderedImage(source, at);
  g2d.dispose();
  return bi;
}

private BufferedImage getCompatibleImage(int w, int h) {
  GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
  GraphicsDevice gd = ge.getDefaultScreenDevice();
  GraphicsConfiguration gc = gd.getDefaultConfiguration();
  BufferedImage image = gc.createCompatibleImage(w, h);
  return image;
}

然后致电:

BufferedImage scaled = scale(img,0.5);

其中0.5是比例,img是包含正常大小图像的BufferedImage。

答案 1 :(得分:31)

你可能已经发现“简单”和“好看的结果”是两个非常不同的东西。我已将这两个要求封装成一个非常简单的java image scaling library(Apache 2许可证),它可以为您完成一切。

创建缩略图的示例代码如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 150);

您的图像比例很受尊重,图书馆根据图像因缩放(FASTEST,BALANCED或QUALITY)而发生的变化量,最佳地猜测它应该使用的方法,并且最佳支持的Java2D图像类型总是如此用于进行缩放以避免出现“黑色”结果或看起来非常糟糕的输出(例如过度抖动的GIF图像)。

另外,如果您想强制它在Java中输出最好看的缩略图,那么API调用将如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

库不仅会使用Java2D推荐的增量缩放来为您提供最佳效果,还会对缩略图(带有非常微调的内核的ConvolveOp)应用可选的抗锯齿效果。稍微柔化像素值之间的过渡,使缩略图看起来更均匀,不会像从非常大的图像变为非常小的图像时看到的那样锐利或罂粟。

您可以阅读库中的所有注释(代码本身是大量文档),以查看解决的所有不同JDK错误或为提高性能或内存使用而进行的优化。我花了很多时间来调整这个实现,并且从在Web应用程序和其他Java项目中部署它的人那里获得了很多很好的反馈。

答案 2 :(得分:12)

这是创建100 X 100缩略图的简单方法,图像中没有任何拉伸或歪斜。

private  void saveScaledImage(String filePath,String outputFile){
    try {

        BufferedImage sourceImage = ImageIO.read(new File(filePath));
        int width = sourceImage.getWidth();
        int height = sourceImage.getHeight();

        if(width>height){
            float extraSize=    height-100;
            float percentHight = (extraSize/height)*100;
            float percentWidth = width - ((width/100)*percentHight);
            BufferedImage img = new BufferedImage((int)percentWidth, 100, BufferedImage.TYPE_INT_RGB);
            Image scaledImage = sourceImage.getScaledInstance((int)percentWidth, 100, Image.SCALE_SMOOTH);
            img.createGraphics().drawImage(scaledImage, 0, 0, null);
            BufferedImage img2 = new BufferedImage(100, 100 ,BufferedImage.TYPE_INT_RGB);
            img2 = img.getSubimage((int)((percentWidth-100)/2), 0, 100, 100);

            ImageIO.write(img2, "jpg", new File(outputFile));    
        }else{
            float extraSize=    width-100;
            float percentWidth = (extraSize/width)*100;
            float  percentHight = height - ((height/100)*percentWidth);
            BufferedImage img = new BufferedImage(100, (int)percentHight, BufferedImage.TYPE_INT_RGB);
            Image scaledImage = sourceImage.getScaledInstance(100,(int)percentHight, Image.SCALE_SMOOTH);
            img.createGraphics().drawImage(scaledImage, 0, 0, null);
            BufferedImage img2 = new BufferedImage(100, 100 ,BufferedImage.TYPE_INT_RGB);
            img2 = img.getSubimage(0, (int)((percentHight-100)/2), 100, 100);

            ImageIO.write(img2, "jpg", new File(outputFile));
        }

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

答案 3 :(得分:4)

JMagick库(以及Java中ImageMagick的实现)将满足您的需求。

答案 4 :(得分:3)

上面的Java代码(使用scale / getCompatibleImage方法)对我很有用,但是当我部署到服务器时,它停止工作,因为服务器没有与之关联的显示 - 其他任何有此问题的人都可以修复它通过使用:     BufferedImage bi = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);

而不是   BufferedImage bi = getCompatibleImage(w,h);

并删除getCompatibleImage方法

(后来注意 - 事实证明这适用于大多数图像,但我从公司营销部门获得了一堆32位颜色深度的jpeg图像,并且该库为所有这些图像抛出了不受支持的图像格式异常:( - imagemagick / jmagick开始看起来更有吸引力)

答案 5 :(得分:2)

我用过Thumbnailator!它用两行代码解决了我的问题。

https://github.com/coobird/thumbnailator

答案 6 :(得分:2)

我知道这是一篇很老的帖子。我一直在寻找生成缩略图的解决方案,所以最终使用此

Thumbnails.of(originalImage).scale(0.25).asBufferedImage();

如果您使用移动设备,建议将比例设置为0.45

Thumbnails.of(originalImage).scale(0.45).asBufferedImage();

https://github.com/coobird/thumbnailator

使用Graphics2D肯定要快得多,因为测试了这两个选项。

答案 7 :(得分:1)

我创建了一个名为fotovault(sourceforge.net)的应用程序,它可以使用imagej apis上传图像并在java中创建缩略图。

请阅读我的博客

http://www.gingercart.com/Home/java-snippets/create-image-thumbnail-in-java-using-imagej-api

答案 8 :(得分:1)

我已经浏览了一个博客,根据该博客您有以下选项 -

  1. 对于简单的RGB文件,请使用ImageScalr。 ImageIO类用于读取文件,ImageScalr用于创建缩略图
  2. 要支持RGB + CYMK,请使用ImageIO和JAI(Java Advanced Imaging)API读取文件,使用ImageScalr创建缩略图。
  3. 如果您不知道要处理的文件格式,颜色模式,最安全的选择是使用ImageMagick。
  4. 以下是link,它提供了代码段的完整答案。

答案 9 :(得分:1)

有许多图像处理框架可供您使用,只需几行即可。下面的示例使用Marvin Framework以不同的分辨率(给定宽度作为参考)生成缩略图。这三个缩略图是在 92 ms 中生成的。

<强>输入

enter image description here

<强>输出:

enter image description here

enter image description here

enter image description here

import static marvin.MarvinPluginCollection.*;

MarvinImage image = MarvinImageIO.loadImage("./res/input.jpg");
MarvinImage scaledImage = new MarvinImage(1,1);

scale(image, scaledImage, 250);
MarvinImageIO.saveImage(scaledImage, "./res/output_x250.jpg");

scale(image, scaledImage, 150);
MarvinImageIO.saveImage(scaledImage, "./res/output_x150.jpg");

scale(image, scaledImage, 50);
MarvinImageIO.saveImage(scaledImage, "./res/output_x50.jpg");

答案 10 :(得分:1)

无需拉伸或库创建缩略图的简单方法。也适用于png中的透明度。

public File createThumbnail(String imageUrl, String targetPath) {
    final int imageSize = 100;
    File thumbnail = new File(targetPath);

    try {
        thumbnail.getParentFile().mkdirs();
        thumbnail.createNewFile();
        BufferedImage sourceImage = ImageIO.read(new File(imageUrl));
        float width = sourceImage.getWidth();
        float height = sourceImage.getHeight();

        BufferedImage img2;
        if (width > height) {
            float scaledWidth = (width / height) * (float) imageSize;
            float scaledHeight = imageSize;

            BufferedImage img = new BufferedImage((int) scaledWidth, (int) scaledHeight, sourceImage.getType());
            Image scaledImage = sourceImage.getScaledInstance((int) scaledWidth, (int) scaledHeight, Image.SCALE_SMOOTH);
            img.createGraphics().drawImage(scaledImage, 0, 0, null);

            int offset = (int) ((scaledWidth - scaledHeight) / 2f);
            img2 = img.getSubimage(offset, 0, imageSize, imageSize);
        }
        else if (width < height) {
            float scaledWidth = imageSize;
            float scaledHeight = (height / width) * (float) imageSize;

            BufferedImage img = new BufferedImage((int) scaledWidth, (int) scaledHeight, sourceImage.getType());
            Image scaledImage = sourceImage.getScaledInstance((int) scaledWidth, (int) scaledHeight, Image.SCALE_SMOOTH);
            img.createGraphics().drawImage(scaledImage, 0, 0, null);

            int offset = (int) ((scaledHeight - scaledWidth) / 2f);
            img2 = img.getSubimage(0, offset, imageSize, imageSize);
        }
        else {
            img2 = new BufferedImage(imageSize, imageSize, sourceImage.getType());
            Image scaledImage = sourceImage.getScaledInstance(imageSize, imageSize, Image.SCALE_SMOOTH);
            img2.createGraphics().drawImage(scaledImage, 0, 0, null);
        }
        ImageIO.write(img2, "png", thumbnail);
    }
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return thumbnail;
}

答案 11 :(得分:1)

几年前,我使用JAI编写了一个带有静态方法的util类。 Java Advanced Imaging API是Java中用于处理图像的最可靠的API。它的矢量插值在Java世界中最接近Photoshop。这是其中之一:

public static ByteArrayOutputStream resize(InputStream inputStream , int IMG_WIDTH,
        int IMG_HEIGHT) throws Exception {
    BufferedImage originalImage = ImageIO.read(inputStream);
    int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB
            : originalImage.getType();
    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();
        g.setComposite(AlphaComposite.Src);

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
    }
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ImageIO.write(resizedImage, "png", bos);
    return bos;

} 

答案 12 :(得分:0)

也许最简单的方法是:

static public BufferedImage scaleImage(BufferedImage image, int max_width, int max_height) {
    int img_width = image.getWidth();
    int img_height = image.getHeight();

    float horizontal_ratio = 1;
    float vertical_ratio    = 1;


    if(img_height > max_height) {
        vertical_ratio = (float)max_height / (float)img_height;
    }
    if(img_width > max_width) {
        horizontal_ratio = (float)max_width / (float)img_width;
    }

    float scale_ratio = 1;

    if (vertical_ratio < horizontal_ratio) {
        scale_ratio = vertical_ratio;
    }
    else if (horizontal_ratio < vertical_ratio) {
        scale_ratio = horizontal_ratio;
    }

    int dest_width  = (int) (img_width * scale_ratio);
    int dest_height = (int) (img_height * scale_ratio);

    BufferedImage scaled = new BufferedImage(dest_width, dest_height, image.getType());
    Graphics graphics = scaled.getGraphics();
    graphics.drawImage(image, 0, 0, dest_width, dest_height, null);
    graphics.dispose();

    return scaled;

}

答案 13 :(得分:0)

当您想从非方形源创建方形 (75x75) 缩略图时的解决方案。

下面的代码首先使用比调整方形图像更小的尺寸将原始图像裁剪为方形。

public static void generateThumbnailWithCrop(String imgPath, String thumbnailPath, int size) throws IOException {
    BufferedImage sourceImage = ImageIO.read(new File(imgPath));
    int width = sourceImage.getWidth();
    int height = sourceImage.getHeight();
    int smallerSize = width > height ? height : width;
    BufferedImage quadrateImage = cropToQuadrate(sourceImage, smallerSize);
    int type = quadrateImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : quadrateImage.getType();
    BufferedImage resizedImage = resizeImageWithHint(quadrateImage, type, size, size);
    File thumb = new File(thumbnailPath);
    thumb.getParentFile().mkdirs();
    ImageIO.write(resizedImage, "jpg", thumb);
}

private static BufferedImage cropToQuadrate(BufferedImage sourceImage, int size) {
    BufferedImage img = sourceImage.getSubimage(0, 0, size, size);
    BufferedImage copyOfImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics g = copyOfImage.createGraphics();
    g.drawImage(img, 0, 0, null);
    return copyOfImage;
}
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type, int width, int height) {
    BufferedImage resizedImage = new BufferedImage(width, height, type);
    Graphics2D g = resizedImage.createGraphics();
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.setComposite(AlphaComposite.Src);
    g.drawImage(originalImage, 0, 0, width, height, null);
    g.dispose();

    return resizedImage;
}