pdf to img fix

This commit is contained in:
Anthony Stirling 2023-02-08 23:35:19 +00:00
parent e896dfeaec
commit dcaddb53ee
10 changed files with 241 additions and 111 deletions

View File

@ -1,9 +1,13 @@
package stirling.software.SPDF.controller.converters;
import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.rendering.ImageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@ -44,16 +48,41 @@ public class ConvertImgPDFController {
}
@PostMapping("/pdf-to-img")
public ResponseEntity<byte[]> convertToImage(@RequestParam("fileInput") MultipartFile file,
@RequestParam("imageFormat") String imageFormat) throws IOException {
public ResponseEntity<Resource> convertToImage(@RequestParam("fileInput") MultipartFile file,
@RequestParam("imageFormat") String imageFormat,
@RequestParam("singleOrMultiple") String singleOrMultiple,
@RequestParam("colorType") String colorType) throws IOException {
byte[] pdfBytes = file.getBytes();
ImageType colorTypeResult = ImageType.RGB;
if("greyscale".equals(colorType)) {
colorTypeResult = ImageType.GRAY;
} else if ("blackwhite".equals(colorType)) {
colorTypeResult = ImageType.BINARY;
}
// returns bytes for image
byte[] result = PdfUtils.convertFromPdf(pdfBytes, imageFormat.toLowerCase());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
ResponseEntity<byte[]> response = new ResponseEntity<>(result, headers, HttpStatus.OK);
return response;
boolean singleImage = singleOrMultiple.equals("single");
byte[] result = null;
try {
result = PdfUtils.convertFromPdf(pdfBytes, imageFormat.toLowerCase(), colorTypeResult, singleImage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(singleImage) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(getMediaType(imageFormat)));
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
ResponseEntity<Resource> response = new ResponseEntity<>(new ByteArrayResource(result), headers, HttpStatus.OK);
return response;
} else {
ByteArrayResource resource = new ByteArrayResource(result);
// return the Resource in the response
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=converted_documents.zip")
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource);
}
}
private String getMediaType(String imageFormat) {

View File

@ -3,6 +3,8 @@ package stirling.software.SPDF.controller.security;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
@ -19,11 +21,13 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
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 jakarta.servlet.http.HttpServletRequest;
import stirling.software.SPDF.utils.PdfUtils;
@Controller
@ -34,25 +38,55 @@ public class MetadataController {
model.addAttribute("currentPage", "change-metadata");
return "security/change-metadata";
}
@PostMapping("/update-metadata")
public ResponseEntity<byte[]> addWatermark(@RequestParam("pdfFile") MultipartFile pdfFile,
@RequestParam("author") String author) throws IOException {
// Load the PDF file
PDDocument document = PDDocument.load(pdfFile.getBytes());
// Remove all metadata based on flag
PDDocumentInformation info = document.getDocumentInformation();
for (String key : info.getMetadataKeys()) {
info.setCustomMetadataValue(key, null);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_metadata.pdf");
public ResponseEntity<byte[]> metadata(
@RequestParam Map<String,String> allRequestParams) throws IOException {
System.out.println("1 allRequestParams.size() = " + allRequestParams.size());
for(Entry entry : allRequestParams.entrySet()) {
System.out.println("1 key=" + entry.getKey() + ", value=" + entry.getValue());
}
return null;
}
// @PostMapping("/update-metadata")
// public ResponseEntity<byte[]> addWatermark(@RequestParam("fileInput") MultipartFile pdfFile,
// @RequestParam Map<String,String> allRequestParams,HttpServletRequest request, ModelMap model) throws IOException {
// // Load the PDF file
// System.out.println("1 allRequestParams.size() = " + allRequestParams.size());
// for(Entry entry : allRequestParams.entrySet()) {
// System.out.println("1 key=" + entry.getKey() + ", value=" + entry.getValue());
// }
//
//
// System.out.println("request.getParameterMap().size() = " + request.getParameterMap().size());
// for(Entry entry : request.getParameterMap().entrySet()) {
// System.out.println("2 key=" + entry.getKey() + ", value=" + entry.getValue());
// }
//
//
// System.out.println("mdoel.size() = " + model.size());
// for(Entry entry : model.entrySet()) {
// System.out.println("3 key=" + entry.getKey() + ", value=" + entry.getValue());
// }
//
// PDDocument document = PDDocument.load(pdfFile.getBytes());
//
//
// // Remove all metadata based on flag
// PDDocumentInformation info = document.getDocumentInformation();
// for (String key : info.getMetadataKeys()) {
// info.setCustomMetadataValue(key, null);
// }
//
//
//
//
// return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_metadata.pdf");
// }
// // Loop over all pages and remove annotations

View File

@ -1,5 +1,6 @@
package stirling.software.SPDF.utils;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -7,19 +8,22 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
@ -76,27 +80,55 @@ public class PdfUtils {
}
}
public static byte[] convertFromPdf(byte[] inputStream, String imageType) throws IOException {
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
// Create a PDFRenderer to convert the PDF to an image
PDFRenderer pdfRenderer = new PDFRenderer(document);
BufferedImage bim = pdfRenderer.renderImageWithDPI(0, 300, ImageType.RGB);
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage) throws IOException, Exception {
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
PDFRenderer pdfRenderer = new PDFRenderer(document);
int pageCount = document.getNumberOfPages();
List<BufferedImage> images = new ArrayList<>();
// Create images of all pages
for (int i = 0; i < pageCount; i++) {
images.add(pdfRenderer.renderImageWithDPI(i, 300, colorType));
}
// Get an ImageWriter for the specified image type
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(imageType);
ImageWriter writer = writers.next();
if (singleImage) {
// Combine all images into a single big image
BufferedImage combined = new BufferedImage(images.get(0).getWidth() ,
images.get(0).getHeight()* pageCount, BufferedImage.TYPE_INT_RGB);
Graphics g = combined.getGraphics();
for (int i = 0; i < images.size(); i++) {
g.drawImage(images.get(i), 0, i * images.get(0).getHeight(), null);
}
images = Arrays.asList(combined);
}
// Create a ByteArrayOutputStream to save the image to
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
writer.setOutput(ios);
// Write the image to the output stream
writer.write(new IIOImage(bim, null, null));
// Log that the image was successfully written to the byte array
logger.info("Image successfully written to byte array");
}
return baos.toByteArray();
} catch (IOException e) {
// Create a ByteArrayOutputStream to save the image(s) to
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (singleImage) {
// Write the image to the output stream
ImageIO.write(images.get(0), "PNG", baos);
// Log that the image was successfully written to the byte array
logger.info("Image successfully written to byte array");
} else {
// Zip the images and return as byte array
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < images.size(); i++) {
BufferedImage image = images.get(i);
try (ByteArrayOutputStream baosImage = new ByteArrayOutputStream()) {
ImageIO.write(image, "PNG", baosImage);
// Add the image to the zip file
zos.putNextEntry(new ZipEntry(String.format("page_%d.%s", i + 1, "png")));
zos.write(baosImage.toByteArray());
}
}
// Log that the images were successfully written to the byte array
logger.info("Images successfully written to byte array as a zip");
}
}
return baos.toByteArray();
} catch (IOException e) {
// Log an error message if there is an issue converting the PDF to an image
logger.error("Error converting PDF to image", e);
throw e;

View File

@ -129,6 +129,13 @@ imageToPDF.submit=تحول
pdfToImage.title=تحويل PDF إلى صورة
pdfToImage.header=تحويل PDF إلى صورة
pdfToImage.selectText=تنسيق الصورة
pdfToImage.singleOrMultiple = \u0646\u0648\u0639 \u0646\u062A\u064A\u062C\u0629 \u0627\u0644\u0635\u0648\u0631\u0629
pdfToImage.single = \u0635\u0648\u0631\u0629 \u0648\u0627\u062D\u062F\u0629 \u0643\u0628\u064A\u0631\u0629
pdfToImage.multi = \u0635\u0648\u0631 \u0645\u062A\u0639\u062F\u062F\u0629
pdfToImage.colorType = \u0646\u0648\u0639 \u0627\u0644\u0644\u0648\u0646
pdfToImage.color = \u0627\u0644\u0644\u0648\u0646
pdfToImage.grey = \u062A\u062F\u0631\u062C \u0627\u0644\u0631\u0645\u0627\u062F\u064A
pdfToImage.blackwhite = \u0623\u0628\u064A\u0636 \u0648\u0623\u0633\u0648\u062F (\u0642\u062F \u064A\u0641\u0642\u062F \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A!)
pdfToImage.submit=تحول
#addPassword

View File

@ -126,6 +126,13 @@ imageToPDF.submit=Umwandeln
pdfToImage.title=PDF zu Bild
pdfToImage.header=PDF zu Bild
pdfToImage.selectText=Bildformat
pdfToImage.singleOrMultiple=Bildergebnistyp
pdfToImage.single=Einzelnes großes Bild
pdfToImage.multi=Mehrere Bilder
pdfToImage.colorType=Farbtyp
pdfToImage.color=Farbe
pdfToImage.grey=Graustufen
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
pdfToImage.submit=Umwandeln
#addPassword

View File

@ -124,6 +124,13 @@ imageToPDF.submit=Convert
pdfToImage.title=PDF to Image
pdfToImage.header=PDF to Image
pdfToImage.selectText=Image Format
pdfToImage.singleOrMultiple=Image result type
pdfToImage.single=Single Big Image
pdfToImage.multi=Multiple Images
pdfToImage.colorType=Colour type
pdfToImage.color=Colour
pdfToImage.grey=Greyscale
pdfToImage.blackwhite=Black and White (May lose data!)
pdfToImage.submit=Convert
#addPassword

View File

@ -127,8 +127,16 @@ imageToPDF.submit=Convert
pdfToImage.title=PDF to Image
pdfToImage.header=PDF to Image
pdfToImage.selectText=Image Format
pdfToImage.singleOrMultiple=Image result type
pdfToImage.single=Single Big Image
pdfToImage.multi=Multiple Images
pdfToImage.colorType=Color type
pdfToImage.color=Color
pdfToImage.grey=Grayscale
pdfToImage.blackwhite=Black and White (May lose data!)
pdfToImage.submit=Convert
#addPassword
addPassword.title=Add Password
addPassword.header=Add password (Encrypt)

View File

@ -129,6 +129,13 @@ imageToPDF.submit=Convertir
pdfToImage.title=PDF vers image
pdfToImage.header=PDF vers image
pdfToImage.selectText=Format d'image
pdfToImage.singleOrMultiple=Type de résultat d'image
pdfToImage.single=Une seule grande image
pdfToImage.multi=Plusieurs images
pdfToImage.colorType=Type de couleur
pdfToImage.color=Couleur
pdfToImage.grey=Niveaux de gris
pdfToImage.blackwhite=Noir et Blanc (Peut perdre des données !)
pdfToImage.submit=Convertir
#addPassword

View File

@ -14,24 +14,39 @@
<div class="row justify-content-center">
<div class="col-md-6">
<h2 th:text="#{pdfToImage.header}"></h2>
<p th:text="#{processTimeWarning}"></p>
<form method="post" enctype="multipart/form-data"
th:action="@{pdf-to-img}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div class="form-group">
<label th:text="#{pdfToImage.selectText}"></label> <select class="form-control"
name="imageFormat">
<option value="jpg">JPEG</option>
<option value="png">PNG</option>
<option value="gif">GIF</option>
</select>
</div>
<div class="form-group">
<label th:text="#{pdfToImage.singleOrMultiple}"></label>
<select class="form-control" name="singleOrMultiple">
<option value="single" th:text="#{pdfToImage.single}"></option>
<option value="multiple" th:text="#{pdfToImage.multi}"></option>
</select>
</div>
<div class="form-group">
<label th:text="#{pdfToImage.colorType}"></label>
<select class="form-control" name="colorType">
<option value="color" th:text="#{pdfToImage.color}"></option>
<option value="greyscale" th:text="#{pdfToImage.grey}"></option>
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option>
</select>
</div>
<button type="submit" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>

View File

@ -14,25 +14,21 @@
<h2 th:text="#{changeMetadata.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{/update-metadata}">
<div class="form-group">
<label for="pdfFile">PDF File:</label>
<input type="file" id="pdfFile" name="pdfFile"/>
</div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<p class="text-muted">Please select the variables you wish to change</p>
<div class="form-group">
<label for="advancedMode">Delete all metadata</label>
<div class="form-group form-check form-check-inline">
<input type="checkbox" class="form-check-input" id="deleteAll">
<label class="ml-3" for="deleteAll">Delete all metadata</label>
</div>
<div class="form-group">
<label for="advancedMode">Show Advanced Metadata:</label>
<input type="checkbox" class="form-check-input" id="advancedMode">
<div class="form-group form-check form-check-inline">
<input type="checkbox" class="form-check-input" id="advancedModeCheckbox">
<label class="ml-3" for="advancedModeCheckbox">Show Advanced Metadata:</label>
</div>
<div class="form-group form-check">
<label class="form-check-label" for="author">Author:</label>
<input type="text" class="form-control" id="author">
@ -69,12 +65,12 @@
</div>
<div class="form-group form-check">
<label class="form-check-label" for="title">Subject:</label>
<label class="form-check-label" for="title">Title:</label>
<input type="text" class="form-control" id="title">
</div>
<div class="form-group form-check">
<label class="form-check-label" for="trapped">Subject:</label>
<label class="form-check-label" for="trapped">Trapped:</label>
<input type="text" class="form-control" id="trapped">
</div>
<div id="advancedMetadata" style="display:none;">
@ -82,13 +78,13 @@
<div class="form-group" id="otherMetadataEntries"></div>
</div>
<div id="customMetadataEntries"></div>
<button type="button" id="addMetadataBtn">Add Custom Metadata Entry</button>
<button type="button" class="btn btn-secondary" id="addMetadataBtn">Add Custom Metadata Entry</button>
<br><br>
<button type="submit">Save Changes and Download PDF</button>
<button class="btn btn-primary" type="submit">Save Changes and Download PDF</button>
<script>
const advancedModeCheckbox = document.getElementById('advancedMode');
const advancedModeCheckbox = document.getElementById('advancedModeCheckbox');
const advancedMetadataDiv = document.getElementById('advancedMetadata');
const otherMetadataEntriesDiv = document.getElementById('otherMetadataEntries');
@ -113,23 +109,9 @@
customMetadataFormContainer.appendChild(valueInput);
});
// async function addCustomMetadata(pdf, key, value) {
// const pdfMetadata = pdf.getMetadata();
// pdfMetadata.then((metadata) => {
// metadata[key] = value;
// pdf.setMetadata(metadata).then(() => {
// console.log(`Successfully added custom metadata with key '${key}' and value '${value}'`);
// }).catch((err) => {
// console.error(`Error adding custom metadata: ${err}`);
// });
// });
//}
//const customMetadataEntries = customMetadataFormContainer.querySelectorAll("input[type='text']");
//for (let i = 0; i < customMetadataEntries.length; i += 2) {
const pdfFileInput = document.querySelector("#pdfFile");
const fileInput = document.querySelector("#fileInput-input");
const authorInput = document.querySelector("#author");
const creationDateInput = document.querySelector("#creationDate");
const creatorInput = document.querySelector("#creator");
@ -141,7 +123,7 @@
const trappedInput = document.querySelector("#trapped");
var lastPDFFileMeta = null;
pdfFile.addEventListener("change", async function() {
fileInput.addEventListener("change", async function() {
const file = this.files[0];
var url = URL.createObjectURL(file)
@ -161,39 +143,41 @@
addExtra();
});
function addExtra() {
const event = document.getElementById("advancedModeCheckbox");
if (event.checked) {
advancedMetadataDiv.style.display = 'block';
for (const [key, value] of Object.entries(lastPDFFile)) {
if (key === 'Author' || key === 'CreationDate' || key === 'Creator' || key === 'Keywords' || key === 'ModDate' || key === 'Producer' || key === 'Subject' || key === 'Title' || key === 'Trapped') {
continue;
}
const entryDiv = document.createElement('div');
entryDiv.className = 'form-group';
entryDiv.innerHTML = `<div class="form-group form-check"><label class="form-check-label" for="${key}">${key}:</label><input value="${value}" type="text" class="form-control" id="${key}"></div>`;
otherMetadataEntriesDiv.appendChild(entryDiv);
}
} else {
advancedMetadataDiv.style.display = 'none';
while (otherMetadataEntriesDiv.firstChild) {
otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild);
}
}
}
advancedModeCheckbox.addEventListener('change', (event) => {
addExtra();
});
function addExtra() {
const event = document.getElementById("advancedModeCheckbox");
if (event.target.checked) {
advancedMetadataDiv.style.display = 'block';
for (const [key, value] of Object.entries(pdfMetadata.info)) {
if (key === 'Author' || key === 'CreationDate' || key === 'Creator' || key === 'Keywords' || key === 'ModDate' || key === 'Producer' || key === 'Subject' || key === 'Title' || key === 'Trapped') {
continue;
}
const entryDiv = document.createElement('div');
entryDiv.className = 'form-group';
entryDiv.innerHTML = `<label for="${key}">${key}:</label><input type="text" id="${key}" value="${value}" disabled>`;
otherMetadataEntriesDiv.appendChild(entryDiv);
}
} else {
advancedMetadataDiv.style.display = 'none';
while (otherMetadataEntriesDiv.firstChild) {
otherMetadataEntriesDiv.removeChild(otherMetadataEntriesDiv.firstChild);
}
}
}
</script>
</form>