pdfjs worker changes and crop fix
This commit is contained in:
parent
e83a027023
commit
749461334d
15 changed files with 1093 additions and 996 deletions
|
@ -90,7 +90,7 @@ public class CropController {
|
|||
@PostMapping(value = "/crop", consumes = "multipart/form-data")
|
||||
@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> cropPdf(
|
||||
@Parameter(description = "The input PDF file", required = true) @RequestParam("file") MultipartFile file,
|
||||
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||
@Parameter(description = "The x-coordinate of the top-left corner of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("x") float x,
|
||||
@Parameter(description = "The y-coordinate of the top-left corner of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("y") float y,
|
||||
@Parameter(description = "The width of the crop area", required = true, schema = @Schema(type = "number")) @RequestParam("width") float width,
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package stirling.software.SPDF.controller.api.converters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
public class ConvertHtmlToPDF {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-pdfa")
|
||||
@Operation(
|
||||
summary = "Convert a PDF to a PDF/A",
|
||||
description = "This endpoint converts a PDF file to a PDF/A file. PDF/A is a format designed for long-term archiving of digital documents. Input:PDF Output:PDF Type:SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> pdfToPdfA(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true)
|
||||
MultipartFile inputFile) throws IOException, InterruptedException {
|
||||
|
||||
// Save the uploaded file to a temporary location
|
||||
Path tempInputFile = Files.createTempFile("input_", ".pdf");
|
||||
inputFile.transferTo(tempInputFile.toFile());
|
||||
|
||||
// Prepare the output file path
|
||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
||||
|
||||
// Prepare the OCRmyPDF command
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add("ocrmypdf");
|
||||
command.add("--skip-text");
|
||||
command.add("--tesseract-timeout=0");
|
||||
command.add("--output-type");
|
||||
command.add("pdfa");
|
||||
command.add(tempInputFile.toString());
|
||||
command.add(tempOutputFile.toString());
|
||||
|
||||
int returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF).runCommandWithOutputHandling(command);
|
||||
|
||||
// Read the optimized PDF file
|
||||
byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
|
||||
|
||||
// Clean up the temporary files
|
||||
Files.delete(tempInputFile);
|
||||
Files.delete(tempOutputFile);
|
||||
|
||||
// Return the optimized PDF as a response
|
||||
String outputFilename = inputFile.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_PDFA.pdf";
|
||||
return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
|
||||
}
|
||||
|
||||
}
|
|
@ -126,7 +126,7 @@ home.PDFToWord.desc=Convert PDF to Word formats (DOC, DOCX and ODT)
|
|||
home.PDFToPresentation.title=PDF to Presentation
|
||||
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
||||
|
||||
home.PDFToText.title=PDF to Text/RTF
|
||||
home.PDFToText.title=PDF to RTF (Text)
|
||||
home.PDFToText.desc=Convert PDF to Text or RTF format
|
||||
|
||||
home.PDFToHTML.title=PDF to HTML
|
||||
|
@ -582,8 +582,8 @@ PDFToPresentation.submit=Convert
|
|||
|
||||
|
||||
#PDFToText
|
||||
PDFToText.title=PDF to Text/RTF
|
||||
PDFToText.header=PDF to Text/RTF
|
||||
PDFToText.title=PDF to RTF (Text)
|
||||
PDFToText.header=PDF to RTF (Text)
|
||||
PDFToText.selectText.1=Output file format
|
||||
PDFToText.credit=This service uses LibreOffice for file conversion.
|
||||
PDFToText.submit=Convert
|
||||
|
|
|
@ -594,7 +594,7 @@ PDFToPresentation.submit=변환
|
|||
|
||||
|
||||
#PDFToText
|
||||
PDFToText.title=PDF to Text/RTF
|
||||
PDFToText.title=PDF to RTF (Text)
|
||||
PDFToText.header=PDF를 텍스트/RTF로 변환
|
||||
PDFToText.selectText.1=출력 파일 형식
|
||||
PDFToText.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
||||
|
|
|
@ -135,7 +135,7 @@ home.PDFToWord.desc=将PDF转换为Word格式(DOC、DOCX和ODT)。
|
|||
home.PDFToPresentation.title=PDF To Presentation
|
||||
home.PDFToPresentation.desc=将PDF转换成演示文稿格式(PPT、PPTX和ODP)。
|
||||
|
||||
home.PDFToText.title=PDF To Text/RTF
|
||||
home.PDFToText.title=PDF to RTF (Text)
|
||||
home.PDFToText.desc=将PDF转换为文本或RTF格式
|
||||
|
||||
home.PDFToHTML.title=PDF To HTML
|
||||
|
@ -594,7 +594,7 @@ PDFToPresentation.submit=转换
|
|||
|
||||
|
||||
#PDFToText
|
||||
PDFToText.title=PDF To Text/RTF
|
||||
PDFToText.title=PDF to RTF (Text)
|
||||
PDFToText.header=将PDF转换成文本/RTF
|
||||
PDFToText.selectText.1=输出文件格式
|
||||
PDFToText.credit=该服务使用LibreOffice进行文件转换。
|
||||
|
|
|
@ -70,3 +70,13 @@ html[lang-direction="rtl"] label.form-check-label {
|
|||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
width: 100%;
|
||||
}
|
||||
.fixed-shadow-canvas {
|
||||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
width: 100%;
|
||||
}
|
||||
.shadow-canvas {
|
||||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
|
@ -120,6 +120,7 @@ class PdfContainer {
|
|||
}
|
||||
|
||||
async toRenderer(objectUrl) {
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
||||
return {
|
||||
document: pdf,
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
<label th:text="#{PDFToText.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="rtf">RTF</option>
|
||||
<option value="txt:Text">TXT</option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
<button type="submit" class="btn btn-primary" th:text="#{crop.submit}"></button>
|
||||
</form>
|
||||
<div style="position: relative; display: inline-block;">
|
||||
<canvas id="pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
||||
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
let pdfCanvas = document.getElementById('pdf-canvas');
|
||||
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
||||
let overlayCanvas = document.getElementById('overlayCanvas');
|
||||
|
||||
let context = pdfCanvas.getContext('2d');
|
||||
|
@ -61,6 +61,7 @@
|
|||
let reader = new FileReader();
|
||||
reader.onload = function(ev) {
|
||||
let typedArray = new Uint8Array(reader.result);
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
|
||||
pdfDoc = pdf;
|
||||
totalPages = pdf.numPages;
|
||||
|
@ -126,6 +127,7 @@
|
|||
|
||||
let renderContext = { canvasContext: context, viewport: viewport };
|
||||
page.render(renderContext);
|
||||
pdfCanvas.classList.add("shadow-canvas");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
if (file) {
|
||||
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
||||
const pdfData = await file.arrayBuffer();
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
||||
await DraggableUtils.renderPage(pdfDoc, 0);
|
||||
|
||||
|
|
|
@ -14,37 +14,50 @@
|
|||
<br> <br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 th:text="#{adjustContrast.header}"></h2>
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
||||
<div class="col-md-12">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-3">
|
||||
<div id="sliders-container" style="display:none;">
|
||||
<h4>
|
||||
<span th:text="#{adjustContrast.contrast}"></span> <span id="contrast-val">100</span>%
|
||||
</h4>
|
||||
<input type="range" min="0" max="200" value="100"
|
||||
id="contrast-slider" />
|
||||
<input type="range" min="0" max="200" value="100" id="contrast-slider" />
|
||||
|
||||
<h4>
|
||||
<span th:text="#{adjustContrast.brightness}"></span> <span id="brightness-val">100</span>%
|
||||
</h4>
|
||||
<input type="range" min="0" max="200" value="100"
|
||||
id="brightness-slider" />
|
||||
<input type="range" min="0" max="200" value="100" id="brightness-slider" />
|
||||
|
||||
<h4>
|
||||
<span th:text="#{adjustContrast.saturation}"></span> <span id="saturation-val">100</span>%
|
||||
</h4>
|
||||
<input type="range" min="0" max="200" value="100"
|
||||
id="saturation-slider" />
|
||||
|
||||
</br>
|
||||
<canvas id="pdf-canvas"></canvas>
|
||||
|
||||
|
||||
|
||||
<input type="range" min="0" max="200" value="100" id="saturation-slider" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<h2 th:text="#{adjustContrast.header}"></h2>
|
||||
<div class="col-md-8">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
||||
</div>
|
||||
<br>
|
||||
<canvas id="contrast-pdf-canvas"></canvas>
|
||||
<button id="download-button" class="btn btn-primary" th:text="#{adjustContrast.download}"></button>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
#flex-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
#sliders-container {
|
||||
padding: 0 20px; /* Add some padding to separate sliders from canvas */
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script src="pdfjs/pdf.js"></script>
|
||||
<script>
|
||||
var canvas = document.getElementById('pdf-canvas');
|
||||
var canvas = document.getElementById('contrast-pdf-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
var originalImageData = null;
|
||||
var allPages = [];
|
||||
|
@ -55,6 +68,7 @@
|
|||
var fileReader = new FileReader();
|
||||
fileReader.onload = async function() {
|
||||
var data = new Uint8Array(this.result);
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
pdf = await pdfjsLib.getDocument({data: data}).promise;
|
||||
|
||||
// Get the number of pages in the PDF
|
||||
|
@ -65,6 +79,8 @@
|
|||
pdfDoc = await PDFLib.PDFDocument.create();
|
||||
// Render the first page in the viewer
|
||||
await renderPageAndAdjustImageProperties(1);
|
||||
document.getElementById("sliders-container").style.display = "block";
|
||||
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
@ -90,6 +106,7 @@
|
|||
adjustImageProperties();
|
||||
resolve();
|
||||
});
|
||||
canvas.classList.add("fixed-shadow-canvas");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
|
||||
const file = this.files[0];
|
||||
var url = URL.createObjectURL(file)
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
const pdf = await pdfjsLib.getDocument(url).promise;
|
||||
const pdfMetadata = await pdf.getMetadata();
|
||||
lastPDFFile = pdfMetadata?.info
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
console.error("Please select two PDF files to compare");
|
||||
return;
|
||||
}
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
const [pdf1, pdf2] = await Promise.all([
|
||||
pdfjsLib.getDocument(URL.createObjectURL(file1)).promise,
|
||||
pdfjsLib.getDocument(URL.createObjectURL(file2)).promise
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
document.querySelector("#editSection").style.display = "";
|
||||
|
||||
var url = URL.createObjectURL(fileInput.files[0])
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
const pdf = await pdfjsLib.getDocument(url).promise;
|
||||
const page = await pdf.getPage(1);
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ select#font-select, select#font-select option {
|
|||
if (file) {
|
||||
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
||||
const pdfData = await file.arrayBuffer();
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
||||
await DraggableUtils.renderPage(pdfDoc, 0);
|
||||
|
||||
|
|
Loading…
Reference in a new issue