fixes
This commit is contained in:
parent
2c0fb33548
commit
82b641458f
23 changed files with 121 additions and 100 deletions
|
@ -39,63 +39,69 @@ public class MultiPageLayoutController {
|
|||
)
|
||||
public ResponseEntity<byte[]> mergeMultiplePagesIntoOne(@ModelAttribute MergeMultiplePagesRequest request)
|
||||
throws IOException {
|
||||
|
||||
int pagesPerSheet = request.getPagesPerSheet();
|
||||
MultipartFile file = request.getFileInput();
|
||||
if (pagesPerSheet != 2 && pagesPerSheet != 3 && pagesPerSheet != (int) Math.sqrt(pagesPerSheet) * Math.sqrt(pagesPerSheet)) {
|
||||
throw new IllegalArgumentException("pagesPerSheet must be 2, 3 or a perfect square");
|
||||
}
|
||||
|
||||
int cols = pagesPerSheet == 2 || pagesPerSheet == 3 ? pagesPerSheet : (int) Math.sqrt(pagesPerSheet);
|
||||
int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet);
|
||||
int pagesPerSheet = request.getPagesPerSheet();
|
||||
MultipartFile file = request.getFileInput();
|
||||
|
||||
PDDocument sourceDocument = PDDocument.load(file.getInputStream());
|
||||
PDDocument newDocument = new PDDocument();
|
||||
PDPage newPage = new PDPage(PDRectangle.A4);
|
||||
newDocument.addPage(newPage);
|
||||
if (pagesPerSheet != 2 && pagesPerSheet != 3 && pagesPerSheet != (int) Math.sqrt(pagesPerSheet) * Math.sqrt(pagesPerSheet)) {
|
||||
throw new IllegalArgumentException("pagesPerSheet must be 2, 3 or a perfect square");
|
||||
}
|
||||
|
||||
int totalPages = sourceDocument.getNumberOfPages();
|
||||
float cellWidth = newPage.getMediaBox().getWidth() / cols;
|
||||
float cellHeight = newPage.getMediaBox().getHeight() / rows;
|
||||
int cols = pagesPerSheet == 2 || pagesPerSheet == 3 ? pagesPerSheet : (int) Math.sqrt(pagesPerSheet);
|
||||
int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet);
|
||||
|
||||
PDPageContentStream contentStream = new PDPageContentStream(newDocument, newPage, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||
PDDocument sourceDocument = PDDocument.load(file.getInputStream());
|
||||
PDDocument newDocument = new PDDocument();
|
||||
PDPage newPage = new PDPage(PDRectangle.A4);
|
||||
newDocument.addPage(newPage);
|
||||
|
||||
LayerUtility layerUtility = new LayerUtility(newDocument);
|
||||
int totalPages = sourceDocument.getNumberOfPages();
|
||||
float cellWidth = newPage.getMediaBox().getWidth() / cols;
|
||||
float cellHeight = newPage.getMediaBox().getHeight() / rows;
|
||||
|
||||
for (int i = 0; i < totalPages; i++) {
|
||||
PDPage sourcePage = sourceDocument.getPage(i);
|
||||
System.out.println("Reading page " + (i+1));
|
||||
PDRectangle rect = sourcePage.getMediaBox();
|
||||
float scaleWidth = cellWidth / rect.getWidth();
|
||||
float scaleHeight = cellHeight / rect.getHeight();
|
||||
float scale = Math.min(scaleWidth, scaleHeight);
|
||||
System.out.println("Scale for page " + (i+1) + ": " + scale);
|
||||
PDPageContentStream contentStream = new PDPageContentStream(newDocument, newPage, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||
LayerUtility layerUtility = new LayerUtility(newDocument);
|
||||
|
||||
for (int i = 0; i < totalPages; i++) {
|
||||
if (i != 0 && i % pagesPerSheet == 0) {
|
||||
// Close the current content stream and create a new page and content stream
|
||||
contentStream.close();
|
||||
newPage = new PDPage(PDRectangle.A4);
|
||||
newDocument.addPage(newPage);
|
||||
contentStream = new PDPageContentStream(newDocument, newPage, PDPageContentStream.AppendMode.APPEND, true, true);
|
||||
}
|
||||
|
||||
PDPage sourcePage = sourceDocument.getPage(i);
|
||||
PDRectangle rect = sourcePage.getMediaBox();
|
||||
float scaleWidth = cellWidth / rect.getWidth();
|
||||
float scaleHeight = cellHeight / rect.getHeight();
|
||||
float scale = Math.min(scaleWidth, scaleHeight);
|
||||
|
||||
int adjustedPageIndex = i % pagesPerSheet; // This will reset the index for every new page
|
||||
int rowIndex = adjustedPageIndex / cols;
|
||||
int colIndex = adjustedPageIndex % cols;
|
||||
|
||||
float x = colIndex * cellWidth + (cellWidth - rect.getWidth() * scale) / 2;
|
||||
float y = newPage.getMediaBox().getHeight() - ((rowIndex + 1) * cellHeight - (cellHeight - rect.getHeight() * scale) / 2);
|
||||
|
||||
contentStream.saveGraphicsState();
|
||||
contentStream.transform(Matrix.getTranslateInstance(x, y));
|
||||
contentStream.transform(Matrix.getScaleInstance(scale, scale));
|
||||
|
||||
PDFormXObject formXObject = layerUtility.importPageAsForm(sourceDocument, i);
|
||||
contentStream.drawForm(formXObject);
|
||||
|
||||
contentStream.restoreGraphicsState();
|
||||
}
|
||||
|
||||
|
||||
int rowIndex = i / cols;
|
||||
int colIndex = i % cols;
|
||||
contentStream.close(); // Close the final content stream
|
||||
sourceDocument.close();
|
||||
|
||||
float x = colIndex * cellWidth + (cellWidth - rect.getWidth() * scale) / 2;
|
||||
float y = newPage.getMediaBox().getHeight() - ((rowIndex + 1) * cellHeight - (cellHeight - rect.getHeight() * scale) / 2);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
newDocument.save(baos);
|
||||
newDocument.close();
|
||||
|
||||
contentStream.saveGraphicsState();
|
||||
contentStream.transform(Matrix.getTranslateInstance(x, y));
|
||||
contentStream.transform(Matrix.getScaleInstance(scale, scale));
|
||||
|
||||
PDFormXObject formXObject = layerUtility.importPageAsForm(sourceDocument, i);
|
||||
contentStream.drawForm(formXObject);
|
||||
|
||||
contentStream.restoreGraphicsState();
|
||||
}
|
||||
|
||||
|
||||
contentStream.close();
|
||||
sourceDocument.close();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
newDocument.save(baos);
|
||||
newDocument.close();
|
||||
|
||||
byte[] result = baos.toByteArray();
|
||||
return WebResponseUtils.bytesToWebResponse(result, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_layoutChanged.pdf");
|
||||
}
|
||||
|
|
|
@ -186,7 +186,8 @@ public class RearrangePagesPDFController {
|
|||
} else {
|
||||
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages);
|
||||
}
|
||||
|
||||
logger.info("newPageOrder = " +newPageOrder);
|
||||
logger.info("totalPages = " +totalPages);
|
||||
// Create a new list to hold the pages in the new order
|
||||
List<PDPage> newPages = new ArrayList<>();
|
||||
for (int i = 0; i < newPageOrder.size(); i++) {
|
||||
|
|
|
@ -36,7 +36,7 @@ public class ScalePagesController {
|
|||
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> scalePages(@ModelAttribute ScalePagesRequest request) throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String targetPDRectangle = request.getTargetPDRectangle();
|
||||
String targetPDRectangle = request.getPageSize();
|
||||
float scaleFactor = request.getScaleFactor();
|
||||
|
||||
Map<String, PDRectangle> sizeMap = new HashMap<>();
|
||||
|
|
|
@ -35,7 +35,7 @@ public class AutoRenameController {
|
|||
@Operation(summary = "Extract header from PDF file", description = "This endpoint accepts a PDF file and attempts to extract its title or header based on heuristics. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> extractHeader(@ModelAttribute ExtractHeaderRequest request) throws Exception {
|
||||
MultipartFile file = request.getFileInput();
|
||||
Boolean useFirstTextAsFallback = request.getUseFirstTextAsFallback();
|
||||
Boolean useFirstTextAsFallback = request.isUseFirstTextAsFallback();
|
||||
|
||||
PDDocument document = PDDocument.load(file.getInputStream());
|
||||
PDFTextStripper reader = new PDFTextStripper() {
|
||||
|
|
|
@ -48,7 +48,7 @@ public class CompressController {
|
|||
public ResponseEntity<byte[]> optimizePdf(@ModelAttribute OptimizePdfRequest request) throws Exception {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
Integer optimizeLevel = request.getOptimizeLevel();
|
||||
String expectedOutputSizeString = request.getExpectedOutputSizeString();
|
||||
String expectedOutputSizeString = request.getExpectedOutputSize();
|
||||
|
||||
|
||||
if(expectedOutputSizeString == null && optimizeLevel == null) {
|
||||
|
|
|
@ -48,7 +48,7 @@ public class MetadataController {
|
|||
MultipartFile pdfFile = request.getFileInput();
|
||||
|
||||
// Extract metadata information
|
||||
Boolean deleteAll = request.getDeleteAll();
|
||||
Boolean deleteAll = request.isDeleteAll();
|
||||
String author = request.getAuthor();
|
||||
String creationDate = request.getCreationDate();
|
||||
String creator = request.getCreator();
|
||||
|
@ -61,7 +61,9 @@ public class MetadataController {
|
|||
|
||||
// Extract additional custom parameters
|
||||
Map<String, String> allRequestParams = request.getAllRequestParams();
|
||||
|
||||
if(allRequestParams == null) {
|
||||
allRequestParams = new java.util.HashMap<String, String>();
|
||||
}
|
||||
// Load the PDF file into a PDDocument
|
||||
PDDocument document = PDDocument.load(pdfFile.getBytes());
|
||||
|
||||
|
|
|
@ -53,14 +53,14 @@ public class OCRController {
|
|||
description = "This endpoint processes a PDF file using OCR (Optical Character Recognition). Users can specify languages, sidecar, deskew, clean, cleanFinal, ocrType, ocrRenderType, and removeImagesAfter options. Input:PDF Output:PDF Type:SI-Conditional")
|
||||
public ResponseEntity<byte[]> processPdfWithOCR(@ModelAttribute ProcessPdfWithOcrRequest request) throws IOException, InterruptedException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
List<String> selectedLanguages = request.getSelectedLanguages();
|
||||
Boolean sidecar = request.getSidecar();
|
||||
Boolean deskew = request.getDeskew();
|
||||
Boolean clean = request.getClean();
|
||||
Boolean cleanFinal = request.getCleanFinal();
|
||||
List<String> selectedLanguages = request.getLanguages();
|
||||
Boolean sidecar = request.isSidecar();
|
||||
Boolean deskew = request.isDeskew();
|
||||
Boolean clean = request.isClean();
|
||||
Boolean cleanFinal = request.isCleanFinal();
|
||||
String ocrType = request.getOcrType();
|
||||
String ocrRenderType = request.getOcrRenderType();
|
||||
Boolean removeImagesAfter = request.getRemoveImagesAfter();
|
||||
Boolean removeImagesAfter = request.isRemoveImagesAfter();
|
||||
// --output-type pdfa
|
||||
if (selectedLanguages == null || selectedLanguages.isEmpty()) {
|
||||
throw new IOException("Please select at least one language.");
|
||||
|
|
|
@ -75,7 +75,7 @@ public class CertSignController {
|
|||
MultipartFile certFile = request.getCertFile();
|
||||
MultipartFile p12File = request.getP12File();
|
||||
String password = request.getPassword();
|
||||
Boolean showSignature = request.getShowSignature();
|
||||
Boolean showSignature = request.isShowSignature();
|
||||
String reason = request.getReason();
|
||||
String location = request.getLocation();
|
||||
String name = request.getName();
|
||||
|
|
|
@ -39,11 +39,11 @@ public class SanitizeController {
|
|||
description = "This endpoint processes a PDF file and removes specific elements based on the provided options. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> sanitizePDF(@ModelAttribute SanitizePdfRequest request) throws IOException {
|
||||
MultipartFile inputFile = request.getFileInput();
|
||||
Boolean removeJavaScript = request.getRemoveJavaScript();
|
||||
Boolean removeEmbeddedFiles = request.getRemoveEmbeddedFiles();
|
||||
Boolean removeMetadata = request.getRemoveMetadata();
|
||||
Boolean removeLinks = request.getRemoveLinks();
|
||||
Boolean removeFonts = request.getRemoveFonts();
|
||||
boolean removeJavaScript = request.isRemoveJavaScript();
|
||||
boolean removeEmbeddedFiles = request.isRemoveEmbeddedFiles();
|
||||
boolean removeMetadata = request.isRemoveMetadata();
|
||||
boolean removeLinks = request.isRemoveLinks();
|
||||
boolean removeFonts = request.isRemoveFonts();
|
||||
|
||||
try (PDDocument document = PDDocument.load(inputFile.getInputStream())) {
|
||||
if (removeJavaScript) {
|
||||
|
|
|
@ -148,6 +148,14 @@ public class GeneralWebController {
|
|||
}
|
||||
|
||||
|
||||
@GetMapping("/scale-pages")
|
||||
@Hidden
|
||||
public String scalePagesFrom(Model model) {
|
||||
model.addAttribute("currentPage", "scale-pages");
|
||||
return "scale-pages";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
private ResourceLoader resourceLoader;
|
||||
|
|
|
@ -27,7 +27,7 @@ public class OtherWebController {
|
|||
@GetMapping("/extract-image-scans")
|
||||
@Hidden
|
||||
public ModelAndView extractImageScansForm() {
|
||||
ModelAndView modelAndView = new ModelAndView("other/extract-image-scans");
|
||||
ModelAndView modelAndView = new ModelAndView("misc/extract-image-scans");
|
||||
modelAndView.addObject("currentPage", "extract-image-scans");
|
||||
return modelAndView;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class OtherWebController {
|
|||
@GetMapping("/ocr-pdf")
|
||||
@Hidden
|
||||
public ModelAndView ocrPdfPage() {
|
||||
ModelAndView modelAndView = new ModelAndView("other/ocr-pdf");
|
||||
ModelAndView modelAndView = new ModelAndView("misc/ocr-pdf");
|
||||
List<String> languages = getAvailableTesseractLanguages();
|
||||
Collections.sort(languages);
|
||||
modelAndView.addObject("languages", languages);
|
||||
|
@ -127,13 +127,7 @@ public class OtherWebController {
|
|||
return "misc/remove-blanks";
|
||||
}
|
||||
|
||||
@GetMapping("/scale-pages")
|
||||
@Hidden
|
||||
public String scalePagesFrom(Model model) {
|
||||
model.addAttribute("currentPage", "scale-pages");
|
||||
return "misc/scale-pages";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/auto-crop")
|
||||
@Hidden
|
||||
public String autoCropForm(Model model) {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package stirling.software.SPDF.model.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=true)
|
||||
public class PDFWithPageSize extends PDFFile {
|
||||
|
||||
@Schema(description = "The scale of pages in the output PDF. Acceptable values are A0-A6, LETTER, LEGAL.",
|
||||
allowableValues = {
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "LETTER", "LEGAL"
|
||||
})
|
||||
private String pageSize;
|
||||
}
|
|
@ -4,17 +4,11 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import stirling.software.SPDF.model.api.PDFFile;
|
||||
import stirling.software.SPDF.model.api.PDFWithPageSize;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper=true)
|
||||
public class ScalePagesRequest extends PDFFile {
|
||||
|
||||
@Schema(description = "The scale of pages in the output PDF. Acceptable values are A0-A10, B0-B9, LETTER, TABLOID, LEDGER, LEGAL, EXECUTIVE.",
|
||||
allowableValues = {
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "B0", "B1", "B2", "B3", "B4",
|
||||
"B5", "B6", "B7", "B8", "B9", "LETTER", "TABLOID", "LEDGER", "LEGAL", "EXECUTIVE"
|
||||
})
|
||||
private String targetPDRectangle;
|
||||
public class ScalePagesRequest extends PDFWithPageSize {
|
||||
|
||||
@Schema(description = "The scale of the content on the pages of the output PDF. Acceptable values are floats.")
|
||||
private float scaleFactor;
|
||||
|
|
|
@ -10,5 +10,5 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||
public class ExtractHeaderRequest extends PDFFile {
|
||||
|
||||
@Schema(description = "Flag indicating whether to use the first text as a fallback if no suitable title is found. Defaults to false.", required = false, defaultValue = "false")
|
||||
private Boolean useFirstTextAsFallback;
|
||||
private boolean useFirstTextAsFallback;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||
public class MetadataRequest extends PDFFile {
|
||||
|
||||
@Schema(description = "Delete all metadata if set to true")
|
||||
private Boolean deleteAll;
|
||||
private boolean deleteAll;
|
||||
|
||||
@Schema(description = "The author of the document")
|
||||
private String author;
|
||||
|
|
|
@ -14,5 +14,5 @@ public class OptimizePdfRequest extends PDFFile {
|
|||
private Integer optimizeLevel;
|
||||
|
||||
@Schema(description = "The expected output size, e.g. '100MB', '25KB', etc.")
|
||||
private String expectedOutputSizeString;
|
||||
private String expectedOutputSize;
|
||||
}
|
||||
|
|
|
@ -12,19 +12,19 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||
public class ProcessPdfWithOcrRequest extends PDFFile {
|
||||
|
||||
@Schema(description = "List of languages to use in OCR processing")
|
||||
private List<String> selectedLanguages;
|
||||
private List<String> languages;
|
||||
|
||||
@Schema(description = "Include OCR text in a sidecar text file if set to true")
|
||||
private Boolean sidecar;
|
||||
private boolean sidecar;
|
||||
|
||||
@Schema(description = "Deskew the input file if set to true")
|
||||
private Boolean deskew;
|
||||
private boolean deskew;
|
||||
|
||||
@Schema(description = "Clean the input file if set to true")
|
||||
private Boolean clean;
|
||||
private boolean clean;
|
||||
|
||||
@Schema(description = "Clean the final output if set to true")
|
||||
private Boolean cleanFinal;
|
||||
private boolean cleanFinal;
|
||||
|
||||
@Schema(description = "Specify the OCR type, e.g., 'skip-text', 'force-ocr', or 'Normal'", allowableValues = {"skip-text", "force-ocr", "Normal"})
|
||||
private String ocrType;
|
||||
|
@ -33,5 +33,5 @@ public class ProcessPdfWithOcrRequest extends PDFFile {
|
|||
private String ocrRenderType = "hocr";
|
||||
|
||||
@Schema(description = "Remove images from the output PDF if set to true")
|
||||
private Boolean removeImagesAfter;
|
||||
private boolean removeImagesAfter;
|
||||
}
|
||||
|
|
|
@ -10,17 +10,17 @@ import stirling.software.SPDF.model.api.PDFFile;
|
|||
public class SanitizePdfRequest extends PDFFile {
|
||||
|
||||
@Schema(description = "Remove JavaScript actions from the PDF", defaultValue = "false")
|
||||
private Boolean removeJavaScript;
|
||||
private boolean removeJavaScript;
|
||||
|
||||
@Schema(description = "Remove embedded files from the PDF", defaultValue = "false")
|
||||
private Boolean removeEmbeddedFiles;
|
||||
private boolean removeEmbeddedFiles;
|
||||
|
||||
@Schema(description = "Remove metadata from the PDF", defaultValue = "false")
|
||||
private Boolean removeMetadata;
|
||||
private boolean removeMetadata;
|
||||
|
||||
@Schema(description = "Remove links from the PDF", defaultValue = "false")
|
||||
private Boolean removeLinks;
|
||||
private boolean removeLinks;
|
||||
|
||||
@Schema(description = "Remove fonts from the PDF", defaultValue = "false")
|
||||
private Boolean removeFonts;
|
||||
private boolean removeFonts;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public class SignPDFWithCertRequest extends PDFFile {
|
|||
private String password;
|
||||
|
||||
@Schema(description = "Whether to visually show the signature in the PDF file")
|
||||
private Boolean showSignature;
|
||||
private boolean showSignature;
|
||||
|
||||
@Schema(description = "The reason for signing the PDF")
|
||||
private String reason;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<input type="hidden" id="customMode" name="customMode" value="">
|
||||
<div class="mb-3">
|
||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||
<input type="text" class="form-control" id="pageOrder" name="pageOrder" placeholder="(e.g. 1,2,8 or 4,7,12-16 or 2n-1)" required>
|
||||
<input type="text" class="form-control" id="pageOrder" name="pageNumbers" placeholder="(e.g. 1,2,8 or 4,7,12-16 or 2n-1)" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageExtracter.submit}"></button>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 th:text="#{scalePages.header}"></h2>
|
||||
<form id="scalePagesFrom" th:action="@{api/v1/misc/scale-pages}" method="post" enctype="multipart/form-data">
|
||||
<form id="scalePagesFrom" th:action="@{api/v1/general/scale-pages}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label for="pageSize" th:text="#{scalePages.pageSize}"></label>
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
const formData = new FormData(event.target);
|
||||
|
||||
fetch('get-info-on-pdf', {
|
||||
fetch('api/v1/security/get-info-on-pdf', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue