Search code examples
c#canvasgraphicsbitmapgrasshopper

Issues with Rendering a Bitmap


I am currently working on a histogram renderer that renders bitmaps onto the Grasshopper canvas. There are a total of two bitmaps, both of them explained below

private readonly Bitmap _image;

and:

private readonly Bitmap _overlayedImage;

The Bitmap instance with the name _image looks like this:

_bitmap http://puu.sh/6mUk4/20b879710a.png

While the Bitmap instance with the name _overlayedImage looks like this:

enter image description here

Basically, _overlayedImage is a bitmap that is created using the _image bitmap, and as the name suggests, overlays the text (that you can see in the image I posted) and adds a black background to it. This is how it is assigned

_overlayedImage = overlayBitmap(_image, width * 3, height * 3, times, dates, colors);

(The * 3 is used to resize the image).


An issue I currently have is multi-fold.

Using this method, I am able to render _image onto the canvas.

enter image description here

The code is like this:

    protected override void Render(Grasshopper.GUI.Canvas.GH_Canvas canvas, Graphics graphics, Grasshopper.GUI.Canvas.GH_CanvasChannel channel) {
        // Render the default component.
        base.Render(canvas, graphics, channel);

        // Now render our bitmap if it exists.
        if (channel == Grasshopper.GUI.Canvas.GH_CanvasChannel.Wires) {
            var comp = Owner as KT_HeatmapComponent;
            if (comp == null)
                return;

            List<HeatMap> maps = comp.CachedHeatmaps;
            if (maps == null)
                return;

            if (maps.Count == 0)
                return;

            int x = Convert.ToInt32(Bounds.X + Bounds.Width / 2);
            int y = Convert.ToInt32(Bounds.Bottom + 10);

            for (int i = 0; i < maps.Count; i++) {
                Bitmap image = maps[i].overlayedImage;
                if (image == null)
                    continue;

                Rectangle mapBounds = new Rectangle(x, y, maps[i].Width, maps[i].Height);
                mapBounds.X -= mapBounds.Width / 2;

                Rectangle edgeBounds = mapBounds;

                GH_Capsule capsule = GH_Capsule.CreateCapsule(edgeBounds, GH_Palette.Normal);
                capsule.Render(graphics, Selected, false, false);
                capsule.Dispose();
                graphics.DrawImage(image, mapBounds);
                graphics.DrawRectangle(Pens.Black, mapBounds);

                // some graphics interpolation and bicubic methods

                y = edgeBounds.Bottom - (mapBounds.Height) - 4;
            }
        }
    }

As per what comp.CachedHeatmaps; is:

    private readonly List<HeatMap> _maps = new List<HeatMap>();

    internal List<HeatMap> CachedHeatmaps {
        get { return _maps; }
    }

However, whenever I try to use Render() on the _overlayedImage, I am unable to do so.

I have isolated the issue to the Render() method, and it seems this line

Rectangle mapBounds = new Rectangle(x, y, maps[i].Width, maps[i].Height); is the main issue, as maps[i].Width and maps[i].Height returns 1 and 100 respectively, which are coincidentally the dimensions of the legend, which are 100 pixels vertically and 1 pixel horizontally.


I apologize for the decently long question, but I don't think I could have explained it any other way.


Solution

  • It turns out there are two issues:

    In my main method I used _overlayedImage.Dispose(), which effectively destroyed the image before it was even displayed onto the canvas.

    Also, my issue isolation was also correct. This line resulted in the thing rendering correctly:

    Rectangle mapBounds = new Rectangle(x, y, maps[i].overlayedImage.Width, maps[i].overlayedImage.Height);

    Resulting component:

    enter image description here