1
0
mirror of https://github.com/Stirling-Tools/Stirling-PDF.git synced 2024-06-03 06:10:11 +02:00

feat: add remove annotations

This commit is contained in:
sbplat 2023-12-23 13:47:21 -05:00
parent 24568f4a42
commit b7d6107a2d
7 changed files with 91 additions and 2 deletions

View File

@ -124,6 +124,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Other", "flatten");
addEndpointToGroup("Other", "repair");
addEndpointToGroup("Other", "remove-blanks");
addEndpointToGroup("Other", "remove-annotations");
addEndpointToGroup("Other", "compare");
addEndpointToGroup("Other", "add-page-numbers");
addEndpointToGroup("Other", "auto-rename");

View File

@ -126,7 +126,13 @@ public class OtherWebController {
model.addAttribute("currentPage", "remove-blanks");
return "misc/remove-blanks";
}
@GetMapping("/remove-annotations")
@Hidden
public String removeAnnotationsForm(Model model) {
model.addAttribute("currentPage", "remove-annotations");
return "misc/remove-annotations";
}
@GetMapping("/auto-crop")
@Hidden

View File

@ -255,6 +255,10 @@ home.removeBlanks.title=Remove Blank pages
home.removeBlanks.desc=Detects and removes blank pages from a document
removeBlanks.tags=cleanup,streamline,non-content,organize
home.removeAnnotations.title=Remove Annotations
home.removeAnnotations.desc=Removes all comments/annotations from a PDF
removeAnnotations.tags=comments,highlight,notes,markup,remove
home.compare.title=Compare
home.compare.desc=Compares and shows the differences between 2 PDF Documents
compare.tags=differentiate,contrast,changes,analysis
@ -539,6 +543,12 @@ removeBlanks.whitePercentDesc=Percent of page that must be 'white' pixels to be
removeBlanks.submit=Remove Blanks
#removeAnnotations
removeAnnotations.title=Remove Annotations
removeAnnotations.header=Remove Annotations
removeAnnotations.submit=Remove
#compare
compare.title=Compare
compare.header=Compare PDFs

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="16" height="16" fill="currentColor" class="bi bi-chat-left-text" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H4.414A2 2 0 0 0 3 11.586l-2 2V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12.793a.5.5 0 0 0 .854.353l2.853-2.853A1 1 0 0 1 4.414 12H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z" style="fill: rgb(0, 0, 0);"/>
<path d="M3 3.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3 6a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 6m0 2.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5" style="fill: rgb(0, 0, 0);"/>
<path d="M 0.125 0.178 C 0.312 -0.024 0.636 -0.043 0.831 0.152 L 15.771 15.1 C 16.242 15.571 15.561 16.304 15.09 15.832 L 0.151 0.885 C -0.045 0.69 -0.063 0.381 0.125 0.178 Z" id="path937" style="fill: rgb(0, 0, 0);"/>
</svg>

After

Width:  |  Height:  |  Size: 853 B

View File

@ -107,7 +107,7 @@
</li>
<li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='sign' OR ${currentPage}=='repair' OR ${currentPage}=='compare' OR ${currentPage}=='show-javascript' OR ${currentPage}=='flatten' OR ${currentPage}=='remove-blanks' OR ${currentPage}=='extract-image-scans' OR ${currentPage}=='change-metadata' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='change-permissions' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' OR ${currentPage}=='add-page-numbers' OR ${currentPage}=='auto-rename' OR ${currentPage}=='get-info-on-pdf' ? 'active' : ''">
<li class="nav-item dropdown" th:classappend="${currentPage}=='sign' OR ${currentPage}=='repair' OR ${currentPage}=='compare' OR ${currentPage}=='show-javascript' OR ${currentPage}=='flatten' OR ${currentPage}=='remove-blanks' OR ${currentPage}=='remove-annotations' OR ${currentPage}=='extract-image-scans' OR ${currentPage}=='change-metadata' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='change-permissions' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' OR ${currentPage}=='add-page-numbers' OR ${currentPage}=='auto-rename' OR ${currentPage}=='get-info-on-pdf' ? 'active' : ''">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/card-list.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;">
<span class="icon-text" th:text="#{navbar.other}"></span>
@ -125,6 +125,7 @@
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('flatten', 'images/flatten.svg', 'home.flatten.title', 'home.flatten.desc', 'flatten.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('repair', 'images/wrench.svg', 'home.repair.title', 'home.repair.desc', 'repair.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-blanks', 'images/blank-file.svg', 'home.removeBlanks.title', 'home.removeBlanks.desc', 'removeBlanks.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-annotations', 'images/no-chat.svg', 'home.removeAnnotations.title', 'home.removeAnnotations.desc', 'removeAnnotations.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('compare', 'images/scales.svg', 'home.compare.title', 'home.compare.desc', 'compare.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-page-numbers', 'images/add-page-numbers.svg', 'home.add-page-numbers.title', 'home.add-page-numbers.desc', 'add-page-numbers.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-rename', 'images/fonts.svg', 'home.auto-rename.title', 'home.auto-rename.desc', 'auto-rename.tags')}"></div>

View File

@ -73,6 +73,7 @@
<div th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', svgPath='images/wrench.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', svgPath='images/blank-file.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', svgPath='images/no-chat.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', svgPath='images/scales.svg')}"></div>
<div th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', svgPath='images/award.svg')}"></div>

View File

@ -0,0 +1,64 @@
<!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=#{removeAnnotations.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="#{removeAnnotations.header}"></h2>
<form id="pdfForm" class="mb-3">
<div class="custom-file">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeAnnotations.submit}"></button>
</form>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
<script src="js/local-pdf-input-download.js"></script>
<script>
document.getElementById('pdfForm').addEventListener('submit', async (e) => {
e.preventDefault();
const { PDFDocument } = PDFLib;
const processFile = async (file) => {
const origFileUrl = URL.createObjectURL(file);
const formPdfBytes = await fetch(origFileUrl).then(res => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(formPdfBytes, { ignoreEncryption: true });
const pages = pdfDoc.getPages();
for (let i = 0; i < pages.length; ++i) {
const page = pages[i];
const annotations = page.node.Annots();
if (!annotations) continue;
const ctx = annotations.context;
for (let j = 0; j < annotations.size(); ++j) {
const annotation = annotations.get(j);
ctx.delete(annotation);
}
}
const pdfBytes = await pdfDoc.save();
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' });
const fileName = (file.name ? file.name.replace('.pdf', '') : 'pdf') + '_removed_annotations.pdf';
return { processedData: pdfBlob, fileName };
};
await downloadFilesWithCallback(processFile);
});
</script>
</body>
</html>