-
Notifications
You must be signed in to change notification settings - Fork 18.6k
Description
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