2023-07-16 19:57:21 +02:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
|
|
|
|
|
|
|
<th:block th:insert="~{fragments/common :: head(title=#{crop.title})}"></th:block>
|
|
|
|
|
|
|
|
|
|
|
|
<body>
|
|
|
|
<div id="page-container">
|
|
|
|
<div id="content-wrap">
|
|
|
|
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
|
|
|
<br> <br>
|
|
|
|
<div class="container">
|
|
|
|
<div class="row justify-content-center">
|
|
|
|
<div class="col-md-6">
|
|
|
|
<h2 th:text="#{crop.header}"></h2>
|
|
|
|
<form id="cropForm" action="/crop" method="post" enctype="multipart/form-data">
|
|
|
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
|
|
|
<input id="x" type="hidden" name="x">
|
|
|
|
<input id="y" type="hidden" name="y">
|
|
|
|
<input id="width" type="hidden" name="width">
|
|
|
|
<input id="height" type="hidden" name="height">
|
|
|
|
<button type="submit" class="btn btn-primary" th:text="#{crop.submit}"></button>
|
|
|
|
</form>
|
2023-07-19 23:11:59 +02:00
|
|
|
<div style="position: relative; display: inline-block;">
|
2023-07-22 14:17:24 +02:00
|
|
|
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
2023-07-19 23:11:59 +02:00
|
|
|
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
|
|
|
</div>
|
|
|
|
|
2023-07-16 19:57:21 +02:00
|
|
|
<script>
|
|
|
|
|
2023-07-22 14:17:24 +02:00
|
|
|
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
2023-07-19 23:11:59 +02:00
|
|
|
let overlayCanvas = document.getElementById('overlayCanvas');
|
2023-07-16 19:57:21 +02:00
|
|
|
|
2023-07-19 23:11:59 +02:00
|
|
|
let context = pdfCanvas.getContext('2d');
|
|
|
|
let overlayContext = overlayCanvas.getContext('2d');
|
|
|
|
|
|
|
|
overlayCanvas.width = pdfCanvas.width;
|
|
|
|
overlayCanvas.height = pdfCanvas.height;
|
|
|
|
|
|
|
|
let isDrawing = false; // New flag to check if drawing is ongoing
|
|
|
|
|
2023-07-16 19:57:21 +02:00
|
|
|
let cropForm = document.getElementById('cropForm');
|
|
|
|
let fileInput = document.getElementById('fileInput-input');
|
|
|
|
let xInput = document.getElementById('x');
|
|
|
|
let yInput = document.getElementById('y');
|
|
|
|
let widthInput = document.getElementById('width');
|
|
|
|
let heightInput = document.getElementById('height');
|
|
|
|
|
|
|
|
let pdfDoc = null;
|
|
|
|
let currentPage = 1;
|
|
|
|
let totalPages = 0;
|
|
|
|
|
|
|
|
let startX = 0;
|
|
|
|
let startY = 0;
|
|
|
|
let rectWidth = 0;
|
|
|
|
let rectHeight = 0;
|
|
|
|
|
|
|
|
fileInput.addEventListener('change', function(e) {
|
|
|
|
let file = e.target.files[0];
|
|
|
|
if (file.type === 'application/pdf') {
|
|
|
|
let reader = new FileReader();
|
|
|
|
reader.onload = function(ev) {
|
|
|
|
let typedArray = new Uint8Array(reader.result);
|
2023-07-22 14:17:24 +02:00
|
|
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
2023-07-16 19:57:21 +02:00
|
|
|
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
|
|
|
|
pdfDoc = pdf;
|
|
|
|
totalPages = pdf.numPages;
|
|
|
|
renderPage(currentPage);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
reader.readAsArrayBuffer(file);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-19 23:11:59 +02:00
|
|
|
overlayCanvas.addEventListener('mousedown', function(e) {
|
|
|
|
// Clear previously drawn rectangle on the main canvas
|
|
|
|
context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height);
|
|
|
|
renderPage(currentPage); // Re-render the PDF
|
|
|
|
|
|
|
|
// Clear the overlay canvas to ensure old drawings are removed
|
|
|
|
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
|
|
|
|
|
|
|
startX = e.offsetX;
|
|
|
|
startY = e.offsetY;
|
|
|
|
isDrawing = true;
|
2023-07-16 19:57:21 +02:00
|
|
|
});
|
|
|
|
|
2023-07-19 23:11:59 +02:00
|
|
|
overlayCanvas.addEventListener('mousemove', function(e) {
|
|
|
|
if (!isDrawing) return;
|
|
|
|
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear previous rectangle
|
|
|
|
|
|
|
|
rectWidth = e.offsetX - startX;
|
|
|
|
rectHeight = e.offsetY - startY;
|
|
|
|
overlayContext.strokeStyle = 'red';
|
|
|
|
overlayContext.strokeRect(startX, startY, rectWidth, rectHeight);
|
|
|
|
});
|
2023-07-16 19:57:21 +02:00
|
|
|
|
2023-07-19 23:11:59 +02:00
|
|
|
overlayCanvas.addEventListener('mouseup', function(e) {
|
|
|
|
isDrawing = false;
|
|
|
|
|
|
|
|
rectWidth = e.offsetX - startX;
|
|
|
|
rectHeight = e.offsetY - startY;
|
2023-07-16 19:57:21 +02:00
|
|
|
|
2023-07-19 23:11:59 +02:00
|
|
|
let flippedY = pdfCanvas.height - e.offsetY;
|
2023-07-16 19:57:21 +02:00
|
|
|
|
2023-07-19 23:11:59 +02:00
|
|
|
xInput.value = startX;
|
|
|
|
yInput.value = flippedY;
|
|
|
|
widthInput.value = rectWidth;
|
|
|
|
heightInput.value = rectHeight;
|
|
|
|
|
|
|
|
// Draw the final rectangle on the main canvas
|
|
|
|
context.strokeStyle = 'red';
|
|
|
|
context.strokeRect(startX, startY, rectWidth, rectHeight);
|
|
|
|
|
|
|
|
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); // Clear the overlay
|
|
|
|
});
|
2023-07-16 19:57:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
function renderPage(pageNumber) {
|
2023-07-19 23:11:59 +02:00
|
|
|
pdfDoc.getPage(pageNumber).then(function(page) {
|
|
|
|
let viewport = page.getViewport({ scale: 1.0 });
|
|
|
|
pdfCanvas.width = viewport.width;
|
|
|
|
pdfCanvas.height = viewport.height;
|
|
|
|
|
|
|
|
overlayCanvas.width = viewport.width; // Match overlay canvas size with PDF canvas
|
|
|
|
overlayCanvas.height = viewport.height;
|
|
|
|
|
|
|
|
let renderContext = { canvasContext: context, viewport: viewport };
|
|
|
|
page.render(renderContext);
|
2023-07-22 14:17:24 +02:00
|
|
|
pdfCanvas.classList.add("shadow-canvas");
|
2023-07-19 23:11:59 +02:00
|
|
|
});
|
2023-07-16 19:57:21 +02:00
|
|
|
}
|
2023-07-19 23:11:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-07-16 19:57:21 +02:00
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
|
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|