This commit is contained in:
Anthony Stirling 2025-06-30 22:38:51 +01:00
parent 617ab2ad79
commit 5591a655d0
4 changed files with 43 additions and 45 deletions

View File

@ -47,6 +47,7 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration; import stirling.software.SPDF.config.EndpointConfiguration;
@ -61,18 +62,18 @@ import stirling.software.common.util.WebResponseUtils;
@RequestMapping("/api/v1/misc") @RequestMapping("/api/v1/misc")
@Slf4j @Slf4j
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
@RequiredArgsConstructor
public class CompressController { public class CompressController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
private final boolean qpdfEnabled; private final EndpointConfiguration endpointConfiguration;
private final boolean ghostscriptEnabled;
private boolean isQpdfEnabled() {
public CompressController( return endpointConfiguration.isGroupEnabled("qpdf");
CustomPDFDocumentFactory pdfDocumentFactory, }
EndpointConfiguration endpointConfiguration) {
this.pdfDocumentFactory = pdfDocumentFactory; private boolean isGhostscriptEnabled() {
this.qpdfEnabled = endpointConfiguration.isGroupEnabled("qpdf"); return endpointConfiguration.isGroupEnabled("Ghostscript");
this.ghostscriptEnabled = endpointConfiguration.isGroupEnabled("Ghostscript");
} }
@Data @Data
@ -707,7 +708,7 @@ public class CompressController {
boolean ghostscriptSuccess = false; boolean ghostscriptSuccess = false;
// Try Ghostscript first if available - for ANY compression level // Try Ghostscript first if available - for ANY compression level
if (ghostscriptEnabled) { if (isGhostscriptEnabled()) {
try { try {
applyGhostscriptCompression( applyGhostscriptCompression(
request, optimizeLevel, currentFile, tempFiles); request, optimizeLevel, currentFile, tempFiles);
@ -719,7 +720,7 @@ public class CompressController {
} }
// Fallback to QPDF if Ghostscript failed or not available (levels 1-3 only) // Fallback to QPDF if Ghostscript failed or not available (levels 1-3 only)
if (!ghostscriptSuccess && qpdfEnabled && optimizeLevel <= 3) { if (!ghostscriptSuccess && isQpdfEnabled() && optimizeLevel <= 3) {
try { try {
applyQpdfCompression(request, optimizeLevel, currentFile, tempFiles); applyQpdfCompression(request, optimizeLevel, currentFile, tempFiles);
log.info("QPDF compression applied successfully"); log.info("QPDF compression applied successfully");
@ -728,7 +729,7 @@ public class CompressController {
} }
} }
if (!ghostscriptSuccess && !qpdfEnabled) { if (!ghostscriptSuccess && !isQpdfEnabled()) {
log.info( log.info(
"No external compression tools available, using image compression only"); "No external compression tools available, using image compression only");
} }

View File

@ -27,6 +27,7 @@ import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration; import stirling.software.SPDF.config.EndpointConfiguration;
@ -44,24 +45,20 @@ import stirling.software.common.util.WebResponseUtils;
@RequestMapping("/api/v1/misc") @RequestMapping("/api/v1/misc")
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
@Slf4j @Slf4j
@RequiredArgsConstructor
public class OCRController { public class OCRController {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
private final TempFileManager tempFileManager; private final TempFileManager tempFileManager;
private final boolean ocrMyPdfEnabled; private final EndpointConfiguration endpointConfiguration;
private final boolean tesseractEnabled;
private boolean isOcrMyPdfEnabled() {
public OCRController( return endpointConfiguration.isGroupEnabled("OCRmyPDF");
ApplicationProperties applicationProperties, }
CustomPDFDocumentFactory pdfDocumentFactory,
TempFileManager tempFileManager, private boolean isTesseractEnabled() {
EndpointConfiguration endpointConfiguration) { return endpointConfiguration.isGroupEnabled("tesseract");
this.applicationProperties = applicationProperties;
this.pdfDocumentFactory = pdfDocumentFactory;
this.tempFileManager = tempFileManager;
this.ocrMyPdfEnabled = endpointConfiguration.isGroupEnabled("OCRmyPDF");
this.tesseractEnabled = endpointConfiguration.isGroupEnabled("tesseract");
} }
/** Gets the list of available Tesseract languages from the tessdata directory */ /** Gets the list of available Tesseract languages from the tessdata directory */
@ -127,7 +124,7 @@ public class OCRController {
try { try {
// Use OCRmyPDF if available (no fallback - error if it fails) // Use OCRmyPDF if available (no fallback - error if it fails)
if (ocrMyPdfEnabled) { if (isOcrMyPdfEnabled()) {
if (sidecar != null && sidecar) { if (sidecar != null && sidecar) {
sidecarTextFile = new TempFile(tempFileManager, ".txt"); sidecarTextFile = new TempFile(tempFileManager, ".txt");
} }
@ -147,7 +144,7 @@ public class OCRController {
log.info("OCRmyPDF processing completed successfully"); log.info("OCRmyPDF processing completed successfully");
} }
// Use Tesseract only if OCRmyPDF is not available // Use Tesseract only if OCRmyPDF is not available
else if (tesseractEnabled) { else if (isTesseractEnabled()) {
processWithTesseract( processWithTesseract(
selectedLanguages, selectedLanguages,
ocrType, ocrType,

View File

@ -14,7 +14,8 @@ import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames; import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration; import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.common.model.api.PDFFile; import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.CustomPDFDocumentFactory;
@ -27,21 +28,20 @@ import stirling.software.common.util.WebResponseUtils;
@RestController @RestController
@RequestMapping("/api/v1/misc") @RequestMapping("/api/v1/misc")
@Tag(name = "Misc", description = "Miscellaneous APIs") @Tag(name = "Misc", description = "Miscellaneous APIs")
@Slf4j
@RequiredArgsConstructor
public class RepairController { public class RepairController {
private final CustomPDFDocumentFactory pdfDocumentFactory; private final CustomPDFDocumentFactory pdfDocumentFactory;
private final TempFileManager tempFileManager; private final TempFileManager tempFileManager;
private final boolean ghostscriptEnabled; private final EndpointConfiguration endpointConfiguration;
private final boolean qpdfEnabled;
private boolean isGhostscriptEnabled() {
public RepairController( return endpointConfiguration.isGroupEnabled("Ghostscript");
CustomPDFDocumentFactory pdfDocumentFactory, }
TempFileManager tempFileManager,
EndpointConfiguration endpointConfiguration) { private boolean isQpdfEnabled() {
this.pdfDocumentFactory = pdfDocumentFactory; return endpointConfiguration.isGroupEnabled("qpdf");
this.tempFileManager = tempFileManager;
this.ghostscriptEnabled = endpointConfiguration.isGroupEnabled("Ghostscript");
this.qpdfEnabled = endpointConfiguration.isGroupEnabled("qpdf");
} }
@PostMapping(consumes = "multipart/form-data", value = "/repair") @PostMapping(consumes = "multipart/form-data", value = "/repair")
@ -65,7 +65,7 @@ public class RepairController {
boolean repairSuccess = false; boolean repairSuccess = false;
// Try Ghostscript first if available // Try Ghostscript first if available
if (ghostscriptEnabled) { if (isGhostscriptEnabled()) {
try { try {
List<String> gsCommand = new ArrayList<>(); List<String> gsCommand = new ArrayList<>();
gsCommand.add("gs"); gsCommand.add("gs");
@ -83,13 +83,13 @@ public class RepairController {
} }
} catch (Exception e) { } catch (Exception e) {
// Log and continue to QPDF fallback // Log and continue to QPDF fallback
System.out.println( log.warn(
"Ghostscript repair failed, trying QPDF fallback: " + e.getMessage()); "Ghostscript repair failed, trying QPDF fallback: ", e);
} }
} }
// Fallback to QPDF if Ghostscript failed or not available // Fallback to QPDF if Ghostscript failed or not available
if (!repairSuccess && qpdfEnabled) { if (!repairSuccess && isQpdfEnabled()) {
List<String> qpdfCommand = new ArrayList<>(); List<String> qpdfCommand = new ArrayList<>();
qpdfCommand.add("qpdf"); qpdfCommand.add("qpdf");
qpdfCommand.add("--replace-input"); // Automatically fixes problems it can qpdfCommand.add("--replace-input"); // Automatically fixes problems it can
@ -107,7 +107,7 @@ public class RepairController {
// Use PDFBox as last resort if no external tools are available // Use PDFBox as last resort if no external tools are available
if (!repairSuccess) { if (!repairSuccess) {
if (!ghostscriptEnabled && !qpdfEnabled) { if (!isGhostscriptEnabled() && !isQpdfEnabled()) {
// Basic PDFBox repair - load and save to fix structural issues // Basic PDFBox repair - load and save to fix structural issues
try (var document = pdfDocumentFactory.load(tempInputFile.getFile())) { try (var document = pdfDocumentFactory.load(tempInputFile.getFile())) {
document.save(tempOutputFile.getFile()); document.save(tempOutputFile.getFile());

View File

@ -79,7 +79,7 @@
</select> </select>
</div> </div>
<br> <br>
<div class="mb-3" th:if> <div class="mb-3" th:if="${@endpointConfiguration.isGroupEnabled('OCRmyPDF')}">
<label class="form-label">OCR Options</label> <label class="form-label">OCR Options</label>
<div class="form-check"> <div class="form-check">
<input type="checkbox" class="form-check-input" id="sidecar" name="sidecar" value="true"> <input type="checkbox" class="form-check-input" id="sidecar" name="sidecar" value="true">