drwu24647 2018-06-20 20:37
浏览 84

使用非Alpha预乘颜色解码WebP

I am trying to convert WebP images to PNGs but I am having some difficulties with the WebP, Image, and Color packages.
The WebP decoding package returns an image.Image, which uses alpha-premultiplied colors.

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)
}

The problem is the WebP textures that I am trying to convert use the alpha channel as a specular map rather than for transparency. So even if the alpha on a particular pixel is 0, the color value is still important.
But with alpha-premultiplication, that pixel's color data would be irreversibly lost because anything * 0 = 0.

Here is my code to convert WebP to 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
    }

}

What I want is to output a PNG that is fully opaque and retains all of the color data that was in the original WebP, even if a given pixel in the WebP was partially or fully transparent.
i.e. if I could just take the original texture and set every pixel's alpha value to 1 without disturbing the RGB values.

I have tried converting the color model for the img, but I am still confused on how the model system works. I don't think this would solve the problem anyway because, as I understand, the conversion would still convert from the already alpha-premultiplied colors.
I have also tried undoing the alpha-premultplication for each pixel in img by dividing each RGB value by the alpha. This works except for when the alpha was 0 because then all of the RGB data was lost when it was multiplied by 0.

So is there any way to convert from WebP to an image.Image and then to a PNG without alpha-premultiplied colors?

Edit:
This was solved here: https://github.com/golang/go/issues/26001
I used separate functions to handle transparent WebPs.

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条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 微信小程序协议怎么写
    • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
    • ¥20 怎么用dlib库的算法识别小麦病虫害
    • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
    • ¥15 java写代码遇到问题,求帮助
    • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
    • ¥15 有了解d3和topogram.js库的吗?有偿请教
    • ¥100 任意维数的K均值聚类
    • ¥15 stamps做sbas-insar,时序沉降图怎么画
    • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看