...

Source file src/pkg/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	}
   110	

View as plain text