How to export Flutter DataTable (SfDataGrid) to image?
The Syncfusion Flutter DataTable can be exported as image by wrapping the SfDataGrid inside the RepaintBoundary widget and then converting the render object of RepaintBoundary to image.
The following steps explains how to export the SfDataGrid as image.
STEP 1:
Import following library in flutter application
import 'package:flutter/rendering.dart'; import 'image_viewer.dart'; import 'dart:ui' as ui;
STEP 2:
Wrap SfDataGrid inside the RepaintBoundary. Initialize the SfDataGrid with all the required properties. Wrap RepaintBoundary widget inside SingleChildScrollView widgets for vertical and horizontal scrolling.
Here, you have to fill the SfDataGrid to fit it’s all rows and columns. So that, it will be exported to image with all rows and columns instead of visible rows and columns.
This view will be used to only export the datagrid to image.
List<Product>? _productData; final math.Random random = math.Random(); final _dataGridKey = GlobalKey(); late _CustomDataGridSource _customDataGridSource; static double rowHeight = 49.0; static double headerRowHeight = 56.0; static double columnWidth = 90; late List<GridColumn> _columns; bool changeToImage = false; @override void initState() { super.initState(); _productData = generateList(25); _columns = getColumns(); _customDataGridSource = _CustomDataGridSource(productData: _productData!); } Widget _buildImageView() { return Expanded( child: SingleChildScrollView( scrollDirection: Axis.vertical, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: RepaintBoundary( key: _dataGridKey, child: Container( height: (_productData!.length * rowHeight) + headerRowHeight, width: (_columns.length * columnWidth), child: SfDataGrid(source: _customDataGridSource, columns: _columns), ), ), ), ), ); }
STEP 3:
Create ImageViewPage as simple stateful widget having with SingleChildScrollView and Container. This ImageViewPage is used to show SfDataGrid Image by using imageData variable. This widget is used to view the exported image.
import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class ImageViewPage extends StatefulWidget { ImageViewPage( {required this.imageData, required this.byteData, required this.dataGridHeight, required this.dataGridWidth}); final Uint8List imageData; final ByteData byteData; final double dataGridHeight; final double dataGridWidth; @override _ImageViewPageState createState() => _ImageViewPageState(); } class _ImageViewPageState extends State<ImageViewPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Center( child: Text('DataGrid Image'), ), ), body: SingleChildScrollView( scrollDirection: Axis.vertical, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Container( height: widget.dataGridHeight, width: widget.dataGridWidth, child: Image.memory( widget.imageData, )), ), ), ); } }
STEP 4:
You can access the RenderObject via currentContext of global key which you created. Then You can obtain the image data by using toImage method. After getting image data, you need to convert it to bytecode and after that, you can convert the bytecode to Unit8List.
Future<void> captureImage() async { try { setState(() { changeToImage = true; WidgetsBinding.instance!.addPostFrameCallback((timeStamp) async { final dynamic boundary = _dataGridKey.currentContext!.findRenderObject(); final ui.Image image = await boundary.toImage(pixelRatio: 3.0); final ByteData byteData = (await image.toByteData(format: ui.ImageByteFormat.png))!; final pngBytes = byteData.buffer.asUint8List(); await Navigator.push( context, MaterialPageRoute( builder: ((context) => ImageViewPage( imageData: pngBytes, byteData: byteData, dataGridHeight: (_productData!.length * rowHeight) + headerRowHeight, dataGridWidth: (_columns.length * columnWidth), )))); }); }); } catch (e) { print(e); } }
STEP 5:
Call the captureImage method from the button’s onPressed callback.
@override Widget build(BuildContext context) { final List<Widget> children = []; final button = TextButton( child: Text('Convert to Image'), onPressed: captureImage, ); children.add(button); if (changeToImage) { children.add(_buildImageView()); } else { children.add(Expanded( child: SfDataGrid(source: _customDataGridSource, columns: _columns))); } return Scaffold( appBar: AppBar( title: Text('DataGrid Demo'), ), body: Column( children: children, ), ); }
You can download the example from GitHub.