mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 18:52:24 -06:00 
			
		
		
		
	Bumps [golang.org/x/image](https://github.com/golang/image) from 0.5.0 to 0.6.0. - [Release notes](https://github.com/golang/image/releases) - [Commits](https://github.com/golang/image/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: golang.org/x/image dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
		
			
				
	
	
		
			441 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			441 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2012 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
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"compress/zlib"
 | 
						|
	"encoding/binary"
 | 
						|
	"errors"
 | 
						|
	"image"
 | 
						|
	"io"
 | 
						|
	"sort"
 | 
						|
)
 | 
						|
 | 
						|
// The TIFF format allows to choose the order of the different elements freely.
 | 
						|
// The basic structure of a TIFF file written by this package is:
 | 
						|
//
 | 
						|
//   1. Header (8 bytes).
 | 
						|
//   2. Image data.
 | 
						|
//   3. Image File Directory (IFD).
 | 
						|
//   4. "Pointer area" for larger entries in the IFD.
 | 
						|
 | 
						|
// We only write little-endian TIFF files.
 | 
						|
var enc = binary.LittleEndian
 | 
						|
 | 
						|
// An ifdEntry is a single entry in an Image File Directory.
 | 
						|
// A value of type dtRational is composed of two 32-bit values,
 | 
						|
// thus data contains two uints (numerator and denominator) for a single number.
 | 
						|
type ifdEntry struct {
 | 
						|
	tag      int
 | 
						|
	datatype int
 | 
						|
	data     []uint32
 | 
						|
}
 | 
						|
 | 
						|
func (e ifdEntry) putData(p []byte) {
 | 
						|
	for _, d := range e.data {
 | 
						|
		switch e.datatype {
 | 
						|
		case dtByte, dtASCII:
 | 
						|
			p[0] = byte(d)
 | 
						|
			p = p[1:]
 | 
						|
		case dtShort:
 | 
						|
			enc.PutUint16(p, uint16(d))
 | 
						|
			p = p[2:]
 | 
						|
		case dtLong, dtRational:
 | 
						|
			enc.PutUint32(p, uint32(d))
 | 
						|
			p = p[4:]
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type byTag []ifdEntry
 | 
						|
 | 
						|
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 encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
						|
	if !predictor {
 | 
						|
		return writePix(w, pix, dy, dx, stride)
 | 
						|
	}
 | 
						|
	buf := make([]byte, dx)
 | 
						|
	for y := 0; y < dy; y++ {
 | 
						|
		min := y*stride + 0
 | 
						|
		max := y*stride + dx
 | 
						|
		off := 0
 | 
						|
		var v0 uint8
 | 
						|
		for i := min; i < max; i++ {
 | 
						|
			v1 := pix[i]
 | 
						|
			buf[off] = v1 - v0
 | 
						|
			v0 = v1
 | 
						|
			off++
 | 
						|
		}
 | 
						|
		if _, err := w.Write(buf); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
						|
	buf := make([]byte, dx*2)
 | 
						|
	for y := 0; y < dy; y++ {
 | 
						|
		min := y*stride + 0
 | 
						|
		max := y*stride + dx*2
 | 
						|
		off := 0
 | 
						|
		var v0 uint16
 | 
						|
		for i := min; i < max; i += 2 {
 | 
						|
			// An image.Gray16's Pix is in big-endian order.
 | 
						|
			v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
 | 
						|
			if predictor {
 | 
						|
				v0, v1 = v1, v1-v0
 | 
						|
			}
 | 
						|
			// We only write little-endian TIFF files.
 | 
						|
			buf[off+0] = byte(v1)
 | 
						|
			buf[off+1] = byte(v1 >> 8)
 | 
						|
			off += 2
 | 
						|
		}
 | 
						|
		if _, err := w.Write(buf); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
						|
	if !predictor {
 | 
						|
		return writePix(w, pix, dy, dx*4, stride)
 | 
						|
	}
 | 
						|
	buf := make([]byte, dx*4)
 | 
						|
	for y := 0; y < dy; y++ {
 | 
						|
		min := y*stride + 0
 | 
						|
		max := y*stride + dx*4
 | 
						|
		off := 0
 | 
						|
		var r0, g0, b0, a0 uint8
 | 
						|
		for i := min; i < max; i += 4 {
 | 
						|
			r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3]
 | 
						|
			buf[off+0] = r1 - r0
 | 
						|
			buf[off+1] = g1 - g0
 | 
						|
			buf[off+2] = b1 - b0
 | 
						|
			buf[off+3] = a1 - a0
 | 
						|
			off += 4
 | 
						|
			r0, g0, b0, a0 = r1, g1, b1, a1
 | 
						|
		}
 | 
						|
		if _, err := w.Write(buf); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
						|
	buf := make([]byte, dx*8)
 | 
						|
	for y := 0; y < dy; y++ {
 | 
						|
		min := y*stride + 0
 | 
						|
		max := y*stride + dx*8
 | 
						|
		off := 0
 | 
						|
		var r0, g0, b0, a0 uint16
 | 
						|
		for i := min; i < max; i += 8 {
 | 
						|
			// An image.RGBA64's Pix is in big-endian order.
 | 
						|
			r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1])
 | 
						|
			g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3])
 | 
						|
			b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5])
 | 
						|
			a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7])
 | 
						|
			if predictor {
 | 
						|
				r0, r1 = r1, r1-r0
 | 
						|
				g0, g1 = g1, g1-g0
 | 
						|
				b0, b1 = b1, b1-b0
 | 
						|
				a0, a1 = a1, a1-a0
 | 
						|
			}
 | 
						|
			// We only write little-endian TIFF files.
 | 
						|
			buf[off+0] = byte(r1)
 | 
						|
			buf[off+1] = byte(r1 >> 8)
 | 
						|
			buf[off+2] = byte(g1)
 | 
						|
			buf[off+3] = byte(g1 >> 8)
 | 
						|
			buf[off+4] = byte(b1)
 | 
						|
			buf[off+5] = byte(b1 >> 8)
 | 
						|
			buf[off+6] = byte(a1)
 | 
						|
			buf[off+7] = byte(a1 >> 8)
 | 
						|
			off += 8
 | 
						|
		}
 | 
						|
		if _, err := w.Write(buf); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func encode(w io.Writer, m image.Image, predictor bool) error {
 | 
						|
	bounds := m.Bounds()
 | 
						|
	buf := make([]byte, 4*bounds.Dx())
 | 
						|
	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
 | 
						|
		off := 0
 | 
						|
		if predictor {
 | 
						|
			var r0, g0, b0, a0 uint8
 | 
						|
			for x := bounds.Min.X; x < bounds.Max.X; x++ {
 | 
						|
				r, g, b, a := m.At(x, y).RGBA()
 | 
						|
				r1 := uint8(r >> 8)
 | 
						|
				g1 := uint8(g >> 8)
 | 
						|
				b1 := uint8(b >> 8)
 | 
						|
				a1 := uint8(a >> 8)
 | 
						|
				buf[off+0] = r1 - r0
 | 
						|
				buf[off+1] = g1 - g0
 | 
						|
				buf[off+2] = b1 - b0
 | 
						|
				buf[off+3] = a1 - a0
 | 
						|
				off += 4
 | 
						|
				r0, g0, b0, a0 = r1, g1, b1, a1
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			for x := bounds.Min.X; x < bounds.Max.X; x++ {
 | 
						|
				r, g, b, a := m.At(x, y).RGBA()
 | 
						|
				buf[off+0] = uint8(r >> 8)
 | 
						|
				buf[off+1] = uint8(g >> 8)
 | 
						|
				buf[off+2] = uint8(b >> 8)
 | 
						|
				buf[off+3] = uint8(a >> 8)
 | 
						|
				off += 4
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if _, err := w.Write(buf); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// writePix writes the internal byte array of an image to w. It is less general
 | 
						|
// but much faster then encode. writePix is used when pix directly
 | 
						|
// corresponds to one of the TIFF image types.
 | 
						|
func writePix(w io.Writer, pix []byte, nrows, length, stride int) error {
 | 
						|
	if length == stride {
 | 
						|
		_, err := w.Write(pix[:nrows*length])
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	for ; nrows > 0; nrows-- {
 | 
						|
		if _, err := w.Write(pix[:length]); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		pix = pix[stride:]
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
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 := 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(byTag(d))
 | 
						|
 | 
						|
	// Write the number of entries in this IFD.
 | 
						|
	if err := binary.Write(w, enc, uint16(len(d))); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	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))
 | 
						|
		if ent.datatype == dtRational {
 | 
						|
			count /= 2
 | 
						|
		}
 | 
						|
		enc.PutUint32(buf[4:8], count)
 | 
						|
		datalen := int(count * lengths[ent.datatype])
 | 
						|
		if datalen <= 4 {
 | 
						|
			ent.putData(buf[8:12])
 | 
						|
		} else {
 | 
						|
			if (o + datalen) > len(parea) {
 | 
						|
				newlen := len(parea) + 1024
 | 
						|
				for (o + datalen) > newlen {
 | 
						|
					newlen += 1024
 | 
						|
				}
 | 
						|
				newarea := make([]byte, newlen)
 | 
						|
				copy(newarea, parea)
 | 
						|
				parea = newarea
 | 
						|
			}
 | 
						|
			ent.putData(parea[o : o+datalen])
 | 
						|
			enc.PutUint32(buf[8:12], uint32(pstart+o))
 | 
						|
			o += datalen
 | 
						|
		}
 | 
						|
		if _, err := w.Write(buf[:]); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// The IFD ends with the offset of the next IFD in the file,
 | 
						|
	// or zero if it is the last one (page 14).
 | 
						|
	if err := binary.Write(w, enc, uint32(0)); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	_, err := w.Write(parea[:o])
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// Options are the encoding parameters.
 | 
						|
type Options struct {
 | 
						|
	// Compression is the type of compression used.
 | 
						|
	Compression CompressionType
 | 
						|
	// Predictor determines whether a differencing predictor is used;
 | 
						|
	// if true, instead of each pixel's color, the color difference to the
 | 
						|
	// preceding one is saved. This improves the compression for certain
 | 
						|
	// types of images and compressors. For example, it works well for
 | 
						|
	// photos with Deflate compression.
 | 
						|
	Predictor bool
 | 
						|
}
 | 
						|
 | 
						|
// Encode writes the image m to w. opt determines the options used for
 | 
						|
// encoding, such as the compression type. If opt is nil, an uncompressed
 | 
						|
// image is written.
 | 
						|
func Encode(w io.Writer, m image.Image, opt *Options) error {
 | 
						|
	d := m.Bounds().Size()
 | 
						|
 | 
						|
	compression := uint32(cNone)
 | 
						|
	predictor := false
 | 
						|
	if opt != nil {
 | 
						|
		compression = opt.Compression.specValue()
 | 
						|
		// The predictor field is only used with LZW. See page 64 of the spec.
 | 
						|
		predictor = opt.Predictor && compression == cLZW
 | 
						|
	}
 | 
						|
 | 
						|
	_, err := io.WriteString(w, leHeader)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// Compressed data is written into a buffer first, so that we
 | 
						|
	// know the compressed size.
 | 
						|
	var buf bytes.Buffer
 | 
						|
	// dst holds the destination for the pixel data of the image --
 | 
						|
	// either w or a writer to buf.
 | 
						|
	var dst io.Writer
 | 
						|
	// imageLen is the length of the pixel data in bytes.
 | 
						|
	// The offset of the IFD is imageLen + 8 header bytes.
 | 
						|
	var imageLen int
 | 
						|
 | 
						|
	switch compression {
 | 
						|
	case cNone:
 | 
						|
		dst = w
 | 
						|
		// Write IFD offset before outputting pixel data.
 | 
						|
		switch m.(type) {
 | 
						|
		case *image.Paletted:
 | 
						|
			imageLen = d.X * d.Y * 1
 | 
						|
		case *image.Gray:
 | 
						|
			imageLen = d.X * d.Y * 1
 | 
						|
		case *image.Gray16:
 | 
						|
			imageLen = d.X * d.Y * 2
 | 
						|
		case *image.RGBA64:
 | 
						|
			imageLen = d.X * d.Y * 8
 | 
						|
		case *image.NRGBA64:
 | 
						|
			imageLen = d.X * d.Y * 8
 | 
						|
		default:
 | 
						|
			imageLen = d.X * d.Y * 4
 | 
						|
		}
 | 
						|
		err = binary.Write(w, enc, uint32(imageLen+8))
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	case cDeflate:
 | 
						|
		dst = zlib.NewWriter(&buf)
 | 
						|
	default:
 | 
						|
		return errors.New("tiff: unsupported compression")
 | 
						|
	}
 | 
						|
 | 
						|
	pr := uint32(prNone)
 | 
						|
	photometricInterpretation := uint32(pRGB)
 | 
						|
	samplesPerPixel := uint32(4)
 | 
						|
	bitsPerSample := []uint32{8, 8, 8, 8}
 | 
						|
	extraSamples := uint32(0)
 | 
						|
	colorMap := []uint32{}
 | 
						|
 | 
						|
	if predictor {
 | 
						|
		pr = prHorizontal
 | 
						|
	}
 | 
						|
	switch m := m.(type) {
 | 
						|
	case *image.Paletted:
 | 
						|
		photometricInterpretation = pPaletted
 | 
						|
		samplesPerPixel = 1
 | 
						|
		bitsPerSample = []uint32{8}
 | 
						|
		colorMap = make([]uint32, 256*3)
 | 
						|
		for i := 0; i < 256 && i < len(m.Palette); i++ {
 | 
						|
			r, g, b, _ := m.Palette[i].RGBA()
 | 
						|
			colorMap[i+0*256] = uint32(r)
 | 
						|
			colorMap[i+1*256] = uint32(g)
 | 
						|
			colorMap[i+2*256] = uint32(b)
 | 
						|
		}
 | 
						|
		err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	case *image.Gray:
 | 
						|
		photometricInterpretation = pBlackIsZero
 | 
						|
		samplesPerPixel = 1
 | 
						|
		bitsPerSample = []uint32{8}
 | 
						|
		err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	case *image.Gray16:
 | 
						|
		photometricInterpretation = pBlackIsZero
 | 
						|
		samplesPerPixel = 1
 | 
						|
		bitsPerSample = []uint32{16}
 | 
						|
		err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	case *image.NRGBA:
 | 
						|
		extraSamples = 2 // Unassociated alpha.
 | 
						|
		err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	case *image.NRGBA64:
 | 
						|
		extraSamples = 2 // Unassociated alpha.
 | 
						|
		bitsPerSample = []uint32{16, 16, 16, 16}
 | 
						|
		err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	case *image.RGBA:
 | 
						|
		extraSamples = 1 // Associated alpha.
 | 
						|
		err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	case *image.RGBA64:
 | 
						|
		extraSamples = 1 // Associated alpha.
 | 
						|
		bitsPerSample = []uint32{16, 16, 16, 16}
 | 
						|
		err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
						|
	default:
 | 
						|
		extraSamples = 1 // Associated alpha.
 | 
						|
		err = encode(dst, m, predictor)
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if compression != cNone {
 | 
						|
		if err = dst.(io.Closer).Close(); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		imageLen = buf.Len()
 | 
						|
		if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if _, err = buf.WriteTo(w); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ifd := []ifdEntry{
 | 
						|
		{tImageWidth, dtShort, []uint32{uint32(d.X)}},
 | 
						|
		{tImageLength, dtShort, []uint32{uint32(d.Y)}},
 | 
						|
		{tBitsPerSample, dtShort, bitsPerSample},
 | 
						|
		{tCompression, dtShort, []uint32{compression}},
 | 
						|
		{tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}},
 | 
						|
		{tStripOffsets, dtLong, []uint32{8}},
 | 
						|
		{tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}},
 | 
						|
		{tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}},
 | 
						|
		{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}},
 | 
						|
	}
 | 
						|
	if pr != prNone {
 | 
						|
		ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}})
 | 
						|
	}
 | 
						|
	if len(colorMap) != 0 {
 | 
						|
		ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap})
 | 
						|
	}
 | 
						|
	if extraSamples > 0 {
 | 
						|
		ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}})
 | 
						|
	}
 | 
						|
 | 
						|
	return writeIFD(w, imageLen+8, ifd)
 | 
						|
}
 |