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
5package image
6
7import (
8	"bufio"
9	"errors"
10	"io"
11)
12
13// ErrFormat indicates that decoding encountered an unknown format.
14var ErrFormat = errors.New("image: unknown format")
15
16// A format holds an image format's name, magic header and how to decode it.
17type 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.
24var 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.
32func 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.
37type reader interface {
38	io.Reader
39	Peek(int) ([]byte, error)
40}
41
42// asReader converts an io.Reader to a reader.
43func 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.
51func 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.
64func 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.
78func 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.
92func 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}
101