github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/image/format.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package image 6 7 import ( 8 "bufio" 9 "errors" 10 "io" 11 ) 12 13 // ErrFormat indicates that decoding encountered an unknown format. 14 var ErrFormat = errors.New("image: unknown format") 15 16 // A format holds an image format's name, magic header and how to decode it. 17 type format struct { 18 name, magic string 19 decode func(io.Reader) (Image, error) 20 decodeConfig func(io.Reader) (Config, error) 21 } 22 23 // Formats is the list of registered formats. 24 var formats []format 25 26 // RegisterFormat registers an image format for use by Decode. 27 // Name is the name of the format, like "jpeg" or "png". 28 // Magic is the magic prefix that identifies the format's encoding. The magic 29 // string can contain "?" wildcards that each match any one byte. 30 // Decode is the function that decodes the encoded image. 31 // DecodeConfig is the function that decodes just its configuration. 32 func RegisterFormat(name, magic string, decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error)) { 33 formats = append(formats, format{name, magic, decode, decodeConfig}) 34 } 35 36 // A reader is an io.Reader that can also peek ahead. 37 type reader interface { 38 io.Reader 39 Peek(int) ([]byte, error) 40 } 41 42 // asReader converts an io.Reader to a reader. 43 func asReader(r io.Reader) reader { 44 if rr, ok := r.(reader); ok { 45 return rr 46 } 47 return bufio.NewReader(r) 48 } 49 50 // Match reports whether magic matches b. Magic may contain "?" wildcards. 51 func match(magic string, b []byte) bool { 52 if len(magic) != len(b) { 53 return false 54 } 55 for i, c := range b { 56 if magic[i] != c && magic[i] != '?' { 57 return false 58 } 59 } 60 return true 61 } 62 63 // Sniff determines the format of r's data. 64 func sniff(r reader) format { 65 for _, f := range formats { 66 b, err := r.Peek(len(f.magic)) 67 if err == nil && match(f.magic, b) { 68 return f 69 } 70 } 71 return format{} 72 } 73 74 // Decode decodes an image that has been encoded in a registered format. 75 // The string returned is the format name used during format registration. 76 // Format registration is typically done by an init function in the codec- 77 // specific package. 78 func Decode(r io.Reader) (Image, string, error) { 79 rr := asReader(r) 80 f := sniff(rr) 81 if f.decode == nil { 82 return nil, "", ErrFormat 83 } 84 m, err := f.decode(rr) 85 return m, f.name, err 86 } 87 88 // DecodeConfig decodes the color model and dimensions of an image that has 89 // been encoded in a registered format. The string returned is the format name 90 // used during format registration. Format registration is typically done by 91 // an init function in the codec-specific package. 92 func DecodeConfig(r io.Reader) (Config, string, error) { 93 rr := asReader(r) 94 f := sniff(rr) 95 if f.decodeConfig == nil { 96 return Config{}, "", ErrFormat 97 } 98 c, err := f.decodeConfig(rr) 99 return c, f.name, err 100 }