Image stuff (#77)

Features
---------
Image to PDF supports multiple images, stretching and auto rotation
File inputs now only search for wanted file type
Settings now has a zip range so it can zip if you have more than x downloads (default 4)

extras
---------
DevTools support for easier development
Fix for temporary files for thread safety
This commit is contained in:
Anthony Stirling
2023-03-25 22:16:26 +00:00
committed by GitHub
parent f866c8a61f
commit a2a27e2216
34 changed files with 243 additions and 153 deletions

View File

@@ -1,23 +1,15 @@
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 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.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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.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 CompressController {

View File

@@ -1,10 +1,8 @@
package stirling.software.SPDF.controller;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
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.nio.file.Paths;
@@ -13,11 +11,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
@@ -28,13 +27,6 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
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.*;
@Controller
public class OCRController {

View File

@@ -1,7 +1,6 @@
package stirling.software.SPDF.controller;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -10,7 +9,6 @@ import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -108,7 +106,7 @@ public class SplitPDFController {
document.close();
// 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());
Map<String, String> env = new HashMap<>();
env.put("create", "true");
@@ -132,7 +130,7 @@ public class SplitPDFController {
logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
byte[] data = Files.readAllBytes(zipFile);
ByteArrayResource resource = new ByteArrayResource(data);
new File("split_documents.zip").delete();
Files.delete(zipFile);
// 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)
.contentLength(resource.contentLength()).body(resource);

View File

@@ -38,12 +38,13 @@ public class ConvertImgPDFController {
}
@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
byte[] bytes = PdfUtils.convertToPdf(file.getInputStream());
logger.info("File {} successfully converted to pdf", file.getOriginalFilename());
return PdfUtils.bytesToWebResponse(bytes, file.getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_coverted.pdf");
System.out.println(stretchToFit);
byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate);
return PdfUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_coverted.pdf");
}
@PostMapping("/pdf-to-img")

View File

@@ -1,9 +1,6 @@
package stirling.software.SPDF.controller.converters;
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;
@@ -17,9 +14,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import stirling.software.SPDF.LibreOfficeListener;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.ProcessExecutor;
@Controller

View File

@@ -8,6 +8,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -28,6 +29,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
@@ -37,49 +39,100 @@ public class PdfUtils {
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
public static byte[] convertToPdf(InputStream imageStream) 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;
}
public static byte[] imageToPdf(MultipartFile[] files, boolean stretchToFit, boolean autoRotate) throws IOException {
try (PDDocument doc = new PDDocument()) {
// Create a new PDF page
PDPage page = new PDPage();
doc.addPage(page);
for (MultipartFile file : files) {
// Create a temporary file for the image
File imageFile = Files.createTempFile("image", ".jpg").toFile();
// Create an image object from the image file
PDImageXObject image = PDImageXObject.createFromFileByContent(imageFile, doc);
try (FileOutputStream fos = new FileOutputStream(imageFile); InputStream input = file.getInputStream()) {
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)) {
// Draw the image onto the page
contentStream.drawImage(image, 0, 0);
logger.info("Image successfully added to PDF");
} catch (IOException e) {
logger.error("Error adding image to PDF", e);
throw e;
// Create a new PDF page
PDPage page = new PDPage();
doc.addPage(page);
// Create an image object from the image file
PDImageXObject image = PDImageXObject.createFromFileByContent(imageFile, doc);
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
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
doc.save(byteArrayOutputStream);
logger.info("PDF successfully saved to byte array");
return byteArrayOutputStream.toByteArray();
}
}
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI)
throws IOException, Exception {
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {

View File

@@ -1,13 +1,11 @@
package stirling.software.SPDF.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.List;
public class ProcessExecutor {
public static int runCommandWithOutputHandling(List<String> command) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder(command);