Add images in WinForm to ListView throw OutOfMemory - c#

I want to show images with gps tags on form. User click on image than I show gps location from the image on statusbar. I loaded some image files(for example, 40) and get exception - OutOfMemory.
File jpeg have size - 5Mb, after Image.FromFile disappear 50 Mb memory.
Example,
1) run application - memory - 50Mb
2) select 5 image files(25Mb) - memory - 316Mb(!?)
3) click on image in ListView,rise event listView1_SelectedIndexChanged, show gps location - memory - 43Mb(GC did his good job)
How do I load images without big memory?
If I call
image.Dispose();
after
imageList1.Images.Add(image);
there is no images on Form
Code load images:
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = true;
ofd.Filter = "Images (*.jpg, )|*.jpg";
ofd.Title = "Select files";
if (ofd.ShowDialog() != DialogResult.OK)
return;
ListPathFoto.Clear();
foreach (string f in ofd.FileNames)
{
ListPathFoto.Add(f);
}
imageList1.Images.Clear();
foreach (var oneFilePath in ListPathFoto)
{
var image = Image.FromFile(oneFilePath);
imageList1.Images.Add(image);
}
listView1.Clear();
listView1.View = View.LargeIcon;
imageList1.ImageSize = new Size(32, 32);
listView1.LargeImageList = imageList1;
for (int j = 0; j < imageList1.Images.Count; j++)
{
ListViewItem item = new ListViewItem
{
ImageIndex = j
};
listView1.Items.Add(item);
}

Thank you for comments. Thanks to them i found a solution.
Solution is - add Thumbnail instead Image
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Multiselect = true;
ofd.Filter = "Файлы изображений (*.jpg, )|*.jpg";
ofd.Title = "Выберите файлы изображений";
if (ofd.ShowDialog() != DialogResult.OK)
return;
ListPathFoto.Clear();
foreach (string f in ofd.FileNames)
{
ListPathFoto.Add(f);
}
}
imageList1.ImageSize = new Size(32, 32);
imageList1.Images.Clear();
foreach (var oneFilePath in ListPathFoto)
{
var image = Image.FromFile(oneFilePath);
Image thumb = image.GetThumbnailImage(32, 32, () => false, IntPtr.Zero);
imageList1.Images.Add(thumb);
image.Dispose(); // important for clear memory
}
listView1.Clear();
listView1.View = View.LargeIcon;
listView1.LargeImageList = imageList1;
for (int j = 0; j < imageList1.Images.Count; j++)
{
ListViewItem item = new ListViewItem
{
ImageIndex = j
};
listView1.Items.Add(item);
}

Apart from answer what you have found, ideally you should not be loading all images at once . Say you have 100 images to load, if you load all images at once you are at high risk of getting OOM exception .
In this case it is advisable to use lazy loading mechanism . Load only say 10 images at first and as you scroll down load remaining 10 or whatever the feasible number and dispose previously loaded 10 .

Related

How to paint Images instead of colors from a Panel to another Panel?

I need to paint images from one panel to another panel like painting colors in a Windows Forms application but not colors, only Images.
I use an OpenFileDialog to open multiple images onto a panel and then paint those images by clicking on one and painting it with my mouse to the panel2.
My code for the openstripmenuitem:
private void openProjectToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Please select your files";
ofd.Multiselect = true;
ofd.Filter = "PNG|*.png|JPEG|*.jpeg|GIF|*.gif|TGA|*.tga|DDS|*.dds";
DialogResult dr = ofd.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.OK)
{
string []files = ofd.FileNames;
int x = 20;
int y = 20;
int maxheight = -1;
foreach(string img in files)
{
PictureBox pic = new PictureBox();
pic.Image = Image.FromFile(img);
pic.Location = new Point(x, y);
pic.SizeMode = PictureBoxSizeMode.StretchImage;
x += pic.Width + 10;
maxheight = Math.Max(pic.Height, maxheight);
if (x > this.ClientSize.Width - 100)
{
x = 20;
y += maxheight + 10;
}
this.flowLayoutPanel1.Controls.Add(pic);
}
}
}
Any advice code examples welcome or link to references.

how to select multiple files without using openfileDialog in c#

I am making a simple app which will show the images from a specific folder on a winform load.
I've done the "showing part" with using openfileDialog and it's working fine, where the user has to select images each time.I want to make it more automatic that user doesn't have to select the files, It should select the files automatically.
Target Folder is static(It'll remain same) while it contains multiple images.
How can I obtain all of the image files from the directory?
I am using this code.
string[] path = Directory.GetFiles("Cards");
foreach (string filepath in path)
{
string[] files = filepath;
int x = 20;
int y = 20;
int maxheight = -1;
foreach (string img in files)
{
PictureBox pic = new PictureBox();
pic.Image = Image.FromFile(img);
pic.Location = new Point(x, y);
pic.Size = new Size(200, 200);
pic.SizeMode = PictureBoxSizeMode.Zoom;
x += pic.Width + 10;
maxheight = Math.Max(pic.Height, maxheight);
if (x > this.ClientSize.Width - 100)
{
x = 20;
y += maxheight + 10;
}
this.panelImages.Controls.Add(pic);
}
}
but stuck at string[] files = filepath; here.
Please guide me where I am making any mistake.
Please let me know if anybody needs more info.
Thanks in advance.
Consider changing:
string[] path = Directory.GetFiles("Cards");
foreach (string filepath in path)
{
string[] files = filepath;
to:
string[] files = Directory.GetFiles("Cards");
Then your later:
foreach (string img in files)
will iterate over all file in the Cards folder.
There are some dangers in passing in just "Cards" as a parameter, as per the docs:
Relative path information is interpreted as relative to the current
working directory.
It would be better, if possible, to pass an absolute path.

Clicking on an image in a listView and making it appear in a pictureBox

I have successfully imported and displayed horizontaly in a listView all the images from a folder/directory and now I want to be able to click on one of them and display that image in a big pictureBox above it called "mainPictureBox". I think I am close to that result, however what i have managed is to make the 100x100pixel image appear on the mainPictureBox that I clicked on from the listview rather than the high quality .PNG or .JPG from the folder. I'm guessing I need to use ImageKey or IndexKey or somehow associate the names of the images in the folder with the index of the clicked-on listView item. I am attaching an image of the GUI and the piece of code used for the imageList and listView if that helps.
http://i.imgur.com/GkF1hNd.jpg <---GUI screenshot
DirectoryInfo dir = new DirectoryInfo(#"C:\Users\UserName\Desktop\PhotoEditorProject\bin\Debug\Images");
foreach (FileInfo file in dir.GetFiles())
{
try
{
this.imageList1.Images.Add(Image.FromFile(file.FullName));
}
catch
{
Console.WriteLine("This is not an image file");
}
}
for (int i = 0; i < this.imageList1.Images.Count; i++)
{
ListViewItem item = new ListViewItem();
item.ImageIndex = i;
this.listView1.Items.Add(item);
}
my dear friend try this..
int b = 0;
public void button1_Click_1(object sender, EventArgs e)
{
var ofd = new OpenFileDialog();
ofd.Multiselect = true;
ofd.ShowDialog();
for (int z = 0; z < ofd.FileNames.Length; z++)
{
Image img = Image.FromFile(ofd.FileNames[z]);
string a = b.ToString();
imageList1.Images.Add(a, img);
var listViewItem = listView1.Items.Add(ofd.FileName );
listViewItem.ImageKey = a;
b++;
}
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
string s= listView1.SelectedItems.ToString();
Bitmap bm= new Bitmap (#"" +s);
pictureBox1.Image = bm;
}

Multiply images boxes

I have a simple form with 10 picture boxes like: pictureBox1, pictureBox2, pictureBox3...
And I have a folder with 10 images like: image1, image2, image3...
Now I am smart enough to know that I don't want to hard code pictureBox1.ImageLocation = image1, pictureBox2.ImageLocation = image2... Rather, I need to create some kind of loop or array that will populate my picture boxes with their respective images, but I am not smart enough to figure out how.
Something like:
for (int i = 0; i < 10; i++)
{
pictureBox[i].ImageLocation = image[i];
}
Eventually, I was hoping this project would scale dynamically, if I have a file with say 12 images, the program will simply create 12 picture boxes and load the images. A little help would be great.
What you have there would roughty work though I would suggest a list.
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<Image> images = new List<Image>();
//code to populate your lists
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
If you want to make sure you have enough images for your PictureBox list you could check ahead of time:
if (images.Count >= pictureBoxes.Count)
{
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
}
...or fill out as many as you can before running out of images.
for (int i = 0; i < pictureBoxes.Count && i < images.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
EDIT:
So if you want to use strings to set the location of the images instead you can do that. Check this out:
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<string> imageLocations = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
PictureBox PB1 = new PictureBox();
PB1.Location = new Point(0, 0);
PB1.Size = new Size(144, 197);
Controls.Add(PB1);
PictureBox PB2 = new PictureBox();
PB2.Location = new Point(145, 0);
PB2.Size = new Size(327, 250);
Controls.Add(PB2);
pictureBoxes.Add(PB1);
pictureBoxes.Add(PB2);
imageLocations.Add(#"C:\PicExample\image1.jpg");
imageLocations.Add(#"C:\PicExample\image2.jpg");
for (int i = 0; i < pictureBoxes.Count && i < imageLocations.Count; i++)
{
pictureBoxes[i].ImageLocation = imageLocations[i];
}
}
EDIT for Iteratively Creating PictureBoxe List:
If you want to not have to worry about hard-coding your list (and your picture boxes will be the same size) you could do something like this:
for (int i = 0; i < HoweverManyPictureBoxesYouWant; i++)
{
PictureBox PB = new PictureBox();
PB.Name = "PB" + i.ToString();
PB.Location = new Point(250 * i, 0); //Edit this as you see fit for location, i'm just putting them in a row
PB.Size = new Size(250, 250);
PB.ImageLocation = #"C:\PicExample\image" + i.ToString() + ".jpg";
Controls.Add(PB);
pictureBoxes.Add(PB); //You only need to do this if you want the PB's in a list for other reasons than setting the image location
}

image list, listview,picturebox

I wanted to show my pics in picturebox. but also wanted to show a preview of pics.
When user select a pic, it is shown in picbox but i have problem in resoulution.
Here is my code
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
ofd = new OpenFileDialog();
ofd.Title = "Open an Image File";
ofd.FileName = "";
ofd.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
if (ofd.ShowDialog() == DialogResult.OK)
{
DirectoryInfo dir = new DirectoryInfo(#"c:\pic");
foreach (FileInfo file in dir.GetFiles())
{
this.imageList1.Images.Add(Image.FromFile(file.FullName));
}
this.listView1.View = View.LargeIcon;
this.imageList1.ImageSize = new Size(40, 40);
this.listView1.LargeImageList = this.imageList1;
for (int j=0; j < this.imageList1.Images.Count; j++) {
ListViewItem item = new ListViewItem();
item.ImageIndex = j;
listView1.Items.Add(item);
ListViewItem item2 = new ListViewItem();
item2.SubItems.Add(j.ToString());
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
int i = this.listView1.FocusedItem.Index;
this.PicBox1.Image = this.imageList1.Images[i];
}
On click i see only image of resolution of (40,40) becuse i have set it
this.imageList1.ImageSize = new Size(40, 40); and not orignal size.
How can I have it.
2-
I want to write also image names and index(image no) under each images.
Its it possible.
reagrsd,
I suppose, that after you have loaded an image to the imageList with resolution 40, 40, there is no way to make it higher.
You should save the original picture in another container like List<> and display the original image from the list and not from the imagelist :)
-Create a new imagelist (imagelist1)**
-Add images to your imagelist
-Create a new listview (listview1)
-Create a picturebox (picturebox1)
-Create a new button (button1)
-Create another button (button2)**
-Import images from imagelist1 to listview1
private void button1_Click(object sender, EventArgs e)
{
listView1.Scrollable = true;
listView1.View = View.LargeIcon;
imageList1.ImageSize = new Size(100, 100);
listView1.LargeImageList = imagelist1;
for (int i = 0; i < imagelist1.Images.Count; ++i)
{
string s = imagelist1.Images.Keys[i].ToString();
ListViewItem lstItem = new ListViewItem();
lstItem.ImageIndex = i;
lstItem.Text = s;
listView1.Items.Add(lstItem);
}
}
- Set the selected image into your picture box from listview
private void button2_Click(object sender, EventArgs e)
{
if (this != null && listView1.SelectedItems.Count > 0)
{
ListViewItem lvi = listView1.SelectedItems[0];
string imagekeyname = lvi.Text;
if (this.pictureBox1.Image != null)
{
this.pictureBox1.Image.Dispose();
this.pictureBox1.Image = null;
}
//set the selected image into your picturebox
this.pictureBox1.Image = imagelist1.Images[imagekeyname];
}
}
and its done.

Categories