Possible bug in image/draw with RGB values of fully transparent pixels

181 views
Skip to first unread message

SugarMGP

unread,
Aug 20, 2025, 2:55:34 PMAug 20
to golang-nuts

Hi all,

I recently encountered an issue when using Go’s standard library image/draw. Specifically, I found that fully transparent pixels (alpha = 0) sometimes retain non-zero RGB values. This can cause unexpected colors when compositing the image onto a white background.

Here is a minimal reproducible example:

func main() {
    // Create a source image with a fully transparent pixel
    src := image.NewRGBA(image.Rect(0, 0, 2, 2))
    src.SetRGBA(0, 0, color.RGBA{R: 100, G: 150, B: 200, A: 0}) // fully transparent

    dst := image.NewRGBA(src.Bounds())
    draw.Draw(dst, dst.Bounds(), src, image.Point{}, draw.Src)

    r, g, b, a := dst.At(0, 0).RGBA()
    fmt.Printf("Pixel (0,0) RGBA: %d %d %d %d\n", r>>8, g>>8, b>>8, a>>8)
}

Output:

Pixel (0,0) RGBA: 100 150 200 0

As you can see, even though alpha is 0, the RGB channels retain their original values. This causes issues when you try to composite the image onto a white background, because these “dirty” RGB values can show up in certain blending scenarios.

In my code, I wrote a manual loop to premultiply or blend alpha into white, which works correctly. But using draw.Draw, these transparent pixels keep their original RGB values.

My questions are:

  • Is this the intended behavior of image/draw?

  • Or is this a bug (or at least a usability issue) in the standard library that should be fixed?

Thank you very much for your opinions and insights!

Note: My English is not very good, so I used an LLM to translate this post.

Rob Pike

unread,
Aug 20, 2025, 7:10:20 PMAug 20
to SugarMGP, golang-nuts
This is correct behavior. The original pixel has value (100, 150, 200, 0) and you use the Src operator, which copies the source to the destination unmodified.

-rob


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/9b7cb846-622c-44c1-9e9b-87ff8ee7453fn%40googlegroups.com.

Jason E. Aten

unread,
Aug 20, 2025, 9:32:06 PMAug 20
to golang-nuts
It might help to review the concept of an Alpha channel, and in
particular look at the rationale for non-premultiplied alphas that the PNG format
describes.

https://www.w3.org/TR/PNG-Rationale.html#R.Non-premultiplied-alpha

SugarMGP

unread,
Aug 21, 2025, 12:25:39 AMAug 21
to golang-nuts
func main(){
src := image.NewRGBA(image.Rect(0, 0, 2, 2))
src.SetRGBA(0, 0, color.RGBA{R: 100, G: 150, B: 200, A: 0})

dst := image.NewRGBA(src.Bounds())
draw.Draw(dst, dst.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src)
draw.Draw(dst, dst.Bounds(), src, image.Point{}, draw.Over)


r, g, b, a := dst.At(0, 0).RGBA()
fmt.Printf("Pixel (0,0) RGBA: %d %d %d %d\n", r>>8, g>>8, b>>8, a>>8)
}

result: Pixel (0,0) RGBA: 100 150 200 255

However, when I tried to blend a transparent pixel onto a white background, the result was not white, which is what really confused me.

Kevin Chowski

unread,
Aug 21, 2025, 6:04:08 PMAug 21
to golang-nuts
The docs for color.RGBA mention: "An alpha-premultiplied color component C has been scaled by alpha (A), so has valid values 0 <= C <= A.", so I believe "color.RGBA{R: 100, G: 150, B: 200, A: 0}" is an invalid value. Perhaps you have non-alpha-premultiplied colors? Using RGBA.Set with an NRGBA value seems to work as I expect (https://go.dev/play/p/OjzdswX-lk_L), same with just using an image.NRGBA in the first place (https://go.dev/play/p/VEvsKjh8lNU)

SugarMGP

unread,
Aug 22, 2025, 4:28:50 AMAug 22
to golang-nuts
I reorganized the code and found that the issue was caused by the dependency library “github.com/chai2010/webp” having a higher priority than “golang.org/x/image/webp,” and its decoder incorrectly decoded the image into incorrect RGBA values (e.g., R: 100, G: 150, B: 200, A: 0).

Thank you for your clarification, which has given me a deeper understanding of RGBA and NRGBA.
Reply all
Reply to author
Forward
0 new messages