[Test PR] Desktop fix and unoconv to unoserver (#2971)
# Description of Changes This pull request includes several updates to the Docker configuration and Java application UI scaling. The changes enhance environment variable management, dependency installation, and UI responsiveness to different screen sizes. ### Docker Configuration Updates: * Added new environment variables `STIRLING_PDF_DESKTOP_UI`, `PYTHONPATH`, `UNO_PATH`, and `URE_BOOTSTRAP` to `Dockerfile` and `Dockerfile.fat` to improve the configuration and integration of the LibreOffice environment. [[1]](diffhunk://#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557L38-R46) [[2]](diffhunk://#diff-571631582b988e88c52c86960cc083b0b8fa63cf88f056f26e9e684195221c27L40-R49) * Updated the `CMD` instruction in `Dockerfile` and `Dockerfile.fat` to run both the Java application and `unoserver` simultaneously. [[1]](diffhunk://#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557L87-R96) [[2]](diffhunk://#diff-571631582b988e88c52c86960cc083b0b8fa63cf88f056f26e9e684195221c27L87-R100) * Modified the `RUN` instruction to include additional Python dependencies and setup a virtual environment. [[1]](diffhunk://#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557L68-R81) [[2]](diffhunk://#diff-571631582b988e88c52c86960cc083b0b8fa63cf88f056f26e9e684195221c27R72-R86) ### Workflow Enhancements: * Added `STIRLING_PDF_DESKTOP_UI` environment variable to the GitHub Actions workflows (`PR-Demo-Comment.yml` and `push-docker.yml`) to ensure consistent environment settings. [[1]](diffhunk://#diff-145fe5c0ed8c24e4673c9ad39800dd171a2d0a2e8050497cff980fc7e3a3df0dR106) [[2]](diffhunk://#diff-76056236de05155107f6a660f1e3956059e37338011b8f0e72188afcb9b17b6fR41) ### Java Application UI Scaling: * Introduced `UIScaling` utility to dynamically adjust the size of UI components based on screen resolution in `DesktopBrowser` and `LoadingWindow` classes. [[1]](diffhunk://#diff-dff83b0fe53cba8ee80dc8cee96b9c2bfec612ec1f2c636ebdf22dedb36671e8L218-R219) [[2]](diffhunk://#diff-dff83b0fe53cba8ee80dc8cee96b9c2bfec612ec1f2c636ebdf22dedb36671e8L267-R270) [[3]](diffhunk://#diff-3e287daf297213b698b3c94d6e6ed4aae139d570ba6b115da459d72b5c36c42fL44-R64) [[4]](diffhunk://#diff-3e287daf297213b698b3c94d6e6ed4aae139d570ba6b115da459d72b5c36c42fL86-R102) * Improved the loading of icons by using the `UIScaling` utility for better visual quality. --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com> Co-authored-by: a <a>
This commit is contained in:
@@ -174,7 +174,38 @@ public class RearrangePagesPDFController {
|
||||
return newPageOrderZeroBased;
|
||||
}
|
||||
|
||||
private List<Integer> processSortTypes(String sortTypes, int totalPages) {
|
||||
private List<Integer> duplicate(int totalPages, String pageOrder) {
|
||||
List<Integer> newPageOrder = new ArrayList<>();
|
||||
int duplicateCount;
|
||||
|
||||
try {
|
||||
// Parse the duplicate count from pageOrder
|
||||
duplicateCount =
|
||||
pageOrder != null && !pageOrder.isEmpty()
|
||||
? Integer.parseInt(pageOrder.trim())
|
||||
: 2; // Default to 2 if not specified
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("Invalid duplicate count specified", e);
|
||||
duplicateCount = 2; // Default to 2 if invalid input
|
||||
}
|
||||
|
||||
// Validate duplicate count
|
||||
if (duplicateCount < 1) {
|
||||
duplicateCount = 2; // Default to 2 if invalid input
|
||||
}
|
||||
|
||||
// For each page in the document
|
||||
for (int pageNum = 0; pageNum < totalPages; pageNum++) {
|
||||
// Add the current page index duplicateCount times
|
||||
for (int dupCount = 0; dupCount < duplicateCount; dupCount++) {
|
||||
newPageOrder.add(pageNum);
|
||||
}
|
||||
}
|
||||
|
||||
return newPageOrder;
|
||||
}
|
||||
|
||||
private List<Integer> processSortTypes(String sortTypes, int totalPages, String pageOrder) {
|
||||
try {
|
||||
SortTypes mode = SortTypes.valueOf(sortTypes.toUpperCase());
|
||||
switch (mode) {
|
||||
@@ -196,6 +227,8 @@ public class RearrangePagesPDFController {
|
||||
return removeLast(totalPages);
|
||||
case REMOVE_FIRST_AND_LAST:
|
||||
return removeFirstAndLast(totalPages);
|
||||
case DUPLICATE:
|
||||
return duplicate(totalPages, pageOrder);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported custom mode");
|
||||
}
|
||||
@@ -223,8 +256,10 @@ public class RearrangePagesPDFController {
|
||||
String[] pageOrderArr = pageOrder != null ? pageOrder.split(",") : new String[0];
|
||||
int totalPages = document.getNumberOfPages();
|
||||
List<Integer> newPageOrder;
|
||||
if (sortType != null && sortType.length() > 0) {
|
||||
newPageOrder = processSortTypes(sortType, totalPages);
|
||||
if (sortType != null
|
||||
&& sortType.length() > 0
|
||||
&& !"custom".equals(sortType.toLowerCase())) {
|
||||
newPageOrder = processSortTypes(sortType, totalPages, pageOrder);
|
||||
} else {
|
||||
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, false);
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ public class ConvertOfficeController {
|
||||
List<String> command =
|
||||
new ArrayList<>(
|
||||
Arrays.asList(
|
||||
"unoconv",
|
||||
"-vvv",
|
||||
"-f",
|
||||
"/opt/venv/bin/unoconvert",
|
||||
"--port",
|
||||
"2003",
|
||||
"--convert-to",
|
||||
"pdf",
|
||||
"-o",
|
||||
tempOutputFile.toString(),
|
||||
tempInputFile.toString()));
|
||||
tempInputFile.toString(),
|
||||
tempOutputFile.toString()));
|
||||
ProcessExecutorResult returnCode =
|
||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE)
|
||||
.runCommandWithOutputHandling(command);
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ConvertWebsiteToPDF {
|
||||
|
||||
// Prepare the WeasyPrint command
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add("weasyprint");
|
||||
command.add("/opt/venv/bin/weasyprint");
|
||||
command.add(URL);
|
||||
command.add(tempOutputFile.toString());
|
||||
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package stirling.software.SPDF.controller.api.converters;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.QuoteMode;
|
||||
@@ -18,18 +25,18 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.extract.PDFFilePage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||
import stirling.software.SPDF.pdf.FlexibleCSVWriter;
|
||||
import technology.tabula.ObjectExtractor;
|
||||
import technology.tabula.Page;
|
||||
import technology.tabula.Table;
|
||||
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
|
||||
import technology.tabula.writers.Writer;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/convert")
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
@Slf4j
|
||||
public class ExtractCSVController {
|
||||
|
||||
@PostMapping(value = "/pdf/csv", consumes = "multipart/form-data")
|
||||
@@ -37,31 +44,80 @@ public class ExtractCSVController {
|
||||
summary = "Extracts a CSV document from a PDF",
|
||||
description =
|
||||
"This operation takes an input PDF file and returns CSV file of whole page. Input:PDF Output:CSV Type:SISO")
|
||||
public ResponseEntity<String> PdfToCsv(@ModelAttribute PDFFilePage form) throws Exception {
|
||||
StringWriter writer = new StringWriter();
|
||||
public ResponseEntity<?> pdfToCsv(@ModelAttribute PDFWithPageNums form) throws Exception {
|
||||
String baseName = getBaseName(form.getFileInput().getOriginalFilename());
|
||||
List<CsvEntry> csvEntries = new ArrayList<>();
|
||||
|
||||
try (PDDocument document = Loader.loadPDF(form.getFileInput().getBytes())) {
|
||||
CSVFormat format =
|
||||
CSVFormat.EXCEL.builder().setEscape('"').setQuoteMode(QuoteMode.ALL).build();
|
||||
Writer csvWriter = new FlexibleCSVWriter(format);
|
||||
List<Integer> pages = form.getPageNumbersList(document, true);
|
||||
SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
|
||||
try (ObjectExtractor extractor = new ObjectExtractor(document)) {
|
||||
Page page = extractor.extract(form.getPageId());
|
||||
List<Table> tables = sea.extract(page);
|
||||
csvWriter.write(writer, tables);
|
||||
CSVFormat format = CSVFormat.EXCEL.builder()
|
||||
.setEscape('"')
|
||||
.setQuoteMode(QuoteMode.ALL)
|
||||
.build();
|
||||
|
||||
for (int pageNum : pages) {
|
||||
try (ObjectExtractor extractor = new ObjectExtractor(document)) {
|
||||
log.info("{}",pageNum);
|
||||
Page page = extractor.extract(pageNum);
|
||||
List<Table> tables = sea.extract(page);
|
||||
|
||||
for (int i = 0; i < tables.size(); i++) {
|
||||
StringWriter sw = new StringWriter();
|
||||
FlexibleCSVWriter csvWriter = new FlexibleCSVWriter(format);
|
||||
csvWriter.write(sw, Collections.singletonList(tables.get(i)));
|
||||
|
||||
String entryName = generateEntryName(baseName, pageNum, i + 1);
|
||||
csvEntries.add(new CsvEntry(entryName, sw.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (csvEntries.isEmpty()) {
|
||||
return ResponseEntity.noContent().build();
|
||||
} else if (csvEntries.size() == 1) {
|
||||
return createCsvResponse(csvEntries.get(0), baseName);
|
||||
} else {
|
||||
return createZipResponse(csvEntries, baseName);
|
||||
}
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentDisposition(
|
||||
ContentDisposition.builder("attachment")
|
||||
.filename(
|
||||
form.getFileInput()
|
||||
.getOriginalFilename()
|
||||
.replaceFirst("[.][^.]+$", "")
|
||||
+ "_extracted.csv")
|
||||
.build());
|
||||
headers.setContentType(MediaType.parseMediaType("text/csv"));
|
||||
|
||||
return ResponseEntity.ok().headers(headers).body(writer.toString());
|
||||
}
|
||||
|
||||
private ResponseEntity<byte[]> createZipResponse(List<CsvEntry> entries, String baseName) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(baos)) {
|
||||
for (CsvEntry entry : entries) {
|
||||
ZipEntry zipEntry = new ZipEntry(entry.filename());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
zipOut.write(entry.content().getBytes(StandardCharsets.UTF_8));
|
||||
zipOut.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentDisposition(ContentDisposition.builder("attachment")
|
||||
.filename(baseName + "_extracted.zip").build());
|
||||
headers.setContentType(MediaType.parseMediaType("application/zip"));
|
||||
|
||||
return ResponseEntity.ok().headers(headers).body(baos.toByteArray());
|
||||
}
|
||||
|
||||
private ResponseEntity<String> createCsvResponse(CsvEntry entry, String baseName) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentDisposition(ContentDisposition.builder("attachment")
|
||||
.filename(baseName + "_extracted.csv").build());
|
||||
headers.setContentType(MediaType.parseMediaType("text/csv"));
|
||||
|
||||
return ResponseEntity.ok().headers(headers).body(entry.content());
|
||||
}
|
||||
|
||||
private String generateEntryName(String baseName, int pageNum, int tableIndex) {
|
||||
return String.format("%s_p%d_t%d.csv", baseName, pageNum, tableIndex);
|
||||
}
|
||||
|
||||
private String getBaseName(String filename) {
|
||||
return filename.replaceFirst("[.][^.]+$", "");
|
||||
}
|
||||
|
||||
private record CsvEntry(String filename, String content) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user