git clone https://git.lucas.co/go_mono.git
go.image/tiff: Support reading 16-bit gray images.
Fixes golang/go#5866.
R=nigeltao
CC=golang-dev
https://golang.org/cl/11920043
tiff/reader.go | 65 +++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 46 insertions(+), 19 deletions(-)
diff --git a/tiff/reader.go b/tiff/reader.go
index 0603b1e..d64aa59 100644
--- a/tiff/reader.go
+++ b/tiff/reader.go
@@ -44,6 +44,7 @@ type decoder struct {
byteOrder binary.ByteOrder
config image.Config
mode imageMode
+ bpp uint
features map[int][]uint
palette []color.Color
@@ -185,7 +186,7 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
// Apply horizontal predictor if necessary.
// In this case, p contains the color difference to the preceding pixel.
// See page 64-65 of the spec.
- if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
+ if d.firstVal(tPredictor) == prHorizontal && d.bpp == 8 {
var off int
spp := len(d.features[tBitsPerSample]) // samples per pixel
for y := ymin; y < ymax; y++ {
@@ -199,25 +200,37 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
switch d.mode {
case mGray, mGrayInvert:
- img := dst.(*image.Gray)
- bpp := d.firstVal(tBitsPerSample)
- max := uint32((1 << bpp) - 1)
- for y := ymin; y < ymax; y++ {
- for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- v := uint8(d.readBits(bpp) * 0xff / max)
- if d.mode == mGrayInvert {
- v = 0xff - v
+ if d.bpp == 16 {
+ img := dst.(*image.Gray16)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ v := d.byteOrder.Uint16(d.buf[d.off : d.off+2])
+ d.off += 2
+ if d.mode == mGrayInvert {
+ v = 0xffff - v
+ }
+ img.SetGray16(x, y, color.Gray16{v})
}
- img.SetGray(x, y, color.Gray{v})
}
- d.flushBits()
+ } else {
+ img := dst.(*image.Gray)
+ max := uint32((1 << d.bpp) - 1)
+ for y := ymin; y < ymax; y++ {
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ v := uint8(d.readBits(d.bpp) * 0xff / max)
+ if d.mode == mGrayInvert {
+ v = 0xff - v
+ }
+ img.SetGray(x, y, color.Gray{v})
+ }
+ d.flushBits()
+ }
}
case mPaletted:
img := dst.(*image.Paletted)
- bpp := d.firstVal(tBitsPerSample)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.SetColorIndex(x, y, uint8(d.readBits(bpp)))
+ img.SetColorIndex(x, y, uint8(d.readBits(d.bpp)))
}
d.flushBits()
}
@@ -299,6 +312,7 @@ func newDecoder(r io.Reader) (*decoder, error) {
if _, ok := d.features[tBitsPerSample]; !ok {
return nil, FormatError("BitsPerSample tag missing")
}
+ d.bpp = d.firstVal(tBitsPerSample)
// Determine the image mode.
switch d.firstVal(tPhotometricInterpretation) {
@@ -336,10 +350,18 @@ func newDecoder(r io.Reader) (*decoder, error) {
d.config.ColorModel = color.Palette(d.palette)
case pWhiteIsZero:
d.mode = mGrayInvert
- d.config.ColorModel = color.GrayModel
+ if d.bpp == 16 {
+ d.config.ColorModel = color.Gray16Model
+ } else {
+ d.config.ColorModel = color.GrayModel
+ }
case pBlackIsZero:
d.mode = mGray
- d.config.ColorModel = color.GrayModel
+ if d.bpp == 16 {
+ d.config.ColorModel = color.Gray16Model
+ } else {
+ d.config.ColorModel = color.GrayModel
+ }
default:
return nil, UnsupportedError("color model")
}
@@ -376,15 +398,20 @@ func Decode(r io.Reader) (img image.Image, err error) {
return nil, FormatError("inconsistent header")
}
+ imgRect := image.Rect(0, 0, d.config.Width, d.config.Height)
switch d.mode {
case mGray, mGrayInvert:
- img = image.NewGray(image.Rect(0, 0, d.config.Width, d.config.Height))
+ if d.bpp == 16 {
+ img = image.NewGray16(imgRect)
+ } else {
+ img = image.NewGray(imgRect)
+ }
case mPaletted:
- img = image.NewPaletted(image.Rect(0, 0, d.config.Width, d.config.Height), d.palette)
+ img = image.NewPaletted(imgRect, d.palette)
case mNRGBA:
- img = image.NewNRGBA(image.Rect(0, 0, d.config.Width, d.config.Height))
+ img = image.NewNRGBA(imgRect)
case mRGB, mRGBA:
- img = image.NewRGBA(image.Rect(0, 0, d.config.Width, d.config.Height))
+ img = image.NewRGBA(imgRect)
}
for i := 0; i < numStrips; i++ {