diff --git a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java index 43180753..303de37f 100644 --- a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java @@ -137,6 +137,7 @@ public class EndpointConfiguration { addEndpointToGroup("Other", "auto-rename"); addEndpointToGroup("Other", "get-info-on-pdf"); addEndpointToGroup("Other", "show-javascript"); + addEndpointToGroup("Other", "remove-image-pdf"); // CLI addEndpointToGroup("CLI", "compress-pdf"); @@ -221,6 +222,7 @@ public class EndpointConfiguration { addEndpointToGroup("Java", "split-pdf-by-sections"); addEndpointToGroup("Java", REMOVE_BLANKS); addEndpointToGroup("Java", "pdf-to-text"); + addEndpointToGroup("Java", "remove-image-pdf"); // Javascript addEndpointToGroup("Javascript", "pdf-organizer"); diff --git a/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java b/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java new file mode 100644 index 00000000..a3b9e93c --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/PdfImageRemovalController.java @@ -0,0 +1,82 @@ +package stirling.software.SPDF.controller.api; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import io.swagger.v3.oas.annotations.Operation; + +import stirling.software.SPDF.model.api.PDFFile; +import stirling.software.SPDF.service.PdfImageRemovalService; +import stirling.software.SPDF.utils.WebResponseUtils; + + +/** + * Controller class for handling PDF image removal requests. + * Provides an endpoint to remove images from a PDF file to reduce its size. + */ +@RestController +@RequestMapping("/api/v1/general") +public class PdfImageRemovalController { + + // Service for removing images from PDFs + @Autowired private PdfImageRemovalService pdfImageRemovalService; + + /** + * Constructor for dependency injection of PdfImageRemovalService. + * + * @param pdfImageRemovalService The service used for removing images from PDFs. + */ + public PdfImageRemovalController(PdfImageRemovalService pdfImageRemovalService) { + this.pdfImageRemovalService = pdfImageRemovalService; + } + + /** + * Endpoint to remove images from a PDF file. + * + * This method processes the uploaded PDF file, removes all images, and returns + * the modified PDF file with a new name indicating that images were removed. + * + * @param file The PDF file with images to be removed. + * @return ResponseEntity containing the modified PDF file as byte array with appropriate content type and filename. + * @throws IOException If an error occurs while processing the PDF file. + */ + @PostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf") + @Operation( + summary = "Remove images from file to reduce the file size.", + description = + "This endpoint remove images from file to reduce the file size.Input:PDF Output:PDF Type:MISO") + public ResponseEntity removeImages(@ModelAttribute PDFFile file) throws IOException { + + MultipartFile pdf = file.getFileInput(); + + // Convert the MultipartFile to a byte array + byte[] pdfBytes = pdf.getBytes(); + + // Load the PDF document from the byte array + PDDocument document = Loader.loadPDF(pdfBytes); + + // Remove images from the PDF document using the service + PDDocument modifiedDocument = pdfImageRemovalService.removeImagesFromPdf(document); + + // Create a ByteArrayOutputStream to hold the modified PDF data + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + // Save the modified PDF document to the output stream + modifiedDocument.save(outputStream); + modifiedDocument.close(); + + // Generate a new filename for the modified PDF + String mergedFileName = + pdf.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_removed_images.pdf"; + + // Convert the byte array to a web response and return it + return WebResponseUtils.bytesToWebResponse(outputStream.toByteArray(), mergedFileName); + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java index bb730dc9..93ad5f34 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java @@ -310,4 +310,11 @@ public class GeneralWebController { model.addAttribute("currentPage", "auto-split-pdf"); return "auto-split-pdf"; } + + @GetMapping("/remove-image-pdf") + @Hidden + public String removeImagePdfForm(Model model) { + model.addAttribute("currentPage", "remove-image-pdf"); + return "remove-image-pdf"; + } } diff --git a/src/main/java/stirling/software/SPDF/service/PdfImageRemovalService.java b/src/main/java/stirling/software/SPDF/service/PdfImageRemovalService.java new file mode 100644 index 00000000..052d9977 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/service/PdfImageRemovalService.java @@ -0,0 +1,43 @@ +package stirling.software.SPDF.service; + +import java.io.IOException; + +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.PDXObject; +import org.springframework.stereotype.Service; + +/** + * Service class responsible for removing image objects from a PDF document. + */ +@Service +public class PdfImageRemovalService { + + /** + * Removes all image objects from the provided PDF document. + * + * This method iterates over each page in the document and removes any + * image XObjects found in the page's resources. + * + * @param document The PDF document from which images will be removed. + * @return The modified PDF document with images removed. + * @throws IOException If an error occurs while processing the PDF document. + */ + public PDDocument removeImagesFromPdf(PDDocument document) throws IOException { + // Iterate over each page in the PDF document + for (PDPage page : document.getPages()) { + PDResources resources = page.getResources(); + // Iterate over all XObject names in the page's resources + for (COSName name : resources.getXObjectNames()) { + // Check if the XObject is an image + if (resources.isImageXObject(name)) { + // Remove the image XObject by setting it to null + resources.put(name, (PDXObject) null); + } + } + } + return document; + } +} diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index f6f77624..e072dc64 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -461,6 +461,10 @@ home.BookToPDF.title=Book to PDF home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf +home.removeImagePdf.title=Remove image +home.removeImagePdf.desc=Remove image from PDF to reduce file size +removeImagePdf.tags=Remove Image,Page operations,Back end,server side + ########################### # # @@ -1125,3 +1129,10 @@ error.showStack=Show Stack Trace error.copyStack=Copy Stack Trace error.githubSubmit=GitHub - Submit a ticket error.discordSubmit=Discord - Submit Support post + + +#remove-image +removeImage.title=Remove image +removeImage.header=Remove image +removeImage.removeImage=Remove image +removeImage.submit=Remove image \ No newline at end of file diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index b90bef09..bd31c0b0 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -461,6 +461,10 @@ home.BookToPDF.title=Book to PDF home.BookToPDF.desc=Converts Books/Comics formats to PDF using calibre BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle +home.removeImagePdf.title=Remove image +home.removeImagePdf.desc=Remove image from PDF to reduce file size +removeImagePdf.tags=Remove Image,Page operations,Back end,server side + ########################### # # @@ -1125,3 +1129,10 @@ error.showStack=Show Stack Trace error.copyStack=Copy Stack Trace error.githubSubmit=GitHub - Submit a ticket error.discordSubmit=Discord - Submit Support post + + +#remove-image +removeImage.title=Remove image +removeImage.header=Remove image +removeImage.removeImage=Remove image +removeImage.submit=Remove image diff --git a/src/main/resources/static/css/removeImage.css b/src/main/resources/static/css/removeImage.css new file mode 100644 index 00000000..4f2be403 --- /dev/null +++ b/src/main/resources/static/css/removeImage.css @@ -0,0 +1,22 @@ +.filename { + flex-grow: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-right: 10px; +} + +.arrows { + flex-shrink: 0; + display: flex; + justify-content: flex-end; +} +.arrows .btn { + margin: 0 3px; +} + +.move-up span, +.move-down span { + font-weight: bold; + font-size: 1.2em; +} diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index 39bd8051..955fb3e6 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -195,6 +195,9 @@
+
+
diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index d2846a24..30c295a5 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -229,6 +229,9 @@
+
+
diff --git a/src/main/resources/templates/remove-image-pdf.html b/src/main/resources/templates/remove-image-pdf.html new file mode 100644 index 00000000..6849bd59 --- /dev/null +++ b/src/main/resources/templates/remove-image-pdf.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
+ +

+
+
+
+
+ remove_selection + +
+
+
+ +
+ +
+
+
+
+
+ +
+ +