mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2024-11-17 12:40:11 +01:00
changes
This commit is contained in:
parent
9aed70408b
commit
a12643194a
@ -151,7 +151,7 @@ public class RearrangePagesPDFController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
|
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
|
||||||
@Operation(summary = "Rearrange pages in a PDF file", description = "This endpoint rearranges pages in a given PDF file based on the specified page order or custom mode. Users can provide a page order as a comma-separated list of page numbers or page ranges, or a custom mode.")
|
@Operation(summary = "Rearrange pages in a PDF file", description = "This endpoint rearranges pages in a given PDF file based on the specified page order or custom mode. Users can provide a page order as a comma-separated list of page numbers or page ranges, or a custom mode. Input:PDF Output:PDF")
|
||||||
public ResponseEntity<byte[]> rearrangePages(
|
public ResponseEntity<byte[]> rearrangePages(
|
||||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to rearrange pages") MultipartFile pdfFile,
|
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to rearrange pages") MultipartFile pdfFile,
|
||||||
@RequestParam(required = false, value = "pageOrder") @Parameter(description = "The new page order as a comma-separated list of page numbers, page ranges (e.g., '1,3,5-7'), or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')") String pageOrder,
|
@RequestParam(required = false, value = "pageOrder") @Parameter(description = "The new page order as a comma-separated list of page numbers, page ranges (e.g., '1,3,5-7'), or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')") String pageOrder,
|
||||||
|
@ -44,7 +44,7 @@ public class PasswordController {
|
|||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
|
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add password to a PDF file",
|
summary = "Add password to a PDF file",
|
||||||
description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file."
|
description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF"
|
||||||
)
|
)
|
||||||
public ResponseEntity<byte[]> addPassword(
|
public ResponseEntity<byte[]> addPassword(
|
||||||
@RequestPart(required = true, value = "fileInput")
|
@RequestPart(required = true, value = "fileInput")
|
||||||
|
@ -43,7 +43,7 @@ public class PdfUtils {
|
|||||||
|
|
||||||
// Create images of all pages
|
// Create images of all pages
|
||||||
for (int i = 0; i < pageCount; i++) {
|
for (int i = 0; i < pageCount; i++) {
|
||||||
images.add(pdfRenderer.renderImageWithDPI(i, 300, colorType));
|
images.add(pdfRenderer.renderImageWithDPI(i, DPI, colorType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (singleImage) {
|
if (singleImage) {
|
||||||
|
@ -131,6 +131,9 @@ home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
|||||||
home.scalePages.title=Adjust page size/scale
|
home.scalePages.title=Adjust page size/scale
|
||||||
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
||||||
|
|
||||||
|
home.pipeline.title=Pipeline
|
||||||
|
home.pipeline.desc=Pipeline desc.
|
||||||
|
|
||||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||||
|
|
||||||
downloadPdf=Download PDF
|
downloadPdf=Download PDF
|
||||||
|
3
src/main/resources/static/images/pipeline.svg
Normal file
3
src/main/resources/static/images/pipeline.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bezier2" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M1 2.5A1.5 1.5 0 0 1 2.5 1h1A1.5 1.5 0 0 1 5 2.5h4.134a1 1 0 1 1 0 1h-2.01c.18.18.34.381.484.605.638.992.892 2.354.892 3.895 0 1.993.257 3.092.713 3.7.356.476.895.721 1.787.784A1.5 1.5 0 0 1 12.5 11h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5H6.866a1 1 0 1 1 0-1h1.711a2.839 2.839 0 0 1-.165-.2C7.743 11.407 7.5 10.007 7.5 8c0-1.46-.246-2.597-.733-3.355-.39-.605-.952-1-1.767-1.112A1.5 1.5 0 0 1 3.5 5h-1A1.5 1.5 0 0 1 1 3.5v-1zM2.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm10 10a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 790 B |
@ -32,6 +32,13 @@
|
|||||||
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
|
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#" th:href="@{pipeline}" th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
|
||||||
|
<img class="icon" src="images/pipeline.svg" alt="icon">
|
||||||
|
<span class="icon-text" th:text="#{home.pipeline.title}"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="nav-item nav-item-separator"></li>
|
<li class="nav-item nav-item-separator"></li>
|
||||||
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' ? 'active' : ''">
|
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' ? 'active' : ''">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<!-- Features -->
|
<!-- Features -->
|
||||||
<div class="features-container container">
|
<div class="features-container container">
|
||||||
|
|
||||||
|
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg')}"></div>
|
||||||
|
|
||||||
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg')}"></div>
|
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg')}"></div>
|
||||||
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', svgPath='images/union.svg')}"></div>
|
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', svgPath='images/union.svg')}"></div>
|
||||||
|
@ -114,29 +114,47 @@
|
|||||||
function validatePipeline() {
|
function validatePipeline() {
|
||||||
let pipelineListItems = document.getElementById('pipelineList').children;
|
let pipelineListItems = document.getElementById('pipelineList').children;
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
|
let containsAddPassword = false;
|
||||||
for (let i = 0; i < pipelineListItems.length - 1; i++) {
|
for (let i = 0; i < pipelineListItems.length - 1; i++) {
|
||||||
let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent;
|
let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent;
|
||||||
let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent;
|
let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent;
|
||||||
|
if(currentOperation === '/add-password'){
|
||||||
let currentOperationOutputDescription = apiDocs[`/${currentOperation}`]?.post?.responses["200"]?.description || "";
|
containsAddPassword = true;
|
||||||
let nextOperationInputDescription = apiDocs[`/${nextOperation}`]?.post?.requestBody?.content["multipart/form-data"]?.schema?.properties?.fileInput?.description || "";
|
|
||||||
|
|
||||||
let currentOperationOutputsPDF = currentOperationOutputDescription.toLowerCase().includes("pdf");
|
|
||||||
let nextOperationExpectsPDF = nextOperationInputDescription.toLowerCase().includes("the pdf file");
|
|
||||||
|
|
||||||
if (currentOperationOutputsPDF && !nextOperationExpectsPDF) {
|
|
||||||
isValid = false;
|
|
||||||
alert(`Incompatible operations: The output of operation '${currentOperation}' is a PDF file but the following operation '${nextOperation}' does not expect a PDF file as input.`);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else if (!currentOperationOutputsPDF && nextOperationExpectsPDF) {
|
console.log(currentOperation);
|
||||||
|
console.log(apiDocs[currentOperation]);
|
||||||
|
let currentOperationDescription = apiDocs[currentOperation]?.post?.description || "";
|
||||||
|
let nextOperationDescription = apiDocs[nextOperation]?.post?.description || "";
|
||||||
|
|
||||||
|
console.log("currentOperationDescription",currentOperationDescription);
|
||||||
|
console.log("nextOperationDescription", nextOperationDescription);
|
||||||
|
|
||||||
|
let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || "";
|
||||||
|
let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || "";
|
||||||
|
|
||||||
|
console.log("Operation " + currentOperation + " Output: " + currentOperationOutput);
|
||||||
|
console.log("Operation " + nextOperation + " Input: " + nextOperationInput);
|
||||||
|
|
||||||
|
// Splitting in case of multiple possible output/input
|
||||||
|
let currentOperationOutputArr = currentOperationOutput.split('/');
|
||||||
|
let nextOperationInputArr = nextOperationInput.split('/');
|
||||||
|
|
||||||
|
if (currentOperationOutput !== 'ANY' && nextOperationInput !== 'ANY') {
|
||||||
|
let intersection = currentOperationOutputArr.filter(value => nextOperationInputArr.includes(value));
|
||||||
|
console.log(`Intersection: ${intersection}`);
|
||||||
|
|
||||||
|
if (intersection.length === 0) {
|
||||||
isValid = false;
|
isValid = false;
|
||||||
alert(`Incompatible operations: The operation '${currentOperation}' does not output a PDF file but the following operation '${nextOperation}' expects a PDF file as input.`);
|
console.log(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
|
||||||
|
alert(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (containsAddPassword && pipelineListItems[pipelineListItems.length - 1].querySelector('.operationName').textContent !== '/add-password') {
|
||||||
|
alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
console.log('Pipeline is valid');
|
console.log('Pipeline is valid');
|
||||||
// Continue with the pipeline operation
|
// Continue with the pipeline operation
|
||||||
@ -144,13 +162,19 @@
|
|||||||
console.error('Pipeline is not valid');
|
console.error('Pipeline is not valid');
|
||||||
// Stop operation, maybe display an error to the user
|
// Stop operation, maybe display an error to the user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
document.getElementById('submitConfigBtn').addEventListener('click', function() {
|
document.getElementById('submitConfigBtn').addEventListener('click', function() {
|
||||||
|
|
||||||
|
if(validatePipeline() === false){
|
||||||
|
return;
|
||||||
|
}
|
||||||
let selectedOperation = document.getElementById('operationsDropdown').value;
|
let selectedOperation = document.getElementById('operationsDropdown').value;
|
||||||
let parameters = operationSettings[selectedOperation] || {};
|
let parameters = operationSettings[selectedOperation] || {};
|
||||||
|
|
||||||
@ -211,9 +235,11 @@
|
|||||||
operationsDropdown.innerHTML = '';
|
operationsDropdown.innerHTML = '';
|
||||||
|
|
||||||
Object.keys(apiDocs).forEach(operation => {
|
Object.keys(apiDocs).forEach(operation => {
|
||||||
|
if(apiDocs[operation].hasOwnProperty('post')) {
|
||||||
let option = document.createElement('option');
|
let option = document.createElement('option');
|
||||||
option.textContent = operation;
|
option.textContent = operation;
|
||||||
operationsDropdown.appendChild(option);
|
operationsDropdown.appendChild(option);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -386,17 +412,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('savePipelineBtn').addEventListener('click', function() {
|
document.getElementById('savePipelineBtn').addEventListener('click', function() {
|
||||||
|
if(validatePipeline() === false){
|
||||||
|
return;
|
||||||
|
}
|
||||||
let pipelineList = document.getElementById('pipelineList').children;
|
let pipelineList = document.getElementById('pipelineList').children;
|
||||||
let pipelineConfig = {
|
let pipelineConfig = {
|
||||||
"name": "uniquePipelineName",
|
"name": "uniquePipelineName",
|
||||||
"pipeline": []
|
"pipeline": []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (pipelineList[pipelineList.length - 1].querySelector('.operationName').textContent !== '/add-password') {
|
|
||||||
alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let i=0; i<pipelineList.length; i++) {
|
for(let i=0; i<pipelineList.length; i++) {
|
||||||
let operationName = pipelineList[i].querySelector('.operationName').textContent;
|
let operationName = pipelineList[i].querySelector('.operationName').textContent;
|
||||||
let parameters = operationSettings[operationName] || {};
|
let parameters = operationSettings[operationName] || {};
|
||||||
|
Loading…
Reference in New Issue
Block a user