This project has moved. For the latest updates, please go here.

Running Magick.Net in a threaded application

Mar 17, 2015 at 5:45 PM
So I'm using a FileSystemWatcher to watch a folder for new images. When a new image comes in raised eventHandler will take the new file, check orientation, add a border, composite it with a background and write it all out.

Oddly, if I drop 10 images in, it cranks through without issue. But if I drop a new image in, wait 2 seconds and then drop another in I get an error message. If I tell the program to sleep for 5-6 seconds, then it doesn't seem have an issue. But I'm sure this is going to vary depending on file size. Is there any way to prevent it? I tried doing sleep(0) to wait for the thread to finish, but that didn't work.

Image

private void startActivityMonitoring(string sPath)
        {
            // This is the path we want to monitor
            watchFolder.Path = sPath;

            // Make sure you use the OR on each Filter because we need to monitor
            // all of those activities

            watchFolder.NotifyFilter = System.IO.NotifyFilters.DirectoryName;

            watchFolder.NotifyFilter =
            watchFolder.NotifyFilter | System.IO.NotifyFilters.FileName;
            watchFolder.NotifyFilter =
            watchFolder.NotifyFilter | System.IO.NotifyFilters.Attributes;

            // Now hook the triggers(events) to our handler (eventRaised)
            watchFolder.Created += new FileSystemEventHandler(eventRaised);


            // Occurs when a file or directory is renamed in the specific path
            //watchFolder.Renamed += new System.IO.RenamedEventHandler(eventRenameRaised);

            // And at last.. We connect our EventHandles to the system API (that is all
            // wrapped up in System.IO)
            try
            {
                watchFolder.EnableRaisingEvents = true;
            }
            catch (ArgumentException)
            {
                //abortAcitivityMonitoring();
            }
        }


private void eventRaised(object sender, System.IO.FileSystemEventArgs e)
        {
            //System.Threading.Thread.Sleep(6000);
            string prevFile = null;
            string archivePath = Path.Combine(txtHotfolder.Text, "archive");
            if (txtStatus.InvokeRequired)
            {
                txtStatus.Invoke(new MethodInvoker(delegate { prevFile = txtStatus.Text; }));
            }

            if (e.ChangeType == WatcherChangeTypes.Created && prevFile != e.Name)
            { 
                string newFile = e.FullPath;
                                    
                //setup output path make sure the folder is there
                string outputPath = @"C:\output\";
                if (!Directory.Exists(outputPath))
                {
                    Directory.CreateDirectory(outputPath);
                }

                    using (MagickImageCollection images = new MagickImageCollection())
                    {
                        string appPath = Path.GetDirectoryName(Application.ExecutablePath);

                        //add the image
                        MagickImage image = new MagickImage(newFile);
image.BorderColor = Color.White;
                        image.Border(10);
                        images.Add(image);
MagickImage background = new MagickImage(Path.Combine(appPath, "backgroud.jpg"));
                            background.ColorSpace = ColorSpace.sRGB;
                            images.Add(background);
                            background.Composite(image, Gravity.Center, CompositeOperator.Over);

                            DrawableFont font = new DrawableFont("Arial");
                            DrawablePointSize pointSize = new DrawablePointSize(40);
                            DrawableFillColor fillcolor = new DrawableFillColor(Color.White);
                            DrawableStrokeColor strokeColor = new DrawableStrokeColor(Color.Black);
                            DrawableText text = new DrawableText(40, background.Height - 50, Path.GetFileNameWithoutExtension(newFile));
                            background.Draw(font, pointSize, strokeColor, fillcolor, text);
                            string outputFile = Path.Combine(outputPath, Path.GetFileName(newFile));
                            background.Write(outputFile);
}
Coordinator
Mar 17, 2015 at 9:59 PM
Edited Mar 18, 2015 at 5:36 AM
I don't think this is a Magick.NET issue. It is most likely that you are trying to access a file that is still being written to. I use a FileInfo extension method that tries to access the file until no security/unauthorizedaccess exceptions are raised anymore in my own projects. Below is the code I am using.
public static bool WaitForExclusiveAccess(this FileInfo self, int timeoutInMilliseconds)
{
  Throw.IfNull("self", self);

  if (!self.Exists)
    return false;

  Stopwatch stopWatch = Stopwatch.StartNew();

  while (stopWatch.ElapsedMilliseconds < timeoutInMilliseconds)
  {
    try
    {
      using(FileStream fs = new FileStream(self.FullName, FileMode.Open, FileAccess.Read, FileShare.None))
      {
      }
      return true;
    }
    catch (IOException)
    {
      Thread.Sleep(500);
      continue;
    }
    catch (UnauthorizedAccessException)
    {
      Thread.Sleep(500);
      continue;
    }
    catch (Exception)
    {
      throw;
    }
  }

  return false;
}