# Async Saving of Images

**URL:** <https://forum.commonvisionblox.com/t/async-saving-of-images/573>\
**Category:** Programming Questions\
**Created:** [October 22, 2018, 11:23am UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573 "2018-10-22T11:23:12Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![parsd](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/parsd/32/7_2.png) [@parsd](https://forum.commonvisionblox.com/u/parsd)\
**Post date:** [October 22, 2018, 8:05pm UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/2 "2018-10-22T20:05:28Z")

</div>

I think the answer is easier shown with a project: [AcqSave.zip](https://forum.commonvisionblox.com/uploads/commonvisionblox/original/1X/0b6930603c92f574c5279fbbe4b771e9264f2611.zip) (11.9 KB). The _Stemmer.Cvb_ and _Stemmer.Cvb.Wpf_ assemblies need to be installed also (see the [downloads](https://forum.commonvisionblox.com/t/common-vision-blox-add-ons/570)). The app expects the camera to be in software trigger mode. If it is not it will save a lot of images 🙂.

In the project I implemented the _ISoftwareTrigger_ via a `Button`. The `MainWindow` also shows a live image. The `MainViewModel` provides the live `Image` and commands for triggering and app-closing. The whole program logic is in the `TriggerSaver` model class.

The `MainWindow` creates the `MainViewModel` which in turn creates the `TriggerSaver` which opens the first GenICam device it finds. Then the app is run async via WPF’s `Dispatcher`. Thus the main logic runs on the UI thread. That is not a bad thing as all the code is written async. The `Image.Save` is executed via .Net’s task pool (`Task.Run`).

The :cvb: `Device` is encapsulated in the model class `TriggerSaver`. Only the live `Image` is publicly available plus the use cases of running the app and sending (double) software triggers. Depending on the camera used you probably want to modify the `TriggerSaver.SendSoftwareTrigger` method.

The app logic is written in a way that we wait for two images and save them as soon as they arrive. We utilize :cvb:'s _IRingBuffer_ interface to keep the acquisition code simple without loosing images. We use `RingBufferLockMode.On` and manually unlock acquired `Image`s via the `using`-block in `SaveAndUnlockImageAsync`. Depending on your acquisition rate and hard disk/ssd used you might need to increase the buffer count on the ring buffer to handle processing peaks (see `TriggerSaver.SetupDevice`).

Here is the core logic:

```auto
public async Task RunAsync(CancellationToken cancellationToken)
{
  var stream = _device.Stream;
  stream.RingBuffer.LockMode = RingBufferLockMode.On;

  stream.Start();
      
  try
  {
    long counter = 0;
    while (!cancellationToken.IsCancellationRequested)
    {
      try
      {
        var savesFinished = new Task[2];
        for (int i = 0; i < 2; i++)
        {
          var imageTask = stream.WaitForAsync(AcquisitionTimeout);
          savesFinished[i] = SaveAndUnlockImageAsync(imageTask, counter++);
        }

        await Task.WhenAll(savesFinished);            
      }
      catch (TimeoutException)
      {
        // swallow timeouts, but we need to check for cancellation
      }
    }
  }
  finally
  {
    stream.Abort();
  }
}

private async Task SaveAndUnlockImageAsync(Task<StreamImage> imageTask, long imageNumber)
{
  Debug.Assert(imageTask != null);

  using (var image = await imageTask)
  {
    await SaveImageAsync(image, imageNumber);
  }
}

private static Task SaveImageAsync(Image image, long imageNumber)
{
  Debug.Assert(image != null);

  return Task.Run(() =>
    image.Save(Path.Combine(StorageDirectory, $"{imageNumber}.bmp"))
  );
}

```

---

_[View the full topic](https://forum.commonvisionblox.com/t/async-saving-of-images/573)._
