mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-03 17:52:30 +02:00
changes to image
This commit is contained in:
parent
0890073bd4
commit
9390ba971b
@ -21,8 +21,9 @@ dependencies {
|
|||||||
|
|
||||||
//general PDF
|
//general PDF
|
||||||
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
|
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
|
||||||
|
|
||||||
implementation 'com.itextpdf:itextpdf:5.5.13.3'
|
implementation 'com.itextpdf:itextpdf:5.5.13.3'
|
||||||
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
package stirling.software.SPDF.controller;
|
package stirling.software.SPDF.controller;
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.COSName;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDResources;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
@ -26,30 +18,8 @@ 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.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.itextpdf.text.DocumentException;
|
|
||||||
import com.itextpdf.text.pdf.PdfReader;
|
|
||||||
import com.itextpdf.text.pdf.PdfStamper;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class CompressController {
|
public class CompressController {
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package stirling.software.SPDF.controller;
|
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.COSName;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDResources;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
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 com.itextpdf.text.DocumentException;
|
|
||||||
import com.itextpdf.text.pdf.PdfReader;
|
|
||||||
import com.itextpdf.text.pdf.PdfStamper;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
public class CropController {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(CropController.class);
|
|
||||||
|
|
||||||
@GetMapping("/crop-pdf")
|
|
||||||
public String compressPdfForm(Model model) {
|
|
||||||
model.addAttribute("currentPage", "crop-pdf");
|
|
||||||
return "crop-pdf";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,10 +1,8 @@
|
|||||||
package stirling.software.SPDF.controller;
|
package stirling.software.SPDF.controller;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@ -13,11 +11,12 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
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.stereotype.Controller;
|
||||||
@ -28,13 +27,6 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
//import com.spire.pdf.*;
|
//import com.spire.pdf.*;
|
||||||
@Controller
|
@Controller
|
||||||
public class OCRController {
|
public class OCRController {
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package stirling.software.SPDF.controller;
|
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.COSName;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDResources;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
|
||||||
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 com.itextpdf.text.DocumentException;
|
|
||||||
import com.itextpdf.text.pdf.PdfReader;
|
|
||||||
import com.itextpdf.text.pdf.PdfStamper;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
public class SignController {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(SignController.class);
|
|
||||||
|
|
||||||
@GetMapping("/sign-pdf")
|
|
||||||
public String compressPdfForm(Model model) {
|
|
||||||
model.addAttribute("currentPage", "sign-pdf");
|
|
||||||
return "sign-pdf";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller;
|
package stirling.software.SPDF.controller;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -10,7 +9,6 @@ import java.nio.file.FileSystem;
|
|||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -108,7 +106,7 @@ public class SplitPDFController {
|
|||||||
document.close();
|
document.close();
|
||||||
|
|
||||||
// create the zip file
|
// create the zip file
|
||||||
Path zipFile = Paths.get("split_documents.zip");
|
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||||
URI uri = URI.create("jar:file:" + zipFile.toUri().getPath());
|
URI uri = URI.create("jar:file:" + zipFile.toUri().getPath());
|
||||||
Map<String, String> env = new HashMap<>();
|
Map<String, String> env = new HashMap<>();
|
||||||
env.put("create", "true");
|
env.put("create", "true");
|
||||||
@ -132,7 +130,7 @@ public class SplitPDFController {
|
|||||||
logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
|
logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
|
||||||
byte[] data = Files.readAllBytes(zipFile);
|
byte[] data = Files.readAllBytes(zipFile);
|
||||||
ByteArrayResource resource = new ByteArrayResource(data);
|
ByteArrayResource resource = new ByteArrayResource(data);
|
||||||
new File("split_documents.zip").delete();
|
Files.delete(zipFile);
|
||||||
// return the Resource in the response
|
// return the Resource in the response
|
||||||
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_split.zip").contentType(MediaType.APPLICATION_OCTET_STREAM)
|
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_split.zip").contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
.contentLength(resource.contentLength()).body(resource);
|
.contentLength(resource.contentLength()).body(resource);
|
||||||
|
@ -38,12 +38,13 @@ public class ConvertImgPDFController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/img-to-pdf")
|
@PostMapping("/img-to-pdf")
|
||||||
public ResponseEntity<byte[]> convertToPdf(@RequestParam("fileInput") MultipartFile file) throws IOException {
|
public ResponseEntity<byte[]> convertToPdf(@RequestParam("fileInput") MultipartFile[] file,
|
||||||
|
@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
|
||||||
byte[] bytes = PdfUtils.convertToPdf(file.getInputStream());
|
System.out.println(stretchToFit);
|
||||||
logger.info("File {} successfully converted to pdf", file.getOriginalFilename());
|
byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate);
|
||||||
|
return PdfUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_coverted.pdf");
|
||||||
return PdfUtils.bytesToWebResponse(bytes, file.getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_coverted.pdf");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/pdf-to-img")
|
@PostMapping("/pdf-to-img")
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package stirling.software.SPDF.controller.converters;
|
package stirling.software.SPDF.controller.converters;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -17,9 +14,7 @@ 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.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.LibreOfficeListener;
|
|
||||||
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
|
@Controller
|
||||||
|
@ -8,6 +8,7 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -28,6 +29,7 @@ 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.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.itextpdf.text.Document;
|
import com.itextpdf.text.Document;
|
||||||
import com.itextpdf.text.DocumentException;
|
import com.itextpdf.text.DocumentException;
|
||||||
@ -37,49 +39,100 @@ public class PdfUtils {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
|
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
|
||||||
|
|
||||||
public static byte[] convertToPdf(InputStream imageStream) throws IOException {
|
public static byte[] imageToPdf(MultipartFile[] files, boolean stretchToFit, boolean autoRotate) throws IOException {
|
||||||
|
|
||||||
// Create a File object for the image
|
|
||||||
File imageFile = new File("image.jpg");
|
|
||||||
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(imageFile); InputStream input = imageStream) {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int len;
|
|
||||||
// Read from the input stream and write to the file
|
|
||||||
while ((len = input.read(buffer)) != -1) {
|
|
||||||
fos.write(buffer, 0, len);
|
|
||||||
}
|
|
||||||
logger.info("Image successfully written to file: {}", imageFile.getAbsolutePath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("Error writing image to file: {}", imageFile.getAbsolutePath(), e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (PDDocument doc = new PDDocument()) {
|
try (PDDocument doc = new PDDocument()) {
|
||||||
// Create a new PDF page
|
for (MultipartFile file : files) {
|
||||||
PDPage page = new PDPage();
|
// Create a temporary file for the image
|
||||||
doc.addPage(page);
|
File imageFile = Files.createTempFile("image", ".jpg").toFile();
|
||||||
|
|
||||||
// Create an image object from the image file
|
try (FileOutputStream fos = new FileOutputStream(imageFile); InputStream input = file.getInputStream()) {
|
||||||
PDImageXObject image = PDImageXObject.createFromFileByContent(imageFile, doc);
|
byte[] buffer = new byte[1024];
|
||||||
|
int len;
|
||||||
|
// Read from the input stream and write to the file
|
||||||
|
while ((len = input.read(buffer)) != -1) {
|
||||||
|
fos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
logger.info("Image successfully written to file: {}", imageFile.getAbsolutePath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error writing image to file: {}", imageFile.getAbsolutePath(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
|
// Create a new PDF page
|
||||||
// Draw the image onto the page
|
PDPage page = new PDPage();
|
||||||
contentStream.drawImage(image, 0, 0);
|
doc.addPage(page);
|
||||||
logger.info("Image successfully added to PDF");
|
|
||||||
} catch (IOException e) {
|
// Create an image object from the image file
|
||||||
logger.error("Error adding image to PDF", e);
|
PDImageXObject image = PDImageXObject.createFromFileByContent(imageFile, doc);
|
||||||
throw e;
|
|
||||||
|
float pageWidth = page.getMediaBox().getWidth();
|
||||||
|
float pageHeight = page.getMediaBox().getHeight();
|
||||||
|
|
||||||
|
if (autoRotate && ((image.getWidth() > image.getHeight() && pageHeight > pageWidth) || (image.getWidth() < image.getHeight() && pageWidth > pageHeight))) {
|
||||||
|
// Rotate the page 90 degrees if the image better fits the page in landscape orientation
|
||||||
|
page.setRotation(90);
|
||||||
|
pageWidth = page.getMediaBox().getHeight();
|
||||||
|
pageHeight = page.getMediaBox().getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
|
||||||
|
if (stretchToFit) {
|
||||||
|
if (page.getRotation() == 0 || page.getRotation() == 180) {
|
||||||
|
// Stretch the image to fit the whole page
|
||||||
|
contentStream.drawImage(image, 0, 0, pageWidth, pageHeight);
|
||||||
|
} else {
|
||||||
|
// Adjust the width and height of the page when rotated
|
||||||
|
contentStream.drawImage(image, 0, 0, pageHeight, pageWidth);
|
||||||
|
}
|
||||||
|
logger.info("Image successfully added to PDF, stretched to fit page");
|
||||||
|
} else {
|
||||||
|
// Ensure the image fits the page but maintain the image's aspect ratio
|
||||||
|
float imageAspectRatio = (float) image.getWidth() / (float) image.getHeight();
|
||||||
|
float pageAspectRatio = pageWidth / pageHeight;
|
||||||
|
|
||||||
|
// Determine the scale factor to fit the image onto the page
|
||||||
|
float scaleFactor = 1.0f;
|
||||||
|
if (imageAspectRatio > pageAspectRatio) {
|
||||||
|
// Image is wider than the page, scale to fit the width
|
||||||
|
scaleFactor = pageWidth / image.getWidth();
|
||||||
|
} else {
|
||||||
|
// Image is taller than the page, scale to fit the height
|
||||||
|
scaleFactor = pageHeight / image.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the position of the image on the page
|
||||||
|
float xPos = (pageWidth - (image.getWidth() * scaleFactor)) / 2;
|
||||||
|
float yPos = (pageHeight - (image.getHeight() * scaleFactor)) / 2;
|
||||||
|
|
||||||
|
// Draw the image onto the page
|
||||||
|
if (page.getRotation() == 0 || page.getRotation() == 180) {
|
||||||
|
contentStream.drawImage(image, xPos, yPos, image.getWidth() * scaleFactor, image.getHeight() * scaleFactor);
|
||||||
|
} else {
|
||||||
|
// Adjust the width and height of the page when rotated
|
||||||
|
contentStream.drawImage(image, yPos, xPos, image.getHeight() * scaleFactor, image.getWidth() * scaleFactor);
|
||||||
|
}
|
||||||
|
logger.info("Image successfully added to PDF, maintaining aspect ratio");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error adding image to PDF", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the temporary file
|
||||||
|
imageFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a ByteArrayOutputStream to save the PDF to
|
// Create a ByteArrayOutputStream to save the PDF to
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
doc.save(byteArrayOutputStream);
|
doc.save(byteArrayOutputStream);
|
||||||
logger.info("PDF successfully saved to byte array");
|
logger.info("PDF successfully saved to byte array");
|
||||||
|
|
||||||
return byteArrayOutputStream.toByteArray();
|
return byteArrayOutputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI)
|
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI)
|
||||||
throws IOException, Exception {
|
throws IOException, Exception {
|
||||||
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
|
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package stirling.software.SPDF.utils;
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
public class ProcessExecutor {
|
public class ProcessExecutor {
|
||||||
public static int runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
|
public static int runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||||
|
@ -16,4 +16,9 @@ server.error.include-stacktrace=always
|
|||||||
server.error.include-exception=true
|
server.error.include-exception=true
|
||||||
server.error.include-message=always
|
server.error.include-message=always
|
||||||
|
|
||||||
server.servlet.session.tracking-modes=cookie
|
server.servlet.session.tracking-modes=cookie
|
||||||
|
|
||||||
|
spring.devtools.restart.enabled=true
|
||||||
|
spring.devtools.livereload.enabled=true
|
||||||
|
|
||||||
|
spring.thymeleaf.encoding=UTF-8
|
@ -95,7 +95,7 @@ settings.downloadOption.title=\u062A\u062D\u062F\u064A\u062F \u062E\u064A\u0627\
|
|||||||
settings.downloadOption.1=\u0641\u062A\u062D \u0641\u064A \u0646\u0641\u0633 \u0627\u0644\u0646\u0627\u0641\u0630\u0629
|
settings.downloadOption.1=\u0641\u062A\u062D \u0641\u064A \u0646\u0641\u0633 \u0627\u0644\u0646\u0627\u0641\u0630\u0629
|
||||||
settings.downloadOption.2=\u0641\u062A\u062D \u0641\u064A \u0646\u0627\u0641\u0630\u0629 \u062C\u062F\u064A\u062F\u0629
|
settings.downloadOption.2=\u0641\u062A\u062D \u0641\u064A \u0646\u0627\u0641\u0630\u0629 \u062C\u062F\u064A\u062F\u0629
|
||||||
settings.downloadOption.3=\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u0644\u0641
|
settings.downloadOption.3=\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u0644\u0641
|
||||||
settings.zip=\u0645\u0644\u0641\u0627\u062A \u0627\u0644\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u0645\u062A\u0639\u062F\u062F \u0627\u0644\u0645\u0636\u063A\u0648\u0637\u0629
|
settings.zipThreshold=\u0645\u0644\u0641\u0627\u062A \u0645\u0636\u063A\u0648\u0637\u0629 \u0639\u0646\u062F \u062A\u062C\u0627\u0648\u0632 \u0639\u062F\u062F \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0627\u0644\u062A\u064A \u062A\u0645 \u062A\u0646\u0632\u064A\u0644\u0647\u0627
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
OCR.title = OCR
|
OCR.title = OCR
|
||||||
|
@ -4,32 +4,32 @@
|
|||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=PDF auswählen
|
pdfPrompt=PDF auswählen
|
||||||
multiPdfPrompt=PDFs auswählen(2+)
|
multiPdfPrompt=PDFs auswählen(2+)
|
||||||
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
|
multiPdfDropPrompt=Wählen Sie alle gewünschten PDFs aus (oder ziehen Sie sie per Drag & Drop hierhin)
|
||||||
imgPrompt=Wählen Sie ein Bild
|
imgPrompt=Wählen Sie ein Bild
|
||||||
genericSubmit=Einreichen
|
genericSubmit=Einreichen
|
||||||
processTimeWarning=Achtung: Abhängig von der Dateigröße kann dieser Prozess bis zu einer Minute dauern
|
processTimeWarning=Achtung: Abhängig von der DateigröÃe kann dieser Prozess bis zu einer Minute dauern
|
||||||
pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein):
|
pageOrderPrompt=Seitenreihenfolge (Geben Sie eine durch Komma getrennte Liste von Seitenzahlen ein):
|
||||||
goToPage=Los
|
goToPage=Los
|
||||||
true=Wahr
|
true=Wahr
|
||||||
false=Falsch
|
false=Falsch
|
||||||
unknown=Unbekannt
|
unknown=Unbekannt
|
||||||
save=Speichern
|
save=Speichern
|
||||||
close=Schließen
|
close=Schließen
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
#############
|
#############
|
||||||
home.desc=Ihr lokal gehosteter One-Stop-Shop für alle Ihre PDF-Anforderungen.
|
home.desc=Ihr lokal gehosteter One-Stop-Shop für alle Ihre PDF-Anforderungen.
|
||||||
|
|
||||||
navbar.convert=Konvertieren
|
navbar.convert=Konvertieren
|
||||||
navbar.security=Sicherheit
|
navbar.security=Sicherheit
|
||||||
navbar.other=Anderes
|
navbar.other=Anderes
|
||||||
navbar.darkmode=Dark Mode
|
navbar.darkmode=Dark Mode
|
||||||
|
|
||||||
home.merge.title=PDFs zusammenführen
|
home.merge.title=PDFs zusammenführen
|
||||||
home.merge.desc=Mehrere PDF-Dateien zu einer einzigen zusammenführen.
|
home.merge.desc=Mehrere PDF-Dateien zu einer einzigen zusammenführen.
|
||||||
|
|
||||||
home.split.title=PDFs aufteilen
|
home.split.title=PDFs aufteilen
|
||||||
home.split.desc=PDFs in mehrere Dokumente aufteilen.
|
home.split.desc=PDFs in mehrere Dokumente aufteilen.
|
||||||
@ -44,75 +44,75 @@ home.pdfToImage.title=PDF zu Bild
|
|||||||
home.pdfToImage.desc=Konvertieren Sie ein PDF in ein Bild (PNG, JPEG, GIF).
|
home.pdfToImage.desc=Konvertieren Sie ein PDF in ein Bild (PNG, JPEG, GIF).
|
||||||
|
|
||||||
home.pdfOrganiser.title=PDF organisieren
|
home.pdfOrganiser.title=PDF organisieren
|
||||||
home.pdfOrganiser.desc=Seiten entfernen und Seitenreihenfolge ändern.
|
home.pdfOrganiser.desc=Seiten entfernen und Seitenreihenfolge ändern.
|
||||||
|
|
||||||
home.addImage.title=Bild einfügen
|
home.addImage.title=Bild einfügen
|
||||||
home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (Work in progress).
|
home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (Work in progress).
|
||||||
|
|
||||||
home.watermark.title=Wasserzeichen hinzufügen
|
home.watermark.title=Wasserzeichen hinzufügen
|
||||||
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu.
|
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu.
|
||||||
|
|
||||||
home.remove-watermark.title=Wasserzeichen entfernen
|
home.remove-watermark.title=Wasserzeichen entfernen
|
||||||
home.remove-watermark.desc=Wasserzeichen aus Ihrem PDF-Dokument entfernen.
|
home.remove-watermark.desc=Wasserzeichen aus Ihrem PDF-Dokument entfernen.
|
||||||
|
|
||||||
home.permissions.title=Berechtigungen ändern
|
home.permissions.title=Berechtigungen ändern
|
||||||
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern.
|
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern.
|
||||||
|
|
||||||
home.removePages.title=Seiten entfernen
|
home.removePages.title=Seiten entfernen
|
||||||
home.removePages.desc=Ungewollte Seiten aus dem PDF entfernen.
|
home.removePages.desc=Ungewollte Seiten aus dem PDF entfernen.
|
||||||
|
|
||||||
home.addPassword.title=Passwort hinzufügen
|
home.addPassword.title=Passwort hinzufügen
|
||||||
home.addPassword.desc=Das PDF mit einem Passwort verschlüsseln.
|
home.addPassword.desc=Das PDF mit einem Passwort verschlüsseln.
|
||||||
|
|
||||||
home.removePassword.title=Passwort entfernen
|
home.removePassword.title=Passwort entfernen
|
||||||
home.removePassword.desc=Den Passwortschutz eines PDFs entfernen.
|
home.removePassword.desc=Den Passwortschutz eines PDFs entfernen.
|
||||||
|
|
||||||
home.compressPdfs.title=PDF komprimieren
|
home.compressPdfs.title=PDF komprimieren
|
||||||
home.compressPdfs.desc=PDF komprimieren um die Dateigröße zu reduzieren.
|
home.compressPdfs.desc=PDF komprimieren um die DateigröÃe zu reduzieren.
|
||||||
|
|
||||||
home.changeMetadata.title=Metadaten ändern
|
home.changeMetadata.title=Metadaten ändern
|
||||||
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
|
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
|
||||||
|
|
||||||
home.fileToPDF.title=Datei in PDF konvertieren
|
home.fileToPDF.title=Datei in PDF konvertieren
|
||||||
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
home.fileToPDF.desc=Konvertieren Sie nahezu jede Datei in PDF (DOCX, PNG, XLS, PPT, TXT und mehr)
|
||||||
|
|
||||||
home.ocr.title=OCR auf PDF ausführen
|
home.ocr.title=OCR auf PDF ausführen
|
||||||
home.ocr.desc=Scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
home.ocr.desc=Scannt und erkennt Text aus Bildern in einer PDF-Datei und fügt ihn erneut als Text hinzu.
|
||||||
|
|
||||||
home.extractImages.title=Bilder extrahieren
|
home.extractImages.title=Bilder extrahieren
|
||||||
home.extractImages.desc=Extrahiert alle Bilder aus einer PDF-Datei und speichert sie als Zip-Datei
|
home.extractImages.desc=Extrahiert alle Bilder aus einer PDF-Datei und speichert sie als Zip-Datei
|
||||||
|
|
||||||
navbar.settings=Einstellungen
|
navbar.settings=Einstellungen
|
||||||
settings.title=Einstellungen
|
settings.title=Einstellungen
|
||||||
settings.update=Update verfügbar
|
settings.update=Update verfügbar
|
||||||
settings.appVersion=App-Version:
|
settings.appVersion=App-Version:
|
||||||
settings.downloadOption.title=Download-Option wählen (für einzelne Dateien, die keine Zip-Downloads sind):
|
settings.downloadOption.title=Download-Option wählen (für einzelne Dateien, die keine Zip-Downloads sind):
|
||||||
settings.downloadOption.1=Im selben Fenster öffnen
|
settings.downloadOption.1=Im selben Fenster öffnen
|
||||||
settings.downloadOption.2=In neuem Fenster öffnen
|
settings.downloadOption.2=In neuem Fenster öffnen
|
||||||
settings.downloadOption.3=Datei herunterladen
|
settings.downloadOption.3=Datei herunterladen
|
||||||
settings.zip=Dateien mit mehrfachem Download zippen
|
settings.zipThreshold=Dateien komprimieren, wenn die Anzahl der heruntergeladenen Dateien überschritten wird
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR
|
ocr.title=OCR
|
||||||
ocr.header=OCR (Optische Zeichenerkennung)
|
ocr.header=OCR (Optische Zeichenerkennung)
|
||||||
ocr.selectText.1=Wählen Sie die Sprachen aus, die in der PDF-Datei erkannt werden sollen (die aufgelisteten sind die aktuell erkannten):
|
ocr.selectText.1=Wählen Sie die Sprachen aus, die in der PDF-Datei erkannt werden sollen (die aufgelisteten sind die aktuell erkannten):
|
||||||
ocr.selectText.2=Textdatei mit OCR-Text neben der OCR-PDF-Datei erstellen
|
ocr.selectText.2=Textdatei mit OCR-Text neben der OCR-PDF-Datei erstellen
|
||||||
ocr.help=Bitte lesen Sie diese Dokumentation, um zu erfahren, wie Sie dies für andere Sprachen verwenden und/oder nicht in Docker verwenden können
|
ocr.help=Bitte lesen Sie diese Dokumentation, um zu erfahren, wie Sie dies für andere Sprachen verwenden und/oder nicht in Docker verwenden können
|
||||||
ocr.credit=Dieser Dienst verwendet OCRmyPDF und Tesseract für OCR.
|
ocr.credit=Dieser Dienst verwendet OCRmyPDF und Tesseract für OCR.
|
||||||
ocr.submit=PDF mit OCR verarbeiten
|
ocr.submit=PDF mit OCR verarbeiten
|
||||||
|
|
||||||
|
|
||||||
extractImages.title=Bilder extrahieren
|
extractImages.title=Bilder extrahieren
|
||||||
extractImages.header=Bilder extrahieren
|
extractImages.header=Bilder extrahieren
|
||||||
extractImages.selectText=Wählen Sie das Bildformat aus, in das extrahierte Bilder konvertiert werden sollen
|
extractImages.selectText=Wählen Sie das Bildformat aus, in das extrahierte Bilder konvertiert werden sollen
|
||||||
extractImages.submit=Extrahieren
|
extractImages.submit=Extrahieren
|
||||||
|
|
||||||
|
|
||||||
#File to PDF
|
#File to PDF
|
||||||
fileToPDF.title=Datei in PDF
|
fileToPDF.title=Datei in PDF
|
||||||
fileToPDF.header=Beliebige Dateien in PDF konvertieren
|
fileToPDF.header=Beliebige Dateien in PDF konvertieren
|
||||||
fileToPDF.credit=Dieser Dienst verwendet LibreOffice und Unoconv für die Dateikonvertierung.
|
fileToPDF.credit=Dieser Dienst verwendet LibreOffice und Unoconv für die Dateikonvertierung.
|
||||||
fileToPDF.supportedFileTypes=Unterstützte Dateitypen sollten die folgenden enthalten, eine vollständige aktualisierte Liste der unterstützten Formate finden Sie jedoch in der LibreOffice-Dokumentation
|
fileToPDF.supportedFileTypes=Unterstützte Dateitypen sollten die folgenden enthalten, eine vollständige aktualisierte Liste der unterstützten Formate finden Sie jedoch in der LibreOffice-Dokumentation
|
||||||
fileToPDF.submit=In PDF konvertieren
|
fileToPDF.submit=In PDF konvertieren
|
||||||
|
|
||||||
|
|
||||||
@ -120,14 +120,14 @@ fileToPDF.submit=In PDF konvertieren
|
|||||||
|
|
||||||
|
|
||||||
#Add image
|
#Add image
|
||||||
addImage.title=Bild hinzufügen
|
addImage.title=Bild hinzufügen
|
||||||
addImage.header=Ein Bild einfügen (Work in progress)
|
addImage.header=Ein Bild einfügen (Work in progress)
|
||||||
addImage.submit=Bild hinzufügen
|
addImage.submit=Bild hinzufügen
|
||||||
|
|
||||||
#compress
|
#compress
|
||||||
compress.title=Komprimieren
|
compress.title=Komprimieren
|
||||||
compress.header=PDF komprimieren
|
compress.header=PDF komprimieren
|
||||||
compress.credit=Dieser Dienst verwendet OCRmyPDF für die PDF-Komprimierung/-Optimierung.
|
compress.credit=Dieser Dienst verwendet OCRmyPDF für die PDF-Komprimierung/-Optimierung.
|
||||||
compress.selectText.1=Optimierungsstufe:
|
compress.selectText.1=Optimierungsstufe:
|
||||||
compress.selectText.2=0 (Keine Optimierung)
|
compress.selectText.2=0 (Keine Optimierung)
|
||||||
compress.selectText.3=1 (Standard, verlustfreie Optimierung)
|
compress.selectText.3=1 (Standard, verlustfreie Optimierung)
|
||||||
@ -139,9 +139,9 @@ compress.submit=Komprimieren
|
|||||||
|
|
||||||
|
|
||||||
#merge
|
#merge
|
||||||
merge.title=Zusammenführen
|
merge.title=Zusammenführen
|
||||||
merge.header=Mehrere PDFs zusammenführen (2+)
|
merge.header=Mehrere PDFs zusammenführen (2+)
|
||||||
merge.submit=Zusammenführen
|
merge.submit=Zusammenführen
|
||||||
|
|
||||||
#pdfOrganiser
|
#pdfOrganiser
|
||||||
pdfOrganiser.title=Seiten anordnen
|
pdfOrganiser.title=Seiten anordnen
|
||||||
@ -153,12 +153,12 @@ pdfOrganiser.submit=Seiten anordnen
|
|||||||
pageRemover.title=Seiten entfernen
|
pageRemover.title=Seiten entfernen
|
||||||
pageRemover.header=PDF Seiten entfernen
|
pageRemover.header=PDF Seiten entfernen
|
||||||
pageRemover.pagesToDelete=Seiten zu entfernen (geben Sie eine Kommagetrennte Liste der Seitenzahlen an):
|
pageRemover.pagesToDelete=Seiten zu entfernen (geben Sie eine Kommagetrennte Liste der Seitenzahlen an):
|
||||||
pageRemover.submit=Seiten löschen
|
pageRemover.submit=Seiten löschen
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=PDF drehen
|
rotate.title=PDF drehen
|
||||||
rotate.header=PDF drehen
|
rotate.header=PDF drehen
|
||||||
rotate.selectAngle=Wählen Sie den Winkel (in Vielfachen von 90 Grad):
|
rotate.selectAngle=Wählen Sie den Winkel (in Vielfachen von 90 Grad):
|
||||||
rotate.submit=Drehen
|
rotate.submit=Drehen
|
||||||
|
|
||||||
|
|
||||||
@ -167,8 +167,8 @@ rotate.submit=Drehen
|
|||||||
#merge
|
#merge
|
||||||
split.title=PDF aufteilen
|
split.title=PDF aufteilen
|
||||||
split.header=PDF aufteilen
|
split.header=PDF aufteilen
|
||||||
split.desc.1=Die Nummern, die Sie auswählen, sind die Seitenzahlen, an denen Sie aufteilen möchten.
|
split.desc.1=Die Nummern, die Sie auswählen, sind die Seitenzahlen, an denen Sie aufteilen möchten.
|
||||||
split.desc.2=So würde die Auswahl von 1,3,7-8 ein 10-seitiges Dokument in 6 separate PDFs aufteilen, mit:
|
split.desc.2=So würde die Auswahl von 1,3,7-8 ein 10-seitiges Dokument in 6 separate PDFs aufteilen, mit:
|
||||||
split.desc.3=Dokument #1: Seite 1
|
split.desc.3=Dokument #1: Seite 1
|
||||||
split.desc.4=Dokument #2: Seite 2 und 3
|
split.desc.4=Dokument #2: Seite 2 und 3
|
||||||
split.desc.5=Dokument #3: Seite 4, 5 und 6
|
split.desc.5=Dokument #3: Seite 4, 5 und 6
|
||||||
@ -189,97 +189,97 @@ pdfToImage.title=PDF zu Bild
|
|||||||
pdfToImage.header=PDF zu Bild
|
pdfToImage.header=PDF zu Bild
|
||||||
pdfToImage.selectText=Bildformat
|
pdfToImage.selectText=Bildformat
|
||||||
pdfToImage.singleOrMultiple=Bildergebnistyp
|
pdfToImage.singleOrMultiple=Bildergebnistyp
|
||||||
pdfToImage.single=Einzelnes großes Bild
|
pdfToImage.single=Einzelnes großes Bild
|
||||||
pdfToImage.multi=Mehrere Bilder
|
pdfToImage.multi=Mehrere Bilder
|
||||||
pdfToImage.colorType=Farbtyp
|
pdfToImage.colorType=Farbtyp
|
||||||
pdfToImage.color=Farbe
|
pdfToImage.color=Farbe
|
||||||
pdfToImage.grey=Graustufen
|
pdfToImage.grey=Graustufen
|
||||||
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
|
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
|
||||||
pdfToImage.submit=Umwandeln
|
pdfToImage.submit=Umwandeln
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
addPassword.title=Passwort hinzufügen
|
addPassword.title=Passwort hinzufügen
|
||||||
addPassword.header=Passwort hinzufügen (Verschlüsseln)
|
addPassword.header=Passwort hinzufügen (Verschlüsseln)
|
||||||
addPassword.selectText.1=Das zu verschlüsselnde PDF auswählen
|
addPassword.selectText.1=Das zu verschlüsselnde PDF auswählen
|
||||||
addPassword.selectText.2=Passwort
|
addPassword.selectText.2=Passwort
|
||||||
addPassword.selectText.3=Länge des Schlüssels
|
addPassword.selectText.3=Länge des Schlüssels
|
||||||
addPassword.selectText.4=Größere Werte sind stärker, aber niedrigere Werte sind besser kompatibel.
|
addPassword.selectText.4=GröÃere Werte sind stärker, aber niedrigere Werte sind besser kompatibel.
|
||||||
addPassword.selectText.5=Zu setzende Berechtigungen
|
addPassword.selectText.5=Zu setzende Berechtigungen
|
||||||
addPassword.selectText.6=Das zusammensetzen des PDFs verhindern
|
addPassword.selectText.6=Das zusammensetzen des PDFs verhindern
|
||||||
addPassword.selectText.7=Inhaltsextrahierung verhindern
|
addPassword.selectText.7=Inhaltsextrahierung verhindern
|
||||||
addPassword.selectText.8=Inhaltsextrahierung zur Barrierefreiheit verhindern
|
addPassword.selectText.8=Inhaltsextrahierung zur Barrierefreiheit verhindern
|
||||||
addPassword.selectText.9=Ausfüllen des Formulars verhindern
|
addPassword.selectText.9=Ausfüllen des Formulars verhindern
|
||||||
addPassword.selectText.10=Modifizierung verhindern
|
addPassword.selectText.10=Modifizierung verhindern
|
||||||
addPassword.selectText.11=Ändern von Kommentaren verhindern
|
addPassword.selectText.11=Ãndern von Kommentaren verhindern
|
||||||
addPassword.selectText.12=Drucken verhindern
|
addPassword.selectText.12=Drucken verhindern
|
||||||
addPassword.selectText.13=Drucken verschiedener Formate verhindern
|
addPassword.selectText.13=Drucken verschiedener Formate verhindern
|
||||||
addPassword.submit=Verschlüsseln
|
addPassword.submit=Verschlüsseln
|
||||||
|
|
||||||
#watermark
|
#watermark
|
||||||
watermark.title=Wasserzeichen hinzufügen
|
watermark.title=Wasserzeichen hinzufügen
|
||||||
watermark.header=Wasserzeichen hinzufügen
|
watermark.header=Wasserzeichen hinzufügen
|
||||||
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
|
watermark.selectText.1=PDF auswählen, dem ein Wasserzeichen hinzugefügt werden soll:
|
||||||
watermark.selectText.2=Wasserzeichen Text:
|
watermark.selectText.2=Wasserzeichen Text:
|
||||||
watermark.selectText.3=Schriftgröße:
|
watermark.selectText.3=SchriftgröÃe:
|
||||||
watermark.selectText.4=Drehung (0-360):
|
watermark.selectText.4=Drehung (0-360):
|
||||||
watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen Wasserzeichen):
|
watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen Wasserzeichen):
|
||||||
watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen):
|
watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen):
|
||||||
watermark.submit=Wasserzeichen hinzufügen
|
watermark.submit=Wasserzeichen hinzufügen
|
||||||
|
|
||||||
#remove-watermark
|
#remove-watermark
|
||||||
remove-watermark.title=Wasserzeichen entfernen
|
remove-watermark.title=Wasserzeichen entfernen
|
||||||
remove-watermark.header=Wasserzeichen entfernen
|
remove-watermark.header=Wasserzeichen entfernen
|
||||||
remove-watermark.selectText.1=PDF auswählen, um Wasserzeichen zu entfernen von:
|
remove-watermark.selectText.1=PDF auswählen, um Wasserzeichen zu entfernen von:
|
||||||
remove-watermark.selectText.2=Wasserzeichentext:
|
remove-watermark.selectText.2=Wasserzeichentext:
|
||||||
remove-watermark.submit=Wasserzeichen entfernen
|
remove-watermark.submit=Wasserzeichen entfernen
|
||||||
|
|
||||||
#Change permissions
|
#Change permissions
|
||||||
permissions.title=Berechtigungen ändern
|
permissions.title=Berechtigungen ändern
|
||||||
permissions.header=Berechtigungen ändern
|
permissions.header=Berechtigungen ändern
|
||||||
permissions.warning=Achtung: Damit diese Berechtigungen nicht geändert werden können, wird empfohlen, sie über die "Passwort hinzufügen"-Seite mit einem Passwort zu versehen
|
permissions.warning=Achtung: Damit diese Berechtigungen nicht geändert werden können, wird empfohlen, sie über die "Passwort hinzufügen"-Seite mit einem Passwort zu versehen
|
||||||
permissions.selectText.1=Das zu ändernde PDF auswählen
|
permissions.selectText.1=Das zu ändernde PDF auswählen
|
||||||
permissions.selectText.2=Zu setzende Berechtigungen
|
permissions.selectText.2=Zu setzende Berechtigungen
|
||||||
permissions.selectText.3=Das zusammensetzen des PDFs verhindern
|
permissions.selectText.3=Das zusammensetzen des PDFs verhindern
|
||||||
permissions.selectText.4=Inhaltsextrahierung verhindern
|
permissions.selectText.4=Inhaltsextrahierung verhindern
|
||||||
permissions.selectText.5=Inhaltsextrahierung zur Barrierefreiheit verhindern
|
permissions.selectText.5=Inhaltsextrahierung zur Barrierefreiheit verhindern
|
||||||
permissions.selectText.6=Ausfüllen des Formulars verhindern
|
permissions.selectText.6=Ausfüllen des Formulars verhindern
|
||||||
permissions.selectText.7=Modifizierung verhindern
|
permissions.selectText.7=Modifizierung verhindern
|
||||||
permissions.selectText.8=Ändern von Kommentaren verhindern
|
permissions.selectText.8=Ãndern von Kommentaren verhindern
|
||||||
permissions.selectText.9=Drucken verhindern
|
permissions.selectText.9=Drucken verhindern
|
||||||
permissions.selectText.10=Drucken verschiedener Formate verhindern
|
permissions.selectText.10=Drucken verschiedener Formate verhindern
|
||||||
permissions.submit=Ändern
|
permissions.submit=Ãndern
|
||||||
|
|
||||||
#remove password
|
#remove password
|
||||||
removePassword.title=Passwort entfernen
|
removePassword.title=Passwort entfernen
|
||||||
removePassword.header=Passwort entfernen (Entschlüsseln)
|
removePassword.header=Passwort entfernen (Entschlüsseln)
|
||||||
removePassword.selectText.1=Das zu entschlüsselnde PDF auswählen
|
removePassword.selectText.1=Das zu entschlüsselnde PDF auswählen
|
||||||
removePassword.selectText.2=Passwort
|
removePassword.selectText.2=Passwort
|
||||||
removePassword.submit=Entfernen
|
removePassword.submit=Entfernen
|
||||||
|
|
||||||
|
|
||||||
changeMetadata.title=Metadaten ändern
|
changeMetadata.title=Metadaten ändern
|
||||||
changeMetadata.header=Metadaten ändern
|
changeMetadata.header=Metadaten ändern
|
||||||
changeMetadata.selectText.1=Bitte bearbeiten Sie die Variablen, die Sie ändern möchten
|
changeMetadata.selectText.1=Bitte bearbeiten Sie die Variablen, die Sie ändern möchten
|
||||||
changeMetadata.selectText.2=Alle Metadaten löschen
|
changeMetadata.selectText.2=Alle Metadaten löschen
|
||||||
changeMetadata.selectText.3=Benutzerdefinierte Metadaten anzeigen:
|
changeMetadata.selectText.3=Benutzerdefinierte Metadaten anzeigen:
|
||||||
changeMetadata.author=Autor:
|
changeMetadata.author=Autor:
|
||||||
changeMetadata.creationDate=Erstellungsdatum (jjjj/MM/tt HH:mm:ss):
|
changeMetadata.creationDate=Erstellungsdatum (jjjj/MM/tt HH:mm:ss):
|
||||||
changeMetadata.creator=Ersteller:
|
changeMetadata.creator=Ersteller:
|
||||||
changeMetadata.keywords=Schlüsselwörter:
|
changeMetadata.keywords=Schlüsselwörter:
|
||||||
changeMetadata.modDate=Änderungsdatum (JJJJ/MM/TT HH:mm:ss):
|
changeMetadata.modDate=Änderungsdatum (JJJJ/MM/TT HH:mm:ss):
|
||||||
changeMetadata.producer=Produzent:
|
changeMetadata.producer=Produzent:
|
||||||
changeMetadata.subject=Betreff:
|
changeMetadata.subject=Betreff:
|
||||||
changeMetadata.title=Titel:
|
changeMetadata.title=Titel:
|
||||||
changeMetadata.trapped=Gefangen:
|
changeMetadata.trapped=Gefangen:
|
||||||
changeMetadata.selectText.4=Andere Metadaten:
|
changeMetadata.selectText.4=Andere Metadaten:
|
||||||
changeMetadata.selectText.5=Benutzerdefinierten Metadateneintrag hinzufügen
|
changeMetadata.selectText.5=Benutzerdefinierten Metadateneintrag hinzufügen
|
||||||
changeMetadata.submit=Ändern
|
changeMetadata.submit=Ändern
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
xlsToPdf.title=Excel in PDF
|
xlsToPdf.title=Excel in PDF
|
||||||
xlsToPdf.header=Excel in PDF
|
xlsToPdf.header=Excel in PDF
|
||||||
xlsToPdf.selectText.1=XLS- oder XLSX-Excel-Tabelle zum Konvertieren auswählen
|
xlsToPdf.selectText.1=XLS- oder XLSX-Excel-Tabelle zum Konvertieren auswählen
|
||||||
xlsToPdf.convert=konvertieren
|
xlsToPdf.convert=konvertieren
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Choose PDF
|
pdfPrompt=Select PDF(s)
|
||||||
multiPdfPrompt=Choose PDFs (2+)
|
multiPdfPrompt=Select PDFs (2+)
|
||||||
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
||||||
imgPrompt=Choose Image
|
imgPrompt=Select Image(s)
|
||||||
genericSubmit=Submit
|
genericSubmit=Submit
|
||||||
processTimeWarning=Warning: This process can take up to a minute depending on file-size
|
processTimeWarning=Warning: This process can take up to a minute depending on file-size
|
||||||
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
|
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
|
||||||
@ -91,7 +91,7 @@ settings.downloadOption.title=Choose download option (For single file non zip do
|
|||||||
settings.downloadOption.1=Open in same window
|
settings.downloadOption.1=Open in same window
|
||||||
settings.downloadOption.2=Open in new window
|
settings.downloadOption.2=Open in new window
|
||||||
settings.downloadOption.3=Download file
|
settings.downloadOption.3=Download file
|
||||||
settings.zip=Zip multi-download files
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR
|
ocr.title=OCR
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||||
language.direction=ltr
|
language.direction=ltr
|
||||||
|
|
||||||
pdfPrompt=Choose PDF
|
pdfPrompt=Select PDF(s)
|
||||||
multiPdfPrompt=Choose PDFs (2+)
|
multiPdfPrompt=Select PDFs (2+)
|
||||||
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
multiPdfDropPrompt=Select (or drag & drop) all PDFs you require
|
||||||
imgPrompt=Choose Image
|
imgPrompt=Select Image(s)
|
||||||
genericSubmit=Submit
|
genericSubmit=Submit
|
||||||
processTimeWarning=Warning: This process can take up to a minute depending on file-size
|
processTimeWarning=Warning: This process can take up to a minute depending on file-size
|
||||||
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
|
pageOrderPrompt=Page Order (Enter a comma-separated list of page numbers) :
|
||||||
@ -91,7 +91,7 @@ settings.downloadOption.title=Choose download option (For single file non zip do
|
|||||||
settings.downloadOption.1=Open in same window
|
settings.downloadOption.1=Open in same window
|
||||||
settings.downloadOption.2=Open in new window
|
settings.downloadOption.2=Open in new window
|
||||||
settings.downloadOption.3=Download file
|
settings.downloadOption.3=Download file
|
||||||
settings.zip=Zip multi-download files
|
settings.zipThreshold=Zip files when the number of downloaded files exceeds
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
ocr.title=OCR
|
ocr.title=OCR
|
||||||
|
@ -96,7 +96,7 @@ settings.downloadOption.title=Choisissez l\u2019option de t
|
|||||||
settings.downloadOption.1=Ouvrir dans la même fenêtre
|
settings.downloadOption.1=Ouvrir dans la même fenêtre
|
||||||
settings.downloadOption.2=Ouvrir dans une nouvelle fenêtre
|
settings.downloadOption.2=Ouvrir dans une nouvelle fenêtre
|
||||||
settings.downloadOption.3=Fichier téléchargé
|
settings.downloadOption.3=Fichier téléchargé
|
||||||
settings.zip=Fichiers multi-téléchargements Zip
|
settings.zipThreshold=Zip les fichiers lorsque le nombre de fichiers téléchargés dépasse
|
||||||
|
|
||||||
|
|
||||||
#OCR
|
#OCR
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{addImage.header}"></h2>
|
<h2 th:text="#{addImage.header}"></h2>
|
||||||
<form method="post" th:action="@{add-image}" enctype="multipart/form-data">
|
<form method="post" th:action="@{add-image}" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
<input type="file" class="custom-file-input" id="fileInput2" name="fileInput2" required>
|
<input type="file" class="custom-file-input" id="fileInput2" name="fileInput2" accept="image/*" required>
|
||||||
<label class="custom-file-label" for="fileInput2" th:text="#{imgPrompt}"></label>
|
<label class="custom-file-label" for="fileInput2" th:text="#{imgPrompt}"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{compress.header}"></h2>
|
<h2 th:text="#{compress.header}"></h2>
|
||||||
<form action="#" th:action="@{/compress-pdf}" method="post" enctype="multipart/form-data">
|
<form action="#" th:action="@{/compress-pdf}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div>
|
<div>
|
||||||
<label for="optimizeLevel" th:text="#{compress.selectText.1}"></label>
|
<label for="optimizeLevel" th:text="#{compress.selectText.1}"></label>
|
||||||
<select name="optimizeLevel" id="optimizeLevel">
|
<select name="optimizeLevel" id="optimizeLevel">
|
||||||
|
@ -15,13 +15,56 @@
|
|||||||
<h2 th:text="#{imageToPDF.header}"></h2>
|
<h2 th:text="#{imageToPDF.header}"></h2>
|
||||||
|
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{img-to-pdf}">
|
<form method="post" enctype="multipart/form-data" th:action="@{img-to-pdf}">
|
||||||
<div class="custom-file">
|
|
||||||
<input type="file" class="custom-file-input" id="fileInput" name="fileInput" required>
|
|
||||||
<label class="custom-file-label" for="fileInput" th:text="#{imgPrompt}"></label>
|
|
||||||
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*')}"></div>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" name="stretchToFit" id="stretchToFit">
|
||||||
|
<label class="ml-3" for="stretchToFit">Stretch to fit</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" name="autoRotate" id="autoRotate">
|
||||||
|
<label class="ml-3" for="autoRotate">Auto rotate PDF</label>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<input type="hidden" id="override" name="override" value="multi">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Multi file logic (Only enabled if working with multiple images)</label>
|
||||||
|
<select class="form-control" id="conversionType" name="conversionType" disabled>
|
||||||
|
<option value="merge">Merge into single PDF</option>
|
||||||
|
<option value="convert" selected>Convert to separate PDFs</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br> <br>
|
<br> <br>
|
||||||
<button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
|
<button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
|
||||||
|
<script>
|
||||||
|
$('#fileInput-input').on('change', function() {
|
||||||
|
var files = document.getElementById("fileInput-input").files;
|
||||||
|
var conversionType = document.getElementById("conversionType");
|
||||||
|
console.log("files.length=" + files.length)
|
||||||
|
if (files.length > 1) {
|
||||||
|
conversionType.disabled = false;
|
||||||
|
} else {
|
||||||
|
conversionType.disabled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#conversionType').change(function() {
|
||||||
|
var selectedValue = $(this).val();
|
||||||
|
var override = document.getElementById("override");
|
||||||
|
console.log("selectedValue=" + selectedValue)
|
||||||
|
if (selectedValue === 'merge') {
|
||||||
|
override.value = "single";
|
||||||
|
} else if (selectedValue === 'convert') {
|
||||||
|
override.value = "multi";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<h2 th:text="#{pdfToImage.header}"></h2>
|
<h2 th:text="#{pdfToImage.header}"></h2>
|
||||||
<p th:text="#{processTimeWarning}"></p>
|
<p th:text="#{processTimeWarning}"></p>
|
||||||
<form method="post" enctype="multipart/form-data" th:action="@{pdf-to-img}">
|
<form method="post" enctype="multipart/form-data" th:action="@{pdf-to-img}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{pdfToImage.selectText}"></label>
|
<label th:text="#{pdfToImage.selectText}"></label>
|
||||||
<select class="form-control" name="imageFormat">
|
<select class="form-control" name="imageFormat">
|
||||||
|
@ -1,162 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
|
||||||
|
|
||||||
<th:block th:insert="~{fragments/common :: head(title=#{extractImages.title})}"></th:block>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css" />
|
|
||||||
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="page-container">
|
|
||||||
<div id="content-wrap">
|
|
||||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
|
||||||
<br> <br>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h2 th:text="#{extractImages.header}"></h2>
|
|
||||||
|
|
||||||
<input type="file" id="pdfFile" accept=".pdf" />
|
|
||||||
<canvas id="pdfCanvas" style="border:1px solid black;"></canvas>
|
|
||||||
<input type="number" id="pageNumber" min="1" />
|
|
||||||
<button id="goToPage">Go to Page</button>
|
|
||||||
<button id="cropPdf">Crop PDF</button>
|
|
||||||
<button id="downloadPdf">Download PDF</button>
|
|
||||||
|
|
||||||
<Script>
|
|
||||||
const pdfCanvas = document.getElementById('pdfCanvas');
|
|
||||||
const ctx = pdfCanvas.getContext('2d');
|
|
||||||
let pdfDoc = null;
|
|
||||||
let currentPage = 1;
|
|
||||||
let scaleFactor = 1.0;
|
|
||||||
let cropper = null;
|
|
||||||
|
|
||||||
async function renderPage(pageNumber) {
|
|
||||||
const page = await pdfDoc.getPage(pageNumber);
|
|
||||||
const viewport = page.getViewport({ scale: scaleFactor });
|
|
||||||
pdfCanvas.width = viewport.width;
|
|
||||||
pdfCanvas.height = viewport.height;
|
|
||||||
const renderContext = {
|
|
||||||
canvasContext: ctx,
|
|
||||||
viewport: viewport,
|
|
||||||
};
|
|
||||||
await page.render(renderContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('pdfFile').addEventListener('change', async (event) => {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
if (!file) return;
|
|
||||||
const fileReader = new FileReader();
|
|
||||||
fileReader.onload = async (e) => {
|
|
||||||
const typedArray = new Uint8Array(e.target.result);
|
|
||||||
pdfDoc = await pdfjsLib.getDocument(typedArray).promise;
|
|
||||||
await renderPage(currentPage);
|
|
||||||
|
|
||||||
if (cropper) cropper.destroy();
|
|
||||||
cropper = new Cropper(pdfCanvas, {
|
|
||||||
viewMode: 1,
|
|
||||||
autoCropArea: 1,
|
|
||||||
background: false, // Disable the default checkered background
|
|
||||||
modal: false, // Disable the default shading of the cropped area
|
|
||||||
dragMode: "crop",
|
|
||||||
cropBoxResizable: true,
|
|
||||||
guides: false, // Disable the default dashed crop box guides
|
|
||||||
// Set a custom background color with transparency
|
|
||||||
cropBox: {
|
|
||||||
background: "rgba(0, 0, 0, 0.2)",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
fileReader.readAsArrayBuffer(file);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('goToPage').addEventListener('click', async () => {
|
|
||||||
currentPage = parseInt(document.getElementById('pageNumber').value);
|
|
||||||
await renderPage(currentPage);
|
|
||||||
if (cropper) cropper.destroy();
|
|
||||||
cropper = new Cropper(pdfCanvas, {
|
|
||||||
viewMode: 1,
|
|
||||||
autoCropArea: 1,
|
|
||||||
background: false, // Disable the default checkered background
|
|
||||||
modal: false, // Disable the default shading of the cropped area
|
|
||||||
dragMode: "crop",
|
|
||||||
cropBoxResizable: true,
|
|
||||||
guides: false, // Disable the default dashed crop box guides
|
|
||||||
// Set a custom background color with transparency
|
|
||||||
cropBox: {
|
|
||||||
background: "rgba(0, 0, 0, 0.2)",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('cropPdf').addEventListener('click', async () => {
|
|
||||||
if (!cropper) return;
|
|
||||||
|
|
||||||
const cropBoxData = cropper.getCropBoxData();
|
|
||||||
const [x, y, width, height] = [cropBoxData.left, cropBoxData.top, cropBoxData.width, cropBoxData.height];
|
|
||||||
|
|
||||||
const page = await pdfDoc.getPage(currentPage);
|
|
||||||
const croppedPdf = await PDFLib.PDFDocument.create();
|
|
||||||
const [croppedPage] = await croppedPdf.copyPages(pdfDoc, [currentPage - 1]);
|
|
||||||
const cropBox = {
|
|
||||||
left: x / scaleFactor,
|
|
||||||
bottom: (pdfCanvas.height - y - height) / scaleFactor,
|
|
||||||
right: (x + width) / scaleFactor,
|
|
||||||
top: (pdfCanvas.height - y) / scaleFactor,
|
|
||||||
};
|
|
||||||
croppedPage.setCropBox(cropBox);
|
|
||||||
croppedPdf.addPage(croppedPage);
|
|
||||||
|
|
||||||
const croppedPdfBytes = await croppedPdf.save();
|
|
||||||
const croppedPdfBlob = new Blob([croppedPdfBytes], { type: 'application/pdf' });
|
|
||||||
|
|
||||||
const downloadLink = document.getElementById('downloadPdf');
|
|
||||||
downloadLink.href = URL.createObjectURL(croppedPdfBlob);
|
|
||||||
downloadLink.download = 'cropped.pdf';
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('downloadPdf').addEventListener('click', async () => {
|
|
||||||
if (!pdfDoc || !cropper) {
|
|
||||||
alert('No PDF available. Please load a PDF first.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cropBoxData = cropper.getCropBoxData();
|
|
||||||
const [x, y, width, height] = [cropBoxData.left, cropBoxData.top, cropBoxData.width, cropBoxData.height];
|
|
||||||
|
|
||||||
const page = await pdfDoc.getPage(currentPage);
|
|
||||||
const croppedPdf = await PDFLib.PDFDocument.create();
|
|
||||||
if (!isNaN(currentPage)) {
|
|
||||||
const [croppedPage] = await croppedPdf.copyPages(pdfDoc, [currentPage - 1]);
|
|
||||||
const cropBox = {
|
|
||||||
left: x / scaleFactor,
|
|
||||||
bottom: (pdfCanvas.height - y - height) / scaleFactor,
|
|
||||||
right: (x + width) / scaleFactor,
|
|
||||||
top: (pdfCanvas.height - y) / scaleFactor,
|
|
||||||
};
|
|
||||||
croppedPage.setCropBox(cropBox);
|
|
||||||
croppedPdf.addPage(croppedPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
const croppedPdfBytes = await croppedPdf.save();
|
|
||||||
const croppedPdfBlob = new Blob([croppedPdfBytes], { type: 'application/pdf' });
|
|
||||||
|
|
||||||
const downloadLink = document.getElementById('downloadPdf');
|
|
||||||
downloadLink.href = URL.createObjectURL(croppedPdfBlob);
|
|
||||||
downloadLink.download = 'cropped.pdf';
|
|
||||||
});
|
|
||||||
|
|
||||||
</Script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -15,7 +15,7 @@
|
|||||||
<h2 th:text="#{extractImages.header}"></h2>
|
<h2 th:text="#{extractImages.header}"></h2>
|
||||||
|
|
||||||
<form id="multiPdfForm" th:action="@{extract-images}" method="post" enctype="multipart/form-data">
|
<form id="multiPdfForm" th:action="@{extract-images}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{extractImages.selectText}"></label>
|
<label th:text="#{extractImages.selectText}"></label>
|
||||||
<select class="form-control" name="format">
|
<select class="form-control" name="format">
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<!-- Metadata -->
|
<!-- Metadata -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<title th:text="'S-PDF ' + ${title}"></title>
|
<title th:text="'S-PDF ' + ${title}"></title>
|
||||||
<link rel="shortcut icon" href="favicon.svg">
|
<link rel="shortcut icon" href="favicon.svg">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
@ -63,10 +64,10 @@ function toggleDarkMode() {
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<th:block th:fragment="fileSelector(name, multiple)">
|
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*'">
|
||||||
<div class="custom-file-chooser">
|
<div class="custom-file-chooser">
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
<input type="file" class="custom-file-input" th:name="${name}" th:id="${name}+'-input'" multiple>
|
<input type="file" class="custom-file-input" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple>
|
||||||
<label class="custom-file-label" th:for="${name}+'-input'" th:text="#{pdfPrompt}"></label>
|
<label class="custom-file-label" th:for="${name}+'-input'" th:text="#{pdfPrompt}"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="selected-files"></div>
|
<div class="selected-files"></div>
|
||||||
@ -90,7 +91,9 @@ function toggleDarkMode() {
|
|||||||
event.preventDefault(); // Prevent the default form handling behavior
|
event.preventDefault(); // Prevent the default form handling behavior
|
||||||
/* Check if ${multiple} is false */
|
/* Check if ${multiple} is false */
|
||||||
var multiple = [[${multiple}]] || false;
|
var multiple = [[${multiple}]] || false;
|
||||||
if (!multiple && files.length > 1) {
|
var override = $('#override').val() || '';
|
||||||
|
console.log("override=" + override)
|
||||||
|
if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) {
|
||||||
console.log("multi parallel download")
|
console.log("multi parallel download")
|
||||||
submitMultiPdfForm(event,url);
|
submitMultiPdfForm(event,url);
|
||||||
} else {
|
} else {
|
||||||
@ -208,8 +211,9 @@ function toggleDarkMode() {
|
|||||||
progressBar.attr('aria-valuenow', 0);
|
progressBar.attr('aria-valuenow', 0);
|
||||||
progressBar.attr('aria-valuemax', files.length);
|
progressBar.attr('aria-valuemax', files.length);
|
||||||
|
|
||||||
// Check the flag in localStorage
|
// Check the flag in localStorage, default to 4
|
||||||
const zipFiles = localStorage.getItem('zipParallelFiles') === 'true';
|
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
||||||
|
const zipFiles = files.length > zipThreshold;
|
||||||
|
|
||||||
// Initialize JSZip instance if needed
|
// Initialize JSZip instance if needed
|
||||||
let jszip = null;
|
let jszip = null;
|
||||||
@ -355,6 +359,7 @@ function toggleDarkMode() {
|
|||||||
fileNames.forEach(fileName => {
|
fileNames.forEach(fileName => {
|
||||||
selectedFilesContainer.append("<div>" + fileName + "</div>");
|
selectedFilesContainer.append("<div>" + fileName + "</div>");
|
||||||
});
|
});
|
||||||
|
console.log("fileNames.length=" + fileNames.length)
|
||||||
if (fileNames.length === 1) {
|
if (fileNames.length === 1) {
|
||||||
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
|
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
|
||||||
} else if (fileNames.length > 1) {
|
} else if (fileNames.length > 1) {
|
||||||
|
@ -206,25 +206,24 @@ function compareVersions(version1, version2) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<p class="mb-0" th:text="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
||||||
<a href="https://github.com/Frooodle/Stirling-PDF/releases" target="_blank">
|
<a href="https://github.com/Frooodle/Stirling-PDF/releases" target="_blank">
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary" id="update-btn" th:text="#{settings.update}"></button>
|
<button type="button" class="btn btn-sm btn-outline-primary" id="update-btn" th:utext="#{settings.update}"></button>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="downloadOption" th:text="#{settings.downloadOption.title}"></label>
|
<label for="downloadOption" th:utext="#{settings.downloadOption.title}"></label>
|
||||||
<select class="form-control" id="downloadOption">
|
<select class="form-control" id="downloadOption">
|
||||||
<option value="sameWindow" th:text="#{settings.downloadOption.1}"></option>
|
<option value="sameWindow" th:utext="#{settings.downloadOption.1}"></option>
|
||||||
<option value="newWindow" th:text="#{settings.downloadOption.2}"></option>
|
<option value="newWindow" th:utext="#{settings.downloadOption.2}"></option>
|
||||||
<option value="downloadFile" th:text="#{settings.downloadOption.3}"></option>
|
<option value="downloadFile" th:utext="#{settings.downloadOption.3}"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<label for="zipThreshold" th:utext="#{settings.zipThreshold}"></label>
|
||||||
<input type="checkbox" class="custom-control-input" id="zipParallelFiles">
|
<input type="range" class="custom-range" min="0" max="9" step="1" id="zipThreshold" value="4">
|
||||||
<label class="custom-control-label" for="zipParallelFiles" th:text="#{settings.zip}"></label>
|
<span id="zipThresholdValue" class="ml-2"></span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@ -253,17 +252,20 @@ function compareVersions(version1, version2) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Get the zipParallelFiles flag from local storage, or set it to false if it doesn't exist
|
// Get the zipThreshold value from local storage, or set it to 0 if it doesn't exist
|
||||||
var zipParallelFiles = localStorage.getItem('zipParallelFiles') === 'true';
|
var zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
||||||
|
|
||||||
// Set the checked state of the checkbox
|
// Set the value of the slider and the display span
|
||||||
document.getElementById('zipParallelFiles').checked = zipParallelFiles;
|
document.getElementById('zipThreshold').value = zipThreshold;
|
||||||
|
document.getElementById('zipThresholdValue').textContent = zipThreshold;
|
||||||
|
|
||||||
// Save the checked state of the checkbox to local storage when it changes
|
// Save the selected value to local storage when the slider value changes
|
||||||
document.getElementById('zipParallelFiles').addEventListener('change', function () {
|
document.getElementById('zipThreshold').addEventListener('input', function () {
|
||||||
zipParallelFiles = this.checked;
|
zipThreshold = this.value;
|
||||||
localStorage.setItem('zipParallelFiles', zipParallelFiles);
|
document.getElementById('zipThresholdValue').textContent = zipThreshold;
|
||||||
|
localStorage.setItem('zipThreshold', zipThreshold);
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,9 @@
|
|||||||
|
|
||||||
<!-- Features -->
|
<!-- Features -->
|
||||||
<div class="features-container container">
|
<div class="features-container container">
|
||||||
|
|
||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs')}"></div>
|
||||||
|
|
||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs')}"></div>
|
||||||
<div th:replace="~{fragments/card :: card(cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf')}"></div>
|
<div th:replace="~{fragments/card :: card(cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf')}"></div>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{multiPdfDropPrompt}"></label>
|
<label th:text="#{multiPdfDropPrompt}"></label>
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
<input type="file" class="custom-file-input" id="fileInput" name="fileInput" multiple required>
|
<input type="file" class="custom-file-input" id="fileInput" name="fileInput" accept="application/pdf" multiple required>
|
||||||
<label class="custom-file-label" th:text="#{pdfPrompt}"></label>
|
<label class="custom-file-label" th:text="#{pdfPrompt}"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<h2 th:text="#{ocr.header}"></h2>
|
<h2 th:text="#{ocr.header}"></h2>
|
||||||
|
|
||||||
<form action="#" th:action="@{/ocr-pdf}" method="post" enctype="multipart/form-data" class="mb-3">
|
<form action="#" th:action="@{/ocr-pdf}" method="post" enctype="multipart/form-data" class="mb-3">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
|
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
|
||||||
<div id="languages">
|
<div id="languages">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<h2 th:text="#{pdfOrganiser.header}"></h2>
|
<h2 th:text="#{pdfOrganiser.header}"></h2>
|
||||||
|
|
||||||
<form th:action="@{rearrange-pages}" method="post" enctype="multipart/form-data">
|
<form th:action="@{rearrange-pages}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||||
<input type="text" class="form-control" id="fileInput" name="pageOrder" placeholder="(e.g. 1,3,2 or 4-8,2,10-12)" required>
|
<input type="text" class="form-control" id="fileInput" name="pageOrder" placeholder="(e.g. 1,3,2 or 4-8,2,10-12)" required>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<h2 th:text="#{pageRemover.header}"></h2>
|
<h2 th:text="#{pageRemover.header}"></h2>
|
||||||
|
|
||||||
<form th:action="@{remove-pages}" method="post" enctype="multipart/form-data">
|
<form th:action="@{remove-pages}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="pagesToDelete" th:text="#{pageRemover.pagesToDelete}"></label>
|
<label for="pagesToDelete" th:text="#{pageRemover.pagesToDelete}"></label>
|
||||||
<input type="text" class="form-control" id="fileInput" name="pagesToDelete" placeholder="(e.g. 1,2,6 or 1-10,15-30)" required>
|
<input type="text" class="form-control" id="fileInput" name="pagesToDelete" placeholder="(e.g. 1,2,6 or 1-10,15-30)" required>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<h2 th:text="#{rotate.header}"></h2>
|
<h2 th:text="#{rotate.header}"></h2>
|
||||||
|
|
||||||
<form action="#" th:action="@{rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
|
<form action="#" th:action="@{rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<input type="hidden" id="angleInput" name="angle" value="0">
|
<input type="hidden" id="angleInput" name="angle" value="0">
|
||||||
|
|
||||||
<div id="editSection" style="display: none">
|
<div id="editSection" style="display: none">
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<form action="add-password" method="post" enctype="multipart/form-data">
|
<form action="add-password" method="post" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{addPassword.selectText.1}"></label>
|
<label th:text="#{addPassword.selectText.1}"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{addPassword.selectText.2}"></label> <input type="password" class="form-control" id="password" name="password" required>
|
<label th:text="#{addPassword.selectText.2}"></label> <input type="password" class="form-control" id="password" name="password" required>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<form method="post" enctype="multipart/form-data" action="add-watermark">
|
<form method="post" enctype="multipart/form-data" action="add-watermark">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{watermark.selectText.1}"></label>
|
<label th:text="#{watermark.selectText.1}"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="watermarkText" th:text="#{watermark.selectText.2}"></label>
|
<label for="watermarkText" th:text="#{watermark.selectText.2}"></label>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<h2 th:text="#{changeMetadata.header}"></h2>
|
<h2 th:text="#{changeMetadata.header}"></h2>
|
||||||
|
|
||||||
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{/update-metadata}">
|
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{/update-metadata}">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
|
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
|
||||||
|
|
||||||
<div class="form-group-inline form-check">
|
<div class="form-group-inline form-check">
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<form action="add-password" method="post" enctype="multipart/form-data">
|
<form action="add-password" method="post" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{permissions.selectText.1}"></label>
|
<label th:text="#{permissions.selectText.1}"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{permissions.selectText.2}"></label>
|
<label th:text="#{permissions.selectText.2}"></label>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<form action="remove-password" method="post" enctype="multipart/form-data">
|
<form action="remove-password" method="post" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{removePassword.selectText.1}"></label>
|
<label th:text="#{removePassword.selectText.1}"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{removePassword.selectText.2}"></label>
|
<label th:text="#{removePassword.selectText.2}"></label>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<form method="post" enctype="multipart/form-data" action="remove-watermark">
|
<form method="post" enctype="multipart/form-data" action="remove-watermark">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{remove-watermark.selectText.1}"></label>
|
<label th:text="#{remove-watermark.selectText.1}"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="watermarkText" th:text="#{remove-watermark.selectText.2}"></label>
|
<label for="watermarkText" th:text="#{remove-watermark.selectText.2}"></label>
|
||||||
|
@ -1,173 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
|
||||||
|
|
||||||
<th:block th:insert="~{fragments/common :: head(title=#{extractImages.title})}"></th:block>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="page-container">
|
|
||||||
<div id="content-wrap">
|
|
||||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
|
||||||
<br> <br>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h2 th:text="#{extractImages.header}"></h2>
|
|
||||||
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PDF Signature App</title>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
|
||||||
<script src="https://unpkg.com/pdf-lib@1.18.0/dist/umd/pdf-lib.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
|
|
||||||
<style>
|
|
||||||
canvas {
|
|
||||||
border: 1px solid black;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<input type="file" id="pdf-upload" accept=".pdf" />
|
|
||||||
<div>
|
|
||||||
<canvas id="pdf-canvas"></canvas>
|
|
||||||
<canvas id="signature-pad" width="400" height="200"></canvas>
|
|
||||||
</div>
|
|
||||||
<button id="save-signature">Save Signature</button>
|
|
||||||
<button id="download-pdf">Download PDF</button>
|
|
||||||
<script>
|
|
||||||
|
|
||||||
const pdfUpload = document.getElementById('pdf-upload');
|
|
||||||
|
|
||||||
// app.js
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const pdfCanvas = document.getElementById('pdf-canvas');
|
|
||||||
const signatureCanvas = document.getElementById('signature-pad');
|
|
||||||
const saveSignatureBtn = document.getElementById('save-signature');
|
|
||||||
const downloadPdfBtn = document.getElementById('download-pdf');
|
|
||||||
|
|
||||||
const pdfCtx = pdfCanvas.getContext('2d');
|
|
||||||
const signaturePad = new SignaturePad(signatureCanvas);
|
|
||||||
|
|
||||||
let pdfDoc = null;
|
|
||||||
let signatureImage = null;
|
|
||||||
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.worker.min.js';
|
|
||||||
|
|
||||||
async function loadPdf(pdfData) {
|
|
||||||
pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
|
||||||
renderPage(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfUpload.addEventListener('change', async (event) => {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
const pdfData = await file.arrayBuffer();
|
|
||||||
loadPdf(pdfData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function renderPage(pageNum) {
|
|
||||||
pdfDoc.getPage(pageNum).then((page) => {
|
|
||||||
const viewport = page.getViewport({ scale: 1 });
|
|
||||||
pdfCanvas.width = viewport.width;
|
|
||||||
pdfCanvas.height = viewport.height;
|
|
||||||
|
|
||||||
const renderCtx = {
|
|
||||||
canvasContext: pdfCtx,
|
|
||||||
viewport: viewport,
|
|
||||||
};
|
|
||||||
|
|
||||||
page.render(renderCtx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
saveSignatureBtn.addEventListener('click', () => {
|
|
||||||
if (signaturePad.isEmpty()) {
|
|
||||||
alert('Please provide a signature.');
|
|
||||||
} else {
|
|
||||||
signatureImage = signaturePad.toDataURL();
|
|
||||||
signaturePad.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
downloadPdfBtn.addEventListener('click', async () => {
|
|
||||||
if (!signatureImage) {
|
|
||||||
alert('Please save a signature first.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the original PDF
|
|
||||||
const pdfUrl = 'path/to/your/pdf-file.pdf';
|
|
||||||
const pdfBytes = await fetch(pdfUrl).then((res) => res.arrayBuffer());
|
|
||||||
const pdfDoc = await PDFLib.PDFDocument.load(pdfBytes);
|
|
||||||
|
|
||||||
// Embed the signature image
|
|
||||||
const signaturePng = await fetch(signatureImage).then((res) => res.arrayBuffer());
|
|
||||||
const signatureImageObject = await pdfDoc.embedPng(signaturePng);
|
|
||||||
|
|
||||||
// Get the page to insert the signature
|
|
||||||
const [page] = pdfDoc.getPages();
|
|
||||||
const { width, height } = page.getSize();
|
|
||||||
|
|
||||||
// Set the signature dimensions and position (customize this as needed)
|
|
||||||
const signatureWidth = 200;
|
|
||||||
const signatureHeight = 100;
|
|
||||||
const signatureX = width / 2 - signatureWidth / 2;
|
|
||||||
const signatureY = height / 2 - signatureHeight / 2;
|
|
||||||
|
|
||||||
// Add the signature image to the page
|
|
||||||
page.drawImage(signatureImageObject, {
|
|
||||||
x: signatureX,
|
|
||||||
y: signatureY,
|
|
||||||
width: signatureWidth,
|
|
||||||
height: signatureHeight,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Serialize the PDF and create a download link
|
|
||||||
const pdfBytesModified = await pdfDoc.save();
|
|
||||||
const blob = new Blob([pdfBytesModified], { type: 'application/pdf' });
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = URL.createObjectURL(blob);
|
|
||||||
link.download = 'signed-document.pdf';
|
|
||||||
link.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (pdfUpload.files[0]) {
|
|
||||||
(async () => {
|
|
||||||
if (pdfUpload.files[0]) {
|
|
||||||
await loadPdf(await pdfUpload.files[0].arrayBuffer());
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
145
src/main/resources/templates/sign-pdfold.html
Normal file
145
src/main/resources/templates/sign-pdfold.html
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{extractImages.title})}"></th:block>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
||||||
|
<br> <br>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 th:text="#{extractImages.header}"></h2>
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>PDF Signature App</title>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/pdf-lib@1.18.0/dist/umd/pdf-lib.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
|
||||||
|
<input type="file" id="pdf-upload" accept=".pdf" />
|
||||||
|
<div>
|
||||||
|
<canvas id="pdf-canvas"></canvas>
|
||||||
|
<canvas id="signature-pad" width="400" height="200"></canvas>
|
||||||
|
</div>
|
||||||
|
<button id="save-signature">Save Signature</button>
|
||||||
|
<button id="download-pdf">Download PDF</button>
|
||||||
|
<script>
|
||||||
|
const pdfUpload = document.getElementById('pdf-upload');
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const pdfCanvas = document.getElementById('pdf-canvas');
|
||||||
|
const signatureCanvas = document.getElementById('signature-pad');
|
||||||
|
const saveSignatureBtn = document.getElementById('save-signature');
|
||||||
|
const downloadPdfBtn = document.getElementById('download-pdf');
|
||||||
|
|
||||||
|
const pdfCtx = pdfCanvas.getContext('2d');
|
||||||
|
const signaturePad = new SignaturePad(signatureCanvas);
|
||||||
|
|
||||||
|
let pdfDoc = null;
|
||||||
|
let signatureImage = null;
|
||||||
|
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.worker.min.js';
|
||||||
|
|
||||||
|
async function loadPdf(pdfData) {
|
||||||
|
pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
||||||
|
renderPage(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfUpload.addEventListener('change', async (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const pdfData = await file.arrayBuffer();
|
||||||
|
loadPdf(pdfData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderPage(pageNum) {
|
||||||
|
pdfDoc.getPage(pageNum).then((page) => {
|
||||||
|
const viewport = page.getViewport({ scale: 1 });
|
||||||
|
pdfCanvas.width = viewport.width;
|
||||||
|
pdfCanvas.height = viewport.height;
|
||||||
|
const renderCtx = {
|
||||||
|
canvasContext: pdfCtx,
|
||||||
|
viewport: viewport,
|
||||||
|
};
|
||||||
|
|
||||||
|
page.render(renderCtx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSignatureBtn.addEventListener('click', () => {
|
||||||
|
if (signaturePad.isEmpty()) {
|
||||||
|
alert('Please provide a signature.');
|
||||||
|
} else {
|
||||||
|
signatureImage = signaturePad.toDataURL();
|
||||||
|
signaturePad.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadPdfBtn.addEventListener('click', async () => {
|
||||||
|
if (!signatureImage) {
|
||||||
|
alert('Please save a signature first.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the original PDF
|
||||||
|
const pdfBytes = await pdfUpload.files[0].arrayBuffer();
|
||||||
|
const pdfDoc = await PDFLib.PDFDocument.load(pdfBytes);
|
||||||
|
|
||||||
|
// Embed the signature image
|
||||||
|
const signaturePng = await fetch(signatureImage).then((res) => res.arrayBuffer());
|
||||||
|
const signatureImageObject = await pdfDoc.embedPng(signaturePng);
|
||||||
|
|
||||||
|
// Get the page to insert the signature
|
||||||
|
const [page] = pdfDoc.getPages();
|
||||||
|
const { width, height } = page.getSize();
|
||||||
|
|
||||||
|
// Set the signature dimensions and position (customize this as needed)
|
||||||
|
const signatureWidth = 200;
|
||||||
|
const signatureHeight = 100;
|
||||||
|
const signatureX = width / 2 - signatureWidth / 2;
|
||||||
|
const signatureY = height / 2 - signatureHeight / 2;
|
||||||
|
|
||||||
|
// Add the signature image to the page
|
||||||
|
page.drawImage(signatureImageObject, {
|
||||||
|
x: signatureX,
|
||||||
|
y: signatureY,
|
||||||
|
width: signatureWidth,
|
||||||
|
height: signatureHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Serialize the PDF and create a download link
|
||||||
|
const pdfBytesModified = await pdfDoc.save();
|
||||||
|
const blob = new Blob([pdfBytesModified], { type: 'application/pdf' });
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = URL.createObjectURL(blob);
|
||||||
|
link.download = 'signed-document.pdf';
|
||||||
|
link.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pdfUpload.files[0]) {
|
||||||
|
(async () => {
|
||||||
|
if (pdfUpload.files[0]) {
|
||||||
|
await loadPdf(await pdfUpload.files[0].arrayBuffer());
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||||
|
</div>
|
||||||
|
|
@ -24,7 +24,7 @@
|
|||||||
<p th:text="#{split.desc.8}"></p>
|
<p th:text="#{split.desc.8}"></p>
|
||||||
|
|
||||||
<form th:action="@{split-pages}" method="post" enctype="multipart/form-data">
|
<form th:action="@{split-pages}" method="post" enctype="multipart/form-data">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="pages" th:text="#{split.splitPages}"></label>
|
<label for="pages" th:text="#{split.splitPages}"></label>
|
||||||
|
Loading…
Reference in New Issue
Block a user