mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-11-01 01:21:18 +01:00 
			
		
		
		
	Merge pull request #34 from Sf298/addGraphicsToRotatePage
Add graphics to rotate page
This commit is contained in:
		
						commit
						4c88c1bc54
					
				@ -37,7 +37,7 @@ public class RotationController {
 | 
			
		||||
 | 
			
		||||
	@PostMapping("/rotate-pdf")
 | 
			
		||||
	public ResponseEntity<byte[]> rotatePDF(@RequestParam("fileInput") MultipartFile pdfFile,
 | 
			
		||||
			@RequestParam("angle") String angle) throws IOException {
 | 
			
		||||
			@RequestParam("angle") Integer angle) throws IOException {
 | 
			
		||||
 | 
			
		||||
		// Load the PDF document
 | 
			
		||||
		PDDocument document = PDDocument.load(pdfFile.getBytes());
 | 
			
		||||
@ -50,7 +50,7 @@ public class RotationController {
 | 
			
		||||
 | 
			
		||||
		while (iterPage.hasNext()) {
 | 
			
		||||
			PDPage page = iterPage.next();
 | 
			
		||||
			page.setRotation(Integer.valueOf(angle));
 | 
			
		||||
			page.setRotation(page.getRotation() + angle);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_rotated.pdf");
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,9 @@
 | 
			
		||||
<meta charset="UTF-8">
 | 
			
		||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
 | 
			
		||||
<script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.3.122/build/pdf.min.js"></script>
 | 
			
		||||
<link href="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.3.122/web/pdf_viewer.min.css" rel="stylesheet">
 | 
			
		||||
 | 
			
		||||
<link rel="stylesheet" th:href="@{dark-mode.css}" id="dark-mode-styles">
 | 
			
		||||
<script>
 | 
			
		||||
	function toggleDarkMode() {
 | 
			
		||||
@ -94,3 +97,24 @@
 | 
			
		||||
		}
 | 
			
		||||
	</script>
 | 
			
		||||
</th:block>
 | 
			
		||||
 | 
			
		||||
<th:block th:fragment="fileSelector(name, multiple)">
 | 
			
		||||
	<div class="custom-file-chooser">
 | 
			
		||||
		<div class="custom-file">
 | 
			
		||||
			<input type="file" class="custom-file-input" th:name="${name}" th:id="${name}+'-input'" th:multiple="${multiple}">
 | 
			
		||||
			<label class="custom-file-label" th:for="${name}+'-input'" th:text="#{pdfPrompt}"></label>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<script th:inline="javascript">
 | 
			
		||||
		$([[${"#"+name+"-input"}]]).on("change", function() {
 | 
			
		||||
			const files = $(this).get(0).files;
 | 
			
		||||
			const fileNames = Array.from(files).map(f => f.name).join(", ");
 | 
			
		||||
			if (fileNames) {
 | 
			
		||||
				$(this).siblings(".custom-file-label").addClass("selected").html(fileNames);
 | 
			
		||||
			} else {
 | 
			
		||||
				$(this).siblings(".custom-file-label").addClass("selected").html([[#{pdfPrompt}]]);
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	</script>
 | 
			
		||||
</th:block>
 | 
			
		||||
@ -15,27 +15,32 @@
 | 
			
		||||
			<div class="col-md-6">
 | 
			
		||||
				<h2 th:text="#{rotate.header}"></h2>
 | 
			
		||||
 | 
			
		||||
				<form action="#" th:action="@{rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
 | 
			
		||||
					<div th:replace="fragments/common :: fileSelector(name='fileInput', multiple=false)"></div>
 | 
			
		||||
					<input type="hidden" id="angleInput" name="angle" value="0">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				<form action="#" th:action="@{rotate-pdf}" th:object="${rotateForm}"
 | 
			
		||||
					method="post" enctype="multipart/form-data">
 | 
			
		||||
					<div class="custom-file">
 | 
			
		||||
						<input type="file" class="custom-file-input" id="fileInput"
 | 
			
		||||
							name="fileInput" required> <label
 | 
			
		||||
							class="custom-file-label" for="fileInput" th:text="#{pdfPrompt}"></label>
 | 
			
		||||
					<div id="editSection" style="display: none">
 | 
			
		||||
						<div class="previewContainer">
 | 
			
		||||
							<img id="pdf-preview"/>
 | 
			
		||||
						</div>
 | 
			
		||||
 | 
			
		||||
					<label for="angle" th:text="#{rotate.selectAngle}"></label> <select id="angle" class="form-control" name="angle">
 | 
			
		||||
						<option value="90">90</option>
 | 
			
		||||
						<option value="180">180</option>
 | 
			
		||||
						<option value="270">270</option>
 | 
			
		||||
						<option value="-90">-90</option>
 | 
			
		||||
						<option value="-180">-180</option>
 | 
			
		||||
						<option value="-270">-270</option>
 | 
			
		||||
					</select> <br>
 | 
			
		||||
						<div class="buttonContainer">
 | 
			
		||||
							<button type="button" class="btn btn-secondary" onclick="rotate(-90)">
 | 
			
		||||
								<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
 | 
			
		||||
									<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
 | 
			
		||||
									<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
 | 
			
		||||
								</svg>
 | 
			
		||||
							</button>
 | 
			
		||||
							<button type="submit" class="btn btn-primary" th:text="#{rotate.submit}"></button>
 | 
			
		||||
							<button type="button" class="btn btn-secondary" onclick="rotate(90)">
 | 
			
		||||
								<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
 | 
			
		||||
									<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
 | 
			
		||||
									<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
 | 
			
		||||
								</svg>
 | 
			
		||||
							</button>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</form>
 | 
			
		||||
				<th:block th:insert="~{fragments/common :: filelist}"></th:block>
 | 
			
		||||
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
@ -43,6 +48,84 @@
 | 
			
		||||
	</div>
 | 
			
		||||
		<div th:insert="~{fragments/footer.html :: footer}"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<script>
 | 
			
		||||
		const angleInput = document.getElementById("angleInput");
 | 
			
		||||
		const fileInput = document.getElementById("fileInput-input");
 | 
			
		||||
		const preview = document.getElementById("pdf-preview");
 | 
			
		||||
		fileInput.addEventListener("change", async function() {
 | 
			
		||||
			console.log("loading pdf");
 | 
			
		||||
 | 
			
		||||
			document.querySelector("#editSection").style.display = "";
 | 
			
		||||
 | 
			
		||||
			var url = URL.createObjectURL(fileInput.files[0])
 | 
			
		||||
 | 
			
		||||
			const pdf = await pdfjsLib.getDocument(url).promise;
 | 
			
		||||
			const page = await pdf.getPage(1);
 | 
			
		||||
 | 
			
		||||
			const canvas = document.createElement("canvas");
 | 
			
		||||
 | 
			
		||||
			// set the canvas size to the size of the page
 | 
			
		||||
			if (page.rotate == 90 || page.rotate == 270) {
 | 
			
		||||
				canvas.width = page.view[3];
 | 
			
		||||
				canvas.height = page.view[2];
 | 
			
		||||
			} else {
 | 
			
		||||
				canvas.width = page.view[2];
 | 
			
		||||
				canvas.height = page.view[3];
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// render the page onto the canvas
 | 
			
		||||
			var renderContext = {
 | 
			
		||||
			   	canvasContext: canvas.getContext("2d"),
 | 
			
		||||
			  	viewport: page.getViewport({ scale: 1 })
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			await page.render(renderContext).promise;
 | 
			
		||||
			preview.src = canvas.toDataURL();
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		function rotate(deg) {
 | 
			
		||||
			var lastTransform = preview.style.rotate;
 | 
			
		||||
			if (!lastTransform) {
 | 
			
		||||
				lastTransform = "0";
 | 
			
		||||
			}
 | 
			
		||||
			const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ''));
 | 
			
		||||
			const newAngle = lastAngle + deg;
 | 
			
		||||
 | 
			
		||||
			preview.style.rotate = newAngle + "deg";
 | 
			
		||||
			angleInput.value = newAngle;
 | 
			
		||||
		}
 | 
			
		||||
	</script>
 | 
			
		||||
	<style>
 | 
			
		||||
		#pdf-preview {
 | 
			
		||||
			margin: 0 auto;
 | 
			
		||||
			display: block;
 | 
			
		||||
			max-width: calc(100% - 30px);
 | 
			
		||||
			max-height: calc(100% - 30px);
 | 
			
		||||
    		box-shadow: 0 0 4px rgba(100,100,100,.25);
 | 
			
		||||
    		transition: rotate .3s;
 | 
			
		||||
    		position: absolute;
 | 
			
		||||
    		top: 50%;
 | 
			
		||||
    		left: 50%;
 | 
			
		||||
    		translate: -50% -50%;
 | 
			
		||||
		}
 | 
			
		||||
		.previewContainer {
 | 
			
		||||
			aspect-ratio: 1;
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			border: 1px solid rgba(0,0,0,.125);
 | 
			
		||||
			border-radius: 0.25rem;
 | 
			
		||||
			margin: 1rem 0;
 | 
			
		||||
			padding: 15px;
 | 
			
		||||
			display: block;
 | 
			
		||||
			overflow: hidden;
 | 
			
		||||
			position: relative;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.buttonContainer {
 | 
			
		||||
			display: flex;
 | 
			
		||||
			justify-content: space-around;
 | 
			
		||||
		}
 | 
			
		||||
	</style>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user