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

commit20e9620e9976e95b072c900a541d86c8b60975ce
parentf594c3aad5
authorNigel Tao <[email protected]>
date2012-03-07 10:32
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.
+	})
 }