wallstop
wallstop

Reputation: 41

GDI+ Fails to save PNG C#

Edit:

This appears to be a filesize issue. The filesize that I'm working with is 10600 x 700 pixels. This ends up being a ~280 MB bitmap. I've attempted saving significantly smaller file sizes (10x10) as PNG, where they correctly save out. Is there a size limitation that is being hit with GDI+?

Pretty much full code:

class Converter
{
    /* Each PNG below is 50x50 */
    private static readonly int BLOCK_SIZE = 50;

    private static Dictionary<char, Bitmap> BlockLookup => new Dictionary<char, Bitmap>
    {
        {'R', new Bitmap("Content/Map/Blocks/RedBlock.png")},
        {'G', new Bitmap("Content/Map/Blocks/GreenBlock.png")},
        {'B', new Bitmap("Content/Map/Blocks/BlueBlock.png")},
        {'P', new Bitmap("Content/Map/Blocks/PurpleBlock.png")},
        {'Y', new Bitmap("Content/Map/Blocks/YellowBlock.png")},
        {'O', new Bitmap("Content/Map/Blocks/OrangeBlock.png")}
    };

    public void Convert(string textFilePath, string outputDirectory)
    {
        List<string> fileContents = new List<string>();
        /* Irrelevant loading code snipped, loads text file into fileContents */
        int width = fileContents.Max(line => line.Length) * BLOCK_SIZE; // 10600
        int height = fileContents.Count * BLOCK_SIZE; // 700

        /* Try to convert our text-file-as-image into a real image, mapping chars to their blocks */
        using (Bitmap bitmap = new Bitmap(width, height))
        {
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.Clear(Color.WhiteSmoke);
                graphics.SmoothingMode = SmoothingMode.AntiAlias;

                for (int y = 0; y < fileContents.Count; ++y)
                {
                    for (int x = 0; x < fileContents[y].Length; ++x)
                    {
                        char currentCharacter = fileContents[y][x];
                        if (!blockLookup.ContainsKey(currentCharacter))
                        {
                            continue;
                        }
                        Bitmap mapBlock = blockLookup[currentCharacter];
                        var mapX = x * BLOCK_SIZE;
                        var mapY = y * BLOCK_SIZE;
                        graphics.DrawImage(mapBlock, new Point(mapX, mapY));
                    }
                }
                graphics.Flush(FlushIntention.Sync);
                graphics.Save();
            }
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }
            bitmap.Save(outputDirectory + mapName, ImageFormat.Png);
        }

    }
}

I have the following code:

using (Bitmap bitmap = new Bitmap(width, height))
{
    using (Graphics graphics = Graphics.FromImage(bitmap))
    {
        graphics.Clear(Color.WhiteSmoke);
        /* SNIP, a bunch of image manipulation here */
        graphics.Flush();
    }

    if (!Directory.Exists(outputDirectory))
    {
        Directory.CreateDirectory(outputDirectory);
    }
    bitmap.Save(outputDirectory + imageName, ImageFormat.Bmp);
}

This code works great. However, if I change the ImageFormat from ImageFormat.Bmp to be ImageFormat.Png, I get a "A generic error occurred in GDI+.". I've scoured stackoverflow and google. The files do not exist, the path does. I've deleted all output files. I've tried 64bit & 32bit builds. Even stuff like copying the Bitmap and writing to memory streams fails (the below does not work):

using (Bitmap bitmap = new Bitmap(width, height))
{
    using (Graphics graphics = Graphics.FromImage(bitmap))
    {
        graphics.Clear(Color.WhiteSmoke);
        /* SNIP, a bunch of image manipulation here */
        graphics.Flush();
    }

    if (!Directory.Exists(outputDirectory))
    {
        Directory.CreateDirectory(outputDirectory);
    }
    using (MemoryStream memoryStream = new MemoryStream())
    {
        Bitmap temp = new Bitmap(bitmap);
        temp.Save(memoryStream, ImageFormat.Png);
    }
}

I'd really like to be able to output PNG files. However, there seems to be some issue that I'm unaware of with (my version?) of GDI and PNG files. Is there anything I can do to get PNG output?

Upvotes: 4

Views: 759

Answers (2)

innuendomaximus
innuendomaximus

Reputation: 353

Maybe this isn't worth as an answer and should be a comment. But I can move it if you want to :)

Indeeed Windows 7 has some problems with big pictures, not sure its GDI+ related or just deeper in the core. But I programmed a photoediting software for university and noticed, that I couldn't load and/or format pictures larger than ~180MB. I found a workaround by piping it in an array and slicing it. But I don't know if you can use that. If I find that code I will update this post.

Upvotes: 1

Juergen
Juergen

Reputation: 68

Sorry, but your Code is working great - I tested it with VS 2013 Express for Win Desktop on Windows Server 2012 R2 - not a problem at all.

Test 1:

private int width = 10600;
private int height = 700;
using (Bitmap bitmap = new Bitmap(width, height))
        {
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.Clear(Color.Black);
                /* SNIP, a bunch of image manipulation here */
                graphics.Flush();

            }
            bitmap.Save("image.png", ImageFormat.Png);

        }
    }

Test 2:

private int width = 10600;
private int height = 700;
using (Bitmap bitmap = new Bitmap(width, height))
        {
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.Clear(Color.Black);
                /* SNIP, a bunch of image manipulation here */
                //I read a little around - maybe your graphics operations are out of sync?
                graphics.Flush(FlushIntention.Sync);
                graphics.Save();


            }

            using (MemoryStream memoryStream = new MemoryStream())
            {
                Bitmap temp = new Bitmap(bitmap);
                //temp.Save("image.png", ImageFormat.Png); //this worked obviously
                temp.Save(memoryStream, ImageFormat.Png);

                pictureBox1.Image = Image.FromStream(memoryStream); //a huge black box appears - everything is working fine
            }
        }
    }

Maybe you have a system-issue?

I meant to comment this, but not enough reputation =,(

Upvotes: 2

Related Questions