Search code examples
c#bitmapmonosystem.drawing

Drawing Ellipses to a Bitmap. Works in .NET, does not work in Mono


I'm having some issues with drawing ellipses to a bitmap in a .NET 4.0 C# WinForms application running on mono 4.6.2 on Raspbian 9 (stretch). The method in question generates a bitmap of 5 white circles of a specified diameter on a black screen. One circle per corner of the screen, and one in the center. The bitmap is meant to encompass the entire screen, so I'm getting the size for the bitmap as a rectangle via Screen.Bounds(), which in turn gives me Res.Width and Res.Height.

This code works as expected in Windows in .NET (which is what it was originally written for and tested on) but running the exe through mono on Raspbian, simply fills the bitmap with white. I have also found that running in mono for Windows (v5.10.0.160), the circles generated end up being smaller than when run in .NET.

private Bitmap GenerateCirclesBitmap(int diam)
    {
        Bitmap bmp = GenerateColorBitmap(Color.Black);
        Graphics g = Graphics.FromImage(bmp);
        g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;

        Brush whiteBrush = new SolidBrush(Color.White);
        g.FillEllipse(whiteBrush, diam/7, diam/7, diam, diam);    //Top Left Corner
        g.FillEllipse(whiteBrush, diam/7, (Res.Height - diam)-(diam/7), diam, diam); //Bottom Left Corner
        g.FillEllipse(whiteBrush, (Res.Width - diam) - (diam / 7), (Res.Height - diam) - (diam / 7), diam, diam); //Bottom Right Corner
        g.FillEllipse(whiteBrush, (Res.Width - diam) - (diam / 7), diam/7, diam, diam); //Top Right Corner
        g.FillEllipse(whiteBrush, (Res.Width / 2) - (diam / 2), (Res.Height / 2) - (diam / 2), diam, diam); //Center
        g.DrawImage(bmp, Res.Width, Res.Height);
        return bmp;
    }

I was thinking maybe it was an issue with the dimensions of the screen, Res.Width and/or Res.Height, but if that were the case I would expect my method to generate color bars would have problems as well. However this code works as expected (8 color bars each 1/8 of total screen width) on both versions of mono as well as in .NET, which leads me to think that Res.Width is OK:

        private Bitmap GenerateBarsBitmap(Color bar1, Color bar2, Color bar3, Color bar4, Color bar5, Color bar6)
    {
        Bitmap bmp = GenerateColorBitmap(Color.Black);
        int barwidth = Res.Width / 8;
        Color[] colors = new Color[8];
        Brush b = new SolidBrush(Color.White);
        Graphics g = Graphics.FromImage(bmp);

        colors[0] = Color.White;
        colors[1] = bar1;
        colors[2] = bar2;
        colors[3] = bar3;
        colors[4] = bar4;
        colors[5] = bar5;
        colors[6] = bar6;
        colors[7] = Color.Black;

        g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;

        for (int colornum = 0; colornum < colors.Length; colornum++)
        {
            b = new SolidBrush(colors[colornum]);
            g.FillRectangle(b, barwidth * colornum, 0, barwidth, Res.Height);
            b.Dispose();
        }

        return bmp;
    }

Any ideas or insight would be appreciated. Thanks!


Solution

  • One difference between your two routines is the line

    g.DrawImage(bmp, Res.Width, Res.Height);
    

    It comes after you draw the circles. So in a fully compatible world the Mono framework should do the same as .NET does, i.e. draw the bitmap with all the new content over itself.

    But fully compatible is not just hard. Given all the weirdness in the long history of GDI, .NET etc, it is in fact out of the question..

    Mono seems to use the original version of the bitmap without the newly drawn circles and by drawing it over itself it deletes them.

    So remove the unnessesary line and all should be well..