Commit 695024b8 authored by Nigel Tao's avatar Nigel Tao

image/png: tRNS chunk is *non*-alpha-premultiplied.

R=r
CC=golang-dev
https://golang.org/cl/6446062
parent b6ea905e
...@@ -226,7 +226,7 @@ func (d *decoder) parsetRNS(length uint32) error { ...@@ -226,7 +226,7 @@ func (d *decoder) parsetRNS(length uint32) error {
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
rgba := d.palette[i].(color.RGBA) rgba := d.palette[i].(color.RGBA)
d.palette[i] = color.RGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]} d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
} }
case cbGA8, cbGA16, cbTCA8, cbTCA16: case cbGA8, cbGA16, cbTCA8, cbTCA16:
return FormatError("tRNS, color type mismatch") return FormatError("tRNS, color type mismatch")
......
...@@ -107,13 +107,18 @@ func sng(w io.WriteCloser, filename string, png image.Image) { ...@@ -107,13 +107,18 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
lastAlpha := -1 lastAlpha := -1
io.WriteString(w, "PLTE {\n") io.WriteString(w, "PLTE {\n")
for i, c := range cpm { for i, c := range cpm {
r, g, b, a := c.RGBA() var r, g, b, a uint8
if a != 0xffff { switch c := c.(type) {
case color.RGBA:
r, g, b, a = c.R, c.G, c.B, 0xff
case color.NRGBA:
r, g, b, a = c.R, c.G, c.B, c.A
default:
panic("unknown palette color type")
}
if a != 0xff {
lastAlpha = i lastAlpha = i
} }
r >>= 8
g >>= 8
b >>= 8
fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b) fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
} }
io.WriteString(w, "}\n") io.WriteString(w, "}\n")
......
...@@ -21,7 +21,7 @@ type encoder struct { ...@@ -21,7 +21,7 @@ type encoder struct {
err error err error
header [8]byte header [8]byte
footer [4]byte footer [4]byte
tmp [3 * 256]byte tmp [4 * 256]byte
} }
// Big-endian. // Big-endian.
...@@ -70,7 +70,7 @@ func (e *encoder) writeChunk(b []byte, name string) { ...@@ -70,7 +70,7 @@ func (e *encoder) writeChunk(b []byte, name string) {
e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b))) e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
return return
} }
writeUint32(e.header[0:4], n) writeUint32(e.header[:4], n)
e.header[4] = name[0] e.header[4] = name[0]
e.header[5] = name[1] e.header[5] = name[1]
e.header[6] = name[2] e.header[6] = name[2]
...@@ -78,9 +78,9 @@ func (e *encoder) writeChunk(b []byte, name string) { ...@@ -78,9 +78,9 @@ func (e *encoder) writeChunk(b []byte, name string) {
crc := crc32.NewIEEE() crc := crc32.NewIEEE()
crc.Write(e.header[4:8]) crc.Write(e.header[4:8])
crc.Write(b) crc.Write(b)
writeUint32(e.footer[0:4], crc.Sum32()) writeUint32(e.footer[:4], crc.Sum32())
_, e.err = e.w.Write(e.header[0:8]) _, e.err = e.w.Write(e.header[:8])
if e.err != nil { if e.err != nil {
return return
} }
...@@ -88,7 +88,7 @@ func (e *encoder) writeChunk(b []byte, name string) { ...@@ -88,7 +88,7 @@ func (e *encoder) writeChunk(b []byte, name string) {
if e.err != nil { if e.err != nil {
return return
} }
_, e.err = e.w.Write(e.footer[0:4]) _, e.err = e.w.Write(e.footer[:4])
} }
func (e *encoder) writeIHDR() { func (e *encoder) writeIHDR() {
...@@ -122,36 +122,29 @@ func (e *encoder) writeIHDR() { ...@@ -122,36 +122,29 @@ func (e *encoder) writeIHDR() {
e.tmp[10] = 0 // default compression method e.tmp[10] = 0 // default compression method
e.tmp[11] = 0 // default filter method e.tmp[11] = 0 // default filter method
e.tmp[12] = 0 // non-interlaced e.tmp[12] = 0 // non-interlaced
e.writeChunk(e.tmp[0:13], "IHDR") e.writeChunk(e.tmp[:13], "IHDR")
} }
func (e *encoder) writePLTE(p color.Palette) { func (e *encoder) writePLTEAndTRNS(p color.Palette) {
if len(p) < 1 || len(p) > 256 { if len(p) < 1 || len(p) > 256 {
e.err = FormatError("bad palette length: " + strconv.Itoa(len(p))) e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
return return
} }
for i, c := range p {
r, g, b, _ := c.RGBA()
e.tmp[3*i+0] = uint8(r >> 8)
e.tmp[3*i+1] = uint8(g >> 8)
e.tmp[3*i+2] = uint8(b >> 8)
}
e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
}
func (e *encoder) maybeWritetRNS(p color.Palette) {
last := -1 last := -1
for i, c := range p { for i, c := range p {
_, _, _, a := c.RGBA() c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
if a != 0xffff { e.tmp[3*i+0] = c1.R
e.tmp[3*i+1] = c1.G
e.tmp[3*i+2] = c1.B
if c1.A != 0xff {
last = i last = i
} }
e.tmp[i] = uint8(a >> 8) e.tmp[3*256+i] = c1.A
} }
if last == -1 { e.writeChunk(e.tmp[:3*len(p)], "PLTE")
return if last != -1 {
e.writeChunk(e.tmp[3*256:3*256+1+last], "tRNS")
} }
e.writeChunk(e.tmp[:last+1], "tRNS")
} }
// An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks, // An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
...@@ -412,7 +405,7 @@ func (e *encoder) writeIDATs() { ...@@ -412,7 +405,7 @@ func (e *encoder) writeIDATs() {
e.err = bw.Flush() e.err = bw.Flush()
} }
func (e *encoder) writeIEND() { e.writeChunk(e.tmp[0:0], "IEND") } func (e *encoder) writeIEND() { e.writeChunk(nil, "IEND") }
// Encode writes the Image m to w in PNG format. Any Image may be encoded, but // Encode writes the Image m to w in PNG format. Any Image may be encoded, but
// images that are not image.NRGBA might be encoded lossily. // images that are not image.NRGBA might be encoded lossily.
...@@ -460,8 +453,7 @@ func Encode(w io.Writer, m image.Image) error { ...@@ -460,8 +453,7 @@ func Encode(w io.Writer, m image.Image) error {
_, e.err = io.WriteString(w, pngHeader) _, e.err = io.WriteString(w, pngHeader)
e.writeIHDR() e.writeIHDR()
if pal != nil { if pal != nil {
e.writePLTE(pal) e.writePLTEAndTRNS(pal)
e.maybeWritetRNS(pal)
} }
e.writeIDATs() e.writeIDATs()
e.writeIEND() e.writeIEND()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment