Dylan Parry
Dylan Parry

Reputation: 3453

Empty file when saving as PNG

I’ve got a method which takes an input image, does some things to the image, then saves it to another file. At its most basic it resizes the image, but it can do a few more complicated things like converting to greyscale, quantizing etc, but for the case of this question I’m only attempting to resize the image and not performing any of the other actions.

It looks something like:

public void SaveImage(string src, string dest, int width, int height, ImageFormat format, bool deleteOriginal, bool quantize, bool convertToGreyscale) {
    // Open the source file
    Bitmap source = (Bitmap)Image.FromFile(src);

    // Check dimensions
    if (source.Width < width)
        throw new Exception();
    if (source.Height < height)
        throw new Exception();

    // Output image
    Bitmap output = new Bitmap(width, height);
    using (Graphics g = Graphics.FromImage(output)) {
        // Resize the image to new dimensions
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.DrawImage(source, 0, 0, width, height);
    }

    // Convert to greyscale if supposed to
    if (convertToGreyscale) {
        output = this.ConvertToGreyscale(output);
    }

    // Save the image
    if (quantize) {
        OctreeQuantizer quantizer = new OctreeQuantizer(255, 8);
        using (var quantized = quantizer.Quantize(output)) {
            quantized.Save(dest, format);
        }
    }
    else {
        output.Save(dest, format);
    }

    // Close all the images
    output.Dispose();
    source.Dispose();

    // Delete the original
    if (deleteOriginal) {
        File.Delete(src);
    }
}

Then to use it I’d call something like: imageService.SaveImage("c:\image.png", "c:\output.png", 300, 300, ImageFormat.Png, false, false, false);

That should open up the “image.png” file, resize in to 300×300, then save it to “output.png” as a PNG file. But it’s not working—the file that gets created is in the correct location but has a file size of zero and contains no image at all.

This also only seems to happen when I pass in the parameter ImageFormat.Png; if I pass ImageFormat.Jpeg, then it works fine and creates the image file perfectly.

I’m wondering if there’s some sort of delay occurring between creating the image and somewhere else in the code attempting to access the image that’s been created (not in the above code) which locks up the file and so it’s never written to? Could that be the case?

Any ideas what else could be going on?

Cheers

Edits:

Upvotes: 4

Views: 1903

Answers (2)

Lilith River
Lilith River

Reputation: 16468

Using the Save() parameter with a Stream instead of a filename will allow you to ensure the file is flushed to disk before the objects are disposed.

However, I'd strongly suggest using a server-safe image-processing library here, as you're playing with fire.

Upvotes: 0

lboshuizen
lboshuizen

Reputation: 2786

There are some historical issues with saving bitmaps as png.

Using System.Windows.Media.Imaging.PngBitmapEncoder can resolve this

See System.Windows.Media.Imaging.PngBitmapEncoder

And How to: Encode and Decode a PNG Image for a sample.

Upvotes: 3

Related Questions