mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-24 12:36:13 +00:00
Compare commits
8 Commits
a3dedf3e8b
...
81d0e2cb5f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
81d0e2cb5f | ||
![]() |
5e72dce0de | ||
![]() |
6d03ab27d4 | ||
![]() |
830b346945 | ||
![]() |
e5da63554e | ||
![]() |
9b3e2c29a5 | ||
![]() |
9a39aff19f | ||
![]() |
f14955a019 |
@ -122,13 +122,13 @@ Stirling-PDF currently supports 40 languages!
|
|||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
@ -144,7 +144,7 @@ Stirling-PDF currently supports 40 languages!
|
|||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Slovenian (Slovenščina) (sl_SI) |  |
|
| Slovenian (Slovenščina) (sl_SI) |  |
|
||||||
|
@ -3,6 +3,7 @@ package stirling.software.common.annotations;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
import org.springframework.core.annotation.AliasFor;
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ public @interface AutoJobPostMapping {
|
|||||||
|
|
||||||
/** MIME types this endpoint accepts. Defaults to {@code multipart/form-data}. */
|
/** MIME types this endpoint accepts. Defaults to {@code multipart/form-data}. */
|
||||||
@AliasFor(annotation = RequestMapping.class, attribute = "consumes")
|
@AliasFor(annotation = RequestMapping.class, attribute = "consumes")
|
||||||
String[] consumes() default {"multipart/form-data"};
|
String[] consumes() default {MediaType.MULTIPART_FORM_DATA_VALUE};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum execution time in milliseconds before the job is aborted. A negative value means "use
|
* Maximum execution time in milliseconds before the job is aborted. A negative value means "use
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.common.model.api;
|
package stirling.software.common.model.api;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
@ -14,7 +15,7 @@ import lombok.NoArgsConstructor;
|
|||||||
public class PDFFile {
|
public class PDFFile {
|
||||||
@Schema(
|
@Schema(
|
||||||
description = "The input PDF file",
|
description = "The input PDF file",
|
||||||
contentMediaType = "application/pdf",
|
contentMediaType = MediaType.APPLICATION_PDF_VALUE,
|
||||||
format = "binary")
|
format = "binary")
|
||||||
private MultipartFile fileInput;
|
private MultipartFile fileInput;
|
||||||
|
|
||||||
|
@ -227,7 +227,8 @@ public class JobExecutorService {
|
|||||||
if (result instanceof byte[]) {
|
if (result instanceof byte[]) {
|
||||||
// Store byte array directly to disk to avoid double memory consumption
|
// Store byte array directly to disk to avoid double memory consumption
|
||||||
String fileId = fileStorage.storeBytes((byte[]) result, "result.pdf");
|
String fileId = fileStorage.storeBytes((byte[]) result, "result.pdf");
|
||||||
taskManager.setFileResult(jobId, fileId, "result.pdf", "application/pdf");
|
taskManager.setFileResult(
|
||||||
|
jobId, fileId, "result.pdf", MediaType.APPLICATION_PDF_VALUE);
|
||||||
log.debug("Stored byte[] result with fileId: {}", fileId);
|
log.debug("Stored byte[] result with fileId: {}", fileId);
|
||||||
|
|
||||||
// Let the byte array get collected naturally in the next GC cycle
|
// Let the byte array get collected naturally in the next GC cycle
|
||||||
@ -239,7 +240,7 @@ public class JobExecutorService {
|
|||||||
if (body instanceof byte[]) {
|
if (body instanceof byte[]) {
|
||||||
// Extract filename from content-disposition header if available
|
// Extract filename from content-disposition header if available
|
||||||
String filename = "result.pdf";
|
String filename = "result.pdf";
|
||||||
String contentType = "application/pdf";
|
String contentType = MediaType.APPLICATION_PDF_VALUE;
|
||||||
|
|
||||||
if (response.getHeaders().getContentDisposition() != null) {
|
if (response.getHeaders().getContentDisposition() != null) {
|
||||||
String disposition =
|
String disposition =
|
||||||
@ -276,7 +277,7 @@ public class JobExecutorService {
|
|||||||
if (fileId != null && !fileId.isEmpty()) {
|
if (fileId != null && !fileId.isEmpty()) {
|
||||||
// Try to get filename and content type
|
// Try to get filename and content type
|
||||||
String filename = "result.pdf";
|
String filename = "result.pdf";
|
||||||
String contentType = "application/pdf";
|
String contentType = MediaType.APPLICATION_PDF_VALUE;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
java.lang.reflect.Method getOriginalFileName =
|
java.lang.reflect.Method getOriginalFileName =
|
||||||
@ -317,8 +318,7 @@ public class JobExecutorService {
|
|||||||
// Store generic result
|
// Store generic result
|
||||||
taskManager.setResult(jobId, body);
|
taskManager.setResult(jobId, body);
|
||||||
}
|
}
|
||||||
} else if (result instanceof MultipartFile) {
|
} else if (result instanceof MultipartFile file) {
|
||||||
MultipartFile file = (MultipartFile) result;
|
|
||||||
String fileId = fileStorage.storeFile(file);
|
String fileId = fileStorage.storeFile(file);
|
||||||
taskManager.setFileResult(
|
taskManager.setFileResult(
|
||||||
jobId, fileId, file.getOriginalFilename(), file.getContentType());
|
jobId, fileId, file.getOriginalFilename(), file.getContentType());
|
||||||
@ -335,7 +335,7 @@ public class JobExecutorService {
|
|||||||
if (fileId != null && !fileId.isEmpty()) {
|
if (fileId != null && !fileId.isEmpty()) {
|
||||||
// Try to get filename and content type
|
// Try to get filename and content type
|
||||||
String filename = "result.pdf";
|
String filename = "result.pdf";
|
||||||
String contentType = "application/pdf";
|
String contentType = MediaType.APPLICATION_PDF_VALUE;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
java.lang.reflect.Method getOriginalFileName =
|
java.lang.reflect.Method getOriginalFileName =
|
||||||
@ -398,9 +398,8 @@ public class JobExecutorService {
|
|||||||
HttpHeaders.CONTENT_DISPOSITION,
|
HttpHeaders.CONTENT_DISPOSITION,
|
||||||
"form-data; name=\"attachment\"; filename=\"result.pdf\"")
|
"form-data; name=\"attachment\"; filename=\"result.pdf\"")
|
||||||
.body(result);
|
.body(result);
|
||||||
} else if (result instanceof MultipartFile) {
|
} else if (result instanceof MultipartFile file) {
|
||||||
// Return MultipartFile content
|
// Return MultipartFile content
|
||||||
MultipartFile file = (MultipartFile) result;
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.contentType(MediaType.parseMediaType(file.getContentType()))
|
.contentType(MediaType.parseMediaType(file.getContentType()))
|
||||||
.header(
|
.header(
|
||||||
|
@ -12,6 +12,8 @@ import java.util.List;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
@ -28,8 +30,8 @@ public class EmlParser {
|
|||||||
Pattern.compile("=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?=");
|
Pattern.compile("=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?=");
|
||||||
|
|
||||||
private static final String DISPOSITION_ATTACHMENT = "attachment";
|
private static final String DISPOSITION_ATTACHMENT = "attachment";
|
||||||
private static final String TEXT_PLAIN = "text/plain";
|
private static final String TEXT_PLAIN = MediaType.TEXT_PLAIN_VALUE;
|
||||||
private static final String TEXT_HTML = "text/html";
|
private static final String TEXT_HTML = MediaType.TEXT_HTML_VALUE;
|
||||||
private static final String MULTIPART_PREFIX = "multipart/";
|
private static final String MULTIPART_PREFIX = "multipart/";
|
||||||
|
|
||||||
private static final String HEADER_CONTENT_TYPE = "content-type:";
|
private static final String HEADER_CONTENT_TYPE = "content-type:";
|
||||||
@ -69,12 +71,12 @@ public class EmlParser {
|
|||||||
if (isJakartaMailAvailable()) {
|
if (isJakartaMailAvailable()) {
|
||||||
return extractEmailContentAdvanced(emlBytes, request, customHtmlSanitizer);
|
return extractEmailContentAdvanced(emlBytes, request, customHtmlSanitizer);
|
||||||
} else {
|
} else {
|
||||||
return extractEmailContentBasic(emlBytes, request, customHtmlSanitizer);
|
return extractEmailContentBasic(emlBytes, customHtmlSanitizer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static EmailContent extractEmailContentBasic(
|
private static EmailContent extractEmailContentBasic(
|
||||||
byte[] emlBytes, EmlToPdfRequest request, CustomHtmlSanitizer customHtmlSanitizer) {
|
byte[] emlBytes, CustomHtmlSanitizer customHtmlSanitizer) {
|
||||||
String emlContent = new String(emlBytes, StandardCharsets.UTF_8);
|
String emlContent = new String(emlBytes, StandardCharsets.UTF_8);
|
||||||
EmailContent content = new EmailContent();
|
EmailContent content = new EmailContent();
|
||||||
|
|
||||||
@ -121,7 +123,7 @@ public class EmlParser {
|
|||||||
return extractFromMimeMessage(message, request, customHtmlSanitizer);
|
return extractFromMimeMessage(message, request, customHtmlSanitizer);
|
||||||
|
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
return extractEmailContentBasic(emlBytes, request, customHtmlSanitizer);
|
return extractEmailContentBasic(emlBytes, customHtmlSanitizer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import java.util.Map;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
import stirling.software.common.model.api.converters.EmlToPdfRequest;
|
import stirling.software.common.model.api.converters.EmlToPdfRequest;
|
||||||
@ -33,10 +35,10 @@ public class EmlProcessingUtils {
|
|||||||
// MIME type detection
|
// MIME type detection
|
||||||
private static final Map<String, String> EXTENSION_TO_MIME_TYPE =
|
private static final Map<String, String> EXTENSION_TO_MIME_TYPE =
|
||||||
Map.of(
|
Map.of(
|
||||||
".png", "image/png",
|
".png", MediaType.IMAGE_PNG_VALUE,
|
||||||
".jpg", "image/jpeg",
|
".jpg", MediaType.IMAGE_JPEG_VALUE,
|
||||||
".jpeg", "image/jpeg",
|
".jpeg", MediaType.IMAGE_JPEG_VALUE,
|
||||||
".gif", "image/gif",
|
".gif", MediaType.IMAGE_GIF_VALUE,
|
||||||
".bmp", "image/bmp",
|
".bmp", "image/bmp",
|
||||||
".webp", "image/webp",
|
".webp", "image/webp",
|
||||||
".svg", "image/svg+xml",
|
".svg", "image/svg+xml",
|
||||||
@ -81,8 +83,8 @@ public class EmlProcessingUtils {
|
|||||||
|| lowerContent.contains("bcc:");
|
|| lowerContent.contains("bcc:");
|
||||||
boolean hasMimeStructure =
|
boolean hasMimeStructure =
|
||||||
lowerContent.contains("multipart/")
|
lowerContent.contains("multipart/")
|
||||||
|| lowerContent.contains("text/plain")
|
|| lowerContent.contains(MediaType.TEXT_PLAIN_VALUE)
|
||||||
|| lowerContent.contains("text/html")
|
|| lowerContent.contains(MediaType.TEXT_HTML_VALUE)
|
||||||
|| lowerContent.contains("boundary=");
|
|| lowerContent.contains("boundary=");
|
||||||
|
|
||||||
int headerCount = 0;
|
int headerCount = 0;
|
||||||
@ -464,7 +466,7 @@ public class EmlProcessingUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "image/png";
|
return MediaType.IMAGE_PNG_VALUE; // Default MIME type
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String decodeUrlEncoded(String encoded) {
|
public static String decodeUrlEncoded(String encoded) {
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package stirling.software.common.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.multipdf.PDFMergerUtility;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PDFService {
|
||||||
|
|
||||||
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge multiple PDF documents into a single PDF document
|
||||||
|
*
|
||||||
|
* @param documents List of PDDocument to be merged
|
||||||
|
* @return Merged PDDocument
|
||||||
|
* @throws IOException If an error occurs during merging
|
||||||
|
*/
|
||||||
|
public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
|
||||||
|
PDDocument merged = pdfDocumentFactory.createNewDocument();
|
||||||
|
PDFMergerUtility merger = new PDFMergerUtility();
|
||||||
|
for (PDDocument doc : documents) {
|
||||||
|
merger.appendDocument(merged, doc);
|
||||||
|
}
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@ public class PDFToFile {
|
|||||||
|
|
||||||
public ResponseEntity<byte[]> processPdfToMarkdown(MultipartFile inputFile)
|
public ResponseEntity<byte[]> processPdfToMarkdown(MultipartFile inputFile)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
if (!"application/pdf".equals(inputFile.getContentType())) {
|
if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ public class PDFToFile {
|
|||||||
|
|
||||||
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
|
public ResponseEntity<byte[]> processPdfToHtml(MultipartFile inputFile)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
if (!"application/pdf".equals(inputFile.getContentType())) {
|
if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ public class PDFToFile {
|
|||||||
MultipartFile inputFile, String outputFormat, String libreOfficeFilter)
|
MultipartFile inputFile, String outputFormat, String libreOfficeFilter)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
if (!"application/pdf".equals(inputFile.getContentType())) {
|
if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
|
|||||||
import org.apache.pdfbox.text.PDFTextStripper;
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
import org.apache.pdfbox.text.TextPosition;
|
import org.apache.pdfbox.text.TextPosition;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -118,7 +119,7 @@ public class PdfAttachmentHandler {
|
|||||||
public String getContentType() {
|
public String getContentType() {
|
||||||
return attachment.getContentType() != null
|
return attachment.getContentType() != null
|
||||||
? attachment.getContentType()
|
? attachment.getContentType()
|
||||||
: "application/octet-stream";
|
: MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,6 +29,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|||||||
import org.apache.pdfbox.rendering.ImageType;
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
import org.apache.pdfbox.text.PDFTextStripper;
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import io.github.pixee.security.Filenames;
|
import io.github.pixee.security.Filenames;
|
||||||
@ -156,7 +157,8 @@ public class PdfUtils {
|
|||||||
if (DPI > maxSafeDpi) {
|
if (DPI > maxSafeDpi) {
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.dpiExceedsLimit",
|
"error.dpiExceedsLimit",
|
||||||
"DPI value {0} exceeds maximum safe limit of {1}. High DPI values can cause memory issues and crashes. Please use a lower DPI value.",
|
"DPI value {0} exceeds maximum safe limit of {1}. High DPI values can cause"
|
||||||
|
+ " memory issues and crashes. Please use a lower DPI value.",
|
||||||
DPI,
|
DPI,
|
||||||
maxSafeDpi);
|
maxSafeDpi);
|
||||||
}
|
}
|
||||||
@ -196,7 +198,9 @@ public class PdfUtils {
|
|||||||
.contains("Maximum size of image exceeded")) {
|
.contains("Maximum size of image exceeded")) {
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.pageTooBigForDpi",
|
"error.pageTooBigForDpi",
|
||||||
"PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).",
|
"PDF page {0} is too large to render at {1} DPI. Please"
|
||||||
|
+ " try a lower DPI value (recommended: 150 or"
|
||||||
|
+ " less).",
|
||||||
i + 1,
|
i + 1,
|
||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
@ -241,7 +245,10 @@ public class PdfUtils {
|
|||||||
.contains("Maximum size of image exceeded")) {
|
.contains("Maximum size of image exceeded")) {
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.pageTooBigExceedsArray",
|
"error.pageTooBigExceedsArray",
|
||||||
"PDF page {0} is too large to render at {1} DPI. The resulting image would exceed Java's maximum array size. Please try a lower DPI value (recommended: 150 or less).",
|
"PDF page {0} is too large to render at {1} DPI. The"
|
||||||
|
+ " resulting image would exceed Java's maximum"
|
||||||
|
+ " array size. Please try a lower DPI value"
|
||||||
|
+ " (recommended: 150 or less).",
|
||||||
i + 1,
|
i + 1,
|
||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
@ -282,7 +289,9 @@ public class PdfUtils {
|
|||||||
.contains("Maximum size of image exceeded")) {
|
.contains("Maximum size of image exceeded")) {
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.pageTooBigForDpi",
|
"error.pageTooBigForDpi",
|
||||||
"PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).",
|
"PDF page {0} is too large to render at {1} DPI. Please"
|
||||||
|
+ " try a lower DPI value (recommended: 150 or"
|
||||||
|
+ " less).",
|
||||||
i + 1,
|
i + 1,
|
||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
@ -315,7 +324,8 @@ public class PdfUtils {
|
|||||||
&& e.getMessage().contains("Maximum size of image exceeded")) {
|
&& e.getMessage().contains("Maximum size of image exceeded")) {
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.pageTooBigForDpi",
|
"error.pageTooBigForDpi",
|
||||||
"PDF page {0} is too large to render at {1} DPI. Please try a lower DPI value (recommended: 150 or less).",
|
"PDF page {0} is too large to render at {1} DPI. Please try"
|
||||||
|
+ " a lower DPI value (recommended: 150 or less).",
|
||||||
i + 1,
|
i + 1,
|
||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
@ -366,7 +376,9 @@ public class PdfUtils {
|
|||||||
&& e.getMessage().contains("Maximum size of image exceeded")) {
|
&& e.getMessage().contains("Maximum size of image exceeded")) {
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.pageTooBigFor300Dpi",
|
"error.pageTooBigFor300Dpi",
|
||||||
"PDF page {0} is too large to render at 300 DPI. The resulting image would exceed Java's maximum array size. Please use a lower DPI value for PDF-to-image conversion.",
|
"PDF page {0} is too large to render at 300 DPI. The resulting image"
|
||||||
|
+ " would exceed Java's maximum array size. Please use a lower DPI"
|
||||||
|
+ " value for PDF-to-image conversion.",
|
||||||
page + 1);
|
page + 1);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
@ -435,7 +447,7 @@ public class PdfUtils {
|
|||||||
ImageProcessingUtils.convertColorType(image, colorType);
|
ImageProcessingUtils.convertColorType(image, colorType);
|
||||||
// Use JPEGFactory if it's JPEG since JPEG is lossy
|
// Use JPEGFactory if it's JPEG since JPEG is lossy
|
||||||
PDImageXObject pdImage =
|
PDImageXObject pdImage =
|
||||||
(contentType != null && "image/jpeg".equals(contentType))
|
(contentType != null && MediaType.IMAGE_JPEG_VALUE.equals(contentType))
|
||||||
? JPEGFactory.createFromImage(doc, convertedImage)
|
? JPEGFactory.createFromImage(doc, convertedImage)
|
||||||
: LosslessFactory.createFromImage(doc, convertedImage);
|
: LosslessFactory.createFromImage(doc, convertedImage);
|
||||||
addImageToDocument(doc, pdImage, fitOption, autoRotate);
|
addImageToDocument(doc, pdImage, fitOption, autoRotate);
|
||||||
|
@ -4,6 +4,8 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
@ -11,9 +13,13 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||||
|
|
||||||
import io.github.pixee.security.Filenames;
|
import io.github.pixee.security.Filenames;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class WebResponseUtils {
|
public class WebResponseUtils {
|
||||||
|
|
||||||
public static ResponseEntity<byte[]> baosToWebResponse(
|
public static ResponseEntity<byte[]> baosToWebResponse(
|
||||||
@ -64,4 +70,59 @@ public class WebResponseUtils {
|
|||||||
|
|
||||||
return baosToWebResponse(baos, docName);
|
return baosToWebResponse(baos, docName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a File to a web response (PDF default).
|
||||||
|
*
|
||||||
|
* @param outputTempFile The temporary file to be sent as a response.
|
||||||
|
* @param docName The name of the document.
|
||||||
|
* @return A ResponseEntity containing the file as a resource.
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<StreamingResponseBody> pdfFileToWebResponse(
|
||||||
|
TempFile outputTempFile, String docName) throws IOException {
|
||||||
|
return fileToWebResponse(outputTempFile, docName, MediaType.APPLICATION_PDF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a File to a web response (ZIP default).
|
||||||
|
*
|
||||||
|
* @param outputTempFile The temporary file to be sent as a response.
|
||||||
|
* @param docName The name of the document.
|
||||||
|
* @return A ResponseEntity containing the file as a resource.
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<StreamingResponseBody> zipFileToWebResponse(
|
||||||
|
TempFile outputTempFile, String docName) throws IOException {
|
||||||
|
return fileToWebResponse(outputTempFile, docName, MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a File to a web response with explicit media type (e.g., ZIP).
|
||||||
|
*
|
||||||
|
* @param outputTempFile The temporary file to be sent as a response.
|
||||||
|
* @param docName The name of the document.
|
||||||
|
* @param mediaType The content type to set on the response.
|
||||||
|
* @return A ResponseEntity containing the file as a resource.
|
||||||
|
*/
|
||||||
|
public static ResponseEntity<StreamingResponseBody> fileToWebResponse(
|
||||||
|
TempFile outputTempFile, String docName, MediaType mediaType) throws IOException {
|
||||||
|
|
||||||
|
Path path = outputTempFile.getFile().toPath().normalize();
|
||||||
|
long len = Files.size(path);
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(mediaType);
|
||||||
|
headers.setContentLength(len);
|
||||||
|
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + docName + "\"");
|
||||||
|
|
||||||
|
StreamingResponseBody body =
|
||||||
|
os -> {
|
||||||
|
try (os) {
|
||||||
|
Files.copy(path, os);
|
||||||
|
os.flush();
|
||||||
|
} finally {
|
||||||
|
outputTempFile.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new ResponseEntity<>(body, headers, HttpStatus.OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import java.nio.file.Path;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
@ -23,7 +24,7 @@ class ApplicationPropertiesSaml2HttpTest {
|
|||||||
server.enqueue(
|
server.enqueue(
|
||||||
new MockResponse()
|
new MockResponse()
|
||||||
.setResponseCode(200)
|
.setResponseCode(200)
|
||||||
.addHeader("Content-Type", "application/xml")
|
.addHeader("Content-Type", MediaType.APPLICATION_XML_VALUE)
|
||||||
.setBody("<EntityDescriptor/>"));
|
.setBody("<EntityDescriptor/>"));
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package stirling.software.common.service;
|
package stirling.software.common.service;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import static stirling.software.common.service.SpyPDFDocumentFactory.*;
|
import static stirling.software.common.service.SpyPDFDocumentFactory.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
@ -18,9 +18,11 @@ import org.junit.jupiter.api.parallel.Execution;
|
|||||||
import org.junit.jupiter.api.parallel.ExecutionMode;
|
import org.junit.jupiter.api.parallel.ExecutionMode;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.CsvSource;
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
|
|
||||||
import stirling.software.common.model.api.PDFFile;
|
import stirling.software.common.model.api.PDFFile;
|
||||||
|
import stirling.software.common.service.SpyPDFDocumentFactory.StrategyType;
|
||||||
|
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||||
@ -73,7 +75,7 @@ class CustomPDFDocumentFactoryTest {
|
|||||||
void testStrategy_MultipartFile(int sizeMB, StrategyType expected) throws IOException {
|
void testStrategy_MultipartFile(int sizeMB, StrategyType expected) throws IOException {
|
||||||
byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
|
byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
|
||||||
MockMultipartFile multipart =
|
MockMultipartFile multipart =
|
||||||
new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated);
|
new MockMultipartFile("file", "doc.pdf", MediaType.APPLICATION_PDF_VALUE, inflated);
|
||||||
try (PDDocument doc = factory.load(multipart)) {
|
try (PDDocument doc = factory.load(multipart)) {
|
||||||
Assertions.assertEquals(expected, factory.lastStrategyUsed);
|
Assertions.assertEquals(expected, factory.lastStrategyUsed);
|
||||||
}
|
}
|
||||||
@ -84,7 +86,7 @@ class CustomPDFDocumentFactoryTest {
|
|||||||
void testStrategy_PDFFile(int sizeMB, StrategyType expected) throws IOException {
|
void testStrategy_PDFFile(int sizeMB, StrategyType expected) throws IOException {
|
||||||
byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
|
byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
|
||||||
MockMultipartFile multipart =
|
MockMultipartFile multipart =
|
||||||
new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated);
|
new MockMultipartFile("file", "doc.pdf", MediaType.APPLICATION_PDF_VALUE, inflated);
|
||||||
PDFFile pdfFile = new PDFFile();
|
PDFFile pdfFile = new PDFFile();
|
||||||
pdfFile.setFileInput(multipart);
|
pdfFile.setFileInput(multipart);
|
||||||
try (PDDocument doc = factory.load(pdfFile)) {
|
try (PDDocument doc = factory.load(pdfFile)) {
|
||||||
|
@ -2,6 +2,8 @@ package stirling.software.common.service;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.AdditionalAnswers.*;
|
import static org.mockito.AdditionalAnswers.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -15,6 +17,7 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -36,7 +39,7 @@ class FileStorageTest {
|
|||||||
// Create a mock MultipartFile
|
// Create a mock MultipartFile
|
||||||
mockFile = mock(MultipartFile.class);
|
mockFile = mock(MultipartFile.class);
|
||||||
when(mockFile.getOriginalFilename()).thenReturn("test.pdf");
|
when(mockFile.getOriginalFilename()).thenReturn("test.pdf");
|
||||||
when(mockFile.getContentType()).thenReturn("application/pdf");
|
when(mockFile.getContentType()).thenReturn(MediaType.APPLICATION_PDF_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import stirling.software.common.model.job.JobResult;
|
import stirling.software.common.model.job.JobResult;
|
||||||
@ -77,7 +78,7 @@ class TaskManagerTest {
|
|||||||
taskManager.createTask(jobId);
|
taskManager.createTask(jobId);
|
||||||
String fileId = "file-id";
|
String fileId = "file-id";
|
||||||
String originalFileName = "test.pdf";
|
String originalFileName = "test.pdf";
|
||||||
String contentType = "application/pdf";
|
String contentType = MediaType.APPLICATION_PDF_VALUE;
|
||||||
long fileSize = 1024L;
|
long fileSize = 1024L;
|
||||||
|
|
||||||
// Mock the fileStorage.getFileSize() call
|
// Mock the fileStorage.getFileSize() call
|
||||||
@ -185,7 +186,8 @@ class TaskManagerTest {
|
|||||||
// 2. Create completed successful job with file
|
// 2. Create completed successful job with file
|
||||||
String successFileJobId = "success-file-job";
|
String successFileJobId = "success-file-job";
|
||||||
taskManager.createTask(successFileJobId);
|
taskManager.createTask(successFileJobId);
|
||||||
taskManager.setFileResult(successFileJobId, "file-id", "test.pdf", "application/pdf");
|
taskManager.setFileResult(
|
||||||
|
successFileJobId, "file-id", "test.pdf", MediaType.APPLICATION_PDF_VALUE);
|
||||||
|
|
||||||
// 3. Create completed successful job without file
|
// 3. Create completed successful job without file
|
||||||
String successJobId = "success-job";
|
String successJobId = "success-job";
|
||||||
@ -235,7 +237,7 @@ class TaskManagerTest {
|
|||||||
ResultFile.builder()
|
ResultFile.builder()
|
||||||
.fileId("file-id")
|
.fileId("file-id")
|
||||||
.fileName("test.pdf")
|
.fileName("test.pdf")
|
||||||
.contentType("application/pdf")
|
.contentType(MediaType.APPLICATION_PDF_VALUE)
|
||||||
.fileSize(1024L)
|
.fileSize(1024L)
|
||||||
.build();
|
.build();
|
||||||
ReflectionTestUtils.setField(oldJob, "resultFiles", java.util.List.of(resultFile));
|
ReflectionTestUtils.setField(oldJob, "resultFiles", java.util.List.of(resultFile));
|
||||||
|
@ -25,6 +25,7 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -57,7 +58,10 @@ class PDFToFileTest {
|
|||||||
// Prepare
|
// Prepare
|
||||||
MultipartFile nonPdfFile =
|
MultipartFile nonPdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.txt", "text/plain", "This is not a PDF".getBytes());
|
"file",
|
||||||
|
"test.txt",
|
||||||
|
MediaType.TEXT_PLAIN_VALUE,
|
||||||
|
"This is not a PDF".getBytes());
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
ResponseEntity<byte[]> response = pdfToFile.processPdfToMarkdown(nonPdfFile);
|
ResponseEntity<byte[]> response = pdfToFile.processPdfToMarkdown(nonPdfFile);
|
||||||
@ -71,7 +75,10 @@ class PDFToFileTest {
|
|||||||
// Prepare
|
// Prepare
|
||||||
MultipartFile nonPdfFile =
|
MultipartFile nonPdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.txt", "text/plain", "This is not a PDF".getBytes());
|
"file",
|
||||||
|
"test.txt",
|
||||||
|
MediaType.TEXT_PLAIN_VALUE,
|
||||||
|
"This is not a PDF".getBytes());
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
ResponseEntity<byte[]> response = pdfToFile.processPdfToHtml(nonPdfFile);
|
ResponseEntity<byte[]> response = pdfToFile.processPdfToHtml(nonPdfFile);
|
||||||
@ -86,7 +93,10 @@ class PDFToFileTest {
|
|||||||
// Prepare
|
// Prepare
|
||||||
MultipartFile nonPdfFile =
|
MultipartFile nonPdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.txt", "text/plain", "This is not a PDF".getBytes());
|
"file",
|
||||||
|
"test.txt",
|
||||||
|
MediaType.TEXT_PLAIN_VALUE,
|
||||||
|
"This is not a PDF".getBytes());
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
ResponseEntity<byte[]> response =
|
ResponseEntity<byte[]> response =
|
||||||
@ -102,7 +112,10 @@ class PDFToFileTest {
|
|||||||
// Prepare
|
// Prepare
|
||||||
MultipartFile pdfFile =
|
MultipartFile pdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.pdf", "application/pdf", "Fake PDF content".getBytes());
|
"file",
|
||||||
|
"test.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Execute with invalid format
|
// Execute with invalid format
|
||||||
ResponseEntity<byte[]> response =
|
ResponseEntity<byte[]> response =
|
||||||
@ -120,7 +133,10 @@ class PDFToFileTest {
|
|||||||
// Create a mock PDF file
|
// Create a mock PDF file
|
||||||
MultipartFile pdfFile =
|
MultipartFile pdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.pdf", "application/pdf", "Fake PDF content".getBytes());
|
"file",
|
||||||
|
"test.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Create a mock HTML output file
|
// Create a mock HTML output file
|
||||||
Path htmlOutputFile = tempDir.resolve("test.html");
|
Path htmlOutputFile = tempDir.resolve("test.html");
|
||||||
@ -168,7 +184,7 @@ class PDFToFileTest {
|
|||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file",
|
"file",
|
||||||
"multipage.pdf",
|
"multipage.pdf",
|
||||||
"application/pdf",
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
"Fake PDF content".getBytes());
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Setup ProcessExecutor mock
|
// Setup ProcessExecutor mock
|
||||||
@ -245,7 +261,10 @@ class PDFToFileTest {
|
|||||||
// Create a mock PDF file
|
// Create a mock PDF file
|
||||||
MultipartFile pdfFile =
|
MultipartFile pdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.pdf", "application/pdf", "Fake PDF content".getBytes());
|
"file",
|
||||||
|
"test.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Setup ProcessExecutor mock
|
// Setup ProcessExecutor mock
|
||||||
mockedStaticProcessExecutor
|
mockedStaticProcessExecutor
|
||||||
@ -324,7 +343,7 @@ class PDFToFileTest {
|
|||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file",
|
"file",
|
||||||
"document.pdf",
|
"document.pdf",
|
||||||
"application/pdf",
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
"Fake PDF content".getBytes());
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Setup ProcessExecutor mock
|
// Setup ProcessExecutor mock
|
||||||
@ -386,7 +405,7 @@ class PDFToFileTest {
|
|||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file",
|
"file",
|
||||||
"document.pdf",
|
"document.pdf",
|
||||||
"application/pdf",
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
"Fake PDF content".getBytes());
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Setup ProcessExecutor mock
|
// Setup ProcessExecutor mock
|
||||||
@ -472,7 +491,7 @@ class PDFToFileTest {
|
|||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file",
|
"file",
|
||||||
"document.pdf",
|
"document.pdf",
|
||||||
"application/pdf",
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
"Fake PDF content".getBytes());
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Setup ProcessExecutor mock
|
// Setup ProcessExecutor mock
|
||||||
@ -531,7 +550,10 @@ class PDFToFileTest {
|
|||||||
// Create a mock PDF file with no filename
|
// Create a mock PDF file with no filename
|
||||||
MultipartFile pdfFile =
|
MultipartFile pdfFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "", "application/pdf", "Fake PDF content".getBytes());
|
"file",
|
||||||
|
"",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"Fake PDF content".getBytes());
|
||||||
|
|
||||||
// Setup ProcessExecutor mock
|
// Setup ProcessExecutor mock
|
||||||
mockedStaticProcessExecutor
|
mockedStaticProcessExecutor
|
||||||
|
@ -48,7 +48,8 @@ public class WebResponseUtilsTest {
|
|||||||
try {
|
try {
|
||||||
byte[] fileContent = "Sample file content".getBytes();
|
byte[] fileContent = "Sample file content".getBytes();
|
||||||
MockMultipartFile file =
|
MockMultipartFile file =
|
||||||
new MockMultipartFile("file", "sample.txt", "text/plain", fileContent);
|
new MockMultipartFile(
|
||||||
|
"file", "sample.txt", MediaType.TEXT_PLAIN_VALUE, fileContent);
|
||||||
|
|
||||||
ResponseEntity<byte[]> responseEntity =
|
ResponseEntity<byte[]> responseEntity =
|
||||||
WebResponseUtils.multiPartFileToWebResponse(file);
|
WebResponseUtils.multiPartFileToWebResponse(file);
|
||||||
|
@ -8,6 +8,7 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -24,7 +25,10 @@ class CustomColorReplaceStrategyTest {
|
|||||||
// Create a mock file
|
// Create a mock file
|
||||||
mockFile =
|
mockFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.pdf", "application/pdf", "test pdf content".getBytes());
|
"file",
|
||||||
|
"test.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"test pdf content".getBytes());
|
||||||
|
|
||||||
// Initialize strategy with custom colors
|
// Initialize strategy with custom colors
|
||||||
strategy =
|
strategy =
|
||||||
|
@ -24,6 +24,7 @@ import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -38,7 +39,9 @@ class InvertFullColorStrategyTest {
|
|||||||
void setUp() throws Exception {
|
void setUp() throws Exception {
|
||||||
// Create a simple PDF document for testing
|
// Create a simple PDF document for testing
|
||||||
byte[] pdfBytes = createSimplePdfWithRectangle();
|
byte[] pdfBytes = createSimplePdfWithRectangle();
|
||||||
mockPdfFile = new MockMultipartFile("file", "test.pdf", "application/pdf", pdfBytes);
|
mockPdfFile =
|
||||||
|
new MockMultipartFile(
|
||||||
|
"file", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes);
|
||||||
|
|
||||||
// Create the strategy instance
|
// Create the strategy instance
|
||||||
strategy = new InvertFullColorStrategy(mockPdfFile, ReplaceAndInvert.FULL_INVERSION);
|
strategy = new InvertFullColorStrategy(mockPdfFile, ReplaceAndInvert.FULL_INVERSION);
|
||||||
|
@ -7,6 +7,7 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -35,7 +36,10 @@ class ReplaceAndInvertColorStrategyTest {
|
|||||||
// Arrange
|
// Arrange
|
||||||
MultipartFile mockFile =
|
MultipartFile mockFile =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file", "test.pdf", "application/pdf", "test content".getBytes());
|
"file",
|
||||||
|
"test.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"test content".getBytes());
|
||||||
ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR;
|
ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -56,7 +60,7 @@ class ReplaceAndInvertColorStrategyTest {
|
|||||||
// Arrange
|
// Arrange
|
||||||
byte[] content = "test pdf content".getBytes();
|
byte[] content = "test pdf content".getBytes();
|
||||||
MultipartFile mockFile =
|
MultipartFile mockFile =
|
||||||
new MockMultipartFile("file", "test.pdf", "application/pdf", content);
|
new MockMultipartFile("file", "test.pdf", MediaType.APPLICATION_PDF_VALUE, content);
|
||||||
ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR;
|
ReplaceAndInvert replaceAndInvert = ReplaceAndInvert.CUSTOM_COLOR;
|
||||||
|
|
||||||
ReplaceAndInvertColorStrategy strategy =
|
ReplaceAndInvertColorStrategy strategy =
|
||||||
@ -74,10 +78,16 @@ class ReplaceAndInvertColorStrategyTest {
|
|||||||
// Arrange
|
// Arrange
|
||||||
MultipartFile mockFile1 =
|
MultipartFile mockFile1 =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file1", "test1.pdf", "application/pdf", "content1".getBytes());
|
"file1",
|
||||||
|
"test1.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"content1".getBytes());
|
||||||
MultipartFile mockFile2 =
|
MultipartFile mockFile2 =
|
||||||
new MockMultipartFile(
|
new MockMultipartFile(
|
||||||
"file2", "test2.pdf", "application/pdf", "content2".getBytes());
|
"file2",
|
||||||
|
"test2.pdf",
|
||||||
|
MediaType.APPLICATION_PDF_VALUE,
|
||||||
|
"content2".getBytes());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ReplaceAndInvertColorStrategy strategy =
|
ReplaceAndInvertColorStrategy strategy =
|
||||||
|
@ -11,6 +11,7 @@ import org.apache.pdfbox.pdmodel.PDPageTree;
|
|||||||
import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
|
import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
|
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@ -29,7 +30,7 @@ public class AnalysisController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/page-count", consumes = "multipart/form-data")
|
@PostMapping(value = "/page-count", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get PDF page count",
|
summary = "Get PDF page count",
|
||||||
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
|
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
|
||||||
@ -39,7 +40,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/basic-info", consumes = "multipart/form-data")
|
@PostMapping(value = "/basic-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get basic PDF information",
|
summary = "Get basic PDF information",
|
||||||
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
|
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
|
||||||
@ -53,7 +54,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/document-properties", consumes = "multipart/form-data")
|
@PostMapping(value = "/document-properties", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get PDF document properties",
|
summary = "Get PDF document properties",
|
||||||
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
|
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
|
||||||
@ -76,7 +77,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
|
@PostMapping(value = "/page-dimensions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get page dimensions for all pages",
|
summary = "Get page dimensions for all pages",
|
||||||
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
|
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
|
||||||
@ -96,7 +97,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/form-fields", consumes = "multipart/form-data")
|
@PostMapping(value = "/form-fields", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get form field information",
|
summary = "Get form field information",
|
||||||
description =
|
description =
|
||||||
@ -119,7 +120,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/annotation-info", consumes = "multipart/form-data")
|
@PostMapping(value = "/annotation-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get annotation information",
|
summary = "Get annotation information",
|
||||||
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
|
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
|
||||||
@ -143,7 +144,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/font-info", consumes = "multipart/form-data")
|
@PostMapping(value = "/font-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get font information",
|
summary = "Get font information",
|
||||||
description =
|
description =
|
||||||
@ -165,7 +166,7 @@ public class AnalysisController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/security-info", consumes = "multipart/form-data")
|
@PostMapping(value = "/security-info", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Get security information",
|
summary = "Get security information",
|
||||||
description =
|
description =
|
||||||
|
@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -33,7 +34,7 @@ public class CropController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/crop", consumes = "multipart/form-data")
|
@PostMapping(value = "/crop", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Crops a PDF document",
|
summary = "Crops a PDF document",
|
||||||
description =
|
description =
|
||||||
|
@ -46,7 +46,7 @@ public class EditTableOfContentsController {
|
|||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
@PostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data")
|
@PostMapping(value = "/extract-bookmarks", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract PDF Bookmarks",
|
summary = "Extract PDF Bookmarks",
|
||||||
description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
|
description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
|
||||||
@ -154,7 +154,7 @@ public class EditTableOfContentsController {
|
|||||||
return bookmark;
|
return bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data")
|
@PostMapping(value = "/edit-table-of-contents", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Edit Table of Contents",
|
summary = "Edit Table of Contents",
|
||||||
description = "Add or edit bookmarks/table of contents in a PDF document.")
|
description = "Add or edit bookmarks/table of contents in a PDF document.")
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package stirling.software.SPDF.controller.api;
|
package stirling.software.SPDF.controller.api;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -20,12 +19,14 @@ import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlin
|
|||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@ -36,8 +37,9 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.ExceptionUtils;
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
|
||||||
import stirling.software.common.util.PdfErrorUtils;
|
import stirling.software.common.util.PdfErrorUtils;
|
||||||
|
import stirling.software.common.util.TempFile;
|
||||||
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -48,6 +50,7 @@ import stirling.software.common.util.WebResponseUtils;
|
|||||||
public class MergeController {
|
public class MergeController {
|
||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
private final TempFileManager tempFileManager;
|
||||||
|
|
||||||
// Merges a list of PDDocument objects into a single PDDocument
|
// Merges a list of PDDocument objects into a single PDDocument
|
||||||
public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
|
public PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
|
||||||
@ -62,56 +65,54 @@ public class MergeController {
|
|||||||
|
|
||||||
// Returns a comparator for sorting MultipartFile arrays based on the given sort type
|
// Returns a comparator for sorting MultipartFile arrays based on the given sort type
|
||||||
private Comparator<MultipartFile> getSortComparator(String sortType) {
|
private Comparator<MultipartFile> getSortComparator(String sortType) {
|
||||||
switch (sortType) {
|
return switch (sortType) {
|
||||||
case "byFileName":
|
case "byFileName" -> Comparator.comparing(MultipartFile::getOriginalFilename);
|
||||||
return Comparator.comparing(MultipartFile::getOriginalFilename);
|
case "byDateModified" ->
|
||||||
case "byDateModified":
|
(file1, file2) -> {
|
||||||
return (file1, file2) -> {
|
try {
|
||||||
try {
|
BasicFileAttributes attr1 =
|
||||||
BasicFileAttributes attr1 =
|
Files.readAttributes(
|
||||||
Files.readAttributes(
|
Paths.get(file1.getOriginalFilename()),
|
||||||
Paths.get(file1.getOriginalFilename()),
|
BasicFileAttributes.class);
|
||||||
BasicFileAttributes.class);
|
BasicFileAttributes attr2 =
|
||||||
BasicFileAttributes attr2 =
|
Files.readAttributes(
|
||||||
Files.readAttributes(
|
Paths.get(file2.getOriginalFilename()),
|
||||||
Paths.get(file2.getOriginalFilename()),
|
BasicFileAttributes.class);
|
||||||
BasicFileAttributes.class);
|
return attr1.lastModifiedTime().compareTo(attr2.lastModifiedTime());
|
||||||
return attr1.lastModifiedTime().compareTo(attr2.lastModifiedTime());
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
return 0; // If there's an error, treat them as equal
|
||||||
return 0; // If there's an error, treat them as equal
|
}
|
||||||
}
|
};
|
||||||
};
|
case "byDateCreated" ->
|
||||||
case "byDateCreated":
|
(file1, file2) -> {
|
||||||
return (file1, file2) -> {
|
try {
|
||||||
try {
|
BasicFileAttributes attr1 =
|
||||||
BasicFileAttributes attr1 =
|
Files.readAttributes(
|
||||||
Files.readAttributes(
|
Paths.get(file1.getOriginalFilename()),
|
||||||
Paths.get(file1.getOriginalFilename()),
|
BasicFileAttributes.class);
|
||||||
BasicFileAttributes.class);
|
BasicFileAttributes attr2 =
|
||||||
BasicFileAttributes attr2 =
|
Files.readAttributes(
|
||||||
Files.readAttributes(
|
Paths.get(file2.getOriginalFilename()),
|
||||||
Paths.get(file2.getOriginalFilename()),
|
BasicFileAttributes.class);
|
||||||
BasicFileAttributes.class);
|
return attr1.creationTime().compareTo(attr2.creationTime());
|
||||||
return attr1.creationTime().compareTo(attr2.creationTime());
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
return 0; // If there's an error, treat them as equal
|
||||||
return 0; // If there's an error, treat them as equal
|
}
|
||||||
}
|
};
|
||||||
};
|
case "byPDFTitle" ->
|
||||||
case "byPDFTitle":
|
(file1, file2) -> {
|
||||||
return (file1, file2) -> {
|
try (PDDocument doc1 = pdfDocumentFactory.load(file1);
|
||||||
try (PDDocument doc1 = pdfDocumentFactory.load(file1);
|
PDDocument doc2 = pdfDocumentFactory.load(file2)) {
|
||||||
PDDocument doc2 = pdfDocumentFactory.load(file2)) {
|
String title1 = doc1.getDocumentInformation().getTitle();
|
||||||
String title1 = doc1.getDocumentInformation().getTitle();
|
String title2 = doc2.getDocumentInformation().getTitle();
|
||||||
String title2 = doc2.getDocumentInformation().getTitle();
|
return title1.compareTo(title2);
|
||||||
return title1.compareTo(title2);
|
} catch (IOException e) {
|
||||||
} catch (IOException e) {
|
return 0;
|
||||||
return 0;
|
}
|
||||||
}
|
};
|
||||||
};
|
case "orderProvided" -> (file1, file2) -> 0; // Default is the order provided
|
||||||
case "orderProvided":
|
default -> (file1, file2) -> 0; // Default is the order provided
|
||||||
default:
|
};
|
||||||
return (file1, file2) -> 0; // Default is the order provided
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a table of contents to the merged document using filenames as chapter titles
|
// Adds a table of contents to the merged document using filenames as chapter titles
|
||||||
@ -154,17 +155,18 @@ public class MergeController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/merge-pdfs")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Merge multiple PDF files into one",
|
summary = "Merge multiple PDF files into one",
|
||||||
description =
|
description =
|
||||||
"This endpoint merges multiple PDF files into a single PDF file. The merged"
|
"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"
|
+ " file will contain all pages from the input files in the order they were"
|
||||||
+ " provided. Input:PDF Output:PDF Type:MISO")
|
+ " provided. Input:PDF Output:PDF Type:MISO")
|
||||||
public ResponseEntity<byte[]> mergePdfs(@ModelAttribute MergePdfsRequest request)
|
public ResponseEntity<StreamingResponseBody> mergePdfs(@ModelAttribute MergePdfsRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
List<File> filesToDelete = new ArrayList<>(); // List of temporary files to delete
|
List<File> filesToDelete = new ArrayList<>(); // List of temporary files to delete
|
||||||
File mergedTempFile = null;
|
TempFile mergedTempFile = null;
|
||||||
|
TempFile outputTempFile = null;
|
||||||
PDDocument mergedDocument = null;
|
PDDocument mergedDocument = null;
|
||||||
|
|
||||||
boolean removeCertSign = Boolean.TRUE.equals(request.getRemoveCertSign());
|
boolean removeCertSign = Boolean.TRUE.equals(request.getRemoveCertSign());
|
||||||
@ -182,14 +184,14 @@ public class MergeController {
|
|||||||
for (MultipartFile multipartFile : files) {
|
for (MultipartFile multipartFile : files) {
|
||||||
totalSize += multipartFile.getSize();
|
totalSize += multipartFile.getSize();
|
||||||
File tempFile =
|
File tempFile =
|
||||||
GeneralUtils.convertMultipartFileToFile(
|
tempFileManager.convertMultipartFileToFile(
|
||||||
multipartFile); // Convert MultipartFile to File
|
multipartFile); // Convert MultipartFile to File
|
||||||
filesToDelete.add(tempFile); // Add temp file to the list for later deletion
|
filesToDelete.add(tempFile); // Add temp file to the list for later deletion
|
||||||
mergerUtility.addSource(tempFile); // Add source file to the merger utility
|
mergerUtility.addSource(tempFile); // Add source file to the merger utility
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedTempFile = Files.createTempFile("merged-", ".pdf").toFile();
|
mergedTempFile = new TempFile(tempFileManager, ".pdf");
|
||||||
mergerUtility.setDestinationFileName(mergedTempFile.getAbsolutePath());
|
mergerUtility.setDestinationFileName(mergedTempFile.getFile().getAbsolutePath());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mergerUtility.mergeDocuments(
|
mergerUtility.mergeDocuments(
|
||||||
@ -204,7 +206,7 @@ public class MergeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the merged PDF document
|
// Load the merged PDF document
|
||||||
mergedDocument = pdfDocumentFactory.load(mergedTempFile);
|
mergedDocument = pdfDocumentFactory.load(mergedTempFile.getFile());
|
||||||
|
|
||||||
// Remove signatures if removeCertSign is true
|
// Remove signatures if removeCertSign is true
|
||||||
if (removeCertSign) {
|
if (removeCertSign) {
|
||||||
@ -213,7 +215,7 @@ public class MergeController {
|
|||||||
if (acroForm != null) {
|
if (acroForm != null) {
|
||||||
List<PDField> fieldsToRemove =
|
List<PDField> fieldsToRemove =
|
||||||
acroForm.getFields().stream()
|
acroForm.getFields().stream()
|
||||||
.filter(field -> field instanceof PDSignatureField)
|
.filter(PDSignatureField.class::isInstance)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (!fieldsToRemove.isEmpty()) {
|
if (!fieldsToRemove.isEmpty()) {
|
||||||
@ -229,16 +231,15 @@ public class MergeController {
|
|||||||
addTableOfContents(mergedDocument, files);
|
addTableOfContents(mergedDocument, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the modified document to a new ByteArrayOutputStream
|
// Save the modified document to a temporary file
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
outputTempFile = new TempFile(tempFileManager, ".pdf");
|
||||||
mergedDocument.save(baos);
|
mergedDocument.save(outputTempFile.getFile());
|
||||||
|
|
||||||
String mergedFileName =
|
String mergedFileName =
|
||||||
files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
files[0].getOriginalFilename().replaceFirst("[.][^.]+$", "")
|
||||||
+ "_merged_unsigned.pdf";
|
+ "_merged_unsigned.pdf";
|
||||||
return WebResponseUtils.baosToWebResponse(
|
return WebResponseUtils.pdfFileToWebResponse(
|
||||||
baos, mergedFileName); // Return the modified PDF
|
outputTempFile, mergedFileName); // Return the modified PDF as stream
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
if (ex instanceof IOException && PdfErrorUtils.isCorruptedPdfError((IOException) ex)) {
|
if (ex instanceof IOException && PdfErrorUtils.isCorruptedPdfError((IOException) ex)) {
|
||||||
log.warn("Corrupted PDF detected in merge pdf process: {}", ex.getMessage());
|
log.warn("Corrupted PDF detected in merge pdf process: {}", ex.getMessage());
|
||||||
@ -251,12 +252,10 @@ public class MergeController {
|
|||||||
mergedDocument.close(); // Close the merged document
|
mergedDocument.close(); // Close the merged document
|
||||||
}
|
}
|
||||||
for (File file : filesToDelete) {
|
for (File file : filesToDelete) {
|
||||||
if (file != null) {
|
tempFileManager.deleteTempFile(file); // Delete temporary files
|
||||||
Files.deleteIfExists(file.toPath()); // Delete temporary files
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (mergedTempFile != null) {
|
if (mergedTempFile != null) {
|
||||||
Files.deleteIfExists(mergedTempFile.toPath());
|
mergedTempFile.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -36,7 +37,7 @@ public class MultiPageLayoutController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
|
@PostMapping(value = "/multi-page-layout", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Merge multiple pages of a PDF document into a single page",
|
summary = "Merge multiple pages of a PDF document into a single page",
|
||||||
description =
|
description =
|
||||||
|
@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -46,7 +47,7 @@ public class PdfImageRemovalController {
|
|||||||
* content type and filename.
|
* content type and filename.
|
||||||
* @throws IOException If an error occurs while processing the PDF file.
|
* @throws IOException If an error occurs while processing the PDF file.
|
||||||
*/
|
*/
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-image-pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove images from file to reduce the file size.",
|
summary = "Remove images from file to reduce the file size.",
|
||||||
description =
|
description =
|
||||||
|
@ -39,7 +39,7 @@ public class PdfOverlayController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
|
@PostMapping(value = "/overlay-pdfs", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Overlay PDF files in various modes",
|
summary = "Overlay PDF files in various modes",
|
||||||
description =
|
description =
|
||||||
|
@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -38,7 +39,7 @@ public class RearrangePagesPDFController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-pages")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove pages from a PDF file",
|
summary = "Remove pages from a PDF file",
|
||||||
description =
|
description =
|
||||||
@ -237,7 +238,7 @@ public class RearrangePagesPDFController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/rearrange-pages")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Rearrange pages in a PDF file",
|
summary = "Rearrange pages in a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -5,6 +5,7 @@ import java.io.IOException;
|
|||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -31,7 +32,7 @@ public class RotationController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/rotate-pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Rotate a PDF file",
|
summary = "Rotate a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -12,6 +12,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -38,7 +39,7 @@ public class ScalePagesController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
|
@PostMapping(value = "/scale-pages", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Change the size of a PDF page/document",
|
summary = "Change the size of a PDF page/document",
|
||||||
description =
|
description =
|
||||||
|
@ -30,6 +30,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.ExceptionUtils;
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
|
import stirling.software.common.util.TempFile;
|
||||||
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -40,8 +42,9 @@ import stirling.software.common.util.WebResponseUtils;
|
|||||||
public class SplitPDFController {
|
public class SplitPDFController {
|
||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
private final TempFileManager tempFileManager;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/split-pages")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/split-pages")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split a PDF file into separate documents",
|
summary = "Split a PDF file into separate documents",
|
||||||
description =
|
description =
|
||||||
@ -55,8 +58,11 @@ public class SplitPDFController {
|
|||||||
PDDocument document = null;
|
PDDocument document = null;
|
||||||
Path zipFile = null;
|
Path zipFile = null;
|
||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
|
String filename;
|
||||||
|
TempFile outputTempFile = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
outputTempFile = new TempFile(tempFileManager, ".zip");
|
||||||
|
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
String pages = request.getPageNumbers();
|
String pages = request.getPageNumbers();
|
||||||
@ -105,12 +111,11 @@ public class SplitPDFController {
|
|||||||
// closing the original document
|
// closing the original document
|
||||||
document.close();
|
document.close();
|
||||||
|
|
||||||
zipFile = Files.createTempFile("split_documents", ".zip");
|
filename =
|
||||||
|
|
||||||
String filename =
|
|
||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
.replaceFirst("[.][^.]+$", "");
|
.replaceFirst("[.][^.]+$", "");
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut =
|
||||||
|
new ZipOutputStream(Files.newOutputStream(outputTempFile.getPath()))) {
|
||||||
// loop through the split documents and write them to the zip file
|
// loop through the split documents and write them to the zip file
|
||||||
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
||||||
String fileName = filename + "_" + (i + 1) + ".pdf";
|
String fileName = filename + "_" + (i + 1) + ".pdf";
|
||||||
@ -125,19 +130,13 @@ public class SplitPDFController {
|
|||||||
|
|
||||||
log.debug("Wrote split document {} to zip file", fileName);
|
log.debug("Wrote split document {} to zip file", fileName);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed writing to zip", e);
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
log.debug(
|
||||||
log.debug("Successfully created zip file with split documents: {}", zipFile.toString());
|
"Successfully created zip file with split documents: {}",
|
||||||
byte[] data = Files.readAllBytes(zipFile);
|
outputTempFile.getPath());
|
||||||
Files.deleteIfExists(zipFile);
|
byte[] data = Files.readAllBytes(outputTempFile.getPath());
|
||||||
|
|
||||||
// return the Resource in the response
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
// Close the main document
|
// Close the main document
|
||||||
@ -152,9 +151,9 @@ public class SplitPDFController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete temporary zip file
|
// Close the output temporary file
|
||||||
if (zipFile != null) {
|
if (outputTempFile != null) {
|
||||||
Files.deleteIfExists(zipFile);
|
outputTempFile.close();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error while cleaning up resources", e);
|
log.error("Error while cleaning up resources", e);
|
||||||
|
@ -117,7 +117,7 @@ public class SplitPdfByChaptersController {
|
|||||||
return bookmarks;
|
return bookmarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
|
@PostMapping(value = "/split-pdf-by-chapters", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split PDFs by Chapters",
|
summary = "Split PDFs by Chapters",
|
||||||
description = "Splits a PDF into chapters and returns a ZIP file.")
|
description = "Splits a PDF into chapters and returns a ZIP file.")
|
||||||
|
@ -2,8 +2,8 @@ package stirling.software.SPDF.controller.api;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
@ -24,6 +24,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||||
|
|
||||||
import io.github.pixee.security.Filenames;
|
import io.github.pixee.security.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@ -33,6 +34,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
|
import stirling.software.common.util.PDFService;
|
||||||
|
import stirling.software.common.util.TempFile;
|
||||||
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -42,16 +46,18 @@ import stirling.software.common.util.WebResponseUtils;
|
|||||||
public class SplitPdfBySectionsController {
|
public class SplitPdfBySectionsController {
|
||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
private final TempFileManager tempFileManager;
|
||||||
|
private final PDFService pdfService;
|
||||||
|
|
||||||
@PostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
|
@PostMapping(value = "/split-pdf-by-sections", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Split PDF pages into smaller sections",
|
summary = "Split PDF pages into smaller sections",
|
||||||
description =
|
description =
|
||||||
"Split each page of a PDF into smaller sections based on the user's choice"
|
"Split each page of a PDF into smaller sections based on the user's choice"
|
||||||
+ " (halves, thirds, quarters, etc.), both vertically and horizontally."
|
+ " (halves, thirds, quarters, etc.), both vertically and horizontally."
|
||||||
+ " Input:PDF Output:ZIP-PDF Type:SISO")
|
+ " Input:PDF Output:ZIP-PDF Type:SISO")
|
||||||
public ResponseEntity<byte[]> splitPdf(@ModelAttribute SplitPdfBySectionsRequest request)
|
public ResponseEntity<StreamingResponseBody> splitPdf(
|
||||||
throws Exception {
|
@ModelAttribute SplitPdfBySectionsRequest request) throws Exception {
|
||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
|
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
@ -67,10 +73,14 @@ public class SplitPdfBySectionsController {
|
|||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
.replaceFirst("[.][^.]+$", "");
|
.replaceFirst("[.][^.]+$", "");
|
||||||
if (merge) {
|
if (merge) {
|
||||||
MergeController mergeController = new MergeController(pdfDocumentFactory);
|
TempFile tempFile = new TempFile(tempFileManager, ".pdf");
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
try (PDDocument merged = pdfService.mergeDocuments(splitDocuments);
|
||||||
mergeController.mergeDocuments(splitDocuments).save(baos);
|
OutputStream out = Files.newOutputStream(tempFile.getPath())) {
|
||||||
return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), filename + "_split.pdf");
|
merged.save(out);
|
||||||
|
for (PDDocument d : splitDocuments) d.close();
|
||||||
|
sourceDocument.close();
|
||||||
|
}
|
||||||
|
return WebResponseUtils.pdfFileToWebResponse(tempFile, filename + "_split.pdf");
|
||||||
}
|
}
|
||||||
for (PDDocument doc : splitDocuments) {
|
for (PDDocument doc : splitDocuments) {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
@ -81,10 +91,9 @@ public class SplitPdfBySectionsController {
|
|||||||
|
|
||||||
sourceDocument.close();
|
sourceDocument.close();
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
TempFile zipTempFile = new TempFile(tempFileManager, ".zip");
|
||||||
byte[] data;
|
try (ZipOutputStream zipOut =
|
||||||
|
new ZipOutputStream(Files.newOutputStream(zipTempFile.getPath()))) {
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
|
||||||
int pageNum = 1;
|
int pageNum = 1;
|
||||||
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
||||||
ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
|
ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
|
||||||
@ -98,15 +107,8 @@ public class SplitPdfBySectionsController {
|
|||||||
|
|
||||||
if (sectionNum == horiz * verti) pageNum++;
|
if (sectionNum == horiz * verti) pageNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
zipOut.finish();
|
|
||||||
data = Files.readAllBytes(zipFile);
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
|
||||||
data, filename + "_split.zip", MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
Files.deleteIfExists(zipFile);
|
|
||||||
}
|
}
|
||||||
|
return WebResponseUtils.zipFileToWebResponse(zipTempFile, filename + "_split.zip");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PDDocument> splitPdfPages(
|
public List<PDDocument> splitPdfPages(
|
||||||
|
@ -28,6 +28,8 @@ import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
|
|||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
import stirling.software.common.util.ExceptionUtils;
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.common.util.GeneralUtils;
|
||||||
|
import stirling.software.common.util.TempFile;
|
||||||
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -38,8 +40,9 @@ import stirling.software.common.util.WebResponseUtils;
|
|||||||
public class SplitPdfBySizeController {
|
public class SplitPdfBySizeController {
|
||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
private final TempFileManager tempFileManager;
|
||||||
|
|
||||||
@PostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
|
@PostMapping(value = "/split-by-size-or-count", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Auto split PDF pages into separate documents based on size or count",
|
summary = "Auto split PDF pages into separate documents based on size or count",
|
||||||
description =
|
description =
|
||||||
@ -54,89 +57,68 @@ public class SplitPdfBySizeController {
|
|||||||
log.debug("Starting PDF split process with request: {}", request);
|
log.debug("Starting PDF split process with request: {}", request);
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
|
||||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
|
||||||
log.debug("Created temporary zip file: {}", zipFile);
|
|
||||||
|
|
||||||
String filename =
|
String filename =
|
||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
.replaceFirst("[.][^.]+$", "");
|
.replaceFirst("[.][^.]+$", "");
|
||||||
log.debug("Base filename for output: {}", filename);
|
log.debug("Base filename for output: {}", filename);
|
||||||
|
|
||||||
byte[] data = null;
|
try (TempFile zipTempFile = new TempFile(tempFileManager, ".zip")) {
|
||||||
try {
|
Path zipFile = zipTempFile.getPath();
|
||||||
log.debug("Reading input file bytes");
|
log.debug("Created temporary zip file: {}", zipFile);
|
||||||
byte[] pdfBytes = file.getBytes();
|
try {
|
||||||
log.debug("Successfully read {} bytes from input file", pdfBytes.length);
|
log.debug("Reading input file bytes");
|
||||||
|
byte[] pdfBytes = file.getBytes();
|
||||||
|
log.debug("Successfully read {} bytes from input file", pdfBytes.length);
|
||||||
|
|
||||||
log.debug("Creating ZIP output stream");
|
log.debug("Creating ZIP output stream");
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||||
log.debug("Loading PDF document");
|
log.debug("Loading PDF document");
|
||||||
try (PDDocument sourceDocument = pdfDocumentFactory.load(pdfBytes)) {
|
try (PDDocument sourceDocument = pdfDocumentFactory.load(pdfBytes)) {
|
||||||
log.debug(
|
log.debug(
|
||||||
"Successfully loaded PDF with {} pages",
|
"Successfully loaded PDF with {} pages",
|
||||||
sourceDocument.getNumberOfPages());
|
sourceDocument.getNumberOfPages());
|
||||||
|
|
||||||
int type = request.getSplitType();
|
int type = request.getSplitType();
|
||||||
String value = request.getSplitValue();
|
String value = request.getSplitValue();
|
||||||
log.debug("Split type: {}, Split value: {}", type, value);
|
log.debug("Split type: {}, Split value: {}", type, value);
|
||||||
|
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
log.debug("Processing split by size");
|
log.debug("Processing split by size");
|
||||||
long maxBytes = GeneralUtils.convertSizeToBytes(value);
|
long maxBytes = GeneralUtils.convertSizeToBytes(value);
|
||||||
log.debug("Max bytes per document: {}", maxBytes);
|
log.debug("Max bytes per document: {}", maxBytes);
|
||||||
handleSplitBySize(sourceDocument, maxBytes, zipOut, filename);
|
handleSplitBySize(sourceDocument, maxBytes, zipOut, filename);
|
||||||
} else if (type == 1) {
|
} else if (type == 1) {
|
||||||
log.debug("Processing split by page count");
|
log.debug("Processing split by page count");
|
||||||
int pageCount = Integer.parseInt(value);
|
int pageCount = Integer.parseInt(value);
|
||||||
log.debug("Pages per document: {}", pageCount);
|
log.debug("Pages per document: {}", pageCount);
|
||||||
handleSplitByPageCount(sourceDocument, pageCount, zipOut, filename);
|
handleSplitByPageCount(sourceDocument, pageCount, zipOut, filename);
|
||||||
} else if (type == 2) {
|
} else if (type == 2) {
|
||||||
log.debug("Processing split by document count");
|
log.debug("Processing split by document count");
|
||||||
int documentCount = Integer.parseInt(value);
|
int documentCount = Integer.parseInt(value);
|
||||||
log.debug("Total number of documents: {}", documentCount);
|
log.debug("Total number of documents: {}", documentCount);
|
||||||
handleSplitByDocCount(sourceDocument, documentCount, zipOut, filename);
|
handleSplitByDocCount(sourceDocument, documentCount, zipOut, filename);
|
||||||
} else {
|
} else {
|
||||||
log.error("Invalid split type: {}", type);
|
log.error("Invalid split type: {}", type);
|
||||||
throw ExceptionUtils.createIllegalArgumentException(
|
throw ExceptionUtils.createIllegalArgumentException(
|
||||||
"error.invalidArgument",
|
"error.invalidArgument",
|
||||||
"Invalid argument: {0}",
|
"Invalid argument: {0}",
|
||||||
"split type: " + type);
|
"split type: " + type);
|
||||||
|
}
|
||||||
|
log.debug("PDF splitting completed successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("PDF splitting completed successfully");
|
|
||||||
} catch (Exception e) {
|
|
||||||
ExceptionUtils.logException("PDF document loading or processing", e);
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error creating or writing to ZIP file", e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
byte[] data = Files.readAllBytes(zipFile);
|
||||||
ExceptionUtils.logException("PDF splitting process", e);
|
|
||||||
throw e; // Re-throw to ensure proper error response
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
log.debug("Reading ZIP file data");
|
|
||||||
data = Files.readAllBytes(zipFile);
|
|
||||||
log.debug("Successfully read {} bytes from ZIP file", data.length);
|
log.debug("Successfully read {} bytes from ZIP file", data.length);
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error reading ZIP file data", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
log.debug("Returning response with {} bytes of data", data.length);
|
||||||
log.debug("Deleting temporary ZIP file");
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
boolean deleted = Files.deleteIfExists(zipFile);
|
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
log.debug("Temporary ZIP file deleted: {}", deleted);
|
} catch (Exception e) {
|
||||||
} catch (IOException e) {
|
ExceptionUtils.logException("PDF splitting process", e);
|
||||||
log.error("Error deleting temporary ZIP file", e);
|
throw e; // Re-throw to ensure proper error response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Returning response with {} bytes of data", data != null ? data.length : 0);
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
|
||||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSplitBySize(
|
private void handleSplitBySize(
|
||||||
|
@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
|
|||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -33,7 +34,7 @@ public class ToSinglePageController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-single-page")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf-to-single-page")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a multi-page PDF into a single long page PDF",
|
summary = "Convert a multi-page PDF into a single long page PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -40,7 +40,7 @@ public class ConvertEmlToPDF {
|
|||||||
private final TempFileManager tempFileManager;
|
private final TempFileManager tempFileManager;
|
||||||
private final CustomHtmlSanitizer customHtmlSanitizer;
|
private final CustomHtmlSanitizer customHtmlSanitizer;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/eml/pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/eml/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert EML to PDF",
|
summary = "Convert EML to PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.api.converters;
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -36,7 +37,7 @@ public class ConvertHtmlToPDF {
|
|||||||
|
|
||||||
private final CustomHtmlSanitizer customHtmlSanitizer;
|
private final CustomHtmlSanitizer customHtmlSanitizer;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/html/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
|
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -51,7 +51,7 @@ public class ConvertImgPDFController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/img")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/img")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to image(s)",
|
summary = "Convert PDF to image(s)",
|
||||||
description =
|
description =
|
||||||
@ -213,7 +213,7 @@ public class ConvertImgPDFController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/img/pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/img/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert images to a PDF file",
|
summary = "Convert images to a PDF file",
|
||||||
description =
|
description =
|
||||||
@ -244,7 +244,7 @@ public class ConvertImgPDFController {
|
|||||||
|
|
||||||
private String getMediaType(String imageFormat) {
|
private String getMediaType(String imageFormat) {
|
||||||
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
|
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
|
||||||
return "null".equals(mimeType) ? "application/octet-stream" : mimeType;
|
return "null".equals(mimeType) ? MediaType.APPLICATION_OCTET_STREAM_VALUE : mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +10,7 @@ import org.commonmark.node.Node;
|
|||||||
import org.commonmark.parser.Parser;
|
import org.commonmark.parser.Parser;
|
||||||
import org.commonmark.renderer.html.AttributeProvider;
|
import org.commonmark.renderer.html.AttributeProvider;
|
||||||
import org.commonmark.renderer.html.HtmlRenderer;
|
import org.commonmark.renderer.html.HtmlRenderer;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -45,7 +46,7 @@ public class ConvertMarkdownToPdf {
|
|||||||
|
|
||||||
private final CustomHtmlSanitizer customHtmlSanitizer;
|
private final CustomHtmlSanitizer customHtmlSanitizer;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/markdown/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a Markdown file to PDF",
|
summary = "Convert a Markdown file to PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -171,7 +172,7 @@ public class ConvertOfficeController {
|
|||||||
return fileExtension.matches(extensionPattern);
|
return fileExtension.matches(extensionPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/file/pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/file/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a file to a PDF using LibreOffice",
|
summary = "Convert a file to a PDF using LibreOffice",
|
||||||
description =
|
description =
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.api.converters;
|
package stirling.software.SPDF.controller.api.converters;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -18,7 +19,7 @@ import stirling.software.common.util.PDFToFile;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertPDFToHtml {
|
public class ConvertPDFToHtml {
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/html")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/html")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to HTML",
|
summary = "Convert PDF to HTML",
|
||||||
description =
|
description =
|
||||||
|
@ -34,7 +34,7 @@ public class ConvertPDFToOffice {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/presentation")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/presentation")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Presentation format",
|
summary = "Convert PDF to Presentation format",
|
||||||
description =
|
description =
|
||||||
@ -49,7 +49,7 @@ public class ConvertPDFToOffice {
|
|||||||
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
|
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/text")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/text")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Text or RTF format",
|
summary = "Convert PDF to Text or RTF format",
|
||||||
description =
|
description =
|
||||||
@ -77,7 +77,7 @@ public class ConvertPDFToOffice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/word")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/word")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Word document",
|
summary = "Convert PDF to Word document",
|
||||||
description =
|
description =
|
||||||
@ -91,7 +91,7 @@ public class ConvertPDFToOffice {
|
|||||||
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
|
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/xml")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/xml")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to XML",
|
summary = "Convert PDF to XML",
|
||||||
description =
|
description =
|
||||||
|
@ -78,7 +78,7 @@ import stirling.software.common.util.WebResponseUtils;
|
|||||||
@Tag(name = "Convert", description = "Convert APIs")
|
@Tag(name = "Convert", description = "Convert APIs")
|
||||||
public class ConvertPDFToPDFA {
|
public class ConvertPDFToPDFA {
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/pdfa")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a PDF to a PDF/A",
|
summary = "Convert a PDF to a PDF/A",
|
||||||
description =
|
description =
|
||||||
@ -89,7 +89,7 @@ public class ConvertPDFToPDFA {
|
|||||||
String outputFormat = request.getOutputFormat();
|
String outputFormat = request.getOutputFormat();
|
||||||
|
|
||||||
// Validate input file type
|
// Validate input file type
|
||||||
if (!"application/pdf".equals(inputFile.getContentType())) {
|
if (!MediaType.APPLICATION_PDF_VALUE.equals(inputFile.getContentType())) {
|
||||||
log.error("Invalid input file type: {}", inputFile.getContentType());
|
log.error("Invalid input file type: {}", inputFile.getContentType());
|
||||||
throw ExceptionUtils.createPdfFileRequiredException();
|
throw ExceptionUtils.createPdfFileRequiredException();
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -43,7 +44,7 @@ public class ConvertWebsiteToPDF {
|
|||||||
private final RuntimePathConfig runtimePathConfig;
|
private final RuntimePathConfig runtimePathConfig;
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/url/pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/url/pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert a URL to a PDF",
|
summary = "Convert a URL to a PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -46,7 +46,7 @@ public class ExtractCSVController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
|
@PostMapping(value = "/pdf/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extracts a CSV document from a PDF",
|
summary = "Extracts a CSV document from a PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -5,6 +5,7 @@ import java.io.IOException;
|
|||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -37,7 +38,7 @@ public class FilterController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-text")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-contains-text")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Checks if a PDF contains set text, returns true if does",
|
summary = "Checks if a PDF contains set text, returns true if does",
|
||||||
description = "Input:PDF Output:Boolean Type:SISO")
|
description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
@ -55,7 +56,7 @@ public class FilterController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/filter-contains-image")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-contains-image")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Checks if a PDF contains an image",
|
summary = "Checks if a PDF contains an image",
|
||||||
description = "Input:PDF Output:Boolean Type:SISO")
|
description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
@ -71,7 +72,7 @@ public class FilterController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-count")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-page-count")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Checks if a PDF is greater, less or equal to a setPageCount",
|
summary = "Checks if a PDF is greater, less or equal to a setPageCount",
|
||||||
description = "Input:PDF Output:Boolean Type:SISO")
|
description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
@ -104,7 +105,7 @@ public class FilterController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-size")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-page-size")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Checks if a PDF is of a certain size",
|
summary = "Checks if a PDF is of a certain size",
|
||||||
description = "Input:PDF Output:Boolean Type:SISO")
|
description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
@ -147,7 +148,7 @@ public class FilterController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/filter-file-size")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-file-size")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Checks if a PDF is a set file size",
|
summary = "Checks if a PDF is a set file size",
|
||||||
description = "Input:PDF Output:Boolean Type:SISO")
|
description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
@ -180,7 +181,7 @@ public class FilterController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/filter-page-rotation")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/filter-page-rotation")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Checks if a PDF is of a certain rotation",
|
summary = "Checks if a PDF is of a certain rotation",
|
||||||
description = "Input:PDF Output:Boolean Type:SISO")
|
description = "Input:PDF Output:Boolean Type:SISO")
|
||||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -34,7 +35,7 @@ public class AttachmentController {
|
|||||||
|
|
||||||
private final AttachmentServiceInterface pdfAttachmentService;
|
private final AttachmentServiceInterface pdfAttachmentService;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-attachments")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-attachments")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add attachments to PDF",
|
summary = "Add attachments to PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -8,6 +8,7 @@ import java.util.List;
|
|||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.text.PDFTextStripper;
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
import org.apache.pdfbox.text.TextPosition;
|
import org.apache.pdfbox.text.TextPosition;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -38,7 +39,7 @@ public class AutoRenameController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/auto-rename")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/auto-rename")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract header from PDF file",
|
summary = "Extract header from PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -6,7 +6,6 @@ import java.awt.image.DataBufferInt;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -36,6 +35,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
|
import stirling.software.common.util.TempFile;
|
||||||
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -53,6 +54,7 @@ public class AutoSplitPdfController {
|
|||||||
"https://stirlingpdf.com"));
|
"https://stirlingpdf.com"));
|
||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
private final TempFileManager tempFileManager;
|
||||||
|
|
||||||
private static String decodeQRCode(BufferedImage bufferedImage) {
|
private static String decodeQRCode(BufferedImage bufferedImage) {
|
||||||
LuminanceSource source;
|
LuminanceSource source;
|
||||||
@ -102,7 +104,7 @@ public class AutoSplitPdfController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
|
@PostMapping(value = "/auto-split-pdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Auto split PDF pages into separate documents",
|
summary = "Auto split PDF pages into separate documents",
|
||||||
description =
|
description =
|
||||||
@ -117,10 +119,10 @@ public class AutoSplitPdfController {
|
|||||||
|
|
||||||
PDDocument document = null;
|
PDDocument document = null;
|
||||||
List<PDDocument> splitDocuments = new ArrayList<>();
|
List<PDDocument> splitDocuments = new ArrayList<>();
|
||||||
Path zipFile = null;
|
TempFile outputTempFile = null;
|
||||||
byte[] data = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
outputTempFile = new TempFile(tempFileManager, ".zip");
|
||||||
document = pdfDocumentFactory.load(file.getInputStream());
|
document = pdfDocumentFactory.load(file.getInputStream());
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
pdfRenderer.setSubsamplingAllowed(true);
|
pdfRenderer.setSubsamplingAllowed(true);
|
||||||
@ -152,12 +154,12 @@ public class AutoSplitPdfController {
|
|||||||
// Remove split documents that have no pages
|
// Remove split documents that have no pages
|
||||||
splitDocuments.removeIf(pdDocument -> pdDocument.getNumberOfPages() == 0);
|
splitDocuments.removeIf(pdDocument -> pdDocument.getNumberOfPages() == 0);
|
||||||
|
|
||||||
zipFile = Files.createTempFile("split_documents", ".zip");
|
|
||||||
String filename =
|
String filename =
|
||||||
Filenames.toSimpleFileName(file.getOriginalFilename())
|
Filenames.toSimpleFileName(file.getOriginalFilename())
|
||||||
.replaceFirst("[.][^.]+$", "");
|
.replaceFirst("[.][^.]+$", "");
|
||||||
|
|
||||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
try (ZipOutputStream zipOut =
|
||||||
|
new ZipOutputStream(Files.newOutputStream(outputTempFile.getPath()))) {
|
||||||
for (int i = 0; i < splitDocuments.size(); i++) {
|
for (int i = 0; i < splitDocuments.size(); i++) {
|
||||||
String fileName = filename + "_" + (i + 1) + ".pdf";
|
String fileName = filename + "_" + (i + 1) + ".pdf";
|
||||||
PDDocument splitDocument = splitDocuments.get(i);
|
PDDocument splitDocument = splitDocuments.get(i);
|
||||||
@ -173,10 +175,10 @@ public class AutoSplitPdfController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data = Files.readAllBytes(zipFile);
|
byte[] data = Files.readAllBytes(outputTempFile.getPath());
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error in auto split", e);
|
log.error("Error in auto split", e);
|
||||||
throw e;
|
throw e;
|
||||||
@ -198,12 +200,8 @@ public class AutoSplitPdfController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zipFile != null) {
|
if (outputTempFile != null) {
|
||||||
try {
|
outputTempFile.close();
|
||||||
Files.deleteIfExists(zipFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error deleting temporary zip file", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class BlankPageController {
|
|||||||
return whitePixelPercentage >= whitePercent;
|
return whitePixelPercentage >= whitePercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-blanks")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove blank pages from a PDF file",
|
summary = "Remove blank pages from a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -32,6 +32,7 @@ import org.apache.pdfbox.pdmodel.PDResources;
|
|||||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -658,7 +659,7 @@ public class CompressController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/compress-pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Optimize PDF file",
|
summary = "Optimize PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -38,7 +38,7 @@ public class DecompressPdfController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/decompress-pdf", consumes = "multipart/form-data")
|
@PostMapping(value = "/decompress-pdf", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Decompress PDF streams",
|
summary = "Decompress PDF streams",
|
||||||
description = "Fully decompresses all PDF streams including text content")
|
description = "Fully decompresses all PDF streams including text content")
|
||||||
|
@ -50,7 +50,7 @@ public class ExtractImageScansController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/extract-image-scans")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/extract-image-scans")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract image scans from an input file",
|
summary = "Extract image scans from an input file",
|
||||||
description =
|
description =
|
||||||
|
@ -54,7 +54,7 @@ public class ExtractImagesController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/extract-images")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/extract-images")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Extract images from a PDF file",
|
summary = "Extract images from a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -11,6 +11,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
import org.apache.pdfbox.rendering.ImageType;
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -38,7 +39,7 @@ public class FlattenController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/flatten")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/flatten")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Flatten PDF form fields or full page",
|
summary = "Flatten PDF form fields or full page",
|
||||||
description =
|
description =
|
||||||
|
@ -10,6 +10,7 @@ import java.util.Map.Entry;
|
|||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -51,7 +52,7 @@ public class MetadataController {
|
|||||||
binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor());
|
binder.registerCustomEditor(Map.class, "allRequestParams", new StringToMapPropertyEditor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/update-metadata")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Update metadata of a PDF file",
|
summary = "Update metadata of a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -76,7 +76,7 @@ public class OCRController {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/ocr-pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Process a PDF file with OCR",
|
summary = "Process a PDF file with OCR",
|
||||||
description =
|
description =
|
||||||
|
@ -3,6 +3,7 @@ package stirling.software.SPDF.controller.api.misc;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -31,7 +32,7 @@ public class OverlayImageController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-image")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-image")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Overlay image onto a PDF file",
|
summary = "Overlay image onto a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -39,7 +39,7 @@ public class PageNumbersController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(value = "/add-page-numbers", consumes = "multipart/form-data")
|
@PostMapping(value = "/add-page-numbers", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add page numbers to a PDF document",
|
summary = "Add page numbers to a PDF document",
|
||||||
description =
|
description =
|
||||||
|
@ -18,6 +18,7 @@ import org.apache.pdfbox.Loader;
|
|||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.printing.PDFPageable;
|
import org.apache.pdfbox.printing.PDFPageable;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -37,7 +38,7 @@ import stirling.software.SPDF.model.api.misc.PrintFileRequest;
|
|||||||
public class PrintFileController {
|
public class PrintFileController {
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// @PostMapping(value = "/print-file", consumes = "multipart/form-data")
|
// @PostMapping(value = "/print-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
// @Operation(
|
// @Operation(
|
||||||
// summary = "Prints PDF/Image file to a set printer",
|
// summary = "Prints PDF/Image file to a set printer",
|
||||||
// description =
|
// description =
|
||||||
@ -69,7 +70,7 @@ public class PrintFileController {
|
|||||||
|
|
||||||
log.info("Selected Printer: " + selectedService.getName());
|
log.info("Selected Printer: " + selectedService.getName());
|
||||||
|
|
||||||
if ("application/pdf".equals(contentType)) {
|
if (MediaType.APPLICATION_PDF_VALUE.equals(contentType)) {
|
||||||
PDDocument document = Loader.loadPDF(file.getBytes());
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
PrinterJob job = PrinterJob.getPrinterJob();
|
PrinterJob job = PrinterJob.getPrinterJob();
|
||||||
job.setPrintService(selectedService);
|
job.setPrintService(selectedService);
|
||||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -46,7 +47,7 @@ public class RepairController {
|
|||||||
return endpointConfiguration.isGroupEnabled("qpdf");
|
return endpointConfiguration.isGroupEnabled("qpdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/repair")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/repair")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Repair a PDF file",
|
summary = "Repair a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -27,7 +27,7 @@ public class ReplaceAndInvertColorController {
|
|||||||
|
|
||||||
private final ReplaceAndInvertColorService replaceAndInvertColorService;
|
private final ReplaceAndInvertColorService replaceAndInvertColorService;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/replace-invert-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/replace-invert-pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Replace-Invert Color PDF",
|
summary = "Replace-Invert Color PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -52,7 +52,7 @@ public class ScannerEffectController {
|
|||||||
private static final int MAX_IMAGE_HEIGHT = 8192;
|
private static final int MAX_IMAGE_HEIGHT = 8192;
|
||||||
private static final long MAX_IMAGE_PIXELS = 16_777_216; // 4096x4096
|
private static final long MAX_IMAGE_PIXELS = 16_777_216; // 4096x4096
|
||||||
|
|
||||||
@PostMapping(value = "/scanner-effect", consumes = "multipart/form-data")
|
@PostMapping(value = "/scanner-effect", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Apply scanner effect to PDF",
|
summary = "Apply scanner effect to PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -32,7 +32,7 @@ public class ShowJavascript {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/show-javascript")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/show-javascript")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Grabs all JS from a PDF and returns a single JS file with all code",
|
summary = "Grabs all JS from a PDF and returns a single JS file with all code",
|
||||||
description = "desc. Input:PDF Output:JS Type:SISO")
|
description = "desc. Input:PDF Output:JS Type:SISO")
|
||||||
|
@ -25,6 +25,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|||||||
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
@ -72,7 +73,7 @@ public class StampController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-stamp")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-stamp")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add stamp to a PDF file",
|
summary = "Add stamp to a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -10,6 +10,7 @@ import org.apache.pdfbox.pdmodel.PDDocument;
|
|||||||
import org.apache.pdfbox.pdmodel.common.PDStream;
|
import org.apache.pdfbox.pdmodel.common.PDStream;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -37,7 +38,7 @@ public class UnlockPDFFormsController {
|
|||||||
this.pdfDocumentFactory = pdfDocumentFactory;
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/unlock-pdf-forms")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/unlock-pdf-forms")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove read-only property from form fields",
|
summary = "Remove read-only property from form fields",
|
||||||
description =
|
description =
|
||||||
|
@ -188,7 +188,7 @@ public class GetInfoOnPDF {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/get-info-on-pdf")
|
||||||
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
|
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
|
||||||
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
|
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
|
||||||
MultipartFile inputFile = request.getFileInput();
|
MultipartFile inputFile = request.getFileInput();
|
||||||
|
@ -5,6 +5,7 @@ import java.io.IOException;
|
|||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
|
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
|
||||||
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
|
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -32,7 +33,7 @@ public class PasswordController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-password")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove password from a PDF file",
|
summary = "Remove password from a PDF file",
|
||||||
description =
|
description =
|
||||||
@ -58,7 +59,7 @@ public class PasswordController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-password")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add password to a PDF file",
|
summary = "Add password to a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -34,6 +34,7 @@ import org.apache.pdfbox.pdmodel.common.PDStream;
|
|||||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
@ -97,7 +98,7 @@ public class RedactController {
|
|||||||
List.class, "redactions", new StringToArrayListPropertyEditor());
|
List.class, "redactions", new StringToArrayListPropertyEditor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/redact", consumes = "multipart/form-data")
|
@PostMapping(value = "/redact", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Redact PDF manually",
|
summary = "Redact PDF manually",
|
||||||
description =
|
description =
|
||||||
@ -494,7 +495,7 @@ public class RedactController {
|
|||||||
return pageNumbers;
|
return pageNumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/auto-redact", consumes = "multipart/form-data")
|
@PostMapping(value = "/auto-redact", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Redact PDF automatically",
|
summary = "Redact PDF automatically",
|
||||||
description =
|
description =
|
||||||
|
@ -7,6 +7,7 @@ import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
|||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -32,7 +33,7 @@ public class RemoveCertSignController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-cert-sign")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Remove digital signature from PDF",
|
summary = "Remove digital signature from PDF",
|
||||||
description =
|
description =
|
||||||
|
@ -21,6 +21,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
|
|||||||
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
|
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -46,7 +47,7 @@ public class SanitizeController {
|
|||||||
|
|
||||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/sanitize-pdf")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Sanitize a PDF file",
|
summary = "Sanitize a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -24,6 +24,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|||||||
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||||
import org.apache.pdfbox.util.Matrix;
|
import org.apache.pdfbox.util.Matrix;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
@ -64,7 +65,7 @@ public class WatermarkController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/add-watermark")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Add watermark to a PDF file",
|
summary = "Add watermark to a PDF file",
|
||||||
description =
|
description =
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.model.api.converters;
|
package stirling.software.SPDF.model.api.converters;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -18,7 +19,7 @@ import stirling.software.common.util.PDFToFile;
|
|||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
public class ConvertPDFToMarkdown {
|
public class ConvertPDFToMarkdown {
|
||||||
|
|
||||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf/markdown")
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/markdown")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Convert PDF to Markdown",
|
summary = "Convert PDF to Markdown",
|
||||||
description =
|
description =
|
||||||
|
@ -260,7 +260,7 @@ public class JobController {
|
|||||||
"fileName",
|
"fileName",
|
||||||
"unknown",
|
"unknown",
|
||||||
"contentType",
|
"contentType",
|
||||||
"application/octet-stream",
|
MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||||
"fileSize",
|
"fileSize",
|
||||||
fileSize));
|
fileSize));
|
||||||
}
|
}
|
||||||
@ -295,7 +295,9 @@ public class JobController {
|
|||||||
|
|
||||||
String fileName = resultFile != null ? resultFile.getFileName() : "download";
|
String fileName = resultFile != null ? resultFile.getFileName() : "download";
|
||||||
String contentType =
|
String contentType =
|
||||||
resultFile != null ? resultFile.getContentType() : "application/octet-stream";
|
resultFile != null
|
||||||
|
? resultFile.getContentType()
|
||||||
|
: MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||||
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header("Content-Type", contentType)
|
.header("Content-Type", contentType)
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=حجم الخط
|
addPageNumbers.fontSize=حجم الخط
|
||||||
addPageNumbers.fontName=اسم الخط
|
addPageNumbers.fontName=اسم الخط
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=اختر PDF
|
pdfPrompt=اختر PDF
|
||||||
multiPdfPrompt=اختر ملفات PDF (2+)
|
multiPdfPrompt=اختر ملفات PDF (2+)
|
||||||
multiPdfDropPrompt=حدد (أو اسحب وأفلت) جميع ملفات PDF التي تحتاجها
|
multiPdfDropPrompt=حدد (أو اسحب وأفلت) جميع ملفات PDF التي تحتاجها
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Şrift Ölçüsü
|
addPageNumbers.fontSize=Şrift Ölçüsü
|
||||||
addPageNumbers.fontName=Şrift Adı
|
addPageNumbers.fontName=Şrift Adı
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDF(lər)i Seç
|
pdfPrompt=PDF(lər)i Seç
|
||||||
multiPdfPrompt=PDFləri Seç (2+)
|
multiPdfPrompt=PDFləri Seç (2+)
|
||||||
multiPdfDropPrompt=Ehtiyacınız olan bütün PDFləri seçin (və ya sürükləyib buraxın)
|
multiPdfDropPrompt=Ehtiyacınız olan bütün PDFləri seçin (və ya sürükləyib buraxın)
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Размер на шрифт
|
addPageNumbers.fontSize=Размер на шрифт
|
||||||
addPageNumbers.fontName=Име на шрифт
|
addPageNumbers.fontName=Име на шрифт
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Изберете PDF(и)
|
pdfPrompt=Изберете PDF(и)
|
||||||
multiPdfPrompt=Изберете PDF (2+)
|
multiPdfPrompt=Изберете PDF (2+)
|
||||||
multiPdfDropPrompt=Изберете (или плъзнете и пуснете) всички PDF файлове, от които се нуждаете
|
multiPdfDropPrompt=Изберете (или плъзнете и пуснете) всички PDF файлове, от които се нуждаете
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=ཡིག་གཟུགས་ཆེ་ཆུང་
|
addPageNumbers.fontSize=ཡིག་གཟུགས་ཆེ་ཆུང་
|
||||||
addPageNumbers.fontName=ཡིག་གཟུགས་མིང་
|
addPageNumbers.fontName=ཡིག་གཟུགས་མིང་
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDF འདེམས་རོགས།
|
pdfPrompt=PDF འདེམས་རོགས།
|
||||||
multiPdfPrompt=PDF གཉིས་ཡན་འདེམས་རོགས།
|
multiPdfPrompt=PDF གཉིས་ཡན་འདེམས་རོགས།
|
||||||
multiPdfDropPrompt=དགོས་མཁོ་འདི་ PDF ཡིག་ཆ་ཚང་མ་འདེམས་པའམ་འཐེན་རོགས།
|
multiPdfDropPrompt=དགོས་མཁོ་འདི་ PDF ཡིག་ཆ་ཚང་མ་འདེམས་པའམ་འཐེན་རོགས།
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Mida del tipus de lletra
|
addPageNumbers.fontSize=Mida del tipus de lletra
|
||||||
addPageNumbers.fontName=Nom del tipus de lletra
|
addPageNumbers.fontName=Nom del tipus de lletra
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Selecciona PDF(s)
|
pdfPrompt=Selecciona PDF(s)
|
||||||
multiPdfPrompt=Selecciona PDFs (2+)
|
multiPdfPrompt=Selecciona PDFs (2+)
|
||||||
multiPdfDropPrompt=Selecciona (o arrossega) els documents PDF
|
multiPdfDropPrompt=Selecciona (o arrossega) els documents PDF
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Velikost písma
|
addPageNumbers.fontSize=Velikost písma
|
||||||
addPageNumbers.fontName=Název písma
|
addPageNumbers.fontName=Název písma
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Vyberte PDF soubor(y)
|
pdfPrompt=Vyberte PDF soubor(y)
|
||||||
multiPdfPrompt=Vyberte PDF soubory (2+)
|
multiPdfPrompt=Vyberte PDF soubory (2+)
|
||||||
multiPdfDropPrompt=Vyberte (nebo přetáhněte) všechny požadované PDF soubory
|
multiPdfDropPrompt=Vyberte (nebo přetáhněte) všechny požadované PDF soubory
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Skriftstørrelse
|
addPageNumbers.fontSize=Skriftstørrelse
|
||||||
addPageNumbers.fontName=Skriftnavn
|
addPageNumbers.fontName=Skriftnavn
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Vælg PDF-fil(er)
|
pdfPrompt=Vælg PDF-fil(er)
|
||||||
multiPdfPrompt=Vælg PDF-filerne (2+)
|
multiPdfPrompt=Vælg PDF-filerne (2+)
|
||||||
multiPdfDropPrompt=Vælg (eller drag & drop) alle PDF-filerne du skal bruge
|
multiPdfDropPrompt=Vælg (eller drag & drop) alle PDF-filerne du skal bruge
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Schriftgröße
|
addPageNumbers.fontSize=Schriftgröße
|
||||||
addPageNumbers.fontName=Schriftart
|
addPageNumbers.fontName=Schriftart
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDF(s) auswählen
|
pdfPrompt=PDF(s) auswählen
|
||||||
multiPdfPrompt=PDFs auswählen (2+)
|
multiPdfPrompt=PDFs auswählen (2+)
|
||||||
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
|
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Μέγεθος γραμματοσειράς
|
addPageNumbers.fontSize=Μέγεθος γραμματοσειράς
|
||||||
addPageNumbers.fontName=Όνομα γραμματοσειράς
|
addPageNumbers.fontName=Όνομα γραμματοσειράς
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Επιλέξτε PDF(s)
|
pdfPrompt=Επιλέξτε PDF(s)
|
||||||
multiPdfPrompt=Επιλέξτε PDFs (2+)
|
multiPdfPrompt=Επιλέξτε PDFs (2+)
|
||||||
multiPdfDropPrompt=Επιλέξτε (ή σύρετε & αφήστε) όλα τα PDF που χρειάζεστε
|
multiPdfDropPrompt=Επιλέξτε (ή σύρετε & αφήστε) όλα τα PDF που χρειάζεστε
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Font Size
|
addPageNumbers.fontSize=Font Size
|
||||||
addPageNumbers.fontName=Font Name
|
addPageNumbers.fontName=Font Name
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Select PDF(s)
|
pdfPrompt=Select PDF(s)
|
||||||
multiPdfPrompt=Select PDFs (2+)
|
multiPdfPrompt=Select PDFs (2+)
|
||||||
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Tamaño de Letra
|
addPageNumbers.fontSize=Tamaño de Letra
|
||||||
addPageNumbers.fontName=Nombre de Letra
|
addPageNumbers.fontName=Nombre de Letra
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Seleccionar PDF(s)
|
pdfPrompt=Seleccionar PDF(s)
|
||||||
multiPdfPrompt=Seleccionar PDFs (2+)
|
multiPdfPrompt=Seleccionar PDFs (2+)
|
||||||
multiPdfDropPrompt=Seleccione (o arrastre y suelte) todos los PDFs que quiera
|
multiPdfDropPrompt=Seleccione (o arrastre y suelte) todos los PDFs que quiera
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Font Size
|
addPageNumbers.fontSize=Font Size
|
||||||
addPageNumbers.fontName=Font Name
|
addPageNumbers.fontName=Font Name
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Hautatu PDFa(k)
|
pdfPrompt=Hautatu PDFa(k)
|
||||||
multiPdfPrompt=Hautatu PDFak (2+)
|
multiPdfPrompt=Hautatu PDFak (2+)
|
||||||
multiPdfDropPrompt=Hautatu (edo arrastatu eta jaregin) nahi dituzun PDFak
|
multiPdfDropPrompt=Hautatu (edo arrastatu eta jaregin) nahi dituzun PDFak
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=اندازه فونت
|
addPageNumbers.fontSize=اندازه فونت
|
||||||
addPageNumbers.fontName=نام فونت
|
addPageNumbers.fontName=نام فونت
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=انتخاب فایل(های) PDF
|
pdfPrompt=انتخاب فایل(های) PDF
|
||||||
multiPdfPrompt=انتخاب فایلهای PDF (دو یا بیشتر)
|
multiPdfPrompt=انتخاب فایلهای PDF (دو یا بیشتر)
|
||||||
multiPdfDropPrompt=انتخاب (یا کشیدن و رها کردن) تمام فایلهای PDF مورد نیاز
|
multiPdfDropPrompt=انتخاب (یا کشیدن و رها کردن) تمام فایلهای PDF مورد نیاز
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Taille de Police
|
addPageNumbers.fontSize=Taille de Police
|
||||||
addPageNumbers.fontName=Nom de la Police
|
addPageNumbers.fontName=Nom de la Police
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Sélectionnez le(s) PDF
|
pdfPrompt=Sélectionnez le(s) PDF
|
||||||
multiPdfPrompt=Sélectionnez les PDF
|
multiPdfPrompt=Sélectionnez les PDF
|
||||||
multiPdfDropPrompt=Sélectionnez (ou glissez-déposez) tous les PDF dont vous avez besoin
|
multiPdfDropPrompt=Sélectionnez (ou glissez-déposez) tous les PDF dont vous avez besoin
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Méid an Chló
|
addPageNumbers.fontSize=Méid an Chló
|
||||||
addPageNumbers.fontName=Ainm Cló
|
addPageNumbers.fontName=Ainm Cló
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Roghnaigh PDF(anna)
|
pdfPrompt=Roghnaigh PDF(anna)
|
||||||
multiPdfPrompt=Roghnaigh PDFs (2+)
|
multiPdfPrompt=Roghnaigh PDFs (2+)
|
||||||
multiPdfDropPrompt=Roghnaigh (nó tarraing & scaoil) gach PDF atá uait
|
multiPdfDropPrompt=Roghnaigh (nó tarraing & scaoil) gach PDF atá uait
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=फ़ॉन्ट आकार
|
addPageNumbers.fontSize=फ़ॉन्ट आकार
|
||||||
addPageNumbers.fontName=फ़ॉन्ट नाम
|
addPageNumbers.fontName=फ़ॉन्ट नाम
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=पीडीएफ फ़ाइल(ें) चुनें
|
pdfPrompt=पीडीएफ फ़ाइल(ें) चुनें
|
||||||
multiPdfPrompt=पीडीएफ फ़ाइलें चुनें (2+)
|
multiPdfPrompt=पीडीएफ फ़ाइलें चुनें (2+)
|
||||||
multiPdfDropPrompt=आवश्यक सभी पीडीएफ फ़ाइलों को चुनें (या खींच कर छोड़ें)
|
multiPdfDropPrompt=आवश्यक सभी पीडीएफ फ़ाइलों को चुनें (या खींच कर छोड़ें)
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Veličina pisma
|
addPageNumbers.fontSize=Veličina pisma
|
||||||
addPageNumbers.fontName=Ime pisma
|
addPageNumbers.fontName=Ime pisma
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Odaberi PDF(ove)
|
pdfPrompt=Odaberi PDF(ove)
|
||||||
multiPdfPrompt=Odaberi PDF-ove (2+)
|
multiPdfPrompt=Odaberi PDF-ove (2+)
|
||||||
multiPdfDropPrompt=Odaberi (ili povuci i ispusti) sve potrebne PDF-ove
|
multiPdfDropPrompt=Odaberi (ili povuci i ispusti) sve potrebne PDF-ove
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=joruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Betűméret
|
addPageNumbers.fontSize=Betűméret
|
||||||
addPageNumbers.fontName=Betűtípus
|
addPageNumbers.fontName=Betűtípus
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDF-fájl kiválasztása
|
pdfPrompt=PDF-fájl kiválasztása
|
||||||
multiPdfPrompt=PDF-fájlok kiválasztása (2+)
|
multiPdfPrompt=PDF-fájlok kiválasztása (2+)
|
||||||
multiPdfDropPrompt=Válassza ki (vagy húzza ide) az összes szükséges PDF-fájlt
|
multiPdfDropPrompt=Válassza ki (vagy húzza ide) az összes szükséges PDF-fájlt
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Ukuran Fonta
|
addPageNumbers.fontSize=Ukuran Fonta
|
||||||
addPageNumbers.fontName=Nama Fonta
|
addPageNumbers.fontName=Nama Fonta
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Pilih PDF
|
pdfPrompt=Pilih PDF
|
||||||
multiPdfPrompt=Pilih PDF (2+)
|
multiPdfPrompt=Pilih PDF (2+)
|
||||||
multiPdfDropPrompt=Pilih (atau seret & letakkan)) semua PDF yang Anda butuhkan
|
multiPdfDropPrompt=Pilih (atau seret & letakkan)) semua PDF yang Anda butuhkan
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Dimensione del font
|
addPageNumbers.fontSize=Dimensione del font
|
||||||
addPageNumbers.fontName=Nome del font
|
addPageNumbers.fontName=Nome del font
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Scegli PDF
|
pdfPrompt=Scegli PDF
|
||||||
multiPdfPrompt=Scegli 2 o più PDF
|
multiPdfPrompt=Scegli 2 o più PDF
|
||||||
multiPdfDropPrompt=Scegli (o trascina e rilascia) uno o più PDF
|
multiPdfDropPrompt=Scegli (o trascina e rilascia) uno o più PDF
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=ヨルバ語
|
|||||||
|
|
||||||
addPageNumbers.fontSize=フォントサイズ
|
addPageNumbers.fontSize=フォントサイズ
|
||||||
addPageNumbers.fontName=フォント名
|
addPageNumbers.fontName=フォント名
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDFを選択
|
pdfPrompt=PDFを選択
|
||||||
multiPdfPrompt=PDFを選択(2つ以上)
|
multiPdfPrompt=PDFを選択(2つ以上)
|
||||||
multiPdfDropPrompt=PDFを選択(又はドラッグ&ドロップ)
|
multiPdfDropPrompt=PDFを選択(又はドラッグ&ドロップ)
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=글꼴 크기
|
addPageNumbers.fontSize=글꼴 크기
|
||||||
addPageNumbers.fontName=글꼴 이름
|
addPageNumbers.fontName=글꼴 이름
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDF 선택
|
pdfPrompt=PDF 선택
|
||||||
multiPdfPrompt=PDF 선택 (2개 이상)
|
multiPdfPrompt=PDF 선택 (2개 이상)
|
||||||
multiPdfDropPrompt=필요한 모든 PDF를 선택(또는 끌어다 놓기)하세요
|
multiPdfDropPrompt=필요한 모든 PDF를 선택(또는 끌어다 놓기)하세요
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=അക്ഷര വലുപ്പം
|
addPageNumbers.fontSize=അക്ഷര വലുപ്പം
|
||||||
addPageNumbers.fontName=അക്ഷരത്തിന്റെ പേര്
|
addPageNumbers.fontName=അക്ഷരത്തിന്റെ പേര്
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=PDF(കൾ) തിരഞ്ഞെടുക്കുക
|
pdfPrompt=PDF(കൾ) തിരഞ്ഞെടുക്കുക
|
||||||
multiPdfPrompt=PDF-കൾ തിരഞ്ഞെടുക്കുക (2+)
|
multiPdfPrompt=PDF-കൾ തിരഞ്ഞെടുക്കുക (2+)
|
||||||
multiPdfDropPrompt=നിങ്ങൾക്ക് ആവശ്യമുള്ള എല്ലാ PDF-കളും തിരഞ്ഞെടുക്കുക (അല്ലെങ്കിൽ വലിച്ചിടുക)
|
multiPdfDropPrompt=നിങ്ങൾക്ക് ആവശ്യമുള്ള എല്ലാ PDF-കളും തിരഞ്ഞെടുക്കുക (അല്ലെങ്കിൽ വലിച്ചിടുക)
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Lettertypegrootte
|
addPageNumbers.fontSize=Lettertypegrootte
|
||||||
addPageNumbers.fontName=Lettertypenaam
|
addPageNumbers.fontName=Lettertypenaam
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Selecteer PDF('s)
|
pdfPrompt=Selecteer PDF('s)
|
||||||
multiPdfPrompt=Selecteer PDF's (2+)
|
multiPdfPrompt=Selecteer PDF's (2+)
|
||||||
multiPdfDropPrompt=Selecteer (of sleep & zet neer) alle PDF's die je nodig hebt
|
multiPdfDropPrompt=Selecteer (of sleep & zet neer) alle PDF's die je nodig hebt
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Skriftstørrelse
|
addPageNumbers.fontSize=Skriftstørrelse
|
||||||
addPageNumbers.fontName=Skrifttype
|
addPageNumbers.fontName=Skrifttype
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Velg PDF(er)
|
pdfPrompt=Velg PDF(er)
|
||||||
multiPdfPrompt=Velg PDF-filer (2+)
|
multiPdfPrompt=Velg PDF-filer (2+)
|
||||||
multiPdfDropPrompt=Velg (eller dra og slipp) alle PDF-ene du trenger
|
multiPdfDropPrompt=Velg (eller dra og slipp) alle PDF-ene du trenger
|
||||||
|
@ -137,6 +137,7 @@ lang.yor=Yoruba
|
|||||||
|
|
||||||
addPageNumbers.fontSize=Rozmiar Czcionki
|
addPageNumbers.fontSize=Rozmiar Czcionki
|
||||||
addPageNumbers.fontName=Nazwa Czcionki
|
addPageNumbers.fontName=Nazwa Czcionki
|
||||||
|
addPageNumbers.fontColor=Font Colour
|
||||||
pdfPrompt=Wybierz PDF
|
pdfPrompt=Wybierz PDF
|
||||||
multiPdfPrompt=Wybierz PDF (2+)
|
multiPdfPrompt=Wybierz PDF (2+)
|
||||||
multiPdfDropPrompt=Wybierz (lub przeciągnij i puść) wszystkie dokumenty PDF
|
multiPdfDropPrompt=Wybierz (lub przeciągnij i puść) wszystkie dokumenty PDF
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user