feat(flatten): Add support for configuring rendering DPI in Flatten PDF feature (#4669)

# Description of Changes

Rendering on high DPI can needlessly increase the file size and
processing time, even when users would prefer smaller size, (with lesser
quality)

This PR adds support for configurable DPI, so that users can choose
their preferred balance between processing time/file size and quality.


**Backend logic and data model updates:**

* The `FlattenController` now processes an optional `renderDpi`
parameter from the request, using it to set the rendering DPI for each
page. It enforces minimum and maximum values based on system
configuration and ensures a sensible default if not provided.
* The `FlattenRequest` model has a new `renderDpi` field to carry the
requested DPI through the API and backend logic.

**User interface and documentation improvements:**

* The flatten form in `flatten.html` includes a new input field for DPI,
with validation and help text to guide users about its impact and usage.
* English resource messages have been updated to describe the new DPI
field and provide help text explaining its effects.

**UI:**
<img width="595" height="604" alt="image"
src="https://github.com/user-attachments/assets/f78a0401-0348-490b-920a-91475cab224b"
/>
**File size before after (100 DPI vs 500 DPI):**
<img width="493" height="141" alt="image"
src="https://github.com/user-attachments/assets/fe21bf79-a18f-4674-bbb5-c99b3d3bd7be"
/>
Sample used was originally 8 MB.

Sample used are attached here:


[image-doc-1.pdf](https://github.com/user-attachments/files/22889873/image-doc-1.pdf)

[image-doc-2.pdf](https://github.com/user-attachments/files/22889876/image-doc-2.pdf)

Strange stuff, I can personally _barely_ tell difference between 500 vs
100 DPI tbh, but the file size difference is very significant.


Closes: #4668

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
Balázs Szücs
2025-10-16 23:50:04 +02:00
committed by GitHub
parent dbf0a4fdf4
commit 3a6c0c7722
4 changed files with 43 additions and 9 deletions

View File

@@ -67,19 +67,32 @@ public class FlattenController {
PDFRenderer pdfRenderer = new PDFRenderer(document);
PDDocument newDocument =
pdfDocumentFactory.createNewDocumentBasedOnOldDocument(document);
int defaultRenderDpi = 100; // Default fallback
ApplicationProperties properties =
ApplicationContextProvider.getBean(ApplicationProperties.class);
Integer configuredMaxDpi = null;
if (properties != null && properties.getSystem() != null) {
configuredMaxDpi = properties.getSystem().getMaxDPI();
}
int maxDpi =
(configuredMaxDpi != null && configuredMaxDpi > 0)
? configuredMaxDpi
: defaultRenderDpi;
Integer requestedDpi = request.getRenderDpi();
int renderDpi = maxDpi;
if (requestedDpi != null) {
renderDpi = Math.min(requestedDpi, maxDpi);
renderDpi = Math.max(renderDpi, 72);
}
int numPages = document.getNumberOfPages();
for (int i = 0; i < numPages; i++) {
try {
BufferedImage image;
// Use global maximum DPI setting, fallback to 300 if not set
int renderDpi = 300; // Default fallback
ApplicationProperties properties =
ApplicationContextProvider.getBean(ApplicationProperties.class);
if (properties != null && properties.getSystem() != null) {
renderDpi = properties.getSystem().getMaxDPI();
}
try {
image = pdfRenderer.renderImageWithDPI(i, renderDpi, ImageType.RGB);
} catch (OutOfMemoryError e) {

View File

@@ -18,4 +18,10 @@ public class FlattenRequest extends PDFFile {
requiredMode = Schema.RequiredMode.REQUIRED,
defaultValue = "false")
private Boolean flattenOnlyForms;
@Schema(
description = "Optional DPI for page rendering when flattening the full document.",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
minimum = "72")
private Integer renderDpi;
}

View File

@@ -1259,6 +1259,8 @@ repair.submit=Repair
flatten.title=Flatten
flatten.header=Flatten PDF
flatten.flattenOnlyForms=Flatten only forms
flatten.renderDpi=Rendering DPI (optional, recommended 150 DPI):
flatten.renderDpi.help=Leave blank to use the system default. Higher DPI sharpens output but increases processing time and file size.
flatten.submit=Flatten

View File

@@ -24,7 +24,20 @@
<div class="form-check ms-3">
<input id="flattenOnlyForms" name="flattenOnlyForms" type="checkbox">
<label for="flattenOnlyForms" th:text="#{flatten.flattenOnlyForms}" ></label>
</div>
</div>
<div class="form-group ms-3 mt-2">
<label class="form-label" for="renderDpi" th:text="#{flatten.renderDpi}"></label>
<input
class="form-control"
id="renderDpi"
min="72"
name="renderDpi"
step="1"
th:attr="aria-describedby=${'renderDpiHelp'}"
type="number"
>
<small class="form-text text-muted" id="renderDpiHelp" th:text="#{flatten.renderDpi.help}"></small>
</div>
<br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{flatten.submit}"></button>
</form>