git.lucas.co / go_mono
git clone https://git.lucas.co/go_mono.git

commit26936f55904a9d5e8d0327ec2753f1bb3209e613
parentd165204442
authorBenny Siegert <bsiegert@gmail.com>
date2013-07-30 15:02
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++ {