Avatar of jeesrinu
jeesrinu
 asked on

How to load images into windows forms or Listview as faster?

I am using Imagelist control for loading images and listview control is used to show images. I used Application.DoEvents() also for updating GUI. But The process is very slow. I need a approach to load images fastly as same as in Windows Movie Maker --> Import Pictures option. For loading 250 images my program takes 9 seconds, But movie maker takes just 2 seconds. Give me a suggestion. Thanks in advance.
.NET Programming

Avatar of undefined
Last Comment
jeesrinu

8/22/2022 - Mon
Mike Tomlinson

Can you show us your current loading code?

The most common method is to live with an SLOW first load but make thumbnails of the images and store them in the same folder with a different extension.  Then subsequent runs can load the smaller file and execute faster.  This way you only load the full size image when it is actually needed.
jeesrinu

ASKER

openFileDialog1.Multiselect = true;
            imageList1.ImageSize = new Size(100, 75);
            listView1.View = View.LargeIcon;
            listView1.Font = new Font("arail", 8);
            ListViewItem item;
            //listView1.Columns.Add("0","Nothing",80,HorizontalAlignment.Center,0);
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                btnClearlist.Enabled = false;
                lblDone.Text = "";
                lblDragPhotos.Visible = false;
                fileNames = openFileDialog1.FileNames;
                imgList.ImageSize = new Size(100, 75);
                imgList.ColorDepth = ColorDepth.Depth24Bit;
                //Bitmap bmp = new Bitmap(95, 75);
                //Graphics g = Graphics.FromImage(bmp);
                //Pen p = new Pen(Color.Gray);
                //g.FillRectangle(new SolidBrush(Color.LightGray), 0, 0, 100, 70);
                //g.DrawRectangle(p, 1, 1, 93, 73);
                //g.Dispose();
                foreach (string s in fileNames)
                {
                    try
                    {
                        if (imageList1.Images[s] is Image)
                        { }
                        else
                        {
                            //imgList.Images.Add(s,bmp);
                            listView1.LargeImageList = imgList;
                            item = new ListViewItem();
                            string str=System.IO.Path.GetFileName(s);
                            if (str.Length > 18)
                                item.Text = str.Substring(0, 15)+"...";
                            else
                                item.Text = str;
                            item.ImageKey = s;
                            listView1.Items.Add(item);
                        }
                    }
                    catch
                    {
                    }
                }
                lblPhotos.Text = "Total photos are " + listView1.Items.Count;
                foreach (string s in fileNames)
                {
                    try
                    {
                        if (imageList1.Images[s] is Image)
                        { }
                        else
                        {
                            Application.DoEvents();
                            Cursor.Current = Cursors.WaitCursor;
                            listView1.LargeImageList = imageList1;
                            //imgList.Images[imgList.Images.IndexOfKey(s)] = imageList1.Images[imageList1.Images.IndexOfKey(s)];
                            imageList1.Images.Add(s, Image.FromFile(s));
                        }
                    }
                    catch
                    {
                    }
                }
                listView1.LargeImageList = imageList1;
                lblPhotos.Text = "Total photos are " + listView1.Items.Count;
                if (listView1.Items.Count != 0)
                {
                    lblDone.Text = "You can create now";
                    lblDone.Left = Convert.ToInt32((grpCollage.Width - lblDone.Width - 4) / 2);
                    btnClearlist.Enabled = true;
                    lblDragPhotos.Visible = false;
                }
            }

Open in new window

jeesrinu

ASKER
Did you see the code? Please give me replay....
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
jeesrinu

ASKER
Above my code is working dead slow. I need fast to load images into listview. Please give me replay. Thanks in advance.
Mike Tomlinson

The bottleneck is here:

    imageList1.Images.Add(s, Image.FromFile(s));

The whole image must be read in to make a thumbnail from it.  How big are the images?

As I said before, the best method is to make your own thumbnails and load those instead.
jeesrinu

ASKER
I used to load Thumbnails also but it took also same time for loading images into images list.
imageList1.Images.Add(s, Image.FromFile(s).GetThumbnailImage(100, 100,myCallback,IntPtr.Zero));
I used this one also before but speed there is no difference. ok leave it. Later i wil put multi threading. Actually my requirement is  while i am scrolling listview at that time loading images into listview should not be paused.i used Application.DoEvents() to update GUI. Is there any solution for this. Please let me know. If i will get this solution then put my concentration on speeding. If u didn't get my point please check the Windows Movie maker --> Import Pictures option. Thanks in advance.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
DanRollins

I don't see an  "Import Pictures"  option in my copy of Movie Maker (Win7).  I do see "Add Videos and Photos"   Is that what you mean?
If so, then the answer is this:  
Display the OpenFIle dialog, having it pre-set to show Thumbnails.  That is, use the existing high-speed system provided by the OS to populate and display the listview.
jeesrinu

ASKER
i mean same what you said(Add Videos and photos). But i am not asking that what you gave the answer. when we click on add photos option to add photos  into the movie maker collections. That photos are loading faster into movie maker collection. When i am scrolling scroll bar of photos collection window  at the time of loading photos, The loading process could not be paused. That's good. How it's possible there? If u didn't get my point take photos more than 100 and import or add them into movie maker.Then you will see. While loading images you can scroll collection window scrollbar with out disturbance to your images loading.


 It's not possible in my program as listview loading images (ImagesList --> Listview). Here when we are scrolling listview, loading process will be paused up to we release the scrollbar. i am using Application.DoEvents() here to upadte GUI while loading images into listview(Imagelist-->listview).

My requirement is while loading images suppose we take more than 100 into list view from imagelist  (open file dialog-->imagelist), After ecry single image loading into RAM, the image should be appear in Listview. For this i am using Application.DoEvents(). If you didn't get see my above code. At the time of loading when scroll listview ,the loading process is paused. That's i no need. I hope you will catch my point. Thanks in advance.
DanRollins

So you want scrolling in your own listview to be fast...
I don't know what MovieMaker does or how Explorer shows even a very large list of  thumbnails so quickly.
My guess is that they use LVS_OWNERDRAWFIXED and display images manually.  For high speed, I would suggest using a worker thread that created a cache of thumbnails.  Draw the first few items immediately, and then the thread would prepare the rest so they'd be ready for viewing when the user scrolls to that point.
In fact, that almost certainly how MovieMaker does it.  Try this:
Import several hundred items.  The first screen fills with images in a few seconds.  But if you quickly scroll down, you will see that MOST of the images are in "generic" form.
=-=-=-=-=-=-=-=-=-=-=-=-=-=
Another angle of attack:  
Pre-create an ImageList that is populated with a "generic" image for each item.  Then all you need to do is update the ImageList (rather than increase its length with each addition).
That might be a lot of work.  A possibe alternative:
Use Explorer rather than your own listview control.  Just move the images all into a particular directory, then use an explorer window to display them.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
jeesrinu

ASKER
Pre-create an ImageList that is populated with a "generic" image for each item.  Then all you need to do is update the ImageList (rather than increase its length with each addition).
 
That is appeared in my above code.  Use explorer is not suit for my app.

I am also using background thread. But no need. because of Application.DoEvents(). This is helpful and same time this is my problem.

I need to load images dynamically but not static. Have u free try with my code then you will catch my point what i am facing. Thanks in advance.
DanRollins

I think that the only way to handle this is to create an image cache -- like the thumbs.db file that Explorer uses.  
Right now you must open each image file and create a  thumbnail.  That's going to take time even on the fastest processor.
If you saved a cache file of pre-thumbnailed images, then loading them the next time you need them would be considerably faster.  That will not help you fhte first time, but it's something.
ASKER CERTIFIED SOLUTION
Mike Tomlinson

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
jeesrinu

ASKER
Every time i need to  import images into listview. so Thumbnail concept is not suitable for my requirement. My requirement is while loading images suppose we take more than 100 into list view from imagelist  (open file dialog-->imagelist), After every single image loading into RAM, the image should be appear in Listview. For this i am using Application.DoEvents() (update GUI). At the time of loading images into listview, I need to scroll. If i scroll listview, the loading process is paused up to leave focus from listview. This would happen in my program. Actually what i am  need when i am scrolling lisview, the loading process should not be paused. Please give me a suitable answer. Thanks in advance.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Mike Tomlinson

Try this out...it worked well for me on a folder having 700+ full sized wallpapers:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private class Thumbnail
        {
            public string fileName; // this is a full path filename!
            public Bitmap bmp;
        }

        private Dictionary<string, ListViewItem> ListViewItems = new Dictionary<string, ListViewItem>();
        private Size ImageSize = new Size(100, 75);

        private void button1_Click(object sender, EventArgs e)
        {
            openFileDialog1.Multiselect = true;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                button1.Enabled = false;

                imageList1.Images.Clear();
                imageList1.ImageSize = this.ImageSize;
                imageList1.ColorDepth = ColorDepth.Depth24Bit;
                
                listView1.View = View.LargeIcon;
                listView1.Font = new Font("Arial", 8);
                listView1.LargeImageList = imageList1;

                List<string> fileNames = new List<string>();
                fileNames.AddRange(openFileDialog1.FileNames);
                ListViewItems.Clear();

                // load up BLANK ListViewItems for each image
                listView1.Items.Clear();
                listView1.BeginUpdate();
                foreach (string fileName in fileNames)
                {
                    ListViewItem lvi = listView1.Items.Add(System.IO.Path.GetFileNameWithoutExtension(fileName));
                    lvi.Tag = fileName;
                    ListViewItems.Add(fileName, lvi);
                }
                listView1.EndUpdate();

                // generate the thumbnails in the background thread
                BackgroundWorker bgw = new BackgroundWorker();
                bgw.WorkerReportsProgress = true;
                bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
                bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
                bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
                bgw.RunWorkerAsync(fileNames);
            }
        }

        void bgw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bgw = (BackgroundWorker)sender;

            Bitmap bmp;
            PictureBox pb = new PictureBox();
            pb.SizeMode = PictureBoxSizeMode.Zoom;
            pb.Size = this.ImageSize;
            
            List<string> fileNames = (List<string>)e.Argument;
            foreach (string fileName in fileNames)
            {
                try
                {
                    // create a thumbnail using an invisible picturebox
                    pb.Image = Image.FromFile(fileName);
                    bmp = new Bitmap(this.ImageSize.Width, this.ImageSize.Height);
                    pb.DrawToBitmap(bmp, pb.ClientRectangle);
                    
                    // pass the thumbnail with its name out to the main UI
                    Thumbnail tb = new Thumbnail();
                    tb.fileName = fileName;
                    tb.bmp = bmp;
                    bgw.ReportProgress(-1, tb);
                    pb.Image = null;

                    // throttle the image loading background thread so it doesn't overload the main UI
                    // YES...this was necessary!  Otherwise the main UI eventually got bogged down tyring
                    // to update with the new thumbnails being generated...
                    System.Threading.Thread.Sleep(50); 
                }
                catch (Exception ex)
                {
                    MessageBox.Show("FileName: " + fileName + "\r\n\r\n" + ex.ToString(), "Error Loading Image", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

            }
        }

        void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // add the new thumbnail to the Listview
            Thumbnail tb = (Thumbnail)e.UserState;
            imageList1.Images.Add(tb.fileName, tb.bmp);
            ListViewItems[tb.fileName].ImageKey = tb.fileName;
        }

        void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show(listView1.Items.Count + " Image(s) Imported.", "Import Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
            button1.Enabled = true;            
        }

    }
}

Open in new window

jeesrinu

ASKER
I feel happy. You are really Genius. You got my point. The code what you sent is exactly suitable for my requirement. It's  working fine.

I have to need the same experience using  Multi threading to increase the speed twice or thrice for loading images into listview. If you feel free give me suggestion please. Thanks in advance.
jeesrinu

ASKER

I have to need the same experience using  Multi threading to increase the speed twice or thrice for loading images into listview. If you feel free give me suggestion please. Thanks in advance.
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Mike Tomlinson

Using the .Net native image handling methods I don't know how to make it any faster (other than pre-building thumbnails for the NEXT run).  Adding more threads won't help as you'll end up flooding the UI and making it un-responsive again.

It might be possible using external Win APIs but I've never done it...
jeesrinu

ASKER

hjk