zip and drag drop changes

This commit is contained in:
Anthony Stirling 2023-03-19 23:19:13 +00:00
parent cbfa70d851
commit 98df0bfdf9
16 changed files with 257 additions and 174 deletions

View File

@ -35,6 +35,7 @@ RUN apt-get update && \
python3-uno \
python3-pip \
unoconv \
pngquant \
ocrmypdf && \
pip install --user --upgrade ocrmypdf
@ -52,3 +53,6 @@ ENV LOG_LEVEL=INFO
# Run the application
ENTRYPOINT ["java","-jar","/app.jar","-Dlogging.level=${LOG_LEVEL}"]

View File

@ -1,11 +1,11 @@
fileToPDF.fileTypesList=Microsoft Word: (DOC, DOCX, DOT, DOTX) \
Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF) \
Microsoft PowerPoint: (PPT, PPTX) \
OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG) \
Plain Text: (TXT, TEXT, XML) \
Rich Text Format: (RTF) \
Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF) \
HTML: (HTML) \
Lotus Word Pro: (LWP) \
StarOffice formats: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW) \
fileToPDF.fileTypesList=Microsoft Word: (DOC, DOCX, DOT, DOTX) <br> \
Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF) <br> \
Microsoft PowerPoint: (PPT, PPTX) <br> \
OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG) <br> \
Plain Text: (TXT, TEXT, XML) <br> \
Rich Text Format: (RTF) <br> \
Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF) <br> \
HTML: (HTML) <br> \
Lotus Word Pro: (LWP) <br> \
StarOffice formats: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW) <br> \
Other formats: (DBF, FODS, VSD, VOR, VOR3, VOR4, UOP, PCT, PS, PDF)

View File

@ -15,6 +15,8 @@ goToPage=Go
true=True
false=False
unknown=Unknown
save=Save
close=Close
#############
# HOME-PAGE #
#############
@ -70,20 +72,68 @@ home.compressPdfs.desc=Compress PDFs to reduce their file size.
home.changeMetadata.title=Change Metadata
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
home.xlsToPdf.title=Excel (Xls) to PDF
home.xlsToPdf.desc=Convert a Excel document (xls, xlsx) to PDF.
home.fileToPDF.title=Convert file to PDF
home.fileToPDF.desc=Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)
home.ocr.title=Run OCR on PDF
home.ocr.desc=Scans and detects text from images within a PDF and re-adds it as text.
home.extractImages.title=Extract Images
home.extractImages.desc=Extracts all images from a PDF and saves them to zip
navbar.settings=Settings/About
settings.title=Settings
settings.update=Update available
settings.appVersion=App Version:
settings.downloadOption.title=Choose download option (For single file non zip downloads):
settings.downloadOption.1=Open in same window
settings.downloadOption.2=Open in new window
settings.downloadOption.3=Download file
settings.zip=Zip multi-download files
#OCR
ocr.title=OCR
ocr.header=OCR (Optical Character Recognition)
ocr.selectText.1=Select languages that are to be detected within the PDF (Ones listed are the ones currently detected):
ocr.selectText.2=Produce text file containing OCR text alongside the OCR'ed PDF
ocr.help=Please read this documentation on how to use this for other languages and/or use not in docker
ocr.credit=This service uses OCRmyPDF and Tesseract for OCR.
ocr.submit=Process PDF with OCR
extractImages.title=Extract Images
extractImages.header=Extract Images
extractImages.selectText=Select image format to convert extracted images to
extractImages.submit=Extract
#File to PDF
fileToPDF.title=File to PDF
fileToPDF.header=Convert any file to PDF
fileToPDF.credit=This service uses LibreOffice and Unoconv for file conversion.
fileToPDF.supportedFileTypes=Supported file types should include the below however for a full updated list of supported formats, please refer to the LibreOffice documentation
fileToPDF.submit=Convert to PDF
#compress
compress.title=Compress
compress.header=Compress PDF
compress.credit=This service uses OCRmyPDF for PDF Compress/Optimisation.
compress.selectText.1=Optimization level:
compress.selectText.2=0 (No optimization)
compress.selectText.3=1 (Default, lossless optimization)
compress.selectText.4=2 (Lossy optimization)
compress.selectText.5=3 (Lossy optimization, more aggressive)
compress.selectText.6=Enable fast web view (linearize PDF)
compress.selectText.7=Enable lossy JBIG2 encoding
compress.submit=Compress
#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

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,6 @@
</div>
<button type="submit" class="btn btn-primary" th:text="#{addImage.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>

View File

@ -15,31 +15,27 @@
<div class="col-md-6">
<h2 th:text="#{compress.header}"></h2>
<form action="#" th:action="@{/compress-pdf}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div>
<label for="fileInput">Choose a PDF file</label>
<input type="file" name="fileInput" id="fileInput" accept="application/pdf" required>
</div>
<div>
<label for="optimizeLevel">Optimization level:</label>
<label for="optimizeLevel" th:text="#{compress.selectText.1}"></label>
<select name="optimizeLevel" id="optimizeLevel">
<option value="0">-O0 (No optimization)</option>
<option value="1" selected>-O1 (Default, lossless optimization)</option>
<option value="2">-O2 (Lossy optimization)</option>
<option value="3">-O3 (Lossy optimization, more aggressive)</option>
<option value="0" th:text="#{compress.selectText.2}"></option>
<option value="1" selected th:text="#{compress.selectText.3}"></option>
<option value="2" th:text="#{compress.selectText.4}"></option>
<option value="3" th:text="#{compress.selectText.5}"></option>
</select>
</div>
<div>
<input type="checkbox" name="fastWebView" id="fastWebView" checked>
<label for="fastWebView">Enable fast web view (linearize PDF)</label>
<input type="checkbox" name="fastWebView" id="fastWebView">
<label for="fastWebView" th:text="#{compress.selectText.6}"></label>
</div>
<div>
<input type="checkbox" name="jbig2Lossy" id="jbig2Lossy">
<label for="jbig2Lossy">Enable lossy JBIG2 encoding</label>
<label for="jbig2Lossy" th:text="#{compress.selectText.7}"></label>
</div>
<button type="submit">Optimize PDF</button>
<button type="submit" th:text="#{compress.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
<p class="mt-3" th:text="#{compress.credit}"></p>
</div>
</div>

View File

@ -13,17 +13,13 @@
<div class="row justify-content-center">
<div class="col-md-6">
<h2 th:text="#{fileToPDF.header}"></h2>
<p th:text="#{processTimeWarning}">
<form method="post" enctype="multipart/form-data" th:action="@{file-to-pdf}">
<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="#{filePrompt}"></label>
</div>
<br> <br>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<br>
<button type="submit" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
<p class="mt-3" th:text="#{fileToPDF.credit}"></p>
<p class="mt-3" th:text="#{fileToPDF.supportedFileTypes}"></p>
<p th:utext="#{fileToPDF.fileTypesList}"></p>

View File

@ -23,7 +23,6 @@
<button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>

View File

@ -46,7 +46,6 @@
</div>
<button type="submit" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>

View File

@ -9,6 +9,9 @@
<!-- jQuery -->
<script src="js/jquery.min.js"></script>
<!-- jQuery -->
<script src="js/jszip.min.js"></script>
<!-- Bootstrap -->
<script src="js/popper.min.js"></script>
<script src="js/bootstrap.min.js"></script>
@ -60,65 +63,6 @@ function toggleDarkMode() {
</script>
</head>
<th:block th:fragment="filelist">
<div id="fileList"></div>
<div id="fileList2"></div>
<script>
var input = document.getElementById("fileInput");
var output = document.getElementById("fileList");
input.addEventListener("change", function() {
var files = input.files;
var fileNames = "";
for (var i = 0; i < files.length; i++) {
fileNames += (i + 1) + ". " + files[i].name + "<br>";
}
output.innerHTML = fileNames;
});
</script>
<script>
var input2 = document.getElementById("fileInput2");
var output2 = document.getElementById("fileList2");
if (input2 != null && !input2) {
input2.addEventListener("change", function() {
var files = input2.files;
var fileNames = "";
for (var i = 0; i < files.length; i++) {
fileNames += (i + 1) + ". " + files[i].name + "<br>";
}
output2.innerHTML = fileNames;
});
}
</script>
<script>
if (dropContainer) {
dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
evt.preventDefault();
};
dropContainer.ondrop = function(evt) {
if (fileInput) {
fileInput.files = evt.dataTransfer.files;
const dT = new DataTransfer();
dT.items.add(evt.dataTransfer.files[0]);
dT.items.add(evt.dataTransfer.files[3]);
fileInput.files = dT.files;
evt.preventDefault();
}
};
}
</script>
</th:block>
<th:block th:fragment="fileSelector(name, multiple)">
<div class="custom-file-chooser">
<div class="custom-file">
@ -263,7 +207,17 @@ function toggleDarkMode() {
progressBar.css('width', '0%');
progressBar.attr('aria-valuenow', 0);
progressBar.attr('aria-valuemax', files.length);
// Check the flag in localStorage
const zipFiles = localStorage.getItem('zipParallelFiles') === 'true';
// Initialize JSZip instance if needed
let jszip = null;
if (zipFiles) {
jszip = new JSZip();
}
// Submit each PDF file in parallel
var promises = [];
for (var i = 0; i < files.length; i++) {
@ -287,16 +241,24 @@ function toggleDarkMode() {
var contentDisposition = response.headers.get('content-disposition');
var fileName = contentDisposition.split('filename=')[1].replace(/"/g, '');
response.blob().then(function(blob) {
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
a.remove();
resolve();
});
response.blob().then(function (blob) {
if (zipFiles) {
// Add the file to the ZIP archive
jszip.file(fileName, blob);
resolve();
} else {
// Download the file directly
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
a.remove();
resolve();
}
});
}).catch(function(error) {
console.error('Error submitting request for file ' + i + ': ' + error);
@ -329,10 +291,23 @@ function toggleDarkMode() {
} catch (error) {
console.error('Error while uploading files: ' + error);
}
// Update the progress bar
progressBar.css('width', '100%');
progressBar.attr('aria-valuenow', files.length);
// After all requests are finished, download the ZIP file if needed
if (zipFiles) {
jszip.generateAsync({ type: "blob" }).then(function (content) {
var url = window.URL.createObjectURL(content);
var a = document.createElement('a');
a.href = url;
a.download = "files.zip";
document.body.appendChild(a);
a.click();
a.remove();
});
}
}
@ -341,22 +316,54 @@ function toggleDarkMode() {
<script th:inline="javascript">
$([[${"#"+name+"-input"}]]).on("change", function() {
const files = $(this).get(0).files;
const fileNames = Array.from(files).map(f => f.name);
const selectedFilesContainer = $(this).siblings(".selected-files");
selectedFilesContainer.empty();
fileNames.forEach(fileName => {
selectedFilesContainer.append("<div>" + fileName + "</div>");
document.addEventListener('DOMContentLoaded', function () {
const fileInput = document.getElementById('fileInput-input');
// Prevent default behavior for drag events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
fileInput.addEventListener(eventName, preventDefaults, false);
});
if (fileNames.length === 1) {
$(this).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
} else if (fileNames.length > 1) {
$(this).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " files selected");
} else {
$(this).siblings(".custom-file-label").addClass("selected").html([[#{pdfPrompt}]]);
}
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Add drop event listener
fileInput.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
fileInput.files = files;
handleFileInputChange(fileInput)
}
});
$([[${"#"+name+"-input"}]]).on("change", function() {
handleFileInputChange(this);
});
function handleFileInputChange(inputElement) {
const files = $(inputElement).get(0).files;
const fileNames = Array.from(files).map(f => f.name);
const selectedFilesContainer = $(inputElement).siblings(".selected-files");
selectedFilesContainer.empty();
fileNames.forEach(fileName => {
selectedFilesContainer.append("<div>" + fileName + "</div>");
});
if (fileNames.length === 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
} else if (fileNames.length > 1) {
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " files selected");
} else {
$(inputElement).siblings(".custom-file-label").addClass("selected").html([[#{pdfPrompt}]]);
}
}
</script>

View File

@ -127,12 +127,12 @@ function compareVersions(version1, version2) {
<li class="nav-item"><a class="nav-link" href="#" th:href="@{rotate-pdf}" th:classappend="${currentPage}=='rotate-pdf' ? 'active' : ''" th:text="#{home.rotate.title}"></a></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='xlsx-to-pdf' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='xlsx-to-pdf' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" th:text="#{navbar.convert}"></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#" th:href="@{pdf-to-img}" th:classappend="${currentPage}=='pdf-to-img' ? 'active' : ''" th:text="#{home.pdfToImage.title}"></a>
<a class="dropdown-item" href="#" th:href="@{img-to-pdf}" th:classappend="${currentPage}=='img-to-pdf' ? 'active' : ''" th:text="#{home.imageToPdf.title}"></a>
<a class="dropdown-item" href="#" th:href="@{xlsx-to-pdf}" th:classappend="${currentPage}=='xlsx-to-pdf' ? 'active' : ''" th:text="#{home.xlsToPdf.title}"></a>
<a class="dropdown-item" href="#" th:href="@{file-to-pdf}" th:classappend="${currentPage}=='file-to-pdf' ? 'active' : ''" th:text="#{home.fileToPDF.title}"></a>
</div>
</li>
@ -149,20 +149,22 @@ function compareVersions(version1, version2) {
</li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='add-image' OR ${currentPage}=='compress-pdf' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' ? 'active' : ''"><a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" th:text="#{navbar.other}"></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#" th:href="@{add-image}" th:classappend="${currentPage}=='add-image' ? 'active' : ''" th:text="#{home.addImage.title}"></a> <a class="dropdown-item" href="#" th:href="@{compress-pdf}"
th:classappend="${currentPage}=='compress-pdf' ? 'active' : ''" th:text="#{home.compressPdfs.title}"></a> <a class="dropdown-item" href="#" th:href="@{remove-pages}" th:classappend="${currentPage}=='remove-pages' ? 'active' : ''" th:text="#{home.removePages.title}"></a>
<a class="dropdown-item" href="#" th:href="@{ocr-pdf}" th:classappend="${currentPage}=='ocr-pdf' ? 'active' : ''" th:text="#{home.ocr.title}"></a>
<a class="dropdown-item" href="#" th:href="@{add-image}" th:classappend="${currentPage}=='add-image' ? 'active' : ''" th:text="#{home.addImage.title}"></a>
<a class="dropdown-item" href="#" th:href="@{compress-pdf}" th:classappend="${currentPage}=='compress-pdf' ? 'active' : ''" th:text="#{home.compressPdfs.title}"></a>
<a class="dropdown-item" href="#" th:href="@{remove-pages}" th:classappend="${currentPage}=='remove-pages' ? 'active' : ''" th:text="#{home.removePages.title}"></a>
<a class="dropdown-item" href="#" th:href="@{extract-images}" th:classappend="${currentPage}=='extract-images' ? 'active' : ''" th:text="#{home.extractImages.title}"></a>
</div></li>
<input type="checkbox" id="toggle-dark-mode" checked="true" th:onclick="javascript:toggleDarkMode()">
<a class="nav-link" href="#" for="toggle-dark-mode" th:text="#{navbar.darkmode}"></a>
<a class="nav-link" href="#" for="toggle-dark-mode" th:text="#{navbar.darkmode}" ></a>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 20 20">
@ -178,7 +180,7 @@ function compareVersions(version1, version2) {
<li class="nav-item">
<!-- Settings Button -->
<button type="button" class="btn btn-secondary float-right" data-toggle="modal" data-target="#settingsModal">
<span class="glyphicon glyphicon-cog"></span> Settings/About
<span class="glyphicon glyphicon-cog"></span><span th:text="#{navbar.settings}"></span>
</button>
</li>
</ul>
@ -191,31 +193,41 @@ function compareVersions(version1, version2) {
<div th:insert="~{fragments/errorBanner.html :: errorBanner}"></div>
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content dark-card">
<div class="modal-header">
<h5 class="modal-title" id="settingsModalLabel">Settings</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content dark-card">
<div class="modal-header">
<h5 class="modal-title" id="settingsModalLabel" th:text="#{settings.title}"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<p class="mb-0" th:text="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
<button type="button" class="btn btn-sm btn-outline-primary" id="update-btn" th:text="#{settings.update}"></button>
</div>
<button type="button" class="btn btn-outline-primary" id="update-btn">Update available</button>
<div class="modal-body">
<p th:text="'App Version: ' + ${@appVersion}"></p>
<div class="form-group">
<label for="downloadOption">Choose download option (For non ZIP downloads):</label> <select class="form-control" id="downloadOption">
<option value="sameWindow">Open in same window (Single file downloads only)</option>
<option value="newWindow">Open in new window</option>
<option value="downloadFile">Download file</option>
</select>
<div class="form-group">
<label for="downloadOption" th:text="#{settings.downloadOption.title}"></label>
<select class="form-control" id="downloadOption">
<option value="sameWindow" th:text="#{settings.downloadOption.1}"></option>
<option value="newWindow" th:text="#{settings.downloadOption.2}"></option>
<option value="downloadFile" th:text="#{settings.downloadOption.3}"></option>
</select>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="zipParallelFiles">
<label class="custom-control-label" for="zipParallelFiles" th:text="#{settings.zip}"></label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" th:text="#{close}"></button>
</div>
</div>
</div>
</div>
<script>
// Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist
@ -233,6 +245,19 @@ function compareVersions(version1, version2) {
localStorage.setItem('downloadOption',
downloadOption);
});
// Get the zipParallelFiles flag from local storage, or set it to false if it doesn't exist
var zipParallelFiles = localStorage.getItem('zipParallelFiles') === 'true';
// Set the checked state of the checkbox
document.getElementById('zipParallelFiles').checked = zipParallelFiles;
// Save the checked state of the checkbox to local storage when it changes
document.getElementById('zipParallelFiles').addEventListener('change', function () {
zipParallelFiles = this.checked;
localStorage.setItem('zipParallelFiles', zipParallelFiles);
});
</script>

View File

@ -50,8 +50,8 @@
<div th:replace="~{fragments/card :: card(cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.xlsToPdf.title}, cardText=#{home.xlsToPdf.desc}, cardLink='xlsx-to-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password')}"></div>
@ -60,6 +60,10 @@
<div th:replace="~{fragments/card :: card(cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images')}"></div>
</div>
</div>

View File

@ -2,7 +2,7 @@
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<th:block th:insert="~{fragments/common :: head(title=#{addImage.title})}"></th:block>
<th:block th:insert="~{fragments/common :: head(title=#{ocr.title})}"></th:block>
<body>
@ -13,15 +13,12 @@
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<h2 th:text="#{ocrPDF.header}"></h2>
<h2 th:text="#{ocr.header}"></h2>
<form action="#" th:action="@{/ocr-pdf}" method="post" enctype="multipart/form-data" class="mb-3">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div class="mb-3">
<label for="fileInput" class="form-label">Choose a PDF file</label>
<input type="file" name="fileInput" id="fileInput" accept="application/pdf" required class="form-control">
</div>
<div class="mb-3">
<label for="languages" class="form-label">Select languages that are to be detected within the PDF (Ones listed are the ones currently detected):</label>
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
<div id="languages">
<div th:each="language: ${languages}">
<input type="checkbox" class="form-check-input" th:name="languages" th:value="${language}" th:id="${'language-' + language}" />
@ -31,15 +28,13 @@
</div>
<div class="mb-3">
<input type="checkbox" class="form-check-input" name="sidecar" id="sidecar" />
<label class="form-check-label" for="sidecar">Produce text file containing OCR text alongside the OCR'ed PDF</label>
<label class="form-check-label" for="sidecar" th:text="#{ocr.selectText.2}"></label>
</div>
<button type="submit" class="btn btn-primary">Process PDF with OCR</button>
<button type="submit" class="btn btn-primary" th:text="#{ocr.submit}"></button>
</form>
<p>
Please read this documentation on how to use this for other languages and/or not in docker
</p>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
<p th:text="#{ocr.credit}"></p>
<p th:text="#{ocr.help}"></p>
<a href="https://github.com/Frooodle/Stirling-PDF/blob/main/HowToUseOCR.md"></a>
</div>
</div>
</div>

View File

@ -22,7 +22,6 @@
</div>
<button type="submit" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>

View File

@ -22,8 +22,6 @@
</div>
<button type="submit" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>

View File

@ -33,7 +33,6 @@
<br>
<button type="submit" class="btn btn-primary" th:text="#{split.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>