6

我想从 PNG 中去除 alpha 通道(透明背景),然后将它们写为 JPEG 图像。更准确地说,我想让透明像素变白。我尝试了两种技术,两种技术都以不同的方式失败:

方法一:

BufferedImage rgbCopy = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = rgbCopy.createGraphics();
graphics.drawImage(inputImage, 0, 0, Color.WHITE, null);
graphics.dispose();
return rgbCopy;

结果:图像具有粉红色背景。

方法二:

final WritableRaster raster = inputImage.getRaster();
final WritableRaster newRaster = raster.createWritableChild(0, 0, inputImage.getWidth(), inputImage.getHeight(), 0, 0, new int[]{0, 1, 2});
ColorModel newCM = new ComponentColorModel(inputImage.getColorModel().getColorSpace(), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
return new BufferedImage(newCM, newRaster, false, null);

结果:图像具有黑色背景。

在这两种情况下,输入图像都是 PNG,输出图像是 JPEG,如下所示:ImageIO.write(bufferedImage, "jpg", buffer). 万一它是相关的:这是在Java 8上,我正在使用十二猴子库来调整图像的大小,然后再将其写入JPEG。

我已经尝试了上述代码的许多变体,但没有运气。有许多先前的问题建议使用上述代码,但在这种情况下似乎不起作用。

4

2 回答 2

7

多亏了 Rob 的回答,我们现在知道为什么颜色会乱了。

问题是双重的:

  • 用于写入 JPEG的默认值JPEGImageWriter不会以其他软件理解的方式写入带有 alpha 的 JPEG(这是一个已知问题)。ImageIO
  • null作为目标传递到ResampleOp.filter(src, dest)并且过滤器方法为时,将创建FILTER_TRIANGLE一个新的,带有 alpha (实际上是)。BufferedImageBufferedImage.TYPE_INT_ARGB

重新采样后去除 alpha 将起作用。但是,还有另一种方法可能更快并节省一些内存。也就是说,不是传递null目标,而是传递BufferedImage适当大小和类型的 a:

public static void main(String[] args) throws IOException {
    // Read input
    File input = new File(args[0]);
    BufferedImage inputImage = ImageIO.read(input);

    // Make any transparent parts white
    if (inputImage.getTransparency() == Transparency.TRANSLUCENT) {
        // NOTE: For BITMASK images, the color model is likely IndexColorModel,
        // and this model will contain the "real" color of the transparent parts
        // which is likely a better fit than unconditionally setting it to white.

        // Fill background  with white
        Graphics2D graphics = inputImage.createGraphics();
        try {
            graphics.setComposite(AlphaComposite.DstOver); // Set composite rules to paint "behind"
            graphics.setPaint(Color.WHITE);
            graphics.fillRect(0, 0, inputImage.getWidth(), inputImage.getHeight());
        }
        finally {
            graphics.dispose();
        }
    }

    // Resample to fixed size
    int width = 100;
    int height = 100;

    BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_TRIANGLE);

    // Using explicit destination, resizedImg will be of TYPE_INT_RGB
    BufferedImage resizedImg = resampler.filter(inputImage, new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB));

    // Write output as JPEG
    ImageIO.write(resizedImg, "JPEG", new File(input.getParent(), input.getName().replace('.', '_') + ".jpg"));
}
于 2016-03-17T10:09:45.003 回答
1

haraldk 是正确的,还有一段代码导致了 alpha 通道问题。方法 1 中的代码是正确且有效的。

但是,如果在剥离 Alpha 通道后,您使用 Decembermonkeys ResampleOp 调整图像大小,如下所示:

BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_TRIANGLE);
BufferedImage resizedImg = resampler.filter(rgbImage, null);

这会导致 Alpha 通道为粉红色。

解决方案是在剥离 Alpha 通道之前调整图像大小。

于 2016-03-16T15:46:02.607 回答