twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

stdlibwriter.go (14744B)


      1 // Code generated by gen.go. DO NOT EDIT.
      2 
      3 // Copyright 2009 The Go Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style
      5 // license that can be found in the LICENSE file.
      6 
      7 package png
      8 
      9 import (
     10 	"bufio"
     11 	"compress/zlib"
     12 	"encoding/binary"
     13 	"hash/crc32"
     14 	"image"
     15 	"image/color"
     16 	"io"
     17 	"strconv"
     18 )
     19 
     20 // Encoder configures encoding PNG images.
     21 type Encoder struct {
     22 	CompressionLevel CompressionLevel
     23 
     24 	// BufferPool optionally specifies a buffer pool to get temporary
     25 	// EncoderBuffers when encoding an image.
     26 	BufferPool EncoderBufferPool
     27 }
     28 
     29 // EncoderBufferPool is an interface for getting and returning temporary
     30 // instances of the EncoderBuffer struct. This can be used to reuse buffers
     31 // when encoding multiple images.
     32 type EncoderBufferPool interface {
     33 	Get() *EncoderBuffer
     34 	Put(*EncoderBuffer)
     35 }
     36 
     37 // EncoderBuffer holds the buffers used for encoding PNG images.
     38 type EncoderBuffer encoder
     39 
     40 type encoder struct {
     41 	enc     *Encoder
     42 	w       io.Writer
     43 	m       image.Image
     44 	cb      int
     45 	err     error
     46 	header  [8]byte
     47 	footer  [4]byte
     48 	tmp     [4 * 256]byte
     49 	cr      [nFilter][]uint8
     50 	pr      []uint8
     51 	zw      *zlib.Writer
     52 	zwLevel int
     53 	bw      *bufio.Writer
     54 }
     55 
     56 type CompressionLevel int
     57 
     58 const (
     59 	DefaultCompression CompressionLevel = 0
     60 	NoCompression      CompressionLevel = -1
     61 	BestSpeed          CompressionLevel = -2
     62 	BestCompression    CompressionLevel = -3
     63 
     64 	// Positive CompressionLevel values are reserved to mean a numeric zlib
     65 	// compression level, although that is not implemented yet.
     66 )
     67 
     68 type opaquer interface {
     69 	Opaque() bool
     70 }
     71 
     72 // Returns whether or not the image is fully opaque.
     73 func opaque(m image.Image) bool {
     74 	if o, ok := m.(opaquer); ok {
     75 		return o.Opaque()
     76 	}
     77 	b := m.Bounds()
     78 	for y := b.Min.Y; y < b.Max.Y; y++ {
     79 		for x := b.Min.X; x < b.Max.X; x++ {
     80 			_, _, _, a := m.At(x, y).RGBA()
     81 			if a != 0xffff {
     82 				return false
     83 			}
     84 		}
     85 	}
     86 	return true
     87 }
     88 
     89 // The absolute value of a byte interpreted as a signed int8.
     90 func abs8(d uint8) int {
     91 	if d < 128 {
     92 		return int(d)
     93 	}
     94 	return 256 - int(d)
     95 }
     96 
     97 func (e *encoder) writeChunk(b []byte, name string) {
     98 	if e.err != nil {
     99 		return
    100 	}
    101 	n := uint32(len(b))
    102 	if int(n) != len(b) {
    103 		e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
    104 		return
    105 	}
    106 	binary.BigEndian.PutUint32(e.header[:4], n)
    107 	e.header[4] = name[0]
    108 	e.header[5] = name[1]
    109 	e.header[6] = name[2]
    110 	e.header[7] = name[3]
    111 	crc := crc32.NewIEEE()
    112 	crc.Write(e.header[4:8])
    113 	crc.Write(b)
    114 	binary.BigEndian.PutUint32(e.footer[:4], crc.Sum32())
    115 
    116 	_, e.err = e.w.Write(e.header[:8])
    117 	if e.err != nil {
    118 		return
    119 	}
    120 	_, e.err = e.w.Write(b)
    121 	if e.err != nil {
    122 		return
    123 	}
    124 	_, e.err = e.w.Write(e.footer[:4])
    125 }
    126 
    127 func (e *encoder) writeIHDR() {
    128 	b := e.m.Bounds()
    129 	binary.BigEndian.PutUint32(e.tmp[0:4], uint32(b.Dx()))
    130 	binary.BigEndian.PutUint32(e.tmp[4:8], uint32(b.Dy()))
    131 	// Set bit depth and color type.
    132 	switch e.cb {
    133 	case cbG8:
    134 		e.tmp[8] = 8
    135 		e.tmp[9] = ctGrayscale
    136 	case cbTC8:
    137 		e.tmp[8] = 8
    138 		e.tmp[9] = ctTrueColor
    139 	case cbP8:
    140 		e.tmp[8] = 8
    141 		e.tmp[9] = ctPaletted
    142 	case cbP4:
    143 		e.tmp[8] = 4
    144 		e.tmp[9] = ctPaletted
    145 	case cbP2:
    146 		e.tmp[8] = 2
    147 		e.tmp[9] = ctPaletted
    148 	case cbP1:
    149 		e.tmp[8] = 1
    150 		e.tmp[9] = ctPaletted
    151 	case cbTCA8:
    152 		e.tmp[8] = 8
    153 		e.tmp[9] = ctTrueColorAlpha
    154 	case cbG16:
    155 		e.tmp[8] = 16
    156 		e.tmp[9] = ctGrayscale
    157 	case cbTC16:
    158 		e.tmp[8] = 16
    159 		e.tmp[9] = ctTrueColor
    160 	case cbTCA16:
    161 		e.tmp[8] = 16
    162 		e.tmp[9] = ctTrueColorAlpha
    163 	}
    164 	e.tmp[10] = 0 // default compression method
    165 	e.tmp[11] = 0 // default filter method
    166 	e.tmp[12] = 0 // non-interlaced
    167 	e.writeChunk(e.tmp[:13], "IHDR")
    168 }
    169 
    170 func (e *encoder) writePLTEAndTRNS(p color.Palette) {
    171 	if len(p) < 1 || len(p) > 256 {
    172 		e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
    173 		return
    174 	}
    175 	last := -1
    176 	for i, c := range p {
    177 		c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
    178 		e.tmp[3*i+0] = c1.R
    179 		e.tmp[3*i+1] = c1.G
    180 		e.tmp[3*i+2] = c1.B
    181 		if c1.A != 0xff {
    182 			last = i
    183 		}
    184 		e.tmp[3*256+i] = c1.A
    185 	}
    186 	e.writeChunk(e.tmp[:3*len(p)], "PLTE")
    187 	if last != -1 {
    188 		e.writeChunk(e.tmp[3*256:3*256+1+last], "tRNS")
    189 	}
    190 }
    191 
    192 // An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
    193 // including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
    194 // should be relatively infrequent, since writeIDATs uses a bufio.Writer.
    195 //
    196 // This method should only be called from writeIDATs (via writeImage).
    197 // No other code should treat an encoder as an io.Writer.
    198 func (e *encoder) Write(b []byte) (int, error) {
    199 	e.writeChunk(b, "IDAT")
    200 	if e.err != nil {
    201 		return 0, e.err
    202 	}
    203 	return len(b), nil
    204 }
    205 
    206 // Chooses the filter to use for encoding the current row, and applies it.
    207 // The return value is the index of the filter and also of the row in cr that has had it applied.
    208 func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
    209 	// We try all five filter types, and pick the one that minimizes the sum of absolute differences.
    210 	// This is the same heuristic that libpng uses, although the filters are attempted in order of
    211 	// estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than
    212 	// in their enumeration order (ftNone, ftSub, ftUp, ftAverage, ftPaeth).
    213 	cdat0 := cr[0][1:]
    214 	cdat1 := cr[1][1:]
    215 	cdat2 := cr[2][1:]
    216 	cdat3 := cr[3][1:]
    217 	cdat4 := cr[4][1:]
    218 	pdat := pr[1:]
    219 	n := len(cdat0)
    220 
    221 	// The up filter.
    222 	sum := 0
    223 	for i := 0; i < n; i++ {
    224 		cdat2[i] = cdat0[i] - pdat[i]
    225 		sum += abs8(cdat2[i])
    226 	}
    227 	best := sum
    228 	filter := ftUp
    229 
    230 	// The Paeth filter.
    231 	sum = 0
    232 	for i := 0; i < bpp; i++ {
    233 		cdat4[i] = cdat0[i] - pdat[i]
    234 		sum += abs8(cdat4[i])
    235 	}
    236 	for i := bpp; i < n; i++ {
    237 		cdat4[i] = cdat0[i] - paeth(cdat0[i-bpp], pdat[i], pdat[i-bpp])
    238 		sum += abs8(cdat4[i])
    239 		if sum >= best {
    240 			break
    241 		}
    242 	}
    243 	if sum < best {
    244 		best = sum
    245 		filter = ftPaeth
    246 	}
    247 
    248 	// The none filter.
    249 	sum = 0
    250 	for i := 0; i < n; i++ {
    251 		sum += abs8(cdat0[i])
    252 		if sum >= best {
    253 			break
    254 		}
    255 	}
    256 	if sum < best {
    257 		best = sum
    258 		filter = ftNone
    259 	}
    260 
    261 	// The sub filter.
    262 	sum = 0
    263 	for i := 0; i < bpp; i++ {
    264 		cdat1[i] = cdat0[i]
    265 		sum += abs8(cdat1[i])
    266 	}
    267 	for i := bpp; i < n; i++ {
    268 		cdat1[i] = cdat0[i] - cdat0[i-bpp]
    269 		sum += abs8(cdat1[i])
    270 		if sum >= best {
    271 			break
    272 		}
    273 	}
    274 	if sum < best {
    275 		best = sum
    276 		filter = ftSub
    277 	}
    278 
    279 	// The average filter.
    280 	sum = 0
    281 	for i := 0; i < bpp; i++ {
    282 		cdat3[i] = cdat0[i] - pdat[i]/2
    283 		sum += abs8(cdat3[i])
    284 	}
    285 	for i := bpp; i < n; i++ {
    286 		cdat3[i] = cdat0[i] - uint8((int(cdat0[i-bpp])+int(pdat[i]))/2)
    287 		sum += abs8(cdat3[i])
    288 		if sum >= best {
    289 			break
    290 		}
    291 	}
    292 	if sum < best {
    293 		filter = ftAverage
    294 	}
    295 
    296 	return filter
    297 }
    298 
    299 func zeroMemory(v []uint8) {
    300 	for i := range v {
    301 		v[i] = 0
    302 	}
    303 }
    304 
    305 func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) error {
    306 	if e.zw == nil || e.zwLevel != level {
    307 		zw, err := zlib.NewWriterLevel(w, level)
    308 		if err != nil {
    309 			return err
    310 		}
    311 		e.zw = zw
    312 		e.zwLevel = level
    313 	} else {
    314 		e.zw.Reset(w)
    315 	}
    316 	defer e.zw.Close()
    317 
    318 	bitsPerPixel := 0
    319 
    320 	switch cb {
    321 	case cbG8:
    322 		bitsPerPixel = 8
    323 	case cbTC8:
    324 		bitsPerPixel = 24
    325 	case cbP8:
    326 		bitsPerPixel = 8
    327 	case cbP4:
    328 		bitsPerPixel = 4
    329 	case cbP2:
    330 		bitsPerPixel = 2
    331 	case cbP1:
    332 		bitsPerPixel = 1
    333 	case cbTCA8:
    334 		bitsPerPixel = 32
    335 	case cbTC16:
    336 		bitsPerPixel = 48
    337 	case cbTCA16:
    338 		bitsPerPixel = 64
    339 	case cbG16:
    340 		bitsPerPixel = 16
    341 	}
    342 
    343 	// cr[*] and pr are the bytes for the current and previous row.
    344 	// cr[0] is unfiltered (or equivalently, filtered with the ftNone filter).
    345 	// cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the
    346 	// other PNG filter types. These buffers are allocated once and re-used for each row.
    347 	// The +1 is for the per-row filter type, which is at cr[*][0].
    348 	b := m.Bounds()
    349 	sz := 1 + (bitsPerPixel*b.Dx()+7)/8
    350 	for i := range e.cr {
    351 		if cap(e.cr[i]) < sz {
    352 			e.cr[i] = make([]uint8, sz)
    353 		} else {
    354 			e.cr[i] = e.cr[i][:sz]
    355 		}
    356 		e.cr[i][0] = uint8(i)
    357 	}
    358 	cr := e.cr
    359 	if cap(e.pr) < sz {
    360 		e.pr = make([]uint8, sz)
    361 	} else {
    362 		e.pr = e.pr[:sz]
    363 		zeroMemory(e.pr)
    364 	}
    365 	pr := e.pr
    366 
    367 	gray, _ := m.(*image.Gray)
    368 	rgba, _ := m.(*image.RGBA)
    369 	paletted, _ := m.(*image.Paletted)
    370 	nrgba, _ := m.(*image.NRGBA)
    371 
    372 	for y := b.Min.Y; y < b.Max.Y; y++ {
    373 		// Convert from colors to bytes.
    374 		i := 1
    375 		switch cb {
    376 		case cbG8:
    377 			if gray != nil {
    378 				offset := (y - b.Min.Y) * gray.Stride
    379 				copy(cr[0][1:], gray.Pix[offset:offset+b.Dx()])
    380 			} else {
    381 				for x := b.Min.X; x < b.Max.X; x++ {
    382 					c := color.GrayModel.Convert(m.At(x, y)).(color.Gray)
    383 					cr[0][i] = c.Y
    384 					i++
    385 				}
    386 			}
    387 		case cbTC8:
    388 			// We have previously verified that the alpha value is fully opaque.
    389 			cr0 := cr[0]
    390 			stride, pix := 0, []byte(nil)
    391 			if rgba != nil {
    392 				stride, pix = rgba.Stride, rgba.Pix
    393 			} else if nrgba != nil {
    394 				stride, pix = nrgba.Stride, nrgba.Pix
    395 			}
    396 			if stride != 0 {
    397 				j0 := (y - b.Min.Y) * stride
    398 				j1 := j0 + b.Dx()*4
    399 				for j := j0; j < j1; j += 4 {
    400 					cr0[i+0] = pix[j+0]
    401 					cr0[i+1] = pix[j+1]
    402 					cr0[i+2] = pix[j+2]
    403 					i += 3
    404 				}
    405 			} else {
    406 				for x := b.Min.X; x < b.Max.X; x++ {
    407 					r, g, b, _ := m.At(x, y).RGBA()
    408 					cr0[i+0] = uint8(r >> 8)
    409 					cr0[i+1] = uint8(g >> 8)
    410 					cr0[i+2] = uint8(b >> 8)
    411 					i += 3
    412 				}
    413 			}
    414 		case cbP8:
    415 			if paletted != nil {
    416 				offset := (y - b.Min.Y) * paletted.Stride
    417 				copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
    418 			} else {
    419 				pi := m.(image.PalettedImage)
    420 				for x := b.Min.X; x < b.Max.X; x++ {
    421 					cr[0][i] = pi.ColorIndexAt(x, y)
    422 					i += 1
    423 				}
    424 			}
    425 
    426 		case cbP4, cbP2, cbP1:
    427 			pi := m.(image.PalettedImage)
    428 
    429 			var a uint8
    430 			var c int
    431 			pixelsPerByte := 8 / bitsPerPixel
    432 			for x := b.Min.X; x < b.Max.X; x++ {
    433 				a = a<<uint(bitsPerPixel) | pi.ColorIndexAt(x, y)
    434 				c++
    435 				if c == pixelsPerByte {
    436 					cr[0][i] = a
    437 					i += 1
    438 					a = 0
    439 					c = 0
    440 				}
    441 			}
    442 			if c != 0 {
    443 				for c != pixelsPerByte {
    444 					a = a << uint(bitsPerPixel)
    445 					c++
    446 				}
    447 				cr[0][i] = a
    448 			}
    449 
    450 		case cbTCA8:
    451 			if nrgba != nil {
    452 				offset := (y - b.Min.Y) * nrgba.Stride
    453 				copy(cr[0][1:], nrgba.Pix[offset:offset+b.Dx()*4])
    454 			} else {
    455 				// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
    456 				for x := b.Min.X; x < b.Max.X; x++ {
    457 					c := color.NRGBAModel.Convert(m.At(x, y)).(color.NRGBA)
    458 					cr[0][i+0] = c.R
    459 					cr[0][i+1] = c.G
    460 					cr[0][i+2] = c.B
    461 					cr[0][i+3] = c.A
    462 					i += 4
    463 				}
    464 			}
    465 		case cbG16:
    466 			for x := b.Min.X; x < b.Max.X; x++ {
    467 				c := color.Gray16Model.Convert(m.At(x, y)).(color.Gray16)
    468 				cr[0][i+0] = uint8(c.Y >> 8)
    469 				cr[0][i+1] = uint8(c.Y)
    470 				i += 2
    471 			}
    472 		case cbTC16:
    473 			// We have previously verified that the alpha value is fully opaque.
    474 			for x := b.Min.X; x < b.Max.X; x++ {
    475 				r, g, b, _ := m.At(x, y).RGBA()
    476 				cr[0][i+0] = uint8(r >> 8)
    477 				cr[0][i+1] = uint8(r)
    478 				cr[0][i+2] = uint8(g >> 8)
    479 				cr[0][i+3] = uint8(g)
    480 				cr[0][i+4] = uint8(b >> 8)
    481 				cr[0][i+5] = uint8(b)
    482 				i += 6
    483 			}
    484 		case cbTCA16:
    485 			// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
    486 			for x := b.Min.X; x < b.Max.X; x++ {
    487 				c := color.NRGBA64Model.Convert(m.At(x, y)).(color.NRGBA64)
    488 				cr[0][i+0] = uint8(c.R >> 8)
    489 				cr[0][i+1] = uint8(c.R)
    490 				cr[0][i+2] = uint8(c.G >> 8)
    491 				cr[0][i+3] = uint8(c.G)
    492 				cr[0][i+4] = uint8(c.B >> 8)
    493 				cr[0][i+5] = uint8(c.B)
    494 				cr[0][i+6] = uint8(c.A >> 8)
    495 				cr[0][i+7] = uint8(c.A)
    496 				i += 8
    497 			}
    498 		}
    499 
    500 		// Apply the filter.
    501 		// Skip filter for NoCompression and paletted images (cbP8) as
    502 		// "filters are rarely useful on palette images" and will result
    503 		// in larger files (see http://www.libpng.org/pub/png/book/chapter09.html).
    504 		f := ftNone
    505 		if level != zlib.NoCompression && cb != cbP8 && cb != cbP4 && cb != cbP2 && cb != cbP1 {
    506 			// Since we skip paletted images we don't have to worry about
    507 			// bitsPerPixel not being a multiple of 8
    508 			bpp := bitsPerPixel / 8
    509 			f = filter(&cr, pr, bpp)
    510 		}
    511 
    512 		// Write the compressed bytes.
    513 		if _, err := e.zw.Write(cr[f]); err != nil {
    514 			return err
    515 		}
    516 
    517 		// The current row for y is the previous row for y+1.
    518 		pr, cr[0] = cr[0], pr
    519 	}
    520 	return nil
    521 }
    522 
    523 // Write the actual image data to one or more IDAT chunks.
    524 func (e *encoder) writeIDATs() {
    525 	if e.err != nil {
    526 		return
    527 	}
    528 	if e.bw == nil {
    529 		e.bw = bufio.NewWriterSize(e, 1<<15)
    530 	} else {
    531 		e.bw.Reset(e)
    532 	}
    533 	e.err = e.writeImage(e.bw, e.m, e.cb, levelToZlib(e.enc.CompressionLevel))
    534 	if e.err != nil {
    535 		return
    536 	}
    537 	e.err = e.bw.Flush()
    538 }
    539 
    540 // This function is required because we want the zero value of
    541 // Encoder.CompressionLevel to map to zlib.DefaultCompression.
    542 func levelToZlib(l CompressionLevel) int {
    543 	switch l {
    544 	case DefaultCompression:
    545 		return zlib.DefaultCompression
    546 	case NoCompression:
    547 		return zlib.NoCompression
    548 	case BestSpeed:
    549 		return zlib.BestSpeed
    550 	case BestCompression:
    551 		return zlib.BestCompression
    552 	default:
    553 		return zlib.DefaultCompression
    554 	}
    555 }
    556 
    557 func (e *encoder) writeIEND() { e.writeChunk(nil, "IEND") }
    558 
    559 // Encode writes the Image m to w in PNG format. Any Image may be
    560 // encoded, but images that are not image.NRGBA might be encoded lossily.
    561 func Encode(w io.Writer, m image.Image) error {
    562 	var e Encoder
    563 	return e.Encode(w, m)
    564 }
    565 
    566 // Encode writes the Image m to w in PNG format.
    567 func (enc *Encoder) Encode(w io.Writer, m image.Image) error {
    568 	// Obviously, negative widths and heights are invalid. Furthermore, the PNG
    569 	// spec section 11.2.2 says that zero is invalid. Excessively large images are
    570 	// also rejected.
    571 	mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
    572 	if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
    573 		return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mh, 10))
    574 	}
    575 
    576 	var e *encoder
    577 	if enc.BufferPool != nil {
    578 		buffer := enc.BufferPool.Get()
    579 		e = (*encoder)(buffer)
    580 
    581 	}
    582 	if e == nil {
    583 		e = &encoder{}
    584 	}
    585 	if enc.BufferPool != nil {
    586 		defer enc.BufferPool.Put((*EncoderBuffer)(e))
    587 	}
    588 
    589 	e.enc = enc
    590 	e.w = w
    591 	e.m = m
    592 
    593 	var pal color.Palette
    594 	// cbP8 encoding needs PalettedImage's ColorIndexAt method.
    595 	if _, ok := m.(image.PalettedImage); ok {
    596 		pal, _ = m.ColorModel().(color.Palette)
    597 	}
    598 	if pal != nil {
    599 		if len(pal) <= 2 {
    600 			e.cb = cbP1
    601 		} else if len(pal) <= 4 {
    602 			e.cb = cbP2
    603 		} else if len(pal) <= 16 {
    604 			e.cb = cbP4
    605 		} else {
    606 			e.cb = cbP8
    607 		}
    608 	} else {
    609 		switch m.ColorModel() {
    610 		case color.GrayModel:
    611 			e.cb = cbG8
    612 		case color.Gray16Model:
    613 			e.cb = cbG16
    614 		case color.RGBAModel, color.NRGBAModel, color.AlphaModel:
    615 			if opaque(m) {
    616 				e.cb = cbTC8
    617 			} else {
    618 				e.cb = cbTCA8
    619 			}
    620 		default:
    621 			if opaque(m) {
    622 				e.cb = cbTC16
    623 			} else {
    624 				e.cb = cbTCA16
    625 			}
    626 		}
    627 	}
    628 
    629 	_, e.err = io.WriteString(w, pngHeader)
    630 	e.writeIHDR()
    631 	if pal != nil {
    632 		e.writePLTEAndTRNS(pal)
    633 	}
    634 	e.writeIDATs()
    635 	e.writeIEND()
    636 	return e.err
    637 }