// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package tiff implements a TIFF image decoder and encoder. // // The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf package tiff // import "git.fireandbrimst.one/aw/golang-image/tiff" import ( "compress/zlib" "encoding/binary" "fmt" "image" "image/color" "io" "io/ioutil" "math" "git.fireandbrimst.one/aw/golang-image/tiff/lzw" ) // A FormatError reports that the input is not a valid TIFF image. type FormatError string func (e FormatError) Error() string { return "tiff: invalid format: " + string(e) } // An UnsupportedError reports that the input uses a valid but // unimplemented feature. type UnsupportedError string func (e UnsupportedError) Error() string { return "tiff: unsupported feature: " + string(e) } var errNoPixels = FormatError("not enough pixel data") type decoder struct { r io.ReaderAt byteOrder binary.ByteOrder config image.Config mode imageMode bpp uint features map[int][]uint palette []color.Color buf []byte off int // Current offset in buf. v uint32 // Buffer value for reading with arbitrary bit depths. nbits uint // Remaining number of bits in v. } // firstVal returns the first uint of the features entry with the given tag, // or 0 if the tag does not exist. func (d *decoder) firstVal(tag int) uint { f := d.features[tag] if len(f) == 0 { return 0 } return f[0] } // ifdUint decodes the IFD entry in p, which must be of the Byte, Short // or Long type, and returns the decoded uint values. func (d *decoder) ifdUint(p []byte) (u []uint, err error) { var raw []byte if len(p) < ifdLen { return nil, FormatError("bad IFD entry") } datatype := d.byteOrder.Uint16(p[2:4]) if dt := int(datatype); dt <= 0 || dt >= len(lengths) { return nil, UnsupportedError("IFD entry datatype") } count := d.byteOrder.Uint32(p[4:8]) if count > math.MaxInt32/lengths[datatype] { return nil, FormatError("IFD data too large") } if datalen := lengths[datatype] * count; datalen > 4 { // The IFD contains a pointer to the real value. raw = make([]byte, datalen) _, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12]))) } else { raw = p[8 : 8+datalen] } if err != nil { return nil, err } u = make([]uint, count) switch datatype { case dtByte: for i := uint32(0); i < count; i++ { u[i] = uint(raw[i]) } case dtShort: for i := uint32(0); i < count; i++ { u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)])) } case dtLong: for i := uint32(0); i < count; i++ { u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)])) } default: return nil, UnsupportedError("data type") } return u, nil } // parseIFD decides whether the IFD entry in p is "interesting" and // stows away the data in the decoder. It returns the tag number of the // entry and an error, if any. func (d *decoder) parseIFD(p []byte) (int, error) { tag := d.byteOrder.Uint16(p[0:2]) switch tag { case tBitsPerSample, tExtraSamples, tPhotometricInterpretation, tCompression, tPredictor, tStripOffsets, tStripByteCounts, tRowsPerStrip, tTileWidth, tTileLength, tTileOffsets, tTileByteCounts, tImageLength, tImageWidth: val, err := d.ifdUint(p) if err != nil { return 0, err } d.features[int(tag)] = val case tColorMap: val, err := d.ifdUint(p) if err != nil { return 0, err } numcolors := len(val) / 3 if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 { return 0, FormatError("bad ColorMap length") } d.palette = make([]color.Color, numcolors) for i := 0; i < numcolors; i++ { d.palette[i] = color.RGBA64{ uint16(val[i]), uint16(val[i+numcolors]), uint16(val[i+2*numcolors]), 0xffff, } } case tSampleFormat: // Page 27 of the spec: If the SampleFormat is present and // the value is not 1 [= unsigned integer data], a Baseline // TIFF reader that cannot handle the SampleFormat value // must terminate the import process gracefully. val, err := d.ifdUint(p) if err != nil { return 0, err } for _, v := range val { if v != 1 { return 0, UnsupportedError("sample format") } } } return int(tag), nil } // readBits reads n bits from the internal buffer starting at the current offset. func (d *decoder) readBits(n uint) (v uint32, ok bool) { for d.nbits < n { d.v <<= 8 if d.off >= len(d.buf) { return 0, false } d.v |= uint32(d.buf[d.off]) d.off++ d.nbits += 8 } d.nbits -= n rv := d.v >> d.nbits d.v &^= rv << d.nbits return rv, true } // flushBits discards the unread bits in the buffer used by readBits. // It is used at the end of a line. func (d *decoder) flushBits() { d.v = 0 d.nbits = 0 } // minInt returns the smaller of x or y. func minInt(a, b int) int { if a <= b { return a } return b } // decode decodes the raw data of an image. // It reads from d.buf and writes the strip or tile into dst. func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error { d.off = 0 // 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 { switch d.bpp { case 16: var off int n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel for y := ymin; y < ymax; y++ { off += n for x := 0; x < (xmax-xmin-1)*n; x += 2 { if off+2 > len(d.buf) { return errNoPixels } v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2]) v1 := d.byteOrder.Uint16(d.buf[off : off+2]) d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0) off += 2 } } case 8: var off int n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel for y := ymin; y < ymax; y++ { off += n for x := 0; x < (xmax-xmin-1)*n; x++ { if off >= len(d.buf) { return errNoPixels } d.buf[off] += d.buf[off-n] off++ } } case 1: return UnsupportedError("horizontal predictor with 1 BitsPerSample") } } rMaxX := minInt(xmax, dst.Bounds().Max.X) rMaxY := minInt(ymax, dst.Bounds().Max.Y) switch d.mode { case mGray, mGrayInvert: if d.bpp == 16 { img := dst.(*image.Gray16) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { if d.off+2 > len(d.buf) { return errNoPixels } 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}) } if rMaxX == img.Bounds().Max.X { d.off += 2 * (xmax - img.Bounds().Max.X) } } } else { img := dst.(*image.Gray) max := uint32((1 << d.bpp) - 1) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { v, ok := d.readBits(d.bpp) if !ok { return errNoPixels } v = v * 0xff / max if d.mode == mGrayInvert { v = 0xff - v } img.SetGray(x, y, color.Gray{uint8(v)}) } d.flushBits() } } case mPaletted: img := dst.(*image.Paletted) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { v, ok := d.readBits(d.bpp) if !ok { return errNoPixels } img.SetColorIndex(x, y, uint8(v)) } d.flushBits() } case mRGB: if d.bpp == 16 { img := dst.(*image.RGBA64) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { if d.off+6 > len(d.buf) { return errNoPixels } r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) d.off += 6 img.SetRGBA64(x, y, color.RGBA64{r, g, b, 0xffff}) } } } else { img := dst.(*image.RGBA) for y := ymin; y < rMaxY; y++ { min := img.PixOffset(xmin, y) max := img.PixOffset(rMaxX, y) off := (y - ymin) * (xmax - xmin) * 3 for i := min; i < max; i += 4 { if off+3 > len(d.buf) { return errNoPixels } 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: if d.bpp == 16 { img := dst.(*image.NRGBA64) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { if d.off+8 > len(d.buf) { return errNoPixels } r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8]) d.off += 8 img.SetNRGBA64(x, y, color.NRGBA64{r, g, b, a}) } } } else { img := dst.(*image.NRGBA) for y := ymin; y < rMaxY; y++ { min := img.PixOffset(xmin, y) max := img.PixOffset(rMaxX, y) i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 if i1 > len(d.buf) { return errNoPixels } copy(img.Pix[min:max], d.buf[i0:i1]) } } case mRGBA: if d.bpp == 16 { img := dst.(*image.RGBA64) for y := ymin; y < rMaxY; y++ { for x := xmin; x < rMaxX; x++ { if d.off+8 > len(d.buf) { return errNoPixels } r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2]) g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4]) b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6]) a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8]) d.off += 8 img.SetRGBA64(x, y, color.RGBA64{r, g, b, a}) } } } else { img := dst.(*image.RGBA) for y := ymin; y < rMaxY; y++ { min := img.PixOffset(xmin, y) max := img.PixOffset(rMaxX, y) i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4 if i1 > len(d.buf) { return errNoPixels } copy(img.Pix[min:max], d.buf[i0:i1]) } } } return nil } func newDecoder(r io.Reader) (*decoder, error) { d := &decoder{ r: newReaderAt(r), features: make(map[int][]uint), } p := make([]byte, 8) if _, err := d.r.ReadAt(p, 0); err != nil { return nil, err } switch string(p[0:4]) { case leHeader: d.byteOrder = binary.LittleEndian case beHeader: d.byteOrder = binary.BigEndian default: return nil, FormatError("malformed header") } ifdOffset := int64(d.byteOrder.Uint32(p[4:8])) // The first two bytes contain the number of entries (12 bytes each). if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil { return nil, err } numItems := int(d.byteOrder.Uint16(p[0:2])) // All IFD entries are read in one chunk. p = make([]byte, ifdLen*numItems) if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil { return nil, err } prevTag := -1 for i := 0; i < len(p); i += ifdLen { tag, err := d.parseIFD(p[i : i+ifdLen]) if err != nil { return nil, err } if tag <= prevTag { return nil, FormatError("tags are not sorted in ascending order") } prevTag = tag } d.config.Width = int(d.firstVal(tImageWidth)) d.config.Height = int(d.firstVal(tImageLength)) if _, ok := d.features[tBitsPerSample]; !ok { return nil, FormatError("BitsPerSample tag missing") } d.bpp = d.firstVal(tBitsPerSample) switch d.bpp { case 0: return nil, FormatError("BitsPerSample must not be 0") case 1, 8, 16: // Nothing to do, these are accepted by this implementation. default: return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp)) } // Determine the image mode. switch d.firstVal(tPhotometricInterpretation) { case pRGB: if d.bpp == 16 { for _, b := range d.features[tBitsPerSample] { if b != 16 { return nil, FormatError("wrong number of samples for 16bit RGB") } } } else { for _, b := range d.features[tBitsPerSample] { if b != 8 { return nil, FormatError("wrong number of samples for 8bit RGB") } } } // RGB images normally have 3 samples per pixel. // If there are more, ExtraSamples (p. 31-32 of the spec) // gives their meaning (usually an alpha channel). // // This implementation does not support extra samples // of an unspecified type. switch len(d.features[tBitsPerSample]) { case 3: d.mode = mRGB if d.bpp == 16 { d.config.ColorModel = color.RGBA64Model } else { d.config.ColorModel = color.RGBAModel } case 4: switch d.firstVal(tExtraSamples) { case 1: d.mode = mRGBA if d.bpp == 16 { d.config.ColorModel = color.RGBA64Model } else { d.config.ColorModel = color.RGBAModel } case 2: d.mode = mNRGBA if d.bpp == 16 { d.config.ColorModel = color.NRGBA64Model } else { d.config.ColorModel = color.NRGBAModel } default: return nil, FormatError("wrong number of samples for RGB") } default: return nil, FormatError("wrong number of samples for RGB") } case pPaletted: d.mode = mPaletted d.config.ColorModel = color.Palette(d.palette) case pWhiteIsZero: d.mode = mGrayInvert if d.bpp == 16 { d.config.ColorModel = color.Gray16Model } else { d.config.ColorModel = color.GrayModel } case pBlackIsZero: d.mode = mGray if d.bpp == 16 { d.config.ColorModel = color.Gray16Model } else { d.config.ColorModel = color.GrayModel } default: return nil, UnsupportedError("color model") } return d, nil } // DecodeConfig returns the color model and dimensions of a TIFF image without // decoding the entire image. func DecodeConfig(r io.Reader) (image.Config, error) { d, err := newDecoder(r) if err != nil { return image.Config{}, err } return d.config, nil } // Decode reads a TIFF image from r and returns it as an image.Image. // The type of Image returned depends on the contents of the TIFF. func Decode(r io.Reader) (img image.Image, err error) { d, err := newDecoder(r) if err != nil { return } blockPadding := false blockWidth := d.config.Width blockHeight := d.config.Height blocksAcross := 1 blocksDown := 1 if d.config.Width == 0 { blocksAcross = 0 } if d.config.Height == 0 { blocksDown = 0 } var blockOffsets, blockCounts []uint if int(d.firstVal(tTileWidth)) != 0 { blockPadding = true blockWidth = int(d.firstVal(tTileWidth)) blockHeight = int(d.firstVal(tTileLength)) if blockWidth != 0 { blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth } if blockHeight != 0 { blocksDown = (d.config.Height + blockHeight - 1) / blockHeight } blockCounts = d.features[tTileByteCounts] blockOffsets = d.features[tTileOffsets] } else { if int(d.firstVal(tRowsPerStrip)) != 0 { blockHeight = int(d.firstVal(tRowsPerStrip)) } if blockHeight != 0 { blocksDown = (d.config.Height + blockHeight - 1) / blockHeight } blockOffsets = d.features[tStripOffsets] blockCounts = d.features[tStripByteCounts] } // Check if we have the right number of strips/tiles, offsets and counts. if n := blocksAcross * blocksDown; len(blockOffsets) < n || len(blockCounts) < n { return nil, FormatError("inconsistent header") } imgRect := image.Rect(0, 0, d.config.Width, d.config.Height) switch d.mode { case mGray, mGrayInvert: if d.bpp == 16 { img = image.NewGray16(imgRect) } else { img = image.NewGray(imgRect) } case mPaletted: img = image.NewPaletted(imgRect, d.palette) case mNRGBA: if d.bpp == 16 { img = image.NewNRGBA64(imgRect) } else { img = image.NewNRGBA(imgRect) } case mRGB, mRGBA: if d.bpp == 16 { img = image.NewRGBA64(imgRect) } else { img = image.NewRGBA(imgRect) } } for i := 0; i < blocksAcross; i++ { blkW := blockWidth if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 { blkW = d.config.Width % blockWidth } for j := 0; j < blocksDown; j++ { blkH := blockHeight if !blockPadding && j == blocksDown-1 && d.config.Height%blockHeight != 0 { blkH = d.config.Height % blockHeight } offset := int64(blockOffsets[j*blocksAcross+i]) n := int64(blockCounts[j*blocksAcross+i]) switch d.firstVal(tCompression) { // According to the spec, Compression does not have a default value, // but some tools interpret a missing Compression value as none so we do // the same. case cNone, 0: if b, ok := d.r.(*buffer); ok { d.buf, err = b.Slice(int(offset), int(n)) } else { d.buf = make([]byte, n) _, err = d.r.ReadAt(d.buf, offset) } case cLZW: r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8) d.buf, err = ioutil.ReadAll(r) r.Close() case cDeflate, cDeflateOld: var r io.ReadCloser r, err = zlib.NewReader(io.NewSectionReader(d.r, offset, n)) if err != nil { return nil, err } d.buf, err = ioutil.ReadAll(r) r.Close() case cPackBits: d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n)) default: err = UnsupportedError(fmt.Sprintf("compression value %d", d.firstVal(tCompression))) } if err != nil { return nil, err } xmin := i * blockWidth ymin := j * blockHeight xmax := xmin + blkW ymax := ymin + blkH err = d.decode(img, xmin, ymin, xmax, ymax) if err != nil { return nil, err } } } return } func init() { image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig) image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig) }