Deleting a file after printing - c#

I am using the following code to create a file at a temp path and then delete it after the print happened successfully. But after printing I try to dispose the file and when I try to delete the file, I still get an exception saying "The process cannot access the file 'Chart0.png' because it is being used by another process." Please help.
I also tried putting the deleting code in the finally block but still no luck.
public static bool PrintAllCharts(Dictionary<string, ILightningChartInterface> charts)
{
DirectoryInfo info = null;
try
{
string FilePathWithoutFileName = string.Empty;
info = Directory.CreateDirectory(#"C:\TempCharts");
for (int i = 0; i < charts.Count; i++)
{
KeyValuePair<string, ILightningChartInterface> kp = charts.ElementAt(i);
FilePathWithoutFileName = info.FullName;
string FullPath = string.Format("{0}/Chart{1}.png", FilePathWithoutFileName, i.ToString());
kp.Value.SaveChartToFile(FullPath);
}
var files = Directory.GetFiles(FilePathWithoutFileName);
using (var pdoc = new PrintDocument())
{
using (var pdi = new System.Windows.Forms.PrintDialog { Document = pdoc, UseEXDialog = true })
{
if (pdi.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
pdoc.PrinterSettings = pdi.PrinterSettings;
pdoc.PrintPage += Pdoc_PrintPage;
foreach (var file in files)
{
pdoc.DocumentName = file;
pdoc.Print();
}
}
}
}
//Dispose the file after printing.
foreach(var file in files)
{
Image.FromFile(file).Dispose();
File.Delete(file); //This line gives an exception
}
foreach (DirectoryInfo dir in info.GetDirectories())
{
dir.Delete(true);
}
return true;
}
catch (Exception ex)
{
return false;
}
}
private static void Pdoc_PrintPage(object sender, PrintPageEventArgs e)
{
string file = ((PrintDocument)sender).DocumentName;
System.Drawing.Image img = System.Drawing.Image.FromFile(file);
Rectangle m = e.MarginBounds;
if ((double)img.Width / (double)img.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)img.Height / (double)img.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)img.Width / (double)img.Height * (double)m.Height);
}
e.Graphics.DrawImage(img, m);
}

The issue lies in your Pdoc_PrintPage method. You're using the following line to read the file:
System.Drawing.Image img = System.Drawing.Image.FromFile(file);
The docs for FromFile state:
The file remains locked until the Image is disposed.
So really you should write your code like this, so that the image is disposed of (and the file unlocked) after you're done with it:
string file = ((PrintDocument)sender).DocumentName;
using (System.Drawing.Image img = System.Drawing.Image.FromFile(file))
{
Rectangle m = e.MarginBounds;
if ((double)img.Width / (double)img.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)img.Height / (double)img.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)img.Width / (double)img.Height * (double)m.Height);
}
e.Graphics.DrawImage(img, m);
}
Note that you have to dispose of the same image instance. You currently have this code in your delete loop:
Image.FromFile(file).Dispose();
That's simply trying to load a second copy of the file and then immediately dispose of it. Once you have implemented the above change, you should also remove this line from your delete loop.

Related

Fit Image height and width to the page during Print

I am trying to open a print preview dialog and Print all the images. My problem is when I am printing the image, the width doesn't seem to be aligning with printer paper and the image is getting cut. How can I print the image on the paper without cutting it. Please help.
Please see Pdoc_PrintPage event method. I am using e.Graphics.DrawImageUnscaled is it the right overload that I am using. I debug my code put in the values.
private void PrintAllCharts(Dictionary<LightningChartUserControl, string> charts)
{
try
{
if (PrinterSettings.InstalledPrinters.Count == 0)
{
Xceed.Wpf.Toolkit.MessageBox.Show(System.Windows.Application.Current.TryFindResource("SetUpPrinter").ToString(),
"Default printer not found", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
string FilePathWithoutFileName = string.Empty;
DirectoryInfo info = Directory.CreateDirectory(#"C:\TempCharts");
for (int i = 0; i < charts.Count; i++)
{
KeyValuePair<LightningChartUserControl, string> kp = charts.ElementAt(i);
FilePathWithoutFileName = info.FullName;
string FullPath = string.Format("{0}/Chart{1}.png", FilePathWithoutFileName, i.ToString());
kp.Key.Chart.SaveToFile(FullPath);
}
var files = Directory.GetFiles(FilePathWithoutFileName);
using(var pdoc=new PrintDocument())
{
using(var pdi=new System.Windows.Forms.PrintDialog { Document = pdoc, UseEXDialog = true })
{
if (pdi.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
pdoc.PrinterSettings = pdi.PrinterSettings;
pdoc.PrintPage += Pdoc_PrintPage;
foreach(var file in files)
{
pdoc.DocumentName = file;
pdoc.Print();
}
}
}
}
PrinterSettings settings = new PrinterSettings();
Xceed.Wpf.Toolkit.MessageBox.Show(string.Format(System.Windows.Application.Current.TryFindResource("PrintSuccessful").ToString(),settings.PrinterName),
"Print Successful", MessageBoxButton.OK);
foreach(FileInfo file in info.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in info.GetDirectories())
{
dir.Delete(true);
}
}
catch (Exception ex)
{
SystemDebugLogLogger.LogError(ex);
}
}
private void Pdoc_PrintPage(object sender, PrintPageEventArgs e)
{
string file = ((PrintDocument)sender).DocumentName;
System.Drawing.Image img = System.Drawing.Image.FromFile(file);
//e.Graphics.DrawImage(img, e.MarginBounds);
//e.Graphics.DrawImageUnscaled(img, e.MarginBounds);
var hei = img.Height; //509
var wid = img.Width; //1671
int x1 = e.MarginBounds.Left;//100
int y1 = e.MarginBounds.Top;//100
int w = e.MarginBounds.Width;//650
int h = e.MarginBounds.Height;//900
e.Graphics.DrawImageUnscaled(img, x1, y1, w, h);
}

ForEach Loop, Execute Command for Each Randomly Named Image

I'm using Movie Maker Timeline Control in C# to try and randomize the order of pictures in Windows Movie Maker. I have the form set up, but I seem to encounter a problem with the importing of photos. My code needs to be able to import multiple randomly named images (ex: IMG_xxxx.JPG). I'm able to individually import a specifically named image, but when I try to use a foreach loop, it fails.
My code:
private void btnOpen_Click(object sender, EventArgs e)
{
openFolder.Description = "Open a folder containing pictures for the slideshow!";
if (openFolder.ShowDialog() == DialogResult.OK)
{
// this code right here
string folderPath = openFolder.SelectedPath;
string[] fileArray = Directory.GetFiles(folderPath, "*.JPG");
foreach (string file in fileArray)
{
folderPath = folderPath + "\\" + file;
float duration = 4;
float startpos = 0;
timelineControl.AddImageClip(timelineControl.GetImageTrackIndex(), folderPath, startpos, (startpos + duration));
startpos = startpos + 4;
}
/* string image = "C:\\Users\\OSR\\Desktop\\jpgs\\img.JPG";
float duration = 4;
timelineControl.AddImageClip(timelineControl.GetImageTrackIndex(), image, 0, duration);
*/
}
else
{
MessageBox.Show("Next time, select a folder and click open!", "Selection Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Full code: https://pastebin.com/MrB928Ri
Program: http://imgur.com/a/bikxU
You are destroying the folderPath in the loop:
var folderPath = openFolder.SelectedPath;
var fileArray = Directory.GetFiles(folderPath, "*.JPG");
float duration = 4;
float startpos = 0;
foreach (var file in fileArray) {
var filePath = $#"{folderPath}\{file}";
timelineControl.AddImageClip(timelineControl.GetImageTrackIndex(), filePath, startpos, (startpos + duration));
startpos += 4;
}

Luxand API in Visual Studio 2010?

How can I use Luxand API to get to work in visual studio 2010? I need to detect points of chin in a given face, can I do it with any other API?
I have tried this sample code:
OpenFileDialog openFileDialog1 = new OpenFileDialog();
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
FSDK.CImage image = new FSDK.CImage(openFileDialog1.FileName);
// resize image to fit the window width
double ratio = System.Math.Min((pictureBox1.Width + 0.4) / image.Width,
(pictureBox1.Height + 0.4) / image.Height);
image = image.Resize(ratio);
Image frameImage = image.ToCLRImage();
Graphics gr = Graphics.FromImage(frameImage);
FSDK.TFacePosition facePosition = image.DetectFace();
if (0 == facePosition.w)
MessageBox.Show("No faces detected", "Face Detection");
else
{
int left = facePosition.xc - facePosition.w / 2;
int top = facePosition.yc - facePosition.w / 2;
gr.DrawRectangle(Pens.LightGreen, left, top, facePosition.w, facePosition.w);
FSDK.TPoint[] facialFeatures = image.DetectFacialFeaturesInRegion(ref facePosition);
int i = 0;
foreach (FSDK.TPoint point in facialFeatures)
gr.DrawEllipse((++i > 2) ? Pens.LightGreen : Pens.Blue, point.x, point.y, 3, 3);
gr.Flush();
}
// display image
pictureBox1.Image = frameImage;
pictureBox1.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception");
}
}
I get this error:
Could not load file or assembly 'xquisite.application.exe' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.
what is your settings for your target? Any CPU ? Try x86 for Runtime !
have you add to your app.config <startup useLegacyV2RuntimeActivationPolicy="true"/>
?
These two thinks i forgot, were the reason of my errors which was the same as yours.
here is a piece of my code:
private void DetectFace()
{
var failerCounter = 0;
var cameraHandler = 0;
try
{
const int failerLimit = 2;
int failerLimitFaceDetection = Properties.Settings.Default.NotDetectedLimit;
float similarityMinimum = Properties.Settings.Default.SimilarityLimit;
var r = FSDKCam.OpenVideoCamera(ref CameraName, ref cameraHandler);
if (r != FSDK.FSDKE_OK)
{
MessageBox.Show(StringHelper.ErrorCamera);
}
FSDK.SetFaceDetectionParameters(
Properties.Settings.Default.DetectionHandleArbitaryRotations,
Properties.Settings.Default.DetectionDetermineFaceRotationAngle,
Properties.Settings.Default.DetectionInternalResizeWidth);
FSDK.SetFaceDetectionThreshold(Properties.Settings.Default.DetectionFaceDetectionThreshold);
while (IsFaceDetectionActive)
{
var imageHandle = 0;
if (FSDK.FSDKE_OK != FSDKCam.GrabFrame(cameraHandler, ref imageHandle))
{
Application.Current.Dispatcher.Invoke(delegate { }, DispatcherPriority.Background);
continue;
}
var image = new FSDK.CImage(imageHandle);
var frameImage = image.ToCLRImage();
FaceContent = frameImage;
var gr = Graphics.FromImage(frameImage);
var facePosition = image.DetectFace();
IsFaceDetected = facePosition.w != 0;
if (!IsFaceDetected)
{
if (failerCounter++ > failerLimitFaceDetection)
{
failerCounter = 0;
OnFaceNotDetected();
}
}
// if a face is detected, we detect facial features
if (IsFaceDetected)
{
var facialFeatures = image.DetectFacialFeaturesInRegion(ref facePosition);
SmoothFacialFeatures(ref facialFeatures);
FaceTemplate = image.GetFaceTemplate();
// Similarity = 0.5f -> fin the right value ....
IsFaceRecognized = FaceMetricHandler.LooksLike(FaceTemplate, similarityMinimum).Any();
if (IsFaceRecognized)
{
foreach (var match in FaceMetricHandler.LooksLike(FaceTemplate, similarityMinimum))
{
failerCounter = 0;
GreetingMessage = match.Name;
IsFaceDetectionActive = false;
OnFaceRecognized();
break;
}
}
else
{
if (failerCounter++ > failerLimit)
{
failerCounter = 0;
IsFaceDetectionActive = false;
OnFaceNotRecognized();
}
}
if (IsFaceFrameActive)
{
gr.DrawRectangle(Pens.Red, facePosition.xc - 2*facePosition.w/3,
facePosition.yc - facePosition.w/2,
4*facePosition.w/3, 4*facePosition.w/3);
}
}
else
{
ResetSmoothing();
}
FaceContent = frameImage;
GC.Collect();
Application.Current.Dispatcher.Invoke(delegate { }, DispatcherPriority.Background);
}
}
catch(Exception e)
{
logger.Fatal(e.Message);
InitializeCamera();
}
finally
{
FSDKCam.CloseVideoCamera(cameraHandler);
FSDKCam.FinalizeCapturing();
}
}
BTW, you can use x64 with win64\FaceSDK.NET.dll

GDI+ error upon upload multiple images then create thumbnails

I've got an image upload page that works just fine when I only upload the files.
I added a 'Create Thumbnail' function. It looks like the file system has a handle on the images when the thumbnail process starts.
I get the 'unspecified GDI+ error' only when the image is over about 250K. When the files are below 250K, thumbnails are created as expected.
What are my options? Is there an elegant solution here? I want something not hacky.
Also, I am using HttpFileCollection so we can upload multiple images at one time. I've tried to use .Dispose on the Thumbnail creation, but it fails before we get to this point.
public void Upload_Click(object Sender, EventArgs e)
{
string directory = Server.MapPath(#"~\images\");
HttpFileCollection hfc = Request.Files;
for (int i = 0; i < hfc.Count; i++)
{
HttpPostedFile hpf = hfc[i];
if (hpf.ContentLength > 0)
{
string fileName = hpf.FileName;
fileName = fileName.Replace(" ", "");
hpf.SaveAs(fileName);
createThumbnail(fileName);
}
}
}
private void createThumbnail(string filename)
{
Image image = Image.FromFile(filename);
Image thumb = image.GetThumbnailImage(100,100, () => false, IntPtr.Zero);
thumb.Save(filename);
image.Dispose();
thumb.Dispose();
}
Please let me know if this works any better:
public string ImageDirectory { get { return Server.MapPath(#"~\images\"); } }
public void OnUploadClick(object sender, EventArgs e)
{
var files = HttpContext.Request.Files.AllKeys.AsEnumerable()
.Select(k =>HttpContext.Request.Files[k]);
foreach(var file in files)
{
if(file.ContentLength <= 0)
continue;
string savePath = GetFullSavePath(file);
var dimensions = new Size(100, 100);
CreateThumbnail(file,savePath,dimensions);
}
}
private void CreateThumbnail(HttpPostedFile file,string savePath, Size dimensions)
{
using (var image = Image.FromStream(file.InputStream))
{
using (var thumb = image.GetThumbnailImage(dimensions.Width, dimensions.Height, () => false, IntPtr.Zero))
{
thumb.Save(savePath);
}
}
}
private string GetFullSavePath(HttpPostedFile file)
{
string fileName = System.IO.Path.GetFileName(file.FileName).Replace(" ", "");
string savePath = System.IO.Path.Combine(this.ImageDirectory, fileName);
return savePath;
}
Edit -
The foreach should have followed more to this pattern:
var files = HttpContext.Request.Files.AllKeys.AsEnumerable()
.Select(k =>HttpContext.Request.Files[k]);
foreach(var file in files)
{
}
You can try this code to create your thumbnails.
MemoryStream ms = new MemoryStream(File.ReadAllBytes(path));
Bitmap originalBMP = new Bitmap(ms);
int maxWidth = 200;
int maxHeight = 200;
// Calculate the new image dimensions
int origWidth = originalBMP.Width;
int origHeight = originalBMP.Height;
double sngRatio = Convert.ToDouble(origWidth) / Convert.ToDouble(origHeight);
// New dimensions
int newWidth = 0;
int newHeight = 0;
try
{
// max 200 by 200
if ((origWidth <= maxWidth && origHeight <= maxHeight) || origWidth <= maxWidth)
{
newWidth = origWidth;
newHeight = origHeight;
}
else
{
// Width longer (shrink width)
newWidth = 200;
newHeight = Convert.ToInt32(Convert.ToDouble(newWidth) / sngRatio);
}
// Create a new bitmap which will hold the previous resized bitmap
Bitmap newBMP = new Bitmap(originalBMP, newWidth, newHeight);
// Create a graphic based on the new bitmap
Graphics oGraphics = Graphics.FromImage(newBMP);
// Set the properties for the new graphic file
oGraphics.SmoothingMode = SmoothingMode.AntiAlias;
oGraphics.InterpolationMode = InterpolationMode.High;
// Draw the new graphic based on the resized bitmap
oGraphics.CompositingQuality = CompositingQuality.HighSpeed;
oGraphics.DrawImage(originalBMP, 0, 0, newWidth, newHeight);
// Save the new graphic file to the server
EncoderParameters p = new EncoderParameters(1);
p.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 70); // Percent Compression
MemoryStream savedBmp = new MemoryStream();
newBMP.Save(savedBmp, ImageCodecInfo.GetImageEncoders()[1], p);
// Once finished with the bitmap objects, we deallocate them.
originalBMP.Dispose();
newBMP.Dispose();
oGraphics.Dispose();
savedBmp.Dispose();
Certainly a bit more work but it does give you greater control.

c# Bitmap.Save A generic error occurred in GDI+ windows application

I am doing OCR application. I have this error when I run the system which the system will save the picturebox3.image into a folder.
//When user is selecting, RegionSelect = true
private bool RegionSelect = false;
private int x0, x1, y0, y1;
private Bitmap bmpImage;
private void loadImageBT_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog open = new OpenFileDialog();
open.InitialDirectory = #"C:\Users\Shen\Desktop";
open.Filter = "Image Files(*.jpg; *.jpeg)|*.jpg; *.jpeg";
if (open.ShowDialog() == DialogResult.OK)
{
singleFileInfo = new FileInfo(open.FileName);
string dirName = System.IO.Path.GetDirectoryName(open.FileName);
loadTB.Text = open.FileName;
pictureBox1.Image = new Bitmap(open.FileName);
bmpImage = new Bitmap(pictureBox1.Image);
}
}
catch (Exception)
{
throw new ApplicationException("Failed loading image");
}
}
//User image selection Start Point
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
RegionSelect = true;
//Save the start point.
x0 = e.X;
y0 = e.Y;
}
//User select image progress
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
//Do nothing it we're not selecting an area.
if (!RegionSelect) return;
//Save the new point.
x1 = e.X;
y1 = e.Y;
//Make a Bitmap to display the selection rectangle.
Bitmap bm = new Bitmap(bmpImage);
//Draw the rectangle in the image.
using (Graphics g = Graphics.FromImage(bm))
{
g.DrawRectangle(Pens.Red, Math.Min(x0, x1), Math.Min(y0, y1), Math.Abs(x1 - x0), Math.Abs(y1 - y0));
}
//Temporary display the image.
pictureBox1.Image = bm;
}
//Image Selection End Point
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
// Do nothing it we're not selecting an area.
if (!RegionSelect) return;
RegionSelect = false;
//Display the original image.
pictureBox1.Image = bmpImage;
// Copy the selected part of the image.
int wid = Math.Abs(x0 - x1);
int hgt = Math.Abs(y0 - y1);
if ((wid < 1) || (hgt < 1)) return;
Bitmap area = new Bitmap(wid, hgt);
using (Graphics g = Graphics.FromImage(area))
{
Rectangle source_rectangle = new Rectangle(Math.Min(x0, x1), Math.Min(y0, y1), wid, hgt);
Rectangle dest_rectangle = new Rectangle(0, 0, wid, hgt);
g.DrawImage(bmpImage, dest_rectangle, source_rectangle, GraphicsUnit.Pixel);
}
// Display the result.
pictureBox3.Image = area;
** ERROR occuer here!!!!!**
area.Save(#"C:\Users\Shen\Desktop\LenzOCR\TempFolder\tempPic.jpg"); // error line occcur
singleFileInfo = new FileInfo("C:\\Users\\Shen\\Desktop\\LenzOCR\\TempFolder\\tempPic.jpg");
}
private void ScanBT_Click(object sender, EventArgs e)
{
var folder = #"C:\Users\Shen\Desktop\LenzOCR\LenzOCR\WindowsFormsApplication1\ImageFile";
DirectoryInfo directoryInfo;
FileInfo[] files;
directoryInfo = new DirectoryInfo(folder);
files = directoryInfo.GetFiles("*.jpg", SearchOption.AllDirectories);
var processImagesDelegate = new ProcessImagesDelegate(ProcessImages2);
processImagesDelegate.BeginInvoke(files, null, null);
//BackgroundWorker bw = new BackgroundWorker();
//bw.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
//bw.RunWorkerAsync(bw);
//bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}
private void ProcessImages2(FileInfo[] files)
{
var comparableImages = new List<ComparableImage>();
var index = 0x0;
foreach (var file in files)
{
if (exit)
{
return;
}
var comparableImage = new ComparableImage(file);
comparableImages.Add(comparableImage);
index++;
}
index = 0;
similarityImagesSorted = new List<SimilarityImages>();
var fileImage = new ComparableImage(singleFileInfo);
for (var i = 0; i < comparableImages.Count; i++)
{
if (exit)
return;
var destination = comparableImages[i];
var similarity = fileImage.CalculateSimilarity(destination);
var sim = new SimilarityImages(fileImage, destination, similarity);
similarityImagesSorted.Add(sim);
index++;
}
similarityImagesSorted.Sort();
similarityImagesSorted.Reverse();
similarityImages = new BindingList<SimilarityImages>(similarityImagesSorted);
var buttons =
new List<Button>
{
ScanBT
};
if (similarityImages[0].Similarity > 70)
{
con = new System.Data.SqlClient.SqlConnection();
con.ConnectionString = "Data Source=SHEN-PC\\SQLEXPRESS;Initial Catalog=CharacterImage;Integrated Security=True";
con.Open();
String getFile = "SELECT ImageName, Character FROM CharacterImage WHERE ImageName='" + similarityImages[0].Destination.ToString() + "'";
SqlCommand cmd2 = new SqlCommand(getFile, con);
SqlDataReader rd2 = cmd2.ExecuteReader();
while (rd2.Read())
{
for (int i = 0; i < 1; i++)
{
string getText = rd2["Character"].ToString();
Action showText = () => ocrTB.AppendText(getText);
ocrTB.Invoke(showText);
}
}
con.Close();
}
else
{
MessageBox.Show("No character found!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
Since it has been a while, I'm hoping you found your answer, but I'm going to guess that you needed to set the file format when you're saving a jpeg:
area.Save(#"C:\Users\Shen\Desktop\LenzOCR\TempFolder\tempPic.jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
Past that, I can't remember if the picturebox control is double buffered or not which could be the problem (if it's not, you might not be able to access it for saving purposes while it is being rendered, but if you make a copy of area before setting the picturebox3.Image property that would fix that issue):
Bitmap SavingObject=new Bitmap(area);
picturebox3.Image=area;
SavingObject.Save(#"C:\Users\Shen\Desktop\LenzOCR\TempFolder\tempPic.jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
Anyway, I hope you ended up finding your solution (considering it's been a couple months since this was posted).
This looks like a copy of this question:
c# A generic error occurred in GDI+
Same code, same error, same author.
Can't see any difference. But maybe I'm missing something.

Categories