使用非Alpha预乘颜色解码WebP

时间:2018-06-20 20:37:09

标签: go webp

我正在尝试将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)

}

0 个答案:

没有答案