Java:使用透明度生成缩略图

4

我在生成带有Alpha通道(透明度)的图像缩略图时遇到了问题。我使用的代码如下:

public void saveThumbnail(File file, String imageType) {
    if (bufferedThumb == null) {
        return;
    }

    if(bufferedImage.getColorModel().hasAlpha()) {
        logger.debug("Original image has Alpha channel");
    }

    BufferedImage bi = new BufferedImage(bufferedThumb.getWidth(null), bufferedThumb.getHeight(null), BufferedImage.TYPE_INT_ARGB);
    Graphics g = bi.getGraphics();
    g.drawImage(bufferedThumb, 0, 0, null);
    try {
        ImageIO.write(bi, imageType, file);
    } catch (IOException ioe) {
        ioe.printStackTrace();
        System.out.println("Error occured saving thumbnail");
    }
}

然而,如果我使用带有透明背景的GIF图像,最终总是会出现黑色或有色背景。

编辑:

这是从类中使用缩略图调用它的方式,上次我错过了getThuimbnail()方法的双参数版本:

Thumbnail th = new Thumbnail(file.getPath());
th.getThumbnail(100);

添加了用于获取图像的方法:

public Thumbnail(String fileName) {
    try {
        this.bufferedImage = ImageIO.read(new File(fileName));
    } catch (IOException ex) {
        logger.error("Failed to read image file: " + ex.getMessage());
    }
}

public Image getThumbnail(int size) {
    int dir = VERTICAL;
    if (bufferedImage.getHeight() < bufferedImage.getWidth()) {
        dir = HORIZONTAL;
    }
    return getThumbnail(size, dir);
}

/**
 * Creates image with specifed max sized to a specified direction.
 * Will use Image.SCALE_SMOOTH for scaling.
 * @param size Maximum size
 * @param dir Direction of maximum size - 0 = vertical, 1 = height.
 * @return Resized image.
 */
public Image getThumbnail(int size, int dir) {
    return getThumbnail(size, dir, Image.SCALE_SMOOTH);
}

/**
 * Creates image with specified size.
 * @param size Maximum size
 * @param dir Direction of maximum size - 0 = vertical, 1 = height.
 * @param scale Image.Scale to use for conversion.
 * @return Resized image.
 */
public Image getThumbnail(int size, int dir, int scale) {
    if (dir == HORIZONTAL) {
        bufferedThumb = bufferedImage.getScaledInstance(size, -1, scale);
    } else {
        bufferedThumb = bufferedImage.getScaledInstance(-1, size, scale);
    }
    return bufferedThumb;
}

谢谢!


1
GIF图像没有alpha通道,只有一个标记为透明的颜色。当你将其缩小时,最终得到的数据无法表示为GIF格式。 - Josh Lee
我明白了,所以最好总是将缩略图保存为JPEG或PNG格式? - Malakim
最好使用PNG格式,适用于透明效果。 - Gordon
4个回答

1

使用透明色缩小 GIF 图像应该可以正常工作。我同意 jarnbjo 的看法,问题很可能在 bufferedThumb 生成中。

也许以下提示有所帮助:

1)创建缩略图时,从源图像复制图像类型,例如:

BufferedImage thumb = new BufferedImage(fit, fit, image.getType());

2) 使用二维方法:

Graphics2D g = thumb.createGraphics();

这里是一些简单的缩略图创建示例代码(已测试并可用;支持透明GIF,缩略图保持透明度):

  public static BufferedImage thumb(BufferedImage image, int fit) {

    //image = blur(image);
    BufferedImage thumb = new BufferedImage(fit, fit, image.getType());
    Graphics2D g = thumb.createGraphics();

    try {
      int width = image.getWidth();
      int height = image.getHeight();
      int sx1;
      int sy1;
      int sx2;
      int sy2;
      int tmp;

      if (height > width) {
        tmp = height - width;
        sx1 = 0;
        sy1 = tmp / 2;
        sx2 = width;
        sy2 = height - sy1;
      } else if (width > height) {
        tmp = width - height;
        sx1 = tmp / 2;
        sy1 = 0;
        sx2 = width - sx1;
        sy2 = height;
      } else {
        sx1 = 0;
        sy1 = 0;
        sx2 = width;
        sy2 = height;
      }

      g.drawImage(
          image,
          0, 0,
          fit, fit,
          sx1, sy1,
          sx2, sy2,
          null
      );

    } finally {
      g.dispose();
    }
    return thumb;
  }//thumb

注意:所谓简单,是指如果您试图在单个步骤中扩展太多(例如将2048像素缩小到100像素),它不会产生高质量的结果。您可能需要采用多步方法,并且最好使用带有提示的AffineTransformOp而不是使用Graphics设备。

谢谢,我已经将获取图像所使用的方法添加到问题中。图片质量并不太重要,缩略图将会很小,仅供用户了解原始图片。 - Malakim
Malakim,你试过我发的拇指方法了吗?它真的应该可以工作。只需传递图像和缩略图的框大小(代码会处理水平和垂直方向,将其适合框内)。 - Dieter
刚到办公室,正在尝试。
  • 谢谢!
- Malakim
对我来说不起作用。当使用透明GIF时,我仍然得到黑色背景。我尝试添加if(image.getColorModel().hasAlpha()) { logger.debug("原始图像具有Alpha通道"); } if(thumb.getColorModel().hasAlpha()) { logger.debug("缩略图像具有Alpha通道"); }第一个命中了,但第二个没有。我还尝试在图像呈现为新的缩略图之后设置它(在您的方法中的最后一件事),但它仍然无法命中调试语句。-谢谢! - Malakim

1

通过使用AffineTransform缩放操作解决了它:

AffineTransform af = new AffineTransform();
af.scale(scaleFactor, scaleFactor);

AffineTransformOp operation = new AffineTransformOp(af, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
bufferedThumb = operation.filter(bufferedImage, null);
return bufferedThumb;

这似乎可以保留图像中的透明度。


0

你用于编写文件的代码是正确的,至少如果你使用支持透明度的格式(例如PNG)的话。很可能,bufferedThumb 已经损坏了,为了帮助你,如果你说明一下如何获取 bufferedImage 和如何创建 bufferedThumb,那将更有帮助。


谢谢,我已经在问题中添加了获取图像所使用的方法。 - Malakim
不,你没有。如果你正在使用getThumbnail(int size)来生成缩略图,那么你没有包含你正在调用的getThumbnail的两个参数实现。如果三个参数的getThumbnail实现是相关的,你也没有展示你如何使用它。 - jarnbjo

-1
你可以使用Image IO库来尝试它:
以下是代码:
package com.incture.thumbnail;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Thumnail {

    public static void main(String[] args) {

        String source = "E:/Incture/APAutomation/NewWorkspace/BarCodeReading/download-button.gif";
        String target = "E:/Incture/APAutomation/NewWorkspace/BarCodeReading/thumb1.jpg";

        saveScaledImage(source, target);

    }

    public static void saveScaledImage(String filePath, String outputFile) {

        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
        try {
            Graphics g=img.getGraphics();
            g.setColor(Color.white);
            g.fillRect(0, 0, img.getWidth(), img.getHeight());   
            g.drawImage(ImageIO.read(new File(filePath)), 0 , 0, 20, 20, null);
            ImageIO.write(img, "png", new File(outputFile));
            System.out.println("done");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

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