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 Encoder
- type EncoderBuffer
- type EncoderBufferPool
- type FormatError
- type Frame
- type FrameByFrameEncoder
- 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)
}
}
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--
}
}
}
type CompressionLevel ¶
type CompressionLevel int
CompressionLevel indicates the compression level.
const ( DefaultCompression CompressionLevel = 0 NoCompression CompressionLevel = -1 BestSpeed CompressionLevel = -2 BestCompression CompressionLevel = -3 )
type Encoder ¶
type Encoder struct {
CompressionLevel CompressionLevel
// BufferPool optionally specifies a buffer pool to get temporary
// EncoderBuffers when encoding an image.
BufferPool EncoderBufferPool
}
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 FrameByFrameEncoder ¶
type FrameByFrameEncoder struct {
Encoder *EncoderBuffer
FrameCnt uint32
Started bool
}
func InitializeEncoding ¶
func InitializeEncoding(w io.Writer, frameCnt uint32, loopCount uint) *FrameByFrameEncoder
Call to initialize frame-by-frame encoding. Returns Encoder to use with remaining frame-by-frame functions
func (*FrameByFrameEncoder) EncodeFrame ¶
func (enc *FrameByFrameEncoder) EncodeFrame(frm Frame) error
Encode frame
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