Here's working code I wrote to allow the user to select a part of the pdf and download the selected area as an image. Hope this helps anyone looking for this feature :) - be sure to set the document url. @phuocng Thank you for the awesome repo! I'd be happy to clean up my code and submit an official pull request for this feature over the next few days. Lmk what you think.
import React, { useState, useEffect, useRef } from 'react';
import { Button, Position, Tooltip, Viewer, RenderPageProps, Worker, PluginRenderPageLayer, Plugin, PluginFunctions } from '@react-pdf-viewer/core';
// Import the styles
import '@react-pdf-viewer/core/lib/styles/index.css';
import '@react-pdf-viewer/default-layout/lib/styles/index.css';
import { MessageIcon, RenderHighlightTargetProps, highlightPlugin, getImageFromArea } from '../../../../packages/highlight/src';
const Drag = ({ PluginRenderPageLayer, pageIndex, setCanvas, setDimensions }) => {
var isDragging = false
const dragStart = useRef({ x: 0, y: 0 });
const initialCanvasState = useRef(null); // New ref to store initial canvas state
const { canvasLayerRef, scale, width } = PluginRenderPageLayer;
const captureCanvasState = () => {
const canvas = canvasLayerRef.current;
const ctx = canvas.getContext('2d');
initialCanvasState.current = ctx.getImageData(0, 0, canvas.width, canvas.height);
};
const restoreCanvasState = () => {
const canvas = canvasLayerRef.current;
const ctx = canvas.getContext('2d');
ctx.putImageData(initialCanvasState.current, 0, 0);
};
const handleMouseMove = (e) => {
if (!isDragging || !canvasLayerRef.current) {
return;
}
restoreCanvasState(); // Restore the initial canvas state
const canvas = canvasLayerRef.current;
const ctx = canvas.getContext('2d');
const rect = canvas.getBoundingClientRect();
const scaleConst = canvas.width / width;
const currentX = (e.clientX - rect.left) * scaleConst;
const currentY = (e.clientY - rect.top) * scaleConst;
const rectWidth = currentX - dragStart.current.x;
const rectHeight = currentY - dragStart.current.y;
ctx.lineWidth = 4; // Set the line width to 2 pixels
ctx.setLineDash([6, 3]); // Set dashed line style
ctx.beginPath();
ctx.rect(dragStart.current.x, dragStart.current.y, rectWidth, rectHeight);
ctx.strokeStyle = '#1A84FF';
ctx.stroke();
};
const handleMouseDown = (e) => {
e.preventDefault();
if (isDragging || !canvasLayerRef.current) {
return;
}
const canvas = canvasLayerRef.current;
isDragging = true;
//document.body.style.cursor = 'crosshair'; // Change cursor to crosshair
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
// Restore the canvas to its initial state before drawing a new rectangle
restoreCanvasState();
const ctx = canvas.getContext('2d');
const rect = canvas.getBoundingClientRect();
const scaleConst = canvas.width/width
dragStart.current = {
x: (e.clientX - rect.left)*scaleConst,
y: (e.clientY - rect.top)*scaleConst,
};
isDragging = true;
const x = (e.clientX - rect.left)*scaleConst;
const y = (e.clientY - rect.top)*scaleConst;
console.log("Mouse down at:", x, y, "Canvas Width:", canvas.width, "Page Width:", canvas.width, "Scale:", scale);
}
const handleMouseUp = (e) => {
e.preventDefault();
if (!PluginRenderPageLayer.canvasLayerRef.current) {
return;
}
window.removeEventListener('mouseup', handleMouseUp);
console.log("mouseup")
const canvas = canvasLayerRef.current;
const ctx = canvas.getContext('2d');
const rect = canvas.getBoundingClientRect();
const scaleConst = canvas.width/width
const x = (e.clientX - rect.left)*scaleConst;
const y = (e.clientY - rect.top)*scaleConst;
if (PluginRenderPageLayer.canvasLayerRef.current) {
const canvas = PluginRenderPageLayer.canvasLayerRef.current;
setCanvas(canvas);
setDimensions({
x: dragStart.current.x,
y: dragStart.current.y,
width: x - dragStart.current.x,
height: y - dragStart.current.y,
});
}
isDragging = (false);
};
useEffect(() => {
const textLayerEle = PluginRenderPageLayer.textLayerRef.current;
if (!PluginRenderPageLayer.canvasLayerRendered || !PluginRenderPageLayer.textLayerRendered || !textLayerEle) {
return;
}
// Capture the initial state of the canvas
captureCanvasState();
textLayerEle.addEventListener('mousedown', handleMouseDown);
return () => {
textLayerEle.removeEventListener('mousedown', handleMouseDown);
};
}, [PluginRenderPageLayer.canvasLayerRendered, PluginRenderPageLayer.textLayerRendered]);
return <></>;
// Define your custom plugin
const createCustomPlugin = (setCanvas, setDimensions) => {
const customPlugin: Plugin = {
// Install is called when the plugin is added to the Viewer
install: (pluginFunctions: PluginFunctions) => {
// You can use pluginFunctions to interact with the viewer
},
// Called when the document is successfully loaded
onDocumentLoad: (props) => {
console.log('Document is loaded', props);
},
// Add other necessary plugin methods and properties here
renderPageLayer: (props: PluginRenderPageLayer) => {
// Your custom page layer rendering
console.log("RenderPageLayer props:", props);
Here's working code I wrote to allow the user to select a part of the pdf and download the selected area as an image. Hope this helps anyone looking for this feature :) - be sure to set the document url. @phuocng Thank you for the awesome repo! I'd be happy to clean up my code and submit an official pull request for this feature over the next few days. Lmk what you think.
import React, { useState, useEffect, useRef } from 'react'; import { Button, Position, Tooltip, Viewer, RenderPageProps, Worker, PluginRenderPageLayer, Plugin, PluginFunctions } from '@react-pdf-viewer/core'; // Import the styles import '@react-pdf-viewer/core/lib/styles/index.css'; import '@react-pdf-viewer/default-layout/lib/styles/index.css'; import { MessageIcon, RenderHighlightTargetProps, highlightPlugin, getImageFromArea } from '../../../../packages/highlight/src';
const Drag = ({ PluginRenderPageLayer, pageIndex, setCanvas, setDimensions }) => { var isDragging = false const dragStart = useRef({ x: 0, y: 0 }); const initialCanvasState = useRef(null); // New ref to store initial canvas state const { canvasLayerRef, scale, width } = PluginRenderPageLayer;
};
const WaterMarkExample: React.FC = () => { const [documentURL, setDocumentURL] = useState("");
// Define your custom plugin const createCustomPlugin = (setCanvas, setDimensions) => { const customPlugin: Plugin = { // Install is called when the plugin is added to the Viewer install: (pluginFunctions: PluginFunctions) => { // You can use pluginFunctions to interact with the viewer }, // Called when the document is successfully loaded onDocumentLoad: (props) => { console.log('Document is loaded', props); }, // Add other necessary plugin methods and properties here renderPageLayer: (props: PluginRenderPageLayer) => { // Your custom page layer rendering console.log("RenderPageLayer props:", props);
};
};
export default WaterMarkExample;