chnages testing new stuff

This commit is contained in:
Anthony Stirling 2023-03-17 20:21:52 +00:00
parent 585562b363
commit ca1aa75208
16 changed files with 768 additions and 117 deletions

View File

@ -20,16 +20,26 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
//implementation 'org.apache.pdfbox:preflight:2.0.27'
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'e-iceblue:spire.pdf.free:5.1.0'
implementation 'org.apache.poi:poi:5.2.3'
implementation 'org.apache.poi:poi-ooxml:5.2.3'
implementation 'org.apache.xmlgraphics:batik-transcoder:1.14'
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
//general PDF
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
implementation 'com.itextpdf:itextpdf:5.5.13.3'
//xml conversions and others
implementation 'org.apache.poi:poi:5.2.3'
implementation 'org.apache.poi:poi-scratchpad:5.2.3'
implementation 'org.apache.poi:poi-ooxml:5.2.3'
implementation 'com.itextpdf.tool:xmlworker:5.5.13.3'
//docx conversions
implementation('org.docx4j:docx4j:6.1.2') {
exclude group: 'org.slf4j', module: 'slf4j-reload4j'
}
implementation 'org.docx4j:docx4j-export-fo:11.2.9'
}
jar {

View File

@ -9,6 +9,6 @@ public class AppConfig {
@Bean(name = "appVersion")
public String appVersion() {
String version = getClass().getPackage().getImplementationVersion();
return (version != null) ? version : "Develop";
return (version != null) ? version : "0.3.3";
}
}

View File

@ -1,9 +1,23 @@
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;
@ -12,11 +26,9 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.spire.pdf.PdfCompressionLevel;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.exporting.PdfImageInfo;
import com.spire.pdf.graphics.PdfBitmap;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import stirling.software.SPDF.utils.PdfUtils;
@ -32,36 +44,81 @@ public class CompressController {
return "compress-pdf";
}
@PostMapping("/compress-pdf")
public ResponseEntity<byte[]> compressPDF(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("imageCompressionLevel") String imageCompressionLevel)
throws IOException {
// Load a sample PDF document
PdfDocument document = new PdfDocument();
document.loadFromBytes(pdfFile.getBytes());
public ResponseEntity<byte[]> compressPDF(
@RequestParam("fileInput") MultipartFile pdfFile,
@RequestParam(value = "compressPDF", defaultValue = "false") boolean compressPDF,
@RequestParam(value = "compressImages", defaultValue = "false") boolean compressImages,
@RequestParam(value = "useLossyCompression", defaultValue = "false") boolean useLossyCompression,
@RequestParam(value = "resolutionPercentage", defaultValue = "50") int resolutionPercentage) {
// Compress PDF
document.getFileInfo().setIncrementalUpdate(false);
document.setCompressionLevel(PdfCompressionLevel.Best);
ByteArrayOutputStream baosPDFBox = new ByteArrayOutputStream();
try (InputStream is = pdfFile.getInputStream();
PDDocument document = PDDocument.load(is)) {
// compress PDF Images
for (int i = 0; i < document.getPages().getCount(); i++) {
PdfPageBase page = document.getPages().get(i);
PdfImageInfo[] images = page.getImagesInfo();
if (images != null && images.length > 0)
for (int j = 0; j < images.length; j++) {
PdfImageInfo image = images[j];
PdfBitmap bp = new PdfBitmap(image.getImage());
// bp.setPngDirectToJpeg(true);
bp.setQuality(Integer.valueOf(imageCompressionLevel));
page.replaceImage(j, bp);
if (compressImages) {
for (PDPage page : document.getPages()) {
PDResources resources = page.getResources();
for (COSName cosName : resources.getXObjectNames()) {
if (resources.isImageXObject(cosName)) {
PDImageXObject image = (PDImageXObject) resources.getXObject(cosName);
BufferedImage bufferedImage = image.getImage();
BufferedImage resizedImage = resizeImage(bufferedImage, resolutionPercentage);
if (useLossyCompression) {
File tempFile = File.createTempFile("pdfbox", ".jpg");
ImageIO.write(resizedImage, "jpg", tempFile);
PDImageXObject newImage = PDImageXObject.createFromFile(tempFile.getAbsolutePath(), document);
resources.put(cosName, newImage);
} else {
File tempFile = File.createTempFile("pdfbox", ".png");
ImageIO.write(resizedImage, "png", tempFile);
PDImageXObject newImage = PDImageXObject.createFromFile(tempFile.getAbsolutePath(), document);
resources.put(cosName, newImage);
}
}
}
}
}
document.save(baosPDFBox);
} catch (IOException e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_compressed.pdf");
try (ByteArrayInputStream baisPDFBox = new ByteArrayInputStream(baosPDFBox.toByteArray());
ByteArrayOutputStream baosFinal = new ByteArrayOutputStream()) {
PdfReader reader = new PdfReader(baisPDFBox);
PdfStamper stamper = new PdfStamper(reader, baosFinal);
if (compressPDF) {
stamper.setFullCompression();
}
stamper.close();
reader.close();
return PdfUtils.boasToWebResponse(baosFinal, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_compressed.pdf");
} catch (IOException | DocumentException e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private BufferedImage resizeImage(BufferedImage originalImage, int resolutionPercentage) {
int newWidth = originalImage.getWidth() * resolutionPercentage / 100;
int newHeight = originalImage.getHeight() * resolutionPercentage / 100;
BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
g.dispose();
return resizedImage;
}
}

View File

@ -0,0 +1,79 @@
package stirling.software.SPDF.controller.converters;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
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.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import stirling.software.SPDF.utils.PdfUtils;
@Controller
public class ConvertCsvController {
@GetMapping("/csv-to-pdf")
public String cinvertToPDF(Model model) {
model.addAttribute("currentPage", "xlsx-to-pdf");
return "convert/xlsx-to-pdf";
}
@PostMapping("/csv-to-pdf")
public ResponseEntity<byte[]> convertCsvToPdf(@RequestParam("fileInput") MultipartFile csvFile) throws IOException, DocumentException {
// Create PDF document
Document document = new Document();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter.getInstance(document, outputStream);
document.open();
// Read CSV file
InputStreamReader inputStreamReader = new InputStreamReader(csvFile.getInputStream(), StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// Create PDF table from CSV content
PdfPTable table = null;
String csvRow;
while ((csvRow = bufferedReader.readLine()) != null) {
String[] csvRowCells = csvRow.split(","); // Assuming comma as a delimiter
if (table == null) {
table = new PdfPTable(csvRowCells.length);
}
for (String cellValue : csvRowCells) {
PdfPCell pdfCell = new PdfPCell(new Paragraph(cellValue));
table.addCell(pdfCell);
}
}
if (table != null) {
document.add(table);
}
// Close BufferedReader, document, and output stream
bufferedReader.close();
document.close();
outputStream.close();
return PdfUtils.boasToWebResponse(outputStream, csvFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
}
}

View File

@ -0,0 +1,43 @@
package stirling.software.SPDF.controller.converters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
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 stirling.software.SPDF.utils.PdfUtils;
@Controller
public class ConvertDocController {
@GetMapping("/docx-to-pdf")
public String cinvertToPDF(Model model) {
model.addAttribute("currentPage", "xlsx-to-pdf");
return "convert/xlsx-to-pdf";
}
@PostMapping("/docx-to-pdf")
public ResponseEntity<byte[]> convertDocxToPdf(@RequestParam("fileInput") MultipartFile docxFile) throws IOException, Docx4JException {
// Load WordprocessingMLPackage
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(docxFile.getInputStream());
// Create PDF output stream
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// Convert DOCX to PDF
Docx4J.toPDF(wordMLPackage, outputStream);
return PdfUtils.boasToWebResponse(outputStream, docxFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
}
}

View File

@ -0,0 +1,54 @@
package stirling.software.SPDF.controller.converters;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
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.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import stirling.software.SPDF.utils.PdfUtils;
@Controller
public class ConvertHtmlController {
@GetMapping("//html-to-pdf")
public String cinvertToPDF(Model model) {
model.addAttribute("currentPage", "xlsx-to-pdf");
return "convert/xlsx-to-pdf";
}
@PostMapping("/html-to-pdf")
public ResponseEntity<byte[]> convertHtmlToPdf(@RequestParam("fileInput") MultipartFile htmlFile) throws IOException, DocumentException {
// Create PDF document
Document document = new Document();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
// Read HTML file
InputStream htmlInputStream = new ByteArrayInputStream(htmlFile.getBytes());
// Convert HTML content to PDF
XMLWorkerHelper.getInstance().parseXHtml(writer, document, htmlInputStream);
// Close document and output stream
document.close();
outputStream.close();
return PdfUtils.boasToWebResponse(outputStream, "");
}
}

View File

@ -0,0 +1,79 @@
package stirling.software.SPDF.controller.converters;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
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.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import stirling.software.SPDF.utils.PdfUtils;
@Controller
public class ConvertPPTController {
@GetMapping("/pptx-to-pdf")
public String cinvertToPDF(Model model) {
model.addAttribute("currentPage", "xlsx-to-pdf");
return "convert/xlsx-to-pdf";
}
@PostMapping("/pptx-to-pdf")
public ResponseEntity<byte[]> convertPptxToPdf(@RequestParam("fileInput") MultipartFile pptxFile) throws IOException, DocumentException {
// Read PowerPoint presentation
XMLSlideShow ppt = new XMLSlideShow(pptxFile.getInputStream());
// Create PDF document
Document pdfDocument = new Document(PageSize.A4.rotate());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter.getInstance(pdfDocument, outputStream);
pdfDocument.open();
// Convert PowerPoint slides to images, then add them to the PDF
for (XSLFSlide slide : ppt.getSlides()) {
BufferedImage slideImage = new BufferedImage((int) Math.ceil(ppt.getPageSize().getWidth()), (int) Math.ceil(ppt.getPageSize().getHeight()), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = slideImage.createGraphics();
// Set graphics rendering hints for better quality
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
// Draw the slide on the graphics
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, slideImage.getWidth(), slideImage.getHeight()));
slide.draw(graphics);
// Add the slide image to the PDF document
Image image = Image.getInstance(slideImage, null);
image.scaleToFit(PageSize.A4.getWidth() - 72, PageSize.A4.getHeight() - 72);
pdfDocument.add(image);
}
// Close PowerPoint and PDF documents
ppt.close();
pdfDocument.close();
outputStream.close();
return PdfUtils.boasToWebResponse(outputStream, pptxFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
}
}

View File

@ -0,0 +1,63 @@
package stirling.software.SPDF.controller.converters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
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.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import stirling.software.SPDF.utils.PdfUtils;
@Controller
public class ConvertTextController {
@GetMapping("/txt-rtf-to-pdf")
public String cinvertToPDF(Model model) {
model.addAttribute("currentPage", "xlsx-to-pdf");
return "convert/xlsx-to-pdf";
}
@PostMapping("/txt-rtf-to-pdf")
public ResponseEntity<byte[]> convertTxtRtfToPdf(@RequestParam("fileInput") MultipartFile txtRtfFile) throws IOException, DocumentException {
// Create PDF document
Document document = new Document();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter.getInstance(document, outputStream);
document.open();
// Read TXT/RTF file content
String fileContent;
String fileExtension = FilenameUtils.getExtension(txtRtfFile.getOriginalFilename());
if (fileExtension.equalsIgnoreCase("rtf")) {
HWPFDocument hwpfDocument = new HWPFDocument(new POIFSFileSystem(txtRtfFile.getInputStream()));
fileContent = hwpfDocument.getText().toString();
} else {
fileContent = new String(txtRtfFile.getBytes(), StandardCharsets.UTF_8);
}
// Add content to PDF
document.add(new Paragraph(fileContent));
// Close document and output stream
document.close();
outputStream.close();
return PdfUtils.boasToWebResponse(outputStream, txtRtfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
}
}

View File

@ -3,8 +3,15 @@ package stirling.software.SPDF.controller.converters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@ -16,6 +23,8 @@ import org.springframework.web.multipart.MultipartFile;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
@ -33,11 +42,10 @@ public class ConvertXlsxController {
}
@PostMapping("/xlsx-to-pdf")
public ResponseEntity<byte[]> convertToPDF(@RequestParam("fileInput") MultipartFile xlsx) throws IOException, DocumentException{
// Load Excel file
public ResponseEntity<byte[]> convertToPDF(@RequestParam("fileInput") MultipartFile xlsx) throws IOException, DocumentException {
// Load Excel file
Workbook workbook = WorkbookFactory.create(xlsx.getInputStream());
// Create PDF document
Document document = new Document();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@ -46,32 +54,99 @@ public class ConvertXlsxController {
// Convert each sheet in Excel to a separate page in PDF
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
PdfPTable table = new PdfPTable(workbook.getSheetAt(i).getRow(0).getPhysicalNumberOfCells());
for (int row = 0; row < workbook.getSheetAt(i).getPhysicalNumberOfRows(); row++) {
for (int cell = 0; cell < workbook.getSheetAt(i).getRow(row).getPhysicalNumberOfCells(); cell++) {
PdfPCell pdfCell = new PdfPCell();
pdfCell.addElement(new com.itextpdf.text.Paragraph(workbook.getSheetAt(i).getRow(row).getCell(cell).toString()));
Sheet sheet = workbook.getSheetAt(i);
int numOfColumns = sheet.getRow(0).getPhysicalNumberOfCells();
PdfPTable table = new PdfPTable(numOfColumns);
// Copy cell style, borders, and background color
pdfCell.setBorderColor(new BaseColor(workbook.getSheetAt(i).getRow(row).getCell(cell).getCellStyle().getBottomBorderColor()));
pdfCell.setBorderColor(new BaseColor(workbook.getSheetAt(i).getRow(row).getCell(cell).getCellStyle().getTopBorderColor()));
pdfCell.setBorderColor(new BaseColor(workbook.getSheetAt(i).getRow(row).getCell(cell).getCellStyle().getLeftBorderColor()));
pdfCell.setBorderColor(new BaseColor(workbook.getSheetAt(i).getRow(row).getCell(cell).getCellStyle().getRightBorderColor()));
Short bc = workbook.getSheetAt(i).getRow(row).getCell(cell).getCellStyle().getFillBackgroundColor();
pdfCell.setBackgroundColor(new BaseColor(bc));
for (int row = 0; row < sheet.getPhysicalNumberOfRows(); row++) {
Row excelRow = sheet.getRow(row);
if (excelRow == null) {
continue; // Skip this row if it's null
}
for (int cell = 0; cell < excelRow.getPhysicalNumberOfCells(); cell++) {
Cell excelCell = excelRow.getCell(cell);
// Check if the cell is null
if (excelCell == null) {
table.addCell(""); // Add an empty cell to the PDF table
continue;
}
// Convert cell to string
DataFormatter dataFormatter = new DataFormatter();
String cellValue = dataFormatter.formatCellValue(excelCell);
System.out.println("Cell Value: " + cellValue);
// Get Excel cell font
Font cellFont = getFontFromExcelCell(workbook, excelCell);
// Create PDF cell with Excel cell font
PdfPCell pdfCell = new PdfPCell(new Paragraph(cellValue, cellFont));
// Set cell height and width
float height = sheet.getRow(row).getHeightInPoints();
System.out.print(height);
pdfCell.setFixedHeight(30f);
// Copy cell style, borders, and background color
XSSFCellStyle cellStyle = (XSSFCellStyle) excelCell.getCellStyle();
if (cellStyle != null) {
XSSFColor bottomBorderColor = cellStyle.getBottomBorderXSSFColor();
if (bottomBorderColor != null) {
pdfCell.setBorderColor(new BaseColor(bottomBorderColor.getRGB()[0] & 0xFF, bottomBorderColor.getRGB()[1] & 0xFF, bottomBorderColor.getRGB()[2] & 0xFF));
}
XSSFColor topBorderColor = cellStyle.getTopBorderXSSFColor();
if (topBorderColor != null) {
pdfCell.setBorderColor(new BaseColor(topBorderColor.getRGB()[0] & 0xFF, topBorderColor.getRGB()[1] & 0xFF, topBorderColor.getRGB()[2] & 0xFF));
}
XSSFColor leftBorderColor = cellStyle.getLeftBorderXSSFColor();
if (leftBorderColor != null) {
pdfCell.setBorderColor(new BaseColor(leftBorderColor.getRGB()[0] & 0xFF, leftBorderColor.getRGB()[1] & 0xFF, leftBorderColor.getRGB()[2] & 0xFF));
}
XSSFColor rightBorderColor = cellStyle.getRightBorderXSSFColor();
if (rightBorderColor != null) {
pdfCell.setBorderColor(new BaseColor(rightBorderColor.getRGB()[0] & 0xFF, rightBorderColor.getRGB()[1] & 0xFF, rightBorderColor.getRGB()[2] & 0xFF));
}
XSSFColor fillForegroundColor = cellStyle.getFillForegroundXSSFColor();
if (fillForegroundColor != null) {
pdfCell.setBackgroundColor(new BaseColor(fillForegroundColor.getRGB()[0] & 0xFF, fillForegroundColor.getRGB()[1] & 0xFF, fillForegroundColor.getRGB()[2] & 0xFF));
}
}
table.addCell(pdfCell);
}
}
// Add sheet to PDF
document.add(table);
// Add page break if there are more sheets
if (i < workbook.getNumberOfSheets() - 1) {
document.newPage();
}
}
// Close document and output stream
document.close();
outputStream.flush();
outputStream.close();
return PdfUtils.boasToWebResponse(outputStream, xlsx.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
// Close document and input stream
outputStream.close();
// Return PDF as response
return PdfUtils.boasToWebResponse(outputStream, xlsx.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_convertedToPDF.pdf");
}
private Font getFontFromExcelCell(Workbook workbook, Cell excelCell) {
XSSFFont excelFont = ((XSSFCellStyle) excelCell.getCellStyle()).getFont();
Font.FontFamily fontFamily = Font.getFamily(excelFont.getFontName());
float fontSize = excelFont.getFontHeightInPoints();
int fontStyle = (excelFont.getBold() ? Font.BOLD : Font.NORMAL) | (excelFont.getItalic() ? Font.ITALIC : Font.NORMAL);
return new Font(fontFamily, fontSize, fontStyle);
}
}

View File

@ -2,12 +2,19 @@ package stirling.software.SPDF.controller.security;
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationMarkup;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.util.Matrix;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
@ -18,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.utils.PdfUtils;
import stirling.software.SPDF.utils.WatermarkRemover;
@Controller
public class WatermarkController {
@ -28,6 +36,12 @@ public class WatermarkController {
return "security/add-watermark";
}
@GetMapping("/remove-watermark")
public String removeWatermarkForm(Model model) {
model.addAttribute("currentPage", "remove-watermark");
return "security/remove-watermark";
}
@PostMapping("/add-watermark")
public ResponseEntity<byte[]> addWatermark(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("watermarkText") String watermarkText,
@RequestParam(defaultValue = "30", name = "fontSize") float fontSize, @RequestParam(defaultValue = "0", name = "rotation") float rotation,
@ -71,4 +85,62 @@ public class WatermarkController {
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
}
@PostMapping("/remove-watermark")
public ResponseEntity<byte[]> removeWatermark(@RequestParam("fileInput") MultipartFile pdfFile, @RequestParam("watermarkText") String watermarkText) throws Exception {
// Load the input PDF
PDDocument document = PDDocument.load(pdfFile.getInputStream());
// Create a new PDF document for the output
PDDocument outputDocument = new PDDocument();
// Loop through the pages
int numPages = document.getNumberOfPages();
for (int i = 0; i < numPages; i++) {
PDPage page = document.getPage(i);
// Process the content stream to remove the watermark text
WatermarkRemover editor = new WatermarkRemover(watermarkText) {};
editor.processPage(page);
editor.processPage(page);
// Add the page to the output document
outputDocument.addPage(page);
}
for (PDPage page : outputDocument.getPages()) {
List<PDAnnotation> annotations = page.getAnnotations();
List<PDAnnotation> annotationsToRemove = new ArrayList<>();
for (PDAnnotation annotation : annotations) {
if (annotation instanceof PDAnnotationMarkup) {
PDAnnotationMarkup markup = (PDAnnotationMarkup) annotation;
String contents = markup.getContents();
if (contents != null && contents.contains(watermarkText)) {
annotationsToRemove.add(markup);
}
}
}
annotations.removeAll(annotationsToRemove);
}
PDDocumentCatalog catalog = outputDocument.getDocumentCatalog();
PDAcroForm acroForm = catalog.getAcroForm();
if (acroForm != null) {
List<PDField> fields = acroForm.getFields();
for (PDField field : fields) {
String fieldValue = field.getValueAsString();
if (fieldValue.contains(watermarkText)) {
field.setValue(fieldValue.replace(watermarkText, ""));
}
}
}
return PdfUtils.pdfDocToWebResponse(outputDocument, "removed.pdf");
}
}

View File

@ -32,7 +32,6 @@ import org.springframework.http.ResponseEntity;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.spire.pdf.PdfDocument;
public class PdfUtils {
@ -172,16 +171,7 @@ public class PdfUtils {
return PdfUtils.boasToWebResponse(baos, docName);
}
public static ResponseEntity<byte[]> pdfDocToWebResponse(PdfDocument document, String docName) throws IOException {
// Open Byte Array and save document to it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.saveToStream(baos);
// Close the document
document.close();
return PdfUtils.boasToWebResponse(baos, docName);
}
public static ResponseEntity<byte[]> pdfDocToWebResponse(PDDocument document, String docName) throws IOException {

View File

@ -0,0 +1,69 @@
package stirling.software.SPDF.utils;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.pdfbox.contentstream.PDFStreamEngine;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSString;
public class WatermarkRemover extends PDFStreamEngine {
private final String watermarkText;
private final Pattern pattern;
public WatermarkRemover(String watermarkText) {
this.watermarkText = watermarkText;
this.pattern = Pattern.compile(Pattern.quote(watermarkText));
}
@Override
protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
String operation = operator.getName();
boolean processText = false;
if ("Tj".equals(operation) || "TJ".equals(operation) || "'".equals(operation) || "\"".equals(operation)) {
processText = true;
}
if (processText) {
for(int j = 0 ; j < operands.size(); ++j) {
COSBase operand = operands.get(j);
if (operand instanceof COSString) {
COSString cosString = (COSString) operand;
String string = cosString.getString();
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
string = matcher.replaceAll("");
cosString.setValue(string.getBytes());
}
} else if (operand instanceof COSArray) {
COSArray array = (COSArray) operand;
for (int i = 0; i < array.size(); i++) {
COSBase item = array.get(i);
if (item instanceof COSString) {
COSString cosString = (COSString) item;
String string = cosString.getString();
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
System.out.println("operation =" + operation);
System.out.println("1 =" + string);
string = matcher.replaceAll("");
cosString.setValue(string.getBytes());
array.set(i, cosString);
operands.set(j, array);
}
}
}
}
}
}
super.processOperator(operator, operands);
}
}

View File

@ -14,15 +14,61 @@
<div class="row justify-content-center">
<div class="col-md-6">
<h2 th:text="#{compress.header}"></h2>
<form action="#" th:action="@{compress-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
<p th:text="#{processTimeWarning}"></p>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<div class="form-group">
<label for="imageCompressionLevel" th:text="#{compress.compressLevel}"></label>
<input type="number" class="form-control" id="imageCompressionLevel" name="imageCompressionLevel" step="1" value="1" min="1" max="100" required>
</div>
<button type="submit" class="btn btn-primary" th:text="#{compress.submit}"></button>
</form>
<form method="post" enctype="multipart/form-data" th:action="@{/compress-pdf}">
<div class="form-group">
<label for="fileInput">Select a PDF file to compress:</label>
<input type="file" class="form-control-file" id="fileInput" name="fileInput" accept=".pdf">
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="compressPDF" name="compressPDF" checked>
<label class="form-check-label" for="compressPDF">Compress PDF?</label>
</div>
<div class="form-group">
<label for="pdfCompressionLevel">PDF Compression Level:</label>
<select class="form-control" id="pdfCompressionLevel" name="pdfCompressionLevel">
<option value="0">0 (No compression)</option>
<option value="1">1 (Lowest compression)</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5" selected>5 (Default compression)</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9 (Maximum compression)</option>
</select>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="compressImages" name="compressImages" checked>
<label class="form-check-label" for="compressImages">Compress Images?</label>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="useLossyCompression" name="useLossyCompression">
<label class="form-check-label" for="useLossyCompression">Use Lossy Compression for Images?</label>
</div>
</div>
<div class="form-group">
<label for="imageCompressionLevel">Image Compression Level:</label>
<select class="form-control" id="imageCompressionLevel" name="imageCompressionLevel">
<option value="0">0 (No compression)</option>
<option value="10">10 (Lowest quality)</option>
<option value="25">25</option>
<option value="50" selected>50 (Default quality)</option>
<option value="75">75</option>
<option value="90">90 (High quality)</option>
<option value="100">100 (Best quality)</option>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Compress PDF</button>
</div>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>

View File

@ -1,4 +1,5 @@
<th:block th:fragment="errorBanner">
<style>
#github-button,
#discord-button {
@ -17,7 +18,7 @@
background-color: #005b7f;
}
</style>
<br th:if="${message}">
<br th:if="${message}">
<div id="errorContainer" th:if="${message}" class="alert alert-danger alert-dismissible fade show" role="alert">
<h4 class="alert-heading" th:text="'Error: ' + ${status} + ' ' + ${error}"></h4>
<p th:text="${message} + ' for path: ' + ${path}"></p>
@ -36,39 +37,53 @@
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank">Join our Discord server</a>
</div>
</div>
<script>
function toggletrace() {
var traceDiv = document.getElementById("trace");
if (traceDiv.style.maxHeight === "0px") {
traceDiv.style.maxHeight = "500px";
} else {
traceDiv.style.maxHeight = "0px";
<script>
var traceVisible = false;
function toggletrace() {
var traceDiv = document.getElementById("trace");
if (!traceVisible) {
traceDiv.style.maxHeight = "500px";
traceVisible = true;
} else {
traceDiv.style.maxHeight = "0px";
traceVisible = false;
}
adjustContainerHeight();
}
adjustContainerHeight();
}
function copytrace() {
var traceContent = document.getElementById("traceContent");
var range = document.createRange();
range.selectNode(traceContent);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand("copy");
window.getSelection().removeAllRanges();
}
function copytrace() {
var flip = false
if(!traceVisible) {
toggletrace()
flip = true
}
var traceContent = document.getElementById("traceContent");
var range = document.createRange();
range.selectNode(traceContent);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand("copy");
window.getSelection().removeAllRanges();
if(flip){
toggletrace()
}
}
function dismissError() {
var errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "none";
errorContainer.style.height ="0";
}
function dismissError() {
var errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "none";
errorContainer.style.height ="0";
}
function adjustContainerHeight() {
var errorContainer = document.getElementById("errorContainer");
var traceDiv = document.getElementById("trace");
errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
}
function adjustContainerHeight() {
var errorContainer = document.getElementById("errorContainer");
var traceDiv = document.getElementById("trace");
if (traceVisible) {
errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
} else {
errorContainer.style.height = "auto";
}
}
</script>
</th:block>
</th:block>

View File

@ -93,10 +93,12 @@ function compareVersions(version1, version2) {
console.log("latestVersion=" + latestVersion)
console.log("currentVersion=" + currentVersion)
console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion))
if (latestVersion != null && latestVersion != "" && compareVersions(currentVersion, latestVersion) > 0) {
document.getElementById("update-btn").style.display = "block";
if (latestVersion != null && latestVersion != "" && compareVersions(latestVersion, currentVersion) > 0) {
document.getElementById("update-btn").style.visibility = "visible";
console.log("visible")
} else {
document.getElementById("update-btn").style.display = "none";
document.getElementById("update-btn").style.visibility = "hidden";
console.log("hidden")
}
}
@ -166,16 +168,12 @@ function compareVersions(version1, version2) {
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 20 20">
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.539c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.312.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a13.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.694.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.418.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
</svg>
</a>
</a>
<div class="dropdown-menu" aria-labelledby="languageDropdown">
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_US">English (US)</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_GB">English (UK)</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="ar_AR">العربية</a>
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="de_DE">Deutsch</a> <a class="dropdown-item lang_dropdown-item" href="" data-language-code="fr_FR">Français</a>
</div></li>
<li class="nav-item">
<button type="button" class="btn btn-outline-primary" id="update-btn">Update available</button>
</div>
</li>
<li class="nav-item">
<!-- Settings Button -->
@ -201,6 +199,7 @@ function compareVersions(version1, version2) {
<span aria-hidden="true">&times;</span>
</button>
</div>
<button type="button" class="btn btn-outline-primary" id="update-btn">Update available</button>
<div class="modal-body">
<p th:text="'App Version: ' + ${@appVersion}"></p>
<div class="form-group">

View File

@ -13,7 +13,7 @@
<div class="col-md-6">
<h2 th:text="#{remove-watermark.header}"></h2>
<form method="post" enctype="multipart/form-data" action="remove-text">
<form method="post" enctype="multipart/form-data" action="remove-watermark">
<div class="form-group">
<label th:text="#{remove-watermark.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>