pdf-e-signature
Version:
A React component that allows users to select positions for e-signatures on PDFs
157 lines (156 loc) • 5.36 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = require("react");
var _pdfLib = require("pdf-lib");
const usePDFOperations = () => {
const [pdfFile, setPdfFile] = (0, _react.useState)(null);
const [pdfUrl, setPdfUrl] = (0, _react.useState)(null);
const [numPages, setNumPages] = (0, _react.useState)(null);
const [currentPage, setCurrentPage] = (0, _react.useState)(1);
const [scale, setScale] = (0, _react.useState)(1.5);
const [signaturePositions, setSignaturePositions] = (0, _react.useState)([]);
const [isSelectingPosition, setIsSelectingPosition] = (0, _react.useState)(false);
const [viewMode, setViewMode] = (0, _react.useState)('upload');
const containerRef = (0, _react.useRef)(null);
const [cursorPosition, setCursorPosition] = (0, _react.useState)({
x: 0,
y: 0
});
const handleFileChange = e => {
const file = e.target.files[0];
if (file && file.type === 'application/pdf') {
setPdfFile(file);
const fileURL = URL.createObjectURL(file);
setPdfUrl(fileURL);
setSignaturePositions([]);
setViewMode('upload');
}
};
const handlePdfClick = e => {
if (!isSelectingPosition) return;
const container = containerRef.current;
const pdfElement = container.querySelector(".react-pdf__Page");
if (!pdfElement) return;
const pdfRect = pdfElement.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const scrollLeft = container.scrollLeft || 0;
const scrollTop = container.scrollTop || 0;
const normalizedX = (e.clientX + scrollLeft - pdfRect.left) / pdfRect.width;
const normalizedY = (e.clientY + scrollTop - pdfRect.top) / pdfRect.height;
const newSignaturePosition = {
normalizedX,
normalizedY,
page: currentPage,
scale: scale,
pdfWidth: pdfRect.width,
pdfHeight: pdfRect.height,
containerWidth: containerRect.width,
containerHeight: containerRect.height
};
setSignaturePositions([...signaturePositions, newSignaturePosition]);
};
const handleRemoveSign = index => {
const signature = signaturePositions.filter((_, i) => i !== index);
setSignaturePositions(signature);
};
const handleMouseMove = e => {
if (isSelectingPosition) {
const container = containerRef.current;
const pdfElement = container.querySelector(".react-pdf__Page");
if (!pdfElement) return;
const pdfRect = pdfElement.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const scrollLeft = container.scrollLeft || 0;
const scrollTop = container.scrollTop || 0;
setCursorPosition({
x: (e.clientX + scrollLeft - pdfRect.left) / pdfRect.width,
y: (e.clientY + scrollTop - pdfRect.top) / pdfRect.height
});
}
};
const generateSignedPdf = async document => {
try {
const response = await fetch(document.pdf);
const pdfBlob = await response.blob();
const arrayBuffer = await pdfBlob.arrayBuffer();
const pdfDoc = await _pdfLib.PDFDocument.load(arrayBuffer);
for (const position of document.signaturePositions) {
if (!position.signature) continue;
const page = pdfDoc.getPages()[position.page - 1];
const {
width: pdfWidth,
height: pdfHeight
} = page.getSize();
const signatureImage = await pdfDoc.embedPng(position.signature);
const signatureWidth = 150;
const signatureHeight = 50;
const xPos = position.normalizedX * pdfWidth - signatureWidth / 2;
const yPos = pdfHeight - position.normalizedY * pdfHeight - signatureHeight / 2;
page.drawImage(signatureImage, {
x: xPos,
y: Math.max(0, Math.min(yPos, pdfHeight - signatureHeight)),
width: signatureWidth,
height: signatureHeight
});
if (position.timestamp) {
page.drawText(position.timestamp, {
x: xPos,
y: Math.max(0, Math.min(yPos - 15, pdfHeight - signatureHeight)),
size: 8
});
}
}
const pdfBytes = await pdfDoc.save();
const blob = new Blob([pdfBytes], {
type: 'application/pdf'
});
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `signed_${document.documentId}.pdf`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
} catch (error) {
console.error('Error generating signed PDF:', error);
throw error;
}
};
const resetState = () => {
setPdfFile(null);
setPdfUrl(null);
setSignaturePositions([]);
setViewMode('upload');
};
return {
pdfFile,
pdfUrl,
numPages,
currentPage,
scale,
signaturePositions,
isSelectingPosition,
viewMode,
containerRef,
setNumPages,
setCurrentPage,
setScale,
setIsSelectingPosition,
setViewMode,
setPdfFile,
setPdfUrl,
setSignaturePositions,
handleFileChange,
handlePdfClick,
generateSignedPdf,
resetState,
handleMouseMove,
cursorPosition,
handleRemoveSign
};
};
var _default = exports.default = usePDFOperations;