mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-19 18:19:29 +00:00
feat: custom error handling when calling renderImageWithDPI, controllers to respect global DPI (#4407)
This commit is contained in:
parent
a438a15105
commit
c684a51cf9
@ -324,4 +324,63 @@ public class ExceptionUtils {
|
|||||||
return createIllegalArgumentException(
|
return createIllegalArgumentException(
|
||||||
"error.argumentRequired", "{0} must not be null", argumentName);
|
"error.argumentRequired", "{0} must not be null", argumentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RuntimeException for memory/image size errors when rendering PDF images with DPI.
|
||||||
|
* Handles OutOfMemoryError and related conditions (e.g., NegativeArraySizeException) that
|
||||||
|
* result from images exceeding Java's array/memory limits.
|
||||||
|
*
|
||||||
|
* @param pageNumber the page number that caused the error
|
||||||
|
* @param dpi the DPI value used
|
||||||
|
* @param cause the original error/exception (e.g., OutOfMemoryError,
|
||||||
|
* NegativeArraySizeException)
|
||||||
|
* @return RuntimeException with user-friendly message
|
||||||
|
*/
|
||||||
|
public static RuntimeException createOutOfMemoryDpiException(
|
||||||
|
int pageNumber, int dpi, Throwable cause) {
|
||||||
|
String message =
|
||||||
|
MessageFormat.format(
|
||||||
|
"Out of memory or image-too-large error while rendering PDF page {0} at {1} DPI. "
|
||||||
|
+ "This can occur when the resulting image exceeds Java's array/memory limits (e.g., NegativeArraySizeException). "
|
||||||
|
+ "Please use a lower DPI value (recommended: 150 or less) or process the document in smaller chunks.",
|
||||||
|
pageNumber, dpi);
|
||||||
|
return new RuntimeException(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RuntimeException for OutOfMemoryError when rendering PDF images with DPI.
|
||||||
|
*
|
||||||
|
* @param pageNumber the page number that caused the error
|
||||||
|
* @param dpi the DPI value used
|
||||||
|
* @param cause the original OutOfMemoryError
|
||||||
|
* @return RuntimeException with user-friendly message
|
||||||
|
*/
|
||||||
|
public static RuntimeException createOutOfMemoryDpiException(
|
||||||
|
int pageNumber, int dpi, OutOfMemoryError cause) {
|
||||||
|
return createOutOfMemoryDpiException(pageNumber, dpi, (Throwable) cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a RuntimeException for memory/image size errors when rendering PDF images with DPI.
|
||||||
|
* Handles OutOfMemoryError and related conditions (e.g., NegativeArraySizeException) that
|
||||||
|
* result from images exceeding Java's array/memory limits.
|
||||||
|
*
|
||||||
|
* @param dpi the DPI value used
|
||||||
|
* @param cause the original error/exception (e.g., OutOfMemoryError,
|
||||||
|
* NegativeArraySizeException)
|
||||||
|
* @return RuntimeException with user-friendly message
|
||||||
|
*/
|
||||||
|
public static RuntimeException createOutOfMemoryDpiException(int dpi, Throwable cause) {
|
||||||
|
String message =
|
||||||
|
MessageFormat.format(
|
||||||
|
"Out of memory or image-too-large error while rendering PDF at {0} DPI. "
|
||||||
|
+ "This can occur when the resulting image exceeds Java's array/memory limits (e.g., NegativeArraySizeException). "
|
||||||
|
+ "Please use a lower DPI value (recommended: 150 or less) or process the document in smaller chunks.",
|
||||||
|
dpi);
|
||||||
|
return new RuntimeException(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RuntimeException createOutOfMemoryDpiException(int dpi, OutOfMemoryError cause) {
|
||||||
|
return createOutOfMemoryDpiException(dpi, (Throwable) cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,6 +205,10 @@ public class PdfUtils {
|
|||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
|
} catch (NegativeArraySizeException e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
}
|
}
|
||||||
writer.writeToSequence(new IIOImage(image, null, null), param);
|
writer.writeToSequence(new IIOImage(image, null, null), param);
|
||||||
}
|
}
|
||||||
@ -253,6 +257,10 @@ public class PdfUtils {
|
|||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
|
} catch (NegativeArraySizeException e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
}
|
}
|
||||||
pdfSizeImageIndex = i;
|
pdfSizeImageIndex = i;
|
||||||
dimension =
|
dimension =
|
||||||
@ -296,6 +304,10 @@ public class PdfUtils {
|
|||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
|
} catch (NegativeArraySizeException e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +342,10 @@ public class PdfUtils {
|
|||||||
DPI);
|
DPI);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
|
} catch (NegativeArraySizeException e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(i + 1, DPI, e);
|
||||||
}
|
}
|
||||||
try (ByteArrayOutputStream baosImage = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream baosImage = new ByteArrayOutputStream()) {
|
||||||
ImageIO.write(image, imageType, baosImage);
|
ImageIO.write(image, imageType, baosImage);
|
||||||
@ -369,8 +385,17 @@ public class PdfUtils {
|
|||||||
pdfRenderer.setSubsamplingAllowed(true);
|
pdfRenderer.setSubsamplingAllowed(true);
|
||||||
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
||||||
BufferedImage bim;
|
BufferedImage bim;
|
||||||
|
|
||||||
|
// 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 {
|
try {
|
||||||
bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB);
|
bim = pdfRenderer.renderImageWithDPI(page, renderDpi, ImageType.RGB);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
if (e.getMessage() != null
|
if (e.getMessage() != null
|
||||||
&& e.getMessage().contains("Maximum size of image exceeded")) {
|
&& e.getMessage().contains("Maximum size of image exceeded")) {
|
||||||
@ -382,6 +407,10 @@ public class PdfUtils {
|
|||||||
page + 1);
|
page + 1);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(page + 1, 300, e);
|
||||||
|
} catch (NegativeArraySizeException e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(page + 1, 300, e);
|
||||||
}
|
}
|
||||||
PDPage originalPage = document.getPage(page);
|
PDPage originalPage = document.getPage(page);
|
||||||
|
|
||||||
|
@ -19,7 +19,10 @@ import org.apache.pdfbox.rendering.PDFRenderer;
|
|||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.model.api.misc.ReplaceAndInvert;
|
import stirling.software.common.model.api.misc.ReplaceAndInvert;
|
||||||
|
import stirling.software.common.util.ApplicationContextProvider;
|
||||||
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
|
|
||||||
public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {
|
public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {
|
||||||
|
|
||||||
@ -44,8 +47,25 @@ public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {
|
|||||||
// Render each page and invert colors
|
// Render each page and invert colors
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
for (int page = 0; page < document.getNumberOfPages(); page++) {
|
for (int page = 0; page < document.getNumberOfPages(); page++) {
|
||||||
BufferedImage image =
|
BufferedImage image;
|
||||||
pdfRenderer.renderImageWithDPI(page, 300); // Render page at 300 DPI
|
|
||||||
|
// 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(
|
||||||
|
page, renderDpi); // Render page with global DPI setting
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(page + 1, renderDpi, e);
|
||||||
|
} catch (NegativeArraySizeException e) {
|
||||||
|
throw ExceptionUtils.createOutOfMemoryDpiException(page + 1, renderDpi, e);
|
||||||
|
}
|
||||||
|
|
||||||
// Invert the colors
|
// Invert the colors
|
||||||
invertImageColors(image);
|
invertImageColors(image);
|
||||||
|
@ -34,7 +34,10 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
|
||||||
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
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.TempFile;
|
||||||
import stirling.software.common.util.TempFileManager;
|
import stirling.software.common.util.TempFileManager;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
@ -128,7 +131,23 @@ public class AutoSplitPdfController {
|
|||||||
pdfRenderer.setSubsamplingAllowed(true);
|
pdfRenderer.setSubsamplingAllowed(true);
|
||||||
|
|
||||||
for (int page = 0; page < document.getNumberOfPages(); ++page) {
|
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);
|
String result = decodeQRCode(bim);
|
||||||
|
|
||||||
boolean isValidQrCode = VALID_QR_CONTENTS.contains(result);
|
boolean isValidQrCode = VALID_QR_CONTENTS.contains(result);
|
||||||
|
@ -30,7 +30,10 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
|
import stirling.software.SPDF.model.api.misc.RemoveBlankPagesRequest;
|
||||||
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
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.PdfUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@ -108,7 +111,25 @@ public class BlankPageController {
|
|||||||
if (hasImages) {
|
if (hasImages) {
|
||||||
log.info("page {} has image, running blank detection", pageIndex);
|
log.info("page {} has image, running blank detection", pageIndex);
|
||||||
// Render image and save as temp file
|
// 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);
|
blank = isBlankImage(image, threshold, whitePercent, threshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,9 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
|
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
|
||||||
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
|
import stirling.software.common.util.ApplicationContextProvider;
|
||||||
import stirling.software.common.util.CheckProgramInstall;
|
import stirling.software.common.util.CheckProgramInstall;
|
||||||
import stirling.software.common.util.ExceptionUtils;
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.GeneralUtils;
|
import stirling.software.common.util.GeneralUtils;
|
||||||
@ -97,7 +99,23 @@ public class ExtractImageScansController {
|
|||||||
Path tempFile = Files.createTempFile("image_", ".png");
|
Path tempFile = Files.createTempFile("image_", ".png");
|
||||||
|
|
||||||
// Render image and save as temp file
|
// 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());
|
ImageIO.write(image, "png", tempFile.toFile());
|
||||||
|
|
||||||
// Add temp file path to images list
|
// Add temp file path to images list
|
||||||
|
@ -27,7 +27,10 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
||||||
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
|
import stirling.software.common.util.ApplicationContextProvider;
|
||||||
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -67,7 +70,23 @@ public class FlattenController {
|
|||||||
int numPages = document.getNumberOfPages();
|
int numPages = document.getNumberOfPages();
|
||||||
for (int i = 0; i < numPages; i++) {
|
for (int i = 0; i < numPages; i++) {
|
||||||
try {
|
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();
|
PDPage page = new PDPage();
|
||||||
page.setMediaBox(document.getPage(i).getMediaBox());
|
page.setMediaBox(document.getPage(i).getMediaBox());
|
||||||
newDocument.addPage(page);
|
newDocument.addPage(page);
|
||||||
|
@ -359,7 +359,24 @@ public class OCRController {
|
|||||||
|
|
||||||
if (shouldOcr) {
|
if (shouldOcr) {
|
||||||
// Convert page to image
|
// 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 =
|
File imagePath =
|
||||||
new File(tempImagesDir, String.format("page_%d.png", pageNum));
|
new File(tempImagesDir, String.format("page_%d.png", pageNum));
|
||||||
ImageIO.write(image, "png", imagePath);
|
ImageIO.write(image, "png", imagePath);
|
||||||
|
@ -34,7 +34,10 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.misc.ScannerEffectRequest;
|
import stirling.software.SPDF.model.api.misc.ScannerEffectRequest;
|
||||||
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||||
|
import stirling.software.common.util.ApplicationContextProvider;
|
||||||
|
import stirling.software.common.util.ExceptionUtils;
|
||||||
import stirling.software.common.util.WebResponseUtils;
|
import stirling.software.common.util.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -82,6 +85,22 @@ public class ScannerEffectController {
|
|||||||
int resolution = request.getResolution();
|
int resolution = request.getResolution();
|
||||||
ScannerEffectRequest.Colorspace colorspace = request.getColorspace();
|
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)) {
|
try (PDDocument document = pdfDocumentFactory.load(file)) {
|
||||||
PDDocument outputDocument = new PDDocument();
|
PDDocument outputDocument = new PDDocument();
|
||||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||||
@ -118,7 +137,14 @@ public class ScannerEffectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render page to image with safe resolution
|
// 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(
|
log.debug(
|
||||||
"Processing page {} with dimensions {}x{} ({} pixels) at {}dpi",
|
"Processing page {} with dimensions {}x{} ({} pixels) at {}dpi",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user