I like Arraylists. They are wonderful. You can feed them anything and they will digest it without complaining. You can add, delete, insert elements or ranges of elements without any complain and without even needing to re-dimension them. They take objects, and the objects can be of any class, images, sounds, controls, filenames..., even you can add different kinds of objects one after the other or at least a refference to it.
Don't believe me? Just press the button "Believe" and see what happens.
Anyway the purpose of this post is to highlight a situation on another program I made:
On that program I did extract the frames from a gif animation to files in a folder and then manipulated them reading and writting to disk. That was wasteful and slow. So I modified my program to do everything in memory. What do I use? Three arraylists.
This is just a sample project that won't do too much, but will give you a hint of what other things can be done.
Here I open a gif animation and dissassemble it intro frames(bitmaps). Convert them to a readable format (jpeg) and save them in an arraylist. From there I read them to show the individual frames on a picturebox. And change frames by pushing a couple of buttons, controlled by a timer, so it gives the impression of an animation.
The bitmaps in the arraylist are objects that don't have a text or name property and they have the same dimensions, so they can't easily be reordered without creating a class to use some other property. But, by using another arraylist they can be reverted in order.
My layout has a panel set to autoscroll and a picturebox set to autosize, so the image comes at normal size, but can be scrolled.
I added a subroutine for saving one frame to disk but you have to take care of the names if you want to save more frames.
Form load will create the tooltips and arraylists needed:
Imports System.IO Imports System.Collections Imports System.Drawing.Imaging Imports System.Drawing.Drawing2D Public Class Form1 Dim OriginalGif As Image Dim PicArray1, PicArray2 As ArrayList Dim N As Integer = 0 Dim Forward As Boolean = True Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ToolTip1.SetToolTip(btnReverse, "Will Reverse Images In The Arraylist") ToolTip1.SetToolTip(btnBack, "Will Show Images In Reverse Sequence" & vbNewLine & "Keep It Down For Animation") ToolTip1.SetToolTip(btnBack, "Will Show Images In Forward Sequence" & vbNewLine & "Keep It Down For Animation") PicArray1 = New ArrayList PicArray2 = New ArrayList End Sub
And Menu->File->Open will open and load an animation.
Private Sub OpenToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OpenToolStripMenuItem.Click Dim f As New OpenFileDialog Try With f .Filter = "Gif Files|*.gif" If .ShowDialog = DialogResult.OK Then OriginalGif = Image.FromFile(.FileName) Rip() pbOutput.Image = PicArray1(0) btnBack.Enabled = True btnForward.Enabled = True btnReverse.Enabled = True End If End With Catch ex As Exception MessageBox.Show(ex.ToString) Finally If Not f Is Nothing Then f.Dispose() f = Nothing End If End Try End Sub
Enable the controls and call the "Rip" function to dissassemble the animation and extract the frames:
Public Sub Rip() PicArray1.Clear() ' Dim Picture As Image Dim OrigDim As New FrameDimension(OriginalGif.FrameDimensionsList(0)) Dim FrameCount As Integer = OriginalGif.GetFrameCount(OrigDim) ' Dim MemStr As Bitmap For i As Integer = 0 To FrameCount - 1 OriginalGif.SelectActiveFrame(OrigDim, i) Using Frames As New Bitmap(OriginalGif) PicArray1.Add(ConvertToRGB(Frames.Clone)) ' To avoid external code error in gdi End Using Next End Sub
The "Rip" function will call the function "ConvertToRGB" that will change the format of the frames to "RGB", so they can be manipulated without getting "External error code in GDI":
Public Shared Function ConvertToRGB(ByVal original As Bitmap) As Bitmap Dim newImage As New Bitmap(original.Width, original.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb) newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution) Dim g As Graphics = Graphics.FromImage(newImage) g.DrawImageUnscaled(original, 0, 0) g.Dispose() Return newImage End Function
Now we have the bitmaps in an arraylist. What can we do with them? That is up to you.
I am only viewing them in this program and saving one individual frame. But you can do so many other things as your imagination may allow.
For viewing, the first frame is shown on the picturebox, by clicking the chevrons you could advance or reverse on the frames. If you press down and keep it down then you will see a pseudo animation, in forward or reverse, controlled by the timer:
Private Sub btnForward_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnForward.Click 'View Jpg Files in Directory If PicArray1.Count = 1 Then Exit Sub N += 1 If N > PicArray1.Count - 1 Then N = 0 End If If PicArray1(N) IsNot Nothing Then pbOutput.Image = PicArray1(N) End If End Sub Private Sub btnBack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBack.Click 'View Jpg Files in Directory If PicArray1.Count = 1 Then Exit Sub N = N - 1 If N < 0 Then N = PicArray1.Count - 1 End If If PicArray1(N) IsNot Nothing Then pbOutput.Image = PicArray1(N) End If End Sub Private Sub btnForward_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnForward.MouseDown, btnBack.MouseDown If sender Is btnForward Then Forward = True If sender Is btnBack Then Forward = False Timer1.Enabled = True End Sub Private Sub btnForward_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnForward.MouseUp, btnBack.MouseUp Timer1.Enabled = False End Sub Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick If Forward = True Then btnForward.PerformClick() If Forward = False Then btnBack.PerformClick() End Sub
And for saving:
Private Sub SaveToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveToolStripMenuItem.Click Dim Str As String = "MyFile.jpg" If Not System.IO.File.Exists(Str) Then Try pbOutput.Image.Save(Str, System.Drawing.Imaging.ImageFormat.Jpeg) 'PictureBox1.Image.Save(str, System.Drawing.Imaging.ImageFormat.Png) Catch Ex As Exception MessageBox.Show("Could Not Write To Location " & Ex.ToString) End Try End If End Sub
It will create a file in your program directory.
I also added a subroutine to revert the order of the frames. So when yo press the chevron to advance, the animation will reverse, and so will the other button. Here you see how I reversed the frames:
Private Sub btnReverse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReverse.Click PicArray2.Clear() For i As Integer = PicArray1.Count - 1 To 0 Step -1 PicArray2.Add(PicArray1(i)) Next PicArray1.Clear() For Each obj As Object In PicArray2 PicArray1.Add(obj) Next pbOutput.Image = PicArray1(0) pbOutput.Refresh() End Sub
That is it. Please check the attached project sample.
The code for the believe button is in the project.
Number of downloads: 636