mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2024-11-16 12:20:12 +01:00
pdfjs worker changes and crop fix
This commit is contained in:
parent
e83a027023
commit
749461334d
@ -90,7 +90,7 @@ public class CropController {
|
|||||||
@PostMapping(value = "/crop", consumes = "multipart/form-data")
|
@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")
|
@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(
|
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 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 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,
|
@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.title=PDF to Presentation
|
||||||
home.PDFToPresentation.desc=Convert PDF to Presentation formats (PPT, PPTX and ODP)
|
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.PDFToText.desc=Convert PDF to Text or RTF format
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF to HTML
|
home.PDFToHTML.title=PDF to HTML
|
||||||
@ -582,8 +582,8 @@ PDFToPresentation.submit=Convert
|
|||||||
|
|
||||||
|
|
||||||
#PDFToText
|
#PDFToText
|
||||||
PDFToText.title=PDF to Text/RTF
|
PDFToText.title=PDF to RTF (Text)
|
||||||
PDFToText.header=PDF to Text/RTF
|
PDFToText.header=PDF to RTF (Text)
|
||||||
PDFToText.selectText.1=Output file format
|
PDFToText.selectText.1=Output file format
|
||||||
PDFToText.credit=This service uses LibreOffice for file conversion.
|
PDFToText.credit=This service uses LibreOffice for file conversion.
|
||||||
PDFToText.submit=Convert
|
PDFToText.submit=Convert
|
||||||
|
@ -594,7 +594,7 @@ PDFToPresentation.submit=변환
|
|||||||
|
|
||||||
|
|
||||||
#PDFToText
|
#PDFToText
|
||||||
PDFToText.title=PDF to Text/RTF
|
PDFToText.title=PDF to RTF (Text)
|
||||||
PDFToText.header=PDF를 텍스트/RTF로 변환
|
PDFToText.header=PDF를 텍스트/RTF로 변환
|
||||||
PDFToText.selectText.1=출력 파일 형식
|
PDFToText.selectText.1=출력 파일 형식
|
||||||
PDFToText.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
PDFToText.credit=이 서비스는 파일 변환을 위해 LibreOffice를 사용합니다.
|
||||||
|
@ -135,7 +135,7 @@ home.PDFToWord.desc=将PDF转换为Word格式(DOC、DOCX和ODT)。
|
|||||||
home.PDFToPresentation.title=PDF To Presentation
|
home.PDFToPresentation.title=PDF To Presentation
|
||||||
home.PDFToPresentation.desc=将PDF转换成演示文稿格式(PPT、PPTX和ODP)。
|
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.PDFToText.desc=将PDF转换为文本或RTF格式
|
||||||
|
|
||||||
home.PDFToHTML.title=PDF To HTML
|
home.PDFToHTML.title=PDF To HTML
|
||||||
@ -594,7 +594,7 @@ PDFToPresentation.submit=转换
|
|||||||
|
|
||||||
|
|
||||||
#PDFToText
|
#PDFToText
|
||||||
PDFToText.title=PDF To Text/RTF
|
PDFToText.title=PDF to RTF (Text)
|
||||||
PDFToText.header=将PDF转换成文本/RTF
|
PDFToText.header=将PDF转换成文本/RTF
|
||||||
PDFToText.selectText.1=输出文件格式
|
PDFToText.selectText.1=输出文件格式
|
||||||
PDFToText.credit=该服务使用LibreOffice进行文件转换。
|
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);
|
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||||
width: 100%;
|
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) {
|
async toRenderer(objectUrl) {
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
||||||
return {
|
return {
|
||||||
document: pdf,
|
document: pdf,
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
<label th:text="#{PDFToText.selectText.1}"></label>
|
<label th:text="#{PDFToText.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
<option value="rtf">RTF</option>
|
<option value="rtf">RTF</option>
|
||||||
<option value="txt:Text">TXT</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
|
@ -22,13 +22,13 @@
|
|||||||
<button type="submit" class="btn btn-primary" th:text="#{crop.submit}"></button>
|
<button type="submit" class="btn btn-primary" th:text="#{crop.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
<div style="position: relative; display: inline-block;">
|
<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>
|
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
let pdfCanvas = document.getElementById('pdf-canvas');
|
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
||||||
let overlayCanvas = document.getElementById('overlayCanvas');
|
let overlayCanvas = document.getElementById('overlayCanvas');
|
||||||
|
|
||||||
let context = pdfCanvas.getContext('2d');
|
let context = pdfCanvas.getContext('2d');
|
||||||
@ -61,6 +61,7 @@
|
|||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
reader.onload = function(ev) {
|
reader.onload = function(ev) {
|
||||||
let typedArray = new Uint8Array(reader.result);
|
let typedArray = new Uint8Array(reader.result);
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
|
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
|
||||||
pdfDoc = pdf;
|
pdfDoc = pdf;
|
||||||
totalPages = pdf.numPages;
|
totalPages = pdf.numPages;
|
||||||
@ -126,6 +127,7 @@
|
|||||||
|
|
||||||
let renderContext = { canvasContext: context, viewport: viewport };
|
let renderContext = { canvasContext: context, viewport: viewport };
|
||||||
page.render(renderContext);
|
page.render(renderContext);
|
||||||
|
pdfCanvas.classList.add("shadow-canvas");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
if (file) {
|
if (file) {
|
||||||
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
||||||
const pdfData = await file.arrayBuffer();
|
const pdfData = await file.arrayBuffer();
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
||||||
await DraggableUtils.renderPage(pdfDoc, 0);
|
await DraggableUtils.renderPage(pdfDoc, 0);
|
||||||
|
|
||||||
|
@ -14,37 +14,50 @@
|
|||||||
<br> <br>
|
<br> <br>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-12">
|
||||||
<h2 th:text="#{adjustContrast.header}"></h2>
|
<div class="row justify-content-center">
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
|
<div class="col-md-3">
|
||||||
|
<div id="sliders-container" style="display:none;">
|
||||||
<h4>
|
<h4>
|
||||||
<span th:text="#{adjustContrast.contrast}"></span> <span id="contrast-val">100</span>%
|
<span th:text="#{adjustContrast.contrast}"></span> <span id="contrast-val">100</span>%
|
||||||
</h4>
|
</h4>
|
||||||
<input type="range" min="0" max="200" value="100"
|
<input type="range" min="0" max="200" value="100" id="contrast-slider" />
|
||||||
id="contrast-slider" />
|
|
||||||
|
|
||||||
<h4>
|
<h4>
|
||||||
<span th:text="#{adjustContrast.brightness}"></span> <span id="brightness-val">100</span>%
|
<span th:text="#{adjustContrast.brightness}"></span> <span id="brightness-val">100</span>%
|
||||||
</h4>
|
</h4>
|
||||||
<input type="range" min="0" max="200" value="100"
|
<input type="range" min="0" max="200" value="100" id="brightness-slider" />
|
||||||
id="brightness-slider" />
|
|
||||||
|
|
||||||
<h4>
|
<h4>
|
||||||
<span th:text="#{adjustContrast.saturation}"></span> <span id="saturation-val">100</span>%
|
<span th:text="#{adjustContrast.saturation}"></span> <span id="saturation-val">100</span>%
|
||||||
</h4>
|
</h4>
|
||||||
<input type="range" min="0" max="200" value="100"
|
<input type="range" min="0" max="200" value="100" id="saturation-slider" />
|
||||||
id="saturation-slider" />
|
</div>
|
||||||
|
</div>
|
||||||
</br>
|
<div class="col-md-7">
|
||||||
<canvas id="pdf-canvas"></canvas>
|
<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>
|
<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 src="pdfjs/pdf.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var canvas = document.getElementById('pdf-canvas');
|
var canvas = document.getElementById('contrast-pdf-canvas');
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
var originalImageData = null;
|
var originalImageData = null;
|
||||||
var allPages = [];
|
var allPages = [];
|
||||||
@ -55,6 +68,7 @@
|
|||||||
var fileReader = new FileReader();
|
var fileReader = new FileReader();
|
||||||
fileReader.onload = async function() {
|
fileReader.onload = async function() {
|
||||||
var data = new Uint8Array(this.result);
|
var data = new Uint8Array(this.result);
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
pdf = await pdfjsLib.getDocument({data: data}).promise;
|
pdf = await pdfjsLib.getDocument({data: data}).promise;
|
||||||
|
|
||||||
// Get the number of pages in the PDF
|
// Get the number of pages in the PDF
|
||||||
@ -65,6 +79,8 @@
|
|||||||
pdfDoc = await PDFLib.PDFDocument.create();
|
pdfDoc = await PDFLib.PDFDocument.create();
|
||||||
// Render the first page in the viewer
|
// Render the first page in the viewer
|
||||||
await renderPageAndAdjustImageProperties(1);
|
await renderPageAndAdjustImageProperties(1);
|
||||||
|
document.getElementById("sliders-container").style.display = "block";
|
||||||
|
|
||||||
};
|
};
|
||||||
fileReader.readAsArrayBuffer(file);
|
fileReader.readAsArrayBuffer(file);
|
||||||
}
|
}
|
||||||
@ -90,6 +106,7 @@
|
|||||||
adjustImageProperties();
|
adjustImageProperties();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
canvas.classList.add("fixed-shadow-canvas");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@
|
|||||||
|
|
||||||
const file = this.files[0];
|
const file = this.files[0];
|
||||||
var url = URL.createObjectURL(file)
|
var url = URL.createObjectURL(file)
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
const pdf = await pdfjsLib.getDocument(url).promise;
|
const pdf = await pdfjsLib.getDocument(url).promise;
|
||||||
const pdfMetadata = await pdf.getMetadata();
|
const pdfMetadata = await pdf.getMetadata();
|
||||||
lastPDFFile = pdfMetadata?.info
|
lastPDFFile = pdfMetadata?.info
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
console.error("Please select two PDF files to compare");
|
console.error("Please select two PDF files to compare");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
const [pdf1, pdf2] = await Promise.all([
|
const [pdf1, pdf2] = await Promise.all([
|
||||||
pdfjsLib.getDocument(URL.createObjectURL(file1)).promise,
|
pdfjsLib.getDocument(URL.createObjectURL(file1)).promise,
|
||||||
pdfjsLib.getDocument(URL.createObjectURL(file2)).promise
|
pdfjsLib.getDocument(URL.createObjectURL(file2)).promise
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
document.querySelector("#editSection").style.display = "";
|
document.querySelector("#editSection").style.display = "";
|
||||||
|
|
||||||
var url = URL.createObjectURL(fileInput.files[0])
|
var url = URL.createObjectURL(fileInput.files[0])
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
const pdf = await pdfjsLib.getDocument(url).promise;
|
const pdf = await pdfjsLib.getDocument(url).promise;
|
||||||
const page = await pdf.getPage(1);
|
const page = await pdf.getPage(1);
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ select#font-select, select#font-select option {
|
|||||||
if (file) {
|
if (file) {
|
||||||
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
originalFileName = file.name.replace(/\.[^/.]+$/, "");
|
||||||
const pdfData = await file.arrayBuffer();
|
const pdfData = await file.arrayBuffer();
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs/pdf.worker.js'
|
||||||
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
const pdfDoc = await pdfjsLib.getDocument({ data: pdfData }).promise;
|
||||||
await DraggableUtils.renderPage(pdfDoc, 0);
|
await DraggableUtils.renderPage(pdfDoc, 0);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user