0

I'm trying to save a canvas which contains some shapes as image (*.jpg, *.bmp, *.png) and load that image to canvas again.

When I click the "Save button" and then I click the "Load Button" and then I clicked the "Save Button" again, I have the following fault:

The process cannot access the file 'H:\VisualC\HK5\LT Win\ForTesting\TestSaveCanvasToBitmap\bin\Debug\TestImage.bmp' because it is being used by another process.

It seems to be there is a File Stream which is open but isn't closed yet. Can anyone explain for me?

Thanks in advance!

Here is my code

public void SaveImage(Canvas canvas, int width, int height, string filePath)
        {
            Rect bounds = VisualTreeHelper.GetDescendantBounds(canvas);
            double dpi = 96d;
            RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, dpi, dpi, System.Windows.Media.PixelFormats.Default);

            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                VisualBrush vb = new VisualBrush(canvas);
                dc.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
            }

            rtb.Render(dv);

            BmpBitmapEncoder image = new BmpBitmapEncoder();
            image.Frames.Add(BitmapFrame.Create(rtb));

            using (Stream fs = File.Create(filePath))
            {
                image.Save(fs);
                fs.Close();
            }
        }
        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            int width = (int)myCanvas.ActualWidth;
            int height = (int)myCanvas.ActualHeight;
            string filePath = "TestImage.bmp";

            SaveImage(myCanvas, width, height, filePath);
        }

        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            Uri uri = new Uri(@"TestImage.bmp", UriKind.Relative);

            BitmapImage bmi = new BitmapImage(uri);

            ImageBrush brush = new ImageBrush();
            brush.ImageSource = bmi;

            myCanvas.Background = brush;
        }
Duy
  • 67
  • 1
  • 12

2 Answers2

0

The file is still locked, because you are referencing it directly in your brush. Without a good, minimal, complete code example that reliably reproduces the problem, it's impossible to know for sure what the best fix is. But most likely, if you just clone the bitmap object before using it in the brush, by the time you get around to trying to save to the file again, it will be released.

E.g.:

BitmapImage bmi = new BitmapImage(uri).Clone();

Unfortunately, I'm not aware of a good deterministic way to force the BitmapImage object, and in particular its reference to the file, to be closed. It's possible you can call Freeze() and it would disconnect from the file (but I haven't tried that). Alternatively, forcing a garbage collection should work (i.e. call GC.Collect()).

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
0

When you load image and try to save it by overwriting it, the image which is referenced to its physical file, is still used by your application, therefore the file cannot be overwritten. I guess when you create BitmapImage object from URI, the stream that attached to a file is always opened. Try to change your loading method like this.

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
  MemoryStream memoStream = new MemoryStream();

  using (FileStream fs = File.OpenRead("TestImage.bmp"))
  {
    fs.CopyTo(memoStream);

    BitmapImage bmi = new BitmapImage();

    bmi.BeginInit();

    bmi.StreamSource = memoStream;

    bmi.EndInit();

    ImageBrush brush = new ImageBrush(bmi);

    myCanvas.Background = brush;

    fs.Close();
  }
}

The idea is to copy file stream to memory stream, so your image object will live in memory which will not depend on file anymore.

Nugi
  • 862
  • 6
  • 11