| 1 | 747 | jeremybenn | // 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 returns 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 the init method of 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 |  |  | // the init method of 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 |  |  | }
 |