error handling, excel, bug fixes, name fixes (#57)

This commit is contained in:
Anthony Stirling 2023-02-24 22:47:26 +00:00 committed by GitHub
parent 6135d08154
commit 67345d083e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 558 additions and 45 deletions

View file

@ -23,6 +23,12 @@ dependencies {
implementation 'org.apache.pdfbox:pdfbox:2.0.27'
implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
implementation 'e-iceblue:spire.pdf.free:5.1.0'
implementation 'org.apache.poi:poi:5.2.0'
implementation 'org.apache.poi:poi-ooxml:5.2.0'
implementation 'com.itextpdf:itextpdf:5.5.13.2'
}
jar {

View file

@ -18,6 +18,7 @@ import com.spire.pdf.PdfPageBase;
import com.spire.pdf.exporting.PdfImageInfo;
import com.spire.pdf.graphics.PdfBitmap;
import stirling.software.SPDF.utils.ErrorUtils;
import stirling.software.SPDF.utils.PdfUtils;
//import com.spire.pdf.*;
@ -35,7 +36,6 @@ public class CompressController {
@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());
@ -61,7 +61,7 @@ public class CompressController {
}
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_compressed.pdf");
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_compressed.pdf");
}

View file

@ -34,7 +34,7 @@ public class OverlayImageController {
byte[] imageBytes = imageFile.getBytes();
byte[] result = PdfUtils.overlayImage(pdfBytes, imageBytes, x, y);
return PdfUtils.bytesToWebResponse(result, pdfFile.getName() + "_overlayed.pdf");
return PdfUtils.bytesToWebResponse(result, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_overlayed.pdf");
} catch (IOException e) {
logger.error("Failed to add image to PDF", e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

View file

@ -50,7 +50,7 @@ public class RearrangePagesPDFController {
document.removePage(pageIndex);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_removed_pages.pdf");
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_pages.pdf");
}
@ -111,7 +111,7 @@ public class RearrangePagesPDFController {
document.addPage(page);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_rearranged.pdf");
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rearranged.pdf");
} catch (IOException e) {
logger.error("Failed rearranging documents", e);

View file

@ -41,7 +41,7 @@ public class RotationController {
page.setRotation(page.getRotation() + angle);
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_rotated.pdf");
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_rotated.pdf");
}

View file

@ -43,7 +43,7 @@ public class ConvertImgPDFController {
byte[] bytes = PdfUtils.convertToPdf(file.getInputStream());
logger.info("File {} successfully converted to pdf", file.getOriginalFilename());
return PdfUtils.bytesToWebResponse(bytes, file.getName() + "_coverted.pdf");
return PdfUtils.bytesToWebResponse(bytes, file.getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_coverted.pdf");
}
@PostMapping("/pdf-to-img")

View file

@ -0,0 +1,81 @@
package stirling.software.SPDF.controller.converters;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Color;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
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.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
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 ConvertXlsxController {
@GetMapping("/xlsx-to-pdf")
public String cinvertToPDF(Model model) {
model.addAttribute("currentPage", "xlsx-to-pdf");
return "convert/xlsx-to-pdf";
}
@PostMapping("/xlsx-to-pdf")
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();
PdfWriter.getInstance(document, outputStream);
document.open();
// 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()));
// 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));
table.addCell(pdfCell);
}
}
document.add(table);
}
// 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
}
}

View file

@ -7,6 +7,7 @@ import java.util.Calendar;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.springframework.http.ResponseEntity;
@ -49,7 +50,7 @@ public class MetadataController {
// Load the PDF file into a PDDocument
PDDocument document = PDDocument.load(pdfFile.getBytes());
// Get the document information from the PDF
PDDocumentInformation info = document.getDocumentInformation();
@ -69,6 +70,9 @@ public class MetadataController {
for (String key : info.getMetadataKeys()) {
info.setCustomMetadataValue(key, null);
}
// Remove metadata from the PDF history
document.getDocumentCatalog().getCOSObject().removeItem(COSName.getPDFName("Metadata"));
document.getDocumentCatalog().getCOSObject().removeItem(COSName.getPDFName("PieceInfo"));
author = null;
creationDate = null;
creator = null;
@ -126,7 +130,7 @@ public class MetadataController {
info.setTrapped(trapped);
document.setDocumentInformation(info);
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_metadata.pdf");
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_metadata.pdf");
}

View file

@ -44,7 +44,7 @@ public class PasswordController {
public ResponseEntity<byte[]> compressPDF(@RequestParam("fileInput") MultipartFile fileInput, @RequestParam(name = "password") String password) throws IOException {
PDDocument document = PDDocument.load(fileInput.getBytes(), password);
document.setAllSecurityToBeRemoved(true);
return PdfUtils.pdfDocToWebResponse(document, fileInput.getName() + "_password_removed.pdf");
return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_password_removed.pdf");
}
@PostMapping("/add-password")
@ -75,7 +75,7 @@ public class PasswordController {
document.protect(spp);
return PdfUtils.pdfDocToWebResponse(document, fileInput.getName() + "_passworded.pdf");
return PdfUtils.pdfDocToWebResponse(document, fileInput.getOriginalFilename().replaceFirst("[.][^.]+$", "")+ "_passworded.pdf");
}
}

View file

@ -69,6 +69,6 @@ public class WatermarkController {
// Close the content stream
contentStream.close();
}
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getName() + "_watermarked.pdf");
return PdfUtils.pdfDocToWebResponse(document, pdfFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_watermarked.pdf");
}
}

View file

@ -0,0 +1,32 @@
package stirling.software.SPDF.utils;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.springframework.ui.Model;
import org.springframework.web.servlet.ModelAndView;
public class ErrorUtils {
public static Model exceptionToModel(Model model, Exception ex) {
StringWriter sw = new StringWriter();
ex.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
model.addAttribute("errorMessage", ex.getMessage());
model.addAttribute("stackTrace", stackTrace);
return model;
}
public static ModelAndView exceptionToModelView(Model model, Exception ex) {
StringWriter sw = new StringWriter();
ex.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("errorMessage", ex.getMessage());
modelAndView.addObject("stackTrace", stackTrace);
return modelAndView;
}
}

View file

@ -29,6 +29,9 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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 {
@ -157,6 +160,18 @@ public class PdfUtils {
}
}
public static ResponseEntity<byte[]> iTextDocToWebResponse(Document document, String docName) throws IOException, DocumentException {
// Close the document
document.close();
// Open Byte Array and save document to it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter.getInstance(document, baos).close();
return PdfUtils.boasToWebResponse(baos, docName);
}
public static ResponseEntity<byte[]> pdfDocToWebResponse(PdfDocument document, String docName) throws IOException {
// Open Byte Array and save document to it

View file

@ -9,3 +9,9 @@ spring.servlet.multipart.max-file-size=1000MB
spring.servlet.multipart.max-request-size=1000MB
server.forward-headers-strategy=NATIVE
server.error.path=/error
server.error.whitelabel.enabled=false
server.error.include-stacktrace=always
server.error.include-exception=true
server.error.include-message=always

View file

@ -54,6 +54,9 @@ home.addImage.desc=إضافة صورة إلى موقع معين في PDF (الع
home.watermark.title=إضافة علامة مائية
home.watermark.desc=أضف علامة مائية مخصصة إلى مستند PDF الخاص بك.
home.remove-watermark.title = \u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
home.remove-watermark.desc = \u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0627\u062A \u0627\u0644\u0645\u0627\u0626\u064A\u0629 \u0645\u0646 \u0645\u0633\u062A\u0646\u062F PDF \u0627\u0644\u062E\u0627\u0635 \u0628\u0643.
home.permissions.title=تغيير الأذونات
home.permissions.desc=قم بتغيير أذونات مستند PDF الخاص بك
@ -72,6 +75,9 @@ home.compressPdfs.desc=ضغط ملفات PDF لتقليل حجم الملف.
home.changeMetadata.title = \u062A\u063A\u064A\u064A\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0648\u0635\u0641\u064A\u0629
home.changeMetadata.desc = \u062A\u063A\u064A\u064A\u0631 / \u0625\u0632\u0627\u0644\u0629 / \u0625\u0636\u0627\u0641\u0629 \u0628\u064A\u0627\u0646\u0627\u062A \u0623\u0648\u0644\u064A\u0629 \u0645\u0646 \u0645\u0633\u062A\u0646\u062F PDF
home.xlsToPdf.title = \u062A\u062D\u0648\u064A\u0644 Excel (Xls) \u0625\u0644\u0649 PDF
home.xlsToPdf.desc = \u0642\u0645 \u0628\u062A\u062D\u0648\u064A\u0644 \u0645\u0633\u062A\u0646\u062F Excel (xls \u060C xlsx) \u0625\u0644\u0649 PDF.
#Add image
addImage.title=إضافة صورة
addImage.header=إضافة صورة إلى PDF (العمل قيد التقدم)
@ -172,6 +178,12 @@ watermark.selectText.5=widthSpacer (مسافة بين كل علامة مائية
watermark.selectText.6=heightSpacer (مسافة بين كل علامة مائية عموديًا):
watermark.submit=إضافة علامة مائية
#remove-watermark
remove-watermark.title = \u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
remove-watermark.header = \u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
remove-watermark.selectText.1 = \u062D\u062F\u062F PDF \u0644\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629 \u0645\u0646:
remove-watermark.selectText.2 = \u0646\u0635 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629:
remove-watermark.submit = \u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0645\u0627\u0626\u064A\u0629
#Change permissions
permissions.title=تغيير الأذونات
@ -213,3 +225,10 @@ changeMetadata.trapped = \u0645\u062D\u0627\u0635\u0631:
changeMetadata.selectText.4 = \u0628\u064A\u0627\u0646\u0627\u062A \u0648\u0635\u0641\u064A\u0629 \u0623\u062E\u0631\u0649:
changeMetadata.selectText.5 = \u0625\u0636\u0627\u0641\u0629 \u0625\u062F\u062E\u0627\u0644 \u0628\u064A\u0627\u0646\u0627\u062A \u0623\u0648\u0644\u064A\u0629 \u0645\u062E\u0635\u0635
changeMetadata.submit = \u062A\u063A\u064A\u064A\u0631
xlsToPdf.title = \u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
xlsToPdf.header = \u062A\u062D\u0648\u064A\u0644 Excel \u0625\u0644\u0649 PDF
xlsToPdf.selectText.1 = \u062D\u062F\u062F \u0648\u0631\u0642\u0629 \u0625\u0643\u0633\u0644 XLS \u0623\u0648 XLSX \u0644\u0644\u062A\u062D\u0648\u064A\u0644
xlsToPdf.convert = \u062A\u062D\u0648\u064A\u0644

View file

@ -50,6 +50,9 @@ home.addImage.desc=Fügt ein Bild an eine bestimmte Stelle im PDF ein (Work in p
home.watermark.title=Wasserzeichen hinzufügen
home.watermark.desc=Fügen Sie ein eigenes Wasserzeichen zu Ihrem PDF hinzu.
home.remove-watermark.title=Wasserzeichen entfernen
home.remove-watermark.desc=Wasserzeichen aus Ihrem PDF-Dokument entfernen.
home.permissions.title=Berechtigungen ändern
home.permissions.desc=Die Berechtigungen für Ihr PDF-Dokument verändern.
@ -68,6 +71,9 @@ home.compressPdfs.desc=PDF komprimieren um die Dateigröße zu reduzieren.
home.changeMetadata.title=Metadaten ändern
home.changeMetadata.desc=Ändern/Entfernen/Hinzufügen von Metadaten aus einem PDF-Dokument
home.xlsToPdf.title=Excel (Xls) in PDF
home.xlsToPdf.desc=Konvertiere ein Excel-Dokument (xls, xlsx) in PDF.
#Add image
addImage.title=Bild hinzufügen
addImage.header=Ein Bild einfügen (Work in progress)
@ -88,7 +94,6 @@ merge.submit=Zusammenführen
#pdfOrganiser
pdfOrganiser.title=Seiten anordnen
pdfOrganiser.header=PDF Seitenorganisation
#pdfOrganiser.pagesToOrganize=Seitenanordnung (geben Sie eine Kommagetrennte Liste der Seitenzahlen an): # may have forgotten to add this as a translation option?
pdfOrganiser.submit=Seiten anordnen
@ -169,6 +174,12 @@ watermark.selectText.5=breiteSpacer (horizontaler Abstand zwischen den einzelnen
watermark.selectText.6=höheSpacer (vertikaler Abstand zwischen den einzelnen Wasserzeichen):
watermark.submit=Wasserzeichen hinzufügen
#remove-watermark
remove-watermark.title=Wasserzeichen entfernen
remove-watermark.header=Wasserzeichen entfernen
remove-watermark.selectText.1=PDF auswählen, um Wasserzeichen zu entfernen von:
remove-watermark.selectText.2=Wasserzeichentext:
remove-watermark.submit=Wasserzeichen entfernen
#Change permissions
permissions.title=Berechtigungen ändern
@ -214,7 +225,10 @@ changeMetadata.submit=
xlsToPdf.title=Excel in PDF
xlsToPdf.header=Excel in PDF
xlsToPdf.selectText.1=XLS- oder XLSX-Excel-Tabelle zum Konvertieren auswählen
xlsToPdf.convert=konvertieren

View file

@ -35,7 +35,7 @@ home.rotate.title=Rotate PDFs
home.rotate.desc=Easily rotate your PDFs.
home.imageToPdf.title=Image to PDF
home.imageToPdf.desc=Convert a images (PNG, JPEG, GIF) to PDF.
home.imageToPdf.desc=Convert a image (PNG, JPEG, GIF) to PDF.
home.pdfToImage.title=PDF to Image
home.pdfToImage.desc=Convert a PDF to a image. (PNG, JPEG, GIF)
@ -49,6 +49,9 @@ home.addImage.desc=Adds a image onto a set location on the PDF (Work in progress
home.watermark.title=Add Watermark
home.watermark.desc=Add a custom watermark to your PDF document.
home.remove-watermark.title=Remove Watermark
home.remove-watermark.desc=Remove watermarks from your PDF document.
home.permissions.title=Change Permissions
home.permissions.desc=Change the permissions of your PDF document
@ -67,6 +70,8 @@ home.compressPdfs.desc=Compress PDFs to reduce their file size.
home.changeMetadata.title=Change Metadata
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
home.xlsToPdf.title=Excel (Xls) to PDF
home.xlsToPdf.desc=Convert a Excel document (xls, xlsx) to PDF.
#Add image
addImage.title=Add Image
@ -168,6 +173,12 @@ watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
watermark.submit=Add Watermark
#remove-watermark
remove-watermark.title=Remove Watermark
remove-watermark.header=Remove Watermark
remove-watermark.selectText.1=Select PDF to remove watermark from:
remove-watermark.selectText.2=Watermark Text:
remove-watermark.submit=Remove Watermark
#Change permissions
permissions.title=Change Permissions
@ -210,7 +221,10 @@ changeMetadata.selectText.4=Other Metadata:
changeMetadata.selectText.5=Add Custom Metadata Entry
changeMetadata.submit=Change
xlsToPdf.title=Excel to PDF
xlsToPdf.header=Excel to PDF
xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert
xlsToPdf.convert=convert

View file

@ -49,6 +49,9 @@ home.addImage.desc=Adds a image onto a set location on the PDF (Work in progress
home.watermark.title=Add Watermark
home.watermark.desc=Add a custom watermark to your PDF document.
home.remove-watermark.title=Remove Watermark
home.remove-watermark.desc=Remove watermarks from your PDF document.
home.permissions.title=Change Permissions
home.permissions.desc=Change the permissions of your PDF document
@ -67,6 +70,9 @@ home.compressPdfs.desc=Compress PDFs to reduce their file size.
home.changeMetadata.title=Change Metadata
home.changeMetadata.desc=Change/Remove/Add metadata from a PDF document
home.xlsToPdf.title=Excel (Xls) to PDF
home.xlsToPdf.desc=Convert a Excel document (xls, xlsx) to PDF.
#Add image
addImage.title=Add Image
@ -169,6 +175,12 @@ watermark.selectText.5=widthSpacer (Space between each watermark horizontally):
watermark.selectText.6=heightSpacer (Space between each watermark vertically):
watermark.submit=Add Watermark
#remove-watermark
remove-watermark.title=Remove Watermark
remove-watermark.header=Remove Watermark
remove-watermark.selectText.1=Select PDF to remove watermark from:
remove-watermark.selectText.2=Watermark Text:
remove-watermark.submit=Remove Watermark
#Change permissions
permissions.title=Change Permissions
@ -213,8 +225,10 @@ changeMetadata.submit=Change
xlsToPdf.title=Excel to PDF
xlsToPdf.header=Excel to PDF
xlsToPdf.selectText.1=Select XLS or XLSX Excel sheet to convert
xlsToPdf.convert=convert

View file

@ -13,8 +13,8 @@ multiPdfPrompt=Choisir des PDF (2+)
multiPdfDropPrompt=Sélectionnez (ou glissez-déposez) tous les PDF dont vous avez besoin
imgPrompt=Choisir une image
genericSubmit=Soumettre
processTimeWarning=Attention : ce processus peut prendre jusqu'à une minute en fonction de la taille du fichier
pageOrderPrompt=Ordre des pages (Entrez une liste de numéros de page séparés par des virgules) :
processTimeWarning=AttentionÂ: ce processus peut prendre jusqu'à une minute en fonction de la taille du fichier
pageOrderPrompt=Ordre des pages (Entrez une liste de numéros de page séparés par des virgules)Â:
goToPage=Aller
true=Vrai
false=Faux
@ -54,6 +54,9 @@ home.addImage.desc=Ajoute une image à un emplacement défini sur le PDF (Travai
home.watermark.title=Ajouter un filigrane
home.watermark.desc=Ajoutez un filigrane personnalisé à votre document PDF.
home.remove-watermark.title=Supprimer le filigrane
home.remove-watermark.desc=Supprimez les filigranes de votre document PDF.
home.permissions.title=Modifier les autorisations
home.permissions.desc=Modifier les permissions de votre document PDF
@ -72,6 +75,9 @@ home.compressPdfs.desc=Compressez les PDF pour réduire leur taille de fichier.
home.changeMetadata.title=Modifier les métadonnées
home.changeMetadata.desc=Modifier/Supprimer/Ajouter des métadonnées d'un document PDF
home.xlsToPdf.title=Excel (Xls) en PDF
home.xlsToPdf.desc=Convertir un document Excel (xls, xlsx) en PDF.
#Add image
addImage.title=Ajouter une image
@ -99,7 +105,7 @@ pdfOrganiser.submit=Réorganiser les pages
#pageRemover
pageRemover.title=Suppresseur de pages
pageRemover.header=Outil de suppression de pages PDF
pageRemover.pagesToDelete=Pages à supprimer (Entrez une liste de numéros de page séparés par des virgules) :
pageRemover.pagesToDelete=Pages à supprimer (Entrez une liste de numéros de page séparés par des virgules)Â:
pageRemover.submit=Supprimer des pages
#rotate
@ -115,14 +121,14 @@ rotate.submit=Rotation
split.title=Fractionner le PDF
split.header=Diviser le PDF
split.desc.1=Les numéros que vous sélectionnez sont le numéro de page sur lequel vous souhaitez faire un fractionnement
split.desc.2=Ainsi, la sélection de 1,3,7-8 diviserait un document de 10 pages en 6 PDF distincts avec :
split.desc.3=Document #1 : Page 1
split.desc.4=Document #2 : Pages 2 et 3
split.desc.5=Document #3 : Pages 4, 5 et 6
split.desc.6=Document #4 : Page 7
split.desc.7=Document #5 : Page 8
split.desc.8=Document #6 : Pages 9 et 10
split.splitPages=Entrez les pages sur lesquelles fractionner :
split.desc.2=Ainsi, la sélection de 1,3,7-8 diviserait un document de 10 pages en 6 PDF distincts avecÂ:
split.desc.3=Document #1Â: Page 1
split.desc.4=Document #2Â: Pages 2 et 3
split.desc.5=Document #3Â: Pages 4, 5 et 6
split.desc.6=Document #4Â: Page 7
split.desc.7=Document #5Â: Page 8
split.desc.8=Document #6Â: Pages 9 et 10
split.splitPages=Entrez les pages sur lesquelles fractionnerÂ:
split.submit=Diviser
@ -165,14 +171,20 @@ addPassword.submit=Crypter
#watermark
watermark.title=Ajouter un filigrane
watermark.header=Ajouter un filigrane
watermark.selectText.1=Sélectionnez le PDF auquel ajouter un filigrane :
watermark.selectText.2=Texte du filigrane :
watermark.selectText.3=Taille de la police :
watermark.selectText.4=Rotation (0-360) :
watermark.selectText.5=widthSpacer (Espace entre chaque filigrane horizontalement) :
watermark.selectText.6=heightSpacer (Espace entre chaque filigrane verticalement) :
watermark.selectText.1=Sélectionnez le PDF auquel ajouter un filigraneÂ:
watermark.selectText.2=Texte du filigraneÂ:
watermark.selectText.3=Taille de la policeÂ:
watermark.selectText.4=Rotation (0-360)Â:
watermark.selectText.5=widthSpacer (Espace entre chaque filigrane horizontalement)Â:
watermark.selectText.6=heightSpacer (Espace entre chaque filigrane verticalement)Â:
watermark.submit=Ajouter un filigrane
#remove-watermark
remove-watermark.title=Supprimer le filigrane
remove-watermark.header=Supprimer le filigrane
remove-watermark.selectText.1=Sélectionnez le PDF pour supprimer le filigrane:
remove-watermark.selectText.2=Texte du filigrane:
remove-watermark.submit=Supprimer le filigrane
#Change permissions
permissions.title=Modifier les autorisations
@ -214,3 +226,10 @@ changeMetadata.trapped=Pi
changeMetadata.selectText.4=Autres métadonnées:
changeMetadata.selectText.5=Ajouter une entrée de métadonnées personnalisées
changeMetadata.submit=Modifier
xlsToPdf.title=Excel vers PDF
xlsToPdf.header=Excel en PDF
xlsToPdf.selectText.1=Sélectionnez une feuille Excel XLS ou XLSX à convertir
xlsToPdf.convert=convertir

View file

@ -1,16 +1,16 @@
/* Dark Mode Styles */
body {
background-color: #333;
color: #fff;
background-color: #333 !important;
color: #fff !important;
}
.dark-card {
background-color: #333 !important;
color: white;
color: white !important;
}
.jumbotron {
background-color: #222; /* or any other dark color */
color: #fff; /* or any other light color */
color: #fff !important; /* or any other light color */
}
.list-group {
@ -20,4 +20,7 @@ body {
.list-group-item {
background-color: #222 !important;
color: fff !important;
}
#support-section {
background-color: #444 !important;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,35 @@
<!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=#{xlsToPdf.title})}"></th:block>
<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="#{xlsToPdf.header}"></h2>
<form method="post" enctype="multipart/form-data" th:action="@{xlsx-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="#{xlsToPdf.selectText.1}"></label>
</div>
<br> <br>
<button type="submit" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
</form>
<th:block th:insert="~{fragments/common :: filelist}"></th:block>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body>
</html>

View file

@ -0,0 +1,131 @@
<!DOCTYPE html>
<html th:lang="${#locale.language}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Error! :(</title>
<th:block th:insert="~{fragments/common :: head(title='')}"></th:block>
<style>
h1 {
text-align: center;
margin-top: 10%;
}
p {
text-align: center;
margin-top: 2em;
}
.button:hover {
background-color: #005b7f;
}
.features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr));
gap: 25px 30px;
}
.feature-card {
border: 1px solid rgba(0, 0, 0, .125);
border-radius: 0.25rem;
padding: 1.25rem;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.feature-card .card-text {
flex: 1;
}
#support-section {
background-color: #f9f9f9;
padding: 4rem;
margin-top: 1rem;
text-align: center;
}
#support-section h1 {
margin-top: 0;
}
#support-section p {
margin-top: 0;
}
#button-group {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
#github-button, #discord-button {
display: inline-block;
padding: 1rem 2rem;
margin: 1rem;
background-color: #008CBA;
color: #fff;
font-size: 1.2rem;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
}
#github-button:hover, #discord-button:hover, #home-button:hover {
background-color: #005b7f;
}
#home-button {
display: block;
width: 200px;
height: 50px;
margin: 2em auto;
background-color: #008CBA;
color: white;
text-align: center;
line-height: 50px;
text-decoration: none;
font-weight: bold;
border-radius: 25px;
transition: all 0.3s ease-in-out;
}
</style>
</head>
<body>
<div id="page-container">
<div id="content-wrap">
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
<div class="container">
<div id="support-section">
<h1 class="display-2">Oops!</h1>
<p class="lead" th:if="${param.status == '404'}">We can't seem to find the page you're looking for.</p>
<p class="lead" th:unless="${param.status == '404'}">Something went wrong</p>
<br>
<h2>Need help / Found a issue?</h2>
<p>If you're still having trouble, don't hesitate to reach out to us for help. You can submit a ticket on our GitHub page or contact us through Discord:</p>
<div id="button-group">
<a href="https://github.com/Frooodle/Stirling-PDF/issues" id="github-button" target="_blank">Submit a ticket on GitHub</a>
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank">Join our Discord server</a>
</div>
<a href="/" id="home-button">Go back to homepage</a>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body>
</html>

View file

@ -0,0 +1,74 @@
<th:block th:fragment="errorBanner">
<style>
#github-button,
#discord-button {
display: inline-block;
padding: 1rem 2rem;
background-color: #008CBA;
color: #fff;
text-align: center;
text-decoration: none;
border-radius: 3rem;
transition: all 0.3s ease-in-out;
}
#github-button:hover,
#discord-button:hover {
background-color: #005b7f;
}
</style>
<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>
<button type="button" class="btn btn-danger" th:if="${trace}" onclick="toggletrace()">Show Stack Trace</button>
<button type="button" class="btn btn-secondary" th:if="${trace}" onclick="copytrace()">Copy Stack Trace</button>
<button type="button" class="close" data-dismiss="alert" aria-label="Close" onclick="dismissError()">
<span aria-hidden="true">&times;</span>
</button>
<!-- Stack trace section -->
<div id="trace" th:if="${trace}" style="max-height: 0; overflow: hidden;">
<div style="background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 3px; padding: 10px; margin-top: 5px;">
<pre id="traceContent" th:text="${trace}"></pre>
</div>
<!-- Buttons to submit a ticket on GitHub and join Discord server -->
<a href="https://github.com/Frooodle/Stirling-PDF/issues" id="github-button" target="_blank">Submit a ticket on GitHub</a>
<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";
}
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 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";
}
</script>
</th:block>

View file

@ -30,15 +30,16 @@
<a class="nav-link" href="#" th:href="@{rotate-pdf}" th:classappend="${currentPage}=='rotate-pdf' ? 'active' : ''" th:text="#{home.rotate.title}"></a>
</li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' ? 'active' : ''">
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='xlsx-to-pdf' ? 'active' : ''">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" th:text="#{navbar.convert}"></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#" th:href="@{pdf-to-img}" th:classappend="${currentPage}=='pdf-to-img' ? 'active' : ''" th:text="#{home.pdfToImage.title}"></a>
<a class="dropdown-item" href="#" th:href="@{img-to-pdf}" th:classappend="${currentPage}=='img-to-pdf' ? 'active' : ''" th:text="#{home.imageToPdf.title}"></a>
<a class="dropdown-item" href="#" th:href="@{xlsx-to-pdf}" th:classappend="${currentPage}=='xlsx-to-pdf' ? 'active' : ''" th:text="#{home.xlsToPdf.title}"></a>
</div>
</li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='add-password' OR ${currentPage}=='remove-password' OR ${currentPage}=='change-permissions' OR ${currentPage}=='add-watermark' ? 'active' : ''">
<li class="nav-item dropdown" th:classappend="${currentPage}=='add-password' OR ${currentPage}=='remove-password' OR ${currentPage}=='change-permissions' OR ${currentPage}=='add-watermark' OR ${currentPage}=='remove-watermark' ? 'active' : ''">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" th:text="#{navbar.security}"></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#" th:href="@{add-password}" th:classappend="${currentPage}=='add-password' ? 'active' : ''" th:text="#{home.addPassword.title}"></a>
@ -84,7 +85,7 @@
</li>
</ul>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Get the dropdown items
@ -128,4 +129,5 @@
</div>
</div>
</nav>
<div th:insert="~{fragments/errorBanner.html :: errorBanner}"></div>
</div>

View file

@ -50,7 +50,7 @@
<div th:replace="~{fragments/card :: card(cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.xlsToPdf.title}, cardText=#{home.xlsToPdf.desc}, cardLink='xlsx-to-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password')}"></div>
@ -58,6 +58,9 @@
<div th:replace="~{fragments/card :: card(cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata')}"></div>
<div th:replace="~{fragments/card :: card(cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions')}"></div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>

View file

@ -0,0 +1,36 @@
<!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=#{remove-watermark.title})}"></th:block>
<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="#{remove-watermark.header}"></h2>
<form method="post" enctype="multipart/form-data" action="remove-text">
<div class="form-group">
<label th:text="#{remove-watermark.selectText.1}"></label>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
</div>
<div class="form-group">
<label for="watermarkText" th:text="#{remove-watermark.selectText.2}"></label>
<input type="text" id="watermarkText" name="watermarkText" class="form-control" placeholder="Stirling-PDF" required />
</div>
<div class="form-group text-center">
<input type="submit" th:value="#{remove-watermark.submit}" class="btn btn-primary" />
</div>
</form>
</div>
</div>
</div>
</div>
<div th:insert="~{fragments/footer.html :: footer}"></div>
</div>
</body>
</html>