mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-03 17:52:30 +02:00
init metadata
This commit is contained in:
parent
4a95e001bb
commit
8a1c0130fc
@ -0,0 +1,62 @@
|
|||||||
|
package stirling.software.SPDF.controller.security;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||||
|
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||||
|
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||||
|
import org.apache.pdfbox.util.Matrix;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.utils.PdfUtils;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class MetadataController {
|
||||||
|
|
||||||
|
@GetMapping("/remove-metadata")
|
||||||
|
public String addWatermarkForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "remove-metadata");
|
||||||
|
return "security/remove-metadata";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update-metadata")
|
||||||
|
public ResponseEntity<byte[]> addWatermark(@RequestParam("pdfFile") MultipartFile pdfFile,
|
||||||
|
@RequestParam("author") String author) throws IOException {
|
||||||
|
// Load the PDF file
|
||||||
|
PDDocument document = PDDocument.load(pdfFile.getBytes());
|
||||||
|
|
||||||
|
|
||||||
|
// Remove all metadata based on flag
|
||||||
|
PDDocumentInformation info = document.getDocumentInformation();
|
||||||
|
for (String key : info.getMetadataKeys()) {
|
||||||
|
info.setCustomMetadataValue(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_metadata.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// // Loop over all pages and remove annotations
|
||||||
|
// for (PDPage page : document.getPages()) {
|
||||||
|
// page.getAnnotations().clear();
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,209 @@
|
|||||||
|
###########
|
||||||
|
# Generic #
|
||||||
|
###########
|
||||||
|
pdfPrompt=Choose PDF
|
||||||
|
multiPdfPrompt=Choose PDFs (2+)
|
||||||
|
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
||||||
|
imgPrompt=Choose Image
|
||||||
|
genericSubmit=Submit
|
||||||
|
processTimeWarning=Warning: This process can take up to a minute depending on file-size
|
||||||
|
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
|
||||||
|
goToPage=go
|
||||||
|
#############
|
||||||
|
# HOME-PAGE #
|
||||||
|
#############
|
||||||
|
home.desc=Your locally hosted one-stop-shop for all your PDF needs.
|
||||||
|
|
||||||
|
navbar.convert=Convert
|
||||||
|
navbar.security=Security
|
||||||
|
navbar.other=Other
|
||||||
|
navbar.darkmode=Dark Mode
|
||||||
|
|
||||||
|
home.merge.title=Merge PDFs
|
||||||
|
home.merge.desc=Easily merge multiple PDFs into one.
|
||||||
|
|
||||||
|
home.split.title=Split PDFs
|
||||||
|
home.split.desc=Split PDFs into multiple documents
|
||||||
|
|
||||||
|
home.rotate.title=Rotate PDFs
|
||||||
|
home.rotate.desc=Easily rotate your PDFs.
|
||||||
|
|
||||||
|
home.imageToPdf.title=Image to PDF
|
||||||
|
home.imageToPdf.desc=Convert a images (PNG, JPEG, GIF) to PDF.
|
||||||
|
|
||||||
|
home.pdfToImage.title=PDF to Image
|
||||||
|
home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF)
|
||||||
|
|
||||||
|
home.pdfOrganiser.title=PDF Organizer
|
||||||
|
home.pdfOrganiser.desc=Remove/Rearrange pages in any order
|
||||||
|
|
||||||
|
home.addImage.title=Add image onto PDF
|
||||||
|
home.addImage.desc=Adds a image onto a set location on the PDF (Work in progress)
|
||||||
|
|
||||||
|
home.watermark.title=Add Watermark
|
||||||
|
home.watermark.desc=Add a custom watermark to your PDF document.
|
||||||
|
|
||||||
|
home.permissions.title=Change Permissions
|
||||||
|
home.permissions.desc=Change the permissions of your PDF document
|
||||||
|
|
||||||
|
home.removePages.title=Remove Pages
|
||||||
|
home.removePages.desc=Delete unwanted pages from your PDF document.
|
||||||
|
|
||||||
|
home.addPassword.title=Add Password
|
||||||
|
home.addPassword.desc=Encrypt your PDF document with a password.
|
||||||
|
|
||||||
|
home.removePassword.title=Remove Password
|
||||||
|
home.removePassword.desc=Remove password protection from your PDF document.
|
||||||
|
|
||||||
|
home.compressPdfs.title=Compress PDFs
|
||||||
|
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Add image
|
||||||
|
addImage.title=Add Image
|
||||||
|
addImage.header=Add image to PDF (Work in progress)
|
||||||
|
addImage.submit=Add image
|
||||||
|
|
||||||
|
#compress
|
||||||
|
compress.title=Compress
|
||||||
|
compress.header=Compress PDF
|
||||||
|
compress.compressLevel=Value between 1 and 100 (1 being most reduced)
|
||||||
|
compress.submit=Compress
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
merge.title=Merge
|
||||||
|
merge.header=Merge multiple PDFs (2+)
|
||||||
|
merge.submit=Merge
|
||||||
|
|
||||||
|
#pdfOrganiser
|
||||||
|
pdfOrganiser.title=Page Organizer
|
||||||
|
pdfOrganiser.header=PDF Page Organizer
|
||||||
|
pdfOrganiser.submit=Rearrange Pages
|
||||||
|
|
||||||
|
|
||||||
|
#pageRemover
|
||||||
|
pageRemover.title=Page Remover
|
||||||
|
pageRemover.header=PDF Page remover
|
||||||
|
pageRemover.pagesToDelete=Pages to delete (Enter a comma-separated list of page numbers) :
|
||||||
|
pageRemover.submit=Delete Pages
|
||||||
|
|
||||||
|
#rotate
|
||||||
|
rotate.title=Rotate PDF
|
||||||
|
rotate.header=Rotate PDF
|
||||||
|
rotate.selectAngle=Select rotation angle (in multiples of 90 degrees):
|
||||||
|
rotate.submit=Rotate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
split.title=Split PDF
|
||||||
|
split.header=Split PDF
|
||||||
|
split.desc.1=The numbers you select are the page number you wish to do a split on
|
||||||
|
split.desc.2=As such selecting 1,3,7-8 would split a 10 page document into 6 separate PDFS with:
|
||||||
|
split.desc.3=Document #1: Page 1
|
||||||
|
split.desc.4=Document #2: Page 2 and 3
|
||||||
|
split.desc.5=Document #3: Page 4, 5 and 6
|
||||||
|
split.desc.6=Document #4: Page 7
|
||||||
|
split.desc.7=Document #5: Page 8
|
||||||
|
split.desc.8=Document #6: Page 9 and 10
|
||||||
|
split.splitPages=Enter pages to split on:
|
||||||
|
split.submit=Split
|
||||||
|
|
||||||
|
|
||||||
|
#merge
|
||||||
|
imageToPDF.title=Image to PDF
|
||||||
|
imageToPDF.header=Image to PDF
|
||||||
|
imageToPDF.submit=Convert
|
||||||
|
|
||||||
|
#pdfToImage
|
||||||
|
pdfToImage.title=PDF to Image
|
||||||
|
pdfToImage.header=PDF to Image
|
||||||
|
pdfToImage.selectText=Image Format
|
||||||
|
pdfToImage.submit=Convert
|
||||||
|
|
||||||
|
#addPassword
|
||||||
|
addPassword.title=Add Password
|
||||||
|
addPassword.header=Add password (Encrypt)
|
||||||
|
addPassword.selectText.1=Select PDF to encrypt
|
||||||
|
addPassword.selectText.2=Password
|
||||||
|
addPassword.selectText.3=Encryption Key Length
|
||||||
|
addPassword.selectText.4=Higher values are stronger, but lower values have better compatibility.
|
||||||
|
addPassword.selectText.5=Permissions to set
|
||||||
|
addPassword.selectText.6=Prevent assembly of document
|
||||||
|
addPassword.selectText.7=Prevent content extraction
|
||||||
|
addPassword.selectText.8=Prevent extraction for accessibility
|
||||||
|
addPassword.selectText.9=Prevent filling in form
|
||||||
|
addPassword.selectText.10=Prevent modification
|
||||||
|
addPassword.selectText.11=Prevent annotation modification
|
||||||
|
addPassword.selectText.12=Prevent printing
|
||||||
|
addPassword.selectText.13=Prevent printing different formats
|
||||||
|
addPassword.submit=Encrypt
|
||||||
|
|
||||||
|
#watermark
|
||||||
|
watermark.title=Add Watermark
|
||||||
|
watermark.header=Add Watermark
|
||||||
|
watermark.selectText.1=Select PDF to add watermark to:
|
||||||
|
watermark.selectText.2=Watermark Text:
|
||||||
|
watermark.selectText.3=Font Size:
|
||||||
|
watermark.selectText.4=Rotation (0-360):
|
||||||
|
watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
|
||||||
|
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
|
||||||
|
watermark.submit=Add Watermark
|
||||||
|
|
||||||
|
|
||||||
|
#Change permissions
|
||||||
|
permissions.title=Change Permissions
|
||||||
|
permissions.header=Change Permissions
|
||||||
|
permissions.warning=Warning to have these permissions be unchangeable it is recommended to set them with a password via the add-password page
|
||||||
|
permissions.selectText.1=Select PDF to change permissions
|
||||||
|
permissions.selectText.2=Permissions to set
|
||||||
|
permissions.selectText.3=Prevent assembly of document
|
||||||
|
permissions.selectText.4=Prevent content extraction
|
||||||
|
permissions.selectText.5=Prevent extraction for accessibility
|
||||||
|
permissions.selectText.6=Prevent filling in form
|
||||||
|
permissions.selectText.7=Prevent modification
|
||||||
|
permissions.selectText.8=Prevent annotation modification
|
||||||
|
permissions.selectText.9=Prevent printing
|
||||||
|
permissions.selectText.10=Prevent printing different formats
|
||||||
|
permissions.submit=Change
|
||||||
|
|
||||||
|
#remove password
|
||||||
|
removePassword.title=Remove password
|
||||||
|
removePassword.header=Remove password (Decrypt)
|
||||||
|
removePassword.selectText.1=Select PDF to Decrypt
|
||||||
|
removePassword.selectText.2=Password
|
||||||
|
removePassword.submit=Remove
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -58,6 +58,8 @@ home.removePassword.desc=Remove password protection from your PDF document.
|
|||||||
home.compressPdfs.title=Compress PDFs
|
home.compressPdfs.title=Compress PDFs
|
||||||
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
home.compressPdfs.desc=Compress PDFs to reduce their file size.
|
||||||
|
|
||||||
|
home.removeMetadata.title=Remove Metadata
|
||||||
|
home.removeMetadata.desc=Remove unwanted metadata from a PDF document
|
||||||
|
|
||||||
|
|
||||||
#Add image
|
#Add image
|
||||||
@ -177,9 +179,14 @@ removePassword.selectText.1=Select PDF to Decrypt
|
|||||||
removePassword.selectText.2=Password
|
removePassword.selectText.2=Password
|
||||||
removePassword.submit=Remove
|
removePassword.submit=Remove
|
||||||
|
|
||||||
|
removeMetadata.title=Remove Metadata
|
||||||
|
removeMetadata.header=Remove Metadata
|
||||||
|
removeMetadata.selectText.1=Select PDF to remove metadata from
|
||||||
|
removeMetadata.selectText.2=Remove document information
|
||||||
|
removeMetadata.selectText.3=Remove page labels
|
||||||
|
removeMetadata.selectText.4=Remove XMP Metadata
|
||||||
|
removeMetadata.selectText.5=Remove annotations
|
||||||
|
removeMetadata.submit=remove data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
<a class="dropdown-item" href="#" th:href="@{remove-password}" th:classappend="${currentPage}=='remove-password' ? 'active' : ''" th:text="#{home.removePassword.title}"></a>
|
<a class="dropdown-item" href="#" th:href="@{remove-password}" th:classappend="${currentPage}=='remove-password' ? 'active' : ''" th:text="#{home.removePassword.title}"></a>
|
||||||
<a class="dropdown-item" href="#" th:href="@{change-permissions}" th:classappend="${currentPage}=='change-permissions' ? 'active' : ''" th:text="#{home.permissions.title}"></a>
|
<a class="dropdown-item" href="#" th:href="@{change-permissions}" th:classappend="${currentPage}=='change-permissions' ? 'active' : ''" th:text="#{home.permissions.title}"></a>
|
||||||
<a class="dropdown-item" href="#" th:href="@{add-watermark}" th:classappend="${currentPage}=='add-watermark' ? 'active' : ''" th:text="#{home.watermark.title}"></a>
|
<a class="dropdown-item" href="#" th:href="@{add-watermark}" th:classappend="${currentPage}=='add-watermark' ? 'active' : ''" th:text="#{home.watermark.title}"></a>
|
||||||
|
<a class="dropdown-item" href="#" th:href="@{remove-metadata}" th:classappend="${currentPage}=='remove-metadata' ? 'active' : ''" th:text="#{home.removeMetadata.title}"></a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password')}"></div>
|
||||||
|
|
||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf')}"></div>
|
||||||
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removeMetadata.title}, cardText=#{home.removeMetadata.desc}, cardLink='remove-metadata')}"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||||
|
121
src/main/resources/templates/security/remove-metadata.html
Normal file
121
src/main/resources/templates/security/remove-metadata.html
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{removeMetadata.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="#{removeMetadata.header}"></h2>
|
||||||
|
|
||||||
|
<form method="post" enctype="multipart/form-data" th:action="@{/update-metadata}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="pdfFile">PDF File:</label>
|
||||||
|
<input type="file" id="pdfFile" name="pdfFile"/>
|
||||||
|
</div>
|
||||||
|
<p>Please select the variables you wish to change</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="author">Author:</label>
|
||||||
|
<input type="checkbox" id="changeAuthor">
|
||||||
|
<input type="text" id="author" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="creationDate">Creation Date:</label>
|
||||||
|
<input type="checkbox" id="changeCreationDate">
|
||||||
|
<input type="text" id="creationDate" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="creator">Creator:</label>
|
||||||
|
<input type="checkbox" id="changeCreator">
|
||||||
|
<input type="text" id="creator" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="keywords">Keywords:</label>
|
||||||
|
<input type="checkbox" id="changeKeywords">
|
||||||
|
<input type="text" id="keywords" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="modificationDate">Modification Date:</label>
|
||||||
|
<input type="checkbox" id="changeModificationDate">
|
||||||
|
<input type="text" id="modificationDate" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="producer">Producer:</label>
|
||||||
|
<input type="checkbox" id="changeProducer">
|
||||||
|
<input type="text" id="producer" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subject">Subject:</label>
|
||||||
|
<input type="checkbox" id="changeSubject">
|
||||||
|
<input type="text" id="subject" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">Title:</label>
|
||||||
|
<input type="checkbox" id="changeTitle">
|
||||||
|
<input type="text" id="title" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="trapped">Trapped:</label>
|
||||||
|
<input type="checkbox" id="changeTrapped">
|
||||||
|
<input type="text" id="trapped" disabled>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const formGroups = document.querySelectorAll(".form-group");
|
||||||
|
|
||||||
|
formGroups.forEach(formGroup => {
|
||||||
|
const checkbox = formGroup.querySelector("input[type='checkbox']");
|
||||||
|
const textbox = formGroup.querySelector("input[type='text']");
|
||||||
|
if(checkbox)
|
||||||
|
checkbox.addEventListener("change", function() {
|
||||||
|
textbox.disabled = !checkbox.checked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const pdfFileInput = document.querySelector("#pdfFile");
|
||||||
|
const authorInput = document.querySelector("#author");
|
||||||
|
const creationDateInput = document.querySelector("#creationDate");
|
||||||
|
const creatorInput = document.querySelector("#creator");
|
||||||
|
const keywordsInput = document.querySelector("#keywords");
|
||||||
|
const modificationDateInput = document.querySelector("#modificationDate");
|
||||||
|
const producerInput = document.querySelector("#producer");
|
||||||
|
const subjectInput = document.querySelector("#subject");
|
||||||
|
const titleInput = document.querySelector("#title");
|
||||||
|
const trappedInput = document.querySelector("#trapped");
|
||||||
|
|
||||||
|
pdfFileInput.addEventListener("change", async function() {
|
||||||
|
const file = this.files[0];
|
||||||
|
const pdf = await pdfjsLib.getDocument(file).promise;
|
||||||
|
const pdfMetadata = pdf.pdfInfo.metadata;
|
||||||
|
authorInput.value = pdfMetadata.Author;
|
||||||
|
creationDateInput.value = pdfMetadata.CreationDate;
|
||||||
|
creatorInput.value = pdfMetadata.Creator;
|
||||||
|
keywordsInput.value = pdfMetadata.Keywords;
|
||||||
|
modificationDateInput.value = pdfMetadata.ModDate;
|
||||||
|
producerInput.value = pdfMetadata.Producer;
|
||||||
|
subjectInput.value = pdfMetadata.Subject;
|
||||||
|
titleInput.value = pdfMetadata.Title;
|
||||||
|
trappedInput.value = pdfMetadata.Trapped;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user