// Fields.
fColorMapFollows = 1 << 7
+ // Screen Descriptor flags.
+ sdGlobalColorTable = 1 << 7
+
// Image fields.
ifLocalColorTable = 1 << 7
ifInterlace = 1 << 6
// Graphic control flags.
gcTransparentColorSet = 1 << 0
+ gcDisposalMethodMask = 7 << 2
+)
+
+// Disposal Methods.
+const (
+ DisposalNone = 0x01
+ DisposalBackground = 0x02
+ DisposalPrevious = 0x03
)
// Section indicators.
vers string
width int
height int
- flags byte
headerFields byte
backgroundIndex byte
loopCount int
delayTime int
+ disposalMethod byte
// Unused from header.
aspect byte
globalColorMap color.Palette
// Used when decoding.
- delay []int
- image []*image.Paletted
- tmp [1024]byte // must be at least 768 so we can read color map
+ delay []int
+ disposal []byte
+ image []*image.Paletted
+ tmp [1024]byte // must be at least 768 so we can read color map
}
// blockReader parses the block structure of GIF image data, which
d.image = append(d.image, m)
d.delay = append(d.delay, d.delayTime)
+ d.disposal = append(d.disposal, d.disposalMethod)
// The GIF89a spec, Section 23 (Graphic Control Extension) says:
// "The scope of this extension is the first graphic rendering block
// to follow." We therefore reset the GCE fields to zero.
d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
d.headerFields = d.tmp[10]
- d.backgroundIndex = d.tmp[11]
+ if d.headerFields&sdGlobalColorTable != 0 {
+ d.backgroundIndex = d.tmp[11]
+ }
d.aspect = d.tmp[12]
d.loopCount = -1
d.pixelSize = uint(d.headerFields&7) + 1
if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
return fmt.Errorf("gif: can't read graphic control: %s", err)
}
- d.flags = d.tmp[1]
+ flags := d.tmp[1]
+ d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
- if d.flags&gcTransparentColorSet != 0 {
+ if flags&gcTransparentColorSet != 0 {
d.transparentIndex = d.tmp[4]
d.hasTransparentIndex = true
}
type GIF struct {
Image []*image.Paletted // The successive images.
Delay []int // The successive delay times, one per frame, in 100ths of a second.
+ Disposal []byte // The successive disposal methods, one per frame.
LoopCount int // The loop count.
+ Config image.Config
+ // The background index in the Global Color Map.
+ BackgroundIndex byte
}
// DecodeAll reads a GIF image from r and returns the sequential frames
Image: d.image,
LoopCount: d.loopCount,
Delay: d.delay,
+ Disposal: d.disposal,
+ Config: image.Config{
+ ColorModel: d.globalColorMap,
+ Width: d.width,
+ Height: d.height,
+ },
+ BackgroundIndex: d.backgroundIndex,
}
return gif, nil
}