0

Perhaps I am wording that question poorly, but I am trying to follow the ImageMagick.net library documentation and I have a program that generates text based on user input.

It works great the first time, but program crashes subsequent times, whilst it is still running.

If I quit and relaunch it overwrites the previous file that is there without a hitch.

using (MagickImageCollection images = new MagickImageCollection())
{
    MagickReadSettings readSettings = new MagickReadSettings()
    {
        BackgroundColor = MagickColors.None, // -background none
        FillColor = MagickColors.Black, // -fill black
        Font = "Helvetica-Condensed-Light", // -font Helvetica-Condensed-Light
        FontPointsize = 26 // -pointsize 26
    };

    // this being declared a second time is probably why it crashes.

    MagickImage image = new MagickImage("label:" + output, readSettings);
    image.RemoveAttribute("label"); // +set label
    images.Add(image);

    MontageSettings montageSettings = new MontageSettings()
    {
        BackgroundColor = MagickColors.None, // -background none
        Shadow = true, // -shadow
        Geometry = new MagickGeometry(5, 5, 0, 0) // -geometry +5+5
    };

    using (MagickImage result = images.Montage(montageSettings))
    {
        result.Write("blarg.png");
    }
}

since the action of the above function resides in a button event handler, thus if pressed a second time, it will be declared a second time, but I am still relatively new to C# as well and unsure of a way to rewrite this properly since I am adapting it from their documentation.

Error:

Exception thrown: 'ImageMagick.MagickCoderErrorException' in Magick.NET-Q8-x64.dll
Exception type ImageMagick.MagickCoderErrorException
Exception message: WriteBlob Failed `blarg.png' @ error/png.c/MagickPNGErrorHandler/1650
Stack trace:    at ImageMagick.MagickExceptionHelper.Check(IntPtr exception)
  at ImageMagick.MagickImage.NativeMagickImage.WriteFile(MagickSettings settings)
  at phVer.frmMain.btnGenerate_Click(Object sender, EventArgs e) in C:\Users\jweinraub\documents\visual studio 2015\Projects\phVer\phVer\Form1.cs:line 83
---BEGIN InnerException--- 
Exception type ImageMagick.MagickBlobErrorException
Exception message: unable to open image 'blarg.png': Permission denied @   error/blob.c/OpenBlob/2695
Stack trace: 
---END Inner Exception

Update: It seems the actual problem is I have a preview pane that contains a background image of the image that gets saved. Subsequent runs crashes. Removing the preview pane allows the file to be written numerous times but unsure why preview pane has an issue (its a panel control with background image control). I've tried setting to null/disposing/&c to no avail.

/* Preview.BackgroundImage = Image.FromFile("blarg.png"); */
if ( Preview.BackgroundImage != null )
{
    Preview.BackgroundImage.Dispose();
    Preview.BackgroundImage = null;
    Preview.Dispose();
}
var image2 = (Bitmap)Image.FromFile("blarg.png", true);
Preview.BackgroundImage = image2;
Jon Weinraub
  • 397
  • 1
  • 8
  • 18
  • 7
    What error do you get? – SLaks Dec 21 '16 at 20:26
  • out of curiosity, does it still crash if you do using(MagickImage result = new MagickImage("blarg.png")) instead of the montage? – Marshall Tigerus Dec 21 '16 at 20:35
  • error added in original question. – Jon Weinraub Dec 21 '16 at 21:10
  • yes, unhandled exception gets thrown on the result. I am suspecting it is the redeclaration of `MagickImage image = new MagickImage` when the button is pressed a second time while the program is still running. – Jon Weinraub Dec 21 '16 at 21:14
  • It looks as though the file `blarg.png` might have been left open somehow. Try writing to a different file each time. – dbc Dec 24 '16 at 04:23
  • @dbc - interesting. I tried now two different theories. First yours, and it worked fine. Then I reverted, back to what I did, and commented out `Preview.BackgroundImage = Image.FromFile("blarg.png");` which is where it actually crashes. So, now I know it is the background preview image that is faulting. I suspect I should edit the original question since that is what is now at fault? – Jon Weinraub Dec 27 '16 at 17:08
  • @JonWeinraub - According to the [docs](https://msdn.microsoft.com/en-us/library/stf701f5(v=vs.110).aspx) for `Image.FromFile()`, *The file remains locked until the Image is disposed.* So you need to dispose the image immediately after loading, cloning it first. See http://stackoverflow.com/a/8701748/3744182 – dbc Dec 29 '16 at 00:50
  • Are you sure that calling `Preview.Dispose();` is correct? Why would you need to dispose the preview pane? – dlemstra Dec 29 '16 at 22:06
  • It is the preview pane that is actually crashing. If I comment it out, the file gets overwritten fine (since I can go to location where the file is being saved and view it actually changed). the preview pane it seems is unable to update itself when i tell it to use the same file again. if i use a different file, it works, fine, which perhaps is another solution, but feels like a cop out. i will try the disposing / clone though. – Jon Weinraub Jan 03 '17 at 14:55

1 Answers1

3

Image.FromFile will lock the file. You should do something like the example below to avoid the lock.

if (Preview.BackgroundImage != null)
  Preview.BackgroundImage.Dispose();

using (var bitmap = new Bitmap("blarg.png"))
{
  Preview.BackgroundImage = new Bitmap(bitmap);
}
dlemstra
  • 7,813
  • 2
  • 27
  • 43
  • Ah, that makes sense, and works, thanks! When I tried putting dispose in an if not equals null block, when it later tried to assign it, I got a null reference exception thrown. Is the `using` method a better way in handling these sort of things opposed to the way I did it? – Jon Weinraub Jan 04 '17 at 14:18