-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #221 from LaserKaspar/main
Scale Pages
- Loading branch information
Showing
8 changed files
with
149 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
src/main/java/stirling/software/SPDF/controller/api/other/ScalePagesController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package stirling.software.SPDF.controller.api.other; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import com.itextpdf.kernel.geom.PageSize; | ||
import com.itextpdf.kernel.geom.Rectangle; | ||
import com.itextpdf.kernel.pdf.PdfDocument; | ||
import com.itextpdf.kernel.pdf.PdfPage; | ||
import com.itextpdf.kernel.pdf.PdfReader; | ||
import com.itextpdf.kernel.pdf.PdfWriter; | ||
import com.itextpdf.kernel.pdf.canvas.PdfCanvas; | ||
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
|
||
@RestController | ||
public class ScalePagesController { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(ScalePagesController.class); | ||
|
||
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data") | ||
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file.") | ||
public ResponseEntity<byte[]> mergeMultiplePagesIntoOne( | ||
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file, | ||
@Parameter(description = "The scale of pages in the output PDF. Acceptable values are A4.", required = true, schema = @Schema(type = "String", allowableValues = { "A4" })) @RequestParam("pageSize") String targetPageSize, | ||
@Parameter(description = "The scale of the content on the pages of the output PDF. Acceptable values are floats.", required = true, schema = @Schema(type = "float")) @RequestParam("scaleFactor") float scaleFactor) | ||
throws IOException { | ||
|
||
if (!targetPageSize.equals("A4")) { | ||
throw new IllegalArgumentException("pageSize must be A4"); | ||
} | ||
|
||
byte[] bytes = file.getBytes(); | ||
PdfReader reader = new PdfReader(new ByteArrayInputStream(bytes)); | ||
PdfDocument pdfDoc = new PdfDocument(reader); | ||
|
||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
PdfWriter writer = new PdfWriter(baos); | ||
PdfDocument outputPdf = new PdfDocument(writer); | ||
|
||
PageSize pageSize = new PageSize(PageSize.A4); // TODO: This (and all other PageSize.A4) need to be dynamically changed in response to targetPageSize | ||
|
||
int totalPages = pdfDoc.getNumberOfPages(); | ||
|
||
for (int i = 1; i <= totalPages; i++) { | ||
PdfPage page = outputPdf.addNewPage(pageSize); | ||
PdfCanvas pdfCanvas = new PdfCanvas(page); | ||
|
||
// Get the page and calculate scaling factors | ||
Rectangle rect = pdfDoc.getPage(i).getPageSize(); | ||
float scaleWidth = PageSize.A4.getWidth() / rect.getWidth(); | ||
float scaleHeight = PageSize.A4.getHeight() / rect.getHeight(); | ||
float scale = Math.min(scaleWidth, scaleHeight) * scaleFactor; | ||
System.out.println("Scale: " + scale); | ||
|
||
PdfFormXObject formXObject = pdfDoc.getPage(i).copyAsFormXObject(outputPdf); | ||
float x = (PageSize.A4.getWidth() - rect.getWidth() * scale) / 2; // Center Page | ||
float y = (PageSize.A4.getHeight() - rect.getHeight() * scale) / 2; | ||
|
||
// Save the graphics state, apply the transformations, add the object, and then | ||
// restore the graphics state | ||
pdfCanvas.saveState(); | ||
pdfCanvas.concatMatrix(scale, 0, 0, scale, x, y); | ||
pdfCanvas.addXObject(formXObject, 0, 0); | ||
pdfCanvas.restoreState(); | ||
} | ||
|
||
outputPdf.close(); | ||
byte[] pdfContent = baos.toByteArray(); | ||
pdfDoc.close(); | ||
return ResponseEntity.ok() | ||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_modified.pdf\"") | ||
.body(pdfContent); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<!DOCTYPE html> | ||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org"> | ||
|
||
|
||
<th:block th:insert="~{fragments/common :: head(title=#{pageLayout.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="#{scalePages.header}"></h2> | ||
<form id="scalePagesFrom" th:action="@{scale-pages}" method="post" enctype="multipart/form-data"> | ||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> | ||
<div class="form-group"> | ||
<label for="pageSize" th:text="#{scalePages.pageSize}"></label> | ||
<select id="pageSize" name="pageSize" required> | ||
<option value="A4">A4</option> | ||
</select> | ||
</div> | ||
<div class="form-group"> | ||
<label for="scaleFactor" th:text="#{scalePages.scaleFactor}"></label> | ||
<input type="number" id="scaleFactor" name="scaleFactor" step="any" min="0" value="1"> | ||
</div> | ||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{scalePages.submit}"></button> | ||
</form> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div th:insert="~{fragments/footer.html :: footer}"></div> | ||
</div> | ||
</body> | ||
|
||
</html> |