Merge branch 'cleanups' of https://github.com/Frooodle/Stirling-PDF into cleanups

This commit is contained in:
Saud Fatayerji 2023-05-08 04:24:42 +03:00
commit 12d457e3ee
9 changed files with 206 additions and 25 deletions

View file

@ -1,8 +1,10 @@
package stirling.software.SPDF.controller.web;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import io.swagger.v3.oas.annotations.Hidden;
@ -67,14 +69,26 @@ public class GeneralWebController {
return "split-pdfs";
}
@GetMapping("/sign")
@Hidden
public String signForm(Model model) {
model.addAttribute("currentPage", "sign");
return "sign";
}
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String getRobotsTxt() {
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISABILITY");
if (allowGoogleVisibility == null)
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISABILITY");
if (allowGoogleVisibility == null)
allowGoogleVisibility = "true";
if (Boolean.parseBoolean(allowGoogleVisibility)) {
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nDisallow: /";
} else {
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
}
}
}

View file

@ -53,6 +53,12 @@ public class OtherWebController {
return "other/change-metadata";
}
@GetMapping("/compare")
@Hidden
public String compareForm(Model model) {
model.addAttribute("currentPage", "compare");
return "other/compare";
}
public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/4.00/tessdata";

View file

@ -117,8 +117,25 @@ home.flatten.desc=Remove all interactive elements and forms from a PDF
home.repair.title=Repair
home.repair.desc=Tries to repair a corrupt/broken PDF
downloadPdf=Download PDF
text=Text
font=Font
sign.title=Sign
sign.header=Sign PDFs
sign.upload=Upload Image
sign.draw=Draw Signature
sign.text=Text Input
sign.clear=Clear
sign.add=Add
repair.title=Repair
repair.header=Repair PDFs
repair.submit=Repair
flatten.title=Flatten
flatten.header=Flatten PDFs
flatten.submit=Flatten
ScannerImageSplit.selectText.1=Angle Threshold:
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,135 @@
<!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=#{repair.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="#{repair.header}"></h2>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf')}"></div>
<button onclick="comparePDFs()">Compare</button>
<div id="result"></div>
<script>
async function comparePDFs() {
const file1 = document.getElementById("fileInput-input").files[0];
const file2 = document.getElementById("fileInput2-input").files[0];
if (!file1 || !file2) {
console.error("Please select two PDF files to compare");
return;
}
const [pdf1, pdf2] = await Promise.all([
pdfjsLib.getDocument(URL.createObjectURL(file1)).promise,
pdfjsLib.getDocument(URL.createObjectURL(file2)).promise
]);
const extractText = async (pdf) => {
const pages = [];
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const content = await page.getTextContent();
const strings = content.items.map(item => item.str);
pages.push(strings.join(""));
}
return pages.join("\n");
};
const [text1, text2] = await Promise.all([
extractText(pdf1),
extractText(pdf2)
]);
const diff = (text1, text2) => {
const lines1 = text1.split("\n");
const lines2 = text2.split("\n");
const result = [];
let i = 0, j = 0;
while (i < lines1.length || j < lines2.length) {
console.log(`lines1[${i}]='${lines1[i]}', lines2[${j}]='${lines2[j]}'`);
console.log(`i=${i}, j=${j}`);
if (lines1[i] === lines2[j]) {
result.push([i, j, lines1[i]]);
i++;
j++;
console.log(`i=${i}, j=${j}`);
} else {
let k = i, l = j;
while (k < lines1.length && l < lines2.length && lines1[k] !== lines2[l]) {
k++;
l++;
}
for (let x = i; x < k; x++) {
result.push([x, -1, lines1[x]]);
}
for (let y = j; y < l; y++) {
result.push([-1, y, lines2[y]]);
}
i = k;
j = l;
}
}
return result;
};
const differences = diff(text1, text2);
const highlightDifferences = async (pdf, differences) => {
for (const difference of differences) {
const [pageIndex, lineIndex, lineText] = difference;
if (lineIndex === -1) {
continue;
}
console.log(pageIndex);
const page = await pdf.getPage(pageIndex);
const viewport = page.getViewport({ scale: 1 });
const [left,top] = viewport.convertToViewportPoint(0, lineIndex * 20);
const [right, bottom] = viewport.convertToViewportPoint(500, (lineIndex + 1) * 20);
const annotation = {
type: "Highlight",
rect: [left, top, right - left, bottom - top],
color: [255, 255, 0],
opacity: 0.5,
quadPoints:
[
left, top, right, top, right, bottom, left, bottom
]
};
await page.addAnnotation(annotation);
const message = `Difference found in page ${pageIndex }, line ${lineIndex + 1}: ${lineText}`;
const p = document.createElement("p");
p.textContent = message;
document.getElementById("result").appendChild(p);
}
};
await highlightDifferences(pdf1, differences);
}
</script>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body>
</html>

View file

@ -3,20 +3,21 @@
<head>
<th:block th:insert="~{fragments/common :: head(title=#{sign.title})}"></th:block>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDF Signature App</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
<script src="https://unpkg.com/pdf-lib@1.18.0/dist/umd/pdf-lib.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.10.11/interact.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Estonia&family=Tangerine&family=Windsong&display=swap" rel="stylesheet">
</head>
<script src="js/signature_pad.umd.min.js"></script>
<script src="js/interact.min.js"></script>
</head>
<style>
@font-face {
font-family: 'Estonia';
src: url(fonts/Estonia.woff2) format('woff2');
}
@font-face {
font-family: 'Tangerine';
src: url(fonts/Tangerine.woff2) format('woff2');
}
</style>
<body>
<th:block th:insert="~{fragments/common.html :: game}"></th:block>
<div id="page-container">
<div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
@ -49,7 +50,7 @@
</script>
<div class="tab-group show-on-file-selected">
<div class="tab-container" title="Upload Image">
<div class="tab-container" th:title="#{sign.upload}">
<div th:replace="~{fragments/common :: fileSelector(name='image-upload', multiple=true, accept='image/*', inputText=#{imgPrompt})}"></div>
<script>
const imageUpload = document.querySelector('input[name=image-upload]');
@ -67,11 +68,11 @@
});
</script>
</div>
<div class="tab-container drawing-pad-container" title="Draw Signature">
<div class="tab-container drawing-pad-container" th:title="#{sign.draw}">
<canvas id="drawing-pad-canvas"></canvas>
<br>
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()">Clear</button>
<button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()">Add</button>
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()" th:text="#{sign.clear}"></button>
<button id="save-signature" class="btn btn-outline-success mt-2" onclick="addDraggableFromPad()" th:text="#{sign.add}"></button>
<script>
const signaturePadCanvas = document.getElementById('drawing-pad-canvas');
const signaturePad = new SignaturePad(signaturePadCanvas, {
@ -160,17 +161,16 @@
}
</style>
</div>
<div class="tab-container" title="Text Input">
<label class="form-check-label" for="sigText">Text</label>
<div class="tab-container" th:title="#{sign.text}">
<label class="form-check-label" for="sigText" th:text="#{text}"></label>
<input type="text" class="form-control" id="sigText" name="sigText">
<label>Font:</label>
<label th:text="#{font}"></label>
<select class="form-control" name="font" id="font-select">
<option value="Estonia" class="estonia-font">Estonia</option>
<option value="Tangerine" class="tangerine-font">Tangerine</option>
<option value="Windsong" class="windsong-font">Windsong</option>
</select>
<div class="margin-auto-parent">
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center" onclick="addDraggableFromText()">Add</button>
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center" onclick="addDraggableFromText()" th:text="#{sign.add}"></button>
</div>
<script>
function addDraggableFromText() {
@ -213,7 +213,7 @@
<!-- draggables box -->
<div id="box-drag-container" class="show-on-file-selected">
<canvas id="pdf-canvas"></canvas>
<script src="/js/draggable-utils.js"></script>
<script src="js/draggable-utils.js"></script>
<div class="draggable-buttons-box ignore-rtl">
<button class="btn btn-outline-secondary" onclick="DraggableUtils.deleteDraggableCanvas(DraggableUtils.getLastInteracted())">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">