mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 04:42:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			604 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			604 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2014 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 vp8l implements a decoder for the VP8L lossless image format.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The VP8L specification is at:
							 | 
						||
| 
								 | 
							
								// https://developers.google.com/speed/webp/docs/riff_container
							 | 
						||
| 
								 | 
							
								package vp8l // import "golang.org/x/image/vp8l"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"bufio"
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"image"
							 | 
						||
| 
								 | 
							
									"image/color"
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									errInvalidCodeLengths = errors.New("vp8l: invalid code lengths")
							 | 
						||
| 
								 | 
							
									errInvalidHuffmanTree = errors.New("vp8l: invalid Huffman tree")
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// colorCacheMultiplier is the multiplier used for the color cache hash
							 | 
						||
| 
								 | 
							
								// function, specified in section 4.2.3.
							 | 
						||
| 
								 | 
							
								const colorCacheMultiplier = 0x1e35a7bd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// distanceMapTable is the look-up table for distanceMap.
							 | 
						||
| 
								 | 
							
								var distanceMapTable = [120]uint8{
							 | 
						||
| 
								 | 
							
									0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
							 | 
						||
| 
								 | 
							
									0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
							 | 
						||
| 
								 | 
							
									0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
							 | 
						||
| 
								 | 
							
									0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
							 | 
						||
| 
								 | 
							
									0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
							 | 
						||
| 
								 | 
							
									0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
							 | 
						||
| 
								 | 
							
									0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
							 | 
						||
| 
								 | 
							
									0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
							 | 
						||
| 
								 | 
							
									0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
							 | 
						||
| 
								 | 
							
									0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
							 | 
						||
| 
								 | 
							
									0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
							 | 
						||
| 
								 | 
							
									0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70,
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// distanceMap maps a LZ77 backwards reference distance to a two-dimensional
							 | 
						||
| 
								 | 
							
								// pixel offset, specified in section 4.2.2.
							 | 
						||
| 
								 | 
							
								func distanceMap(w int32, code uint32) int32 {
							 | 
						||
| 
								 | 
							
									if int32(code) > int32(len(distanceMapTable)) {
							 | 
						||
| 
								 | 
							
										return int32(code) - int32(len(distanceMapTable))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									distCode := int32(distanceMapTable[code-1])
							 | 
						||
| 
								 | 
							
									yOffset := distCode >> 4
							 | 
						||
| 
								 | 
							
									xOffset := 8 - distCode&0xf
							 | 
						||
| 
								 | 
							
									if d := yOffset*w + xOffset; d >= 1 {
							 | 
						||
| 
								 | 
							
										return d
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 1
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decoder holds the bit-stream for a VP8L image.
							 | 
						||
| 
								 | 
							
								type decoder struct {
							 | 
						||
| 
								 | 
							
									r     io.ByteReader
							 | 
						||
| 
								 | 
							
									bits  uint32
							 | 
						||
| 
								 | 
							
									nBits uint32
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// read reads the next n bits from the decoder's bit-stream.
							 | 
						||
| 
								 | 
							
								func (d *decoder) read(n uint32) (uint32, error) {
							 | 
						||
| 
								 | 
							
									for d.nBits < n {
							 | 
						||
| 
								 | 
							
										c, err := d.r.ReadByte()
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											if err == io.EOF {
							 | 
						||
| 
								 | 
							
												err = io.ErrUnexpectedEOF
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return 0, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										d.bits |= uint32(c) << d.nBits
							 | 
						||
| 
								 | 
							
										d.nBits += 8
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									u := d.bits & (1<<n - 1)
							 | 
						||
| 
								 | 
							
									d.bits >>= n
							 | 
						||
| 
								 | 
							
									d.nBits -= n
							 | 
						||
| 
								 | 
							
									return u, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decodeTransform decodes the next transform and the width of the image after
							 | 
						||
| 
								 | 
							
								// transformation (or equivalently, before inverse transformation), specified
							 | 
						||
| 
								 | 
							
								// in section 3.
							 | 
						||
| 
								 | 
							
								func (d *decoder) decodeTransform(w int32, h int32) (t transform, newWidth int32, err error) {
							 | 
						||
| 
								 | 
							
									t.oldWidth = w
							 | 
						||
| 
								 | 
							
									t.transformType, err = d.read(2)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return transform{}, 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									switch t.transformType {
							 | 
						||
| 
								 | 
							
									case transformTypePredictor, transformTypeCrossColor:
							 | 
						||
| 
								 | 
							
										t.bits, err = d.read(3)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return transform{}, 0, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										t.bits += 2
							 | 
						||
| 
								 | 
							
										t.pix, err = d.decodePix(nTiles(w, t.bits), nTiles(h, t.bits), 0, false)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return transform{}, 0, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case transformTypeSubtractGreen:
							 | 
						||
| 
								 | 
							
										// No-op.
							 | 
						||
| 
								 | 
							
									case transformTypeColorIndexing:
							 | 
						||
| 
								 | 
							
										nColors, err := d.read(8)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return transform{}, 0, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										nColors++
							 | 
						||
| 
								 | 
							
										t.bits = 0
							 | 
						||
| 
								 | 
							
										switch {
							 | 
						||
| 
								 | 
							
										case nColors <= 2:
							 | 
						||
| 
								 | 
							
											t.bits = 3
							 | 
						||
| 
								 | 
							
										case nColors <= 4:
							 | 
						||
| 
								 | 
							
											t.bits = 2
							 | 
						||
| 
								 | 
							
										case nColors <= 16:
							 | 
						||
| 
								 | 
							
											t.bits = 1
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										w = nTiles(w, t.bits)
							 | 
						||
| 
								 | 
							
										pix, err := d.decodePix(int32(nColors), 1, 4*256, false)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return transform{}, 0, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										for p := 4; p < len(pix); p += 4 {
							 | 
						||
| 
								 | 
							
											pix[p+0] += pix[p-4]
							 | 
						||
| 
								 | 
							
											pix[p+1] += pix[p-3]
							 | 
						||
| 
								 | 
							
											pix[p+2] += pix[p-2]
							 | 
						||
| 
								 | 
							
											pix[p+3] += pix[p-1]
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// The spec says that "if the index is equal or larger than color_table_size,
							 | 
						||
| 
								 | 
							
										// the argb color value should be set to 0x00000000 (transparent black)."
							 | 
						||
| 
								 | 
							
										// We re-slice up to 256 4-byte pixels.
							 | 
						||
| 
								 | 
							
										t.pix = pix[:4*256]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return t, w, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// repeatsCodeLength is the minimum code length for repeated codes.
							 | 
						||
| 
								 | 
							
								const repeatsCodeLength = 16
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// These magic numbers are specified at the end of section 5.2.2.
							 | 
						||
| 
								 | 
							
								// The 3-length arrays apply to code lengths >= repeatsCodeLength.
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									codeLengthCodeOrder = [19]uint8{
							 | 
						||
| 
								 | 
							
										17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									repeatBits    = [3]uint8{2, 3, 7}
							 | 
						||
| 
								 | 
							
									repeatOffsets = [3]uint8{3, 3, 11}
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decodeCodeLengths decodes a Huffman tree's code lengths which are themselves
							 | 
						||
| 
								 | 
							
								// encoded via a Huffman tree, specified in section 5.2.2.
							 | 
						||
| 
								 | 
							
								func (d *decoder) decodeCodeLengths(dst []uint32, codeLengthCodeLengths []uint32) error {
							 | 
						||
| 
								 | 
							
									h := hTree{}
							 | 
						||
| 
								 | 
							
									if err := h.build(codeLengthCodeLengths); err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									maxSymbol := len(dst)
							 | 
						||
| 
								 | 
							
									useLength, err := d.read(1)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if useLength != 0 {
							 | 
						||
| 
								 | 
							
										n, err := d.read(3)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										n = 2 + 2*n
							 | 
						||
| 
								 | 
							
										ms, err := d.read(n)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										maxSymbol = int(ms) + 2
							 | 
						||
| 
								 | 
							
										if maxSymbol > len(dst) {
							 | 
						||
| 
								 | 
							
											return errInvalidCodeLengths
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// The spec says that "if code 16 [meaning repeat] is used before
							 | 
						||
| 
								 | 
							
									// a non-zero value has been emitted, a value of 8 is repeated."
							 | 
						||
| 
								 | 
							
									prevCodeLength := uint32(8)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for symbol := 0; symbol < len(dst); {
							 | 
						||
| 
								 | 
							
										if maxSymbol == 0 {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										maxSymbol--
							 | 
						||
| 
								 | 
							
										codeLength, err := h.next(d)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if codeLength < repeatsCodeLength {
							 | 
						||
| 
								 | 
							
											dst[symbol] = codeLength
							 | 
						||
| 
								 | 
							
											symbol++
							 | 
						||
| 
								 | 
							
											if codeLength != 0 {
							 | 
						||
| 
								 | 
							
												prevCodeLength = codeLength
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										repeat, err := d.read(uint32(repeatBits[codeLength-repeatsCodeLength]))
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										repeat += uint32(repeatOffsets[codeLength-repeatsCodeLength])
							 | 
						||
| 
								 | 
							
										if symbol+int(repeat) > len(dst) {
							 | 
						||
| 
								 | 
							
											return errInvalidCodeLengths
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// A code length of 16 repeats the previous non-zero code.
							 | 
						||
| 
								 | 
							
										// A code length of 17 or 18 repeats zeroes.
							 | 
						||
| 
								 | 
							
										cl := uint32(0)
							 | 
						||
| 
								 | 
							
										if codeLength == 16 {
							 | 
						||
| 
								 | 
							
											cl = prevCodeLength
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										for ; repeat > 0; repeat-- {
							 | 
						||
| 
								 | 
							
											dst[symbol] = cl
							 | 
						||
| 
								 | 
							
											symbol++
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decodeHuffmanTree decodes a Huffman tree into h.
							 | 
						||
| 
								 | 
							
								func (d *decoder) decodeHuffmanTree(h *hTree, alphabetSize uint32) error {
							 | 
						||
| 
								 | 
							
									useSimple, err := d.read(1)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if useSimple != 0 {
							 | 
						||
| 
								 | 
							
										nSymbols, err := d.read(1)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										nSymbols++
							 | 
						||
| 
								 | 
							
										firstSymbolLengthCode, err := d.read(1)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										firstSymbolLengthCode = 7*firstSymbolLengthCode + 1
							 | 
						||
| 
								 | 
							
										var symbols [2]uint32
							 | 
						||
| 
								 | 
							
										symbols[0], err = d.read(firstSymbolLengthCode)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if nSymbols == 2 {
							 | 
						||
| 
								 | 
							
											symbols[1], err = d.read(8)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return h.buildSimple(nSymbols, symbols, alphabetSize)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nCodes, err := d.read(4)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									nCodes += 4
							 | 
						||
| 
								 | 
							
									if int(nCodes) > len(codeLengthCodeOrder) {
							 | 
						||
| 
								 | 
							
										return errInvalidHuffmanTree
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									codeLengthCodeLengths := [len(codeLengthCodeOrder)]uint32{}
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < nCodes; i++ {
							 | 
						||
| 
								 | 
							
										codeLengthCodeLengths[codeLengthCodeOrder[i]], err = d.read(3)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									codeLengths := make([]uint32, alphabetSize)
							 | 
						||
| 
								 | 
							
									if err = d.decodeCodeLengths(codeLengths, codeLengthCodeLengths[:]); err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return h.build(codeLengths)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									huffGreen    = 0
							 | 
						||
| 
								 | 
							
									huffRed      = 1
							 | 
						||
| 
								 | 
							
									huffBlue     = 2
							 | 
						||
| 
								 | 
							
									huffAlpha    = 3
							 | 
						||
| 
								 | 
							
									huffDistance = 4
							 | 
						||
| 
								 | 
							
									nHuff        = 5
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// hGroup is an array of 5 Huffman trees.
							 | 
						||
| 
								 | 
							
								type hGroup [nHuff]hTree
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decodeHuffmanGroups decodes the one or more hGroups used to decode the pixel
							 | 
						||
| 
								 | 
							
								// data. If one hGroup is used for the entire image, then hPix and hBits will
							 | 
						||
| 
								 | 
							
								// be zero. If more than one hGroup is used, then hPix contains the meta-image
							 | 
						||
| 
								 | 
							
								// that maps tiles to hGroup index, and hBits contains the log-2 tile size.
							 | 
						||
| 
								 | 
							
								func (d *decoder) decodeHuffmanGroups(w int32, h int32, topLevel bool, ccBits uint32) (
							 | 
						||
| 
								 | 
							
									hGroups []hGroup, hPix []byte, hBits uint32, err error) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									maxHGroupIndex := 0
							 | 
						||
| 
								 | 
							
									if topLevel {
							 | 
						||
| 
								 | 
							
										useMeta, err := d.read(1)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil, nil, 0, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if useMeta != 0 {
							 | 
						||
| 
								 | 
							
											hBits, err = d.read(3)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, nil, 0, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											hBits += 2
							 | 
						||
| 
								 | 
							
											hPix, err = d.decodePix(nTiles(w, hBits), nTiles(h, hBits), 0, false)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, nil, 0, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											for p := 0; p < len(hPix); p += 4 {
							 | 
						||
| 
								 | 
							
												i := int(hPix[p])<<8 | int(hPix[p+1])
							 | 
						||
| 
								 | 
							
												if maxHGroupIndex < i {
							 | 
						||
| 
								 | 
							
													maxHGroupIndex = i
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									hGroups = make([]hGroup, maxHGroupIndex+1)
							 | 
						||
| 
								 | 
							
									for i := range hGroups {
							 | 
						||
| 
								 | 
							
										for j, alphabetSize := range alphabetSizes {
							 | 
						||
| 
								 | 
							
											if j == 0 && ccBits > 0 {
							 | 
						||
| 
								 | 
							
												alphabetSize += 1 << ccBits
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if err := d.decodeHuffmanTree(&hGroups[i][j], alphabetSize); err != nil {
							 | 
						||
| 
								 | 
							
												return nil, nil, 0, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return hGroups, hPix, hBits, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									nLiteralCodes  = 256
							 | 
						||
| 
								 | 
							
									nLengthCodes   = 24
							 | 
						||
| 
								 | 
							
									nDistanceCodes = 40
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var alphabetSizes = [nHuff]uint32{
							 | 
						||
| 
								 | 
							
									nLiteralCodes + nLengthCodes,
							 | 
						||
| 
								 | 
							
									nLiteralCodes,
							 | 
						||
| 
								 | 
							
									nLiteralCodes,
							 | 
						||
| 
								 | 
							
									nLiteralCodes,
							 | 
						||
| 
								 | 
							
									nDistanceCodes,
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decodePix decodes pixel data, specified in section 5.2.2.
							 | 
						||
| 
								 | 
							
								func (d *decoder) decodePix(w int32, h int32, minCap int32, topLevel bool) ([]byte, error) {
							 | 
						||
| 
								 | 
							
									// Decode the color cache parameters.
							 | 
						||
| 
								 | 
							
									ccBits, ccShift, ccEntries := uint32(0), uint32(0), ([]uint32)(nil)
							 | 
						||
| 
								 | 
							
									useColorCache, err := d.read(1)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if useColorCache != 0 {
							 | 
						||
| 
								 | 
							
										ccBits, err = d.read(4)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if ccBits < 1 || 11 < ccBits {
							 | 
						||
| 
								 | 
							
											return nil, errors.New("vp8l: invalid color cache parameters")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										ccShift = 32 - ccBits
							 | 
						||
| 
								 | 
							
										ccEntries = make([]uint32, 1<<ccBits)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Decode the Huffman groups.
							 | 
						||
| 
								 | 
							
									hGroups, hPix, hBits, err := d.decodeHuffmanGroups(w, h, topLevel, ccBits)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									hMask, tilesPerRow := int32(0), int32(0)
							 | 
						||
| 
								 | 
							
									if hBits != 0 {
							 | 
						||
| 
								 | 
							
										hMask, tilesPerRow = 1<<hBits-1, nTiles(w, hBits)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Decode the pixels.
							 | 
						||
| 
								 | 
							
									if minCap < 4*w*h {
							 | 
						||
| 
								 | 
							
										minCap = 4 * w * h
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									pix := make([]byte, 4*w*h, minCap)
							 | 
						||
| 
								 | 
							
									p, cachedP := 0, 0
							 | 
						||
| 
								 | 
							
									x, y := int32(0), int32(0)
							 | 
						||
| 
								 | 
							
									hg, lookupHG := &hGroups[0], hMask != 0
							 | 
						||
| 
								 | 
							
									for p < len(pix) {
							 | 
						||
| 
								 | 
							
										if lookupHG {
							 | 
						||
| 
								 | 
							
											i := 4 * (tilesPerRow*(y>>hBits) + (x >> hBits))
							 | 
						||
| 
								 | 
							
											hg = &hGroups[uint32(hPix[i])<<8|uint32(hPix[i+1])]
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										green, err := hg[huffGreen].next(d)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										switch {
							 | 
						||
| 
								 | 
							
										case green < nLiteralCodes:
							 | 
						||
| 
								 | 
							
											// We have a literal pixel.
							 | 
						||
| 
								 | 
							
											red, err := hg[huffRed].next(d)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											blue, err := hg[huffBlue].next(d)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											alpha, err := hg[huffAlpha].next(d)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											pix[p+0] = uint8(red)
							 | 
						||
| 
								 | 
							
											pix[p+1] = uint8(green)
							 | 
						||
| 
								 | 
							
											pix[p+2] = uint8(blue)
							 | 
						||
| 
								 | 
							
											pix[p+3] = uint8(alpha)
							 | 
						||
| 
								 | 
							
											p += 4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											x++
							 | 
						||
| 
								 | 
							
											if x == w {
							 | 
						||
| 
								 | 
							
												x, y = 0, y+1
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											lookupHG = hMask != 0 && x&hMask == 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case green < nLiteralCodes+nLengthCodes:
							 | 
						||
| 
								 | 
							
											// We have a LZ77 backwards reference.
							 | 
						||
| 
								 | 
							
											length, err := d.lz77Param(green - nLiteralCodes)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											distSym, err := hg[huffDistance].next(d)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											distCode, err := d.lz77Param(distSym)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												return nil, err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											dist := distanceMap(w, distCode)
							 | 
						||
| 
								 | 
							
											pEnd := p + 4*int(length)
							 | 
						||
| 
								 | 
							
											q := p - 4*int(dist)
							 | 
						||
| 
								 | 
							
											qEnd := pEnd - 4*int(dist)
							 | 
						||
| 
								 | 
							
											if p < 0 || len(pix) < pEnd || q < 0 || len(pix) < qEnd {
							 | 
						||
| 
								 | 
							
												return nil, errors.New("vp8l: invalid LZ77 parameters")
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											for ; p < pEnd; p, q = p+1, q+1 {
							 | 
						||
| 
								 | 
							
												pix[p] = pix[q]
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											x += int32(length)
							 | 
						||
| 
								 | 
							
											for x >= w {
							 | 
						||
| 
								 | 
							
												x, y = x-w, y+1
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											lookupHG = hMask != 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											// We have a color cache lookup. First, insert previous pixels
							 | 
						||
| 
								 | 
							
											// into the cache. Note that VP8L assumes ARGB order, but the
							 | 
						||
| 
								 | 
							
											// Go image.RGBA type is in RGBA order.
							 | 
						||
| 
								 | 
							
											for ; cachedP < p; cachedP += 4 {
							 | 
						||
| 
								 | 
							
												argb := uint32(pix[cachedP+0])<<16 |
							 | 
						||
| 
								 | 
							
													uint32(pix[cachedP+1])<<8 |
							 | 
						||
| 
								 | 
							
													uint32(pix[cachedP+2])<<0 |
							 | 
						||
| 
								 | 
							
													uint32(pix[cachedP+3])<<24
							 | 
						||
| 
								 | 
							
												ccEntries[(argb*colorCacheMultiplier)>>ccShift] = argb
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											green -= nLiteralCodes + nLengthCodes
							 | 
						||
| 
								 | 
							
											if int(green) >= len(ccEntries) {
							 | 
						||
| 
								 | 
							
												return nil, errors.New("vp8l: invalid color cache index")
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											argb := ccEntries[green]
							 | 
						||
| 
								 | 
							
											pix[p+0] = uint8(argb >> 16)
							 | 
						||
| 
								 | 
							
											pix[p+1] = uint8(argb >> 8)
							 | 
						||
| 
								 | 
							
											pix[p+2] = uint8(argb >> 0)
							 | 
						||
| 
								 | 
							
											pix[p+3] = uint8(argb >> 24)
							 | 
						||
| 
								 | 
							
											p += 4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											x++
							 | 
						||
| 
								 | 
							
											if x == w {
							 | 
						||
| 
								 | 
							
												x, y = 0, y+1
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											lookupHG = hMask != 0 && x&hMask == 0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return pix, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// lz77Param returns the next LZ77 parameter: a length or a distance, specified
							 | 
						||
| 
								 | 
							
								// in section 4.2.2.
							 | 
						||
| 
								 | 
							
								func (d *decoder) lz77Param(symbol uint32) (uint32, error) {
							 | 
						||
| 
								 | 
							
									if symbol < 4 {
							 | 
						||
| 
								 | 
							
										return symbol + 1, nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									extraBits := (symbol - 2) >> 1
							 | 
						||
| 
								 | 
							
									offset := (2 + symbol&1) << extraBits
							 | 
						||
| 
								 | 
							
									n, err := d.read(extraBits)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return offset + n + 1, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// decodeHeader decodes the VP8L header from r.
							 | 
						||
| 
								 | 
							
								func decodeHeader(r io.Reader) (d *decoder, w int32, h int32, err error) {
							 | 
						||
| 
								 | 
							
									rr, ok := r.(io.ByteReader)
							 | 
						||
| 
								 | 
							
									if !ok {
							 | 
						||
| 
								 | 
							
										rr = bufio.NewReader(r)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									d = &decoder{r: rr}
							 | 
						||
| 
								 | 
							
									magic, err := d.read(8)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if magic != 0x2f {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, errors.New("vp8l: invalid header")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									width, err := d.read(14)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									width++
							 | 
						||
| 
								 | 
							
									height, err := d.read(14)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									height++
							 | 
						||
| 
								 | 
							
									_, err = d.read(1) // Read and ignore the hasAlpha hint.
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									version, err := d.read(3)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if version != 0 {
							 | 
						||
| 
								 | 
							
										return nil, 0, 0, errors.New("vp8l: invalid version")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return d, int32(width), int32(height), nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// DecodeConfig decodes the color model and dimensions of a VP8L image from r.
							 | 
						||
| 
								 | 
							
								func DecodeConfig(r io.Reader) (image.Config, error) {
							 | 
						||
| 
								 | 
							
									_, w, h, err := decodeHeader(r)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return image.Config{}, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return image.Config{
							 | 
						||
| 
								 | 
							
										ColorModel: color.NRGBAModel,
							 | 
						||
| 
								 | 
							
										Width:      int(w),
							 | 
						||
| 
								 | 
							
										Height:     int(h),
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Decode decodes a VP8L image from r.
							 | 
						||
| 
								 | 
							
								func Decode(r io.Reader) (image.Image, error) {
							 | 
						||
| 
								 | 
							
									d, w, h, err := decodeHeader(r)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Decode the transforms.
							 | 
						||
| 
								 | 
							
									var (
							 | 
						||
| 
								 | 
							
										nTransforms    int
							 | 
						||
| 
								 | 
							
										transforms     [nTransformTypes]transform
							 | 
						||
| 
								 | 
							
										transformsSeen [nTransformTypes]bool
							 | 
						||
| 
								 | 
							
										originalW      = w
							 | 
						||
| 
								 | 
							
									)
							 | 
						||
| 
								 | 
							
									for {
							 | 
						||
| 
								 | 
							
										more, err := d.read(1)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if more == 0 {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										var t transform
							 | 
						||
| 
								 | 
							
										t, w, err = d.decodeTransform(w, h)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if transformsSeen[t.transformType] {
							 | 
						||
| 
								 | 
							
											return nil, errors.New("vp8l: repeated transform")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										transformsSeen[t.transformType] = true
							 | 
						||
| 
								 | 
							
										transforms[nTransforms] = t
							 | 
						||
| 
								 | 
							
										nTransforms++
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Decode the transformed pixels.
							 | 
						||
| 
								 | 
							
									pix, err := d.decodePix(w, h, 0, true)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Apply the inverse transformations.
							 | 
						||
| 
								 | 
							
									for i := nTransforms - 1; i >= 0; i-- {
							 | 
						||
| 
								 | 
							
										t := &transforms[i]
							 | 
						||
| 
								 | 
							
										pix = inverseTransforms[t.transformType](t, pix, h)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &image.NRGBA{
							 | 
						||
| 
								 | 
							
										Pix:    pix,
							 | 
						||
| 
								 | 
							
										Stride: 4 * int(originalW),
							 | 
						||
| 
								 | 
							
										Rect:   image.Rect(0, 0, int(originalW), int(h)),
							 | 
						||
| 
								 | 
							
									}, nil
							 | 
						||
| 
								 | 
							
								}
							 |