mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-14 18:44:05 +02:00
Improve Type Safety and OpenAPI Schema for PDF API Controllers and Models (#3470)
# Description of Changes - **What was changed** - Updated controller methods to use strongly‐typed primitives (`int`, `long`, `boolean`) instead of `String` for numeric and boolean parameters, eliminating calls to `Integer.parseInt`/`Long.parseLong` and improving null‐safety (`Boolean.TRUE.equals(...)`). - Enhanced all API request model classes with richer Swagger/OpenAPI annotations: added `requiredMode`, `defaultValue`, `allowableValues`, `format`, `pattern`, and tightened schema descriptions for all fields. - Refactored HTML form templates for “Remove Blank Pages” to include `min`, `max`, and `step` attributes on numeric inputs, matching the updated validation rules. - **Why the change was made** - **Type safety & robustness**: Shifting from `String` to native types prevents runtime parsing errors, simplifies controller logic, and makes default values explicit. - **Better API documentation & validation**: Enriching the Swagger annotations ensures generated docs accurately reflect required fields, default values, and permitted ranges, which improves client code generation and developer experience. - **Consistency across codebase**: Aligning all request models and controllers enforces a uniform coding style and reduces bugs. #3406 --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
This commit is contained in:
@@ -59,7 +59,8 @@ public class AnalysisController {
|
||||
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
|
||||
public Map<String, String> getDocumentProperties(@ModelAttribute PDFFile file)
|
||||
throws IOException {
|
||||
// Load the document in read-only mode to prevent modifications and ensure the integrity of the original file.
|
||||
// Load the document in read-only mode to prevent modifications and ensure the integrity of
|
||||
// the original file.
|
||||
try (PDDocument document = pdfDocumentFactory.load(file.getFileInput(), true)) {
|
||||
PDDocumentInformation info = document.getDocumentInformation();
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
@@ -180,7 +181,8 @@ public class AnalysisController {
|
||||
|
||||
// Get permissions
|
||||
Map<String, Boolean> permissions = new HashMap<>();
|
||||
permissions.put("preventPrinting", !document.getCurrentAccessPermission().canPrint());
|
||||
permissions.put(
|
||||
"preventPrinting", !document.getCurrentAccessPermission().canPrint());
|
||||
permissions.put(
|
||||
"preventModify", !document.getCurrentAccessPermission().canModify());
|
||||
permissions.put(
|
||||
|
||||
@@ -39,8 +39,8 @@ public class CropController {
|
||||
description =
|
||||
"This operation takes an input PDF file and crops it according to the given"
|
||||
+ " coordinates. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> cropPdf(@ModelAttribute CropPdfForm form) throws IOException {
|
||||
PDDocument sourceDocument = pdfDocumentFactory.load(form);
|
||||
public ResponseEntity<byte[]> cropPdf(@ModelAttribute CropPdfForm request) throws IOException {
|
||||
PDDocument sourceDocument = pdfDocumentFactory.load(request);
|
||||
|
||||
PDDocument newDocument =
|
||||
pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
|
||||
@@ -64,7 +64,8 @@ public class CropController {
|
||||
contentStream.saveGraphicsState();
|
||||
|
||||
// Define the crop area
|
||||
contentStream.addRect(form.getX(), form.getY(), form.getWidth(), form.getHeight());
|
||||
contentStream.addRect(
|
||||
request.getX(), request.getY(), request.getWidth(), request.getHeight());
|
||||
contentStream.clip();
|
||||
|
||||
// Draw the entire formXObject
|
||||
@@ -76,7 +77,11 @@ public class CropController {
|
||||
|
||||
// Now, set the new page's media box to the cropped size
|
||||
newPage.setMediaBox(
|
||||
new PDRectangle(form.getX(), form.getY(), form.getWidth(), form.getHeight()));
|
||||
new PDRectangle(
|
||||
request.getX(),
|
||||
request.getY(),
|
||||
request.getWidth(),
|
||||
request.getHeight()));
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
@@ -87,7 +92,7 @@ public class CropController {
|
||||
byte[] pdfContent = baos.toByteArray();
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
pdfContent,
|
||||
form.getFileInput().getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
||||
request.getFileInput().getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
||||
+ "_cropped.pdf");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import jakarta.mail.MessagingException;
|
||||
@@ -41,7 +42,13 @@ public class EmailController {
|
||||
* @return ResponseEntity with success or error message.
|
||||
*/
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/send-email")
|
||||
@Operation(
|
||||
summary = "Send an email with an attachment",
|
||||
description =
|
||||
"This endpoint sends an email with an attachment. Input:PDF"
|
||||
+ " Output:Success/Failure Type:MISO")
|
||||
public ResponseEntity<String> sendEmailWithAttachment(@Valid @ModelAttribute Email email) {
|
||||
log.info("Sending email to: {}", email.toString());
|
||||
try {
|
||||
// Calls the service to send the email with attachment
|
||||
emailService.sendEmailWithAttachment(email);
|
||||
|
||||
@@ -117,20 +117,20 @@ public class MergeController {
|
||||
"This endpoint merges multiple PDF files into a single PDF file. The merged"
|
||||
+ " file will contain all pages from the input files in the order they were"
|
||||
+ " provided. Input:PDF Output:PDF Type:MISO")
|
||||
public ResponseEntity<byte[]> mergePdfs(@ModelAttribute MergePdfsRequest form)
|
||||
public ResponseEntity<byte[]> mergePdfs(@ModelAttribute MergePdfsRequest request)
|
||||
throws IOException {
|
||||
List<File> filesToDelete = new ArrayList<>(); // List of temporary files to delete
|
||||
File mergedTempFile = null;
|
||||
PDDocument mergedDocument = null;
|
||||
|
||||
boolean removeCertSign = form.isRemoveCertSign();
|
||||
boolean removeCertSign = Boolean.TRUE.equals(request.getRemoveCertSign());
|
||||
|
||||
try {
|
||||
MultipartFile[] files = form.getFileInput();
|
||||
MultipartFile[] files = request.getFileInput();
|
||||
Arrays.sort(
|
||||
files,
|
||||
getSortComparator(
|
||||
form.getSortType())); // Sort files based on the given sort type
|
||||
request.getSortType())); // Sort files based on the given sort type
|
||||
|
||||
PDFMergerUtility mergerUtility = new PDFMergerUtility();
|
||||
long totalSize = 0;
|
||||
|
||||
@@ -47,7 +47,7 @@ public class MultiPageLayoutController {
|
||||
|
||||
int pagesPerSheet = request.getPagesPerSheet();
|
||||
MultipartFile file = request.getFileInput();
|
||||
boolean addBorder = request.isAddBorder();
|
||||
boolean addBorder = Boolean.TRUE.equals(request.getAddBorder());
|
||||
|
||||
if (pagesPerSheet != 2
|
||||
&& pagesPerSheet != 3
|
||||
|
||||
+2
-2
@@ -127,7 +127,7 @@ public class SplitPdfByChaptersController {
|
||||
Path zipFile = null;
|
||||
|
||||
try {
|
||||
boolean includeMetadata = request.getIncludeMetadata();
|
||||
boolean includeMetadata = Boolean.TRUE.equals(request.getIncludeMetadata());
|
||||
Integer bookmarkLevel =
|
||||
request.getBookmarkLevel(); // levels start from 0 (top most bookmarks)
|
||||
if (bookmarkLevel < 0) {
|
||||
@@ -161,7 +161,7 @@ public class SplitPdfByChaptersController {
|
||||
.body("Unable to extract outline items".getBytes());
|
||||
}
|
||||
|
||||
boolean allowDuplicates = request.getAllowDuplicates();
|
||||
boolean allowDuplicates = Boolean.TRUE.equals(request.getAllowDuplicates());
|
||||
if (!allowDuplicates) {
|
||||
/*
|
||||
duplicates are generated when multiple bookmarks correspond to the same page,
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class SplitPdfBySectionsController {
|
||||
// Process the PDF based on split parameters
|
||||
int horiz = request.getHorizontalDivisions() + 1;
|
||||
int verti = request.getVerticalDivisions() + 1;
|
||||
boolean merge = request.isMerge();
|
||||
boolean merge = Boolean.TRUE.equals(request.getMerge());
|
||||
List<PDDocument> splitDocuments = splitPdfPages(sourceDocument, verti, horiz);
|
||||
|
||||
String filename =
|
||||
|
||||
+4
-4
@@ -58,7 +58,7 @@ public class ConvertImgPDFController {
|
||||
String imageFormat = request.getImageFormat();
|
||||
String singleOrMultiple = request.getSingleOrMultiple();
|
||||
String colorType = request.getColorType();
|
||||
String dpi = request.getDpi();
|
||||
int dpi = request.getDpi();
|
||||
String pageNumbers = request.getPageNumbers();
|
||||
Path tempFile = null;
|
||||
Path tempOutputDir = null;
|
||||
@@ -94,7 +94,7 @@ public class ConvertImgPDFController {
|
||||
: imageFormat.toUpperCase(),
|
||||
colorTypeResult,
|
||||
singleImage,
|
||||
Integer.valueOf(dpi),
|
||||
dpi,
|
||||
filename);
|
||||
if (result == null || result.length == 0) {
|
||||
log.error("resultant bytes for {} is null, error converting ", filename);
|
||||
@@ -132,7 +132,7 @@ public class ConvertImgPDFController {
|
||||
command.add(tempOutputDir.toString());
|
||||
}
|
||||
command.add("--dpi");
|
||||
command.add(dpi);
|
||||
command.add(String.valueOf(dpi));
|
||||
ProcessExecutorResult resultProcess =
|
||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
|
||||
.runCommandWithOutputHandling(command);
|
||||
@@ -213,7 +213,7 @@ public class ConvertImgPDFController {
|
||||
MultipartFile[] file = request.getFileInput();
|
||||
String fitOption = request.getFitOption();
|
||||
String colorType = request.getColorType();
|
||||
boolean autoRotate = request.isAutoRotate();
|
||||
boolean autoRotate = Boolean.TRUE.equals(request.getAutoRotate());
|
||||
// Handle Null entries for formdata
|
||||
if (colorType == null || colorType.isBlank()) {
|
||||
colorType = "color";
|
||||
|
||||
+2
-3
@@ -47,9 +47,8 @@ public class ConvertMarkdownToPdf {
|
||||
description =
|
||||
"This endpoint takes a Markdown file input, converts it to HTML, and then to"
|
||||
+ " PDF format. Input:MARKDOWN Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile request)
|
||||
throws Exception {
|
||||
MultipartFile fileInput = request.getFileInput();
|
||||
public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile generalFile) throws Exception {
|
||||
MultipartFile fileInput = generalFile.getFileInput();
|
||||
|
||||
if (fileInput == null) {
|
||||
throw new IllegalArgumentException("Please provide a Markdown file for conversion.");
|
||||
|
||||
+2
-2
@@ -90,9 +90,9 @@ public class ConvertOfficeController {
|
||||
description =
|
||||
"This endpoint converts a given file to a PDF using LibreOffice API Input:ANY"
|
||||
+ " Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> processFileToPDF(@ModelAttribute GeneralFile request)
|
||||
public ResponseEntity<byte[]> processFileToPDF(@ModelAttribute GeneralFile generalFile)
|
||||
throws Exception {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
MultipartFile inputFile = generalFile.getFileInput();
|
||||
// unused but can start server instance if startup time is to long
|
||||
// LibreOfficeListener.getInstance().start();
|
||||
File file = null;
|
||||
|
||||
+2
-3
@@ -23,9 +23,8 @@ public class ConvertPDFToHtml {
|
||||
summary = "Convert PDF to HTML",
|
||||
description =
|
||||
"This endpoint converts a PDF file to HTML format. Input:PDF Output:HTML Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToHTML(@ModelAttribute PDFFile request)
|
||||
throws Exception {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
public ResponseEntity<byte[]> processPdfToHTML(@ModelAttribute PDFFile file) throws Exception {
|
||||
MultipartFile inputFile = file.getFileInput();
|
||||
PDFToFile pdfToFile = new PDFToFile();
|
||||
return pdfToFile.processPdfToHtml(inputFile);
|
||||
}
|
||||
|
||||
+2
-3
@@ -97,9 +97,8 @@ public class ConvertPDFToOffice {
|
||||
description =
|
||||
"This endpoint converts a PDF file to an XML file. Input:PDF Output:XML"
|
||||
+ " Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToXML(@ModelAttribute PDFFile request)
|
||||
throws Exception {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
public ResponseEntity<byte[]> processPdfToXML(@ModelAttribute PDFFile file) throws Exception {
|
||||
MultipartFile inputFile = file.getFileInput();
|
||||
|
||||
PDFToFile pdfToFile = new PDFToFile();
|
||||
return pdfToFile.processPdfToOfficeFormat(inputFile, "xml", "writer_pdf_import");
|
||||
|
||||
+4
-4
@@ -52,12 +52,12 @@ public class ExtractCSVController {
|
||||
description =
|
||||
"This operation takes an input PDF file and returns CSV file of whole page."
|
||||
+ " Input:PDF Output:CSV Type:SISO")
|
||||
public ResponseEntity<?> pdfToCsv(@ModelAttribute PDFWithPageNums form) throws Exception {
|
||||
String baseName = getBaseName(form.getFileInput().getOriginalFilename());
|
||||
public ResponseEntity<?> pdfToCsv(@ModelAttribute PDFWithPageNums request) throws Exception {
|
||||
String baseName = getBaseName(request.getFileInput().getOriginalFilename());
|
||||
List<CsvEntry> csvEntries = new ArrayList<>();
|
||||
|
||||
try (PDDocument document = pdfDocumentFactory.load(form)) {
|
||||
List<Integer> pages = form.getPageNumbersList(document, true);
|
||||
try (PDDocument document = pdfDocumentFactory.load(request)) {
|
||||
List<Integer> pages = request.getPageNumbersList(document, true);
|
||||
SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
|
||||
CSVFormat format =
|
||||
CSVFormat.EXCEL.builder().setEscape('"').setQuoteMode(QuoteMode.ALL).build();
|
||||
|
||||
@@ -77,7 +77,7 @@ public class FilterController {
|
||||
public ResponseEntity<byte[]> pageCount(@ModelAttribute PDFComparisonAndCount request)
|
||||
throws IOException, InterruptedException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
String pageCount = request.getPageCount();
|
||||
int pageCount = request.getPageCount();
|
||||
String comparator = request.getComparator();
|
||||
// Load the PDF
|
||||
PDDocument document = pdfDocumentFactory.load(inputFile);
|
||||
@@ -87,13 +87,13 @@ public class FilterController {
|
||||
// Perform the comparison
|
||||
switch (comparator) {
|
||||
case "Greater":
|
||||
valid = actualPageCount > Integer.parseInt(pageCount);
|
||||
valid = actualPageCount > pageCount;
|
||||
break;
|
||||
case "Equal":
|
||||
valid = actualPageCount == Integer.parseInt(pageCount);
|
||||
valid = actualPageCount == pageCount;
|
||||
break;
|
||||
case "Less":
|
||||
valid = actualPageCount < Integer.parseInt(pageCount);
|
||||
valid = actualPageCount < pageCount;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||
@@ -153,7 +153,7 @@ public class FilterController {
|
||||
public ResponseEntity<byte[]> fileSize(@ModelAttribute FileSizeRequest request)
|
||||
throws IOException, InterruptedException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
String fileSize = request.getFileSize();
|
||||
long fileSize = request.getFileSize();
|
||||
String comparator = request.getComparator();
|
||||
|
||||
// Get the file size
|
||||
@@ -163,13 +163,13 @@ public class FilterController {
|
||||
// Perform the comparison
|
||||
switch (comparator) {
|
||||
case "Greater":
|
||||
valid = actualFileSize > Long.parseLong(fileSize);
|
||||
valid = actualFileSize > fileSize;
|
||||
break;
|
||||
case "Equal":
|
||||
valid = actualFileSize == Long.parseLong(fileSize);
|
||||
valid = actualFileSize == fileSize;
|
||||
break;
|
||||
case "Less":
|
||||
valid = actualFileSize < Long.parseLong(fileSize);
|
||||
valid = actualFileSize < fileSize;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||
|
||||
@@ -47,7 +47,7 @@ public class AutoRenameController {
|
||||
public ResponseEntity<byte[]> extractHeader(@ModelAttribute ExtractHeaderRequest request)
|
||||
throws Exception {
|
||||
MultipartFile file = request.getFileInput();
|
||||
Boolean useFirstTextAsFallback = request.isUseFirstTextAsFallback();
|
||||
boolean useFirstTextAsFallback = Boolean.TRUE.equals(request.getUseFirstTextAsFallback());
|
||||
|
||||
PDDocument document = pdfDocumentFactory.load(file);
|
||||
PDFTextStripper reader =
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ public class AutoSplitPdfController {
|
||||
public ResponseEntity<byte[]> autoSplitPdf(@ModelAttribute AutoSplitPdfRequest request)
|
||||
throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
boolean duplexMode = request.isDuplexMode();
|
||||
boolean duplexMode = Boolean.TRUE.equals(request.getDuplexMode());
|
||||
|
||||
PDDocument document = null;
|
||||
List<PDDocument> splitDocuments = new ArrayList<>();
|
||||
|
||||
+13
-27
@@ -18,14 +18,13 @@ import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -58,24 +57,11 @@ public class ExtractImageScansController {
|
||||
+ " minimum contour area, and border size. Input:PDF Output:IMAGE/ZIP"
|
||||
+ " Type:SIMO")
|
||||
public ResponseEntity<byte[]> extractImageScans(
|
||||
@RequestBody(
|
||||
description = "Form data containing file and extraction parameters",
|
||||
required = true,
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "multipart/form-data",
|
||||
schema =
|
||||
@Schema(
|
||||
implementation =
|
||||
ExtractImageScansRequest
|
||||
.class) // This should
|
||||
// represent
|
||||
// your form's
|
||||
// structure
|
||||
))
|
||||
ExtractImageScansRequest form)
|
||||
@ModelAttribute ExtractImageScansRequest request)
|
||||
throws IOException, InterruptedException {
|
||||
String fileName = form.getFileInput().getOriginalFilename();
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
|
||||
String fileName = inputFile.getOriginalFilename();
|
||||
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
|
||||
List<String> images = new ArrayList<>();
|
||||
@@ -94,7 +80,7 @@ public class ExtractImageScansController {
|
||||
// Check if input file is a PDF
|
||||
if ("pdf".equalsIgnoreCase(extension)) {
|
||||
// Load PDF document
|
||||
try (PDDocument document = pdfDocumentFactory.load(form.getFileInput())) {
|
||||
try (PDDocument document = pdfDocumentFactory.load(inputFile)) {
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||
pdfRenderer.setSubsamplingAllowed(true);
|
||||
int pageCount = document.getNumberOfPages();
|
||||
@@ -116,7 +102,7 @@ public class ExtractImageScansController {
|
||||
}
|
||||
} else {
|
||||
tempInputFile = Files.createTempFile("input_", "." + extension);
|
||||
form.getFileInput().transferTo(tempInputFile);
|
||||
inputFile.transferTo(tempInputFile);
|
||||
// Add input file path to images list
|
||||
images.add(tempInputFile.toString());
|
||||
}
|
||||
@@ -136,15 +122,15 @@ public class ExtractImageScansController {
|
||||
images.get(i),
|
||||
tempDir.toString(),
|
||||
"--angle_threshold",
|
||||
String.valueOf(form.getAngleThreshold()),
|
||||
String.valueOf(request.getAngleThreshold()),
|
||||
"--tolerance",
|
||||
String.valueOf(form.getTolerance()),
|
||||
String.valueOf(request.getTolerance()),
|
||||
"--min_area",
|
||||
String.valueOf(form.getMinArea()),
|
||||
String.valueOf(request.getMinArea()),
|
||||
"--min_contour_area",
|
||||
String.valueOf(form.getMinContourArea()),
|
||||
String.valueOf(request.getMinContourArea()),
|
||||
"--border_size",
|
||||
String.valueOf(form.getBorderSize())));
|
||||
String.valueOf(request.getBorderSize())));
|
||||
|
||||
// Run CLI command
|
||||
ProcessExecutorResult returnCode =
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public class ExtractImagesController {
|
||||
throws IOException, InterruptedException, ExecutionException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String format = request.getFormat();
|
||||
boolean allowDuplicates = request.isAllowDuplicates();
|
||||
boolean allowDuplicates = Boolean.TRUE.equals(request.getAllowDuplicates());
|
||||
PDDocument document = pdfDocumentFactory.load(file);
|
||||
|
||||
// Determine if multithreading should be used based on PDF size or number of pages
|
||||
|
||||
@@ -65,7 +65,7 @@ public class MetadataController {
|
||||
MultipartFile pdfFile = request.getFileInput();
|
||||
|
||||
// Extract metadata information
|
||||
Boolean deleteAll = request.isDeleteAll();
|
||||
boolean deleteAll = Boolean.TRUE.equals(request.getDeleteAll());
|
||||
String author = request.getAuthor();
|
||||
String creationDate = request.getCreationDate();
|
||||
String creator = request.getCreator();
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class OverlayImageController {
|
||||
MultipartFile imageFile = request.getImageFile();
|
||||
float x = request.getX();
|
||||
float y = request.getY();
|
||||
boolean everyPage = request.isEveryPage();
|
||||
boolean everyPage = Boolean.TRUE.equals(request.getEveryPage());
|
||||
try {
|
||||
byte[] pdfBytes = pdfFile.getBytes();
|
||||
byte[] imageBytes = imageFile.getBytes();
|
||||
|
||||
@@ -49,33 +49,30 @@ public class PageNumbersController {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String customMargin = request.getCustomMargin();
|
||||
int position = request.getPosition();
|
||||
int startingNumber = request.getStartingNumber();
|
||||
int pageNumber = request.getStartingNumber();
|
||||
String pagesToNumber = request.getPagesToNumber();
|
||||
String customText = request.getCustomText();
|
||||
int pageNumber = startingNumber;
|
||||
float fontSize = request.getFontSize();
|
||||
String fontType = request.getFontType();
|
||||
|
||||
PDDocument document = pdfDocumentFactory.load(file);
|
||||
float font_size = request.getFontSize();
|
||||
String font_type = request.getFontType();
|
||||
float marginFactor;
|
||||
switch (customMargin.toLowerCase()) {
|
||||
case "small":
|
||||
marginFactor = 0.02f;
|
||||
break;
|
||||
case "medium":
|
||||
marginFactor = 0.035f;
|
||||
break;
|
||||
case "large":
|
||||
marginFactor = 0.05f;
|
||||
break;
|
||||
case "x-large":
|
||||
marginFactor = 0.075f;
|
||||
break;
|
||||
case "medium":
|
||||
default:
|
||||
marginFactor = 0.035f;
|
||||
break;
|
||||
}
|
||||
|
||||
float fontSize = font_size;
|
||||
if (pagesToNumber == null || pagesToNumber.isEmpty()) {
|
||||
pagesToNumber = "all";
|
||||
}
|
||||
@@ -99,7 +96,7 @@ public class PageNumbersController {
|
||||
.replaceFirst("[.][^.]+$", ""));
|
||||
|
||||
PDType1Font currentFont =
|
||||
switch (font_type.toLowerCase()) {
|
||||
switch (fontType.toLowerCase()) {
|
||||
case "courier" -> new PDType1Font(Standard14Fonts.FontName.COURIER);
|
||||
case "times" -> new PDType1Font(Standard14Fonts.FontName.TIMES_ROMAN);
|
||||
default -> new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||
|
||||
@@ -40,9 +40,9 @@ public class RepairController {
|
||||
"This endpoint repairs a given PDF file by running qpdf command. The PDF is"
|
||||
+ " first saved to a temporary location, repaired, read back, and then"
|
||||
+ " returned as a response. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile request)
|
||||
public ResponseEntity<byte[]> repairPdf(@ModelAttribute PDFFile file)
|
||||
throws IOException, InterruptedException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
MultipartFile inputFile = file.getFileInput();
|
||||
// Save the uploaded file to a temporary location
|
||||
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
||||
byte[] pdfBytes = null;
|
||||
|
||||
+8
-8
@@ -31,18 +31,18 @@ public class ReplaceAndInvertColorController {
|
||||
@Operation(
|
||||
summary = "Replace-Invert Color PDF",
|
||||
description =
|
||||
"This endpoint accepts a PDF file and option of invert all colors or replace text and background colors. Input:PDF Output:PDF Type:SISO")
|
||||
"This endpoint accepts a PDF file and option of invert all colors or replace"
|
||||
+ " text and background colors. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<InputStreamResource> replaceAndInvertColor(
|
||||
@ModelAttribute ReplaceAndInvertColorRequest replaceAndInvertColorRequest)
|
||||
throws IOException {
|
||||
@ModelAttribute ReplaceAndInvertColorRequest request) throws IOException {
|
||||
|
||||
InputStreamResource resource =
|
||||
replaceAndInvertColorService.replaceAndInvertColor(
|
||||
replaceAndInvertColorRequest.getFileInput(),
|
||||
replaceAndInvertColorRequest.getReplaceAndInvertOption(),
|
||||
replaceAndInvertColorRequest.getHighContrastColorCombination(),
|
||||
replaceAndInvertColorRequest.getBackGroundColor(),
|
||||
replaceAndInvertColorRequest.getTextColor());
|
||||
request.getFileInput(),
|
||||
request.getReplaceAndInvertOption(),
|
||||
request.getHighContrastColorCombination(),
|
||||
request.getBackGroundColor(),
|
||||
request.getTextColor());
|
||||
|
||||
// Return the modified PDF as a downloadable file
|
||||
return ResponseEntity.ok()
|
||||
|
||||
@@ -36,8 +36,8 @@ public class ShowJavascript {
|
||||
@Operation(
|
||||
summary = "Grabs all JS from a PDF and returns a single JS file with all code",
|
||||
description = "desc. Input:PDF Output:JS Type:SISO")
|
||||
public ResponseEntity<byte[]> extractHeader(@ModelAttribute PDFFile request) throws Exception {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
public ResponseEntity<byte[]> extractHeader(@ModelAttribute PDFFile file) throws Exception {
|
||||
MultipartFile inputFile = file.getFileInput();
|
||||
String script = "";
|
||||
|
||||
try (PDDocument document = pdfDocumentFactory.load(inputFile)) {
|
||||
|
||||
+10
-8
@@ -63,14 +63,16 @@ public class PasswordController {
|
||||
String ownerPassword = request.getOwnerPassword();
|
||||
String password = request.getPassword();
|
||||
int keyLength = request.getKeyLength();
|
||||
boolean preventAssembly = request.isPreventAssembly();
|
||||
boolean preventExtractContent = request.isPreventExtractContent();
|
||||
boolean preventExtractForAccessibility = request.isPreventExtractForAccessibility();
|
||||
boolean preventFillInForm = request.isPreventFillInForm();
|
||||
boolean preventModify = request.isPreventModify();
|
||||
boolean preventModifyAnnotations = request.isPreventModifyAnnotations();
|
||||
boolean preventPrinting = request.isPreventPrinting();
|
||||
boolean preventPrintingFaithful = request.isPreventPrintingFaithful();
|
||||
boolean preventAssembly = Boolean.TRUE.equals(request.getPreventAssembly());
|
||||
boolean preventExtractContent = Boolean.TRUE.equals(request.getPreventExtractContent());
|
||||
boolean preventExtractForAccessibility =
|
||||
Boolean.TRUE.equals(request.getPreventExtractForAccessibility());
|
||||
boolean preventFillInForm = Boolean.TRUE.equals(request.getPreventFillInForm());
|
||||
boolean preventModify = Boolean.TRUE.equals(request.getPreventModify());
|
||||
boolean preventModifyAnnotations =
|
||||
Boolean.TRUE.equals(request.getPreventModifyAnnotations());
|
||||
boolean preventPrinting = Boolean.TRUE.equals(request.getPreventPrinting());
|
||||
boolean preventPrintingFaithful = Boolean.TRUE.equals(request.getPreventPrintingFaithful());
|
||||
|
||||
PDDocument document = pdfDocumentFactory.load(fileInput);
|
||||
AccessPermission ap = new AccessPermission();
|
||||
|
||||
@@ -75,7 +75,7 @@ public class RedactController {
|
||||
redactPages(request, document, allPages);
|
||||
redactAreas(redactionAreas, document, allPages);
|
||||
|
||||
if (request.isConvertPDFToImage()) {
|
||||
if (Boolean.TRUE.equals(request.getConvertPDFToImage())) {
|
||||
PDDocument convertedPdf = PdfUtils.convertPdfToPdfImage(document);
|
||||
document.close();
|
||||
document = convertedPdf;
|
||||
@@ -180,7 +180,6 @@ public class RedactController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<Integer> getPageNumbers(ManualRedactPdfRequest request, int pagesCount) {
|
||||
String pageNumbersInput = request.getPageNumbers();
|
||||
String[] parsedPageNumbers =
|
||||
@@ -201,11 +200,11 @@ public class RedactController {
|
||||
throws Exception {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String listOfTextString = request.getListOfText();
|
||||
boolean useRegex = request.isUseRegex();
|
||||
boolean wholeWordSearchBool = request.isWholeWordSearch();
|
||||
boolean useRegex = Boolean.TRUE.equals(request.getUseRegex());
|
||||
boolean wholeWordSearchBool = Boolean.TRUE.equals(request.getWholeWordSearch());
|
||||
String colorString = request.getRedactColor();
|
||||
float customPadding = request.getCustomPadding();
|
||||
boolean convertPDFToImage = request.isConvertPDFToImage();
|
||||
boolean convertPDFToImage = Boolean.TRUE.equals(request.getConvertPDFToImage());
|
||||
|
||||
String[] listOfText = listOfTextString.split("\n");
|
||||
PDDocument document = pdfDocumentFactory.load(file);
|
||||
|
||||
+6
-6
@@ -46,12 +46,12 @@ public class SanitizeController {
|
||||
public ResponseEntity<byte[]> sanitizePDF(@ModelAttribute SanitizePdfRequest request)
|
||||
throws IOException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
boolean removeJavaScript = request.isRemoveJavaScript();
|
||||
boolean removeEmbeddedFiles = request.isRemoveEmbeddedFiles();
|
||||
boolean removeXMPMetadata = request.isRemoveXMPMetadata();
|
||||
boolean removeMetadata = request.isRemoveMetadata();
|
||||
boolean removeLinks = request.isRemoveLinks();
|
||||
boolean removeFonts = request.isRemoveFonts();
|
||||
boolean removeJavaScript = Boolean.TRUE.equals(request.getRemoveJavaScript());
|
||||
boolean removeEmbeddedFiles = Boolean.TRUE.equals(request.getRemoveEmbeddedFiles());
|
||||
boolean removeXMPMetadata = Boolean.TRUE.equals(request.getRemoveXMPMetadata());
|
||||
boolean removeMetadata = Boolean.TRUE.equals(request.getRemoveMetadata());
|
||||
boolean removeLinks = Boolean.TRUE.equals(request.getRemoveLinks());
|
||||
boolean removeFonts = Boolean.TRUE.equals(request.getRemoveFonts());
|
||||
|
||||
PDDocument document = pdfDocumentFactory.load(inputFile, true);
|
||||
if (removeJavaScript) {
|
||||
|
||||
+18
-3
@@ -1,5 +1,6 @@
|
||||
package stirling.software.SPDF.controller.api.security;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
@@ -23,6 +24,8 @@ import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
|
||||
import org.bouncycastle.util.Store;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -48,6 +51,18 @@ public class ValidateSignatureController {
|
||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||
private final CertificateValidationService certValidationService;
|
||||
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
binder.registerCustomEditor(
|
||||
MultipartFile.class,
|
||||
new PropertyEditorSupport() {
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
setValue(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Validate PDF Digital Signature",
|
||||
description =
|
||||
@@ -58,12 +73,12 @@ public class ValidateSignatureController {
|
||||
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
||||
List<SignatureValidationResult> results = new ArrayList<>();
|
||||
MultipartFile file = request.getFileInput();
|
||||
MultipartFile certFile = request.getCertFile();
|
||||
|
||||
// Load custom certificate if provided
|
||||
X509Certificate customCert = null;
|
||||
if (request.getCertFile() != null && !request.getCertFile().isEmpty()) {
|
||||
try (ByteArrayInputStream certStream =
|
||||
new ByteArrayInputStream(request.getCertFile().getBytes())) {
|
||||
if (certFile != null && !certFile.isEmpty()) {
|
||||
try (ByteArrayInputStream certStream = new ByteArrayInputStream(certFile.getBytes())) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
customCert = (X509Certificate) cf.generateCertificate(certStream);
|
||||
} catch (CertificateException e) {
|
||||
|
||||
+16
-1
@@ -2,6 +2,7 @@ package stirling.software.SPDF.controller.api.security;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -24,6 +25,8 @@ import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||
import org.apache.pdfbox.util.Matrix;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -49,6 +52,18 @@ public class WatermarkController {
|
||||
|
||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
binder.registerCustomEditor(
|
||||
MultipartFile.class,
|
||||
new PropertyEditorSupport() {
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
setValue(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
|
||||
@Operation(
|
||||
summary = "Add watermark to a PDF file",
|
||||
@@ -69,7 +84,7 @@ public class WatermarkController {
|
||||
int widthSpacer = request.getWidthSpacer();
|
||||
int heightSpacer = request.getHeightSpacer();
|
||||
String customColor = request.getCustomColor();
|
||||
boolean convertPdfToImage = request.isConvertPDFToImage();
|
||||
boolean convertPdfToImage = Boolean.TRUE.equals(request.getConvertPDFToImage());
|
||||
|
||||
// Load the input PDF
|
||||
PDDocument document = pdfDocumentFactory.load(pdfFile);
|
||||
|
||||
Reference in New Issue
Block a user