mirror of
https://gitee.com/energye/energy.git
synced 2024-12-06 05:38:17 +08:00
U: TGIFAnimate To handle simple GIF animations
This commit is contained in:
parent
66ce6e5889
commit
3cfef1130b
@ -14,15 +14,25 @@ package gifanim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/energye/energy/v2/pkgs/ext"
|
||||
"github.com/energye/golcl/lcl"
|
||||
"github.com/energye/golcl/lcl/types"
|
||||
"image/gif"
|
||||
"image/png"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
DisposalNone = iota + 1
|
||||
DisposalBackground
|
||||
DisposalPrevious
|
||||
)
|
||||
|
||||
type TGIFAnimate struct {
|
||||
*lcl.TImage
|
||||
*ext.TImage
|
||||
buffImg *lcl.TBitmap
|
||||
task *lcl.TTimer
|
||||
delay uint32
|
||||
filePath string
|
||||
cache bool
|
||||
gif *gif.GIF
|
||||
@ -37,53 +47,132 @@ type TGIFAnimate struct {
|
||||
|
||||
func NewGIFAnimate(owner lcl.IComponent) *TGIFAnimate {
|
||||
m := new(TGIFAnimate)
|
||||
m.TImage = lcl.NewImage(owner)
|
||||
m.delay = 100
|
||||
m.buffImg = lcl.NewBitmap()
|
||||
m.TImage = ext.NewImage(owner)
|
||||
//m.SetOnPaint(m.onPaint)
|
||||
m.task = lcl.NewTimer(owner)
|
||||
m.task.SetEnabled(false)
|
||||
m.task.SetInterval(100)
|
||||
m.task.SetInterval(m.delay)
|
||||
m.task.SetOnTimer(m.onTimer)
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) Free() {
|
||||
m.Stop()
|
||||
m.reset()
|
||||
m.TImage.Free()
|
||||
m.buffImg.Free()
|
||||
m.task.Free()
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) onTimer(sender lcl.IObject) {
|
||||
if m.count == 0 {
|
||||
return
|
||||
}
|
||||
frame := m.frames[m.index]
|
||||
m.doFrameChanged(frame)
|
||||
m.scan()
|
||||
if m.index >= m.count-1 {
|
||||
m.index = 0
|
||||
} else {
|
||||
m.index++
|
||||
}
|
||||
nextDelay := m.nextDelay()
|
||||
if nextDelay != frame.delay {
|
||||
m.task.SetInterval(nextDelay)
|
||||
if nextDelay != m.delay {
|
||||
m.delay = nextDelay
|
||||
m.task.SetEnabled(false)
|
||||
m.task.SetInterval(m.delay)
|
||||
m.task.SetEnabled(true)
|
||||
}
|
||||
m.scan(frame)
|
||||
//m.Repaint() 使用OnPaint有些问题, 这里直接绘制
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) nextDelay() uint32 {
|
||||
return m.frames[m.index].delay
|
||||
func (m *TGIFAnimate) onPaint(sender lcl.IObject) {
|
||||
m.scan()
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) first() {
|
||||
func (m *TGIFAnimate) initialed() {
|
||||
m.w = int32(m.gif.Config.Width)
|
||||
m.h = int32(m.gif.Config.Height)
|
||||
m.SetWidth(m.w)
|
||||
m.SetHeight(m.h)
|
||||
m.Canvas().FillRect(types.Rect(0, 0, m.w, m.h))
|
||||
m.scan(m.frames[0])
|
||||
m.Picture().LoadFromBytes(m.frames[0].data)
|
||||
m.buffImg.SetSize(m.w, m.h)
|
||||
m.buffImg.SetPixelFormat(types.Pf32bit)
|
||||
m.buffImg.SetHandleType(types.BmDIB)
|
||||
// 填充整个画布
|
||||
//m.Canvas().FillRect(types.Rect(0, 0, m.w, m.h))
|
||||
//m.Repaint()
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) scan(frame *Frame) {
|
||||
func (m *TGIFAnimate) scan() {
|
||||
frame := m.currentFrame()
|
||||
m.doFrameChanged(frame)
|
||||
frame.scan()
|
||||
m.Canvas().Draw(frame.x, frame.y, frame.image)
|
||||
canvas := m.Canvas()
|
||||
m.buffImg.Canvas().Draw(frame.x, frame.y, frame.image)
|
||||
//canvas.Draw(frame.x, frame.y, frame.image)
|
||||
switch frame.method {
|
||||
case DisposalNone: // 不处理,图形留在原处
|
||||
case DisposalBackground: // 删除当前帧,恢复为上一个帧的内容. 显示图形的区域必须要恢复成背景颜色
|
||||
// TOdO 先不处理,当前只处理简单的GIF
|
||||
//pFrame := m.priorFrame(frame.index)
|
||||
//pFrame.scan()
|
||||
////canvas.Draw(pFrame.x, pFrame.y, pFrame.image)
|
||||
//m.buffImg.Canvas().Draw(pFrame.x, pFrame.y, pFrame.image)
|
||||
//m.task.SetEnabled(false) // debug
|
||||
case DisposalPrevious: // 删除当前帧,恢复为 GIF 开始时的状态
|
||||
canvas.FillRect(Rect(0, 0, m.w, m.h))
|
||||
}
|
||||
canvas.Draw(0, 0, m.buffImg)
|
||||
//canvas.Draw(frame.x, frame.y, frame.image)
|
||||
if !m.cache {
|
||||
frame.reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) load() {
|
||||
m.reset()
|
||||
m.count = len(m.gif.Image)
|
||||
m.frames = make([]*Frame, m.count)
|
||||
for i, frame := range m.gif.Image {
|
||||
bounds := frame.Bounds()
|
||||
var pngBuf bytes.Buffer
|
||||
err := png.Encode(&pngBuf, frame)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.frames[i] = &Frame{
|
||||
index: i,
|
||||
method: m.gif.Disposal[i],
|
||||
x: int32(bounds.Min.X),
|
||||
y: int32(bounds.Min.Y),
|
||||
w: int32(bounds.Dx()),
|
||||
h: int32(bounds.Dy()),
|
||||
delay: uint32(m.gif.Delay[i] * 10),
|
||||
data: pngBuf.Bytes(),
|
||||
}
|
||||
pngBuf.Reset()
|
||||
}
|
||||
m.initialed()
|
||||
m.gif = nil
|
||||
}
|
||||
|
||||
//
|
||||
//func background(width, height int, data []byte) lcl.IBitmap {
|
||||
// bmp := lcl.NewBitmap()
|
||||
// bmp.SetSize(int32(width), int32(height))
|
||||
// bmp.SetPixelFormat(types.Pf32bit)
|
||||
// bmp.SetHandleType(types.BmDIB)
|
||||
// //bmp.SetTransparent(true)
|
||||
//
|
||||
// img := lcl.NewPngImage()
|
||||
// //img.SetTransparent(true)
|
||||
// img.LoadFromBytes(data)
|
||||
// bmp.Assign(img)
|
||||
//
|
||||
// return bmp
|
||||
//}
|
||||
|
||||
func (m *TGIFAnimate) reset() {
|
||||
for _, frame := range m.frames {
|
||||
frame.free()
|
||||
@ -94,30 +183,37 @@ func (m *TGIFAnimate) reset() {
|
||||
m.count = 0
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) load() {
|
||||
m.reset()
|
||||
m.count = len(m.gif.Image)
|
||||
m.frames = make([]*Frame, m.count)
|
||||
for i, img := range m.gif.Image {
|
||||
bounds := img.Bounds()
|
||||
var buf = new(bytes.Buffer)
|
||||
err := gif.Encode(buf, img, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.frames[i] = &Frame{
|
||||
index: i,
|
||||
x: int32(bounds.Min.X),
|
||||
y: int32(bounds.Min.Y),
|
||||
w: int32(bounds.Dx()),
|
||||
h: int32(bounds.Dy()),
|
||||
delay: uint32(m.gif.Delay[i] * 10),
|
||||
data: buf.Bytes(),
|
||||
}
|
||||
buf.Reset()
|
||||
func (m *TGIFAnimate) nextDelay() uint32 {
|
||||
return m.frames[m.index].delay
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) currentFrame() *Frame {
|
||||
return m.frames[m.index]
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) PrevFrame() {
|
||||
m.index--
|
||||
if m.index < 0 {
|
||||
m.index = m.count - 1
|
||||
}
|
||||
m.first()
|
||||
m.gif = nil
|
||||
m.scan()
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) NextFrame() {
|
||||
if m.index >= m.count-1 {
|
||||
m.index = 0
|
||||
} else {
|
||||
m.index++
|
||||
}
|
||||
m.scan()
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) priorFrame(index int) *Frame {
|
||||
index--
|
||||
if index < 0 {
|
||||
index = m.count - 1
|
||||
}
|
||||
return m.frames[index]
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) SetAnimate(v bool) {
|
||||
@ -129,6 +225,10 @@ func (m *TGIFAnimate) SetAnimate(v bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) Animate() bool {
|
||||
return m.task.Enabled()
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) CurrentFrameIndex() int {
|
||||
return m.index
|
||||
}
|
||||
@ -159,8 +259,8 @@ func (m *TGIFAnimate) doStop() {
|
||||
}
|
||||
|
||||
func (m *TGIFAnimate) doStart() {
|
||||
if m.onStop != nil {
|
||||
m.onStop()
|
||||
if m.onStart != nil {
|
||||
m.onStart()
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,3 +311,7 @@ func (m *TGIFAnimate) LoadFromBytes(data []byte) {
|
||||
m.gif = g
|
||||
m.load()
|
||||
}
|
||||
|
||||
func Rect(left, top, right, bottom int32) types.TRect {
|
||||
return types.TRect{Left: left, Top: top, Right: right, Bottom: bottom}
|
||||
}
|
||||
|
@ -10,15 +10,20 @@
|
||||
|
||||
package gifanim
|
||||
|
||||
import "github.com/energye/golcl/lcl"
|
||||
import (
|
||||
"github.com/energye/golcl/lcl"
|
||||
)
|
||||
|
||||
type Frame struct {
|
||||
index int
|
||||
x, y int32
|
||||
w, h int32
|
||||
delay uint32
|
||||
data []byte
|
||||
image *lcl.TGIFImage
|
||||
index int
|
||||
method byte
|
||||
x, y int32
|
||||
w, h int32
|
||||
delay uint32
|
||||
data []byte
|
||||
//background lcl.IBitmap
|
||||
//image *lcl.TGIFImage
|
||||
image *lcl.TPngImage
|
||||
}
|
||||
|
||||
func (m *Frame) Index() int {
|
||||
@ -30,26 +35,43 @@ func (m *Frame) Point() (x, y int32) {
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Frame) SetPoint(x, y int32) {
|
||||
m.x, m.y = x, y
|
||||
}
|
||||
|
||||
func (m *Frame) Rect() (width, height int32) {
|
||||
width, height = m.w, m.h
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Frame) SetRect(width, height int32) {
|
||||
m.w, m.h = width, height
|
||||
}
|
||||
|
||||
func (m *Frame) Delay() uint32 {
|
||||
return m.delay
|
||||
}
|
||||
|
||||
func (m *Frame) SetDelay(delay uint32) {
|
||||
m.delay = delay
|
||||
}
|
||||
|
||||
func (m *Frame) Data() []byte {
|
||||
return m.data
|
||||
}
|
||||
|
||||
func (m *Frame) Image() *lcl.TGIFImage {
|
||||
return m.image
|
||||
func (m *Frame) SetData(data []byte) {
|
||||
m.data = data
|
||||
}
|
||||
|
||||
//func (m *Frame) Image() *lcl.TGIFImage {
|
||||
// return m.image
|
||||
//}
|
||||
|
||||
func (m *Frame) scan() {
|
||||
if m.image == nil {
|
||||
m.image = lcl.NewGIFImage()
|
||||
//m.image = lcl.NewGIFImage()
|
||||
m.image = lcl.NewPngImage()
|
||||
m.image.SetSize(m.w, m.h)
|
||||
m.image.LoadFromBytes(m.data)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user