git clone https://git.lucas.co/go_mono.git
go.image/tiff: simplify encoding.
R=bsiegert
CC=golang-dev
https://golang.org/cl/5738044
tiff/writer.go | 108 +++++++++++++++++++++------------------------------------
1 file changed, 40 insertions(+), 68 deletions(-)
diff --git a/tiff/writer.go b/tiff/writer.go
index c3d71e9..9c8b893 100644
--- a/tiff/writer.go
+++ b/tiff/writer.go
@@ -47,63 +47,19 @@ func (e ifdEntry) putData(p []byte) {
}
}
-type ifd []ifdEntry
+type byTag []ifdEntry
-func (d ifd) Len() int {
- return len(d)
-}
-
-func (d ifd) Less(i, j int) bool {
- return d[i].tag < d[j].tag
-}
-
-func (d ifd) Swap(i, j int) {
- d[i], d[j] = d[j], d[i]
-}
-
-type encoder struct {
- ifd ifd
- img image.Image
- imageLen int // Length of the image in bytes.
-}
-
-func newEncoder(m image.Image) *encoder {
- width := m.Bounds().Dx()
- height := m.Bounds().Dy()
- imageLen := width * height * 4
- return &encoder{
- img: m,
- // For uncompressed images, imageLen is known in advance.
- // For compressed images, we would need to write the image
- // data in a buffer here to get its length.
- imageLen: imageLen,
- ifd: ifd{
- {tImageWidth, dtShort, []uint32{uint32(width)}},
- {tImageLength, dtShort, []uint32{uint32(height)}},
- {tBitsPerSample, dtShort, []uint32{8, 8, 8, 8}},
- {tCompression, dtShort, []uint32{cNone}},
- {tPhotometricInterpretation, dtShort, []uint32{pRGB}},
- {tStripOffsets, dtLong, []uint32{8}},
- {tSamplesPerPixel, dtShort, []uint32{4}},
- {tRowsPerStrip, dtShort, []uint32{uint32(height)}},
- {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
- // There is currently no support for storing the image
- // resolution, so give a bogus value of 72x72 dpi.
- {tXResolution, dtRational, []uint32{72, 1}},
- {tYResolution, dtRational, []uint32{72, 1}},
- {tResolutionUnit, dtShort, []uint32{resPerInch}},
- {tExtraSamples, dtShort, []uint32{1}}, // RGBA.
- },
- }
-}
+func (d byTag) Len() int { return len(d) }
+func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag }
+func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
-func (e *encoder) writeImgData(w io.Writer) error {
- b := e.img.Bounds()
- buf := make([]byte, 4*b.Dx())
- for y := b.Min.Y; y < b.Max.Y; y++ {
+func writeImgData(w io.Writer, m image.Image) error {
+ bounds := m.Bounds()
+ buf := make([]byte, 4*bounds.Dx())
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
i := 0
- for x := b.Min.X; x < b.Max.X; x++ {
- r, g, b, a := e.img.At(x, y).RGBA()
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ r, g, b, a := m.At(x, y).RGBA()
buf[i+0] = uint8(r >> 8)
buf[i+1] = uint8(g >> 8)
buf[i+2] = uint8(b >> 8)
@@ -117,22 +73,22 @@ func (e *encoder) writeImgData(w io.Writer) error {
return nil
}
-func (e *encoder) writeIFD(w io.Writer) error {
+func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error {
var buf [ifdLen]byte
// Make space for "pointer area" containing IFD entry data
// longer than 4 bytes.
parea := make([]byte, 1024)
- pstart := int(e.imageLen) + 8 + (ifdLen * len(e.ifd)) + 6
+ pstart := ifdOffset + ifdLen*len(d) + 6
var o int // Current offset in parea.
// The IFD has to be written with the tags in ascending order.
- sort.Sort(e.ifd)
+ sort.Sort(byTag(d))
// Write the number of entries in this IFD.
- if err := binary.Write(w, enc, uint16(len(e.ifd))); err != nil {
+ if err := binary.Write(w, enc, uint16(len(d))); err != nil {
return err
}
- for _, ent := range e.ifd {
+ for _, ent := range d {
enc.PutUint16(buf[0:2], uint16(ent.tag))
enc.PutUint16(buf[2:4], uint16(ent.datatype))
count := uint32(len(ent.data))
@@ -170,25 +126,41 @@ func (e *encoder) writeIFD(w io.Writer) error {
return err
}
-func (e *encoder) encode(w io.Writer) error {
+// Encode writes the image m to w in uncompressed RGBA format.
+func Encode(w io.Writer, m image.Image) error {
_, err := io.WriteString(w, leHeader)
if err != nil {
return err
}
- ifdOffset := e.imageLen + 8 // 8 bytes for TIFF header.
+ bounds := m.Bounds()
+ width, height := bounds.Dx(), bounds.Dy()
+ // imageLen is the length of the image data in bytes.
+ imageLen := width * height * 4
+ ifdOffset := imageLen + 8 // 8 bytes for TIFF header.
err = binary.Write(w, enc, uint32(ifdOffset))
if err != nil {
return err
}
- err = e.writeImgData(w)
+ err = writeImgData(w, m)
if err != nil {
return err
}
- return e.writeIFD(w)
-}
-
-// Encode writes the image m to w in uncompressed RGBA format.
-func Encode(w io.Writer, m image.Image) error {
- return newEncoder(m).encode(w)
+ return writeIFD(w, ifdOffset, []ifdEntry{
+ {tImageWidth, dtShort, []uint32{uint32(width)}},
+ {tImageLength, dtShort, []uint32{uint32(height)}},
+ {tBitsPerSample, dtShort, []uint32{8, 8, 8, 8}},
+ {tCompression, dtShort, []uint32{cNone}},
+ {tPhotometricInterpretation, dtShort, []uint32{pRGB}},
+ {tStripOffsets, dtLong, []uint32{8}},
+ {tSamplesPerPixel, dtShort, []uint32{4}},
+ {tRowsPerStrip, dtShort, []uint32{uint32(height)}},
+ {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
+ // There is currently no support for storing the image
+ // resolution, so give a bogus value of 72x72 dpi.
+ {tXResolution, dtRational, []uint32{72, 1}},
+ {tYResolution, dtRational, []uint32{72, 1}},
+ {tResolutionUnit, dtShort, []uint32{resPerInch}},
+ {tExtraSamples, dtShort, []uint32{1}}, // RGBA.
+ })
}