英文:
What is the best way to decide if an image has alpha channel?
问题
我需要决定一张图片是否具有 alpha 通道,所以我写了以下代码。
var HaveAlpha = func(Image image.Image) bool {
switch Image.ColorModel() {
case color.YCbCrModel, color.CMYKModel:
return false
case color.RGBAModel:
return !Image.(*image.RGBA).Opaque()
}
// ...
return false
}
所以我需要列出所有的 ColorModel
类型,并使用 Opaque()
方法来判断图片是否具有 alpha 通道(因为我不能直接在 image.Image
类型上使用 Opaque()
方法)。如果一张图片具有 alpha 通道,但是图片中的所有像素都是不透明的(所有像素的 RGBA 值都类似于 (*,*,*,255)
),这段代码可能会返回错误的答案。
在 Golang 中,是否有一种正确或更好的方法来判断一张图片是否具有 alpha 通道?
英文:
I need to decide if an image has alpha channel or not, so I write the code like this.
var HaveAlpha = func(Image image.Image) bool {
switch Image.ColorModel() {
case color.YCbCrModel, color.CMYKModel:
return false
case color.RGBAModel:
return !Image.(*image.RGBA).Opaque()
}
// ...
return false
}
So I need to list all the ColorModel
types and use Opaque()
to decide if the image has alpha channel or not (because I cannot use Opaque()
method in type image.Image
directly). And if an image has alpha channel but all pixels are opaque in the image (all RGBA of pixels in that image are like (*,*,*,255)
), this code may return wrong answer.
Is there a right or better way to decide if an image has alpha channel or not in Golang?
答案1
得分: 4
你可以使用type assertion来检查存储在image.Image
接口类型中的具体值是否具有Opaque() bool
方法,如果有,只需调用该方法并返回其结果。请注意,image
包中的所有具体图像类型都具有Opaque()
方法,因此这将涵盖大多数情况。
如果图像没有这样的Opaque()
方法,循环遍历图像的所有像素,并检查任何像素的alpha值是否不等于0xff
,这意味着它是非透明的。
请注意,Image.At()
的返回类型是通用的color.Color
接口类型,该接口只保证一个方法:Color.RGBA()
。这个RGBA()
方法返回_alpha预乘_的红色、绿色、蓝色和alpha分量,因此如果一个像素的alpha值为0xff
,那么在“alpha预乘”时等于0xffff
,这就是我们需要进行比较的值。
func Opaque(im image.Image) bool {
// 检查图像是否具有Opaque()方法:
if oim, ok := im.(interface {
Opaque() bool
}); ok {
return oim.Opaque() // 有,调用它并返回结果!
}
// 没有Opaque()方法,我们需要循环遍历所有像素并手动检查:
rect := im.Bounds()
for y := rect.Min.Y; y < rect.Max.Y; y++ {
for x := rect.Min.X; x < rect.Max.X; x++ {
if _, _, _, a := im.At(x, y).RGBA(); a != 0xffff {
return false // 找到一个非透明像素:图像是非透明的
}
}
}
return true // 所有像素都是不透明的,图像也是不透明的
}
上述的Opaque()
函数将在图像没有alpha通道或者有alpha通道但所有像素都是不透明时返回true
。只有当图像具有alpha通道且至少有1个像素不是(完全)不透明时,它才返回false
。
**注意:**如果图像确实具有Opaque()
方法,你可以确信它会考虑现有像素及其alpha值,因此例如image.RGBA.Opaque()
也会类似于我们上面所做的方式扫描整个图像;但我们必须以一种通用的方式来实现,具体图像的Opaque()
实现可能更高效(因此强烈建议使用“内置”的Opaque()
方法,如果可用的话)。例如,image.YCbCr.Opaque()
的实现是一个简单的return true
语句,因为YCbCr
图像没有alpha通道。
英文:
You may use type assertion to check if the concrete value stored in the image.Image
interface type has an Opaque() bool
method, and if so, simply call that and return its result. Note that all concrete image types in the image
package do have an Opaque()
method, so this will cover most cases.
If the image does not have such an Opaque()
method, loop over all pixels of the image and check if any of the pixel has an alpha value other than 0xff
, which means it's non-opaque.
Note that Image.At()
has a return type of the general color.Color
interface type, which only guarantees a single method: Color.RGBA()
. This RGBA()
method returns the alpha-premultiplied red, green, blue and alpha components, so if a pixel has 0xff
alpha value, that equals to 0xffff
when "alpha-premultiplied", so that's what we need to compare to.
func Opaque(im image.Image) bool {
// Check if image has Opaque() method:
if oim, ok := im.(interface {
Opaque() bool
}); ok {
return oim.Opaque() // It does, call it and return its result!
}
// No Opaque() method, we need to loop through all pixels and check manually:
rect := im.Bounds()
for y := rect.Min.Y; y < rect.Max.Y; y++ {
for x := rect.Min.X; x < rect.Max.X; x++ {
if _, _, _, a := im.At(x, y).RGBA(); a != 0xffff {
return false // Found a non-opaque pixel: image is non-opaque
}
}
}
return true // All pixels are opaque, so is the image
}
The above Opaque()
function will return true
if the image does not have an alpha channel, or it has but all pixels are opaque. It returns false
if and only if the image has alpha channel and there is at least 1 pixel that is not (fully) opaque.
Note: If an image does have an Opaque()
method, you can be sure that it takes existing pixels and their alpha values into consideration, so for example image.RGBA.Opaque()
also scans the entire image similarly to what we did above; but we had to do it in a general way, and Opaque()
implementations of concrete images may be much more efficient (so it is highly recommended to use the "shipped" Opaque()
method if it is available). As an example, implementation of image.YCbCr.Opaque()
is a simple return true
statement because YCbCr
images do not have alpha channel.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论