diff options
Diffstat (limited to 'vendor/golang.org/x/image/webp')
| -rw-r--r-- | vendor/golang.org/x/image/webp/decode.go | 271 | ||||
| -rw-r--r-- | vendor/golang.org/x/image/webp/doc.go | 9 | 
2 files changed, 280 insertions, 0 deletions
| diff --git a/vendor/golang.org/x/image/webp/decode.go b/vendor/golang.org/x/image/webp/decode.go new file mode 100644 index 000000000..d6eefd596 --- /dev/null +++ b/vendor/golang.org/x/image/webp/decode.go @@ -0,0 +1,271 @@ +// Copyright 2011 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 webp + +import ( +	"bytes" +	"errors" +	"image" +	"image/color" +	"io" + +	"golang.org/x/image/riff" +	"golang.org/x/image/vp8" +	"golang.org/x/image/vp8l" +) + +var errInvalidFormat = errors.New("webp: invalid format") + +var ( +	fccALPH = riff.FourCC{'A', 'L', 'P', 'H'} +	fccVP8  = riff.FourCC{'V', 'P', '8', ' '} +	fccVP8L = riff.FourCC{'V', 'P', '8', 'L'} +	fccVP8X = riff.FourCC{'V', 'P', '8', 'X'} +	fccWEBP = riff.FourCC{'W', 'E', 'B', 'P'} +) + +func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) { +	formType, riffReader, err := riff.NewReader(r) +	if err != nil { +		return nil, image.Config{}, err +	} +	if formType != fccWEBP { +		return nil, image.Config{}, errInvalidFormat +	} + +	var ( +		alpha          []byte +		alphaStride    int +		wantAlpha      bool +		widthMinusOne  uint32 +		heightMinusOne uint32 +		buf            [10]byte +	) +	for { +		chunkID, chunkLen, chunkData, err := riffReader.Next() +		if err == io.EOF { +			err = errInvalidFormat +		} +		if err != nil { +			return nil, image.Config{}, err +		} + +		switch chunkID { +		case fccALPH: +			if !wantAlpha { +				return nil, image.Config{}, errInvalidFormat +			} +			wantAlpha = false +			// Read the Pre-processing | Filter | Compression byte. +			if _, err := io.ReadFull(chunkData, buf[:1]); err != nil { +				if err == io.EOF { +					err = errInvalidFormat +				} +				return nil, image.Config{}, err +			} +			alpha, alphaStride, err = readAlpha(chunkData, widthMinusOne, heightMinusOne, buf[0]&0x03) +			if err != nil { +				return nil, image.Config{}, err +			} +			unfilterAlpha(alpha, alphaStride, (buf[0]>>2)&0x03) + +		case fccVP8: +			if wantAlpha || int32(chunkLen) < 0 { +				return nil, image.Config{}, errInvalidFormat +			} +			d := vp8.NewDecoder() +			d.Init(chunkData, int(chunkLen)) +			fh, err := d.DecodeFrameHeader() +			if err != nil { +				return nil, image.Config{}, err +			} +			if configOnly { +				return nil, image.Config{ +					ColorModel: color.YCbCrModel, +					Width:      fh.Width, +					Height:     fh.Height, +				}, nil +			} +			m, err := d.DecodeFrame() +			if err != nil { +				return nil, image.Config{}, err +			} +			if alpha != nil { +				return &image.NYCbCrA{ +					YCbCr:   *m, +					A:       alpha, +					AStride: alphaStride, +				}, image.Config{}, nil +			} +			return m, image.Config{}, nil + +		case fccVP8L: +			if wantAlpha || alpha != nil { +				return nil, image.Config{}, errInvalidFormat +			} +			if configOnly { +				c, err := vp8l.DecodeConfig(chunkData) +				return nil, c, err +			} +			m, err := vp8l.Decode(chunkData) +			return m, image.Config{}, err + +		case fccVP8X: +			if chunkLen != 10 { +				return nil, image.Config{}, errInvalidFormat +			} +			if _, err := io.ReadFull(chunkData, buf[:10]); err != nil { +				return nil, image.Config{}, err +			} +			const ( +				animationBit    = 1 << 1 +				xmpMetadataBit  = 1 << 2 +				exifMetadataBit = 1 << 3 +				alphaBit        = 1 << 4 +				iccProfileBit   = 1 << 5 +			) +			wantAlpha = (buf[0] & alphaBit) != 0 +			widthMinusOne = uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16 +			heightMinusOne = uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16 +			if configOnly { +				if wantAlpha { +					return nil, image.Config{ +						ColorModel: color.NYCbCrAModel, +						Width:      int(widthMinusOne) + 1, +						Height:     int(heightMinusOne) + 1, +					}, nil +				} +				return nil, image.Config{ +					ColorModel: color.YCbCrModel, +					Width:      int(widthMinusOne) + 1, +					Height:     int(heightMinusOne) + 1, +				}, nil +			} +		} +	} +} + +func readAlpha(chunkData io.Reader, widthMinusOne, heightMinusOne uint32, compression byte) ( +	alpha []byte, alphaStride int, err error) { + +	switch compression { +	case 0: +		w := int(widthMinusOne) + 1 +		h := int(heightMinusOne) + 1 +		alpha = make([]byte, w*h) +		if _, err := io.ReadFull(chunkData, alpha); err != nil { +			return nil, 0, err +		} +		return alpha, w, nil + +	case 1: +		// Read the VP8L-compressed alpha values. First, synthesize a 5-byte VP8L header: +		// a 1-byte magic number, a 14-bit widthMinusOne, a 14-bit heightMinusOne, +		// a 1-bit (ignored, zero) alphaIsUsed and a 3-bit (zero) version. +		// TODO(nigeltao): be more efficient than decoding an *image.NRGBA just to +		// extract the green values to a separately allocated []byte. Fixing this +		// will require changes to the vp8l package's API. +		if widthMinusOne > 0x3fff || heightMinusOne > 0x3fff { +			return nil, 0, errors.New("webp: invalid format") +		} +		alphaImage, err := vp8l.Decode(io.MultiReader( +			bytes.NewReader([]byte{ +				0x2f, // VP8L magic number. +				uint8(widthMinusOne), +				uint8(widthMinusOne>>8) | uint8(heightMinusOne<<6), +				uint8(heightMinusOne >> 2), +				uint8(heightMinusOne >> 10), +			}), +			chunkData, +		)) +		if err != nil { +			return nil, 0, err +		} +		// The green values of the inner NRGBA image are the alpha values of the +		// outer NYCbCrA image. +		pix := alphaImage.(*image.NRGBA).Pix +		alpha = make([]byte, len(pix)/4) +		for i := range alpha { +			alpha[i] = pix[4*i+1] +		} +		return alpha, int(widthMinusOne) + 1, nil +	} +	return nil, 0, errInvalidFormat +} + +func unfilterAlpha(alpha []byte, alphaStride int, filter byte) { +	if len(alpha) == 0 || alphaStride == 0 { +		return +	} +	switch filter { +	case 1: // Horizontal filter. +		for i := 1; i < alphaStride; i++ { +			alpha[i] += alpha[i-1] +		} +		for i := alphaStride; i < len(alpha); i += alphaStride { +			// The first column is equivalent to the vertical filter. +			alpha[i] += alpha[i-alphaStride] + +			for j := 1; j < alphaStride; j++ { +				alpha[i+j] += alpha[i+j-1] +			} +		} + +	case 2: // Vertical filter. +		// The first row is equivalent to the horizontal filter. +		for i := 1; i < alphaStride; i++ { +			alpha[i] += alpha[i-1] +		} + +		for i := alphaStride; i < len(alpha); i++ { +			alpha[i] += alpha[i-alphaStride] +		} + +	case 3: // Gradient filter. +		// The first row is equivalent to the horizontal filter. +		for i := 1; i < alphaStride; i++ { +			alpha[i] += alpha[i-1] +		} + +		for i := alphaStride; i < len(alpha); i += alphaStride { +			// The first column is equivalent to the vertical filter. +			alpha[i] += alpha[i-alphaStride] + +			// The interior is predicted on the three top/left pixels. +			for j := 1; j < alphaStride; j++ { +				c := int(alpha[i+j-alphaStride-1]) +				b := int(alpha[i+j-alphaStride]) +				a := int(alpha[i+j-1]) +				x := a + b - c +				if x < 0 { +					x = 0 +				} else if x > 255 { +					x = 255 +				} +				alpha[i+j] += uint8(x) +			} +		} +	} +} + +// Decode reads a WEBP image from r and returns it as an image.Image. +func Decode(r io.Reader) (image.Image, error) { +	m, _, err := decode(r, false) +	if err != nil { +		return nil, err +	} +	return m, err +} + +// DecodeConfig returns the color model and dimensions of a WEBP image without +// decoding the entire image. +func DecodeConfig(r io.Reader) (image.Config, error) { +	_, c, err := decode(r, true) +	return c, err +} + +func init() { +	image.RegisterFormat("webp", "RIFF????WEBPVP8", Decode, DecodeConfig) +} diff --git a/vendor/golang.org/x/image/webp/doc.go b/vendor/golang.org/x/image/webp/doc.go new file mode 100644 index 000000000..e321c8542 --- /dev/null +++ b/vendor/golang.org/x/image/webp/doc.go @@ -0,0 +1,9 @@ +// Copyright 2016 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 webp implements a decoder for WEBP images. +// +// WEBP is defined at: +// https://developers.google.com/speed/webp/docs/riff_container +package webp // import "golang.org/x/image/webp" | 
