Search code examples
vb.netwinformsdatagridviewgraphicstiff

Create a Tiff Bitmap file from a DatagridView


I want to create a Tiff file from a Datagridview. I was able to get the Datagridview to a Tiff file, however I just want the Rows and Columns and nothing else.

Is this possible without using 3rd party Tool?

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    DataGridView1.Rows.Add(New String() {"Value1", "Value2", "Value3"})


    Dim height As Integer = DataGridView1.Height
    DataGridView1.Height = DataGridView1.RowCount * DataGridView1.RowTemplate.Height

    Dim bitmap As Bitmap = New Bitmap(Me.DataGridView1.Width - 1, Me.DataGridView1.Height - 1)
    DataGridView1.DrawToBitmap(bitmap, New Rectangle(0, 0, Me.DataGridView1.Width - 1, Me.DataGridView1.Height - 1))

    'Save the Bitmap to folder.
    bitmap.Save("C:Development\DataGridView.Tiff")

End Sub

I dont want the Highlighted

enter image description here


Solution

  • There are a few things to consider:

    1. The DataGridView Rows and Columns must be visible when the control is drawn to a Bitmap,
    2. ScrollBars may be present,
    3. The height of the Rows may be different, so we have to sum the height of all rows,
    4. The same for the Columns, since each Column has it's own width,
    5. CellFormatting may be in place, so we need to refresh the DataGridView before drawing it: rows that are not visible may not have been formatted yet,
    6. There's a limit (32,767) in the Bitmap dimensions.

    Call this method as follows, specifying whether you want to include the Row or Column Headers or exclude both, passing True/False as the ColumnHeaders and RowHeaders arguments.
    The dgv argument is of course the DataGridView control instance that will be drawn:

    ' Prints the DataGridView including the Columns' Headers only
    Dim dgvBitmap = DataGridViewToBitmap(DataGridView1, True, False)
    Dim imagePath = Path.Combine(AppContext.BaseDirectory, $"{NameOf(DataGridView1)}.tiff")
    dgvBitmap.Save(imagePath, ImageFormat.Tiff)
    
    ' Dispose of the Bitmap or set it as the PictureBox.Image, dispose of it later.  
    dgvBitmap.Dispose()
    

    Private Function DataGridViewToBitmap(dgv As DataGridView, ColumnHeaders As Boolean, RowHeaders As Boolean) As Bitmap
        dgv.ClearSelection()
        Dim originalSize = dgv.Size
        dgv.Height = dgv.Rows.OfType(Of DataGridViewRow).Sum(Function(r) r.Height) + dgv.ColumnHeadersHeight
        dgv.Width = dgv.Columns.OfType(Of DataGridViewColumn).Sum(Function(c) c.Width) + dgv.RowHeadersWidth
        dgv.Refresh()
    
        Dim dgvPosition = New Point(If(RowHeaders, 0, dgv.RowHeadersWidth), If(ColumnHeaders, 0, dgv.ColumnHeadersHeight))
        Dim dgvSize = New Size(dgv.Width, dgv.Height)
        If dgvSize.Height > 32760 OrElse dgvSize.Width > 32760 Then Return Nothing
    
        Dim rect As Rectangle = New Rectangle(Point.Empty, dgvSize)
        Using bmp As Bitmap = New Bitmap(dgvSize.Width, dgvSize.Height)
            dgv.DrawToBitmap(bmp, rect)
            If (dgv.Width > originalSize.Width) AndAlso dgv.ScrollBars.HasFlag(ScrollBars.Vertical) Then
                dgvSize.Width -= SystemInformation.VerticalScrollBarWidth
            End If
            If (dgv.Height > originalSize.Height) AndAlso dgv.ScrollBars.HasFlag(ScrollBars.Horizontal) Then
                dgvSize.Height -= SystemInformation.HorizontalScrollBarHeight
            End If
            dgvSize = New Size(dgvSize.Width - dgvPosition.X, dgvSize.Height - dgvPosition.Y)
    
            dgv.Size = originalSize
            Return bmp.Clone(New Rectangle(dgvPosition, dgvSize), PixelFormat.Format32bppArgb)
        End Using
    End Function