如何使用透明填充缩放Graphics2D图像

4

我正在尝试编写一个小方法,它接受一个BufferedImage图像和一个新的宽度和高度,并通过在左/右或上/下添加透明边框来保持图像纵横比例。 缩放功能正常工作,但我无论如何都无法使边框透明。

到目前为止,我已经在pastebin.com发布了以下代码,它可以很好地实现缩放。

我已经阅读了许多手册和其他SO问题,但都没有成功。我尝试了许多填充、组合类型、图像类型等排列组合,有时会得到蓝色背景,有时是白色,但似乎从未透明过。

BufferedImage newImg = new BufferedImage(newWidth, newHeight, img.getType());
Graphics2D g = newImg.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, newWidth, newHeight);
g.drawImage(img, x, y, x + scaledWidth, y + scaledHeight, 0, 0,
    currentWidth, currentHeight, Color.WHITE, null);
g.dispose();
return newImg;

有没有想法应该进行哪个Graphics2D调用,才能使白色背景透明以及将旧图像绘制在新图像上?感谢任何帮助。
编辑: 事实证明,我遇到的问题是我试图生成一个带有JPEG图像的透明颜色。 JPEG不支持透明度。 噢。

你尝试过使用 new Color(int r, int g, int b, int a) 来设置 alpha 组件吗? - Eng.Fouad
我非常确定这是我尝试过的事情之一,@Eng.Fouad。如果您能更具体一些,我会尝试一下。 - Gray
类似于new Color(0, 0, 0, 0) - Eng.Fouad
1
此外,考虑使用 BufferedImage.TYPE_INT_ARGB 作为图片类型。 - Eng.Fouad
4个回答

6

我刚试过了,它可用。

只需将Color.WHITE替换为new Color(0, 0, 0, 0)img.getType()替换为BufferedImage.TYPE_INT_ARGB


BufferedImage img = ImageIO.read(new File("image.png"));
BufferedImage outImage = scaleWithPadding(img, 300, 100);
ImageIO.write(outImage, "png", new File("newImage.png"));

image.png:(204x53)

输入图像说明

newImage.png:(300x100)

输入图像说明


谢谢你。你尝试了什么类型的图像?我的问题是我正在尝试转换JPEG图像吗? - Gray
1
@Gray PNG 图像。JPEG 内部不能有透明度。 - Eng.Fouad
1
那就是我的问题。非常感谢您的帮助! - Gray

3

我有和你一样的需求,在这篇如何使颜色透明的帖子和网页上找到了很多帮助。

下面是我的最终代码:

public BufferedImage getTransparentScaledImage(BufferedImage originalImage, int finalWidth, int finalHeight) {
    int originalWidth = originalImage.getWidth();
    int originalHeight = originalImage.getHeight();

    int newWidth;
    int newHeight;
    if (originalWidth == 0 || originalHeight == 0
            || (originalWidth == finalWidth && originalHeight == finalHeight)) {
        return originalImage;
    }

    double aspectRatio = (double) originalWidth / (double) originalHeight;
    double boundaryAspect = (double) finalWidth / (double) finalHeight;

    if (aspectRatio > boundaryAspect) {
        newWidth = finalWidth;
        newHeight = (int) Math.round(newWidth / aspectRatio);
    } else {
        newHeight = finalHeight;
        newWidth = (int) Math.round(aspectRatio * newHeight);
    }

    int xOffset = (finalWidth - newWidth) / 2;
    int yOffset = (finalHeight - newHeight) / 2;

    LoggerManager.getInstance().debug("frontoffice",
            "Image Servlet: [" + xOffset + "] [" + yOffset + "] [" + newWidth + "] [" + newHeight + "] [" + originalWidth + "] [" + originalHeight + "] [" + finalWidth + "] [" + finalHeight + "]");

    BufferedImage intermediateImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D gi = intermediateImage.createGraphics();
    gi.setComposite(AlphaComposite.SrcOver);
    gi.setColor(Color.WHITE);
    gi.fillRect(0, 0, finalWidth, finalHeight);
    gi.drawImage(originalImage, xOffset, yOffset, xOffset + newWidth, yOffset + newHeight, 0, 0, originalWidth, originalHeight, Color.WHITE, null);
    gi.dispose();

    //if image from db already had a transparent background, it becomes black when drawing it onto another
    //even if we draw it onto a transparent image
    //so we set it to a specific color, in this case white
    //now we have to set that white background transparent
    Image intermediateWithTransparentPixels = makeColorTransparent(intermediateImage, Color.WHITE);

    //finalize the transparent image
    BufferedImage finalImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_ARGB);
    Graphics2D gf = finalImage.createGraphics();
    gf.setComposite(AlphaComposite.SrcOver);
    gf.setColor(new Color(0, 0, 0, 0));
    gf.fillRect(0, 0, finalWidth, finalHeight);
    gf.drawImage(intermediateWithTransparentPixels, 0, 0, finalWidth, finalHeight, new Color(0, 0, 0, 0), null);
    gf.dispose();

    return finalImage;
}

public static Image makeColorTransparent(Image im, final Color color) {
    ImageFilter filter = new RGBImageFilter() {
        // the color we are looking for... Alpha bits are set to opaque
        public int markerRGB = color.getRGB() | 0xFF000000;

        public final int filterRGB(int x, int y, int rgb) {
            if ((rgb | 0xFF000000) == markerRGB) {
                // Mark the alpha bits as zero - transparent
                return 0x00FFFFFF & rgb;
            } else {
                // nothing to do
                return rgb;
            }
        }
    };

    ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
    return Toolkit.getDefaultToolkit().createImage(ip);
}

非常感谢您,您真正解决了我长时间以来的难题~ - Mr rain

0

你原来的drawImage()方法没有透明背景,因为使用了背景颜色。请替换为以下内容:

 g.drawImage(img, x, y, x + scaledWidth, y + scaledHeight, 0, 0, currentWidth, currentHeight, null);

0

我已经实现了提到的解决方案(或非常相似),只要注意如果您不使用。

graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON;

由于缩放,您的图像将以非常低的质量生成


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