Issue1632 remove images (#1645)
* Implemented PdfImageRemovalService.java and PdfImageRemovalController.java. Image can be removed testing using Postman, but the file size doesn't change. * Fix removal logic in service file to decrease file size. * Implement "Remove Image" feature on the website Updated the front-end code to integrate the "Remove Image" feature. The new functionality is now fully operational on the website, allowing users to remove images as expected. * Add comments to PdfImageRemovalController and PdfImageRemovalService. * Change the google material icon in navbar, homepage and remove-image-pdf.html.
This commit is contained in:
parent
bc35745768
commit
d0bf385d69
10 changed files with 220 additions and 0 deletions
|
@ -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");
|
||||
|
|
|
@ -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<byte[]> 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);
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
22
src/main/resources/static/css/removeImage.css
Normal file
22
src/main/resources/static/css/removeImage.css
Normal file
|
@ -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;
|
||||
}
|
|
@ -195,6 +195,9 @@
|
|||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('get-info-on-pdf', 'info', 'home.getPdfInfo.title', 'home.getPdfInfo.desc', 'getPdfInfo.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-image-pdf','remove_selection', 'home.removeImagePdf.title', 'home.removeImagePdf.desc', 'removeImagePdf.tags', 'other')}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Advance menu items -->
|
||||
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
|
||||
|
|
|
@ -229,6 +229,9 @@
|
|||
<div
|
||||
th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-image-pdf', cardTitle=#{home.removeImagePdf.title}, cardText=#{home.removeImagePdf.desc}, cardLink='remove-image-pdf', toolIcon='remove_selection', tags=#{removeImagePdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
36
src/main/resources/templates/remove-image-pdf.html
Normal file
36
src/main/resources/templates/remove-image-pdf.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block
|
||||
th:insert="~{fragments/common :: head(title=#{removeImage.title}, header=#{removeImage.header})}"></th:block>
|
||||
<link rel="stylesheet" th:href="@{'/css/removeImage.css'}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon word">remove_selection</span>
|
||||
<span class="tool-header-text" th:text="#{removeImage.header}"></span>
|
||||
</div>
|
||||
<form action="api/v1/general/remove-image-pdf" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeImage.submit}"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue