blob: 26e52144d468692d9350f0595839f8e8ef4d475d [file] [log] [blame]
// 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.
//
// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
package tiff
import (
"compress/lzw"
"compress/zlib"
"encoding/binary"
"image"
"io"
"io/ioutil"
"os"
)
// A FormatError reports that the input is not a valid TIFF image.
type FormatError string
func (e FormatError) String() 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) String() string {
return "tiff: unsupported feature: " + string(e)
}
// An InternalError reports that an internal error was encountered.
type InternalError string
func (e InternalError) String() string {
return "tiff: internal error: " + string(e)
}
type decoder struct {
r io.ReaderAt
byteOrder binary.ByteOrder
config image.Config
mode imageMode
features map[int][]uint
palette []image.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 os.Error) {
var raw []byte
datatype := d.byteOrder.Uint16(p[2:4])
count := d.byteOrder.Uint32(p[4:8])
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 the IFD entry in p is "interesting" and
// stows away the data in the decoder.
func (d *decoder) parseIFD(p []byte) os.Error {
tag := d.byteOrder.Uint16(p[0:2])
switch tag {
case tBitsPerSample,
tExtraSamples,
tPhotometricInterpretation,
tCompression,
tPredictor,
tStripOffsets,
tStripByteCounts,
tRowsPerStrip,
tImageLength,
tImageWidth:
val, err := d.ifdUint(p)
if err != nil {
return err
}
d.features[int(tag)] = val
case tColorMap:
val, err := d.ifdUint(p)
if err != nil {
return err
}
numcolors := len(val) / 3
if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
return FormatError("bad ColorMap length")
}
d.palette = make([]image.Color, numcolors)
for i := 0; i < numcolors; i++ {
d.palette[i] = image.RGBA64Color{
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 err
}
for _, v := range val {
if v != 1 {
return UnsupportedError("sample format")
}
}
}
return nil
}
// readBits reads n bits from the internal buffer starting at the current offset.
func (d *decoder) readBits(n uint) uint32 {
for d.nbits < n {
d.v <<= 8
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
}
// 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
}
// decode decodes the raw data of an image.
// 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 {
spp := len(d.features[tBitsPerSample]) // samples per pixel
d.off = 0
width := dst.Bounds().Dx()
// 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 {
for y := ymin; y < ymax; y++ {
d.off += spp
for x := 0; x < (width-1)*spp; x++ {
d.buf[d.off] += d.buf[d.off-spp]
d.off++
}
}
d.off = 0
}
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
}
img.SetGray(x, y, image.GrayColor{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)))
}
d.flushBits()
}
case mRGB:
img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], 0xff})
d.off += spp
}
}
case mNRGBA:
img := dst.(*image.NRGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
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]})
d.off += spp
}
}
case mRGBA:
img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
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]})
d.off += spp
}
}
}
return nil
}
func newDecoder(r io.Reader) (*decoder, os.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
}
for i := 0; i < len(p); i += ifdLen {
if err := d.parseIFD(p[i : i+ifdLen]); err != nil {
return nil, err
}
}
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")
}
// Determine the image mode.
switch d.firstVal(tPhotometricInterpretation) {
case pRGB:
for _, b := range d.features[tBitsPerSample] {
if b != 8 {
return nil, UnsupportedError("non-8-bit RGB image")
}
}
d.config.ColorModel = image.RGBAColorModel
// 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).
switch len(d.features[tBitsPerSample]) {
case 3:
d.mode = mRGB
case 4:
switch d.firstVal(tExtraSamples) {
case 1:
d.mode = mRGBA
case 2:
d.mode = mNRGBA
d.config.ColorModel = image.NRGBAColorModel
default:
// The extra sample is discarded.
d.mode = mRGB
}
default:
return nil, FormatError("wrong number of samples for RGB")
}
case pPaletted:
d.mode = mPaletted
d.config.ColorModel = image.PalettedColorModel(d.palette)
case pWhiteIsZero:
d.mode = mGrayInvert
d.config.ColorModel = image.GrayColorModel
case pBlackIsZero:
d.mode = mGray
d.config.ColorModel = image.GrayColorModel
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, os.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 os.Error) {
d, err := newDecoder(r)
if err != nil {
return
}
// Check if we have the right number of strips, offsets and counts.
rps := int(d.firstVal(tRowsPerStrip))
numStrips := (d.config.Height + rps - 1) / rps
if rps == 0 || len(d.features[tStripOffsets]) < numStrips || len(d.features[tStripByteCounts]) < numStrips {
return nil, FormatError("inconsistent header")
}
switch d.mode {
case mGray, mGrayInvert:
img = image.NewGray(d.config.Width, d.config.Height)
case mPaletted:
img = image.NewPaletted(d.config.Width, d.config.Height, d.palette)
case mNRGBA:
img = image.NewNRGBA(d.config.Width, d.config.Height)
case mRGB, mRGBA:
img = image.NewRGBA(d.config.Width, d.config.Height)
}
for i := 0; i < numStrips; i++ {
ymin := i * rps
// The last strip may be shorter.
if i == numStrips-1 && d.config.Height%rps != 0 {
rps = d.config.Height % rps
}
offset := int64(d.features[tStripOffsets][i])
n := int64(d.features[tStripByteCounts][i])
switch d.firstVal(tCompression) {
case cNone:
// TODO(bsiegert): Avoid copy if r is a tiff.buffer.
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:
r, err := zlib.NewReader(io.NewSectionReader(d.r, offset, n))
if err != nil {
return nil, err
}
d.buf, err = ioutil.ReadAll(r)
r.Close()
default:
err = UnsupportedError("compression")
}
if err != nil {
return
}
err = d.decode(img, ymin, ymin+rps)
}
return
}
func init() {
image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
}