I want to sign pdf electronically. so i used signature package to draw signature , used Draggable widget to position image on the pdf with Stack, and used syncfusion_flutter_pdf for drawing the image on Pdf. when drawing the image with the offset obtained from Draggable widget, its drawing at different position. i even tried to convert offset from local to global position but still not working.
i know the code is large but couldn't avoid any line. any help will be great
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf_editing/helper/constants.dart';
import 'package:signature/signature.dart';
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
class PdfViewer extends StatefulWidget {
PdfViewer({this.file});
File? file;
@override
State<PdfViewer> createState() => _PdfViewerState();
}
class _PdfViewerState extends State<PdfViewer> {
final controller = TextEditingController();
Offset? _offset;
bool isFixed = false;
File? imageFile = File('');
late File file;
final _signatureController = SignatureController();
Uint8List? _signatureBytes;
int currentPage = 0;
createFile() async {
var dir = await getApplicationDocumentsDirectory();
file = File('${dir.path}/doc.pdf');
file.writeAsBytes(widget.file!.readAsBytesSync());
setState(() {});
}
@override
void initState() {
createFile();
super.initState();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
actions: [
InkWell(
onTap: () {
setState(() {
isFixed = false;
});
showSignatureDialogue();
},
child: Icon(Icons.edit)),
sbw(20),
],
),
body: SingleChildScrollView(
child: Column(
children: [
PdfWidget(
file: file,
offset: _offset ?? Offset(37.5.w, 37.5.h),
signatureBytes: _signatureBytes,
isFixed: isFixed,
onDragEnd: (offset) {
_offset = offset;
setState(() {});
}),
],
),
),
),
);
}
showSignatureDialogue() {
showDialog(
context: context,
builder: (c) {
return Dialog(
insetPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 100),
child: Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Signature(
controller: _signatureController,
width: 300,
height: 300,
backgroundColor: Colors.yellow.withOpacity(0.2),
),
Row(
children: [
TextButton(
onPressed: () {
_signatureController.clear();
},
child: Text('clear'),
),
TextButton(
onPressed: () async {
final exportController = SignatureController(
penStrokeWidth: 2,
penColor: Colors.black,
exportBackgroundColor: Colors.white,
points: _signatureController.points,
);
_signatureBytes = await exportController.toPngBytes();
exportController.dispose();
setState(() {});
Navigator.pop(context);
},
child: Text('confirm'),
),
],
),
],
),
),
);
});
}
}
class PdfWidget extends StatefulWidget {
PdfWidget({
Key? key,
this.signatureBytes,
required this.file,
required this.offset,
required this.onDragEnd,
required this.isFixed,
}) : super(key: key);
final Uint8List? signatureBytes;
final File file;
final Offset offset;
final Function(Offset) onDragEnd;
bool isFixed = false;
@override
State<PdfWidget> createState() => _PdfWidgetState();
}
class _PdfWidgetState extends State<PdfWidget> {
int currentPage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
height: 70.h,
child: SfPdfViewer.file(
widget.file,
onPageChanged: (page) {
currentPage = page.newPageNumber;
setState(() {});
},
),
),
Visibility(
visible: widget.signatureBytes != null && !widget.isFixed,
child: Positioned(
top: widget.offset.dy,
left: widget.offset.dx,
child: Draggable(
childWhenDragging: Container(),
feedback: Material(
child: imageWidget(),
),
onDragEnd: (details) {
RenderBox renderBox = context.findRenderObject() as RenderBox;
var offset = renderBox.globalToLocal(details.offset);
widget.onDragEnd(offset);
setState(() {});
},
child: Column(
children: [
imageWidget(),
Visibility(
visible: !widget.isFixed,
child: InkWell(
onTap: () {
final PdfDocument document = PdfDocument(
inputBytes: widget.file.readAsBytesSync());
final PdfBitmap image =
PdfBitmap(widget.signatureBytes!);
RenderBox renderBox =
context.findRenderObject() as RenderBox;
var offset = renderBox.localToGlobal(
Offset(widget.offset.dx, widget.offset.dy));
document.pages[currentPage].graphics.drawImage(
image,
Rect.fromLTWH(offset.dx, offset.dy, 100, 50)
);
widget.file.writeAsBytes(document.save());
document.dispose();
widget.isFixed = true;
setState(() {});
},
child: Icon(Icons.done)),
)
],
),
),
),
),
],
);
}
Widget imageWidget() {
if (widget.signatureBytes != null) {
return Image.memory(
widget.signatureBytes!,
height: 50,
width: 100,
fit: BoxFit.contain,
);
} else
return Container();
}
}
you can use this code to converts the offset of a widget to the corresponding offset on a PDF page.