소스 검색

Reimplemented image format & size detection

DarthSim 5 년 전
부모
커밋
7f4d57ab21
11개의 변경된 파일456개의 추가작업 그리고 178개의 파일을 삭제
  1. 5 10
      download.go
  2. 24 0
      image_size/gif.go
  3. 33 39
      image_size/heic.go
  4. 39 0
      image_size/ico.go
  5. 72 0
      image_size/image_meta.go
  6. 124 0
      image_size/jpeg.go
  7. 39 0
      image_size/png.go
  8. 15 0
      image_size/svg.go
  9. 105 0
      image_size/webp.go
  10. 0 20
      svg.go
  11. 0 109
      webp.go

+ 5 - 10
download.go

@@ -4,18 +4,13 @@ import (
 	"context"
 	"crypto/tls"
 	"fmt"
-	"image"
 	"io"
 	"io/ioutil"
 	"net"
 	"net/http"
 	"time"
 
-	_ "image/gif"
-	_ "image/jpeg"
-	_ "image/png"
-
-	_ "github.com/mat/besticon/ico"
+	imageSize "github.com/imgproxy/imgproxy/image_size"
 )
 
 var (
@@ -107,20 +102,20 @@ func checkDimensions(width, height int) error {
 }
 
 func checkTypeAndDimensions(r io.Reader) (imageType, error) {
-	imgconf, imgtypeStr, err := image.DecodeConfig(r)
-	if err == image.ErrFormat {
+	meta, err := imageSize.DecodeMeta(r)
+	if err == imageSize.ErrFormat {
 		return imageTypeUnknown, errSourceImageTypeNotSupported
 	}
 	if err != nil {
 		return imageTypeUnknown, newUnexpectedError(err.Error(), 0)
 	}
 
-	imgtype, imgtypeOk := imageTypes[imgtypeStr]
+	imgtype, imgtypeOk := imageTypes[meta.Format]
 	if !imgtypeOk || !vipsTypeSupportLoad[imgtype] {
 		return imageTypeUnknown, errSourceImageTypeNotSupported
 	}
 
-	if err = checkDimensions(imgconf.Width, imgconf.Height); err != nil {
+	if err = checkDimensions(meta.Width, meta.Height); err != nil {
 		return imageTypeUnknown, err
 	}
 

+ 24 - 0
image_size/gif.go

@@ -0,0 +1,24 @@
+package imageSize
+
+import (
+	"io"
+)
+
+func DecodeGifMeta(r io.Reader) (*Meta, error) {
+	var tmp [10]byte
+
+	_, err := io.ReadFull(r, tmp[:])
+	if err != nil {
+		return nil, err
+	}
+
+	return &Meta{
+		Format: "gif",
+		Width:  int(tmp[6]) + int(tmp[7])<<8,
+		Height: int(tmp[8]) + int(tmp[9])<<8,
+	}, nil
+}
+
+func init() {
+	RegisterFormat("GIF8?a", DecodeGifMeta)
+}

+ 33 - 39
heic.go → image_size/heic.go

@@ -1,53 +1,51 @@
-package main
+package imageSize
 
 import (
 	"bytes"
 	"encoding/binary"
 	"errors"
 	"fmt"
-	"image"
-	"image/color"
 	"io"
 )
 
-const heifBoxHeaderSize = int64(8)
+const heicBoxHeaderSize = int64(8)
 
 var heicBrand = []byte("heic")
 var heicPict = []byte("pict")
 
-type heifDimensionsData struct {
+type heicDimensionsData struct {
 	Width, Height int64
 }
 
-func (d *heifDimensionsData) IsFilled() bool {
+func (d *heicDimensionsData) IsFilled() bool {
 	return d.Width > 0 && d.Height > 0
 }
 
-func heifReadBoxHeader(r io.Reader) (boxType string, boxDataSize int64, err error) {
-	b := make([]byte, heifBoxHeaderSize)
+func heicReadBoxHeader(r io.Reader) (boxType string, boxDataSize int64, err error) {
+	b := make([]byte, heicBoxHeaderSize)
 	_, err = r.Read(b)
 	if err != nil {
 		return
 	}
 
-	boxDataSize = int64(binary.BigEndian.Uint32(b[0:4])) - heifBoxHeaderSize
+	boxDataSize = int64(binary.BigEndian.Uint32(b[0:4])) - heicBoxHeaderSize
 	boxType = string(b[4:8])
 
 	return
 }
 
-func heifReadBoxData(r io.Reader, boxDataSize int64) (b []byte, err error) {
+func heicReadBoxData(r io.Reader, boxDataSize int64) (b []byte, err error) {
 	b = make([]byte, boxDataSize)
 	_, err = r.Read(b)
 	return
 }
 
-func heifReadFtyp(r io.Reader, boxDataSize int64) error {
+func heicReadFtyp(r io.Reader, boxDataSize int64) error {
 	if boxDataSize < 8 {
 		return errors.New("Invalid ftyp data")
 	}
 
-	data, err := heifReadBoxData(r, boxDataSize)
+	data, err := heicReadBoxData(r, boxDataSize)
 	if err != nil {
 		return err
 	}
@@ -67,7 +65,7 @@ func heifReadFtyp(r io.Reader, boxDataSize int64) error {
 	return errors.New("Image is not compatible with heic")
 }
 
-func heifReadMeta(d *heifDimensionsData, r io.Reader, boxDataSize int64) error {
+func heicReadMeta(d *heicDimensionsData, r io.Reader, boxDataSize int64) error {
 	if boxDataSize < 4 {
 		return errors.New("Invalid meta data")
 	}
@@ -77,7 +75,7 @@ func heifReadMeta(d *heifDimensionsData, r io.Reader, boxDataSize int64) error {
 	}
 
 	if boxDataSize > 4 {
-		if err := heifReadBoxes(d, io.LimitReader(r, boxDataSize-4)); err != nil && err != io.EOF {
+		if err := heicReadBoxes(d, io.LimitReader(r, boxDataSize-4)); err != nil && err != io.EOF {
 			return err
 		}
 	}
@@ -85,12 +83,12 @@ func heifReadMeta(d *heifDimensionsData, r io.Reader, boxDataSize int64) error {
 	return nil
 }
 
-func heifReadHldr(r io.Reader, boxDataSize int64) error {
+func heicReadHldr(r io.Reader, boxDataSize int64) error {
 	if boxDataSize < 12 {
 		return errors.New("Invalid hdlr data")
 	}
 
-	data, err := heifReadBoxData(r, boxDataSize)
+	data, err := heicReadBoxData(r, boxDataSize)
 	if err != nil {
 		return err
 	}
@@ -102,12 +100,12 @@ func heifReadHldr(r io.Reader, boxDataSize int64) error {
 	return nil
 }
 
-func heifReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) {
+func heicReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) {
 	if boxDataSize < 12 {
 		return 0, 0, errors.New("Invalid ispe data")
 	}
 
-	data, err := heifReadBoxData(r, boxDataSize)
+	data, err := heicReadBoxData(r, boxDataSize)
 	if err != nil {
 		return 0, 0, err
 	}
@@ -118,9 +116,9 @@ func heifReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) {
 	return
 }
 
-func heifReadBoxes(d *heifDimensionsData, r io.Reader) error {
+func heicReadBoxes(d *heicDimensionsData, r io.Reader) error {
 	for {
-		boxType, boxDataSize, err := heifReadBoxHeader(r)
+		boxType, boxDataSize, err := heicReadBoxHeader(r)
 
 		if err != nil {
 			return err
@@ -134,11 +132,11 @@ func heifReadBoxes(d *heifDimensionsData, r io.Reader) error {
 
 		switch boxType {
 		case "ftyp":
-			if err := heifReadFtyp(r, boxDataSize); err != nil {
+			if err := heicReadFtyp(r, boxDataSize); err != nil {
 				return err
 			}
 		case "meta":
-			if err := heifReadMeta(d, r, boxDataSize); err != nil {
+			if err := heicReadMeta(d, r, boxDataSize); err != nil {
 				return err
 			}
 			if !d.IsFilled() {
@@ -146,15 +144,15 @@ func heifReadBoxes(d *heifDimensionsData, r io.Reader) error {
 			}
 			return nil
 		case "hdlr":
-			if err := heifReadHldr(r, boxDataSize); err != nil {
+			if err := heicReadHldr(r, boxDataSize); err != nil {
 				return nil
 			}
 		case "iprp", "ipco":
-			if err := heifReadBoxes(d, io.LimitReader(r, boxDataSize)); err != nil && err != io.EOF {
+			if err := heicReadBoxes(d, io.LimitReader(r, boxDataSize)); err != nil && err != io.EOF {
 				return err
 			}
 		case "ispe":
-			w, h, err := heifReadIspe(r, boxDataSize)
+			w, h, err := heicReadIspe(r, boxDataSize)
 			if err != nil {
 				return err
 			}
@@ -164,31 +162,27 @@ func heifReadBoxes(d *heifDimensionsData, r io.Reader) error {
 		case "mdat":
 			return errors.New("mdat box occurred before meta box")
 		default:
-			if _, err := heifReadBoxData(r, boxDataSize); err != nil {
+			if _, err := heicReadBoxData(r, boxDataSize); err != nil {
 				return err
 			}
 		}
 	}
 }
 
-func heifDecodeConfig(r io.Reader) (image.Config, error) {
-	d := new(heifDimensionsData)
+func DecodeHeicMeta(r io.Reader) (*Meta, error) {
+	d := new(heicDimensionsData)
 
-	if err := heifReadBoxes(d, r); err != nil && !d.IsFilled() {
-		return image.Config{}, err
+	if err := heicReadBoxes(d, r); err != nil && !d.IsFilled() {
+		return nil, err
 	}
 
-	return image.Config{
-		ColorModel: color.NRGBAModel,
-		Width:      int(d.Width),
-		Height:     int(d.Height),
+	return &Meta{
+		Format: "heic",
+		Width:  int(d.Width),
+		Height: int(d.Height),
 	}, nil
 }
 
-func heifDecode(r io.Reader) (image.Image, error) {
-	return image.NewRGBA(image.Rect(0, 0, 1, 1)), nil
-}
-
 func init() {
-	image.RegisterFormat("heic", "????ftyp", heifDecode, heifDecodeConfig)
+	RegisterFormat("????ftyp", DecodeHeicMeta)
 }

+ 39 - 0
image_size/ico.go

@@ -0,0 +1,39 @@
+package imageSize
+
+import (
+	"encoding/binary"
+	"io"
+)
+
+func DecodeIcoMeta(r io.Reader) (*Meta, error) {
+	var tmp [16]byte
+
+	if _, err := io.ReadFull(r, tmp[:6]); err != nil {
+		return nil, err
+	}
+
+	count := binary.LittleEndian.Uint16(tmp[4:6])
+
+	width, height := byte(0), byte(0)
+
+	for i := uint16(0); i < count; i++ {
+		if _, err := io.ReadFull(r, tmp[:]); err != nil {
+			return nil, err
+		}
+
+		if tmp[0] > width || tmp[1] > height {
+			width = tmp[0]
+			height = tmp[1]
+		}
+	}
+
+	return &Meta{
+		Format: "ico",
+		Width:  int(width),
+		Height: int(height),
+	}, nil
+}
+
+func init() {
+	RegisterFormat("\x00\x00\x01\x00", DecodeIcoMeta)
+}

+ 72 - 0
image_size/image_meta.go

@@ -0,0 +1,72 @@
+package imageSize
+
+import (
+	"bufio"
+	"errors"
+	"io"
+	"sync"
+	"sync/atomic"
+)
+
+type Meta struct {
+	Format        string
+	Width, Height int
+}
+
+type format struct {
+	magic      string
+	decodeMeta func(io.Reader) (*Meta, error)
+}
+
+type reader interface {
+	io.Reader
+	Peek(int) ([]byte, error)
+}
+
+var (
+	formatsMu     sync.Mutex
+	atomicFormats atomic.Value
+
+	ErrFormat = errors.New("unknown image format")
+)
+
+func asReader(r io.Reader) reader {
+	if rr, ok := r.(reader); ok {
+		return rr
+	}
+	return bufio.NewReader(r)
+}
+
+func matchMagic(magic string, b []byte) bool {
+	if len(magic) != len(b) {
+		return false
+	}
+	for i, c := range b {
+		if magic[i] != c && magic[i] != '?' {
+			return false
+		}
+	}
+	return true
+}
+
+func RegisterFormat(magic string, decodeMeta func(io.Reader) (*Meta, error)) {
+	formatsMu.Lock()
+	defer formatsMu.Unlock()
+
+	formats, _ := atomicFormats.Load().([]format)
+	atomicFormats.Store(append(formats, format{magic, decodeMeta}))
+}
+
+func DecodeMeta(r io.Reader) (*Meta, error) {
+	rr := asReader(r)
+	formats, _ := atomicFormats.Load().([]format)
+
+	for _, f := range formats {
+		b, err := rr.Peek(len(f.magic))
+		if err == nil && matchMagic(f.magic, b) {
+			return f.decodeMeta(rr)
+		}
+	}
+
+	return nil, ErrFormat
+}

+ 124 - 0
image_size/jpeg.go

@@ -0,0 +1,124 @@
+package imageSize
+
+import (
+	"bufio"
+	"io"
+)
+
+const (
+	jpegSof0Marker = 0xc0 // Start Of Frame (Baseline Sequential).
+	jpegSof2Marker = 0xc2 // Start Of Frame (Progressive).
+	jpegRst0Marker = 0xd0 // ReSTart (0).
+	jpegRst7Marker = 0xd7 // ReSTart (7).
+	jpegSoiMarker  = 0xd8 // Start Of Image.
+	jpegEoiMarker  = 0xd9 // End Of Image.
+	jpegSosMarker  = 0xda // Start Of Scan.
+)
+
+type jpegReader interface {
+	io.Reader
+	ReadByte() (byte, error)
+	Discard(n int) (discarded int, err error)
+}
+
+func asJpegReader(r io.Reader) jpegReader {
+	if rr, ok := r.(jpegReader); ok {
+		return rr
+	}
+	return bufio.NewReader(r)
+}
+
+type JpegFormatError string
+
+func (e JpegFormatError) Error() string { return "invalid JPEG format: " + string(e) }
+
+func DecodeJpegMeta(rr io.Reader) (*Meta, error) {
+	var tmp [512]byte
+
+	r := asJpegReader(rr)
+
+	if _, err := io.ReadFull(r, tmp[:2]); err != nil {
+		return nil, err
+	}
+	if tmp[0] != 0xff || tmp[1] != jpegSoiMarker {
+		return nil, JpegFormatError("missing SOI marker")
+	}
+
+	for {
+		_, err := io.ReadFull(r, tmp[:2])
+		if err != nil {
+			return nil, err
+		}
+
+		// This is not a segment, continue searching
+		for tmp[0] != 0xff {
+			tmp[0] = tmp[1]
+			tmp[1], err = r.ReadByte()
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		marker := tmp[1]
+
+		if marker == 0 {
+			// Treat "\xff\x00" as extraneous data.
+			continue
+		}
+
+		// Marker can be preceded by fill bytes
+		for marker == 0xff {
+			marker, err = r.ReadByte()
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if marker == jpegEoiMarker { // End Of Image.
+			return nil, JpegFormatError("missing SOF marker")
+		}
+
+		if jpegRst0Marker <= marker && marker <= jpegRst7Marker {
+			continue
+		}
+
+		if _, err = io.ReadFull(r, tmp[:2]); err != nil {
+			return nil, err
+		}
+		n := int(tmp[0])<<8 + int(tmp[1]) - 2
+		if n <= 0 {
+			// We should fail here, but libvips if more tolerant to this, so, contunue
+			continue
+		}
+
+		if marker >= jpegSof0Marker && marker <= jpegSof2Marker {
+			if _, err := io.ReadFull(r, tmp[:5]); err != nil {
+				return nil, err
+			}
+			// We only support 8-bit precision.
+			if tmp[0] != 8 {
+				return nil, JpegFormatError("unsupported precision")
+			}
+
+			return &Meta{
+				Format: "jpeg",
+				Width:  int(tmp[3])<<8 + int(tmp[4]),
+				Height: int(tmp[1])<<8 + int(tmp[2]),
+			}, nil
+		}
+
+		if marker == jpegSosMarker {
+			return nil, JpegFormatError("missing SOF marker")
+		}
+
+		if n > 0 {
+			if _, err := r.Discard(n); err != nil {
+				return nil, err
+			}
+		}
+	}
+}
+
+func init() {
+	RegisterFormat("\xff\xd8", DecodeJpegMeta)
+}

+ 39 - 0
image_size/png.go

@@ -0,0 +1,39 @@
+package imageSize
+
+import (
+	"bytes"
+	"encoding/binary"
+	"io"
+)
+
+var pngMagick = []byte("\x89PNG\r\n\x1a\n")
+
+type PngFormatError string
+
+func (e PngFormatError) Error() string { return "invalid PNG format: " + string(e) }
+
+func DecodePngMeta(r io.Reader) (*Meta, error) {
+	var tmp [16]byte
+
+	if _, err := io.ReadFull(r, tmp[:8]); err != nil {
+		return nil, err
+	}
+
+	if !bytes.Equal(pngMagick, tmp[:8]) {
+		return nil, PngFormatError("not a PNG image")
+	}
+
+	if _, err := io.ReadFull(r, tmp[:]); err != nil {
+		return nil, err
+	}
+
+	return &Meta{
+		Format: "png",
+		Width:  int(binary.BigEndian.Uint32(tmp[8:12])),
+		Height: int(binary.BigEndian.Uint32(tmp[12:16])),
+	}, nil
+}
+
+func init() {
+	RegisterFormat(string(pngMagick), DecodePngMeta)
+}

+ 15 - 0
image_size/svg.go

@@ -0,0 +1,15 @@
+package imageSize
+
+import (
+	"io"
+)
+
+func init() {
+	// Register fake svg decoder. Since we need this only for type detecting, we can
+	// return fake image sizes
+	decodeMeta := func(io.Reader) (*Meta, error) {
+		return &Meta{Format: "svg", Width: 1, Height: 1}, nil
+	}
+	RegisterFormat("<?xml ", decodeMeta)
+	RegisterFormat("<svg", decodeMeta)
+}

+ 105 - 0
image_size/webp.go

@@ -0,0 +1,105 @@
+// 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.
+
+// Original code was cropped and fixed by @DarthSim for imgproxy needs
+
+package imageSize
+
+import (
+	"errors"
+	"io"
+
+	"golang.org/x/image/riff"
+	"golang.org/x/image/vp8"
+	"golang.org/x/image/vp8l"
+)
+
+var ErrWebpInvalidFormat = errors.New("webp: invalid format")
+
+var (
+	webpFccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
+	webpFccVP8  = riff.FourCC{'V', 'P', '8', ' '}
+	webpFccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
+	webpFccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
+	webpFccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
+)
+
+func DecodeWebpMeta(r io.Reader) (*Meta, error) {
+	formType, riffReader, err := riff.NewReader(r)
+	if err != nil {
+		return nil, err
+	}
+	if formType != webpFccWEBP {
+		return nil, ErrWebpInvalidFormat
+	}
+
+	var buf [10]byte
+
+	for {
+		chunkID, chunkLen, chunkData, err := riffReader.Next()
+		if err == io.EOF {
+			err = ErrWebpInvalidFormat
+		}
+		if err != nil {
+			return nil, err
+		}
+
+		switch chunkID {
+		case webpFccALPH:
+			// Ignore
+		case webpFccVP8:
+			if int32(chunkLen) < 0 {
+				return nil, ErrWebpInvalidFormat
+			}
+
+			d := vp8.NewDecoder()
+			d.Init(chunkData, int(chunkLen))
+
+			fh, err := d.DecodeFrameHeader()
+
+			return &Meta{
+				Format: "webp",
+				Width:  fh.Width,
+				Height: fh.Height,
+			}, err
+
+		case webpFccVP8L:
+			conf, err := vp8l.DecodeConfig(chunkData)
+			if err != nil {
+				return nil, err
+			}
+
+			return &Meta{
+				Format: "webp",
+				Width:  conf.Width,
+				Height: conf.Height,
+			}, nil
+
+		case webpFccVP8X:
+			if chunkLen != 10 {
+				return nil, ErrWebpInvalidFormat
+			}
+
+			if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
+				return nil, err
+			}
+
+			widthMinusOne := uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
+			heightMinusOne := uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
+
+			return &Meta{
+				Format: "webp",
+				Width:  int(widthMinusOne) + 1,
+				Height: int(heightMinusOne) + 1,
+			}, nil
+
+		default:
+			return nil, ErrWebpInvalidFormat
+		}
+	}
+}
+
+func init() {
+	RegisterFormat("RIFF????WEBPVP8", DecodeWebpMeta)
+}

+ 0 - 20
svg.go

@@ -1,20 +0,0 @@
-package main
-
-import (
-	"image"
-	"image/color"
-	"io"
-)
-
-func init() {
-	// Register fake svg decoder. Since we need this only for type detecting, we can
-	// return fake image sizes
-	decode := func(io.Reader) (image.Image, error) {
-		return image.NewRGBA(image.Rect(0, 0, 1, 1)), nil
-	}
-	decodeConfig := func(io.Reader) (image.Config, error) {
-		return image.Config{ColorModel: color.RGBAModel, Width: 1, Height: 1}, nil
-	}
-	image.RegisterFormat("svg", "<?xml ", decode, decodeConfig)
-	image.RegisterFormat("svg", "<svg", decode, decodeConfig)
-}

+ 0 - 109
webp.go

@@ -1,109 +0,0 @@
-// 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.
-
-// Original code was cropped and fixed by @DarthSim for imgproxy needs
-
-package main
-
-import (
-	"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'}
-)
-
-// Since we need this only for type detecting, we can return fake image
-func decodeWebp(r io.Reader) (image.Image, error) {
-	return image.NewRGBA(image.Rect(0, 0, 1, 1)), nil
-}
-
-func decodeWebpConfig(r io.Reader) (image.Config, error) {
-	formType, riffReader, err := riff.NewReader(r)
-	if err != nil {
-		return image.Config{}, err
-	}
-	if formType != fccWEBP {
-		return image.Config{}, errInvalidFormat
-	}
-
-	var (
-		wantAlpha bool
-		buf       [10]byte
-	)
-
-	for {
-		chunkID, chunkLen, chunkData, err := riffReader.Next()
-		if err == io.EOF {
-			err = errInvalidFormat
-		}
-		if err != nil {
-			return image.Config{}, err
-		}
-
-		switch chunkID {
-		case fccALPH:
-			// Ignore
-		case fccVP8:
-			if wantAlpha || int32(chunkLen) < 0 {
-				return image.Config{}, errInvalidFormat
-			}
-
-			d := vp8.NewDecoder()
-			d.Init(chunkData, int(chunkLen))
-
-			fh, err := d.DecodeFrameHeader()
-
-			return image.Config{
-				ColorModel: color.YCbCrModel,
-				Width:      fh.Width,
-				Height:     fh.Height,
-			}, err
-
-		case fccVP8L:
-			if wantAlpha {
-				return image.Config{}, errInvalidFormat
-			}
-			return vp8l.DecodeConfig(chunkData)
-
-		case fccVP8X:
-			if chunkLen != 10 {
-				return image.Config{}, errInvalidFormat
-			}
-
-			if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
-				return image.Config{}, err
-			}
-
-			widthMinusOne := uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
-			heightMinusOne := uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
-
-			return image.Config{
-				ColorModel: color.NYCbCrAModel,
-				Width:      int(widthMinusOne) + 1,
-				Height:     int(heightMinusOne) + 1,
-			}, nil
-
-		default:
-			return image.Config{}, errInvalidFormat
-		}
-	}
-}
-
-func init() {
-	image.RegisterFormat("webp", "RIFF????WEBPVP8", decodeWebp, decodeWebpConfig)
-}