判断一张图片是否具有 alpha 通道的最佳方法是什么?

huangapple go评论120阅读模式
英文:

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 &lt; rect.Max.Y; y++ {
		for x := rect.Min.X; x &lt; 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.

huangapple
  • 本文由 发表于 2017年5月22日 13:52:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/44105499.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定