diff options
Diffstat (limited to 'libgo/go/image/png/reader.go')
-rw-r--r-- | libgo/go/image/png/reader.go | 266 |
1 files changed, 212 insertions, 54 deletions
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go index 2dd5ed80736..32f78f0ffe8 100644 --- a/libgo/go/image/png/reader.go +++ b/libgo/go/image/png/reader.go @@ -113,6 +113,11 @@ type decoder struct { idatLength uint32 tmp [3 * 256]byte interlace int + + // useTransparent and transparent are used for grayscale and truecolor + // transparency, as opposed to palette transparency. + useTransparent bool + transparent [6]byte } // A FormatError reports that the input is not a valid PNG. @@ -252,20 +257,51 @@ func (d *decoder) parsePLTE(length uint32) error { } func (d *decoder) parsetRNS(length uint32) error { - if length > 256 { - return FormatError("bad tRNS length") - } - n, err := io.ReadFull(d.r, d.tmp[:length]) - if err != nil { - return err - } - d.crc.Write(d.tmp[:n]) switch d.cb { - case cbG8, cbG16: - return UnsupportedError("grayscale transparency") + case cbG1, cbG2, cbG4, cbG8, cbG16: + if length != 2 { + return FormatError("bad tRNS length") + } + n, err := io.ReadFull(d.r, d.tmp[:length]) + if err != nil { + return err + } + d.crc.Write(d.tmp[:n]) + + copy(d.transparent[:], d.tmp[:length]) + switch d.cb { + case cbG1: + d.transparent[1] *= 0xff + case cbG2: + d.transparent[1] *= 0x55 + case cbG4: + d.transparent[1] *= 0x11 + } + d.useTransparent = true + case cbTC8, cbTC16: - return UnsupportedError("truecolor transparency") + if length != 6 { + return FormatError("bad tRNS length") + } + n, err := io.ReadFull(d.r, d.tmp[:length]) + if err != nil { + return err + } + d.crc.Write(d.tmp[:n]) + + copy(d.transparent[:], d.tmp[:length]) + d.useTransparent = true + case cbP1, cbP2, cbP4, cbP8: + if length > 256 { + return FormatError("bad tRNS length") + } + n, err := io.ReadFull(d.r, d.tmp[:length]) + if err != nil { + return err + } + d.crc.Write(d.tmp[:n]) + if len(d.palette) < n { d.palette = d.palette[:n] } @@ -273,7 +309,8 @@ func (d *decoder) parsetRNS(length uint32) error { rgba := d.palette[i].(color.RGBA) d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]} } - case cbGA8, cbGA16, cbTCA8, cbTCA16: + + default: return FormatError("tRNS, color type mismatch") } return d.verifyChecksum() @@ -366,7 +403,7 @@ func (d *decoder) decode() (image.Image, error) { // readImagePass reads a single image pass, sized according to the pass number. func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) { - var bitsPerPixel int = 0 + bitsPerPixel := 0 pixOffset := 0 var ( gray *image.Gray @@ -394,16 +431,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image switch d.cb { case cbG1, cbG2, cbG4, cbG8: bitsPerPixel = d.depth - gray = image.NewGray(image.Rect(0, 0, width, height)) - img = gray + if d.useTransparent { + nrgba = image.NewNRGBA(image.Rect(0, 0, width, height)) + img = nrgba + } else { + gray = image.NewGray(image.Rect(0, 0, width, height)) + img = gray + } case cbGA8: bitsPerPixel = 16 nrgba = image.NewNRGBA(image.Rect(0, 0, width, height)) img = nrgba case cbTC8: bitsPerPixel = 24 - rgba = image.NewRGBA(image.Rect(0, 0, width, height)) - img = rgba + if d.useTransparent { + nrgba = image.NewNRGBA(image.Rect(0, 0, width, height)) + img = nrgba + } else { + rgba = image.NewRGBA(image.Rect(0, 0, width, height)) + img = rgba + } case cbP1, cbP2, cbP4, cbP8: bitsPerPixel = d.depth paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette) @@ -414,16 +461,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image img = nrgba case cbG16: bitsPerPixel = 16 - gray16 = image.NewGray16(image.Rect(0, 0, width, height)) - img = gray16 + if d.useTransparent { + nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height)) + img = nrgba64 + } else { + gray16 = image.NewGray16(image.Rect(0, 0, width, height)) + img = gray16 + } case cbGA16: bitsPerPixel = 32 nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height)) img = nrgba64 case cbTC16: bitsPerPixel = 48 - rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height)) - img = rgba64 + if d.useTransparent { + nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height)) + img = nrgba64 + } else { + rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height)) + img = rgba64 + } case cbTCA16: bitsPerPixel = 64 nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height)) @@ -483,27 +540,75 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image // Convert from bytes to colors. switch d.cb { case cbG1: - for x := 0; x < width; x += 8 { - b := cdat[x/8] - for x2 := 0; x2 < 8 && x+x2 < width; x2++ { - gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff}) - b <<= 1 + if d.useTransparent { + ty := d.transparent[1] + for x := 0; x < width; x += 8 { + b := cdat[x/8] + for x2 := 0; x2 < 8 && x+x2 < width; x2++ { + ycol := (b >> 7) * 0xff + acol := uint8(0xff) + if ycol == ty { + acol = 0x00 + } + nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol}) + b <<= 1 + } + } + } else { + for x := 0; x < width; x += 8 { + b := cdat[x/8] + for x2 := 0; x2 < 8 && x+x2 < width; x2++ { + gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff}) + b <<= 1 + } } } case cbG2: - for x := 0; x < width; x += 4 { - b := cdat[x/4] - for x2 := 0; x2 < 4 && x+x2 < width; x2++ { - gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55}) - b <<= 2 + if d.useTransparent { + ty := d.transparent[1] + for x := 0; x < width; x += 4 { + b := cdat[x/4] + for x2 := 0; x2 < 4 && x+x2 < width; x2++ { + ycol := (b >> 6) * 0x55 + acol := uint8(0xff) + if ycol == ty { + acol = 0x00 + } + nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol}) + b <<= 2 + } + } + } else { + for x := 0; x < width; x += 4 { + b := cdat[x/4] + for x2 := 0; x2 < 4 && x+x2 < width; x2++ { + gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55}) + b <<= 2 + } } } case cbG4: - for x := 0; x < width; x += 2 { - b := cdat[x/2] - for x2 := 0; x2 < 2 && x+x2 < width; x2++ { - gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11}) - b <<= 4 + if d.useTransparent { + ty := d.transparent[1] + for x := 0; x < width; x += 2 { + b := cdat[x/2] + for x2 := 0; x2 < 2 && x+x2 < width; x2++ { + ycol := (b >> 4) * 0x11 + acol := uint8(0xff) + if ycol == ty { + acol = 0x00 + } + nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol}) + b <<= 4 + } + } + } else { + for x := 0; x < width; x += 2 { + b := cdat[x/2] + for x2 := 0; x2 < 2 && x+x2 < width; x2++ { + gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11}) + b <<= 4 + } } } case cbG8: @@ -515,16 +620,37 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]}) } case cbTC8: - pix, i, j := rgba.Pix, pixOffset, 0 - for x := 0; x < width; x++ { - pix[i+0] = cdat[j+0] - pix[i+1] = cdat[j+1] - pix[i+2] = cdat[j+2] - pix[i+3] = 0xff - i += 4 - j += 3 + if d.useTransparent { + pix, i, j := nrgba.Pix, pixOffset, 0 + tr, tg, tb := d.transparent[1], d.transparent[3], d.transparent[5] + for x := 0; x < width; x++ { + r := cdat[j+0] + g := cdat[j+1] + b := cdat[j+2] + a := uint8(0xff) + if r == tr && g == tg && b == tb { + a = 0x00 + } + pix[i+0] = r + pix[i+1] = g + pix[i+2] = b + pix[i+3] = a + i += 4 + j += 3 + } + pixOffset += nrgba.Stride + } else { + pix, i, j := rgba.Pix, pixOffset, 0 + for x := 0; x < width; x++ { + pix[i+0] = cdat[j+0] + pix[i+1] = cdat[j+1] + pix[i+2] = cdat[j+2] + pix[i+3] = 0xff + i += 4 + j += 3 + } + pixOffset += rgba.Stride } - pixOffset += rgba.Stride case cbP1: for x := 0; x < width; x += 8 { b := cdat[x/8] @@ -575,9 +701,21 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image copy(nrgba.Pix[pixOffset:], cdat) pixOffset += nrgba.Stride case cbG16: - for x := 0; x < width; x++ { - ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1]) - gray16.SetGray16(x, y, color.Gray16{ycol}) + if d.useTransparent { + ty := uint16(d.transparent[0])<<8 | uint16(d.transparent[1]) + for x := 0; x < width; x++ { + ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1]) + acol := uint16(0xffff) + if ycol == ty { + acol = 0x0000 + } + nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol}) + } + } else { + for x := 0; x < width; x++ { + ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1]) + gray16.SetGray16(x, y, color.Gray16{ycol}) + } } case cbGA16: for x := 0; x < width; x++ { @@ -586,11 +724,27 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol}) } case cbTC16: - for x := 0; x < width; x++ { - rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1]) - gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3]) - bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5]) - rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff}) + if d.useTransparent { + tr := uint16(d.transparent[0])<<8 | uint16(d.transparent[1]) + tg := uint16(d.transparent[2])<<8 | uint16(d.transparent[3]) + tb := uint16(d.transparent[4])<<8 | uint16(d.transparent[5]) + for x := 0; x < width; x++ { + rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1]) + gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3]) + bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5]) + acol := uint16(0xffff) + if rcol == tr && gcol == tg && bcol == tb { + acol = 0x0000 + } + nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol}) + } + } else { + for x := 0; x < width; x++ { + rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1]) + gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3]) + bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5]) + rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff}) + } } case cbTCA16: for x := 0; x < width; x++ { @@ -709,7 +863,11 @@ func (d *decoder) parseChunk() error { d.stage = dsSeenPLTE return d.parsePLTE(length) case "tRNS": - if d.stage != dsSeenPLTE { + if cbPaletted(d.cb) { + if d.stage != dsSeenPLTE { + return chunkOrderError + } + } else if d.stage != dsSeenIHDR { return chunkOrderError } d.stage = dsSeentRNS |