mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-15 19:10:47 +02:00
Merge remote-tracking branch 'origin/main' into V2
This commit is contained in:
@@ -238,14 +238,14 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("PageOps", "rotate-pdf");
|
||||
addEndpointToGroup("PageOps", "multi-page-layout");
|
||||
addEndpointToGroup("PageOps", "scale-pages");
|
||||
addEndpointToGroup("PageOps", "adjust-contrast");
|
||||
addEndpointToGroup("PageOps", "crop");
|
||||
addEndpointToGroup("PageOps", "auto-split-pdf");
|
||||
addEndpointToGroup("PageOps", "extract-page");
|
||||
addEndpointToGroup("PageOps", "pdf-to-single-page");
|
||||
addEndpointToGroup("PageOps", "auto-split-pdf");
|
||||
addEndpointToGroup("PageOps", "split-by-size-or-count");
|
||||
addEndpointToGroup("PageOps", "overlay-pdf");
|
||||
addEndpointToGroup("PageOps", "split-pdf-by-sections");
|
||||
addEndpointToGroup("PageOps", "split-pdf-by-chapters");
|
||||
|
||||
// Adding endpoints to "Convert" group
|
||||
addEndpointToGroup("Convert", "pdf-to-img");
|
||||
@@ -274,27 +274,43 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Security", "sanitize-pdf");
|
||||
addEndpointToGroup("Security", "auto-redact");
|
||||
addEndpointToGroup("Security", "redact");
|
||||
addEndpointToGroup("Security", "validate-signature");
|
||||
addEndpointToGroup("Security", "stamp");
|
||||
addEndpointToGroup("Security", "sign");
|
||||
|
||||
// Adding endpoints to "Other" group
|
||||
addEndpointToGroup("Other", "ocr-pdf");
|
||||
addEndpointToGroup("Other", "add-image");
|
||||
addEndpointToGroup("Other", "compress-pdf");
|
||||
addEndpointToGroup("Other", "extract-images");
|
||||
addEndpointToGroup("Other", "change-metadata");
|
||||
addEndpointToGroup("Other", "extract-image-scans");
|
||||
addEndpointToGroup("Other", "sign");
|
||||
addEndpointToGroup("Other", "flatten");
|
||||
addEndpointToGroup("Other", "repair");
|
||||
addEndpointToGroup("Other", "unlock-pdf-forms");
|
||||
addEndpointToGroup("Other", REMOVE_BLANKS);
|
||||
addEndpointToGroup("Other", "remove-annotations");
|
||||
addEndpointToGroup("Other", "compare");
|
||||
addEndpointToGroup("Other", "add-page-numbers");
|
||||
addEndpointToGroup("Other", "auto-rename");
|
||||
addEndpointToGroup("Other", "get-info-on-pdf");
|
||||
addEndpointToGroup("Other", "show-javascript");
|
||||
addEndpointToGroup("Other", "remove-image-pdf");
|
||||
addEndpointToGroup("Other", "add-attachments");
|
||||
addEndpointToGroup("Other", "view-pdf");
|
||||
addEndpointToGroup("Other", "replace-and-invert-color-pdf");
|
||||
addEndpointToGroup("Other", "multi-tool");
|
||||
|
||||
// Adding endpoints to "Advance" group
|
||||
addEndpointToGroup("Advance", "adjust-contrast");
|
||||
addEndpointToGroup("Advance", "compress-pdf");
|
||||
addEndpointToGroup("Advance", "extract-image-scans");
|
||||
addEndpointToGroup("Advance", "repair");
|
||||
addEndpointToGroup("Advance", "auto-rename");
|
||||
addEndpointToGroup("Advance", "pipeline");
|
||||
addEndpointToGroup("Advance", "scanner-effect");
|
||||
addEndpointToGroup("Advance", "auto-split-pdf");
|
||||
addEndpointToGroup("Advance", "show-javascript");
|
||||
addEndpointToGroup("Advance", "split-by-size-or-count");
|
||||
addEndpointToGroup("Advance", "overlay-pdf");
|
||||
addEndpointToGroup("Advance", "split-pdf-by-sections");
|
||||
addEndpointToGroup("Advance", "edit-table-of-contents");
|
||||
addEndpointToGroup("Advance", "split-pdf-by-chapters");
|
||||
|
||||
// CLI
|
||||
addEndpointToGroup("CLI", "compress-pdf");
|
||||
|
||||
+9
-3
@@ -1,6 +1,7 @@
|
||||
package stirling.software.SPDF.controller.api.converters;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLConnection;
|
||||
@@ -87,7 +88,7 @@ public class ConvertImgPDFController {
|
||||
// returns bytes for image
|
||||
boolean singleImage = "single".equals(singleOrMultiple);
|
||||
String filename =
|
||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||
Filenames.toSimpleFileName(new File(file.getOriginalFilename()).getName())
|
||||
.replaceFirst("[.][^.]+$", "");
|
||||
|
||||
result =
|
||||
@@ -116,10 +117,14 @@ public class ConvertImgPDFController {
|
||||
}
|
||||
|
||||
String pythonVersion = CheckProgramInstall.getAvailablePythonCommand();
|
||||
Path pngToWebpScript = GeneralUtils.extractScript("png_to_webp.py");
|
||||
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add(pythonVersion);
|
||||
command.add("./scripts/png_to_webp.py"); // Python script to handle the conversion
|
||||
command.add(
|
||||
pngToWebpScript
|
||||
.toAbsolutePath()
|
||||
.toString()); // Python script to handle the conversion
|
||||
|
||||
// Create a temporary directory for the output WebP files
|
||||
tempOutputDir = Files.createTempDirectory("webp_output");
|
||||
@@ -231,7 +236,8 @@ public class ConvertImgPDFController {
|
||||
PdfUtils.imageToPdf(file, fitOption, autoRotate, colorType, pdfDocumentFactory);
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
bytes,
|
||||
file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_converted.pdf");
|
||||
new File(file[0].getOriginalFilename()).getName().replaceFirst("[.][^.]+$", "")
|
||||
+ "_converted.pdf");
|
||||
}
|
||||
|
||||
private String getMediaType(String imageFormat) {
|
||||
|
||||
+3
-1
@@ -34,6 +34,7 @@ import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
|
||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||
import stirling.software.common.util.CheckProgramInstall;
|
||||
import stirling.software.common.util.ExceptionUtils;
|
||||
import stirling.software.common.util.GeneralUtils;
|
||||
import stirling.software.common.util.ProcessExecutor;
|
||||
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
|
||||
import stirling.software.common.util.WebResponseUtils;
|
||||
@@ -78,6 +79,7 @@ public class ExtractImageScansController {
|
||||
}
|
||||
|
||||
String pythonVersion = CheckProgramInstall.getAvailablePythonCommand();
|
||||
Path splitPhotosScript = GeneralUtils.extractScript("split_photos.py");
|
||||
try {
|
||||
// Check if input file is a PDF
|
||||
if ("pdf".equalsIgnoreCase(extension)) {
|
||||
@@ -120,7 +122,7 @@ public class ExtractImageScansController {
|
||||
new ArrayList<>(
|
||||
Arrays.asList(
|
||||
pythonVersion,
|
||||
"./scripts/split_photos.py",
|
||||
splitPhotosScript.toAbsolutePath().toString(),
|
||||
images.get(i),
|
||||
tempDir.toString(),
|
||||
"--angle_threshold",
|
||||
|
||||
+6
@@ -7,6 +7,7 @@ import java.awt.print.Printable;
|
||||
import java.awt.print.PrinterException;
|
||||
import java.awt.print.PrinterJob;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -45,6 +46,11 @@ public class PrintFileController {
|
||||
public ResponseEntity<String> printFile(@ModelAttribute PrintFileRequest request)
|
||||
throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename != null
|
||||
&& (originalFilename.contains("..") || Paths.get(originalFilename).isAbsolute())) {
|
||||
throw new IOException("Invalid file path detected: " + originalFilename);
|
||||
}
|
||||
String printerName = request.getPrinterName();
|
||||
String contentType = file.getContentType();
|
||||
try {
|
||||
|
||||
+9
-9
@@ -33,7 +33,7 @@ import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import stirling.software.SPDF.model.api.misc.FakeScanRequest;
|
||||
import stirling.software.SPDF.model.api.misc.ScannerEffectRequest;
|
||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||
import stirling.software.common.util.WebResponseUtils;
|
||||
|
||||
@@ -42,7 +42,7 @@ import stirling.software.common.util.WebResponseUtils;
|
||||
@Tag(name = "Misc", description = "Miscellaneous PDF APIs")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FakeScanController {
|
||||
public class ScannerEffectController {
|
||||
|
||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||
private static final Random RANDOM = new Random();
|
||||
@@ -52,12 +52,12 @@ public class FakeScanController {
|
||||
private static final int MAX_IMAGE_HEIGHT = 8192;
|
||||
private static final long MAX_IMAGE_PIXELS = 16_777_216; // 4096x4096
|
||||
|
||||
@PostMapping(value = "/fake-scan", consumes = "multipart/form-data")
|
||||
@PostMapping(value = "/scanner-effect", consumes = "multipart/form-data")
|
||||
@Operation(
|
||||
summary = "Convert PDF to look like a scanned document",
|
||||
summary = "Apply scanner effect to PDF",
|
||||
description =
|
||||
"Applies various effects to make a PDF look like it was scanned, including rotation, noise, and edge softening. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> fakeScan(@Valid @ModelAttribute FakeScanRequest request)
|
||||
"Applies various effects to simulate a scanned document, including rotation, noise, and edge softening. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> scannerEffect(@Valid @ModelAttribute ScannerEffectRequest request)
|
||||
throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
|
||||
@@ -80,7 +80,7 @@ public class FakeScanController {
|
||||
float noise = request.getNoise();
|
||||
boolean yellowish = request.isYellowish();
|
||||
int resolution = request.getResolution();
|
||||
FakeScanRequest.Colorspace colorspace = request.getColorspace();
|
||||
ScannerEffectRequest.Colorspace colorspace = request.getColorspace();
|
||||
|
||||
try (PDDocument document = pdfDocumentFactory.load(file)) {
|
||||
PDDocument outputDocument = new PDDocument();
|
||||
@@ -130,7 +130,7 @@ public class FakeScanController {
|
||||
|
||||
// 1. Convert to grayscale or keep color
|
||||
BufferedImage processed;
|
||||
if (colorspace == FakeScanRequest.Colorspace.grayscale) {
|
||||
if (colorspace == ScannerEffectRequest.Colorspace.grayscale) {
|
||||
processed =
|
||||
new BufferedImage(
|
||||
image.getWidth(),
|
||||
@@ -316,7 +316,7 @@ public class FakeScanController {
|
||||
String outputFilename =
|
||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||
.replaceFirst("[.][^.]+$", "")
|
||||
+ "_scanned.pdf";
|
||||
+ "_scanner_effect.pdf";
|
||||
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
outputStream.toByteArray(), outputFilename, MediaType.APPLICATION_PDF);
|
||||
@@ -62,9 +62,18 @@ public class StampController {
|
||||
public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
|
||||
throws IOException, Exception {
|
||||
MultipartFile pdfFile = request.getFileInput();
|
||||
String pdfFileName = pdfFile.getOriginalFilename();
|
||||
if (pdfFileName.contains("..") || pdfFileName.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Invalid PDF file path");
|
||||
}
|
||||
|
||||
String stampType = request.getStampType();
|
||||
String stampText = request.getStampText();
|
||||
MultipartFile stampImage = request.getStampImage();
|
||||
String stampImageName = stampImage.getOriginalFilename();
|
||||
if (stampImageName.contains("..") || stampImageName.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Invalid stamp image file path");
|
||||
}
|
||||
String alphabet = request.getAlphabet();
|
||||
float fontSize = request.getFontSize();
|
||||
float rotation = request.getRotation();
|
||||
|
||||
+8
-1
@@ -108,7 +108,9 @@ public class PipelineProcessor {
|
||||
if (inputFileTypes == null) {
|
||||
inputFileTypes = new ArrayList<String>(Arrays.asList("ALL"));
|
||||
}
|
||||
// List outputFileTypes = apiDocService.getExtensionTypes(true, operation);
|
||||
if (!operation.matches("^[a-zA-Z0-9_-]+$")) {
|
||||
throw new IllegalArgumentException("Invalid operation value received.");
|
||||
}
|
||||
String url = getBaseUrl() + operation;
|
||||
List<Resource> newOutputFiles = new ArrayList<>();
|
||||
if (!isMultiInputOperation) {
|
||||
@@ -327,6 +329,11 @@ public class PipelineProcessor {
|
||||
}
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
Path normalizedPath = Paths.get(file.getName()).normalize();
|
||||
if (normalizedPath.startsWith("..")) {
|
||||
throw new SecurityException(
|
||||
"Potential path traversal attempt in file name: " + file.getName());
|
||||
}
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
// debug statement
|
||||
log.info("Reading file: " + path);
|
||||
|
||||
+12
@@ -74,9 +74,21 @@ public class WatermarkController {
|
||||
public ResponseEntity<byte[]> addWatermark(@ModelAttribute AddWatermarkRequest request)
|
||||
throws IOException, Exception {
|
||||
MultipartFile pdfFile = request.getFileInput();
|
||||
String pdfFileName = pdfFile.getOriginalFilename();
|
||||
if (pdfFileName != null && (pdfFileName.contains("..") || pdfFileName.startsWith("/"))) {
|
||||
throw new SecurityException("Invalid file path in pdfFile");
|
||||
}
|
||||
String watermarkType = request.getWatermarkType();
|
||||
String watermarkText = request.getWatermarkText();
|
||||
MultipartFile watermarkImage = request.getWatermarkImage();
|
||||
if (watermarkImage != null) {
|
||||
String watermarkImageFileName = watermarkImage.getOriginalFilename();
|
||||
if (watermarkImageFileName != null
|
||||
&& (watermarkImageFileName.contains("..")
|
||||
|| watermarkImageFileName.startsWith("/"))) {
|
||||
throw new SecurityException("Invalid file path in watermarkImage");
|
||||
}
|
||||
}
|
||||
String alphabet = request.getAlphabet();
|
||||
float fontSize = request.getFontSize();
|
||||
float rotation = request.getRotation();
|
||||
|
||||
+4
-4
@@ -70,11 +70,11 @@ public class OtherWebController {
|
||||
return "misc/add-page-numbers";
|
||||
}
|
||||
|
||||
@GetMapping("/fake-scan")
|
||||
@GetMapping("/scanner-effect")
|
||||
@Hidden
|
||||
public String fakeScanForm(Model model) {
|
||||
model.addAttribute("currentPage", "fake-scan");
|
||||
return "misc/fake-scan";
|
||||
public String scannerEffectForm(Model model) {
|
||||
model.addAttribute("currentPage", "scanner-effect");
|
||||
return "misc/scanner-effect";
|
||||
}
|
||||
|
||||
@GetMapping("/extract-images")
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
public class FakeScanRequest {
|
||||
public class ScannerEffectRequest {
|
||||
public enum Quality {
|
||||
low,
|
||||
medium,
|
||||
Reference in New Issue
Block a user