Make Ghostscript an optional dependency for tools that don't need it (#4840)

# Description of Changes
Make Ghostscript an optional dependency for tools that don't need it.
This commit is contained in:
James Brunton 2025-11-07 15:11:02 +00:00 committed by GitHub
parent ac3e10eb99
commit 9671f6835e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import org.springframework.web.multipart.MultipartFile;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.common.model.api.misc.HighContrastColorCombination; import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.common.model.api.misc.ReplaceAndInvert; import stirling.software.common.model.api.misc.ReplaceAndInvert;
import stirling.software.common.util.TempFileManager; import stirling.software.common.util.TempFileManager;
@ -18,6 +19,7 @@ import stirling.software.common.util.misc.ReplaceAndInvertColorStrategy;
public class ReplaceAndInvertColorFactory { public class ReplaceAndInvertColorFactory {
private final TempFileManager tempFileManager; private final TempFileManager tempFileManager;
private final EndpointConfiguration endpointConfiguration;
public ReplaceAndInvertColorStrategy replaceAndInvert( public ReplaceAndInvertColorStrategy replaceAndInvert(
MultipartFile file, MultipartFile file,
@ -26,6 +28,13 @@ public class ReplaceAndInvertColorFactory {
String backGroundColor, String backGroundColor,
String textColor) { String textColor) {
// Check Ghostscript availability for CMYK conversion
if (replaceAndInvertOption == ReplaceAndInvert.COLOR_SPACE_CONVERSION
&& !endpointConfiguration.isGroupEnabled("Ghostscript")) {
throw new IllegalStateException(
"CMYK color space conversion requires Ghostscript, which is not available on this system");
}
return switch (replaceAndInvertOption) { return switch (replaceAndInvertOption) {
case CUSTOM_COLOR, HIGH_CONTRAST_COLOR -> case CUSTOM_COLOR, HIGH_CONTRAST_COLOR ->
new CustomColorReplaceStrategy( new CustomColorReplaceStrategy(

View File

@ -403,8 +403,6 @@ public class EndpointConfiguration {
/* Ghostscript */ /* Ghostscript */
addEndpointToGroup("Ghostscript", "repair"); addEndpointToGroup("Ghostscript", "repair");
addEndpointToGroup("Ghostscript", "compress-pdf"); addEndpointToGroup("Ghostscript", "compress-pdf");
addEndpointToGroup("Ghostscript", "crop");
addEndpointToGroup("Ghostscript", "replace-invert-pdf");
/* tesseract */ /* tesseract */
addEndpointToGroup("tesseract", "ocr-pdf"); addEndpointToGroup("tesseract", "ocr-pdf");

View File

@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.SPDF.config.swagger.StandardPdfResponse; import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.CropPdfForm; import stirling.software.SPDF.model.api.general.CropPdfForm;
import stirling.software.common.annotations.AutoJobPostMapping; import stirling.software.common.annotations.AutoJobPostMapping;
@ -37,6 +38,11 @@ import stirling.software.common.util.WebResponseUtils;
public class CropController { public class CropController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
private final EndpointConfiguration endpointConfiguration;
private boolean isGhostscriptEnabled() {
return endpointConfiguration.isGroupEnabled("Ghostscript");
}
@AutoJobPostMapping(value = "/crop", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @AutoJobPostMapping(value = "/crop", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@StandardPdfResponse @StandardPdfResponse
@ -46,9 +52,13 @@ public class CropController {
"This operation takes an input PDF file and crops it according to the given" "This operation takes an input PDF file and crops it according to the given"
+ " coordinates. Input:PDF Output:PDF Type:SISO") + " coordinates. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> cropPdf(@ModelAttribute CropPdfForm request) throws IOException { public ResponseEntity<byte[]> cropPdf(@ModelAttribute CropPdfForm request) throws IOException {
if (request.isRemoveDataOutsideCrop()) { if (request.isRemoveDataOutsideCrop() && isGhostscriptEnabled()) {
return cropWithGhostscript(request); return cropWithGhostscript(request);
} else { } else {
if (request.isRemoveDataOutsideCrop()) {
log.warn(
"Ghostscript not available - 'removeDataOutsideCrop' option requires Ghostscript. Falling back to visual crop only.");
}
return cropWithPDFBox(request); return cropWithPDFBox(request);
} }
} }