in vp8l/decode.go [352:487]
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
}