Documentation ¶
Overview ¶
Package apng implements an APNG image decoder.
The PNG specification is at https://www.w3.org/TR/PNG/. The APNG specification is at https://wiki.mozilla.org/APNG_Specification
Index ¶
- Constants
- func Decode(r io.Reader) (image.Image, error)
- func DecodeConfig(r io.Reader) (image.Config, error)
- func Encode(w io.Writer, a APNG) error
- type APNG
- type CompressionLevel
- type CompressionWriter
- type Encoder
- type EncoderBuffer
- type EncoderBufferPool
- type FormatError
- type Frame
- type UnsupportedError
Examples ¶
Constants ¶
const ( DISPOSE_OP_NONE = 0 DISPOSE_OP_BACKGROUND = 1 DISPOSE_OP_PREVIOUS = 2 )
dispose_op values, as per the APNG spec.
const ( BLEND_OP_SOURCE = 0 BLEND_OP_OVER = 1 )
blend_op values, as per the APNG spec.
Variables ¶
This section is empty.
Functions ¶
func DecodeConfig ¶
DecodeConfig returns the color model and dimensions of a PNG image without decoding the entire image.
func Encode ¶
Encode writes the APNG a to w in PNG format. Any Image may be encoded, but images that are not image.NRGBA might be encoded lossily.
Example ¶
package main import ( "image" "image/color" "math" "os" "github.com/kettek/apng" ) func main() { w, h := 200, 200 am := apng.APNG{Frames: make([]apng.Frame, 20)} var circles [3]image.Point for i := range am.Frames { im := image.NewRGBA(image.Rect(0, 0, w, h)) am.Frames[i].Image = im theta := float64(i) * 2 * math.Pi / float64(len(am.Frames)) for c := range circles { theta0 := float64(c) * 2 * math.Pi / 3 circles[c].X = int(float64(w) * (0.5 - 0.15*math.Sin(theta0) - 0.1*math.Sin(theta0+theta))) circles[c].Y = int(float64(h) * (0.5 - 0.15*math.Cos(theta0) - 0.1*math.Cos(theta0+theta))) } for y := 0; y < h; y++ { for x := 0; x < w; x++ { var rgb [3]uint8 for c := range circles { dx, dy := x-circles[c].X, y-circles[c].Y if dx*dx+dy*dy < int(float64(w*h)/20) { rgb[c] = 0xff } } im.Set(x, y, color.RGBA{R: rgb[0], G: rgb[1], B: rgb[2], A: 0xff}) } } } f, err := os.Create("rgb.png") if err != nil { panic(err) } defer f.Close() if err := apng.Encode(f, am); err != nil { panic(err) } }
Output:
Types ¶
type APNG ¶
type APNG struct { Frames []Frame // LoopCount defines the number of times an animation will be // restarted during display. // A LoopCount of 0 means to loop forever LoopCount uint }
func DecodeAll ¶
DecodeAll reads an APNG file from r and returns it as an APNG Type. If the first frame returns true for IsDefault(), that frame should not be part of the result. The type of Image returned depends on the PNG contents.
Example ¶
package main import ( "encoding/base64" "image/color" "io" "strings" "time" "github.com/kettek/apng" ) const gopher = `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` // gopherPNG creates an io.Reader by decoding the base64 encoded image data string in the gopher constant. func gopherPNG() io.Reader { return base64.NewDecoder(base64.StdEncoding, strings.NewReader(gopher)) } func main() { am, err := apng.DecodeAll(gopherPNG()) if err != nil { panic(err) } levels := []rune(" ░▒▓█") loops := int64(am.LoopCount) if loops == 0 { loops = -1 } rect := am.Frames[0].Image.Bounds() buf := make([][]rune, rect.Dy()) for y := range buf { buf[y] = make([]rune, rect.Dx()) for x := range buf[y] { buf[y][x] = ' ' } } n := time.Now() print("\x1b[2J") // clear screen for loops != 0 { for i, fr := range am.Frames { for y := 0; y < fr.Image.Bounds().Dy(); y++ { for x := 0; x < fr.Image.Bounds().Dx(); x++ { c := fr.Image.At(x, y) if _, _, _, a := c.RGBA(); a > 0 { buf[y+fr.YOffset][x+fr.XOffset] = levels[(color.GrayModel.Convert(c).(color.Gray).Y / 52)] } else if fr.BlendOp == apng.BLEND_OP_SOURCE { buf[y+fr.YOffset][x+fr.XOffset] = ' ' } } } print("\x1b[H") // move top left for y := range buf { println(string(buf[y])) } time.Sleep(time.Duration(float64(time.Second)*float64(fr.DelayNumerator)/float64(fr.DelayDenominator)) - time.Now().Sub(n)) n = time.Now() if fr.DisposeOp == apng.DISPOSE_OP_BACKGROUND || i == len(am.Frames)-1 { for y := 0; y < fr.Image.Bounds().Dy(); y++ { for x := 0; x < fr.Image.Bounds().Dx(); x++ { buf[y+fr.YOffset][x+fr.XOffset] = ' ' } } } } if loops > 0 { loops-- } } }
Output:
type CompressionLevel ¶
type CompressionLevel int
CompressionLevel indicates the compression level.
const ( DefaultCompression CompressionLevel = 0 NoCompression CompressionLevel = -1 BestSpeed CompressionLevel = -2 BestCompression CompressionLevel = -3 )
type CompressionWriter ¶
type CompressionWriter interface { Write(p []byte) (n int, err error) Reset(w io.Writer) Close() error }
CompressionWriter zlib compression writer interface.
type Encoder ¶
type Encoder struct { CompressionLevel CompressionLevel // BufferPool optionally specifies a buffer pool to get temporary // EncoderBuffers when encoding an image. BufferPool EncoderBufferPool // CompressionWriter optionally provides a external zlib compression // writer for writing PNG image data. CompressionWriter func(w io.Writer) (CompressionWriter, error) }
Encoder configures encoding PNG images.
type EncoderBuffer ¶
type EncoderBuffer encoder
EncoderBuffer holds the buffers used for encoding PNG images.
type EncoderBufferPool ¶
type EncoderBufferPool interface { Get() *EncoderBuffer Put(*EncoderBuffer) }
EncoderBufferPool is an interface for getting and returning temporary instances of the EncoderBuffer struct. This can be used to reuse buffers when encoding multiple images.
type FormatError ¶
type FormatError string
A FormatError reports that the input is not a valid PNG.
func (FormatError) Error ¶
func (e FormatError) Error() string
type Frame ¶
type Frame struct { Image image.Image XOffset, YOffset int DelayNumerator uint16 DelayDenominator uint16 DisposeOp byte BlendOp byte // IsDefault indicates if the Frame is a default image that // should not be used in the animation. IsDefault can only // be true on the first frame. IsDefault bool // contains filtered or unexported fields }
type UnsupportedError ¶
type UnsupportedError string
An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
func (UnsupportedError) Error ¶
func (e UnsupportedError) Error() string