New Page 1
'=================================说明======================================
'一、原理说明:
'这只是一个简单的Gif图片播放控件
'原理其实很简单Gif文件是由三部分构成
'1、头文件
'2、帧
'3、文件结束标志
'头文件前五个字母固定由Gif89构成,借此可以判断是否为Gif文件
'头文件、帧与帧之间固定由标志 &H21 & HF9
连接,
'从&H21开始的第四个字节表示帧之间的延迟。
'由此就可以由每一帧、头文件和文件结束标志
&H3B 来构成单帧Gif文件
'由程序一帧帧的来显示
'===============================/说明==========================================
Imports
System.IO
Imports System.Drawing
Imports System.Threading
Imports System.ComponentModel
<ToolboxBitmap("E:\Gif_Project\gif.ico"),
DefaultProperty("GifImage"), DefaultEvent("Stoped")>
_
Public Class
GifAnimation
Inherits
System.Windows.Forms.UserControl
Const
GifBz1 As Byte
= 33 '帧标志 &H21
Const
GifBz2 As Byte
= 249 '帧标志 &HF9
Const
GifEnd As Byte
= 179 '结尾标志 &H3B
#Region
" Windows 窗体设计器生成的代码 "
Public Sub
New()
MyBase.New()
'该调用是 Windows
窗体设计器所必需的。
InitializeComponent()
'在 InitializeComponent()
调用之后添加任何初始化
End Sub
'UserControl 重写 dispose
以清理组件列表。
Protected
Overloads Overrides
Sub Dispose(ByVal
disposing As
Boolean)
If
disposing Then
If Not
(components Is
Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Windows
窗体设计器所必需的
Private
components As
System.ComponentModel.IContainer
'注意: 以下过程是
Windows 窗体设计器所必需的
'可以使用 Windows
窗体设计器修改此过程。
'不要使用代码编辑器修改它。
Private WithEvents
PictureBox1 As
System.Windows.Forms.PictureBox
Friend WithEvents
Timer1 As
System.Windows.Forms.Timer
<System.Diagnostics.DebuggerStepThrough()> Private
Sub
InitializeComponent()
Me.components
= New
System.ComponentModel.Container
Me.PictureBox1
= New
System.Windows.Forms.PictureBox
Me.Timer1
= New
System.Windows.Forms.Timer(Me.components)
Me.SuspendLayout()
'
'PictureBox1
'
Me.PictureBox1.BorderStyle
= System.Windows.Forms.BorderStyle.FixedSingle
Me.PictureBox1.Location
= New
System.Drawing.Point(4, 1)
Me.PictureBox1.Name
= "PictureBox1"
Me.PictureBox1.Size
= New
System.Drawing.Size(72, 70)
Me.PictureBox1.SizeMode
= System.Windows.Forms.PictureBoxSizeMode.CenterImage
Me.PictureBox1.TabIndex
= 0
Me.PictureBox1.TabStop
= False
'
'Timer1
'
'
'GifAnimation
'
Me.Controls.Add(Me.PictureBox1)
Me.Name =
"GifAnimation"
Me.Size =
New
System.Drawing.Size(77, 72)
Me.ResumeLayout(False)
End Sub
#End Region
'集合用以获取每帧信息
Private
m_col_Gif As
Collection
'停止标志
Private
mblnStop As Boolean
= True
Private
mintCurrentPosition As
Integer '当前播放位置
Private
mimgGif As
Image
Private
mth As
Thread
Public Event
Stoped(ByVal
sender As Object)
'停止事件
Public WriteOnly
Property
GifFile() As
String
Set(ByVal
Value As String)
If Value Is
Nothing Then
Exit Property
mimgGif = Image.FromFile(Value)
m_col_Gif = FormatGIF(Value)
If
m_col_Gif Is
Nothing OrElse
m_col_Gif.Count = 0 Then
Me.PictureBox1.Image
= Nothing
mimgGif = Nothing
Exit Property
End If
SetPicToPicturbox(CType(m_col_Gif.Item(1),
GifFrame).Frame)
End Set
End Property
Public Property
SizeModel() As
PictureBoxSizeMode
Get
Return Me.PictureBox1.SizeMode
End Get
Set(ByVal
Value As
PictureBoxSizeMode)
Me.PictureBox1.SizeMode
= Value
End Set
End Property
Public Property
BorderStyle() As
BorderStyle
Get
Return Me.PictureBox1.BorderStyle
End Get
Set(ByVal
Value As
BorderStyle)
Me.PictureBox1.BorderStyle
= Value
End Set
End Property
Public Property
GifImage() As
Image
Get
Return
mimgGif
End Get
Set(ByVal
Value As
Image)
If Value Is
Nothing Then
Exit Property
mimgGif = Value
m_col_Gif = FormatGIF(Value)
If
m_col_Gif Is
Nothing OrElse
m_col_Gif.Count = 0 Then
Me.PictureBox1.Image
= Nothing
Exit Property
End If
SetPicToPicturbox(CType(m_col_Gif.Item(1),
GifFrame).Frame)
End Set
End Property
Public Sub
StopView()
mblnStop = True
End Sub
Private Sub
Start()
Dim i As
Integer
Dim gif As
GifFrame
Do Until
mblnStop = True
i += 1
If i >
m_col_Gif.Count Then
i = 1
End If
gif = m_col_Gif.Item(i)
Thread.Sleep(gif.Invert * 10) '帧与帧之间的延迟
'显示图像
SetPicToPicturbox(gif.Frame)
Loop
SetPicToPicturbox(CType(m_col_Gif.Item(1),
GifFrame).Frame)
RaiseEvent
Stoped(Me)
End Sub
Public Sub
StartView(Optional
ByVal
useTimer As Boolean
= True)
If
m_col_Gif Is
Nothing Then
Exit Sub
If
m_col_Gif.Count = 0 Then
Exit Sub
mblnStop = False
If
useTimer Then
If
m_col_Gif Is
Nothing Then
Exit Sub
If
m_col_Gif.Count = 0 Then
Exit Sub
mblnStop = False
Timer1.Enabled = True
Else
mth = New
Thread(AddressOf
Start)
mth.Priority = ThreadPriority.Normal
mth.Start()
End If
End Sub
'从文获得帧信息
Private Function
FormatGIF(ByVal
GifFile As String)
As
Collection
'打开图片文件
Dim fs As
New
FileStream(GifFile, FileMode.Open, FileAccess.Read)
'文件长度
Dim
fileLen As Long
= fs.Length
Dim
br As
New
BinaryReader(fs)
Dim buff As
Byte()
'将图片信息全部读入一个字节数组
buff = br.ReadBytes(fileLen)
Return
FormatGIF(buff)
End Function
'从Image对象获取帧信息
Private Function
FormatGIF(ByVal
GifImage As
Image) As
Collection
Dim col As
New
Collection
'创建一个内存流
Dim sr As
New
MemoryStream
'将图像写入到流
GifImage.Save(sr, GifImage.RawFormat.Gif)
Dim buff As
Byte()
'将图像转换成字节数组
buff = sr.ToArray
Return
FormatGIF(buff)
End Function
'从一个字节数组获得帧信息
Private Function
FormatGIF(ByVal
buff() As Byte)
As
Collection
Dim col As
New
Collection
Dim
Index1 As Long
Dim
Index2 As Long
Dim
IndexTmp As Long
Dim
intTime As Integer
Dim
buffHead() As
Byte
Dim
buffBody() As
Byte
Dim img As
Image
If
buff.Length < 3 Then
Return col
'将头三字节转换成字符串
Dim tmp As
String =
System.Text.Encoding.Default.GetString(buff, 0, 3).ToLower
'是否是Gif文件
If tmp
<> "gif" Then
Throw New
Exception("图片格式错误!必须是Gif文件")
End If
Do
'查找第一个标志 &H21
Index1 = buff.IndexOf(buff, GifBz1, Index1 + 1)
If Index1
< 0 Or
Index1 >= buff.Length - 1 Then
Return col
'查找第二个标志 &H21
Index2 = buff.IndexOf(buff, GifBz2, Index1)
'两个标志是否连续
If Index2
- Index1 = 1 Then
Exit Do
Loop
IndexTmp = Index1
'创建一个缓冲
buffHead = buffHead.CreateInstance(GetType(System.Byte),
Index1)
'获得头部信息
buff.Copy(buff, buffHead, Index1) 'read
gifhead
Do
Do
Index1 = buff.IndexOf(buff, GifBz1, Index1 + 1)
If Index1
< 0 Or
Index1 >= buff.Length - 1 Then
Exit Do
Index2 = buff.IndexOf(buff, GifBz2, Index1)
If Index2
- Index1 = 1 Then
Exit Do
Loop
'是否是最后一帧
If Index1
< 0 Or
Index1 >= buff.Length - 1 Then
Exit Do
'创建缓冲
buffBody = buffBody.CreateInstance(GetType(Byte),
Index1 - IndexTmp)
'获取帧信息
buffBody.Copy(buff, IndexTmp, buffBody, 0, Index1 - IndexTmp)
' 获取每帧的间隔时间
intTime = Val(buff(IndexTmp + 4))
'重建每帧图像
img = CreateImage(buffHead, buffBody)
'创建一个帧对象
Dim gif As
New
GifFrame(img, intTime)
'添加到集合
col.Add(gif)
IndexTmp = Index1
Loop
'最后一帧
buffBody = buffBody.CreateInstance(GetType(Byte),
buff.Length - IndexTmp)
buffBody.Copy(buff, IndexTmp, buffBody, 0, buff.Length - IndexTmp)
'获取每帧的间隔时间
intTime = Val(buff(IndexTmp + 4))
img = CreateImage(buffHead, buffBody, False)
Dim gifs As
New
GifFrame(img, intTime)
col.Add(gifs)
Return
col
End Function
'创建一个帧图像
Private Function
CreateImage(ByVal
gifHead() As
Byte, ByVal
gifBody() As
Byte, Optional
ByVal AddEnd
As Boolean
= True) As
Image
'创建一个内存流
Dim sm As
New
MemoryStream
Dim img As
Image
'写入头部信息
sm.Write(gifHead, 0, gifHead.Length)
'写入帧信息
sm.Write(gifBody, 0, gifBody.Length)
'如果不是最后一帧则写入结束标志
If AddEnd
Then
sm.WriteByte(Me.GifEnd)
'创建图形
img = Image.FromStream(sm)
'关闭流
sm.Close()
Return
img
End Function
'显示一个帧图像
Private Sub
SetPicToPicturbox(ByVal
img As
Image)
Me.PictureBox1.Image
= img
PictureBox1.Top = 0
PictureBox1.Left = 0
If
PictureBox1.SizeMode <> PictureBoxSizeMode.AutoSize Then
Exit Sub
Me.Width
= Me.PictureBox1.Width
Me.Height
= Me.PictureBox1.Height
End Sub
Private Sub
Timer1_Tick(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles
Timer1.Tick
If
mintCurrentPosition < m_col_Gif.Count Then
mintCurrentPosition = mintCurrentPosition + 1
Else
mintCurrentPosition = 1
End If
'获取当前帧
Dim gif As
GifFrame = m_col_Gif.Item(mintCurrentPosition)
SetPicToPicturbox(gif.Frame) '显示帧图像
Timer1.Interval = gif.Invert * 10 '帧延迟
If
mblnStop = True
Then
Timer1.Enabled = False
SetPicToPicturbox(CType(m_col_Gif.Item(1),
GifFrame).Frame)
RaiseEvent
Stoped(Me) '触发事件
End If
End Sub
Private Sub
GifAnimation_BackColorChanged(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles
MyBase.BackColorChanged
PictureBox1.BackColor = Me.BackColor
End Sub
Private Sub
GifAnimation_Resize(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles
MyBase.Resize
PictureBox1.Top = 0
PictureBox1.Left = 0
If
PictureBox1.SizeMode <> PictureBoxSizeMode.AutoSize Then
PictureBox1.Width = Me.Width
PictureBox1.Height = Me.Height
Else
Me.Width
= PictureBox1.Width
Me.Height
= PictureBox1.Height
End If
End Sub
Private Sub
GifAnimation_Disposed(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles
MyBase.Disposed
Try
Me.mblnStop
= True
If Not
mth Is Nothing
Then
'停止线程
mth.Abort()
End If
Catch ex As
Exception
End Try
End Sub
'帧对象
'用以储存每帧的信息:帧延迟、图像
Private Class
GifFrame
Public
Frame As
Image '帧图像
Public
Invert As Integer
'帧延迟
Public Sub
New(ByVal
img As
Image, ByVal
time As Integer)
Frame = img
Invert = time
End Sub
End Class
End Class