rework for API, folder changes, easter eggs and fun

This commit is contained in:
Anthony Stirling 2023-04-28 23:18:10 +01:00
parent 63a698b679
commit 91171727e4
35 changed files with 1345 additions and 1157 deletions

View file

@ -1,9 +1,9 @@
# Build jbig2enc in a separate stage # Build jbig2enc in a separate stage
FROM frooodle/stirling-pdf-base:beta FROM frooodle/stirling-pdf-base:beta2
# Create pythonScripts folder and copy local scripts # Create scripts folder and copy local scripts
RUN mkdir /pythonScripts RUN mkdir /scripts
COPY ./pythonScripts/* /pythonScripts/ COPY ./scripts/* /scripts/
# Copy the application JAR file # Copy the application JAR file
COPY build/libs/*.jar app.jar COPY build/libs/*.jar app.jar
@ -17,7 +17,8 @@ ENV APP_HOME_NAME="Stirling PDF"
#ENV APP_NAVBAR_NAME="Stirling PDF" #ENV APP_NAVBAR_NAME="Stirling PDF"
# Run the application # Run the application
ENTRYPOINT java -jar /app.jar ENTRYPOINT ["/scripts/init.sh"]
CMD ["java", "-jar", "/app.jar"]

View file

@ -21,10 +21,9 @@ RUN git clone https://github.com/agl/jbig2enc && \
make && \ make && \
make install make install
# Main stage
FROM openjdk:17-jdk-slim
# Install necessary dependencies # Main stage
FROM openjdk:17-jdk-slim AS base
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
libreoffice-core \ libreoffice-core \
@ -38,52 +37,27 @@ RUN apt-get update && \
pngquant \ pngquant \
unpaper \ unpaper \
ocrmypdf && \ ocrmypdf && \
pip install --user --upgrade ocrmypdf && \ rm -rf /var/lib/apt/lists/* && \
pip3 install opencv-python-headless mkdir /usr/share/tesseract-ocr-original && \
cp -r /usr/share/tesseract-ocr/* /usr/share/tesseract-ocr-original && \
# Copy the jbig2enc binary from the builder stage mv /usr/share/tesseract-ocr-original/4.00/tessdata/eng.traineddata /usr/share/tesseract-ocr-original/4.00/tessdata/english.traineddata && \
COPY --from=jbig2enc_builder /usr/local/bin/jbig2 /usr/local/bin/jbig2# Build jbig2enc in a separate stage rm -rf /usr/share/tesseract-ocr
FROM debian:bullseye-slim as jbig2enc_builder
# Python packages stage
FROM base AS python-packages
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
git \ build-essential \
automake \ libffi-dev \
autoconf \ libssl-dev \
libtool \
libleptonica-dev \
pkg-config \
ca-certificates \
zlib1g-dev \ zlib1g-dev \
make \ libjpeg-dev && \
g++ pip install --upgrade pip && \
pip install --no-cache-dir \
opencv-python-headless && \
rm -rf /var/lib/apt/lists/*
RUN git clone https://github.com/agl/jbig2enc && \ # Final stage: Copy necessary files from the previous stage
cd jbig2enc && \ FROM base
./autogen.sh && \ COPY --from=python-packages /usr/local /usr/local
./configure && \
make && \
make install
# Main stage
FROM openjdk:17-jdk-slim
# Install necessary dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libreoffice-core \
libreoffice-common \
libreoffice-writer \
libreoffice-calc \
libreoffice-impress \
python3-uno \
python3-pip \
unoconv \
pngquant \
unpaper \
ocrmypdf && \
pip install --user --upgrade ocrmypdf && \
pip3 install opencv-python-headless
# Copy the jbig2enc binary from the builder stage
COPY --from=jbig2enc_builder /usr/local/bin/jbig2 /usr/local/bin/jbig2 COPY --from=jbig2enc_builder /usr/local/bin/jbig2 /usr/local/bin/jbig2

View file

@ -20,6 +20,8 @@ dependencies {
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4' implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
implementation 'commons-io:commons-io:2.11.0' implementation 'commons-io:commons-io:2.11.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
//general PDF //general PDF
implementation 'org.apache.pdfbox:pdfbox:2.0.28' implementation 'org.apache.pdfbox:pdfbox:2.0.28'

9
scripts/init.sh Normal file
View file

@ -0,0 +1,9 @@
#!/bin/bash
# Copy the original tesseract-ocr files to the volume directory without overwriting existing files
echo "Copying original files without overwriting existing files"
mkdir -p /usr/share/tesseract-ocr
cp -rn /usr/share/tesseract-ocr-original/* /usr/share/tesseract-ocr
# Run the main command
exec "$@"

View file

@ -85,7 +85,7 @@ def crop_borders(image, border_color, tolerance=30):
return image[y:y+h, x:x+w] return image[y:y+h, x:x+w]
def split_photos(input_file, output_directory, tolerance=30, min_area=10000, min_contour_area=500, angle_threshold=10, border_size=10): def split_photos(input_file, output_directory, tolerance=30, min_area=10000, min_contour_area=500, angle_threshold=10, border_size=0):
image = cv2.imread(input_file) image = cv2.imread(input_file)
background_color = estimate_background_color(image) background_color = estimate_background_color(image)
@ -121,7 +121,7 @@ if __name__ == "__main__":
print(" [min_area] - Optional. Sets the minimum area threshold for a photo (default: 10000).") print(" [min_area] - Optional. Sets the minimum area threshold for a photo (default: 10000).")
print(" [min_contour_area] - Optional. Sets the minimum contour area threshold for a photo (default: 500).") print(" [min_contour_area] - Optional. Sets the minimum contour area threshold for a photo (default: 500).")
print(" [angle_threshold] - Optional. Sets the minimum absolute angle required for the image to be rotated (default: 10).") print(" [angle_threshold] - Optional. Sets the minimum absolute angle required for the image to be rotated (default: 10).")
print(" [border_size] - Optional. Sets the size of the border added and removed to prevent white borders in the output (default: 10).") print(" [border_size] - Optional. Sets the size of the border added and removed to prevent white borders in the output (default: 0).")
sys.exit(1) sys.exit(1)
input_file = sys.argv[1] input_file = sys.argv[1]
@ -130,4 +130,5 @@ if __name__ == "__main__":
min_area = int(sys.argv[4]) if len(sys.argv) > 4 else 8000 min_area = int(sys.argv[4]) if len(sys.argv) > 4 else 8000
min_contour_area = int(sys.argv[5]) if len(sys.argv) > 5 else 500 min_contour_area = int(sys.argv[5]) if len(sys.argv) > 5 else 500
angle_threshold = int(sys.argv[6]) if len(sys.argv) > 6 else 60 angle_threshold = int(sys.argv[6]) if len(sys.argv) > 6 else 60
split_photos(input_file, output_directory, tolerance=tolerance, min_area=min_area, min_contour_area=min_contour_area, angle_threshold=angle_threshold) border_size = int(sys.argv[7]) if len(sys.argv) > 7 else 0
split_photos(input_file, output_directory, tolerance=tolerance, min_area=min_area, min_contour_area=min_contour_area, angle_threshold=angle_threshold, border_size=border_size)

View file

@ -0,0 +1,20 @@
package stirling.software.SPDF.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().components(new Components()).info(
new Info().title("Your API Title").version("1.0.0").description("Your API Description").license(new License().name("Your License Name").url("Your License URL")));
}
}

View file

@ -1,20 +0,0 @@
package stirling.software.SPDF.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MultiToolController {
private static final Logger logger = LoggerFactory.getLogger(MultiToolController.class);
@GetMapping("/multi-tool")
public String multiToolForm(Model model) {
model.addAttribute("currentPage", "multi-tool");
return "multi-tool";
}
}

View file

@ -1,25 +0,0 @@
package stirling.software.SPDF.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PdfController {
private static final Logger logger = LoggerFactory.getLogger(PdfController.class);
@GetMapping("/")
public String home(Model model) {
model.addAttribute("currentPage", "home");
return "home";
}
@GetMapping("/home")
public String root(Model model) {
return "redirect:/";
}
}

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller; package stirling.software.SPDF.controller.api;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -10,26 +10,21 @@ import org.apache.pdfbox.pdmodel.PDPageTree;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class MergeController { public class MergeController {
private static final Logger logger = LoggerFactory.getLogger(MergeController.class); private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
@GetMapping("/merge-pdfs")
public String hello(Model model) {
model.addAttribute("currentPage", "merge-pdfs");
return "merge-pdfs";
}
private PDDocument mergeDocuments(List<PDDocument> documents) throws IOException { private PDDocument mergeDocuments(List<PDDocument> documents) throws IOException {
// Create a new empty document // Create a new empty document
PDDocument mergedDoc = new PDDocument(); PDDocument mergedDoc = new PDDocument();
@ -48,8 +43,8 @@ public class MergeController {
return mergedDoc; return mergedDoc;
} }
@PostMapping("/merge-pdfs") @PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
public ResponseEntity<byte[]> mergePdfs(@RequestParam("fileInput") MultipartFile[] files) throws IOException { public ResponseEntity<byte[]> mergePdfs(@RequestPart(required = true, value = "fileInput") MultipartFile[] files) throws IOException {
// Read the input PDF files into PDDocument objects // Read the input PDF files into PDDocument objects
List<PDDocument> documents = new ArrayList<>(); List<PDDocument> documents = new ArrayList<>();

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller; package stirling.software.SPDF.controller.api;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -9,22 +9,25 @@ import org.apache.pdfbox.pdmodel.PDPage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class RearrangePagesPDFController { public class RearrangePagesPDFController {
private static final Logger logger = LoggerFactory.getLogger(RearrangePagesPDFController.class); private static final Logger logger = LoggerFactory.getLogger(RearrangePagesPDFController.class);
@PostMapping("/remove-pages") @PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
public ResponseEntity<byte[]> deletePages(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("pagesToDelete") String pagesToDelete) throws IOException { public ResponseEntity<byte[]> deletePages(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile, @RequestParam("pagesToDelete") String pagesToDelete)
throws IOException {
PDDocument document = PDDocument.load(pdfFile.getBytes()); PDDocument document = PDDocument.load(pdfFile.getBytes());
@ -41,12 +44,6 @@ public class RearrangePagesPDFController {
} }
@GetMapping("/remove-pages")
public String pageDeleter(Model model) {
model.addAttribute("currentPage", "remove-pages");
return "remove-pages";
}
private List<Integer> pageOrderToString(String[] pageOrderArr, int totalPages) { private List<Integer> pageOrderToString(String[] pageOrderArr, int totalPages) {
List<Integer> newPageOrder = new ArrayList<>(); List<Integer> newPageOrder = new ArrayList<>();
// loop through the page order array // loop through the page order array
@ -75,14 +72,8 @@ public class RearrangePagesPDFController {
return newPageOrder; return newPageOrder;
} }
@GetMapping("/pdf-organizer") @PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
public String pageOrganizer(Model model) { public ResponseEntity<byte[]> rearrangePages(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile, @RequestParam("pageOrder") String pageOrder) {
model.addAttribute("currentPage", "pdf-organizer");
return "pdf-organizer";
}
@PostMapping("/rearrange-pages")
public ResponseEntity<byte[]> rearrangePages(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("pageOrder") String pageOrder) {
try { try {
// Load the input PDF // Load the input PDF
PDDocument document = PDDocument.load(pdfFile.getInputStream()); PDDocument document = PDDocument.load(pdfFile.getInputStream());

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller; package stirling.software.SPDF.controller.api;
import java.io.IOException; import java.io.IOException;
@ -8,22 +8,24 @@ import org.apache.pdfbox.pdmodel.PDPageTree;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class RotationController { public class RotationController {
private static final Logger logger = LoggerFactory.getLogger(RotationController.class); private static final Logger logger = LoggerFactory.getLogger(RotationController.class);
@PostMapping("/rotate-pdf") @PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
public ResponseEntity<byte[]> rotatePDF(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("angle") Integer angle) throws IOException { public ResponseEntity<byte[]> rotatePDF(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile, @RequestParam("angle") Integer angle) throws IOException {
// Load the PDF document // Load the PDF document
PDDocument document = PDDocument.load(pdfFile.getBytes()); PDDocument document = PDDocument.load(pdfFile.getBytes());
@ -39,10 +41,4 @@ public class RotationController {
} }
@GetMapping("/rotate-pdf")
public String rotatePdfForm(Model model) {
model.addAttribute("currentPage", "rotate-pdf");
return "rotate-pdf";
}
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller; package stirling.software.SPDF.controller.api;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@ -21,20 +21,23 @@ import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@Controller import io.swagger.v3.oas.annotations.Hidden;
@RestController
public class SplitPDFController { public class SplitPDFController {
private static final Logger logger = LoggerFactory.getLogger(SplitPDFController.class); private static final Logger logger = LoggerFactory.getLogger(SplitPDFController.class);
@PostMapping("/split-pages") @PostMapping(consumes = "multipart/form-data", value = "/split-pages")
public ResponseEntity<Resource> splitPdf(@RequestParam("fileInput") MultipartFile file, @RequestParam("pages") String pages) throws IOException { public ResponseEntity<Resource> splitPdf(@RequestPart(required = true, value = "fileInput") MultipartFile file, @RequestParam("pages") String pages) throws IOException {
// parse user input // parse user input
// open the pdf document // open the pdf document
@ -127,9 +130,4 @@ public class SplitPDFController {
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource); .contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource);
} }
@GetMapping("/split-pdfs")
public String splitPdfForm(Model model) {
model.addAttribute("currentPage", "split-pdfs");
return "split-pdfs";
}
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.converters; package stirling.software.SPDF.controller.api.converters;
import java.io.IOException; import java.io.IOException;
@ -11,22 +11,24 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; 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.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class ConvertImgPDFController { public class ConvertImgPDFController {
private static final Logger logger = LoggerFactory.getLogger(ConvertImgPDFController.class); private static final Logger logger = LoggerFactory.getLogger(ConvertImgPDFController.class);
@PostMapping("/pdf-to-img") @PostMapping(consumes = "multipart/form-data", value = "/pdf-to-img")
public ResponseEntity<Resource> convertToImage(@RequestParam("fileInput") MultipartFile file, @RequestParam("imageFormat") String imageFormat, public ResponseEntity<Resource> convertToImage(@RequestPart(required = true, value = "fileInput") MultipartFile file, @RequestParam("imageFormat") String imageFormat,
@RequestParam("singleOrMultiple") String singleOrMultiple, @RequestParam("colorType") String colorType, @RequestParam("dpi") String dpi) throws IOException { @RequestParam("singleOrMultiple") String singleOrMultiple, @RequestParam("colorType") String colorType, @RequestParam("dpi") String dpi) throws IOException {
byte[] pdfBytes = file.getBytes(); byte[] pdfBytes = file.getBytes();
@ -62,21 +64,16 @@ public class ConvertImgPDFController {
} }
} }
@PostMapping("/img-to-pdf") @PostMapping(consumes = "multipart/form-data", value = "/img-to-pdf")
public ResponseEntity<byte[]> convertToPdf(@RequestParam("fileInput") MultipartFile[] file, @RequestParam(defaultValue = "false", name = "stretchToFit") boolean stretchToFit, public ResponseEntity<byte[]> convertToPdf(@RequestPart(required = true, value = "fileInput") MultipartFile[] file,
@RequestParam(defaultValue = "true", name = "autoRotate") boolean autoRotate) throws IOException { @RequestParam(defaultValue = "false", name = "stretchToFit") boolean stretchToFit, @RequestParam(defaultValue = "true", name = "autoRotate") boolean autoRotate)
throws IOException {
// Convert the file to PDF and get the resulting bytes // Convert the file to PDF and get the resulting bytes
System.out.println(stretchToFit); System.out.println(stretchToFit);
byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate); byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate);
return PdfUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_coverted.pdf"); return PdfUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_coverted.pdf");
} }
@GetMapping("/img-to-pdf")
public String convertToPdfForm(Model model) {
model.addAttribute("currentPage", "img-to-pdf");
return "convert/img-to-pdf";
}
private String getMediaType(String imageFormat) { private String getMediaType(String imageFormat) {
if (imageFormat.equalsIgnoreCase("PNG")) if (imageFormat.equalsIgnoreCase("PNG"))
return "image/png"; return "image/png";
@ -88,10 +85,5 @@ public class ConvertImgPDFController {
return "application/octet-stream"; return "application/octet-stream";
} }
@GetMapping("/pdf-to-img")
public String pdfToimgForm(Model model) {
model.addAttribute("currentPage", "pdf-to-img");
return "convert/pdf-to-img";
}
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.converters; package stirling.software.SPDF.controller.api.converters;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -10,17 +10,18 @@ import java.util.List;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
@Controller @RestController
public class ConvertOfficeController { public class ConvertOfficeController {
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException { public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
@ -50,20 +51,13 @@ public class ConvertOfficeController {
return pdfBytes; return pdfBytes;
} }
@GetMapping("/file-to-pdf")
public String convertToPdfForm(Model model) {
model.addAttribute("currentPage", "file-to-pdf");
return "convert/file-to-pdf";
}
private boolean isValidFileExtension(String fileExtension) { private boolean isValidFileExtension(String fileExtension) {
String extensionPattern = "^(?i)[a-z0-9]{2,4}$"; String extensionPattern = "^(?i)[a-z0-9]{2,4}$";
return fileExtension.matches(extensionPattern); return fileExtension.matches(extensionPattern);
} }
@PostMapping("/file-to-pdf") @PostMapping(consumes = "multipart/form-data", value = "/file-to-pdf")
public ResponseEntity<byte[]> processPdfWithOCR(@RequestParam("fileInput") MultipartFile inputFile) throws IOException, InterruptedException { public ResponseEntity<byte[]> processPdfWithOCR(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
// unused but can start server instance if startup time is to long // unused but can start server instance if startup time is to long
// LibreOfficeListener.getInstance().start(); // LibreOfficeListener.getInstance().start();

View file

@ -0,0 +1,55 @@
package stirling.software.SPDF.controller.api.converters;
import java.io.IOException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PDFToFile;
@RestController
public class ConvertPDFToOffice {
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-html")
public ResponseEntity<byte[]> processPdfToHTML(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, "html", "writer_pdf_import");
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-presentation")
public ResponseEntity<byte[]> processPdfToPresentation(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile,
@RequestParam("outputFormat") String outputFormat) throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-text")
public ResponseEntity<byte[]> processPdfToRTForTXT(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile,
@RequestParam("outputFormat") String outputFormat) throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-word")
public ResponseEntity<byte[]> processPdfToWord(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile, @RequestParam("outputFormat") String outputFormat)
throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
}
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-xml")
public ResponseEntity<byte[]> processPdfToXML(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, "xml", "writer_pdf_import");
}
}

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.converters; package stirling.software.SPDF.controller.api.converters;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -7,21 +7,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
@Controller @RestController
public class ConvertPDFToPDFA { public class ConvertPDFToPDFA {
@PostMapping("/pdf-to-pdfa") @PostMapping(consumes = "multipart/form-data", value = "/pdf-to-pdfa")
public ResponseEntity<byte[]> pdfToPdfA(@RequestParam("fileInput") MultipartFile inputFile) throws IOException, InterruptedException { public ResponseEntity<byte[]> pdfToPdfA(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
// Save the uploaded file to a temporary location // Save the uploaded file to a temporary location
Path tempInputFile = Files.createTempFile("input_", ".pdf"); Path tempInputFile = Files.createTempFile("input_", ".pdf");
@ -54,10 +55,4 @@ public class ConvertPDFToPDFA {
return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename); return PdfUtils.bytesToWebResponse(pdfBytes, outputFilename);
} }
@GetMapping("/pdf-to-pdfa")
public String pdfToPdfAForm(Model model) {
model.addAttribute("currentPage", "pdf-to-pdfa");
return "convert/pdf-to-pdfa";
}
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.other; package stirling.software.SPDF.controller.api.other;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -9,29 +9,25 @@ import java.util.List;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
@Controller @RestController
public class CompressController { public class CompressController {
private static final Logger logger = LoggerFactory.getLogger(CompressController.class); private static final Logger logger = LoggerFactory.getLogger(CompressController.class);
@GetMapping("/compress-pdf") @PostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
public String compressPdfForm(Model model) { public ResponseEntity<byte[]> optimizePdf(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile, @RequestParam("optimizeLevel") int optimizeLevel,
model.addAttribute("currentPage", "compress-pdf");
return "other/compress-pdf";
}
@PostMapping("/compress-pdf")
public ResponseEntity<byte[]> optimizePdf(@RequestParam("fileInput") MultipartFile inputFile, @RequestParam("optimizeLevel") int optimizeLevel,
@RequestParam(name = "fastWebView", required = false) Boolean fastWebView, @RequestParam(name = "jbig2Lossy", required = false) Boolean jbig2Lossy) @RequestParam(name = "fastWebView", required = false) Boolean fastWebView, @RequestParam(name = "jbig2Lossy", required = false) Boolean jbig2Lossy)
throws IOException, InterruptedException { throws IOException, InterruptedException {

View file

@ -1,10 +1,9 @@
package stirling.software.SPDF.controller.other; package stirling.software.SPDF.controller.api.other;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
@ -24,35 +23,28 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
@Controller @RestController
public class ExtractImageScansController { public class ExtractImageScansController {
private static final Logger logger = LoggerFactory.getLogger(ExtractImageScansController.class); private static final Logger logger = LoggerFactory.getLogger(ExtractImageScansController.class);
@PostMapping(consumes = "multipart/form-data", value = "/extract-image-scans")
@GetMapping("/extract-image-scans") public ResponseEntity<byte[]> extractImageScans(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile,
public ModelAndView extractImageScansForm() { @RequestParam(name = "angle_threshold", defaultValue = "5") int angleThreshold, @RequestParam(name = "tolerance", defaultValue = "20") int tolerance,
ModelAndView modelAndView = new ModelAndView("other/extract-image-scans"); @RequestParam(name = "min_area", defaultValue = "8000") int minArea, @RequestParam(name = "min_contour_area", defaultValue = "500") int minContourArea,
modelAndView.addObject("currentPage", "extract-image-scans"); @RequestParam(name = "border_size", defaultValue = "1") int borderSize) throws IOException, InterruptedException {
return modelAndView;
}
@PostMapping("/extract-image-scans")
public ResponseEntity<byte[]> extractImageScans(@RequestParam("fileInput") MultipartFile inputFile,
@RequestParam(name = "angle_threshold", defaultValue = "5") int angleThreshold,
@RequestParam(name = "tolerance", defaultValue = "20") int tolerance,
@RequestParam(name = "min_area", defaultValue = "8000") int minArea,
@RequestParam(name = "min_contour_area", defaultValue = "500") int minContourArea) throws IOException, InterruptedException {
String fileName = inputFile.getOriginalFilename(); String fileName = inputFile.getOriginalFilename();
String extension = fileName.substring(fileName.lastIndexOf(".") + 1); String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
@ -87,14 +79,14 @@ public class ExtractImageScansController {
images.add(tempInputFile.toString()); images.add(tempInputFile.toString());
} }
List<byte[]> processedImageBytes = new ArrayList<>(); List<byte[]> processedImageBytes = new ArrayList<>();
// Process each image // Process each image
for (int i = 0; i < images.size(); i++) { for (int i = 0; i < images.size(); i++) {
Path tempDir = Files.createTempDirectory("openCV_output"); Path tempDir = Files.createTempDirectory("openCV_output");
List<String> command = new ArrayList<>(Arrays.asList("python3", "/pythonScripts/split_photos.py", images.get(i), tempDir.toString(), String.valueOf(angleThreshold), String.valueOf(tolerance),String.valueOf(minArea),String.valueOf(minContourArea))); List<String> command = new ArrayList<>(Arrays.asList("python3", "/scripts/split_photos.py", images.get(i), tempDir.toString(), String.valueOf(angleThreshold),
String.valueOf(tolerance), String.valueOf(minArea), String.valueOf(minContourArea), String.valueOf(borderSize)));
// Run CLI command // Run CLI command
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command); int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV).runCommandWithOutputHandling(command);
@ -117,7 +109,7 @@ public class ExtractImageScansController {
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) { try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) {
// Add processed images to the zip // Add processed images to the zip
for (int i = 0; i < processedImageBytes.size(); i++) { for (int i = 0; i < processedImageBytes.size(); i++) {
ZipEntry entry = new ZipEntry(fileName.replaceFirst("[.][^.]+$", "") + "_" + (i+1) + ".png"); ZipEntry entry = new ZipEntry(fileName.replaceFirst("[.][^.]+$", "") + "_" + (i + 1) + ".png");
zipOut.putNextEntry(entry); zipOut.putNextEntry(entry);
zipOut.write(processedImageBytes.get(i)); zipOut.write(processedImageBytes.get(i));
zipOut.closeEntry(); zipOut.closeEntry();
@ -136,10 +128,6 @@ public class ExtractImageScansController {
return PdfUtils.bytesToWebResponse(imageBytes, fileName.replaceFirst("[.][^.]+$", "") + ".png", MediaType.IMAGE_PNG); return PdfUtils.bytesToWebResponse(imageBytes, fileName.replaceFirst("[.][^.]+$", "") + ".png", MediaType.IMAGE_PNG);
} }
} }
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.other; package stirling.software.SPDF.controller.api.other;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Image; import java.awt.Image;
@ -20,22 +20,24 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class ExtractImagesController { public class ExtractImagesController {
private static final Logger logger = LoggerFactory.getLogger(ExtractImagesController.class); private static final Logger logger = LoggerFactory.getLogger(ExtractImagesController.class);
@PostMapping("/extract-images") @PostMapping(consumes = "multipart/form-data", value = "/extract-images")
public ResponseEntity<byte[]> extractImages(@RequestParam("fileInput") MultipartFile file, @RequestParam("format") String format) throws IOException { public ResponseEntity<byte[]> extractImages(@RequestPart(required = true, value = "fileInput") MultipartFile file, @RequestParam("format") String format) throws IOException {
System.out.println(System.currentTimeMillis() + "file=" + file.getName() + ", format=" + format); System.out.println(System.currentTimeMillis() + "file=" + file.getName() + ", format=" + format);
PDDocument document = PDDocument.load(file.getBytes()); PDDocument document = PDDocument.load(file.getBytes());
@ -100,10 +102,4 @@ public class ExtractImagesController {
return PdfUtils.boasToWebResponse(baos, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_extracted-images.zip", MediaType.APPLICATION_OCTET_STREAM); return PdfUtils.boasToWebResponse(baos, file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_extracted-images.zip", MediaType.APPLICATION_OCTET_STREAM);
} }
@GetMapping("/extract-images")
public String extractImagesForm(Model model) {
model.addAttribute("currentPage", "extract-images");
return "other/extract-images";
}
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.other; package stirling.software.SPDF.controller.api.other;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
@ -11,23 +11,20 @@ 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.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class MetadataController { public class MetadataController {
@GetMapping("/change-metadata")
public String addWatermarkForm(Model model) {
model.addAttribute("currentPage", "change-metadata");
return "other/change-metadata";
}
private String checkUndefined(String entry) { private String checkUndefined(String entry) {
// Check if the string is "undefined" // Check if the string is "undefined"
@ -40,8 +37,8 @@ public class MetadataController {
} }
@PostMapping("/update-metadata") @PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
public ResponseEntity<byte[]> metadata(@RequestParam("fileInput") MultipartFile pdfFile, public ResponseEntity<byte[]> metadata(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile,
@RequestParam(value = "deleteAll", required = false, defaultValue = "false") Boolean deleteAll, @RequestParam(value = "author", required = false) String author, @RequestParam(value = "deleteAll", required = false, defaultValue = "false") Boolean deleteAll, @RequestParam(value = "author", required = false) String author,
@RequestParam(value = "creationDate", required = false) String creationDate, @RequestParam(value = "creator", required = false) String creator, @RequestParam(value = "creationDate", required = false) String creationDate, @RequestParam(value = "creator", required = false) String creator,
@RequestParam(value = "keywords", required = false) String keywords, @RequestParam(value = "modificationDate", required = false) String modificationDate, @RequestParam(value = "keywords", required = false) String keywords, @RequestParam(value = "modificationDate", required = false) String modificationDate,

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.other; package stirling.software.SPDF.controller.api.other;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -19,44 +19,30 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor;
@Controller @RestController
public class OCRController { public class OCRController {
private static final Logger logger = LoggerFactory.getLogger(OCRController.class); private static final Logger logger = LoggerFactory.getLogger(OCRController.class);
public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/4.00/tessdata";
File[] files = new File(tessdataDir).listFiles();
if (files == null) {
return Collections.emptyList();
}
return Arrays.stream(files).filter(file -> file.getName().endsWith(".traineddata")).map(file -> file.getName().replace(".traineddata", ""))
.filter(lang -> !lang.equalsIgnoreCase("osd")).collect(Collectors.toList());
}
@GetMapping("/ocr-pdf") @PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
public ModelAndView ocrPdfPage() { public ResponseEntity<byte[]> processPdfWithOCR(@RequestPart(required = true, value = "fileInput") MultipartFile inputFile,
ModelAndView modelAndView = new ModelAndView("other/ocr-pdf"); @RequestParam("languages") List<String> selectedLanguages, @RequestParam(name = "sidecar", required = false) Boolean sidecar,
modelAndView.addObject("languages", getAvailableTesseractLanguages()); @RequestParam(name = "deskew", required = false) Boolean deskew, @RequestParam(name = "clean", required = false) Boolean clean,
modelAndView.addObject("currentPage", "ocr-pdf"); @RequestParam(name = "clean-final", required = false) Boolean cleanFinal, @RequestParam(name = "ocrType", required = false) String ocrType)
return modelAndView; throws IOException, InterruptedException {
}
@PostMapping("/ocr-pdf")
public ResponseEntity<byte[]> processPdfWithOCR(@RequestParam("fileInput") MultipartFile inputFile, @RequestParam("languages") List<String> selectedLanguages,
@RequestParam(name = "sidecar", required = false) Boolean sidecar, @RequestParam(name = "deskew", required = false) Boolean deskew,
@RequestParam(name = "clean", required = false) Boolean clean, @RequestParam(name = "clean-final", required = false) Boolean cleanFinal,
@RequestParam(name = "ocrType", required = false) String ocrType) throws IOException, InterruptedException {
// --output-type pdfa // --output-type pdfa
if (selectedLanguages == null || selectedLanguages.size() < 1) { if (selectedLanguages == null || selectedLanguages.size() < 1) {

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.other; package stirling.software.SPDF.controller.api.other;
import java.io.IOException; import java.io.IOException;
@ -6,29 +6,25 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class OverlayImageController { public class OverlayImageController {
private static final Logger logger = LoggerFactory.getLogger(OverlayImageController.class); private static final Logger logger = LoggerFactory.getLogger(OverlayImageController.class);
@GetMapping("/add-image") @PostMapping(consumes = "multipart/form-data", value = "/add-image")
public String overlayImage(Model model) { public ResponseEntity<byte[]> overlayImage(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile, @RequestParam("fileInput2") MultipartFile imageFile,
model.addAttribute("currentPage", "add-image"); @RequestParam("x") float x, @RequestParam("y") float y, @RequestParam("everyPage") boolean everyPage) {
return "other/add-image";
}
@PostMapping("/add-image")
public ResponseEntity<byte[]> overlayImage(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("fileInput2") MultipartFile imageFile, @RequestParam("x") float x,
@RequestParam("y") float y, @RequestParam("everyPage") boolean everyPage) {
try { try {
byte[] pdfBytes = pdfFile.getBytes(); byte[] pdfBytes = pdfFile.getBytes();
byte[] imageBytes = imageFile.getBytes(); byte[] imageBytes = imageFile.getBytes();

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.security; package stirling.software.SPDF.controller.api.security;
import java.io.IOException; import java.io.IOException;
@ -8,36 +8,35 @@ import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
@Controller @RestController
public class PasswordController { public class PasswordController {
private static final Logger logger = LoggerFactory.getLogger(PasswordController.class); private static final Logger logger = LoggerFactory.getLogger(PasswordController.class);
@GetMapping("/add-password")
public String addPasswordForm(Model model) {
model.addAttribute("currentPage", "add-password");
return "security/add-password";
}
@PostMapping("/remove-password") @PostMapping(consumes = "multipart/form-data", value = "/remove-password")
public ResponseEntity<byte[]> compressPDF(@RequestParam("fileInput") MultipartFile fileInput, @RequestParam(name = "password") String password) throws IOException { public ResponseEntity<byte[]> compressPDF(@RequestPart(required = true, value = "fileInput") MultipartFile fileInput, @RequestParam(name = "password") String password)
throws IOException {
PDDocument document = PDDocument.load(fileInput.getBytes(), password); PDDocument document = PDDocument.load(fileInput.getBytes(), password);
document.setAllSecurityToBeRemoved(true); document.setAllSecurityToBeRemoved(true);
return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_password_removed.pdf"); return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_password_removed.pdf");
} }
@PostMapping("/add-password") @PostMapping(consumes = "multipart/form-data", value = "/add-password")
public ResponseEntity<byte[]> compressPDF(@RequestParam("fileInput") MultipartFile fileInput, @RequestParam(defaultValue = "", name = "password") String password, public ResponseEntity<byte[]> compressPDF(@RequestPart(required = true, value = "fileInput") MultipartFile fileInput,
@RequestParam(defaultValue = "128", name = "keyLength") int keyLength, @RequestParam(defaultValue = "false", name = "canAssembleDocument") boolean canAssembleDocument, @RequestParam(defaultValue = "", name = "password") String password, @RequestParam(defaultValue = "128", name = "keyLength") int keyLength,
@RequestParam(defaultValue = "false", name = "canAssembleDocument") boolean canAssembleDocument,
@RequestParam(defaultValue = "false", name = "canExtractContent") boolean canExtractContent, @RequestParam(defaultValue = "false", name = "canExtractContent") boolean canExtractContent,
@RequestParam(defaultValue = "false", name = "canExtractForAccessibility") boolean canExtractForAccessibility, @RequestParam(defaultValue = "false", name = "canExtractForAccessibility") boolean canExtractForAccessibility,
@RequestParam(defaultValue = "false", name = "canFillInForm") boolean canFillInForm, @RequestParam(defaultValue = "false", name = "canModify") boolean canModify, @RequestParam(defaultValue = "false", name = "canFillInForm") boolean canFillInForm, @RequestParam(defaultValue = "false", name = "canModify") boolean canModify,
@ -66,16 +65,5 @@ public class PasswordController {
return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf"); return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_passworded.pdf");
} }
@GetMapping("/change-permissions")
public String permissionsForm(Model model) {
model.addAttribute("currentPage", "change-permissions");
return "security/change-permissions";
}
@GetMapping("/remove-password")
public String removePasswordForm(Model model) {
model.addAttribute("currentPage", "remove-password");
return "security/remove-password";
}
} }

View file

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.security; package stirling.software.SPDF.controller.api.security;
import java.awt.Color; import java.awt.Color;
import java.io.IOException; import java.io.IOException;
@ -18,21 +18,23 @@ 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.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Hidden;
import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WatermarkRemover; import stirling.software.SPDF.utils.WatermarkRemover;
@Controller @RestController
public class WatermarkController { public class WatermarkController {
@PostMapping("/add-watermark") @PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
public ResponseEntity<byte[]> addWatermark(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("watermarkText") String watermarkText, public ResponseEntity<byte[]> addWatermark(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile, @RequestParam("watermarkText") String watermarkText,
@RequestParam(defaultValue = "30", name = "fontSize") float fontSize, @RequestParam(defaultValue = "0", name = "rotation") float rotation, @RequestParam(defaultValue = "30", name = "fontSize") float fontSize, @RequestParam(defaultValue = "0", name = "rotation") float rotation,
@RequestParam(defaultValue = "0.5", name = "opacity") float opacity, @RequestParam(defaultValue = "50", name = "widthSpacer") int widthSpacer, @RequestParam(defaultValue = "0.5", name = "opacity") float opacity, @RequestParam(defaultValue = "50", name = "widthSpacer") int widthSpacer,
@RequestParam(defaultValue = "50", name = "heightSpacer") int heightSpacer) throws IOException { @RequestParam(defaultValue = "50", name = "heightSpacer") int heightSpacer) throws IOException {
@ -81,14 +83,10 @@ public class WatermarkController {
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf"); return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
} }
@GetMapping("/add-watermark")
public String addWatermarkForm(Model model) {
model.addAttribute("currentPage", "add-watermark");
return "security/add-watermark";
}
@PostMapping("/remove-watermark") @PostMapping(consumes = "multipart/form-data", value = "/remove-watermark")
public ResponseEntity<byte[]> removeWatermark(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("watermarkText") String watermarkText) throws Exception { public ResponseEntity<byte[]> removeWatermark(@RequestPart(required = true, value = "fileInput") MultipartFile pdfFile, @RequestParam("watermarkText") String watermarkText)
throws Exception {
// Load the input PDF // Load the input PDF
PDDocument document = PDDocument.load(pdfFile.getInputStream()); PDDocument document = PDDocument.load(pdfFile.getInputStream());
@ -141,10 +139,5 @@ public class WatermarkController {
return PdfUtils.pdfDocToWebResponse(outputDocument, "removed.pdf"); return PdfUtils.pdfDocToWebResponse(outputDocument, "removed.pdf");
} }
@GetMapping("/remove-watermark")
public String removeWatermarkForm(Model model) {
model.addAttribute("currentPage", "remove-watermark");
return "security/remove-watermark";
}
} }

View file

@ -1,86 +0,0 @@
package stirling.software.SPDF.controller.converters;
import java.io.IOException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import stirling.software.SPDF.utils.PDFToFile;
@Controller
public class ConvertPDFToOffice {
@GetMapping("/pdf-to-html")
public ModelAndView pdfToHTML() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-html");
modelAndView.addObject("currentPage", "pdf-to-html");
return modelAndView;
}
@GetMapping("/pdf-to-presentation")
public ModelAndView pdfToPresentation() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-presentation");
modelAndView.addObject("currentPage", "pdf-to-presentation");
return modelAndView;
}
@GetMapping("/pdf-to-text")
public ModelAndView pdfToText() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-text");
modelAndView.addObject("currentPage", "pdf-to-text");
return modelAndView;
}
@GetMapping("/pdf-to-word")
public ModelAndView pdfToWord() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-word");
modelAndView.addObject("currentPage", "pdf-to-word");
return modelAndView;
}
@GetMapping("/pdf-to-xml")
public ModelAndView pdfToXML() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-xml");
modelAndView.addObject("currentPage", "pdf-to-xml");
return modelAndView;
}
@PostMapping("/pdf-to-html")
public ResponseEntity<byte[]> processPdfToHTML(@RequestParam("fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, "html", "writer_pdf_import");
}
@PostMapping("/pdf-to-presentation")
public ResponseEntity<byte[]> processPdfToPresentation(@RequestParam("fileInput") MultipartFile inputFile, @RequestParam("outputFormat") String outputFormat)
throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "impress_pdf_import");
}
@PostMapping("/pdf-to-text")
public ResponseEntity<byte[]> processPdfToRTForTXT(@RequestParam("fileInput") MultipartFile inputFile, @RequestParam("outputFormat") String outputFormat)
throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
}
@PostMapping("/pdf-to-word")
public ResponseEntity<byte[]> processPdfToWord(@RequestParam("fileInput") MultipartFile inputFile, @RequestParam("outputFormat") String outputFormat)
throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, outputFormat, "writer_pdf_import");
}
@PostMapping("/pdf-to-xml")
public ResponseEntity<byte[]> processPdfToXML(@RequestParam("fileInput") MultipartFile inputFile) throws IOException, InterruptedException {
PDFToFile pdfToFile = new PDFToFile();
return pdfToFile.processPdfToOfficeFormat(inputFile, "xml", "writer_pdf_import");
}
}

View file

@ -0,0 +1,86 @@
package stirling.software.SPDF.controller.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
@Controller
public class ConverterWebController {
@GetMapping("/img-to-pdf")
@Hidden
public String convertImgToPdfForm(Model model) {
model.addAttribute("currentPage", "img-to-pdf");
return "convert/img-to-pdf";
}
@GetMapping("/pdf-to-img")
@Hidden
public String pdfToimgForm(Model model) {
model.addAttribute("currentPage", "pdf-to-img");
return "convert/pdf-to-img";
}
@GetMapping("/file-to-pdf")
@Hidden
public String convertToPdfForm(Model model) {
model.addAttribute("currentPage", "file-to-pdf");
return "convert/file-to-pdf";
}
//PDF TO......
@GetMapping("/pdf-to-html")
@Hidden
public ModelAndView pdfToHTML() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-html");
modelAndView.addObject("currentPage", "pdf-to-html");
return modelAndView;
}
@GetMapping("/pdf-to-presentation")
@Hidden
public ModelAndView pdfToPresentation() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-presentation");
modelAndView.addObject("currentPage", "pdf-to-presentation");
return modelAndView;
}
@GetMapping("/pdf-to-text")
@Hidden
public ModelAndView pdfToText() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-text");
modelAndView.addObject("currentPage", "pdf-to-text");
return modelAndView;
}
@GetMapping("/pdf-to-word")
@Hidden
public ModelAndView pdfToWord() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-word");
modelAndView.addObject("currentPage", "pdf-to-word");
return modelAndView;
}
@GetMapping("/pdf-to-xml")
@Hidden
public ModelAndView pdfToXML() {
ModelAndView modelAndView = new ModelAndView("convert/pdf-to-xml");
modelAndView.addObject("currentPage", "pdf-to-xml");
return modelAndView;
}
@GetMapping("/pdf-to-pdfa")
@Hidden
public String pdfToPdfAForm(Model model) {
model.addAttribute("currentPage", "pdf-to-pdfa");
return "convert/pdf-to-pdfa";
}
}

View file

@ -0,0 +1,62 @@
package stirling.software.SPDF.controller.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import io.swagger.v3.oas.annotations.Hidden;
@Controller
public class GeneralWebController {
@GetMapping("/merge-pdfs")
@Hidden
public String mergePdfForm(Model model) {
model.addAttribute("currentPage", "merge-pdfs");
return "merge-pdfs";
}
@GetMapping("/multi-tool")
@Hidden
public String multiToolForm(Model model) {
model.addAttribute("currentPage", "multi-tool");
return "multi-tool";
}
@GetMapping("/")
public String home(Model model) {
model.addAttribute("currentPage", "home");
return "home";
}
@GetMapping("/home")
public String root(Model model) {
return "redirect:/";
}
@GetMapping("/remove-pages")
@Hidden
public String pageDeleter(Model model) {
model.addAttribute("currentPage", "remove-pages");
return "remove-pages";
}
@GetMapping("/pdf-organizer")
@Hidden
public String pageOrganizer(Model model) {
model.addAttribute("currentPage", "pdf-organizer");
return "pdf-organizer";
}
@GetMapping("/rotate-pdf")
@Hidden
public String rotatePdfForm(Model model) {
model.addAttribute("currentPage", "rotate-pdf");
return "rotate-pdf";
}
@GetMapping("/split-pdfs")
@Hidden
public String splitPdfForm(Model model) {
model.addAttribute("currentPage", "split-pdfs");
return "split-pdfs";
}
}

View file

@ -0,0 +1,75 @@
package stirling.software.SPDF.controller.web;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
@Controller
public class OtherWebController {
@GetMapping("/compress-pdf")
@Hidden
public String compressPdfForm(Model model) {
model.addAttribute("currentPage", "compress-pdf");
return "other/compress-pdf";
}
@GetMapping("/extract-image-scans")
@Hidden
public ModelAndView extractImageScansForm() {
ModelAndView modelAndView = new ModelAndView("other/extract-image-scans");
modelAndView.addObject("currentPage", "extract-image-scans");
return modelAndView;
}
@GetMapping("/extract-images")
@Hidden
public String extractImagesForm(Model model) {
model.addAttribute("currentPage", "extract-images");
return "other/extract-images";
}
@GetMapping("/change-metadata")
@Hidden
public String addWatermarkForm(Model model) {
model.addAttribute("currentPage", "change-metadata");
return "other/change-metadata";
}
public List<String> getAvailableTesseractLanguages() {
String tessdataDir = "/usr/share/tesseract-ocr/4.00/tessdata";
File[] files = new File(tessdataDir).listFiles();
if (files == null) {
return Collections.emptyList();
}
return Arrays.stream(files).filter(file -> file.getName().endsWith(".traineddata")).map(file -> file.getName().replace(".traineddata", ""))
.filter(lang -> !lang.equalsIgnoreCase("osd")).collect(Collectors.toList());
}
@GetMapping("/ocr-pdf")
@Hidden
public ModelAndView ocrPdfPage() {
ModelAndView modelAndView = new ModelAndView("other/ocr-pdf");
modelAndView.addObject("languages", getAvailableTesseractLanguages());
modelAndView.addObject("currentPage", "ocr-pdf");
return modelAndView;
}
@GetMapping("/add-image")
@Hidden
public String overlayImage(Model model) {
model.addAttribute("currentPage", "add-image");
return "other/add-image";
}
}

View file

@ -0,0 +1,46 @@
package stirling.software.SPDF.controller.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import io.swagger.v3.oas.annotations.Hidden;
@Controller
public class SecurityWebController {
@GetMapping("/add-password")
@Hidden
public String addPasswordForm(Model model) {
model.addAttribute("currentPage", "add-password");
return "security/add-password";
}
@GetMapping("/change-permissions")
@Hidden
public String permissionsForm(Model model) {
model.addAttribute("currentPage", "change-permissions");
return "security/change-permissions";
}
@GetMapping("/remove-password")
@Hidden
public String removePasswordForm(Model model) {
model.addAttribute("currentPage", "remove-password");
return "security/remove-password";
}
@GetMapping("/add-watermark")
@Hidden
public String addWatermarkForm(Model model) {
model.addAttribute("currentPage", "add-watermark");
return "security/add-watermark";
}
//WIP
@GetMapping("/remove-watermark")
@Hidden
public String removeWatermarkForm(Model model) {
model.addAttribute("currentPage", "remove-watermark");
return "security/remove-watermark";
}
}

View file

@ -58,7 +58,6 @@ public class PDFToFile {
// Get output files // Get output files
List<File> outputFiles = Arrays.asList(tempOutputDir.toFile().listFiles()); List<File> outputFiles = Arrays.asList(tempOutputDir.toFile().listFiles());
if (outputFiles.size() == 1) { if (outputFiles.size() == 1) {
// Return single output file // Return single output file
File outputFile = outputFiles.get(0); File outputFile = outputFiles.get(0);

View file

@ -48,10 +48,10 @@ public class PdfUtils {
} }
public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException { public static ResponseEntity<byte[]> boasToWebResponse(ByteArrayOutputStream baos, String docName, MediaType mediaType) throws IOException {
return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType ); return PdfUtils.bytesToWebResponse(baos.toByteArray(), docName, mediaType);
} }
public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType ) throws IOException { public static ResponseEntity<byte[]> bytesToWebResponse(byte[] bytes, String docName, MediaType mediaType) throws IOException {
// Return the PDF as a response // Return the PDF as a response
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();

View file

@ -0,0 +1,35 @@
/* Rainbow Mode Styles */
body {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%);
color: #fff !important;
}
.dark-card {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
color: white !important;
}
.jumbotron {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%);
color: #fff !important;
}
.list-group {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
color: fff !important;
}
.list-group-item {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
color: fff !important;
}
#support-section {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
}
#pages-container-wrapper {
--background-color: rgba(255, 255, 255, 0.046) !important;
--scroll-bar-color: #4c4c4c !important;
--scroll-bar-thumb: #d3d3d3 !important;
--scroll-bar-thumb-hover: #ffffff !important;
}

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-rainbow" viewBox="0 0 16 16">
<path d="M8 4.5a7 7 0 0 0-7 7 .5.5 0 0 1-1 0 8 8 0 1 1 16 0 .5.5 0 0 1-1 0 7 7 0 0 0-7-7zm0 2a5 5 0 0 0-5 5 .5.5 0 0 1-1 0 6 6 0 1 1 12 0 .5.5 0 0 1-1 0 5 5 0 0 0-5-5zm0 2a3 3 0 0 0-3 3 .5.5 0 0 1-1 0 4 4 0 1 1 8 0 .5.5 0 0 1-1 0 3 3 0 0 0-3-3zm0 2a1 1 0 0 0-1 1 .5.5 0 0 1-1 0 2 2 0 1 1 4 0 .5.5 0 0 1-1 0 1 1 0 0 0-1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 459 B

View file

@ -28,53 +28,78 @@
<!-- Custom --> <!-- Custom -->
<link rel="stylesheet" href="css/general.css"> <link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" th:href="@{css/dark-mode.css}" id="dark-mode-styles"> <link rel="stylesheet" th:href="@{css/dark-mode.css}" id="dark-mode-styles">
<link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled="true">
<script> <script>
var toggleCount = 0;
var lastToggleTime = Date.now();
function toggleDarkMode() { function toggleDarkMode() {
var currentTime = Date.now();
if (currentTime - lastToggleTime < 1000) {
toggleCount++;
} else {
toggleCount = 1;
}
lastToggleTime = currentTime;
var darkModeStyles = document.getElementById("dark-mode-styles"); var darkModeStyles = document.getElementById("dark-mode-styles");
var rainbowModeStyles = document.getElementById("rainbow-mode-styles");
var darkModeIcon = document.getElementById("dark-mode-icon"); var darkModeIcon = document.getElementById("dark-mode-icon");
if (localStorage.getItem("dark-mode") == "on") { if (toggleCount >= 18) {
localStorage.setItem("dark-mode", "rainbow");
darkModeStyles.disabled = true;
rainbowModeStyles.disabled = false;
darkModeIcon.src = "rainbow.svg";
} else if (localStorage.getItem("dark-mode") == "on") {
localStorage.setItem("dark-mode", "off"); localStorage.setItem("dark-mode", "off");
darkModeStyles.disabled = true; darkModeStyles.disabled = true;
rainbowModeStyles.disabled = true;
darkModeIcon.src = "sun.svg"; darkModeIcon.src = "sun.svg";
} else { } else {
localStorage.setItem("dark-mode", "on"); localStorage.setItem("dark-mode", "on");
darkModeStyles.disabled = false; darkModeStyles.disabled = false;
rainbowModeStyles.disabled = true;
darkModeIcon.src = "moon.svg"; darkModeIcon.src = "moon.svg";
} }
} }
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
var darkModeStyles = document.getElementById("dark-mode-styles"); var darkModeStyles = document.getElementById("dark-mode-styles");
var rainbowModeStyles = document.getElementById("rainbow-mode-styles");
var darkModeIcon = document.getElementById("dark-mode-icon"); var darkModeIcon = document.getElementById("dark-mode-icon");
// Check if the user has already set a preference
if (localStorage.getItem("dark-mode") == "on") { if (localStorage.getItem("dark-mode") == "on") {
darkModeStyles.disabled = false; darkModeStyles.disabled = false;
rainbowModeStyles.disabled = true;
darkModeIcon.src = "moon.svg"; darkModeIcon.src = "moon.svg";
} else if (localStorage.getItem("dark-mode") == "off") { } else if (localStorage.getItem("dark-mode") == "off") {
darkModeStyles.disabled = true; darkModeStyles.disabled = true;
rainbowModeStyles.disabled = true;
darkModeIcon.src = "sun.svg"; darkModeIcon.src = "sun.svg";
} else if (localStorage.getItem("dark-mode") == "rainbow") {
darkModeStyles.disabled = true;
rainbowModeStyles.disabled = false;
darkModeIcon.src = "rainbow.svg";
} else { } else {
// Check the OS's default dark mode setting
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
darkModeStyles.disabled = false; darkModeStyles.disabled = false;
rainbowModeStyles.disabled = true;
darkModeIcon.src = "moon.svg"; darkModeIcon.src = "moon.svg";
} else { } else {
darkModeStyles.disabled = true; darkModeStyles.disabled = true;
rainbowModeStyles.disabled = true;
darkModeIcon.src = "sun.svg"; darkModeIcon.src = "sun.svg";
} }
} }
// Attach the toggleDarkMode function to the click event of the dark mode toggle
document.getElementById("dark-mode-toggle").addEventListener("click", function (event) { document.getElementById("dark-mode-toggle").addEventListener("click", function (event) {
event.preventDefault(); event.preventDefault();
toggleDarkMode(); toggleDarkMode();
}); });
}); });
</script>
</script>
</head> </head>
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}"> <th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}">
<div class="custom-file-chooser"> <div class="custom-file-chooser">

View file

@ -16,6 +16,31 @@
<form id="multiPdfForm" th:action="@{extract-image-scans}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{extract-image-scans}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div>
<div class="form-group">
<label for="angleThreshold">Angle Threshold:</label>
<input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="5">
<small id="angleThresholdHelp" class="form-text text-muted">Sets the minimum absolute angle required for the image to be rotated (default: 10).</small>
</div>
<div class="form-group">
<label for="tolerance">Tolerance:</label>
<input type="number" class="form-control" id="tolerance" name="tolerance" value="20">
<small id="toleranceHelp" class="form-text text-muted">Determines the range of color variation around the estimated background color (default: 30).</small>
</div>
<div class="form-group">
<label for="minArea">Minimum Area:</label>
<input type="number" class="form-control" id="minArea" name="min_area" value="8000">
<small id="minAreaHelp" class="form-text text-muted">Sets the minimum area threshold for a photo (default: 10000).</small>
</div>
<div class="form-group">
<label for="minContourArea">Minimum Contour Area:</label>
<input type="number" class="form-control" id="minContourArea" name="min_contour_area" value="500">
<small id="minContourAreaHelp" class="form-text text-muted">Sets the minimum contour area threshold for a photo (default: 500).</small>
</div>
<div class="form-group">
<label for="borderSize">Border Size:</label>
<input type="number" class="form-control" id="borderSize" name="border_size" value="0">
<small id="borderSizeHelp" class="form-text text-muted">Sets the size of the border added and removed to prevent white borders in the output (default: 0).</small>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{extractImageScans.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{extractImageScans.submit}"></button>
</form> </form>
</div> </div>