PNG 输出 alpha 通道但没有 RGB 和 JPG 输出 RGB 但没有 alpha

PNG outputs alpha channel but no RGB and JPG outputs RGB but no alpha

我想将一个 PNG 文件拆分为另外 4 个 PNG,其中 3 个用于 RGB,一个用于 alpha。当我输入 PNG 时,alpha 通道输出正确,但 RGB 通道没有输出。如果我输入 JPG,RGB 通道输出正确,但 alpha 失败,因为没有可获取的 alpha 通道。

我试过使用多张图像,所有这些图像要么是 PNG 要么是 JPG,但它们都以我描述的相同方式失败。

val original = ImageIO.read(File("images/input.png"))

val alpha = BufferedImage(original.width, original.height, original.type)
val red = BufferedImage(original.width, original.height, original.type)
val green = BufferedImage(original.width, original.height, original.type)
val blue = BufferedImage(original.width, original.height, original.type)

for (y in 0 until original.height) {
    for (x in 0 until original.width) {
        val color = original.getRGB(x,y)

        val a = color  and 0xff000000.toInt()
        val r = color  and 0x00ff0000
        val g = color  and 0x0000ff00
        val b = color  and 0x000000ff

        alpha.setRGB(x,y,a)
        red.setRGB(x,y,r)
        green.setRGB(x,y,g)
        blue.setRGB(x,y,b)

    }
}

ImageIO.write(alpha,"png", File("images/alpha.png"))
ImageIO.write(red,"png", File("images/red.png"))
ImageIO.write(green,"png", File("images/green.png"))
ImageIO.write(blue,"png", File("images/blue.png"))

我希望单独接收 4 个带有各自通道的输出,但我只收到一个带 PNG 的 alpha 通道,没有带 JPG 的 alpha 通道。

setRGB 使用 TYPE_INT_ARGB 作为颜色模型。当您的位掩码将 alpha 通道设置为 0 时,图像看起来是空的。将要显示的图像的 alpha 设置为 ff。

val a = color and 0xff000000.toInt()
val r = (color and 0x00ff0000) or 0xff000000.toInt()
val g = (color and 0x0000ff00) or 0xff000000.toInt()
val b = (color and 0x000000ff) or 0xff000000.toInt() 

JPEG 文件格式不包含任何 alpha 通道 - 要使用 JPEG 重新创建某种透明度,您可以做的是添加另一个由单色图像组成的图层,然后通过该图层过滤图像,但这是一个非常特殊的用例,很可能您不想在此示例中执行任何操作。

您的代码无法按预期工作的部分原因是您根据原始类型创建了新的 BufferedImage

BufferedImage(original.width, original.height, original.type)

原始类型会因输入图像而异。对于 JPEG,它通常是 TYPE_3BYTE_BGR(没有 alpha)。对于 PNG,它取决于类型或 PNG(灰度、调色板、真彩色、带或不带 alpha 等)。您输入的 PNG 似乎是带有 alpha 的真彩色,可能导致 TYPE_4BYTE_ABGRTYPE_INT_ARGB

相反,您可以使用 TYPE_BYTE_GRAY 创建 4 个灰度图像(仅 "levels"),或者像现在一样,使用 TYPE_INT_ARGB 创建 4 个 ARGB 图像(对不起,如果我的 Kotlin 语法关闭了,这些天我主要编程 Java):

BufferedImage(original.width, original.height, BufferedImage.TYPE_INT_ARGB)

接下来,正如@AlexanderEgger 已经指出的那样,set/getRGB 方法以打包的 ARGB 格式运行,因此您需要确保颜色是不透明的(anding with 只是颜色遮罩,将产生完全透明的颜色):

val a = color and 0xff000000.toInt()
val r = (color and 0x00ff0000) or 0xff000000.toInt()
val g = (color and 0x0000ff00) or 0xff000000.toInt()
val b = (color and 0x000000ff) or 0xff000000.toInt()  

或者,如果您喜欢级别方法,您可以按照@MarkSetchell 的建议进行操作,并创建所有灰色图像(同样,Kotlin 语法可能有点偏差):

BufferedImage(original.width, original.height, BufferedImage.TYPE_BYTE_GRAY)

...

val a = (color >> 24) and 0xff
val r = (color >> 16) and 0xff
val g = (color >>  8) and 0xff
val b =  color        and 0xff

val aa = 0xff000000.toInt() or (a << 16) or (a << 8) or a
val rr = 0xff000000.toInt() or (r << 16) or (r << 8) or r
val gg = 0xff000000.toInt() or (g << 16) or (g << 8) or g
val bb = 0xff000000.toInt() or (b << 16) or (b << 8) or b

(并将 aarrggbb 传递给 setRGB)。