I am currently coding a C# application that displays a image using PictureBox on a form.
Now, I want to update this image consistently (e.g. every 2 seconds). But I am not able to do this.
Because the new image is also of the same file directory/name and it will be replacing the original image which is loaded. So when I want to replace the image it is showing, "file is being used by another program...etc)."
Basically, I want to use PictureBox to load an image and this image will be consistently updated as the loaded image is being changed at it's directory.
Is this possible? Is there any other way to do this in C#?
Thanks In Advance,
Perumal
It sounds as if a stream isn't closed. Try to call stream.close(); after you have loaded your image. If you are loading your image like this Image i = new Image(File.Open("blub.png")); Then you will have to rewrite it a bit like this;
FileStream fs = File.Open("blub.png");
Image img = new Image(fs);
fs.Close();
fs.Dispose();
Just use a timer (called timeImageChange in the example below) and rename the files two different files names. Then you could have something like
bool imageALoaded = true;
timerImageChange.Interval = 2000;
timerImageChange.Enabled = true;
private void timerImageChange_Tick(object sender, EventArgs e)
{
if (imageALoaded)
{
this.pictureBox1.Image = imageB;
imageALoaded = false;
}
else
{
this.pictureBox1.Image = imageA;
imageALoaded = true;
}
}
This should do what you want.
I hope this helps.
My best solution for you is to use the executable file, it's called Volume Shadow Copy. This actually is used in windows for backup as it allow you to copy files that are being used. I have actually tried this tool without C# code but it will be easy to use in code.
Here is a link: http://www.howtogeek.com/howto/windows-vista/backupcopy-files-that-are-in-use-or-locked-in-windows/
My idea is to make a copy of the file with another name and access that file and the delete after you next load, i see that to be the best approach for you.
Related
I am new to Windows 8 development and Microsoft's technologies. I've done a lot of iOS development, but I've never touched Visual Studio, C#, etc before, so I am learning a lot (frameworks, IDEs, language) all at once. Forgive me if this is something simple, but I can't find an answer anywhere.
Note: I'm using Visual Studio Express 2013, C#, and Windows 8.1
For learning purposes I'm just trying to create an app that loads images, displays them on the screen, and allows the user to rotate, move, resize, and arrange them. I've got this working, except for one major bug that I can't figure out: When I load images from some directories everything works fine, when I load images from other directories I get E_NETWORK_ERROR and BitmapImage.ImageFailed. I can see no reason for this. I can actually take an image and put it in a directory and it will load, copy the same image to another directory, and it wont load.
Here's the code:
private async void addImageButton_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.Pickers.FileOpenPicker filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
filePicker.FileTypeFilter.Add(".jpg");
filePicker.FileTypeFilter.Add(".png");
filePicker.FileTypeFilter.Add(".bmp");
filePicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
Windows.Storage.StorageFile imageFile = await filePicker.PickSingleFileAsync();
if (imageFile != null)
{
System.Diagnostics.Debug.WriteLine(imageFile.Path);
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmap = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri(imageFile.Path));
System.Diagnostics.Debug.WriteLine(bitmap.UriSource);
bitmap.CreateOptions = Windows.UI.Xaml.Media.Imaging.BitmapCreateOptions.None;
Image img = new Image();
img.Source = bitmap;
this.theCanvas.Children.Add(img);
}
}
This seems to work great with image files from some directories, and doesn't work at all with others. For example: in my Pictures library I have a "Camera Roll" directory that the Windows 8 camera app saves to, and I also have my Steam screenshots directory. If I try to open images in my Steam screenshots directory it works fine; however, if I try to load images in the Camera Roll directory it fails with E_NETWORK_ERROR. If I copy images from the Camera Roll directory to the Steam Screenshots directory I can open them.
Can anyone point out what's wrong? I'm starting to think this isn't a code problem so much as a security / capabilities / declarations type thing. Is there something I need to declare or request to get unfettered access to the filesystem? Do I need to form my URI differently or something?
EDIT: Here is some output from the debug statements showing the paths and URIs:
Loaded fine:
C:\Program Files (x86)\Steam\userdata\24321739\760\remote\72850\screenshots\2013-12-04_00001.jpg
file:///C:/Program Files (x86)/Steam/userdata/24321739/760/remote/72850/screenshots/2013-12-04_00001.jpg
Resulted in E_NETWORK_ERROR
C:\Users\Adam\Pictures\Camera Roll\WIN_20131023_194718.JPG
file:///C:/Users/Adam/Pictures/Camera Roll/WIN_20131023_194718.JPG
Weird issue, but I think that you should modify your code a bit as this answer here suggests. Instead of using the file path, try to create an image via loading a stream.
Just to be sure, does your app have the permission for accessing files in the user libraries?
I fixed this, but I'm not 100% sure I understand how/why the solution I arrived at resolved my problem.
I fixed the problem by switching to using a Windows.Storage.Streams.IRandomAccessStream to read the file into the BitmapImage Source:
private async void addImageButton_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.Pickers.FileOpenPicker filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
filePicker.FileTypeFilter.Add(".jpg");
filePicker.FileTypeFilter.Add(".png");
filePicker.FileTypeFilter.Add(".bmp");
filePicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
Windows.Storage.StorageFile imageFile = await filePicker.PickSingleFileAsync();
if (imageFile != null)
{
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmap = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
Windows.Storage.Streams.IRandomAccessStream stream = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
Image newImage = new Image();
bitmap.SetSource(stream);
newImage.Source = bitmap;
newImage.Height = 250;
newImage.Stretch = Stretch.UniformToFill;
newImage.ManipulationMode = ManipulationModes.All;
newImage.ManipulationDelta += TestImage_ManipulationDelta;
this.theCanvas.Children.Add(newImage);
}
}
This resolved the issue and I can now load image files from any arbitrary location. However, I'm not 100% why this resolved the problem. I think it has something to do with async. I think that the way I was doing it before would somehow result in the BitmapImage or Image not containing the actual image data at display time. What I think this solution did was make the display code wait until we'd actually taken time to load the image. Even though this is solved, if a
I was investigating an interesting thing. I want to get Image from Clipboard in my C# program.
Code sample:
[STAThread]
public Image GetClipboardImage()
{
MessageBox.Show("try to get image");
Image returnImage = null;
if (Clipboard.ContainsImage())
{
MessageBox.Show("getting image");
returnImage = Clipboard.GetImage();
}
return returnImage;
}
When I try to get an image that was copied to clipboard from any website the code above works quite good. But it doesn't work when I am copying an image from my computer (I mean desktop for example). Clipboard.ContainsImage() returns false in the second case.
One more difference between copying from web and from desktop:
In the first case I cannot paste the image from Clipboard to folder on my computer.
Of course in the second case it can be done.
It seems that in the second case there is one real image and one file which contains this image. But I am not sure whether it can be.
So, what's the issue in my situation and how I can resolve it?
The next code demonstrate an appropriate solution
IDataObject myDataObject = Clipboard.GetDataObject();
string[] files = (string[])myDataObject.GetData(DataFormats.FileDrop);
MessageBox.Show(files[0]);
You will show massagebox with the full path to the file you have copied to clipboard before.
I use the following code block with some more code inside the using block:
using (System.Drawing.Bitmap tempImg =
(System.Drawing.Bitmap)tempObj.GetData(System.Windows.Forms.DataFormats.Bitmap))
{
// ...
tempImg.Save("..\\..\\testdata\\tempImg.bmp", ImageFormat.Bmp);
// ...
}
But I still get the error:
A Generic Error occured at GDI+
only after I make some action which is not related to the code inside the using block. In other times this works well.
Also the tempImg.bmp is a temporary file, so I delete the tempImg.bmp within the using block itself.
Since the tempImg is inside the using and this it's disposed, I think the locking problem should be solved.
Can someone please let me know what is the mistake in this code?
Edit:
System.Drawing.Image to System.Drawing.Bitmap as the type of tempImg.
Edit:
I have identified I get this error only after SaveFileDialog is created and user clicks on 'Save'.
Finally I could find what was wrong in my code and would like to mention it here as I think it may be useful to someone....
As I have given a relative path in tempImg.Save, and after the user clicks 'Save' in SaveFileDialog, the actual path for tempImg.Save become :
Path specified by SaveFileDialog + the relative path
automatically.
Thus if the path does not exist, this error occurs.
Thanks every one for the answers.
I also had once this problem- it happens because the bitmap locks and you can't save it( if you want I can find the exact explanation) so anyway a fix around is this:
Create a new bitmap the size of the original bitmap you have- copy the original bitmap to the new created bitmap and then dispose the original bitmap and save the new one.
Bitmap bm3 = new Bitmap(bm2);
And then save.
This is usually an indicator that something else, potentially some other thread in your own application, already has the target file that you're trying to save locked at the file system level. If you look at the inner exception I believe it should mention this. If it's not directly in the InnerException Another way to confirm this (or discover what it might really be instead) is to turn on first chance exceptions in the debugger and watch for what exception is being thrown "underneath" Save and then being turned into this generic exception.
Tried all the solutions given here, but in vain. Found the solution eventually.
Dispose any Graphics applied on image: g.dispose();
Make sure save path exists: System.IO.Directory.Exists(dir);
Is this an ASP.NET application?
A Generic Error occured at GDI+ in asp.net mostly because of missing target folder / access permissions.
Also your code could be simplified to :
using (Image image= dataObject.GetImage())
{
if (image != null)
{
image.Save("test.bmp");
}
}
In my case it was an ASP.NET application in which I replaced a single DLL, and I had to simply re-start the application pool after deployment. Then it worked fine.
This is code sample from Microsoft Forums.
// new image with transparent Alpha layer
using (var bitmap = new Bitmap(330, 18, PixelFormat.Format32bppArgb))
{
using (var graphics = Graphics.FromImage(bitmap))
{
// add some anti-aliasing
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var font = new Font("Arial", 14.0f, GraphicsUnit.Pixel))
{
using (var brush = new SolidBrush(Color.White))
{
// draw it
graphics.DrawString(user.Email, font, brush, 0, 0);
}
}
}
// setup the response
Response.Clear();
Response.ContentType = "image/png";
Response.BufferOutput = true;
// write it to the output stream
bitmap.Save(Response.OutputStream, ImageFormat.Png);
Response.Flush();
}
I am trying to save image from resource and it gives me too GDI error when I directly use the method Bitmap.Save(filepath).
I think We can use the same below code for any other bitmap image by cloning it.
Private void SaveResourceImage() {
object resBmpObject = Resource.Image1.Clone();//Bitmap Image from resource file
//object resBmpObject = anyBmpImage.clone(); //for image other than resource image
Bitmap resBmpImage = (Bitmap)resBmpObject;
resBmpImage.Save(destFilePath, System.Drawing.Imaging.ImageFormat.Png);
resBmpImage.dispose();
}
Dispose your bitMap object after save image:
bitMap.Dispose()
oimg.Dispose()
bitMap = Nothing
oimg = Nothing
In my case, i was saving the bitmap file on the same location as the source,
So that's the problem.
I save the bitmap to the new location and all fine now.
I was facing the same issue, by changing image type ".bmp" to ".png" its work form me
How can I clone FileStream type?
The problem is that I using MagickNet.Image(inputStream) to get the image distentions before saving it, but it seems to closing the inputStream.
So, I can send a clone of inputStream to the function, so the function cannot edit the real inputStream object?
This is my function:
public Picture GetPictureDimension(Stream inputStream, Picture picture)
{
var img = new MagickNet.Image(inputStream);
picture.Width = img.Columns;
picture.Height = img.Rows;
return picture;
}
You could just re-open the file? But to keep a single Stream without it getting closed, you could try NonClosingStreamWrapper in MiscUtil. Just be sure to reset the Position if appropriate.
You didn't post full code, but I imagine that MagickNet.Image(inputStream) gets the full image and you only use the Size from that, and later you load the Image a second time.
So a more practical solution would be to get and hold the Image in memory just once. That gives you access to the Size.
Edit:
You don't seem to realize it but you are asking how to load the Image twice (w/o reopening the stream). I do think it is more efficient to load it just once.
Picture is a XNA class, right? I don't know to much about that but you could try something like:
public Picture GetPictureDimension(Stream inputStream, ref Picture picture)
{
var img = new MagickNet.Image(inputStream);
picture = new Picture(img); // just guessing here
//picture.Width = img.Columns;
//picture.Height = img.Rows;
return picture;
}
I was loading a Bitmap Image from a File. When I tried to save the Image to another file I got the following error "A generic error occurred in GDI+". I believe this is because the file is locked by the image object.
Ok so tried calling the Image.Clone function. This still locks the file.
hmm. Next I try loading a Bitmap Image from a FileStream and load the image into memory so GDI+ doesn't lock the file. This works great except I need to generate thumbnails using Image.GetThumbnailImage method it throws an out of memory exception. Apparently I need to keep the stream open to stop this exception but if I keep the stream open then the file remains locked.
So no good with that method. In the end I created a copy of the file. So now I have 2 versions of the file. 1 I can lock and manipulate in my c# program. This other original file remains unlocked to which I can save modifications to. This has the bonus of allowing me to revert changes even after saving them because I'm manipulating the copy of the file which cant change.
Surely there is a better way of achieving this without having to have 2 versions of the image file. Any ideas?
Well if you're looking for other ways to do what you're asking, I reckon it should work to create a MemoryStream, and read out the FileStream to it, and load the Image from that stream...
var stream = new FileStream("original-image", FileMode.Open);
var bufr = new byte[stream.Length];
stream.Read(bufr, 0, (int)stream.Length);
stream.Dispose();
var memstream = new MemoryStream(bufr);
var image = Image.FromStream(memstream);
Or something prettier to that extent.
Whether or not that's the way you should go about solving that problem, I don't know. :)
I've had a similar problem and wound up fixing it like this.
I have since found an alternative method to clone the image without locking the file. Bob Powell has it all plus more GDI resources.
//open the file
Image i = Image.FromFile(path);
//create temporary
Image t=new Bitmap(i.Width,i.Height);
//get graphics
Graphics g=Graphics.FromImage(t);
//copy original
g.DrawImage(i,0,0);
//close original
i.Dispose();
//Can now save
t.Save(path)
I had a similar problem. But I knew, that I will save the image as a bitmap-file. So I did this:
public void SaveHeightmap(string path)
{
if (File.Exists(path))
{
Bitmap bitmap = new Bitmap(image); //create bitmap from image
image.Dispose(); //delete image, so the file
bitmap.Save(path); //save bitmap
image = (Image) bitmap; //recreate image from bitmap
}
else
//...
}
Sure, thats not the best way, but its working :-)