Skip to content

image/png: info loss when encoding non-alpha-premultiplied that's not NRGBA (e.g., NRGBA64, NYCbCrA) #26001

@rbxb

Description

@rbxb

Edit: solution below

Go Version:
1.10.3 windows/amd64 (latest)

I'm not sure if this is an error or if it is by design.
I think this is a problem with the webp and/or vp8 packages, but it could be a problem with my code. I don't know all the ins and outs of the image package.

When decoding WebPs (and converting to PNG), color data is lost for pixels that are completely transparent. I don't think that this should be happening.
The WebPs affected are structured like so:

  • VP8X
  • ALPH
  • VP8

This loss does not occur when I decode the same WebP using Google's WebP tools.

Here is my Go code:

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 the new PNG file
	pngFile, _ := os.Create(newFilePath + ".png")
	defer pngFile.Close()

	//write to the PNG file
	png.Encode(pngFile, imageData)

}

I reproduced the problem with an example image:
I'm linking to them because they don't display correctly through github

The original PNG before it was encoded to WebP; the Golang logo but completely transparent:
.png

I drew on only the alpha channel of the original so you can see that it still retains color:
.png

Here is the WebP encoded from the original PNG
.webp

Now here is where the problem occurs:
Again, I drew on only the alpha channel so you can see if the color is retained.

Decoded using Google's WebP tool (What I expected to happen):
.png
.png

Decoded using my code (What happened):
.png
.png

Does anyone know why this is happening? Is it a bug/intentional in the WebP packages? Is it my code?

Edit: Here is the solution I implemented.
It handles NYCbCrA and NRGBA images specially and reformats them to a color.RGBA to give to the png encoder. The RGBA pixel is just set to be completely opaque since I don't need the A values.

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)

}

Here is the result:
.png

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions