lin
2025-06-05 ed3dd9d3e7519a82bb871d5eedb24a2fa0c91f47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2010 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 image
 
import (
   "bufio"
   "errors"
   "io"
   "sync"
   "sync/atomic"
)
 
// ErrFormat indicates that decoding encountered an unknown format.
var ErrFormat = errors.New("image: unknown format")
 
// A format holds an image format's name, magic header and how to decode it.
type format struct {
   name, magic  string
   decode       func(io.Reader) (Image, error)
   decodeConfig func(io.Reader) (Config, error)
}
 
// Formats is the list of registered formats.
var (
   formatsMu     sync.Mutex
   atomicFormats atomic.Value
)
 
// RegisterFormat registers an image format for use by Decode.
// Name is the name of the format, like "jpeg" or "png".
// Magic is the magic prefix that identifies the format's encoding. The magic
// string can contain "?" wildcards that each match any one byte.
// Decode is the function that decodes the encoded image.
// DecodeConfig is the function that decodes just its configuration.
func RegisterFormat(name, magic string, decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error)) {
   formatsMu.Lock()
   formats, _ := atomicFormats.Load().([]format)
   atomicFormats.Store(append(formats, format{name, magic, decode, decodeConfig}))
   formatsMu.Unlock()
}
 
// A reader is an io.Reader that can also peek ahead.
type reader interface {
   io.Reader
   Peek(int) ([]byte, error)
}
 
// asReader converts an io.Reader to a reader.
func asReader(r io.Reader) reader {
   if rr, ok := r.(reader); ok {
       return rr
   }
   return bufio.NewReader(r)
}
 
// Match reports whether magic matches b. Magic may contain "?" wildcards.
func match(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
}
 
// Sniff determines the format of r's data.
func sniff(r reader) format {
   formats, _ := atomicFormats.Load().([]format)
   for _, f := range formats {
       b, err := r.Peek(len(f.magic))
       if err == nil && match(f.magic, b) {
           return f
       }
   }
   return format{}
}
 
// Decode decodes an image that has been encoded in a registered format.
// The string returned is the format name used during format registration.
// Format registration is typically done by an init function in the codec-
// specific package.
func Decode(r io.Reader) (Image, string, error) {
   rr := asReader(r)
   f := sniff(rr)
   if f.decode == nil {
       return nil, "", ErrFormat
   }
   m, err := f.decode(rr)
   return m, f.name, err
}
 
// DecodeConfig decodes the color model and dimensions of an image that has
// been encoded in a registered format. The string returned is the format name
// used during format registration. Format registration is typically done by
// an init function in the codec-specific package.
func DecodeConfig(r io.Reader) (Config, string, error) {
   rr := asReader(r)
   f := sniff(rr)
   if f.decodeConfig == nil {
       return Config{}, "", ErrFormat
   }
   c, err := f.decodeConfig(rr)
   return c, f.name, err
}