| // 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" |
| "io" |
| "os" |
| ) |
| |
| // An UnknownFormatErr indicates that decoding encountered an unknown format. |
| var UnknownFormatErr = os.NewError("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, os.Error) |
| decodeConfig func(io.Reader) (Config, os.Error) |
| } |
| |
| // Formats is the list of registered formats. |
| var formats []format |
| |
| // 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, os.Error), decodeConfig func(io.Reader) (Config, os.Error)) { |
| formats = append(formats, format{name, magic, decode, decodeConfig}) |
| } |
| |
| // A reader is an io.Reader that can also peek ahead. |
| type reader interface { |
| io.Reader |
| Peek(int) ([]byte, os.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 returns 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 { |
| 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 the init method of the codec- |
| // specific package. |
| func Decode(r io.Reader) (Image, string, os.Error) { |
| rr := asReader(r) |
| f := sniff(rr) |
| if f.decode == nil { |
| return nil, "", UnknownFormatErr |
| } |
| 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 |
| // the init method of the codec-specific package. |
| func DecodeConfig(r io.Reader) (Config, string, os.Error) { |
| rr := asReader(r) |
| f := sniff(rr) |
| if f.decodeConfig == nil { |
| return Config{}, "", UnknownFormatErr |
| } |
| c, err := f.decodeConfig(rr) |
| return c, f.name, err |
| } |