I’m currently developing an application to help scanning and showing images here at my work.
My application is build with multiple forms, the most important forms here is my mainForm to show statistics about the current scanning and a menustrip with different functinalities. I also have ImageViewerForm with a PictureBox which shows on the secondary monitor to view the current scanned image.
I’m using a Timer to poll the folder where the images are scanned to. When a new image has been scanned and the image is unlocked, i’ll grap it into a FileStream and show it in the PictureBox, see below:
public static void SetPicture(string filename, PictureBox pb)
{
try
{
Image currentImage;
//currentImage = ImageFast.FromFile(filename);
using (FileStream fsImage = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
currentImage = ScaleImage(Image.FromStream(fsImage), new Size(pb.Width, pb.Height));
if (pb.InvokeRequired)
{
pb.Invoke(new MethodInvoker(
delegate()
{
pb.Image = currentImage;
}));
}
else
{
pb.Image = currentImage;
}
}
}
catch (Exception imageEx)
{
throw new ExceptionHandler("Error when showing image", imageEx);
}
}
public static Image ScaleImage(Image imgToResize, Size size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
using (Graphics g = Graphics.FromImage(b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
}
return b;
}
This way the image shown in the PictureBox shouldn’t be locked, but it is.
The problem is that the scanned image might have to be rescanned, and if I do that i’ll get a sharing violation error when trying to overwrite the image file from the scanning software.
Anyone who’s got an answer to what I can do?
SOLUTION
Thanks to @SPFiredrake I’ve got a solution to create a temp file to show in the PictureBox, leaving the original image unlocked.
public static void SetPicture(string filename, PictureBox pb)
{
try
{
Image currentImage;
//currentImage = ImageFast.FromFile(filename);
using (FileStream fsImage = new FileStream(CreateTempFile(filename), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
currentImage = ScaleImage(Image.FromStream(fsImage), new Size(pb.Width, pb.Height));
if (pb.InvokeRequired)
{
pb.Invoke(new MethodInvoker(
delegate()
{
pb.Image = currentImage;
}));
}
else
{
pb.Image = currentImage;
}
}
}
catch (Exception imageEx)
{
throw new ExceptionHandler("Error when showing image", imageEx);
}
}
public static string CreateTempFile(string fileName)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException("fileName");
if (!File.Exists(fileName))
throw new ArgumentException("Specified file must exist!", "fileName");
string tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + Path.GetExtension(fileName));
File.Copy(fileName, tempFile);
Log.New("Temp file created: " + tempFile);
return tempFile;
}
The problem here is that the image is being loaded from a FileStream, which is being locked by the PictureBox because it’s holding a reference to the stream. What you should do is first load the picture into local memory (via a byte[] array) and then load the image from a MemoryStream instead. In your
SetPicturemethod, you should try the following change and see if it works:Edit: After our conversation in Chat, updating with the fix that you ended up using:
This way you are using the temp files to actually load the picture box, leaving the original file untouched (outside of the initial copy).