PNG 输出 alpha 通道但没有 RGB,JPG 输出 RGB 但没有 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() 

您的代码无法按预期工作的原因部分是因为您基于原始类型创建新的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 个灰度图像(只是"级别"),或者像现在一样,使用TYPE_INT_ARGB创建 4 个 ARGB 图像(抱歉,如果我的 Kotlin 语法关闭,我这些天主要编写 Java):

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

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

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)。

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

最新更新