Commit 737e96c7 authored by Dmitry Chestnykh's avatar Dmitry Chestnykh Committed by Nigel Tao

image/png: support encoding of paletted images with alpha channel.

Encoder now writes tRNS chunk for non-opaque paletted images.
CL includes new test images (basn3a08-trns.[ps]ng).

R=nigeltao, rsc, r
CC=golang-dev
https://golang.org/cl/4432078
parent bcf3bfe2
...@@ -28,6 +28,7 @@ var filenames = []string{ ...@@ -28,6 +28,7 @@ var filenames = []string{
"basn3p02", "basn3p02",
"basn3p04", "basn3p04",
"basn3p08", "basn3p08",
"basn3p08-trns",
"basn4a08", "basn4a08",
"basn4a16", "basn4a16",
"basn6a08", "basn6a08",
...@@ -98,17 +99,30 @@ func sng(w io.WriteCloser, filename string, png image.Image) { ...@@ -98,17 +99,30 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
// (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder"). // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
io.WriteString(w, "gAMA {1.0000}\n") io.WriteString(w, "gAMA {1.0000}\n")
// Write the PLTE (if applicable). // Write the PLTE and tRNS (if applicable).
if cpm != nil { if cpm != nil {
lastAlpha := -1
io.WriteString(w, "PLTE {\n") io.WriteString(w, "PLTE {\n")
for i := 0; i < len(cpm); i++ { for i, c := range cpm {
r, g, b, _ := cpm[i].RGBA() r, g, b, a := c.RGBA()
if a != 0xffff {
lastAlpha = i
}
r >>= 8 r >>= 8
g >>= 8 g >>= 8
b >>= 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")
if lastAlpha != -1 {
io.WriteString(w, "tRNS {\n")
for i := 0; i <= lastAlpha; i++ {
_, _, _, a := cpm[i].RGBA()
a >>= 8
fmt.Fprintf(w, " %d", a)
}
io.WriteString(w, "}\n")
}
} }
// Write the IMAGE. // Write the IMAGE.
......
...@@ -10,6 +10,9 @@ The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact ...@@ -10,6 +10,9 @@ The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact
not part of pngsuite but were created from files in pngsuite. Their non-power- not part of pngsuite but were created from files in pngsuite. Their non-power-
of-two sizes makes them useful for testing bit-depths smaller than a byte. of-two sizes makes them useful for testing bit-depths smaller than a byte.
basn3a08.png was generated from basn6a08.png using the pngnq tool, which
converted it to the 8-bit paletted image with alpha values in tRNS chunk.
The *.sng files in this directory were generated from the *.png files The *.sng files in this directory were generated from the *.png files
by the sng command-line tool and some hand editing. The files by the sng command-line tool and some hand editing. The files
basn0g0{1,2,4}.sng were actually generated by first converting the PNG basn0g0{1,2,4}.sng were actually generated by first converting the PNG
......
This diff is collapsed.
...@@ -130,12 +130,8 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) { ...@@ -130,12 +130,8 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) {
e.err = FormatError("bad palette length: " + strconv.Itoa(len(p))) e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
return return
} }
for i := 0; i < len(p); i++ { for i, c := range p {
r, g, b, a := p[i].RGBA() r, g, b, _ := c.RGBA()
if a != 0xffff {
e.err = UnsupportedError("non-opaque palette color")
return
}
e.tmp[3*i+0] = uint8(r >> 8) e.tmp[3*i+0] = uint8(r >> 8)
e.tmp[3*i+1] = uint8(g >> 8) e.tmp[3*i+1] = uint8(g >> 8)
e.tmp[3*i+2] = uint8(b >> 8) e.tmp[3*i+2] = uint8(b >> 8)
...@@ -143,6 +139,21 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) { ...@@ -143,6 +139,21 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) {
e.writeChunk(e.tmp[0:3*len(p)], "PLTE") e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
} }
func (e *encoder) maybeWritetRNS(p image.PalettedColorModel) {
last := -1
for i, c := range p {
_, _, _, a := c.RGBA()
if a != 0xffff {
last = i
}
e.tmp[i] = uint8(a >> 8)
}
if last == -1 {
return
}
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,
// including an 8-byte header and 4-byte CRC checksum per Write call. Such calls // including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
// should be relatively infrequent, since writeIDATs uses a bufio.Writer. // should be relatively infrequent, since writeIDATs uses a bufio.Writer.
...@@ -447,6 +458,7 @@ func Encode(w io.Writer, m image.Image) os.Error { ...@@ -447,6 +458,7 @@ func Encode(w io.Writer, m image.Image) os.Error {
e.writeIHDR() e.writeIHDR()
if pal != nil { if pal != nil {
e.writePLTE(pal.Palette) e.writePLTE(pal.Palette)
e.maybeWritetRNS(pal.Palette)
} }
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