222 lines
9.9 KiB
Java
222 lines
9.9 KiB
Java
package stirling.software.SPDF.controller.api.misc;
|
|
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.StandardCopyOption;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.stream.Collectors;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipOutputStream;
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.apache.pdfbox.Loader;
|
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
import org.apache.pdfbox.rendering.PDFRenderer;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.http.MediaType;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.web.bind.annotation.PostMapping;
|
|
import org.springframework.web.bind.annotation.RequestMapping;
|
|
import org.springframework.web.bind.annotation.RestController;
|
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
import io.swagger.v3.oas.annotations.media.Content;
|
|
import io.swagger.v3.oas.annotations.media.Schema;
|
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
|
import stirling.software.SPDF.model.api.misc.ExtractImageScansRequest;
|
|
import stirling.software.SPDF.utils.ProcessExecutor;
|
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
|
|
|
@RestController
|
|
@RequestMapping("/api/v1/misc")
|
|
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
|
public class ExtractImageScansController {
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(ExtractImageScansController.class);
|
|
|
|
@PostMapping(consumes = "multipart/form-data", value = "/extract-image-scans")
|
|
@Operation(
|
|
summary = "Extract image scans from an input file",
|
|
description =
|
|
"This endpoint extracts image scans from a given file based on certain parameters. Users can specify angle threshold, tolerance, minimum area, minimum contour area, and border size. Input:PDF Output:IMAGE/ZIP Type:SIMO")
|
|
public ResponseEntity<byte[]> extractImageScans(
|
|
@RequestBody(
|
|
description = "Form data containing file and extraction parameters",
|
|
required = true,
|
|
content =
|
|
@Content(
|
|
mediaType = "multipart/form-data",
|
|
schema =
|
|
@Schema(
|
|
implementation =
|
|
ExtractImageScansRequest
|
|
.class) // This should
|
|
// represent
|
|
// your form's
|
|
// structure
|
|
))
|
|
ExtractImageScansRequest form)
|
|
throws IOException, InterruptedException {
|
|
String fileName = form.getFileInput().getOriginalFilename();
|
|
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
|
|
|
|
List<String> images = new ArrayList<>();
|
|
|
|
List<Path> tempImageFiles = new ArrayList<>();
|
|
Path tempInputFile = null;
|
|
Path tempZipFile = null;
|
|
List<Path> tempDirs = new ArrayList<>();
|
|
|
|
try {
|
|
// Check if input file is a PDF
|
|
if ("pdf".equalsIgnoreCase(extension)) {
|
|
// Load PDF document
|
|
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
|
|
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
|
int pageCount = document.getNumberOfPages();
|
|
images = new ArrayList<>();
|
|
|
|
// Create images of all pages
|
|
for (int i = 0; i < pageCount; i++) {
|
|
// Create temp file to save the image
|
|
Path tempFile = Files.createTempFile("image_", ".png");
|
|
|
|
// Render image and save as temp file
|
|
BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300);
|
|
ImageIO.write(image, "png", tempFile.toFile());
|
|
|
|
// Add temp file path to images list
|
|
images.add(tempFile.toString());
|
|
tempImageFiles.add(tempFile);
|
|
}
|
|
}
|
|
} else {
|
|
tempInputFile = Files.createTempFile("input_", "." + extension);
|
|
Files.copy(
|
|
form.getFileInput().getInputStream(),
|
|
tempInputFile,
|
|
StandardCopyOption.REPLACE_EXISTING);
|
|
// Add input file path to images list
|
|
images.add(tempInputFile.toString());
|
|
}
|
|
|
|
List<byte[]> processedImageBytes = new ArrayList<>();
|
|
|
|
// Process each image
|
|
for (int i = 0; i < images.size(); i++) {
|
|
|
|
Path tempDir = Files.createTempDirectory("openCV_output");
|
|
tempDirs.add(tempDir);
|
|
List<String> command =
|
|
new ArrayList<>(
|
|
Arrays.asList(
|
|
"python3",
|
|
"./scripts/split_photos.py",
|
|
images.get(i),
|
|
tempDir.toString(),
|
|
"--angle_threshold",
|
|
String.valueOf(form.getAngleThreshold()),
|
|
"--tolerance",
|
|
String.valueOf(form.getTolerance()),
|
|
"--min_area",
|
|
String.valueOf(form.getMinArea()),
|
|
"--min_contour_area",
|
|
String.valueOf(form.getMinContourArea()),
|
|
"--border_size",
|
|
String.valueOf(form.getBorderSize())));
|
|
|
|
// Run CLI command
|
|
ProcessExecutorResult returnCode =
|
|
ProcessExecutor.getInstance(ProcessExecutor.Processes.PYTHON_OPENCV)
|
|
.runCommandWithOutputHandling(command);
|
|
|
|
// Read the output photos in temp directory
|
|
List<Path> tempOutputFiles =
|
|
Files.list(tempDir).sorted().collect(Collectors.toList());
|
|
for (Path tempOutputFile : tempOutputFiles) {
|
|
byte[] imageBytes = Files.readAllBytes(tempOutputFile);
|
|
processedImageBytes.add(imageBytes);
|
|
}
|
|
// Clean up the temporary directory
|
|
FileUtils.deleteDirectory(tempDir.toFile());
|
|
}
|
|
|
|
// Create zip file if multiple images
|
|
if (processedImageBytes.size() > 1) {
|
|
String outputZipFilename =
|
|
fileName.replaceFirst("[.][^.]+$", "") + "_processed.zip";
|
|
tempZipFile = Files.createTempFile("output_", ".zip");
|
|
|
|
try (ZipOutputStream zipOut =
|
|
new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) {
|
|
// Add processed images to the zip
|
|
for (int i = 0; i < processedImageBytes.size(); i++) {
|
|
ZipEntry entry =
|
|
new ZipEntry(
|
|
fileName.replaceFirst("[.][^.]+$", "")
|
|
+ "_"
|
|
+ (i + 1)
|
|
+ ".png");
|
|
zipOut.putNextEntry(entry);
|
|
zipOut.write(processedImageBytes.get(i));
|
|
zipOut.closeEntry();
|
|
}
|
|
}
|
|
|
|
byte[] zipBytes = Files.readAllBytes(tempZipFile);
|
|
|
|
// Clean up the temporary zip file
|
|
Files.delete(tempZipFile);
|
|
|
|
return WebResponseUtils.bytesToWebResponse(
|
|
zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
|
|
} else {
|
|
// Return the processed image as a response
|
|
byte[] imageBytes = processedImageBytes.get(0);
|
|
return WebResponseUtils.bytesToWebResponse(
|
|
imageBytes,
|
|
fileName.replaceFirst("[.][^.]+$", "") + ".png",
|
|
MediaType.IMAGE_PNG);
|
|
}
|
|
} finally {
|
|
// Cleanup logic for all temporary files and directories
|
|
tempImageFiles.forEach(
|
|
path -> {
|
|
try {
|
|
Files.deleteIfExists(path);
|
|
} catch (IOException e) {
|
|
logger.error("Failed to delete temporary image file: " + path, e);
|
|
}
|
|
});
|
|
|
|
if (tempZipFile != null && Files.exists(tempZipFile)) {
|
|
try {
|
|
Files.delete(tempZipFile);
|
|
} catch (IOException e) {
|
|
logger.error("Failed to delete temporary zip file: " + tempZipFile, e);
|
|
}
|
|
}
|
|
|
|
tempDirs.forEach(
|
|
dir -> {
|
|
try {
|
|
FileUtils.deleteDirectory(dir.toFile());
|
|
} catch (IOException e) {
|
|
logger.error("Failed to delete temporary directory: " + dir, e);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|