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