feat: custom error handling when calling renderImageWithDPI, controllers to respect global DPI (#4407)

This commit is contained in:
Balázs Szücs
2025-09-18 14:43:21 +02:00
committed by GitHub
parent a438a15105
commit c684a51cf9
9 changed files with 237 additions and 9 deletions

View File

@@ -34,7 +34,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ApplicationContextProvider;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.TempFile;
import stirling.software.common.util.TempFileManager;
import stirling.software.common.util.WebResponseUtils;
@@ -128,7 +131,23 @@ public class AutoSplitPdfController {
pdfRenderer.setSubsamplingAllowed(true);
for (int page = 0; page < document.getNumberOfPages(); ++page) {
BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 150);
BufferedImage bim;
// Use global maximum DPI setting, fallback to 300 if not set
int renderDpi = 150; // Default fallback
ApplicationProperties properties =
ApplicationContextProvider.getBean(ApplicationProperties.class);
if (properties != null && properties.getSystem() != null) {
renderDpi = properties.getSystem().getMaxDPI();
}
try {
bim = pdfRenderer.renderImageWithDPI(page, renderDpi);
} catch (OutOfMemoryError e) {
throw ExceptionUtils.createOutOfMemoryDpiException(page + 1, renderDpi, e);
} catch (NegativeArraySizeException e) {
throw ExceptionUtils.createOutOfMemoryDpiException(page + 1, renderDpi, e);
}
String result = decodeQRCode(bim);
boolean isValidQrCode = VALID_QR_CONTENTS.contains(result);

View File

@@ -30,7 +30,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ApplicationContextProvider;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.PdfUtils;
import stirling.software.common.util.WebResponseUtils;
@@ -108,7 +111,25 @@ public class BlankPageController {
if (hasImages) {
log.info("page {} has image, running blank detection", pageIndex);
// Render image and save as temp file
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 30);
BufferedImage image;
// Use global maximum DPI setting
int renderDpi = 30; // Default fallback
ApplicationProperties properties =
ApplicationContextProvider.getBean(ApplicationProperties.class);
if (properties != null && properties.getSystem() != null) {
renderDpi = properties.getSystem().getMaxDPI();
}
try {
image = pdfRenderer.renderImageWithDPI(pageIndex, renderDpi);
} catch (OutOfMemoryError e) {
throw ExceptionUtils.createOutOfMemoryDpiException(
pageIndex + 1, renderDpi, e);
} catch (NegativeArraySizeException e) {
throw ExceptionUtils.createOutOfMemoryDpiException(
pageIndex + 1, renderDpi, e);
}
blank = isBlankImage(image, threshold, whitePercent, threshold);
}
}

View File

@@ -32,7 +32,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ApplicationContextProvider;
import stirling.software.common.util.CheckProgramInstall;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.GeneralUtils;
@@ -97,7 +99,23 @@ public class ExtractImageScansController {
Path tempFile = Files.createTempFile("image_", ".png");
// Render image and save as temp file
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300);
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);
} catch (OutOfMemoryError e) {
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, renderDpi, e);
} catch (NegativeArraySizeException e) {
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, renderDpi, e);
}
ImageIO.write(image, "png", tempFile.toFile());
// Add temp file path to images list

View File

@@ -27,7 +27,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.FlattenRequest;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ApplicationContextProvider;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.WebResponseUtils;
@RestController
@@ -67,7 +70,23 @@ public class FlattenController {
int numPages = document.getNumberOfPages();
for (int i = 0; i < numPages; i++) {
try {
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300, ImageType.RGB);
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) {
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, renderDpi, e);
} catch (NegativeArraySizeException e) {
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, renderDpi, e);
}
PDPage page = new PDPage();
page.setMediaBox(document.getPage(i).getMediaBox());
newDocument.addPage(page);

View File

@@ -359,7 +359,24 @@ public class OCRController {
if (shouldOcr) {
// Convert page to image
BufferedImage image = pdfRenderer.renderImageWithDPI(pageNum, 300);
BufferedImage image;
// Use global maximum DPI setting, fallback to 300 if not set
int renderDpi = 300; // Default fallback
if (applicationProperties != null
&& applicationProperties.getSystem() != null) {
renderDpi = applicationProperties.getSystem().getMaxDPI();
}
try {
image = pdfRenderer.renderImageWithDPI(pageNum, renderDpi);
} catch (OutOfMemoryError e) {
throw ExceptionUtils.createOutOfMemoryDpiException(
pageNum + 1, renderDpi, e);
} catch (NegativeArraySizeException e) {
throw ExceptionUtils.createOutOfMemoryDpiException(
pageNum + 1, renderDpi, e);
}
File imagePath =
new File(tempImagesDir, String.format("page_%d.png", pageNum));
ImageIO.write(image, "png", imagePath);

View File

@@ -34,7 +34,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.ScannerEffectRequest;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.ApplicationContextProvider;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.WebResponseUtils;
@RestController
@@ -82,6 +85,22 @@ public class ScannerEffectController {
int resolution = request.getResolution();
ScannerEffectRequest.Colorspace colorspace = request.getColorspace();
// Validate and limit DPI to prevent excessive memory usage (respecting global limits)
int maxSafeDpi = 500; // Default maximum safe DPI
ApplicationProperties properties =
ApplicationContextProvider.getBean(ApplicationProperties.class);
if (properties != null && properties.getSystem() != null) {
maxSafeDpi = properties.getSystem().getMaxDPI();
}
if (resolution > maxSafeDpi) {
throw ExceptionUtils.createIllegalArgumentException(
"error.dpiExceedsLimit",
"DPI value {0} exceeds maximum safe limit of {1}. High DPI values can cause"
+ " memory issues and crashes. Please use a lower DPI value.",
resolution,
maxSafeDpi);
}
try (PDDocument document = pdfDocumentFactory.load(file)) {
PDDocument outputDocument = new PDDocument();
PDFRenderer pdfRenderer = new PDFRenderer(document);
@@ -118,7 +137,14 @@ public class ScannerEffectController {
}
// Render page to image with safe resolution
BufferedImage image = pdfRenderer.renderImageWithDPI(i, safeResolution);
BufferedImage image;
try {
image = pdfRenderer.renderImageWithDPI(i, safeResolution);
} catch (OutOfMemoryError e) {
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, safeResolution, e);
} catch (NegativeArraySizeException e) {
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, safeResolution, e);
}
log.debug(
"Processing page {} with dimensions {}x{} ({} pixels) at {}dpi",