0

I have this code:

RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(525, 50, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(/* controlName */);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create(Environment.CurrentDirectory)
{
    pngImage.Save(fileStream);
}

It supposed to take a control from my XAML and create a "screenshot" of it and then save it to an image file. But no matter what directory I try to pass to the File.Create method, I get a System.UnauthorizedAccessException.

How to fix it? Thanks.

Note: I have tried to run Visual Studio as an administrator, didn't work.

Michael Haddad
  • 4,085
  • 7
  • 42
  • 82
  • 2
    Your application does not have permissions to access the directory. Make sure you write to a location where the account your application runs under has write access. – Wicher Visser Apr 14 '16 at 14:25
  • What is the full stack trace of the error? Also have you tried using the `File.WriteAllBytes();` method? Try saving it to the desktop of the user you are logged in as. – Wjdavis5 Apr 14 '16 at 14:26
  • @WicherVisser- I have tried several locations including `C:\` drive, the desktop and also the directory of the application itself. – Michael Haddad Apr 14 '16 at 14:29
  • @Wjdavis5 - could you please elaborate? Thank you both very much! – Michael Haddad Apr 14 '16 at 14:30
  • @Sipo elaborate on which part? Chances are you wont be able to save to the C drive root. But the desktop should work fine. – Wjdavis5 Apr 14 '16 at 14:33
  • @Wjdavis5 - about the function. Also, my computer is not in English so the full error contains more languages... – Michael Haddad Apr 14 '16 at 14:36
  • @Sipo A quick google will bring you to this page: https://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes%28v=vs.110%29.aspx – Wjdavis5 Apr 14 '16 at 14:37
  • @Wjdavis5 - I mean - could you elaborate on how this function could help me solve my problem? – Michael Haddad Apr 14 '16 at 14:39
  • `File.Create(/* directory */)` makes me think you are passing a directory name. You would have to pass a file path instead, *including the file name*, or just a file name without path to write to the application's current directory, e.g. `File.Create("MyImage.png")` – Clemens Apr 14 '16 at 14:44
  • @Sipo Clemens is correct, and if you post the full error in the question it should give us the path you are trying to use. – Wjdavis5 Apr 14 '16 at 14:44

2 Answers2

2

You'll have to pass a file name (optionally including a path) to File.Create, like:

File.Create("MyImage.png")

or

var path = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "MyImage.png");

using (var fileStream = FileFile.Create(path))
{
    pngImage.Save(fileStream);
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Yes. It works perfectly. Thanks. The problem is that it creates a black image. Any idea why? – Michael Haddad Apr 14 '16 at 14:49
  • Is the rendered control created on the fly, or already shown somewhere in the UI? – Clemens Apr 14 '16 at 14:51
  • It is created in the code behind during runtime. I have tried after reading your comment to change the element to an element that was created in the XAML, and it worked - but the one that I have tried to create "on the fly" doesn't. – Michael Haddad Apr 14 '16 at 14:53
  • You have to call Measure and Arrange on the control to perform its initial layout. See e.g. here: http://stackoverflow.com/a/12766990/1136211 or here: http://stackoverflow.com/a/28628256/1136211 – Clemens Apr 14 '16 at 14:55
  • Hmm, could you please explain in the answer how to use these Measure and Arrange staff? I am pretty novice to all of this... Thanks a lot for your help! – Michael Haddad Apr 14 '16 at 14:57
  • See the linked answers from my last comment. Or here: http://stackoverflow.com/a/14953281/1136211 – Clemens Apr 14 '16 at 14:58
  • Can't seem to make it worked. Here is what I am *trying* to do (don't ask me why): I want to create a frame dynamically when the user clicks a button. And then I want to "take a photo" of this frame. How to do it, including the Measure and Arrange methods you talked about? Thanks. – Michael Haddad Apr 14 '16 at 15:11
  • You probably better ask a new question, including the relevant parts of the code that you have so far. – Clemens Apr 14 '16 at 15:15
  • OK, Thanks! I will ask a new question, and refer to it here! Thanks a lot! – Michael Haddad Apr 14 '16 at 15:16
  • Here is the new question: http://stackoverflow.com/questions/36627745/how-to-take-a-photo-of-a-frame-that-was-created-in-the-code-behind-during-run/36628215#36628215 Thanks a lot! – Michael Haddad Apr 14 '16 at 16:13
-1

To get rid of the black image try manually disposing the object after you've used it. Example shown below.

private void button_Click(object sender, RoutedEventArgs e)
    {
        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(525, 50, 96, 96, PixelFormats.Pbgra32);
        renderTargetBitmap.Render(btn_StartStop);
        PngBitmapEncoder pngImage = new PngBitmapEncoder();
        pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
        FileStream stream = new FileStream("screenshot.png", FileMode.Create);
        pngImage.Save(stream);
        stream.Dispose();            
    } 
Cuken
  • 29
  • 3
  • This is equivalent to a `using` block, where `using` is the preferred approach. – Clemens Apr 14 '16 at 14:51
  • @Clemens Completely understood, some of these imaging methods do not properly render the image while inside of the using block. – Cuken Apr 14 '16 at 14:53