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_ABGR
或 TYPE_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 格式运行,因此您需要确保颜色是不透明的(and
ing 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
(并将 aa
、rr
、gg
和 bb
传递给 setRGB
)。
我想将一个 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_ABGR
或 TYPE_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 格式运行,因此您需要确保颜色是不透明的(and
ing 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
(并将 aa
、rr
、gg
和 bb
传递给 setRGB
)。