1

I'm writing a simple utility to help teachers create sentence diagrams, which are contained in a standard Panel control. To save the diagram I am doing this:

    Private Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
        dlgSave.DefaultExt = "png"
        dlgSave.Filter = "PNG files (*.png)|*.png|All files (*.*)|*.*"
        Dim result As DialogResult = dlgSave.ShowDialog()
        If result <> DialogResult.Cancel Then
            Dim bounds As Rectangle = DisplayPanel.Bounds
            Dim pt As Point = DisplayPanel.PointToScreen(bounds.Location)
            Dim bitmap As New Bitmap(bounds.Width, bounds.Height, Imaging.PixelFormat.Format32bppArgb)
            Using g As Graphics = Graphics.FromImage(bitmap)
                g.CopyFromScreen(New Point(pt.X, pt.Y), Point.Empty, bounds.Size, CopyPixelOperation.SourceCopy)
            End Using

            bitmap.Save(dlgSave.FileName, Imaging.ImageFormat.Png)
        End If
    End Sub

The result is an incomplete image. Here's what the form with the panel looks like and what the saved image looks like:

Complete form

Incomplete copy of panel

I should mention that the text in the panel is actually contained in label controls, so it wouldn't surprise me if that wasn't included and I would need to find a fix. But I'm puzzled as to why the entire panel client area (at least) isn't getting into the saved image. Any help would be greatly appreciated.

Edit: fixed thanks to a kind user who pointed me to a similar post. Turns out I should have been using DrawToBitmap and resetting the bounds to 0, like so

           Dim bounds As Rectangle = DisplayPanel.Bounds
           Dim bmp As Bitmap = New Bitmap(DisplayPanel.Width, DisplayPanel.Height)
           bounds.X = 0
           bounds.Y = 0
           DisplayPanel.DrawToBitmap(bmp, bounds)
           bmp.Save(dlgSave.FileName, Imaging.ImageFormat.Png)

New edit: the above works for the visible area, but not if content extends beyond it. Jimi's solution (see comments, and many thanks) covers the entire scrollable area but does not include lines drawn. If I can fix this I'll post result in case anyone finds it useful.

New Edit: solution posted in comments.

Jimi
  • 29,621
  • 8
  • 43
  • 61
  • Dim bmp As Bitmap = New Bitmap(DisplayPanel.Width, DisplayPanel.Height) DisplayPanel.DrawToBitmap(bmp, DisplayPanel.Bounds) bmp.Save(dlgSave.FileName, Imaging.ImageFormat.Png) .... This gives me the top lefthand corner of the panel with empty space to top and left. In other words there seems to be some offset I should be applying. I will keep experimenting. Thanks for replying, – GERARD LEWIS Jan 12 '22 at 05:04
  • [How to print hidden and visible content of a Container with ScrollBars](https://stackoverflow.com/a/57309095/7444103) -- Prints child objects of ScrollableControls (as a Panel) in correct order, the content of RichTextBox Controls and, when specified, includes hidden Controls. Can include only the viewport or all the scrollable area. – Jimi Jan 12 '22 at 06:01
  • This is great - I hadn't yet got as far as realising that my approach doesn't work when the content extends beyond the visible area, which it can easily do. THe only trouble is that the lines I'm drawing on the panel don't appear in the bitmap, only the Label controls. I-ll try and figure out a solution to this - maybe redraw them on the bitmap before saving, or something. – GERARD LEWIS Jan 12 '22 at 12:37
  • Yep. If you have custom drawing, you may need to put that code in a method and pass that method as an `Action` to the method that prints the content. The `graphics` objects will be the derived from a BItmap in this case. -- Making the app DpiAware may help to get a Bitmap of the correct size (you also need to target a recent .Net Framework version or .Net 5+). – Jimi Jan 12 '22 at 13:51
  • 1
    Thanks for all the help. It's working perfectly now. What I did is copied your routines into my form module (without the Rich Textbox stuff which I don't need) and then added this call to the Paint event of my panel where the lines are drawn>> Dim g = Graphics.FromImage(bmp) g.Clear(canvas.BackColor) DisplayPanel_Paint(DisplayPanel, New PaintEventArgs(g, New Rectangle(0, 0, bmp.Width, bmp.Height))) .. and it gives me both, the lines and the labe controls correctly sized. Once again many thanks. – GERARD LEWIS Jan 12 '22 at 19:31

0 Answers0