Commit 64c9c7f5 authored by Benny Siegert's avatar Benny Siegert Committed by Nigel Tao

image/tiff: decoder optimization.

Write to image.*.Pix directly in the case of RGB, RGBA and NRGBA
images. For the latter two, the file format matches the memory layout
so a simple copy can be used.

RGB image before/after:
tiff.BenchmarkDecoder	748137 ns/op (62.39 MB/s)	251256 ns/op (185.76 MB/s)	x3.0

NRGBA image before/after:
tiff.BenchmarkDecoder	775540 ns/op (80.12 MB/s)	116721 ns/op (532.34 MB/s)	x6.6

R=nigeltao
CC=golang-dev
https://golang.org/cl/4929046
parent f172338a
...@@ -180,22 +180,21 @@ func (d *decoder) flushBits() { ...@@ -180,22 +180,21 @@ func (d *decoder) flushBits() {
// decode decodes the raw data of an image. // decode decodes the raw data of an image.
// It reads from d.buf and writes the strip with ymin <= y < ymax into dst. // It reads from d.buf and writes the strip with ymin <= y < ymax into dst.
func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error { func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error {
spp := len(d.features[tBitsPerSample]) // samples per pixel
d.off = 0 d.off = 0
width := dst.Bounds().Dx()
// Apply horizontal predictor if necessary. // Apply horizontal predictor if necessary.
// In this case, p contains the color difference to the preceding pixel. // In this case, p contains the color difference to the preceding pixel.
// See page 64-65 of the spec. // See page 64-65 of the spec.
if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 { if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
var off int
spp := len(d.features[tBitsPerSample]) // samples per pixel
for y := ymin; y < ymax; y++ { for y := ymin; y < ymax; y++ {
d.off += spp off += spp
for x := 0; x < (width-1)*spp; x++ { for x := 0; x < (dst.Bounds().Dx()-1)*spp; x++ {
d.buf[d.off] += d.buf[d.off-spp] d.buf[off] += d.buf[off-spp]
d.off++ off++
} }
} }
d.off = 0
} }
switch d.mode { switch d.mode {
...@@ -224,28 +223,32 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error { ...@@ -224,28 +223,32 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error {
} }
case mRGB: case mRGB:
img := dst.(*image.RGBA) img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ { min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ { max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], 0xff}) var off int
d.off += spp for i := min; i < max; i += 4 {
} img.Pix[i+0] = d.buf[off+0]
img.Pix[i+1] = d.buf[off+1]
img.Pix[i+2] = d.buf[off+2]
img.Pix[i+3] = 0xff
off += 3
} }
case mNRGBA: case mNRGBA:
img := dst.(*image.NRGBA) img := dst.(*image.NRGBA)
for y := ymin; y < ymax; y++ { min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ { max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
img.SetNRGBA(x, y, image.NRGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]}) if len(d.buf) != max-min {
d.off += spp return FormatError("short data strip")
}
} }
copy(img.Pix[min:max], d.buf)
case mRGBA: case mRGBA:
img := dst.(*image.RGBA) img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ { min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ { max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]}) if len(d.buf) != max-min {
d.off += spp return FormatError("short data strip")
}
} }
copy(img.Pix[min:max], d.buf)
} }
return nil return nil
...@@ -309,6 +312,9 @@ func newDecoder(r io.Reader) (*decoder, os.Error) { ...@@ -309,6 +312,9 @@ func newDecoder(r io.Reader) (*decoder, os.Error) {
// RGB images normally have 3 samples per pixel. // RGB images normally have 3 samples per pixel.
// If there are more, ExtraSamples (p. 31-32 of the spec) // If there are more, ExtraSamples (p. 31-32 of the spec)
// gives their meaning (usually an alpha channel). // gives their meaning (usually an alpha channel).
//
// This implementation does not support extra samples
// of an unspecified type.
switch len(d.features[tBitsPerSample]) { switch len(d.features[tBitsPerSample]) {
case 3: case 3:
d.mode = mRGB d.mode = mRGB
...@@ -320,8 +326,7 @@ func newDecoder(r io.Reader) (*decoder, os.Error) { ...@@ -320,8 +326,7 @@ func newDecoder(r io.Reader) (*decoder, os.Error) {
d.mode = mNRGBA d.mode = mNRGBA
d.config.ColorModel = image.NRGBAColorModel d.config.ColorModel = image.NRGBAColorModel
default: default:
// The extra sample is discarded. return nil, FormatError("wrong number of samples for RGB")
d.mode = mRGB
} }
default: default:
return nil, FormatError("wrong number of samples for RGB") return nil, FormatError("wrong number of samples for RGB")
......
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