我正在尝试将WebP图像转换为PNG,但是在使用WebP,图像和颜色程序包时遇到了一些困难。
WebP decoding package返回一个image.Image
,它使用alpha预乘颜色。
https://golang.org/pkg/image/color/#Color
type Color interface {
// An alpha-premultiplied color component c has been scaled by alpha (a),
// so has valid values 0 <= c <= a.
RGBA() (r, g, b, a uint32)
}
问题是我尝试转换的WebP纹理使用alpha通道作为specular map而不是透明度。因此,即使特定像素的alpha为0,颜色值也仍然很重要。
但是,使用alpha预乘,该像素的颜色数据将不可逆地丢失,因为anything * 0 = 0
。
这是将WebP转换为PNG的代码:
if extension == ".webp" {
//open the WebP file
webpFile, err := os.OpenFile(fp, os.O_RDWR, 0777)
defer webpFile.Close()
if err != nil {
return
}
//create reader
reader := bufio.NewReader(webpFile)
//decode the WebP into an image.Image
img, err := webp.Decode(reader)
if err != nil {
return
}
webpFile.Close()
//create the new PNG file
os.MkdirAll(destination + parentDirs, 0755)
pngFile, err := os.Create(destination + parentDirs + baseName + ".png")
defer pngFile.Close()
if err != nil {
return
}
//write to the PNG file
err = png.Encode(pngFile,img)
if err != nil {
return
}
}
我想要的是输出一个完全不透明的PNG,并保留原始WebP中的所有颜色数据,即使WebP中的给定像素部分或完全透明。
也就是说,如果我可以采用原始纹理并将每个像素的Alpha值设置为1,而不会干扰RGB值。
我尝试将color model转换为img
,但是我仍然对模型系统的工作方式感到困惑。我认为这无论如何都不会解决问题,因为据我了解,转换仍然会从已经是alpha预乘的颜色转换。
我还尝试通过将每个RGB值除以alpha来撤消img
中每个像素的alpha重复。除alpha为0之外,这都是可行的,因为当它乘以0时,所有RGB数据都会丢失。
那么有什么方法可以将WebP转换为image.Image
,然后再转换为不带alpha预乘颜色的PNG?
修改:
此问题已在此处解决:https://github.com/golang/go/issues/26001
我使用了单独的功能来处理透明WebP。
func ConvertNYCbCrA(Color color.NYCbCrA) color.RGBA {
r,g,b := color.YCbCrToRGB(Color.Y,Color.Cb,Color.Cr)
return color.RGBA{r,g,b,255}
}
func ConvertNRGBA(Color color.NRGBA) color.RGBA {
return color.RGBA{
Color.R,
Color.G,
Color.B,
255,
}
}
/************************/
if extension == ".webp" {
//open the WebP file
webpFile, _ := os.OpenFile(filepath, os.O_RDWR, 0777)
defer webpFile.Close()
//create a reader
reader := bufio.NewReader(webpFile)
//decode the WebP
imageData, _ := webp.Decode(reader)
webpFile.Close()
//create new image
newImage := image.NewRGBA(imageData.Bounds())
//fill new image with pixels
for y := imageData.Bounds().Min.Y; y < imageData.Bounds().Max.Y; y++ {
for x := imageData.Bounds().Min.X; x < imageData.Bounds().Max.X; x++ {
//get pixel from imageData
pixel := imageData.At(x,y)
//convert pixel to RGBA
var RGBApixel color.RGBA
switch imageData.ColorModel() {
case color.NYCbCrAModel:
RGBApixel = ConvertNYCbCrA(pixel.(color.NYCbCrA))
case color.NRGBAModel:
RGBApixel = ConvertNRGBA(pixel.(color.NRGBA))
default:
RGBApixel = color.RGBAModel.Convert(pixel).(color.RGBA)
RGBApixel.A = 255
}
//set new pixel in new image
newImage.Set(x,y,RGBApixel)
}
}
//create the new PNG file
pngFile, _ := os.Create(newFilePath + ".png")
defer pngFile.Close()
//write to the PNG file
png.Encode(pngFile, newImage)
}