Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c4c22e861 | ||
|
|
00e27d9327 | ||
|
|
f082278041 | ||
|
|
09dde64c57 | ||
|
|
b52a6357f6 | ||
|
|
f14a566d06 | ||
|
|
b352ec6888 | ||
|
|
4ec1bad03d | ||
|
|
f20bbc119d | ||
|
|
8555c3d422 | ||
|
|
71f9d03b19 | ||
|
|
0b31379078 | ||
|
|
29c204b2c2 | ||
|
|
657e881963 | ||
|
|
ef6bdc70a4 | ||
|
|
e4a36115a2 | ||
|
|
325f86832c | ||
|
|
e3dbdd6b09 | ||
|
|
919041e879 | ||
|
|
182231a183 | ||
|
|
46d4ae8fc5 | ||
|
|
73ab1936a3 | ||
|
|
59c72527b5 | ||
|
|
5ea3bcc1dd | ||
|
|
c140052822 | ||
|
|
f7832774d9 | ||
|
|
279d25c03a | ||
|
|
f1984047a8 | ||
|
|
eae7c1bd60 | ||
|
|
d7f592ebda | ||
|
|
1798ce002a | ||
|
|
57a0cca595 | ||
|
|
b26fbd7693 | ||
|
|
43b0e25bdb | ||
|
|
3377af1305 | ||
|
|
c81c1006b7 | ||
|
|
f313857f96 | ||
|
|
d5fbe02149 | ||
|
|
159cee0b39 | ||
|
|
5da4dd6cca | ||
|
|
e9daf05f16 | ||
|
|
a12643194a | ||
|
|
25d8fc08f7 | ||
|
|
a72378dd4d | ||
|
|
9aed70408b | ||
|
|
5ae2c71c3a | ||
|
|
4edce515b8 | ||
|
|
67ff664eb8 | ||
|
|
71c1a4f102 | ||
|
|
ba4ba1b9fc | ||
|
|
59f10f06ca | ||
|
|
f7953cbc37 | ||
|
|
9a74e81754 | ||
|
|
420e4b6766 | ||
|
|
aed48ffc93 | ||
|
|
0cebe69ff8 | ||
|
|
e5990dba81 | ||
|
|
c9b0d01250 | ||
|
|
4918ed3f3c | ||
|
|
b176ce4251 | ||
|
|
518ff5409e | ||
|
|
803bd3c5b2 | ||
|
|
03d4e73304 | ||
|
|
55a820b09f | ||
|
|
f2a65dc360 | ||
|
|
7b4a889ea7 | ||
|
|
f627d251c3 | ||
|
|
d5b7125415 | ||
|
|
67dd3cf0e3 | ||
|
|
b8b62bb5af | ||
|
|
b4a9d1ac18 | ||
|
|
8aae651c2c | ||
|
|
fc9465b324 | ||
|
|
579a50be2c | ||
|
|
9c5b967e4c | ||
|
|
d41deb729b | ||
|
|
a93a89f3f0 | ||
|
|
11d642a25f | ||
|
|
67448498ea | ||
|
|
489b8da713 | ||
|
|
728d4d0fa8 | ||
|
|
e70f4ff3a6 | ||
|
|
04032c0dfe | ||
|
|
ecba6461df | ||
|
|
433ba6c250 | ||
|
|
ff6c55d1d0 | ||
|
|
d9f8facf2e | ||
|
|
6bd3e5cc8f | ||
|
|
936fb5ae45 | ||
|
|
8e661e1260 | ||
|
|
987d9b0502 | ||
|
|
f6a9169446 | ||
|
|
d5c1c43eb1 | ||
|
|
20c74dac60 | ||
|
|
30161275a3 | ||
|
|
7e9479806e | ||
|
|
39b9ea9f1d | ||
|
|
5a9165d7c6 |
53
.github/workflows/push-docker.yml
vendored
53
.github/workflows/push-docker.yml
vendored
@@ -8,7 +8,6 @@ on:
|
||||
- main
|
||||
jobs:
|
||||
push:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -46,13 +45,17 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Convert repository owner to lowercase
|
||||
id: repoowner
|
||||
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
|
||||
|
||||
- name: Generate tags
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4.4.0
|
||||
with:
|
||||
images: |
|
||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||
ghcr.io/${{ github.repository_owner }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||
tags: |
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
@@ -76,27 +79,27 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
|
||||
- name: Generate tags
|
||||
|
||||
|
||||
- name: Generate tags ultra-lite
|
||||
id: meta2
|
||||
uses: docker/metadata-action@v4.4.0
|
||||
if: github.ref != 'refs/heads/main'
|
||||
with:
|
||||
images: |
|
||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||
ghcr.io/${{ github.repository_owner }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||
tags: |
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-light,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest-ultra-light,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=alpha-ultra-light,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
- name: Convert repository owner to lowercase
|
||||
id: repoowner
|
||||
run: echo "::set-output name=lowercase::$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')"
|
||||
|
||||
- name: Build and push Dockerfile-ultralite
|
||||
- name: Build and push Dockerfile-ultra-lite
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
if: github.ref != 'refs/heads/main'
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile-ultralite
|
||||
file: ./Dockerfile-ultra-lite
|
||||
push: true
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
@@ -105,3 +108,29 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
|
||||
|
||||
|
||||
- name: Generate tags lite
|
||||
id: meta3
|
||||
uses: docker/metadata-action@v4.4.0
|
||||
if: github.ref != 'refs/heads/main'
|
||||
with:
|
||||
images: |
|
||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||
tags: |
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
|
||||
- name: Build and push Dockerfile-lite
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
if: github.ref != 'refs/heads/main'
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile-lite
|
||||
push: true
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
tags: ${{ steps.meta3.outputs.tags }}
|
||||
labels: ${{ steps.meta3.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
|
||||
45
.github/workflows/releaseArtifacts.yml
vendored
Normal file
45
.github/workflows/releaseArtifacts.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Release Artifacts
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
jobs:
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.5.2
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3.11.0
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Generate jar
|
||||
run: ./gradlew clean createExe
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./build/launch4j/Stirling-PDF.exe
|
||||
asset_name: Stirling-PDF.exe
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
- name: Get version number
|
||||
id: versionNumber
|
||||
run: echo "::set-output name=versionNumber::$(./gradlew printVersion --quiet | tail -1)"
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar
|
||||
asset_name: Stirling-PDF.jar
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
# Build jbig2enc in a separate stage
|
||||
FROM frooodle/stirling-pdf-base:beta3
|
||||
FROM frooodle/stirling-pdf-base:latest
|
||||
|
||||
# Create scripts folder and copy local scripts
|
||||
RUN mkdir /scripts
|
||||
COPY ./scripts/* /scripts/
|
||||
|
||||
#Install fonts
|
||||
RUN mkdir /usr/share/fonts/opentype/noto/
|
||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
||||
COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
|
||||
RUN fc-cache -f -v
|
||||
|
||||
# Copy the application JAR file
|
||||
COPY build/libs/*.jar app.jar
|
||||
|
||||
|
||||
23
Dockerfile-lite
Normal file
23
Dockerfile-lite
Normal file
@@ -0,0 +1,23 @@
|
||||
# Build jbig2enc in a separate stage
|
||||
FROM bellsoft/liberica-openjdk-debian:17
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libreoffice-core-nogui \
|
||||
libreoffice-common \
|
||||
libreoffice-writer-nogui \
|
||||
libreoffice-calc-nogui \
|
||||
libreoffice-impress-nogui \
|
||||
unoconv && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy the application JAR file
|
||||
COPY build/libs/*.jar app.jar
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Set environment variables
|
||||
ENV GROUPS_TO_REMOVE=Python,OpenCV,OCRmyPDF
|
||||
|
||||
# Run the application
|
||||
CMD ["java", "-jar", "/app.jar"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Build jbig2enc in a separate stage
|
||||
FROM openjdk:17-jdk-slim
|
||||
FROM bellsoft/liberica-openjdk-alpine:17
|
||||
|
||||
# Copy the application JAR file
|
||||
COPY build/libs/*.jar app.jar
|
||||
@@ -8,7 +8,7 @@ COPY build/libs/*.jar app.jar
|
||||
EXPOSE 8080
|
||||
|
||||
# Set environment variables
|
||||
ENV GROUPS_TO_REMOVE=LibreOffice,CLI
|
||||
ENV GROUPS_TO_REMOVE=CLI
|
||||
|
||||
# Run the application
|
||||
CMD ["java", "-jar", "/app.jar"]
|
||||
@@ -1,5 +1,5 @@
|
||||
# Main stage
|
||||
FROM openjdk:17-jdk-slim AS base
|
||||
FROM bellsoft/liberica-openjdk-debian:17 AS base
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libreoffice-core-nogui \
|
||||
|
||||
35
Endpoint-groups.md
Normal file
35
Endpoint-groups.md
Normal file
@@ -0,0 +1,35 @@
|
||||
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|
||||
|---------------------|---------|---------|----------|-------|------|--------|--------|-------------|----------|----------|------------|
|
||||
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
||||
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
|
||||
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
|
||||
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||
| split-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
||||
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
|
||||
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-img | | ✔️ | | | | | | | | ✔️ | |
|
||||
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
|
||||
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| add-password | | | ✔️ | | | | | | | ✔️ | |
|
||||
| add-watermark | | | ✔️ | | | | | | | ✔️ | |
|
||||
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
|
||||
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
|
||||
| remove-password | | | ✔️ | | | | | | | ✔️ | |
|
||||
| add-image | | | | ✔️ | | | | | | ✔️ | |
|
||||
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
|
||||
| compare | | | | ✔️ | | | | | | | ✔️ |
|
||||
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||
| extract-images | | | | ✔️ | | | | | | ✔️ | |
|
||||
| flatten | | | | ✔️ | | | | | | | |
|
||||
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
|
||||
| sign | | | | ✔️ | | | | | | | ✔️ |
|
||||
@@ -123,7 +123,7 @@ This folder is required for the python scripts using OpenCV
|
||||
|
||||
```bash
|
||||
sudo mkdir /opt/Stirling-PDF &&\
|
||||
sudo mv ./build/libs/S-PDF-*.jar /opt/Stirling-PDF/ &&\
|
||||
sudo mv ./build/libs/Stirling-PDF-*.jar /opt/Stirling-PDF/ &&\
|
||||
sudo mv scripts /opt/Stirling-PDF/ &&\
|
||||
echo "Scripts installed."
|
||||
```
|
||||
|
||||
20
README.md
20
README.md
@@ -21,7 +21,7 @@ Feel free to request any features or bug fixes either in github issues or our [D
|
||||

|
||||
|
||||
## Features
|
||||
- Full intractable GUI for merging/splitting/rotating/moving PDFs and their pages.
|
||||
- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages.
|
||||
- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
|
||||
- Merge multiple PDFs together into a single resultant file
|
||||
- Convert PDFs to and from images
|
||||
@@ -53,6 +53,7 @@ Hosted instance/demo of the app can be seen [here](https://pdf.adminforge.de/) h
|
||||
## Technologies used
|
||||
- Spring Boot + Thymeleaf
|
||||
- PDFBox
|
||||
- IText7
|
||||
- [LibreOffice](https://www.libreoffice.org/discover/libreoffice/) for advanced conversions
|
||||
- [OcrMyPdf](https://github.com/ocrmypdf/OCRmyPDF)
|
||||
- HTML, CSS, JavaScript
|
||||
@@ -68,13 +69,20 @@ Please view https://github.com/Frooodle/Stirling-PDF/blob/main/LocalRunGuide.md
|
||||
### Docker
|
||||
https://hub.docker.com/r/frooodle/s-pdf
|
||||
|
||||
Stirling PDF has 3 different versions, a Full version, Lite and ultra-Lite. Depending on the types of features you use you may want a smaller image to save on space.
|
||||
To see what the different versions offer please look at our [version mapping](https://github.com/Frooodle/Stirling-PDF/blob/main/Version-groups.md)
|
||||
For people that dont mind about space optimisation just use latest tag.
|
||||

|
||||

|
||||

|
||||
|
||||
Docker Run
|
||||
```
|
||||
docker run -d \
|
||||
-p 8080:8080 \
|
||||
-v /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata \
|
||||
--name stirling-pdf \
|
||||
frooodle/s-pdf
|
||||
frooodle/s-pdf:latest
|
||||
|
||||
|
||||
Can also add these for customisation but are not required
|
||||
@@ -90,7 +98,7 @@ Docker Compose
|
||||
version: '3.3'
|
||||
services:
|
||||
stirling-pdf:
|
||||
image: frooodle/s-pdf
|
||||
image: frooodle/s-pdf:latest
|
||||
ports:
|
||||
- '8080:8080'
|
||||
volumes:
|
||||
@@ -111,7 +119,7 @@ services:
|
||||
Please view https://github.com/Frooodle/Stirling-PDF/blob/main/HowToUseOCR.md
|
||||
|
||||
## Want to add your own language?
|
||||
Stirling PDF currently supports
|
||||
Stirling PDF currently supports 16!
|
||||
- English (English) (en_GB)
|
||||
- Arabic (العربية) (ar_AR)
|
||||
- German (Deutsch) (de_DE)
|
||||
@@ -124,6 +132,10 @@ Stirling PDF currently supports
|
||||
- Polish (Polski) (pl_PL)
|
||||
- Romanian (Română) (ro_RO)
|
||||
- Korean (한국어) (ko_KR)
|
||||
- Portuguese Brazilian (Português) (pt_BR)
|
||||
- Russian (Русский) (ru_RU)
|
||||
- Basque (Euskara) (eu_ES)
|
||||
- Japanese (日本語) (ja_JP)
|
||||
|
||||
If you want to add your own language to Stirling-PDF please refer
|
||||
https://github.com/Frooodle/Stirling-PDF/blob/main/HowToAddNewLanguage.md
|
||||
|
||||
48
Version-groups.md
Normal file
48
Version-groups.md
Normal file
@@ -0,0 +1,48 @@
|
||||
|Technology | Ultra-Lite | Lite | Full |
|
||||
|----------------|:----------:|:----:|:----:|
|
||||
| Java | ✔️ | ✔️ | ✔️ |
|
||||
| JavaScript | ✔️ | ✔️ | ✔️ |
|
||||
| Libre | | ✔️ | ✔️ |
|
||||
| Python | | | ✔️ |
|
||||
| OpenCV | | | ✔️ |
|
||||
| OCRmyPDF | | | ✔️ |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Operation | Ultra-Lite | Lite | Full
|
||||
--------------------|------------|------|-----
|
||||
add-password | ✔️ | ✔️ | ✔️
|
||||
add-watermark | ✔️ | ✔️ | ✔️
|
||||
cert-sign | ✔️ | ✔️ | ✔️
|
||||
change-metadata | ✔️ | ✔️ | ✔️
|
||||
change-permissions | ✔️ | ✔️ | ✔️
|
||||
compare | ✔️ | ✔️ | ✔️
|
||||
extract-images | ✔️ | ✔️ | ✔️
|
||||
flatten | ✔️ | ✔️ | ✔️
|
||||
img-to-pdf | ✔️ | ✔️ | ✔️
|
||||
merge-pdfs | ✔️ | ✔️ | ✔️
|
||||
multi-page-layout | ✔️ | ✔️ | ✔️
|
||||
pdf-organizer | ✔️ | ✔️ | ✔️
|
||||
pdf-to-img | ✔️ | ✔️ | ✔️
|
||||
remove-pages | ✔️ | ✔️ | ✔️
|
||||
remove-password | ✔️ | ✔️ | ✔️
|
||||
rotate-pdf | ✔️ | ✔️ | ✔️
|
||||
scale-pages | ✔️ | ✔️ | ✔️
|
||||
sign | ✔️ | ✔️ | ✔️
|
||||
split-pdfs | ✔️ | ✔️ | ✔️
|
||||
add-image | ✔️ | ✔️ | ✔️
|
||||
file-to-pdf | | ✔️ | ✔️
|
||||
pdf-to-html | | ✔️ | ✔️
|
||||
pdf-to-presentation | | ✔️ | ✔️
|
||||
pdf-to-text | | ✔️ | ✔️
|
||||
pdf-to-word | | ✔️ | ✔️
|
||||
pdf-to-xml | | ✔️ | ✔️
|
||||
repair | | ✔️ | ✔️
|
||||
xlsx-to-pdf | | ✔️ | ✔️
|
||||
compress-pdf | | | ✔️
|
||||
extract-image-scans | | | ✔️
|
||||
ocr-pdf | | | ✔️
|
||||
pdf-to-pdfa | | | ✔️
|
||||
remove-blanks | | | ✔️
|
||||
34
build.gradle
34
build.gradle
@@ -1,13 +1,14 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.1.0'
|
||||
id 'org.springframework.boot' version '3.1.1'
|
||||
id 'io.spring.dependency-management' version '1.1.0'
|
||||
id 'org.springdoc.openapi-gradle-plugin' version '1.6.0'
|
||||
id "io.swagger.swaggerhub" version "1.1.0"
|
||||
id "io.swagger.swaggerhub" version "1.2.0"
|
||||
id 'edu.sc.seis.launch4j' version '3.0.3'
|
||||
}
|
||||
|
||||
group = 'stirling.software'
|
||||
version = '0.10.0'
|
||||
version = '0.10.3'
|
||||
sourceCompatibility = '17'
|
||||
|
||||
repositories {
|
||||
@@ -20,13 +21,36 @@ openApi {
|
||||
outputFileName = "SwaggerDoc.json"
|
||||
}
|
||||
|
||||
|
||||
launch4j {
|
||||
icon = "${projectDir}/src/main/resources/static/favicon.ico"
|
||||
|
||||
outfile="Stirling-PDF.exe"
|
||||
headerType="console"
|
||||
jarTask = tasks.bootJar
|
||||
|
||||
errTitle="Encountered error, Do you have Java 17?"
|
||||
downloadUrl="https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe"
|
||||
variables=["BROWSER_OPEN=true"]
|
||||
jreMinVersion="17"
|
||||
|
||||
mutexName="Stirling-PDF"
|
||||
windowTitle="Stirling-PDF"
|
||||
|
||||
messagesStartupError="An error occurred while starting Stirling-PDF"
|
||||
//messagesJreNotFoundError="This application requires a Java Runtime Environment, Please download Java 17."
|
||||
messagesJreVersionError="You are running the wrong version of Java, Please download Java 17."
|
||||
messagesLauncherError="Java is corrupted. Please uninstall and then install Java 17."
|
||||
messagesInstanceAlreadyExists="Stirling-PDF is already running."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web:3.1.0'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.0'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.1'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.0'
|
||||
// https://mvnrepository.com/artifact/org.apache.pdfbox/jbig2-imageio
|
||||
implementation group: 'org.apache.pdfbox', name: 'jbig2-imageio', version: '3.0.4'
|
||||
implementation 'commons-io:commons-io:2.11.0'
|
||||
implementation 'commons-io:commons-io:2.13.0'
|
||||
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
|
||||
|
||||
|
||||
32
groups.md
32
groups.md
@@ -1,32 +0,0 @@
|
||||
Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript
|
||||
--------------------|---------|---------|----------|-------|------|--------|--------|-------------|--------- |-------- |-----------
|
||||
remove-pages | X | | | | | | | | | X |
|
||||
merge-pdfs | X | | | | | | | | | X |
|
||||
split-pdfs | X | | | | | | | | | X |
|
||||
pdf-organizer | X | | | | | | | | | X | X
|
||||
rotate-pdf | X | | | | | | | | | X |
|
||||
pdf-to-img | | X | | | | | | | | X |
|
||||
img-to-pdf | | X | | | | | | | | X |
|
||||
pdf-to-pdfa | | X | | | X | | | | X | |
|
||||
file-to-pdf | | X | | | X | | | X | | |
|
||||
xlsx-to-pdf | | X | | | X | | | X | | |
|
||||
pdf-to-word | | X | | | X | | | X | | |
|
||||
pdf-to-presentation | | X | | | X | | | X | | |
|
||||
pdf-to-text | | X | | | X | | | X | | |
|
||||
pdf-to-html | | X | | | X | | | X | | |
|
||||
pdf-to-xml | | X | | | X | | | X | | |
|
||||
add-password | | | X | | | | | | | X |
|
||||
remove-password | | | X | | | | | | | X |
|
||||
change-permissions | | | X | | | | | | | X |
|
||||
add-watermark | | | X | | | | | | | X |
|
||||
ocr-pdf | | | | X | X | | | | X | |
|
||||
add-image | | | | X | | | | | | X |
|
||||
compress-pdf | | | | X | X | | | | X
|
||||
extract-images | | | | X | | | | | | X |
|
||||
change-metadata | | | | X | | | | | | X |
|
||||
extract-image-scans | | | | X | X | X | X | | | |
|
||||
sign | | | | X | | | | | | | X
|
||||
flatten | | | | X | | | | | | |
|
||||
repair | | | | X | X | | | X | | |
|
||||
remove-blanks | | | | X | X | X | X | | | |
|
||||
compare | | | | X | | | | | | | X
|
||||
36
lauch4jConfig.xml
Normal file
36
lauch4jConfig.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<launch4jConfig>
|
||||
<dontWrapJar>false</dontWrapJar>
|
||||
<headerType>console</headerType>
|
||||
<jar>.\build\libs\S-PDF-0.10.1.jar</jar>
|
||||
<outfile>.\Stirling-PDF.exe</outfile>
|
||||
<errTitle>Please download Java17</errTitle>
|
||||
<cmdLine></cmdLine>
|
||||
<chdir>.</chdir>
|
||||
<priority>normal</priority>
|
||||
<downloadUrl>https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe</downloadUrl>
|
||||
<supportUrl></supportUrl>
|
||||
<stayAlive>false</stayAlive>
|
||||
<restartOnCrash>false</restartOnCrash>
|
||||
<manifest></manifest>
|
||||
<icon>./src/main/resources/static/favicon.ico</icon>
|
||||
<var>BROWSER_OPEN=true</var>
|
||||
<singleInstance>
|
||||
<mutexName>Stirling-PDF</mutexName>
|
||||
<windowTitle>Stirling-PDF</windowTitle>
|
||||
</singleInstance>
|
||||
<jre>
|
||||
<path>%JAVA_HOME%;%PATH%</path>
|
||||
<requiresJdk>false</requiresJdk>
|
||||
<requires64Bit>false</requires64Bit>
|
||||
<minVersion>17</minVersion>
|
||||
<maxVersion></maxVersion>
|
||||
</jre>
|
||||
<messages>
|
||||
<startupErr>An error occurred while starting Stirling-PDF</startupErr>
|
||||
<jreNotFoundErr>This application requires a Java Runtime Environment, Please download Java 17.</jreNotFoundErr>
|
||||
<jreVersionErr>You are running the wrong version of Java, Please download Java 17.</jreVersionErr>
|
||||
<launcherErr>Java is corrupted. Please uninstall and then install Java 17.</launcherErr>
|
||||
<instanceAlreadyExistsMsg>Stirling-PDF is already running.</instanceAlreadyExistsMsg>
|
||||
</messages>
|
||||
</launch4jConfig>
|
||||
@@ -14,13 +14,21 @@ def is_blank_image(image_path, threshold=10, white_percent=99, white_value=255,
|
||||
blurred_image = cv2.GaussianBlur(image, (blur_size, blur_size), 0)
|
||||
|
||||
_, thresholded_image = cv2.threshold(blurred_image, white_value - threshold, white_value, cv2.THRESH_BINARY)
|
||||
|
||||
|
||||
# Calculate the percentage of white pixels in the thresholded image
|
||||
white_pixels = np.sum(thresholded_image == white_value)
|
||||
white_pixels = 0
|
||||
total_pixels = thresholded_image.size
|
||||
white_pixel_percentage = (white_pixels / total_pixels) * 100
|
||||
for i in range(0, thresholded_image.shape[0], 2):
|
||||
for j in range(0, thresholded_image.shape[1], 2):
|
||||
if thresholded_image[i, j] == white_value:
|
||||
white_pixels += 1
|
||||
white_pixel_percentage = (white_pixels / (i * thresholded_image.shape[1] + j + 1)) * 100
|
||||
if white_pixel_percentage < white_percent:
|
||||
return False
|
||||
|
||||
print(f"Page has white pixel percent of {white_pixel_percentage}")
|
||||
return white_pixel_percentage > white_percent
|
||||
return True
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1 +1 @@
|
||||
rootProject.name = 'S-PDF'
|
||||
rootProject.name = 'Stirling-PDF'
|
||||
|
||||
@@ -1,11 +1,63 @@
|
||||
package stirling.software.SPDF;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
@SpringBootApplication
|
||||
//@EnableScheduling
|
||||
public class SPdfApplication {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// Check if the BROWSER_OPEN environment variable is set to true
|
||||
String browserOpenEnv = env.getProperty("BROWSER_OPEN");
|
||||
boolean browserOpen = browserOpenEnv != null && browserOpenEnv.equalsIgnoreCase("true");
|
||||
|
||||
if (browserOpen) {
|
||||
try {
|
||||
String port = env.getProperty("local.server.port");
|
||||
if(port == null || port.length() == 0) {
|
||||
port="8080";
|
||||
}
|
||||
String url = "http://localhost:" + port;
|
||||
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
if (os.contains("win")) {
|
||||
// For Windows
|
||||
rt.exec("rundll32 url.dll,FileProtocolHandler " + url);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SPdfApplication.class, args);
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Stirling-PDF Started.");
|
||||
|
||||
String port = System.getProperty("local.server.port");
|
||||
if(port == null || port.length() == 0) {
|
||||
port="8080";
|
||||
}
|
||||
String url = "http://localhost:" + port;
|
||||
System.out.println("Navigate to " + url);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -39,10 +39,17 @@ public class Beans implements WebMvcConfigurer {
|
||||
Locale tempLocale = Locale.forLanguageTag(appLocaleEnv);
|
||||
String tempLanguageTag = tempLocale.toLanguageTag();
|
||||
|
||||
if (appLocaleEnv.equalsIgnoreCase(tempLanguageTag)) {
|
||||
if (appLocaleEnv.equalsIgnoreCase(tempLanguageTag)) {
|
||||
defaultLocale = tempLocale;
|
||||
} else {
|
||||
System.err.println("Invalid APP_LOCALE environment variable value. Falling back to default Locale.UK.");
|
||||
tempLocale = Locale.forLanguageTag(appLocaleEnv.replace("_","-"));
|
||||
tempLanguageTag = tempLocale.toLanguageTag();
|
||||
|
||||
if (appLocaleEnv.equalsIgnoreCase(tempLanguageTag)) {
|
||||
defaultLocale = tempLocale;
|
||||
} else {
|
||||
System.err.println("Invalid APP_LOCALE environment variable value. Falling back to default Locale.UK.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
package stirling.software.SPDF.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -7,39 +9,71 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final Pattern LANG_PATTERN = Pattern.compile("&?lang=([^&]+)");
|
||||
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints");
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null && !queryString.isEmpty()) {
|
||||
String requestURI = request.getRequestURI();
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null && !queryString.isEmpty()) {
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
// Keep the lang parameter if it exists
|
||||
Matcher langMatcher = LANG_PATTERN.matcher(queryString);
|
||||
String langQueryString = langMatcher.find() ? "lang=" + langMatcher.group(1) : "";
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
|
||||
// Check if there are any other query parameters besides the lang parameter
|
||||
String remainingQueryString = queryString.replaceAll(LANG_PATTERN.pattern(), "").replaceAll("&+", "&").replaceAll("^&|&$", "");
|
||||
// Keep only the allowed parameters
|
||||
String[] queryParameters = queryString.split("&");
|
||||
for (String param : queryParameters) {
|
||||
String[] keyValue = param.split("=");
|
||||
if (keyValue.length != 2) {
|
||||
continue;
|
||||
}
|
||||
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
||||
parameters.put(keyValue[0], keyValue[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!remainingQueryString.isEmpty()) {
|
||||
// Redirect to the URL without other query parameters
|
||||
String redirectUrl = requestURI + (langQueryString.isEmpty() ? "" : "?" + langQueryString);
|
||||
response.sendRedirect(redirectUrl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// If there are any parameters that are not allowed
|
||||
if (parameters.size() != queryParameters.length) {
|
||||
// Construct new query string
|
||||
StringBuilder newQueryString = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
if (newQueryString.length() > 0) {
|
||||
newQueryString.append("&");
|
||||
}
|
||||
newQueryString.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
|
||||
}
|
||||
// Redirect to the URL with only allowed query parameters
|
||||
String redirectUrl = requestURI + "?" + newQueryString;
|
||||
response.sendRedirect(redirectUrl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
}
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
ModelAndView modelAndView) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,14 @@ public class EndpointConfiguration {
|
||||
}
|
||||
|
||||
public void enableEndpoint(String endpoint) {
|
||||
endpointStatuses.put(endpoint, true);
|
||||
endpointStatuses.put(endpoint, true);
|
||||
}
|
||||
|
||||
public void disableEndpoint(String endpoint) {
|
||||
logger.info("Disabling {}", endpoint);
|
||||
endpointStatuses.put(endpoint, false);
|
||||
if(!endpointStatuses.containsKey(endpoint) || endpointStatuses.get(endpoint) != false) {
|
||||
logger.info("Disabling {}", endpoint);
|
||||
endpointStatuses.put(endpoint, false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEndpointEnabled(String endpoint) {
|
||||
|
||||
@@ -27,7 +27,8 @@ public class MetricsFilter extends OncePerRequestFilter {
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
|
||||
//System.out.println("uri="+uri + ", method=" + request.getMethod() );
|
||||
// Ignore static resources
|
||||
if (!(uri.startsWith("/js") || uri.startsWith("/images") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) {
|
||||
Counter counter = Counter.builder("http.requests")
|
||||
@@ -36,6 +37,7 @@ public class MetricsFilter extends OncePerRequestFilter {
|
||||
.register(meterRegistry);
|
||||
|
||||
counter.increment();
|
||||
//System.out.println("Counted");
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
@@ -17,9 +17,11 @@ 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.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class MergeController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MergeController.class);
|
||||
@@ -47,7 +49,7 @@ public class MergeController {
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
|
||||
@Operation(
|
||||
summary = "Merge multiple PDF files into one",
|
||||
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided."
|
||||
description = "This endpoint merges multiple PDF files into a single PDF file. The merged file will contain all pages from the input files in the order they were provided. Input:PDF Output:PDF Type:MISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> mergePdfs(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
|
||||
@@ -24,15 +24,17 @@ import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class MultiPageLayoutController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MultiPageLayoutController.class);
|
||||
|
||||
@PostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
|
||||
@Operation(summary = "Merge multiple pages of a PDF document into a single page", description = "This operation takes an input PDF file and the number of pages to merge into a single sheet in the output PDF file.")
|
||||
@Operation(summary = "Merge multiple pages of a PDF document into a single page", description = "This operation takes an input PDF file and the number of pages to merge into a single sheet in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> mergeMultiplePagesIntoOne(
|
||||
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||
@Parameter(description = "The number of pages to fit onto a single sheet in the output PDF. Acceptable values are 2, 3, 4, 9, 16.", required = true, schema = @Schema(type = "integer", allowableValues = {
|
||||
|
||||
@@ -18,16 +18,18 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class RearrangePagesPDFController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RearrangePagesPDFController.class);
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-pages")
|
||||
@Operation(summary = "Remove pages from a PDF file", description = "This endpoint removes specified pages from a given PDF file. Users can provide a comma-separated list of page numbers or ranges to delete.")
|
||||
@Operation(summary = "Remove pages from a PDF file", description = "This endpoint removes specified pages from a given PDF file. Users can provide a comma-separated list of page numbers or ranges to delete. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> deletePages(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file from which pages will be removed") MultipartFile pdfFile,
|
||||
@RequestParam("pagesToDelete") @Parameter(description = "Comma-separated list of pages or page ranges to delete, e.g., '1,3,5-8'") String pagesToDelete)
|
||||
@@ -151,7 +153,7 @@ public class RearrangePagesPDFController {
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
|
||||
@Operation(summary = "Rearrange pages in a PDF file", description = "This endpoint rearranges pages in a given PDF file based on the specified page order or custom mode. Users can provide a page order as a comma-separated list of page numbers or page ranges, or a custom mode.")
|
||||
@Operation(summary = "Rearrange pages in a PDF file", description = "This endpoint rearranges pages in a given PDF file based on the specified page order or custom mode. Users can provide a page order as a comma-separated list of page numbers or page ranges, or a custom mode. Input:PDF Output:PDF")
|
||||
public ResponseEntity<byte[]> rearrangePages(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to rearrange pages") MultipartFile pdfFile,
|
||||
@RequestParam(required = false, value = "pageOrder") @Parameter(description = "The new page order as a comma-separated list of page numbers, page ranges (e.g., '1,3,5-7'), or functions in the format 'an+b' where 'a' is the multiplier of the page number 'n', and 'b' is a constant (e.g., '2n+1', '3n', '6n-5')") String pageOrder,
|
||||
|
||||
@@ -16,9 +16,11 @@ 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.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class RotationController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RotationController.class);
|
||||
@@ -26,7 +28,7 @@ public class RotationController {
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
|
||||
@Operation(
|
||||
summary = "Rotate a PDF file",
|
||||
description = "This endpoint rotates a given PDF file by a specified angle. The angle must be a multiple of 90."
|
||||
description = "This endpoint rotates a given PDF file by a specified angle. The angle must be a multiple of 90. Input:PDF Output:PDF Type:SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> rotatePDF(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
|
||||
@@ -39,15 +39,17 @@ import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class ScalePagesController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ScalePagesController.class);
|
||||
|
||||
@PostMapping(value = "/scale-pages", consumes = "multipart/form-data")
|
||||
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file.")
|
||||
@Operation(summary = "Change the size of a PDF page/document", description = "This operation takes an input PDF file and the size to scale the pages to in the output PDF file. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> scalePages(
|
||||
@Parameter(description = "The input PDF file", required = true) @RequestParam("fileInput") MultipartFile file,
|
||||
@Parameter(description = "The scale of pages in the output PDF. Acceptable values are A0-A10, B0-B9, LETTER, TABLOID, LEDGER, LEGAL, EXECUTIVE.", required = true, schema = @Schema(type = "String", allowableValues = {
|
||||
|
||||
@@ -15,9 +15,6 @@ import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -28,17 +25,20 @@ 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.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class SplitPDFController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SplitPDFController.class);
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/split-pages")
|
||||
@Operation(summary = "Split a PDF file into separate documents",
|
||||
description = "This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page.")
|
||||
public ResponseEntity<Resource> splitPdf(
|
||||
description = "This endpoint splits a given PDF file into separate documents based on the specified page numbers or ranges. Users can specify pages using individual numbers, ranges, or 'all' for every page. Input:PDF Output:PDF Type:SIMO")
|
||||
public ResponseEntity<byte[]> splitPdf(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to be split")
|
||||
MultipartFile file,
|
||||
@@ -97,10 +97,11 @@ public class SplitPDFController {
|
||||
|
||||
Path zipFile = Files.createTempFile("split_documents", ".zip");
|
||||
|
||||
String filename = file.getOriginalFilename().replaceFirst("[.][^.]+$", "");
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile))) {
|
||||
// loop through the split documents and write them to the zip file
|
||||
for (int i = 0; i < splitDocumentsBoas.size(); i++) {
|
||||
String fileName = "split_document_" + (i + 1) + ".pdf";
|
||||
String fileName = filename + "_" + (i + 1) + ".pdf";
|
||||
ByteArrayOutputStream baos = splitDocumentsBoas.get(i);
|
||||
byte[] pdf = baos.toByteArray();
|
||||
|
||||
@@ -119,12 +120,11 @@ public class SplitPDFController {
|
||||
|
||||
logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
|
||||
byte[] data = Files.readAllBytes(zipFile);
|
||||
ByteArrayResource resource = new ByteArrayResource(data);
|
||||
Files.delete(zipFile);
|
||||
|
||||
// return the Resource in the response
|
||||
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_split.zip")
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(resource.contentLength()).body(resource);
|
||||
return WebResponseUtils.bytesToWebResponse(data, filename + ".zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,16 +20,18 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
@RestController
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
public class ConvertImgPDFController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConvertImgPDFController.class);
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-img")
|
||||
@Operation(summary = "Convert PDF to image(s)",
|
||||
description = "This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images.")
|
||||
description = "This endpoint converts a PDF file to image(s) with the specified image format, color type, and DPI. Users can choose to get a single image or multiple images. Input:PDF Output:Image Type:SI-Conditional")
|
||||
public ResponseEntity<Resource> convertToImage(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to be converted")
|
||||
@@ -83,7 +85,7 @@ public class ConvertImgPDFController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/img-to-pdf")
|
||||
@Operation(summary = "Convert images to a PDF file",
|
||||
description = "This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images.")
|
||||
description = "This endpoint converts one or more images to a PDF file. Users can specify whether to stretch the images to fit the PDF page, and whether to automatically rotate the images. Input:Image Output:PDF Type:SISO?")
|
||||
public ResponseEntity<byte[]> convertToPdf(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input images to be converted to a PDF file")
|
||||
@@ -99,7 +101,7 @@ public class ConvertImgPDFController {
|
||||
boolean autoRotate) throws IOException {
|
||||
// Convert the file to PDF and get the resulting bytes
|
||||
byte[] bytes = PdfUtils.imageToPdf(file, stretchToFit, autoRotate, colorType);
|
||||
return WebResponseUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_coverted.pdf");
|
||||
return WebResponseUtils.bytesToWebResponse(bytes, file[0].getOriginalFilename().replaceFirst("[.][^.]+$", "") + "_converted.pdf");
|
||||
}
|
||||
|
||||
private String getMediaType(String imageFormat) {
|
||||
|
||||
@@ -17,10 +17,12 @@ 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 ConvertOfficeController {
|
||||
|
||||
public byte[] convertToPdf(MultipartFile inputFile) throws IOException, InterruptedException {
|
||||
@@ -57,8 +59,8 @@ public class ConvertOfficeController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/file-to-pdf")
|
||||
@Operation(
|
||||
summary = "Convert a file to a PDF using OCR",
|
||||
description = "This endpoint converts a given file to a PDF using Optical Character Recognition (OCR). The filename of the resulting PDF will be the original filename with '_convertedToPDF.pdf' appended."
|
||||
summary = "Convert a file to a PDF using LibreOffice",
|
||||
description = "This endpoint converts a given file to a PDF using LibreOffice API Input:Any Output:PDF Type:SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> processPdfWithOCR(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
|
||||
@@ -12,13 +12,15 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.PDFToFile;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
public class ConvertPDFToOffice {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-html")
|
||||
@Operation(summary = "Convert PDF to HTML", description = "This endpoint converts a PDF file to HTML format.")
|
||||
@Operation(summary = "Convert PDF to HTML", description = "This endpoint converts a PDF file to HTML format. Input:PDF Output:HTML Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToHTML(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to HTML format", required = true) MultipartFile inputFile)
|
||||
throws IOException, InterruptedException {
|
||||
@@ -27,7 +29,7 @@ public class ConvertPDFToOffice {
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-presentation")
|
||||
@Operation(summary = "Convert PDF to Presentation format", description = "This endpoint converts a given PDF file to a Presentation format.")
|
||||
@Operation(summary = "Convert PDF to Presentation format", description = "This endpoint converts a given PDF file to a Presentation format. Input:PDF Output:PPT Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToPresentation(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file") MultipartFile inputFile,
|
||||
@RequestParam("outputFormat") @Parameter(description = "The output Presentation format", schema = @Schema(allowableValues = {
|
||||
@@ -38,7 +40,7 @@ public class ConvertPDFToOffice {
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-text")
|
||||
@Operation(summary = "Convert PDF to Text or RTF format", description = "This endpoint converts a given PDF file to Text or RTF format.")
|
||||
@Operation(summary = "Convert PDF to Text or RTF format", description = "This endpoint converts a given PDF file to Text or RTF format. Input:PDF Output:TXT Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToRTForTXT(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file") MultipartFile inputFile,
|
||||
@RequestParam("outputFormat") @Parameter(description = "The output Text or RTF format", schema = @Schema(allowableValues = {
|
||||
@@ -49,7 +51,7 @@ public class ConvertPDFToOffice {
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-word")
|
||||
@Operation(summary = "Convert PDF to Word document", description = "This endpoint converts a given PDF file to a Word document format.")
|
||||
@Operation(summary = "Convert PDF to Word document", description = "This endpoint converts a given PDF file to a Word document format. Input:PDF Output:WORD Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToWord(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file") MultipartFile inputFile,
|
||||
@RequestParam("outputFormat") @Parameter(description = "The output Word document format", schema = @Schema(allowableValues = {
|
||||
@@ -60,7 +62,7 @@ public class ConvertPDFToOffice {
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/pdf-to-xml")
|
||||
@Operation(summary = "Convert PDF to XML", description = "This endpoint converts a PDF file to an XML file.")
|
||||
@Operation(summary = "Convert PDF to XML", description = "This endpoint converts a PDF file to an XML file. Input:PDF Output:XML Type:SISO")
|
||||
public ResponseEntity<byte[]> processPdfToXML(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to an XML file", required = true) MultipartFile inputFile)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
@@ -14,16 +14,18 @@ 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 ConvertPDFToPDFA {
|
||||
|
||||
@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."
|
||||
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")
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package stirling.software.SPDF.controller.api.filters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
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.PdfUtils;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Filter", description = "Filter APIs")
|
||||
public class FilterController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/contains-text")
|
||||
@Operation(summary = "Checks if a PDF contains set text, returns true if does", description = "Input:PDF Output:Boolean Type:SISO")
|
||||
public Boolean containsText(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
|
||||
@Parameter(description = "The text to check for", required = true) String text,
|
||||
@Parameter(description = "The page number to check for text on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
|
||||
throws IOException, InterruptedException {
|
||||
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
||||
return PdfUtils.hasText(pdfDocument, pageNumber);
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/contains-image")
|
||||
@Operation(summary = "Checks if a PDF contains an image", description = "Input:PDF Output:Boolean Type:SISO")
|
||||
public Boolean containsImage(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file to be converted to a PDF/A file", required = true) MultipartFile inputFile,
|
||||
@Parameter(description = "The page number to check for image on accepts 'All', ranges like '1-4'", required = false) String pageNumber)
|
||||
throws IOException, InterruptedException {
|
||||
PDDocument pdfDocument = PDDocument.load(inputFile.getInputStream());
|
||||
return PdfUtils.hasImagesOnPage(null);
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/page-count")
|
||||
@Operation(summary = "Checks if a PDF is greater, less or equal to a setPageCount", description = "Input:PDF Output:Boolean Type:SISO")
|
||||
public Boolean pageCount(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||
@Parameter(description = "Page Count", required = true) String pageCount,
|
||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
||||
throws IOException, InterruptedException {
|
||||
// Load the PDF
|
||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
||||
int actualPageCount = document.getNumberOfPages();
|
||||
|
||||
// Perform the comparison
|
||||
switch (comparator) {
|
||||
case "Greater":
|
||||
return actualPageCount > Integer.parseInt(pageCount);
|
||||
case "Equal":
|
||||
return actualPageCount == Integer.parseInt(pageCount);
|
||||
case "Less":
|
||||
return actualPageCount < Integer.parseInt(pageCount);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/page-size")
|
||||
@Operation(summary = "Checks if a PDF is of a certain size", description = "Input:PDF Output:Boolean Type:SISO")
|
||||
public Boolean pageSize(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||
@Parameter(description = "Standard Page Size", required = true) String standardPageSize,
|
||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
// Load the PDF
|
||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
||||
|
||||
PDPage firstPage = document.getPage(0);
|
||||
PDRectangle actualPageSize = firstPage.getMediaBox();
|
||||
|
||||
// Calculate the area of the actual page size
|
||||
float actualArea = actualPageSize.getWidth() * actualPageSize.getHeight();
|
||||
|
||||
// Get the standard size and calculate its area
|
||||
PDRectangle standardSize = PdfUtils.textToPageSize(standardPageSize);
|
||||
float standardArea = standardSize.getWidth() * standardSize.getHeight();
|
||||
|
||||
// Perform the comparison
|
||||
switch (comparator) {
|
||||
case "Greater":
|
||||
return actualArea > standardArea;
|
||||
case "Equal":
|
||||
return actualArea == standardArea;
|
||||
case "Less":
|
||||
return actualArea < standardArea;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/file-size")
|
||||
@Operation(summary = "Checks if a PDF is a set file size", description = "Input:PDF Output:Boolean Type:SISO")
|
||||
public Boolean fileSize(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||
@Parameter(description = "File Size", required = true) String fileSize,
|
||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
// Get the file size
|
||||
long actualFileSize = inputFile.getSize();
|
||||
|
||||
// Perform the comparison
|
||||
switch (comparator) {
|
||||
case "Greater":
|
||||
return actualFileSize > Long.parseLong(fileSize);
|
||||
case "Equal":
|
||||
return actualFileSize == Long.parseLong(fileSize);
|
||||
case "Less":
|
||||
return actualFileSize < Long.parseLong(fileSize);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/page-rotation")
|
||||
@Operation(summary = "Checks if a PDF is of a certain rotation", description = "Input:PDF Output:Boolean Type:SISO")
|
||||
public Boolean pageRotation(
|
||||
@RequestPart(required = true, value = "fileInput") @Parameter(description = "The input PDF file", required = true) MultipartFile inputFile,
|
||||
@Parameter(description = "Rotation in degrees", required = true) int rotation,
|
||||
@Parameter(description = "Comparison type, accepts Greater, Equal, Less than", required = false) String comparator)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
// Load the PDF
|
||||
PDDocument document = PDDocument.load(inputFile.getInputStream());
|
||||
|
||||
// Get the rotation of the first page
|
||||
PDPage firstPage = document.getPage(0);
|
||||
int actualRotation = firstPage.getRotation();
|
||||
|
||||
// Perform the comparison
|
||||
switch (comparator) {
|
||||
case "Greater":
|
||||
return actualRotation > rotation;
|
||||
case "Equal":
|
||||
return actualRotation == rotation;
|
||||
case "Less":
|
||||
return actualRotation < rotation;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator: " + comparator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,17 +28,19 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import stirling.software.SPDF.pdf.ImageFinder;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.PdfUtils;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class BlankPageController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-blanks")
|
||||
@Operation(
|
||||
summary = "Remove blank pages from a PDF file",
|
||||
description = "This endpoint removes blank pages from a given PDF file. Users can specify the threshold and white percentage to tune the detection of blank pages."
|
||||
description = "This endpoint removes blank pages from a given PDF file. Users can specify the threshold and white percentage to tune the detection of blank pages. Input:PDF Output:PDF Type:SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> removeBlankPages(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@@ -71,7 +73,7 @@ public class BlankPageController {
|
||||
pagesToKeepIndex.add(pageIndex);
|
||||
System.out.println("page " + pageIndex + " has text");
|
||||
} else {
|
||||
boolean hasImages = hasImagesOnPage(page);
|
||||
boolean hasImages = PdfUtils.hasImagesOnPage(page);
|
||||
if (hasImages) {
|
||||
System.out.println("page " + pageIndex + " has image");
|
||||
|
||||
@@ -120,9 +122,5 @@ public class BlankPageController {
|
||||
}
|
||||
|
||||
|
||||
private static boolean hasImagesOnPage(PDPage page) throws IOException {
|
||||
ImageFinder imageFinder = new ImageFinder(page);
|
||||
imageFinder.processPage(page);
|
||||
return imageFinder.hasImages();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,17 +31,19 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.GeneralUtils;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class CompressController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompressController.class);
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
|
||||
@Operation(summary = "Optimize PDF file", description = "This endpoint accepts a PDF file and optimizes it based on the provided parameters.")
|
||||
@Operation(summary = "Optimize PDF file", description = "This endpoint accepts a PDF file and optimizes it based on the provided parameters. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> optimizePdf(
|
||||
@RequestPart(value = "fileInput") @Parameter(description = "The input PDF file to be optimized.", required = true) MultipartFile inputFile,
|
||||
@RequestParam(required = false, value = "optimizeLevel") @Parameter(description = "The level of optimization to apply to the PDF file. Higher values indicate greater compression but may reduce quality.", schema = @Schema(allowableValues = {
|
||||
|
||||
@@ -31,17 +31,19 @@ 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 = "Other", description = "Other 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.")
|
||||
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(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input file containing image scans")
|
||||
|
||||
@@ -29,15 +29,17 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class ExtractImagesController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ExtractImagesController.class);
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/extract-images")
|
||||
@Operation(summary = "Extract images from a PDF file",
|
||||
description = "This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format.")
|
||||
description = "This endpoint extracts images from a given PDF file and returns them in a zip file. Users can specify the output image format. Input:PDF Output:IMAGE/ZIP Type:SIMO")
|
||||
public ResponseEntity<byte[]> extractImages(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file containing images")
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
package stirling.software.SPDF.controller.api.other;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.AffineTransformOp;
|
||||
//Required for image manipulation
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ConvolveOp;
|
||||
import java.awt.image.Kernel;
|
||||
import java.awt.image.RescaleOp;
|
||||
//Required for file input/output
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
//Other required classes
|
||||
import java.util.Random;
|
||||
|
||||
//Required for image input/output
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -17,46 +36,17 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.itextpdf.io.source.ByteArrayOutputStream;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
//Required for PDF manipulation
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
|
||||
|
||||
//Required for image manipulation
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.RescaleOp;
|
||||
import java.awt.image.AffineTransformOp;
|
||||
import java.awt.image.ConvolveOp;
|
||||
import java.awt.image.Kernel;
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
//Required for image input/output
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
//Required for file input/output
|
||||
import java.io.File;
|
||||
|
||||
//Other required classes
|
||||
import java.util.Random;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
|
||||
@RestController
|
||||
public class FakeScanController {
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class FakeScanControllerWIP {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FakeScanController.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(FakeScanControllerWIP.class);
|
||||
|
||||
//TODO
|
||||
@Hidden
|
||||
@@ -19,9 +19,11 @@ 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.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class MetadataController {
|
||||
|
||||
|
||||
@@ -38,7 +40,7 @@ public class MetadataController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/update-metadata")
|
||||
@Operation(summary = "Update metadata of a PDF file",
|
||||
description = "This endpoint allows you to update the metadata of a given PDF file. You can add, modify, or delete standard and custom metadata fields.")
|
||||
description = "This endpoint allows you to update the metadata of a given PDF file. You can add, modify, or delete standard and custom metadata fields. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> metadata(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to update metadata")
|
||||
@@ -73,6 +75,7 @@ public class MetadataController {
|
||||
@RequestParam(value = "trapped", required = false)
|
||||
@Parameter(description = "The trapped status of the document")
|
||||
String trapped,
|
||||
@Parameter(description = "Map list of key and value of custom parameters, note these must start with customKey and customValue if they are non standard")
|
||||
@RequestParam Map<String, String> allRequestParams)
|
||||
throws IOException {
|
||||
|
||||
|
||||
@@ -27,10 +27,12 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class OCRController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OCRController.class);
|
||||
@@ -47,7 +49,7 @@ public class OCRController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
|
||||
@Operation(summary = "Process a PDF file with OCR",
|
||||
description = "This endpoint processes a PDF file using OCR (Optical Character Recognition). Users can specify languages, sidecar, deskew, clean, cleanFinal, ocrType, ocrRenderType, and removeImagesAfter options.")
|
||||
description = "This endpoint processes a PDF file using OCR (Optical Character Recognition). Users can specify languages, sidecar, deskew, clean, cleanFinal, ocrType, ocrRenderType, and removeImagesAfter options. Input:PDF Output:PDF Type:SI-Conditional")
|
||||
public ResponseEntity<byte[]> processPdfWithOCR(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to be processed with OCR")
|
||||
|
||||
@@ -14,10 +14,12 @@ 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.PdfUtils;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class OverlayImageController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OverlayImageController.class);
|
||||
@@ -25,7 +27,7 @@ public class OverlayImageController {
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/add-image")
|
||||
@Operation(
|
||||
summary = "Overlay image onto a PDF file",
|
||||
description = "This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified."
|
||||
description = "This endpoint overlays an image onto a PDF file at the specified coordinates. The image can be overlaid on every page of the PDF if specified. Input:PDF/IMAGE Output:PDF Type:MF-SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> overlayImage(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
|
||||
@@ -16,10 +16,12 @@ 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 = "Other", description = "Other APIs")
|
||||
public class RepairController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RepairController.class);
|
||||
@@ -27,7 +29,7 @@ public class RepairController {
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/repair")
|
||||
@Operation(
|
||||
summary = "Repair a PDF file",
|
||||
description = "This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response."
|
||||
description = "This endpoint repairs a given PDF file by running Ghostscript command. The PDF is first saved to a temporary location, repaired, read back, and then returned as a response. Input:PDF Output:PDF Type:SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> repairPdf(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
package stirling.software.SPDF.controller.api.pipeline;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.model.PipelineConfig;
|
||||
import stirling.software.SPDF.model.PipelineOperation;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
|
||||
|
||||
@RestController
|
||||
@Tag(name = "Pipeline", description = "Pipeline APIs")
|
||||
public class Controller {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
|
||||
final String jsonFileName = "pipelineCofig.json";
|
||||
final String watchedFoldersDir = "watchedFolders/";
|
||||
@Scheduled(fixedRate = 5000)
|
||||
public void scanFolders() {
|
||||
Path watchedFolderPath = Paths.get(watchedFoldersDir);
|
||||
if (!Files.exists(watchedFolderPath)) {
|
||||
try {
|
||||
Files.createDirectories(watchedFolderPath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
|
||||
paths.filter(Files::isDirectory).forEach(t -> {
|
||||
try {
|
||||
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) {
|
||||
handleDirectory(t);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDirectory(Path dir) throws Exception {
|
||||
Path jsonFile = dir.resolve(jsonFileName);
|
||||
Path processingDir = dir.resolve("processing"); // Directory to move files during processing
|
||||
if (!Files.exists(processingDir)) {
|
||||
Files.createDirectory(processingDir);
|
||||
}
|
||||
|
||||
if (Files.exists(jsonFile)) {
|
||||
// Read JSON file
|
||||
String jsonString;
|
||||
try {
|
||||
jsonString = new String(Files.readAllBytes(jsonFile));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode JSON to PipelineConfig
|
||||
PipelineConfig config;
|
||||
try {
|
||||
config = objectMapper.readValue(jsonString, PipelineConfig.class);
|
||||
// Assuming your PipelineConfig class has getters for all necessary fields, you can perform checks here
|
||||
if (config.getOperations() == null || config.getOutputDir() == null || config.getName() == null) {
|
||||
throw new IOException("Invalid JSON format");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
// For each operation in the pipeline
|
||||
for (PipelineOperation operation : config.getOperations()) {
|
||||
// Collect all files based on fileInput
|
||||
File[] files;
|
||||
String fileInput = (String) operation.getParameters().get("fileInput");
|
||||
if ("automated".equals(fileInput)) {
|
||||
// If fileInput is "automated", process all files in the directory
|
||||
try (Stream<Path> paths = Files.list(dir)) {
|
||||
files = paths.filter(path -> !path.equals(jsonFile))
|
||||
.map(Path::toFile)
|
||||
.toArray(File[]::new);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If fileInput contains a path, process only this file
|
||||
files = new File[]{new File(fileInput)};
|
||||
}
|
||||
|
||||
// Prepare the files for processing
|
||||
File[] filesToProcess = files.clone();
|
||||
for (File file : filesToProcess) {
|
||||
Files.move(file.toPath(), processingDir.resolve(file.getName()));
|
||||
}
|
||||
|
||||
// Process the files
|
||||
try {
|
||||
List<Resource> resources = handleFiles(filesToProcess, jsonString);
|
||||
|
||||
// Move resultant files and rename them as per config in JSON file
|
||||
for (Resource resource : resources) {
|
||||
String outputFileName = config.getOutputPattern().replace("{filename}", resource.getFile().getName());
|
||||
outputFileName = outputFileName.replace("{pipelineName}", config.getName());
|
||||
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
outputFileName = outputFileName.replace("{date}", LocalDate.now().format(dateFormatter));
|
||||
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmmss");
|
||||
outputFileName = outputFileName.replace("{time}", LocalTime.now().format(timeFormatter));
|
||||
// {filename} {folder} {date} {tmime} {pipeline}
|
||||
|
||||
Files.move(resource.getFile().toPath(), Paths.get(config.getOutputDir(), outputFileName));
|
||||
}
|
||||
|
||||
// If successful, delete the original files
|
||||
for (File file : filesToProcess) {
|
||||
Files.deleteIfExists(processingDir.resolve(file.getName()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// If an error occurs, move the original files back
|
||||
for (File file : filesToProcess) {
|
||||
Files.move(processingDir.resolve(file.getName()), file.toPath());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
List<Resource> processFiles(List<Resource> outputFiles, String jsonString) throws Exception{
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonNode = mapper.readTree(jsonString);
|
||||
|
||||
JsonNode pipelineNode = jsonNode.get("pipeline");
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
PrintStream logPrintStream = new PrintStream(logStream);
|
||||
|
||||
boolean hasErrors = false;
|
||||
|
||||
for (JsonNode operationNode : pipelineNode) {
|
||||
String operation = operationNode.get("operation").asText();
|
||||
JsonNode parametersNode = operationNode.get("parameters");
|
||||
String inputFileExtension = "";
|
||||
if(operationNode.has("inputFileType")) {
|
||||
inputFileExtension = operationNode.get("inputFileType").asText();
|
||||
} else {
|
||||
inputFileExtension=".pdf";
|
||||
}
|
||||
|
||||
List<Resource> newOutputFiles = new ArrayList<>();
|
||||
boolean hasInputFileType = false;
|
||||
|
||||
for (Resource file : outputFiles) {
|
||||
if (file.getFilename().endsWith(inputFileExtension)) {
|
||||
hasInputFileType = true;
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("fileInput", file);
|
||||
|
||||
Iterator<Map.Entry<String, JsonNode>> parameters = parametersNode.fields();
|
||||
while (parameters.hasNext()) {
|
||||
Map.Entry<String, JsonNode> parameter = parameters.next();
|
||||
body.add(parameter.getKey(), parameter.getValue().asText());
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
String url = "http://localhost:8080/" + operation;
|
||||
|
||||
ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
||||
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
logPrintStream.println("Error: " + response.getBody());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the response body is a zip file
|
||||
if (isZip(response.getBody())) {
|
||||
// Unzip the file and add all the files to the new output files
|
||||
newOutputFiles.addAll(unzip(response.getBody()));
|
||||
} else {
|
||||
Resource outputResource = new ByteArrayResource(response.getBody()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getFilename(); // Preserving original filename
|
||||
}
|
||||
};
|
||||
newOutputFiles.add(outputResource);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasInputFileType) {
|
||||
logPrintStream.println("No files with extension " + inputFileExtension + " found for operation " + operation);
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
outputFiles = newOutputFiles;
|
||||
}
|
||||
logPrintStream.close();
|
||||
|
||||
}
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
|
||||
List<Resource> handleFiles(File[] files, String jsonString) throws Exception{
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonNode = mapper.readTree(jsonString);
|
||||
|
||||
JsonNode pipelineNode = jsonNode.get("pipeline");
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
PrintStream logPrintStream = new PrintStream(logStream);
|
||||
|
||||
boolean hasErrors = false;
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
|
||||
for (File file : files) {
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
Resource fileResource = new ByteArrayResource(Files.readAllBytes(path)) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getName();
|
||||
}
|
||||
};
|
||||
outputFiles.add(fileResource);
|
||||
}
|
||||
return processFiles(outputFiles, jsonString);
|
||||
}
|
||||
|
||||
List<Resource> handleFiles(MultipartFile[] files, String jsonString) throws Exception{
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonNode = mapper.readTree(jsonString);
|
||||
|
||||
JsonNode pipelineNode = jsonNode.get("pipeline");
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
PrintStream logPrintStream = new PrintStream(logStream);
|
||||
|
||||
boolean hasErrors = false;
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
|
||||
for (MultipartFile file : files) {
|
||||
Resource fileResource = new ByteArrayResource(file.getBytes()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getOriginalFilename();
|
||||
}
|
||||
};
|
||||
outputFiles.add(fileResource);
|
||||
}
|
||||
return processFiles(outputFiles, jsonString);
|
||||
}
|
||||
|
||||
@PostMapping("/handleData")
|
||||
public ResponseEntity<byte[]> handleData(@RequestPart("fileInput") MultipartFile[] files,
|
||||
@RequestParam("json") String jsonString) {
|
||||
try {
|
||||
|
||||
List<Resource> outputFiles = handleFiles(files, jsonString);
|
||||
|
||||
if (outputFiles.size() == 1) {
|
||||
// If there is only one file, return it directly
|
||||
Resource singleFile = outputFiles.get(0);
|
||||
InputStream is = singleFile.getInputStream();
|
||||
byte[] bytes = new byte[(int)singleFile.contentLength()];
|
||||
is.read(bytes);
|
||||
is.close();
|
||||
|
||||
return WebResponseUtils.bytesToWebResponse(bytes, singleFile.getFilename(), MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
// Create a ByteArrayOutputStream to hold the zip
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOut = new ZipOutputStream(baos);
|
||||
|
||||
// Loop through each file and add it to the zip
|
||||
for (Resource file : outputFiles) {
|
||||
ZipEntry zipEntry = new ZipEntry(file.getFilename());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
|
||||
// Read the file into a byte array
|
||||
InputStream is = file.getInputStream();
|
||||
byte[] bytes = new byte[(int)file.contentLength()];
|
||||
is.read(bytes);
|
||||
|
||||
// Write the bytes of the file to the zip
|
||||
zipOut.write(bytes, 0, bytes.length);
|
||||
zipOut.closeEntry();
|
||||
|
||||
is.close();
|
||||
}
|
||||
|
||||
zipOut.close();
|
||||
|
||||
return WebResponseUtils.boasToWebResponse(baos, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isZip(byte[] data) {
|
||||
if (data == null || data.length < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the first four bytes of the data against the standard zip magic number
|
||||
return data[0] == 0x50 && data[1] == 0x4B && data[2] == 0x03 && data[3] == 0x04;
|
||||
}
|
||||
|
||||
private List<Resource> unzip(byte[] data) throws IOException {
|
||||
List<Resource> unzippedFiles = new ArrayList<>();
|
||||
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||
ZipInputStream zis = new ZipInputStream(bais)) {
|
||||
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
|
||||
while ((count = zis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
final String filename = entry.getName();
|
||||
Resource fileResource = new ByteArrayResource(baos.toByteArray()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
};
|
||||
|
||||
// If the unzipped file is a zip file, unzip it
|
||||
if (isZip(baos.toByteArray())) {
|
||||
unzippedFiles.addAll(unzip(baos.toByteArray()));
|
||||
} else {
|
||||
unzippedFiles.add(fileResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unzippedFiles;
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,10 @@ import com.itextpdf.signatures.SignatureUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
@RestController
|
||||
@Tag(name = "Security", description = "Security APIs")
|
||||
public class CertSignController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CertSignController.class);
|
||||
@@ -63,7 +65,7 @@ public class CertSignController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/cert-sign")
|
||||
@Operation(summary = "Sign PDF with a Digital Certificate",
|
||||
description = "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file.")
|
||||
description = "This endpoint accepts a PDF file, a digital certificate and related information to sign the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF Type:MF-SISO")
|
||||
public ResponseEntity<byte[]> signPDF(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to be signed")
|
||||
|
||||
@@ -17,8 +17,10 @@ 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.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
@RestController
|
||||
@Tag(name = "Security", description = "Security APIs")
|
||||
public class PasswordController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PasswordController.class);
|
||||
@@ -27,7 +29,7 @@ public class PasswordController {
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/remove-password")
|
||||
@Operation(
|
||||
summary = "Remove password from a PDF file",
|
||||
description = "This endpoint removes the password from a protected PDF file. Users need to provide the existing password."
|
||||
description = "This endpoint removes the password from a protected PDF file. Users need to provide the existing password. Input:PDF Output:PDF Type:SISO"
|
||||
)
|
||||
public ResponseEntity<byte[]> removePassword(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@@ -44,7 +46,7 @@ public class PasswordController {
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/add-password")
|
||||
@Operation(
|
||||
summary = "Add password to a PDF file",
|
||||
description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file."
|
||||
description = "This endpoint adds password protection to a PDF file. Users can specify a set of permissions that should be applied to the file. Input:PDF Output:PDF"
|
||||
)
|
||||
public ResponseEntity<byte[]> addPassword(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
package stirling.software.SPDF.controller.api.security;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
|
||||
import org.apache.pdfbox.util.Matrix;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -19,18 +27,26 @@ 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.WebResponseUtils;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@RestController
|
||||
@Tag(name = "Security", description = "Security APIs")
|
||||
public class WatermarkController {
|
||||
|
||||
@PostMapping(consumes = "multipart/form-data", value = "/add-watermark")
|
||||
@Operation(summary = "Add watermark to a PDF file",
|
||||
description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark text, font size, rotation, opacity, width spacer, and height spacer.")
|
||||
description = "This endpoint adds a watermark to a given PDF file. Users can specify the watermark text, font size, rotation, opacity, width spacer, and height spacer. Input:PDF Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> addWatermark(
|
||||
@RequestPart(required = true, value = "fileInput")
|
||||
@Parameter(description = "The input PDF file to add a watermark")
|
||||
MultipartFile pdfFile,
|
||||
@RequestParam(defaultValue = "roman", name = "alphabet")
|
||||
@Parameter(description = "The selected alphabet",
|
||||
schema = @Schema(type = "string",
|
||||
allowableValues = {"roman","arabic","japanese","korean","chinese"},
|
||||
defaultValue = "roman"))
|
||||
String alphabet,
|
||||
@RequestParam("watermarkText")
|
||||
@Parameter(description = "The watermark text to add to the PDF file")
|
||||
String watermarkText,
|
||||
@@ -48,11 +64,11 @@ public class WatermarkController {
|
||||
int widthSpacer,
|
||||
@RequestParam(defaultValue = "50", name = "heightSpacer")
|
||||
@Parameter(description = "The height spacer between watermark texts", example = "50")
|
||||
int heightSpacer) throws IOException {
|
||||
int heightSpacer) throws IOException, Exception {
|
||||
|
||||
// Load the input PDF
|
||||
PDDocument document = PDDocument.load(pdfFile.getInputStream());
|
||||
|
||||
String producer = document.getDocumentInformation().getProducer();
|
||||
// Create a page in the document
|
||||
for (PDPage page : document.getPages()) {
|
||||
|
||||
@@ -64,8 +80,40 @@ public class WatermarkController {
|
||||
graphicsState.setNonStrokingAlphaConstant(opacity);
|
||||
contentStream.setGraphicsStateParameters(graphicsState);
|
||||
|
||||
// Set font of watermark
|
||||
PDFont font = PDType1Font.HELVETICA_BOLD;
|
||||
|
||||
String resourceDir = "";
|
||||
PDFont font = PDType1Font.HELVETICA_BOLD;
|
||||
switch (alphabet) {
|
||||
case "arabic":
|
||||
resourceDir = "static/fonts/NotoSansArabic-Regular.ttf";
|
||||
break;
|
||||
case "japanese":
|
||||
resourceDir = "static/fonts/Meiryo.ttf";
|
||||
break;
|
||||
case "korean":
|
||||
resourceDir = "static/fonts/malgun.ttf";
|
||||
break;
|
||||
case "chinese":
|
||||
resourceDir = "static/fonts/SimSun.ttf";
|
||||
break;
|
||||
case "roman":
|
||||
default:
|
||||
resourceDir = "static/fonts/NotoSans-Regular.ttf";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(!resourceDir.equals("")) {
|
||||
ClassPathResource classPathResource = new ClassPathResource(resourceDir);
|
||||
String fileExtension = resourceDir.substring(resourceDir.lastIndexOf("."));
|
||||
File tempFile = File.createTempFile("NotoSansFont", fileExtension);
|
||||
try (InputStream is = classPathResource.getInputStream(); FileOutputStream os = new FileOutputStream(tempFile)) {
|
||||
IOUtils.copy(is, os);
|
||||
}
|
||||
|
||||
font = PDType0Font.load(document, tempFile);
|
||||
tempFile.deleteOnExit();
|
||||
}
|
||||
contentStream.beginText();
|
||||
contentStream.setFont(font, fontSize);
|
||||
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
|
||||
@@ -81,11 +129,19 @@ public class WatermarkController {
|
||||
// Add the watermark text
|
||||
for (int i = 0; i < watermarkRows; i++) {
|
||||
for (int j = 0; j < watermarkCols; j++) {
|
||||
contentStream.setTextMatrix(Matrix.getRotateInstance((float) Math.toRadians(rotation), j * watermarkWidth, i * watermarkHeight));
|
||||
|
||||
if(producer.contains("Google Docs")) {
|
||||
//This fixes weird unknown google docs y axis rotation/flip issue
|
||||
//TODO: Long term fix one day
|
||||
//contentStream.setTextMatrix(1, 0, 0, -1, j * watermarkWidth, pageHeight - i * watermarkHeight);
|
||||
Matrix matrix = new Matrix(1, 0, 0, -1, j * watermarkWidth, pageHeight - i * watermarkHeight);
|
||||
contentStream.setTextMatrix(matrix);
|
||||
} else {
|
||||
contentStream.setTextMatrix(Matrix.getRotateInstance((float) Math.toRadians(rotation), j * watermarkWidth, i * watermarkHeight));
|
||||
}
|
||||
contentStream.showTextWithPositioning(new Object[] { watermarkText });
|
||||
}
|
||||
}
|
||||
|
||||
contentStream.endText();
|
||||
|
||||
// Close the content stream
|
||||
|
||||
@@ -6,8 +6,10 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@Controller
|
||||
@Tag(name = "Convert", description = "Convert APIs")
|
||||
public class ConverterWebController {
|
||||
|
||||
@GetMapping("/img-to-pdf")
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
package stirling.software.SPDF.controller.web;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@Controller
|
||||
@Tag(name = "General", description = "General APIs")
|
||||
public class GeneralWebController {
|
||||
@GetMapping("/pipeline")
|
||||
@Hidden
|
||||
public String pipelineForm(Model model) {
|
||||
model.addAttribute("currentPage", "pipeline");
|
||||
return "pipeline";
|
||||
}
|
||||
|
||||
@GetMapping("/merge-pdfs")
|
||||
@Hidden
|
||||
public String mergePdfForm(Model model) {
|
||||
model.addAttribute("currentPage", "merge-pdfs");
|
||||
return "merge-pdfs";
|
||||
}
|
||||
@GetMapping("/about")
|
||||
@Hidden
|
||||
public String gameForm(Model model) {
|
||||
model.addAttribute("currentPage", "about");
|
||||
return "about";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/multi-tool")
|
||||
@Hidden
|
||||
@@ -29,17 +31,7 @@ public class GeneralWebController {
|
||||
model.addAttribute("currentPage", "multi-tool");
|
||||
return "multi-tool";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Model model) {
|
||||
model.addAttribute("currentPage", "home");
|
||||
return "home";
|
||||
}
|
||||
|
||||
@GetMapping("/home")
|
||||
public String root(Model model) {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/remove-pages")
|
||||
@Hidden
|
||||
@@ -76,20 +68,4 @@ public class GeneralWebController {
|
||||
return "sign";
|
||||
}
|
||||
|
||||
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@ResponseBody
|
||||
@Hidden
|
||||
public String getRobotsTxt() {
|
||||
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISIBILITY");
|
||||
if (allowGoogleVisibility == null)
|
||||
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISIBILITY");
|
||||
if (allowGoogleVisibility == null)
|
||||
allowGoogleVisibility = "false";
|
||||
if (Boolean.parseBoolean(allowGoogleVisibility)) {
|
||||
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
|
||||
} else {
|
||||
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package stirling.software.SPDF.controller.web;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
|
||||
@Controller
|
||||
public class HomeWebController {
|
||||
|
||||
@GetMapping("/about")
|
||||
@Hidden
|
||||
public String gameForm(Model model) {
|
||||
model.addAttribute("currentPage", "about");
|
||||
return "about";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Model model) {
|
||||
model.addAttribute("currentPage", "home");
|
||||
return "home";
|
||||
}
|
||||
|
||||
@GetMapping("/home")
|
||||
public String root(Model model) {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@ResponseBody
|
||||
@Hidden
|
||||
public String getRobotsTxt() {
|
||||
String allowGoogleVisibility = System.getProperty("ALLOW_GOOGLE_VISIBILITY");
|
||||
if (allowGoogleVisibility == null)
|
||||
allowGoogleVisibility = System.getenv("ALLOW_GOOGLE_VISIBILITY");
|
||||
if (allowGoogleVisibility == null)
|
||||
allowGoogleVisibility = "false";
|
||||
if (Boolean.parseBoolean(allowGoogleVisibility)) {
|
||||
return "User-agent: Googlebot\nAllow: /\n\nUser-agent: *\nAllow: /";
|
||||
} else {
|
||||
return "User-agent: Googlebot\nDisallow: /\n\nUser-agent: *\nDisallow: /";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,9 +12,12 @@ import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1")
|
||||
@Tag(name = "API", description = "Info APIs")
|
||||
public class MetricsController {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
@@ -36,17 +39,31 @@ public class MetricsController {
|
||||
@GetMapping("/loads")
|
||||
@Operation(summary = "GET request count",
|
||||
description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.")
|
||||
public Double getPageLoads(@RequestParam Optional<String> endpoint) {
|
||||
public Double getPageLoads(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||
try {
|
||||
double count = 0.0;
|
||||
|
||||
double count = 0.0;
|
||||
|
||||
for (Meter meter : meterRegistry.getMeters()) {
|
||||
if (meter.getId().getName().equals("http.requests")) {
|
||||
String method = meter.getId().getTag("method");
|
||||
if (method != null && method.equals("GET")) {
|
||||
if (meter instanceof Counter) {
|
||||
count += ((Counter) meter).count();
|
||||
}
|
||||
|
||||
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
||||
if(!endpoint.get().startsWith("/")) {
|
||||
endpoint = Optional.of("/" + endpoint.get());
|
||||
}
|
||||
System.out.println("loads " + endpoint.get() + " vs " + meter.getId().getTag("uri"));
|
||||
if(endpoint.get().equals(meter.getId().getTag("uri"))){
|
||||
if (meter instanceof Counter) {
|
||||
count += ((Counter) meter).count();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (meter instanceof Counter) {
|
||||
count += ((Counter) meter).count();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,10 +77,15 @@ public class MetricsController {
|
||||
@GetMapping("/requests")
|
||||
@Operation(summary = "POST request count",
|
||||
description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.")
|
||||
public Double getTotalRequests(@RequestParam Optional<String> endpoint) {
|
||||
public Double getTotalRequests(@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional<String> endpoint) {
|
||||
try {
|
||||
Counter counter;
|
||||
if (endpoint.isPresent()) {
|
||||
if (endpoint.isPresent() && !endpoint.get().isBlank()) {
|
||||
if(!endpoint.get().startsWith("/")) {
|
||||
endpoint = Optional.of("/" + endpoint.get());
|
||||
}
|
||||
|
||||
System.out.println("loads " + endpoint.get() + " vs " + meterRegistry.get("http.requests").tags("uri", endpoint.get()).toString());
|
||||
counter = meterRegistry.get("http.requests")
|
||||
.tags("method", "POST", "uri", endpoint.get()).counter();
|
||||
} else {
|
||||
@@ -72,7 +94,8 @@ public class MetricsController {
|
||||
}
|
||||
return counter.count();
|
||||
} catch (Exception e) {
|
||||
return -1.0;
|
||||
e.printStackTrace();
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,10 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@Controller
|
||||
@Tag(name = "Other", description = "Other APIs")
|
||||
public class OtherWebController {
|
||||
@GetMapping("/compress-pdf")
|
||||
@Hidden
|
||||
@@ -74,7 +76,9 @@ public class OtherWebController {
|
||||
@Hidden
|
||||
public ModelAndView ocrPdfPage() {
|
||||
ModelAndView modelAndView = new ModelAndView("other/ocr-pdf");
|
||||
modelAndView.addObject("languages", getAvailableTesseractLanguages());
|
||||
List<String> languages = getAvailableTesseractLanguages();
|
||||
Collections.sort(languages);
|
||||
modelAndView.addObject("languages", languages);
|
||||
modelAndView.addObject("currentPage", "ocr-pdf");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@Controller
|
||||
@Tag(name = "Security", description = "Security APIs")
|
||||
public class SecurityWebController {
|
||||
@GetMapping("/add-password")
|
||||
@Hidden
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package stirling.software.SPDF.model;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class PipelineConfig {
|
||||
private String name;
|
||||
|
||||
@JsonProperty("pipeline")
|
||||
private List<PipelineOperation> operations;
|
||||
|
||||
private String outputDir;
|
||||
|
||||
@JsonProperty("outputFileName")
|
||||
private String outputPattern;
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<PipelineOperation> getOperations() {
|
||||
return operations;
|
||||
}
|
||||
|
||||
public void setOperations(List<PipelineOperation> operations) {
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
public String getOutputDir() {
|
||||
return outputDir;
|
||||
}
|
||||
|
||||
public void setOutputDir(String outputDir) {
|
||||
this.outputDir = outputDir;
|
||||
}
|
||||
|
||||
public String getOutputPattern() {
|
||||
return outputPattern;
|
||||
}
|
||||
|
||||
public void setOutputPattern(String outputPattern) {
|
||||
this.outputPattern = outputPattern;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package stirling.software.SPDF.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PipelineOperation {
|
||||
private String operation;
|
||||
private Map<String, Object> parameters;
|
||||
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public void setOperation(String operation) {
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public Map<String, Object> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(Map<String, Object> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
@@ -27,14 +27,179 @@ import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
import org.apache.pdfbox.text.PDFTextStripper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.itextpdf.kernel.pdf.PdfPage;
|
||||
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
|
||||
import com.itextpdf.kernel.pdf.canvas.parser.listener.SimpleTextExtractionStrategy;
|
||||
|
||||
import stirling.software.SPDF.pdf.ImageFinder;
|
||||
|
||||
public class PdfUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
|
||||
|
||||
|
||||
public static PDRectangle textToPageSize(String size) {
|
||||
switch (size) {
|
||||
case "A0":
|
||||
return PDRectangle.A0;
|
||||
case "A1":
|
||||
return PDRectangle.A1;
|
||||
case "A2":
|
||||
return PDRectangle.A2;
|
||||
case "A3":
|
||||
return PDRectangle.A3;
|
||||
case "A4":
|
||||
return PDRectangle.A4;
|
||||
case "A5":
|
||||
return PDRectangle.A5;
|
||||
case "A6":
|
||||
return PDRectangle.A6;
|
||||
case "LETTER":
|
||||
return PDRectangle.LETTER;
|
||||
case "LEGAL":
|
||||
return PDRectangle.LEGAL;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid standard page size: " + size);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasImageInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
|
||||
PDFTextStripper textStripper = new PDFTextStripper();
|
||||
String pdfText = "";
|
||||
|
||||
if(pagesToCheck == null || pagesToCheck.equals("all")) {
|
||||
pdfText = textStripper.getText(pdfDocument);
|
||||
} else {
|
||||
// remove whitespaces
|
||||
pagesToCheck = pagesToCheck.replaceAll("\\s+", "");
|
||||
|
||||
String[] splitPoints = pagesToCheck.split(",");
|
||||
for (String splitPoint : splitPoints) {
|
||||
if (splitPoint.contains("-")) {
|
||||
// Handle page ranges
|
||||
String[] range = splitPoint.split("-");
|
||||
int startPage = Integer.parseInt(range[0]);
|
||||
int endPage = Integer.parseInt(range[1]);
|
||||
|
||||
for (int i = startPage; i <= endPage; i++) {
|
||||
textStripper.setStartPage(i);
|
||||
textStripper.setEndPage(i);
|
||||
pdfText += textStripper.getText(pdfDocument);
|
||||
}
|
||||
} else {
|
||||
// Handle individual page
|
||||
int page = Integer.parseInt(splitPoint);
|
||||
textStripper.setStartPage(page);
|
||||
textStripper.setEndPage(page);
|
||||
pdfText += textStripper.getText(pdfDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdfDocument.close();
|
||||
|
||||
return pdfText.contains(text);
|
||||
}
|
||||
|
||||
public static boolean hasImagesOnPage(PDPage page) throws IOException {
|
||||
ImageFinder imageFinder = new ImageFinder(page);
|
||||
imageFinder.processPage(page);
|
||||
return imageFinder.hasImages();
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasText(PDDocument document, String phrase) throws IOException {
|
||||
PDFTextStripper pdfStripper = new PDFTextStripper();
|
||||
String text = pdfStripper.getText(document);
|
||||
return text.contains(phrase);
|
||||
}
|
||||
|
||||
|
||||
public boolean containsTextInFile(PDDocument pdfDocument, String text, String pagesToCheck) throws IOException {
|
||||
PDFTextStripper textStripper = new PDFTextStripper();
|
||||
String pdfText = "";
|
||||
|
||||
if(pagesToCheck == null || pagesToCheck.equals("all")) {
|
||||
pdfText = textStripper.getText(pdfDocument);
|
||||
} else {
|
||||
// remove whitespaces
|
||||
pagesToCheck = pagesToCheck.replaceAll("\\s+", "");
|
||||
|
||||
String[] splitPoints = pagesToCheck.split(",");
|
||||
for (String splitPoint : splitPoints) {
|
||||
if (splitPoint.contains("-")) {
|
||||
// Handle page ranges
|
||||
String[] range = splitPoint.split("-");
|
||||
int startPage = Integer.parseInt(range[0]);
|
||||
int endPage = Integer.parseInt(range[1]);
|
||||
|
||||
for (int i = startPage; i <= endPage; i++) {
|
||||
textStripper.setStartPage(i);
|
||||
textStripper.setEndPage(i);
|
||||
pdfText += textStripper.getText(pdfDocument);
|
||||
}
|
||||
} else {
|
||||
// Handle individual page
|
||||
int page = Integer.parseInt(splitPoint);
|
||||
textStripper.setStartPage(page);
|
||||
textStripper.setEndPage(page);
|
||||
pdfText += textStripper.getText(pdfDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdfDocument.close();
|
||||
|
||||
return pdfText.contains(text);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean pageCount(PDDocument pdfDocument, int pageCount, String comparator) throws IOException {
|
||||
int actualPageCount = pdfDocument.getNumberOfPages();
|
||||
pdfDocument.close();
|
||||
|
||||
switch(comparator.toLowerCase()) {
|
||||
case "greater":
|
||||
return actualPageCount > pageCount;
|
||||
case "equal":
|
||||
return actualPageCount == pageCount;
|
||||
case "less":
|
||||
return actualPageCount < pageCount;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid comparator. Only 'greater', 'equal', and 'less' are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean pageSize(PDDocument pdfDocument, String expectedPageSize) throws IOException {
|
||||
PDPage firstPage = pdfDocument.getPage(0);
|
||||
PDRectangle mediaBox = firstPage.getMediaBox();
|
||||
|
||||
float actualPageWidth = mediaBox.getWidth();
|
||||
float actualPageHeight = mediaBox.getHeight();
|
||||
|
||||
pdfDocument.close();
|
||||
|
||||
// Assumes the expectedPageSize is in the format "widthxheight", e.g. "595x842" for A4
|
||||
String[] dimensions = expectedPageSize.split("x");
|
||||
float expectedPageWidth = Float.parseFloat(dimensions[0]);
|
||||
float expectedPageHeight = Float.parseFloat(dimensions[1]);
|
||||
|
||||
// Checks if the actual page size matches the expected page size
|
||||
return actualPageWidth == expectedPageWidth && actualPageHeight == expectedPageHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static byte[] convertFromPdf(byte[] inputStream, String imageType, ImageType colorType, boolean singleImage, int DPI, String filename) throws IOException, Exception {
|
||||
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(inputStream))) {
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(document);
|
||||
@@ -43,7 +208,7 @@ public class PdfUtils {
|
||||
|
||||
// Create images of all pages
|
||||
for (int i = 0; i < pageCount; i++) {
|
||||
images.add(pdfRenderer.renderImageWithDPI(i, 300, colorType));
|
||||
images.add(pdfRenderer.renderImageWithDPI(i, DPI, colorType));
|
||||
}
|
||||
|
||||
if (singleImage) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
spring.http.multipart.max-file-size=2GB
|
||||
spring.http.multipart.max-request-size=2GB
|
||||
spring.http.multipart.max-file-size=${MAX_FILE_SIZE:2000MB}
|
||||
spring.http.multipart.max-request-size=${MAX_FILE_SIZE:2000MB}
|
||||
|
||||
multipart.enabled=true
|
||||
multipart.max-file-size=2000MB
|
||||
multipart.max-request-size=2000MB
|
||||
multipart.max-file-size=${MAX_FILE_SIZE:2000MB}
|
||||
multipart.max-request-size=${MAX_FILE_SIZE:2000MB}
|
||||
|
||||
spring.servlet.multipart.max-file-size=2000MB
|
||||
spring.servlet.multipart.max-request-size=2000MB
|
||||
spring.servlet.multipart.max-file-size=${MAX_FILE_SIZE:2000MB}
|
||||
spring.servlet.multipart.max-request-size=${MAX_FILE_SIZE:2000MB}
|
||||
|
||||
server.forward-headers-strategy=NATIVE
|
||||
|
||||
@@ -22,7 +22,7 @@ server.servlet.context-path=${APP_ROOT_PATH:/}
|
||||
spring.devtools.restart.enabled=true
|
||||
spring.devtools.livereload.enabled=true
|
||||
|
||||
spring.thymeleaf.encoding=UTF-8
|
||||
spring.thymeleaf.encoding=UTF-8
|
||||
|
||||
server.connection-timeout=${CONNECTION_TIMEOUT:5m}
|
||||
spring.mvc.async.request-timeout=${ASYNC_CONNECTION_TIMEOUT:300000}
|
||||
|
||||
@@ -24,7 +24,7 @@ close=\u0625\u063A\u0644\u0627\u0642
|
||||
filesSelected = الملفات المحددة
|
||||
noFavourites = لم تتم إضافة أي مفضلات
|
||||
bored = الانتظار بالملل؟
|
||||
|
||||
alphabet=\u0627\u0644\u0623\u0628\u062C\u062F\u064A\u0629
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -129,6 +129,9 @@ home.repair.desc = يحاول إصلاح ملف PDF تالف / معطل
|
||||
home.removeBlanks.title = إزالة الصفحات الفارغة
|
||||
home.removeBlanks.desc = يكتشف ويزيل الصفحات الفارغة من المستند
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.compare.title = قارن
|
||||
home.compare.desc = يقارن ويظهر الاختلافات بين 2 من مستندات PDF
|
||||
|
||||
@@ -261,6 +264,7 @@ fileToPDF.submit=\u062A\u062D\u0648\u064A\u0644 \u0625\u0644\u0649 PDF
|
||||
addImage.title=إضافة صورة
|
||||
addImage.header=إضافة صورة إلى PDF
|
||||
addImage.everyPage=كل صفحة؟
|
||||
addImage.upload=إضافة صورة
|
||||
addImage.submit=إضافة صورة
|
||||
|
||||
#compress
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Tanca
|
||||
filesSelected=fitxers seleccionats
|
||||
noFavourites=No s'ha afegit cap favorit
|
||||
bored=Avorrit esperant?
|
||||
alphabet=Alfabet
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -122,6 +123,9 @@ home.repair.desc=Intenta reparar un PDF danyat o trencat
|
||||
home.removeBlanks.title=Elimina les pàgines en blanc
|
||||
home.removeBlanks.desc=Detecta i elimina les pàgines en blanc d'un document
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.compare.title=Compara
|
||||
home.compare.desc=Compara i mostra les diferències entre 2 documents PDF
|
||||
|
||||
@@ -269,6 +273,7 @@ compress.submit=Comprimir
|
||||
addImage.title=Afegir Imatge
|
||||
addImage.header=Afegir Imatge a PDF (en construcció)
|
||||
addImage.everyPage=Totes les pàgines?
|
||||
addImage.upload=Afegir Imatge
|
||||
addImage.submit=Afegir Imatge
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Schließen
|
||||
filesSelected=Dateien ausgewählt
|
||||
noFavourites=Keine Favoriten hinzugefügt
|
||||
bored=Gelangweiltes Warten?
|
||||
alphabet=Alphabet
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -121,6 +122,9 @@ home.repair.desc=Versucht, ein beschädigtes/kaputtes PDF zu reparieren
|
||||
home.removeBlanks.title=Leere Seiten entfernen
|
||||
home.removeBlanks.desc=Erkennt und entfernt leere Seiten aus einem Dokument
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.compare.title=Vergleichen
|
||||
home.compare.desc=Vergleicht und zeigt die Unterschiede zwischen zwei PDF-Dokumenten an
|
||||
|
||||
@@ -256,6 +260,7 @@ fileToPDF.submit=In PDF konvertieren
|
||||
addImage.title=Bild hinzufügen
|
||||
addImage.header=Ein Bild einfügen
|
||||
addImage.everyPage=Jede Seite?
|
||||
addImage.upload=Bild hinzufügen
|
||||
addImage.submit=Bild hinzufügen
|
||||
|
||||
#compress
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Close
|
||||
filesSelected=files selected
|
||||
noFavourites=No favourites added
|
||||
bored=Bored Waiting?
|
||||
alphabet=Alphabet
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -131,6 +132,9 @@ home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||
home.scalePages.title=Adjust page size/scale
|
||||
home.scalePages.desc=Change the size/scale of a page and/or its contents.
|
||||
|
||||
home.pipeline.title=Pipeline
|
||||
home.pipeline.desc=Pipeline desc.
|
||||
|
||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||
|
||||
downloadPdf=Download PDF
|
||||
@@ -139,6 +143,8 @@ font=Font
|
||||
selectFillter=-- Select --
|
||||
pageNum=Page Number
|
||||
|
||||
pipeline.title=Pipeline
|
||||
|
||||
pageLayout.title=Multi Page Layout
|
||||
pageLayout.header=Multi Page Layout
|
||||
pageLayout.pagesPerSheet=Pages per sheet:
|
||||
@@ -273,6 +279,7 @@ compress.submit=Compress
|
||||
addImage.title=Add Image
|
||||
addImage.header=Add image to PDF
|
||||
addImage.everyPage=Every Page?
|
||||
addImage.upload=Add image
|
||||
addImage.submit=Add image
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ imgPrompt=Seleccionar Imagen(es)
|
||||
genericSubmit=Enviar
|
||||
processTimeWarning=Advertencia: este proceso puede tardar hasta un minuto dependiendo del tamaño del archivo
|
||||
pageOrderPrompt=Orden de páginas (Introduzca una lista de números de página separados por coma):
|
||||
goToPage=Ir
|
||||
goToPage=Ir a
|
||||
true=Verdadero
|
||||
false=Falso
|
||||
unknown=Desconocido
|
||||
@@ -20,10 +20,11 @@ close=Cerrar
|
||||
filesSelected=archivos seleccionados
|
||||
noFavourites=No se agregaron favoritos
|
||||
bored=¿Aburrido de esperar?
|
||||
alphabet=Alfabeto
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
home.desc=Tu autohospedada ventanilla única para todas tus necesidades PDF.
|
||||
home.desc=Tu ventanilla única autohospedada para todas tus necesidades PDF
|
||||
|
||||
navbar.convert=Convertir
|
||||
navbar.security=Seguridad
|
||||
@@ -35,19 +36,19 @@ home.multiTool.title=Multi-herramienta PDF
|
||||
home.multiTool.desc=Combinar, rotar, reorganizar y eliminar páginas
|
||||
|
||||
home.merge.title=Unir
|
||||
home.merge.desc=Unir fácilmente múltiples PDFs en uno.
|
||||
home.merge.desc=Unir fácilmente múltiples PDFs en uno
|
||||
|
||||
home.split.title=Dividir
|
||||
home.split.desc=Dividir PDFs en múltiples documentos
|
||||
|
||||
home.rotate.title=Rotar
|
||||
home.rotate.desc=Rotar fácilmente tus PDFs.
|
||||
home.rotate.desc=Rotar fácilmente tus PDFs
|
||||
|
||||
home.imageToPdf.title=Imagen a PDF
|
||||
home.imageToPdf.desc=Convertir una imagen (PNG, JPEG, GIF) a PDF.
|
||||
home.imageToPdf.desc=Convertir una imagen (PNG, JPEG, GIF) a PDF
|
||||
|
||||
home.pdfToImage.title=PDF a Imagen
|
||||
home.pdfToImage.desc=Convertir un PDF a una imagen. (PNG, JPEG, GIF)
|
||||
home.pdfToImage.desc=Convertir un PDF a una imagen (PNG, JPEG, GIF)
|
||||
|
||||
home.pdfOrganiser.title=Organizador
|
||||
home.pdfOrganiser.desc=Eliminar/Reorganizar páginas en cualquier orden
|
||||
@@ -56,37 +57,37 @@ home.addImage.title=Agregar imagen al PDF
|
||||
home.addImage.desc=Agregar una imagen en una ubicación establecida en el PDF (trabajo en progreso)
|
||||
|
||||
home.watermark.title=Añadir marca de agua
|
||||
home.watermark.desc=Añadir una marca de agua predefinida a tu documento PDF.
|
||||
home.watermark.desc=Añadir una marca de agua predefinida al documento PDF
|
||||
|
||||
home.remove-watermark.title=Eliminar marca de agua
|
||||
home.remove-watermark.desc=Eliminar marcas de agua de tu documento PDF.
|
||||
home.remove-watermark.desc=Eliminar marca de agua de tu documento PDF
|
||||
|
||||
home.permissions.title=Cambiar Permisos
|
||||
home.permissions.desc=Cambiar los permisos de tu documento PDF
|
||||
home.permissions.title=Cambiar permisos
|
||||
home.permissions.desc=Cambiar los permisos del documento PDF
|
||||
|
||||
home.removePages.title=Eliminar
|
||||
home.removePages.desc=Eliminar páginas no deseadas de tu documento PDF.
|
||||
home.removePages.desc=Eliminar páginas no deseadas del documento PDF
|
||||
|
||||
home.addPassword.title=Añadir Contraseña
|
||||
home.addPassword.desc=Encriptar el documento PDF con una contraseña.
|
||||
home.addPassword.title=Añadir contraseña
|
||||
home.addPassword.desc=Encriptar el documento PDF con una contraseña
|
||||
|
||||
home.removePassword.title=Eliminar Contraseña
|
||||
home.removePassword.desc=Eliminar la contraseña del documento PDF.
|
||||
home.removePassword.title=Eliminar contraseña
|
||||
home.removePassword.desc=Eliminar la contraseña del documento PDF
|
||||
|
||||
home.compressPdfs.title=Comprimir
|
||||
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del fichero.
|
||||
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del fichero
|
||||
|
||||
home.changeMetadata.title=Cambiar Metadatos
|
||||
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF.
|
||||
home.changeMetadata.title=Cambiar metadatos
|
||||
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
||||
|
||||
home.fileToPDF.title=Convertir fichero a PDF
|
||||
home.fileToPDF.desc=Convertir casi cualquier archivo a PDF (DOCX, PNG, XLS, PPT, TXT y más)
|
||||
|
||||
home.ocr.title=Ejecutar OCR en PDF y/o escaneos de limpieza
|
||||
home.ocr.desc=Escaneos de limpieza y detecta texto de imágenes dentro de un PDF y lo vuelve a agregar como texto.
|
||||
home.ocr.desc=Escaneos de limpieza y detectar texto de imágenes dentro de un PDF y volver a agregarlo como texto
|
||||
|
||||
home.extractImages.title=Extraer imágenes
|
||||
home.extractImages.desc=Extraer todas las imágenes de un PDF y guardarlas en zip
|
||||
home.extractImages.desc=Extraer todas las imágenes de un PDF y guardarlas en ZIP
|
||||
|
||||
home.pdfToPDFA.title=Convertir PDF a PDF/A
|
||||
home.pdfToPDFA.desc=Convertir PDF a PDF/A para almacenamiento a largo plazo
|
||||
@@ -110,27 +111,30 @@ home.ScannerImageSplit.title=Detectar/Dividir fotos escaneadas
|
||||
home.ScannerImageSplit.desc=Dividir varias fotos dentro de una foto/PDF
|
||||
|
||||
home.sign.title=Firmar
|
||||
home.sign.desc=Añade firma a PDF mediante dibujo, texto o imagen
|
||||
home.sign.desc=Añadir firma a PDF mediante dibujo, texto o imagen
|
||||
|
||||
home.flatten.title=Aplanar
|
||||
home.flatten.desc=Eliminar todos los elementos y formularios interactivos de un PDF
|
||||
|
||||
home.repair.title=Reparar
|
||||
home.repair.desc=Intenta reparar un PDF corrupto/roto
|
||||
home.repair.desc=Intentar reparar un PDF corrupto/roto
|
||||
|
||||
home.removeBlanks.title=Eliminar páginas en blanco
|
||||
home.removeBlanks.descdetecta y elimina páginas en blanco de un documento
|
||||
home.removeBlanks.desc=Detectar y eliminar páginas en blanco de un documento
|
||||
|
||||
home.certSign.title=Firmar con certificado
|
||||
home.certSign.desc=Firmar un PDF con un Certificado/Clave (PEM/P12)
|
||||
|
||||
home.compare.title=Comparar
|
||||
home.compare.desc=Compara y muestra las diferencias entre 2 documentos PDF
|
||||
home.compare.desc=Comparar y mostrar las diferencias entre 2 documentos PDF
|
||||
|
||||
home.pageLayout.title=Multi-Page Layout
|
||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||
home.pageLayout.title=Diseño de varias páginas
|
||||
home.pageLayout.desc=Unir varias páginas de un documento PDF en una sola página
|
||||
|
||||
home.scalePages.title=Adjust page size/scale
|
||||
home.scalePages.desc=Change the size/scale of page and/or its contents.
|
||||
home.scalePages.title=Escalar/ajustar tamaño de página
|
||||
home.scalePages.desc=Escalar/cambiar el tamaño de una pagina y/o su contenido
|
||||
|
||||
error.pdfPassword=The PDF Document is passworded and either the password was not provided or was incorrect
|
||||
error.pdfPassword=El documento PDF está protegido con contraseña y no se ha proporcionado o es incorrecta
|
||||
|
||||
downloadPdf=Descargar PDF
|
||||
text=Texto
|
||||
@@ -138,19 +142,19 @@ font=Fuente
|
||||
selectFilter=-- Seleccionar --
|
||||
pageNum=Número de página
|
||||
|
||||
pageLayout.title=Multi Page Layout
|
||||
pageLayout.header=Multi Page Layout
|
||||
pageLayout.pagesPerSheet=Pages per sheet:
|
||||
pageLayout.submit=Submit
|
||||
pageLayout.title=Diseño de varias páginas
|
||||
pageLayout.header=Diseño de varias páginas
|
||||
pageLayout.pagesPerSheet=Páginas por hoja:
|
||||
pageLayout.submit=Entregar
|
||||
|
||||
scalePages.title=Adjust page-scale
|
||||
scalePages.header=Adjust page-scale
|
||||
scalePages.pageSize=Size of a page of the document.
|
||||
scalePages.scaleFactor=Zoom level (crop) of a page.
|
||||
scalePages.submit=Submit
|
||||
scalePages.title=Ajustar escala de la página
|
||||
scalePages.header=Adjustar escala de la página
|
||||
scalePages.pageSize=Tamaño de la página del documento
|
||||
scalePages.scaleFactor=Nivel de zoom (recorte) de la página
|
||||
scalePages.submit=Entregar
|
||||
|
||||
certSign.title=Firma de certificado
|
||||
certSign.header=Firme un PDF con su certificado (Trabajo en progreso)
|
||||
certSign.header=Firmar un PDF con su certificado (Trabajo en progreso)
|
||||
certSign.selectPDF=Seleccione un archivo PDF para firmar:
|
||||
certSign.selectKey=Seleccione su archivo de clave privada (formato PKCS#8, podría ser .pem o .der):
|
||||
certSign.selectCert=Seleccione su archivo de certificado (formato X.509, podría ser .pem o .der):
|
||||
@@ -194,13 +198,13 @@ flatten.header=Acoplar archivos PDF
|
||||
flatten.submit=Aplanar
|
||||
|
||||
ScannerImageSplit.selectText.1=Umbral de ángulo:
|
||||
ScannerImageSplit.selectText.2=Establece el ángulo absoluto mínimo requerido para rotar la imagen (predeterminado: 10).
|
||||
ScannerImageSplit.selectText.2=Establecer el ángulo absoluto mínimo requerido para rotar la imagen (predeterminado: 10).
|
||||
ScannerImageSplit.selectText.3=Tolerancia:
|
||||
ScannerImageSplit.selectText.4=Determina el rango de variación de color alrededor del color de fondo estimado (predeterminado: 30).
|
||||
ScannerImageSplit.selectText.4=Determinar el rango de variación de color alrededor del color de fondo estimado (predeterminado: 30).
|
||||
ScannerImageSplit.selectText.5=Área mínima:
|
||||
ScannerImageSplit.selectText.6=Establece el umbral mínimo de área para una foto (predeterminado: 10000).
|
||||
ScannerImageSplit.selectText.6=Establecer el umbral mínimo de área para una foto (predeterminado: 10000).
|
||||
ScannerImageSplit.selectText.7=Área de contorno mínima:
|
||||
ScannerImageSplit.selectText.8=Establece el umbral mínimo del área de contorno para una foto
|
||||
ScannerImageSplit.selectText.8=Establecer el umbral mínimo del área de contorno para una foto
|
||||
ScannerImageSplit.selectText.9=Tamaño del borde:
|
||||
ScannerImageSplit.selectText.10=Establece el tamaño del borde agregado y eliminado para evitar bordes blancos en la salida (predeterminado: 1).
|
||||
|
||||
@@ -208,10 +212,10 @@ navbar.settings=Ajustes
|
||||
settings.title=Ajustes
|
||||
settings.update=Actualización disponible
|
||||
settings.appVersion=Versión de la aplicación:
|
||||
settings.downloadOption.title=Elige la opción de descarga (para descargas de un solo archivo sin ZIP):
|
||||
settings.downloadOption.1=Abre en la misma ventana
|
||||
settings.downloadOption.2=Abre en una nueva ventana
|
||||
settings.downloadOption.3=Descarga el fichero
|
||||
settings.downloadOption.title=Elegir la opción de descarga (para descargas de un solo archivo sin ZIP):
|
||||
settings.downloadOption.1=Abrir en la misma ventana
|
||||
settings.downloadOption.2=Abrir en una nueva ventana
|
||||
settings.downloadOption.3=Descargar el fichero
|
||||
settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descargados
|
||||
|
||||
|
||||
@@ -220,54 +224,55 @@ settings.zipThreshold=Ficheros ZIP cuando excede el número de ficheros descarga
|
||||
#OCR
|
||||
ocr.title=OCR / Escaneo de limpieza
|
||||
ocr.header=Escaneos de limpieza / OCR (Reconocimiento óptico de caracteres)
|
||||
ocr.selectText.1=Selecciona los idiomas que se detectarán en el PDF (Los enumerados son los detectados actualmente):
|
||||
ocr.selectText.2=Produzca un archivo de texto que contenga texto OCR junto con el PDF editado con OCR
|
||||
ocr.selectText.3=Corrija las páginas que se escanearon en un ángulo torcido girándolas nuevamente a su lugar
|
||||
ocr.selectText.4=Limpie la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo. (Sin cambio de salida)
|
||||
ocr.selectText.5=Limpie la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo, mantiene la limpieza en la salida.
|
||||
ocr.selectText.6=Ignora las páginas que tienen texto interactivo, solo las páginas OCR que son imágenes
|
||||
ocr.selectText.7=Fuerza OCR, OCR eliminará en cada página todo el texto original
|
||||
ocr.selectText.8=Normal (Se producirá un error si el PDF contiene texto)
|
||||
ocr.selectText.9=Ajustes Adicionales
|
||||
ocr.selectText.1=Seleccionar los idiomas que se detectarán en el PDF (Los enumerados son los detectados actualmente):
|
||||
ocr.selectText.2=Producir un archivo de texto que contenga texto OCR junto con el PDF editado con OCR
|
||||
ocr.selectText.3=Corregir las páginas que se escanearon en un ángulo torcido girándolas nuevamente a su lugar
|
||||
ocr.selectText.4=Limpiar la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo (Sin cambio de salida)
|
||||
ocr.selectText.5=Limpiar la página para que sea menos probable que el OCR encuentre texto en el ruido de fondo, mantiene la limpieza en la salida.
|
||||
ocr.selectText.6=Ignorar las páginas que tienen texto interactivo, solo las páginas OCR que son imágenes
|
||||
ocr.selectText.7=Forzar OCR, OCR eliminará en cada página todo el texto original
|
||||
ocr.selectText.8=Normal (se producirá un error si el PDF contiene texto)
|
||||
ocr.selectText.9=Ajustes adicionales
|
||||
ocr.selectText.10=Modo OCR
|
||||
ocr.selectText.11=Eliminar imágenes después de OCR (Elimina TODAS las imágenes, solo es útil si es parte del paso de conversión)
|
||||
ocr.selectText.12=Tipo de procesamiento (avanzado)
|
||||
ocr.help=Lea esta documentación sobre cómo usar esto para otros idiomas y/o no usarlo en docker
|
||||
ocr.credit=Este servicio utiliza OCRmyPDF y Tesseract para OCR.
|
||||
ocr.submit=Procesa PDF con OCR
|
||||
ocr.help=Lea esta documentación sobre cómo usar esto para otros idiomas y/o no usarlo en Docker
|
||||
ocr.credit=Este servicio utiliza OCRmyPDF y Tesseract para OCR
|
||||
ocr.submit=Procesar PDF con OCR
|
||||
|
||||
|
||||
|
||||
extractImages.title=Extraer imágenes
|
||||
extractImages.header=Extraer imágenes
|
||||
extractImages.selectText=Selecciona el formato de imagen para convertir las imágenes extraídas
|
||||
extractImages.selectText=Seleccionar el formato de imagen para convertir las imágenes extraídas
|
||||
extractImages.submit=Extraer
|
||||
|
||||
|
||||
#File to PDF
|
||||
fileToPDF.title=Fichero a PDF
|
||||
fileToPDF.header=Convierte cualquier fichero a PDF
|
||||
fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de ficheros.
|
||||
fileToPDF.supportedFileTypes=Los tipos de ficheros soportados deben incluir los de abajo; sin embargo para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
|
||||
fileToPDF.title=Archivo a PDF
|
||||
fileToPDF.header=Convertir cualquier archivo a PDF
|
||||
fileToPDF.credit=Este servicio usa LibreOffice y Unoconv para la conversión de ficheros
|
||||
fileToPDF.supportedFileTypes=Los tipos de ficheros soportados deben incluir los de abajo; sin embargo, para una completa y acutualizada lista de formatos soportados, por favor consulte la documentación de LibreOffice
|
||||
fileToPDF.submit=Convertir a PDF
|
||||
|
||||
|
||||
#compress
|
||||
compress.title=Comprimir
|
||||
compress.header=Comprimir PDF
|
||||
compress.credit=Este servicio utiliza Ghostscript para compresión/optimización de PDF.
|
||||
compress.credit=Este servicio utiliza Ghostscript para compresión/optimización de PDF
|
||||
compress.selectText.1=Modo manual - De 1 a 4
|
||||
compress.selectText.2=Nivel de optimización:
|
||||
compress.selectText.3=4 (Terrible para imágenes de texto)
|
||||
compress.selectText.4=Modo automático: ajusta automáticamente la calidad para que el PDF tenga el tamaño exacto
|
||||
compress.selectText.5=Tamaño de PDF esperado (por ejemplo, 25 MB, 10,8 MB, 25 KB)
|
||||
compress.selectText.5=Tamaño esperado del PDF (por ejemplo, 25 MB, 10.8 MB, 25 KB)
|
||||
compress.submit=Comprimir
|
||||
|
||||
|
||||
#Add image
|
||||
addImage.title=Añadir Imagen
|
||||
addImage.header=Añadir image de PDF
|
||||
addImage.title=Añadir imagen
|
||||
addImage.header=Añadir imagen de PDF
|
||||
addImage.everyPage=¿Todas las páginas?
|
||||
addImage.upload=Añadir imagen
|
||||
addImage.submit=Añadir imagen
|
||||
|
||||
|
||||
@@ -288,13 +293,13 @@ multiTool.header=Multi-herramienta PDF
|
||||
#pageRemover
|
||||
pageRemover.title=Eliminador de páginas
|
||||
pageRemover.header=Eliminador de páginas PDF
|
||||
pageRemover.pagesToDelete=Páginas a eliminar (Introduzca una lista de números de página separados por coma):
|
||||
pageRemover.pagesToDelete=Páginas a eliminar (introducir una lista de números de página separados por coma):
|
||||
pageRemover.submit=Eliminar Páginas
|
||||
|
||||
#rotate
|
||||
rotate.title=Rotar PDF
|
||||
rotate.header=Rotar PDF
|
||||
rotate.SeleccionaAngle=Seleccionar ángulo de rotación (múltiple de 90 grados):
|
||||
rotate.SeleccionaAngle=Seleccionar ángulo de rotación (múltiplo de 90 grados):
|
||||
rotate.submit=Rotar
|
||||
|
||||
|
||||
@@ -303,7 +308,7 @@ rotate.submit=Rotar
|
||||
#merge
|
||||
split.title=Dividir PDF
|
||||
split.header=Dividir PDF
|
||||
split.desc.1=Los números que selecciones son el número de página en el que desea hacer una división
|
||||
split.desc.1=Los números que seleccione son el número de página en el que desea hacer una división
|
||||
split.desc.2=Como tal, seleccionar 1,3,7-8 dividiría un documento de 10 páginas en 6 archivos PDF separados con:
|
||||
split.desc.3=Documento #1: Página 1
|
||||
split.desc.4=Documento #2: Páginas 2 y 3
|
||||
@@ -311,7 +316,7 @@ split.desc.5=Documento #3: Páginas 4, 5 y 6
|
||||
split.desc.6=Documento #4: Página 7
|
||||
split.desc.7=Documento #5: Página 8
|
||||
split.desc.8=Documento #6: Páginas 9 y 10
|
||||
split.splitPages=Introduce las páginas para dividir:
|
||||
split.splitPages=Introducir las páginas para dividir:
|
||||
split.submit=Dividir
|
||||
|
||||
|
||||
@@ -321,7 +326,7 @@ imageToPDF.header=Imagen a PDF
|
||||
imageToPDF.submit=Convertir
|
||||
imageToPDF.selectText.1=Estirar para ajustar
|
||||
imageToPDF.selectText.2=Rotación automática del PDF
|
||||
imageToPDF.selectText.3=Lógica de archivos múltiples (Únicamente activado si funciona con multiples imágenes)
|
||||
imageToPDF.selectText.3=Lógica de archivos múltiples (únicamente activado si funciona con multiples imágenes)
|
||||
imageToPDF.selectText.4=Unir en un único archivo PDF
|
||||
imageToPDF.selectText.5=Convertir a PDFs separados
|
||||
|
||||
@@ -330,21 +335,21 @@ pdfToImage.title=PDF a Imagen
|
||||
pdfToImage.header=PDF a Imagen
|
||||
pdfToImage.selectText=Formato de Imagen
|
||||
pdfToImage.singleOrMultiple=Tipo resultante de imagen
|
||||
pdfToImage.single=Una Imagen Grande Única
|
||||
pdfToImage.multi=Múltiples Imágenes
|
||||
pdfToImage.single=Una única imagen grande
|
||||
pdfToImage.multi=Múltiples imágenes
|
||||
pdfToImage.colorType=Tipo de color
|
||||
pdfToImage.color=Color
|
||||
pdfToImage.grey=Escala de Grises
|
||||
pdfToImage.blackwhite=Blanco y Negro (¡Puedes perder datos!)
|
||||
pdfToImage.grey=Escala de grises
|
||||
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
|
||||
pdfToImage.submit=Convertir
|
||||
|
||||
#addPassword
|
||||
addPassword.title=Añadir Contraseña
|
||||
addPassword.header=Añadir contraseña (Encriptar)
|
||||
addPassword.title=Añadir contraseña
|
||||
addPassword.header=Añadir contraseña (encriptar)
|
||||
addPassword.selectText.1=Seleccionar PDF para encriptar
|
||||
addPassword.selectText.2=Contraseña
|
||||
addPassword.selectText.3=Longitud de la clave de cifrado
|
||||
addPassword.selectText.4=Valores altos son más fuertes, pero valores bajos tienen mejor compatibilidad.
|
||||
addPassword.selectText.4=Valores altos son más fuertes, pero valores bajos tienen mejor compatibilidad
|
||||
addPassword.selectText.5=Permisos para establecer
|
||||
addPassword.selectText.6=Impedir el ensamblaje del documento
|
||||
addPassword.selectText.7=Impedir la extracción de contenido
|
||||
@@ -354,9 +359,9 @@ addPassword.selectText.10=Impedir modificación
|
||||
addPassword.selectText.11=Impedir modificación de anotaciones
|
||||
addPassword.selectText.12=Impedir imprimir
|
||||
addPassword.selectText.13=Impedir imprimir diferentes formatos
|
||||
addPassword.selectText.14=Owner Password
|
||||
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
|
||||
addPassword.selectText.16=Restricts the opening of the document itself
|
||||
addPassword.selectText.14=Contraseña
|
||||
addPassword.selectText.15=Restringe qué se puede hacer con el documento una vez abierto (no soportado por todos los lectores)
|
||||
addPassword.selectText.16=Restringe la apertura del propio documento
|
||||
addPassword.submit=Encriptar
|
||||
|
||||
#watermark
|
||||
@@ -379,8 +384,8 @@ remove-watermark.selectText.2=Texto de la marca de agua:
|
||||
remove-watermark.submit=Eliminar marca de agua
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Cambiar Permisos
|
||||
permissions.header=Cambiar Permisos
|
||||
permissions.title=Cambiar permisos
|
||||
permissions.header=Cambiar permisos
|
||||
permissions.warning=Advertencia: para que estos permisos no se puedan cambiar, se recomienda configurarlos con una contraseña a través de la página de cambio de contraseña
|
||||
permissions.selectText.1=Seleccionar PDF para cambiar los permisos
|
||||
permissions.selectText.2=Permisos a establecer
|
||||
@@ -396,21 +401,21 @@ permissions.submit=Cambiar
|
||||
|
||||
#remove password
|
||||
removePassword.title=Eliminar contraseña
|
||||
removePassword.header=Eliminar contraseña (Desencriptar)
|
||||
removePassword.selectText.1=Seleccionar PDF para Desencriptar
|
||||
removePassword.header=Eliminar contraseña (desencriptar)
|
||||
removePassword.selectText.1=Seleccionar PDF para desencriptar
|
||||
removePassword.selectText.2=Contraseña
|
||||
removePassword.submit=Eliminar
|
||||
|
||||
changeMetadata.title=Cambiar Metadatos
|
||||
changeMetadata.header=Cambiar Metadatos
|
||||
changeMetadata.title=Cambiar metadatos
|
||||
changeMetadata.header=Cambiar metadatos
|
||||
changeMetadata.selectText.1=Editar las variables que desea cambiar
|
||||
changeMetadata.selectText.2=Eliminar todos los metadatos
|
||||
changeMetadata.selectText.3=Mostrar metadatos personalizados:
|
||||
changeMetadata.author=Autor:
|
||||
changeMetadata.creationDate=Fecha de Creación (aaaa/MM/dd HH:mm:ss):
|
||||
changeMetadata.creationDate=Fecha de creación (aaaa/MM/dd HH:mm:ss):
|
||||
changeMetadata.creator=Creador:
|
||||
changeMetadata.keywords=Palabras clave:
|
||||
changeMetadata.modDate=Fecha de Modificación (aaaa/MM/dd HH:mm:ss):
|
||||
changeMetadata.modDate=Fecha de modificación (aaaa/MM/dd HH:mm:ss):
|
||||
changeMetadata.producer=Productor:
|
||||
changeMetadata.subject=Asunto:
|
||||
changeMetadata.title=Título:
|
||||
@@ -437,29 +442,29 @@ pdfToPDFA.submit=Convertir
|
||||
PDFToWord.title=PDF a Word
|
||||
PDFToWord.header=PDF a Word
|
||||
PDFToWord.selectText.1=Formato de archivo de salida
|
||||
PDFToWord.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
|
||||
PDFToWord.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||
PDFToWord.submit=Convertir
|
||||
|
||||
PDFToPresentation.title=PDF a presentación
|
||||
PDFToPresentation.header=PDF a presentación
|
||||
PDFToPresentation.selectText.1=Formato de archivo de salida
|
||||
PDFToPresentation.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
|
||||
PDFToPresentation.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||
PDFToPresentation.submit=Convertir
|
||||
|
||||
|
||||
PDFToText.title=PDF a TXT/RTF
|
||||
PDFToText.header=PDF a TXT/RTF
|
||||
PDFToText.selectText.1=Formato de archivo de salida
|
||||
PDFToText.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
|
||||
PDFToText.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||
PDFToText.submit=Convertir
|
||||
|
||||
|
||||
PDFToHTML.title=PDF a HTML
|
||||
PDFToHTML.header=PDF a HTML
|
||||
PDFToHTML.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
|
||||
PDFToHTML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||
PDFToHTML.submit=Convertir
|
||||
|
||||
PDFToXML.title=PDF a XML
|
||||
PDFToXML.header=PDF a XML
|
||||
PDFToXML.credit=Este servicio utiliza LibreOffice para la conversión de archivos.
|
||||
PDFToXML.credit=Este servicio utiliza LibreOffice para la conversión de archivos
|
||||
PDFToXML.submit=Convertir
|
||||
|
||||
470
src/main/resources/messages_eu_ES.properties
Normal file
470
src/main/resources/messages_eu_ES.properties
Normal file
@@ -0,0 +1,470 @@
|
||||
###########
|
||||
# Generic #
|
||||
###########
|
||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||
language.direction=ltr
|
||||
|
||||
pdfPrompt=Hautatu PDFa(k)
|
||||
multiPdfPrompt=Hautatu PDFak (2+)
|
||||
multiPdfDropPrompt=Hautatu (edo arrastatu eta jaregin) nahi dituzun PDFak
|
||||
imgPrompt=Hautatu Irudia(k)
|
||||
genericSubmit=Bidali
|
||||
processTimeWarning=Oharra: prozesu honetarako minutu bat ere beharko da fitxategiaren tamaiaren arabera
|
||||
pageOrderPrompt=Orrialdeen ordena (sartu komaz bereizitako orrialde-zenbakien zerrenda)
|
||||
goToPage=Joan
|
||||
true=Egiazkoa
|
||||
false=Faltsua
|
||||
unknown=Ezezaguna
|
||||
save=Gorde
|
||||
close=Itxi
|
||||
filesSelected=Hautatutako fitxategiak
|
||||
noFavourites=Ez dira gogokoak gehitu
|
||||
bored=Itxaroten aspertuta?
|
||||
alphabet=Alfabetoa
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
home.desc=Zure leihatila bakarra autoostatatua zure PDF behar guztietarako
|
||||
|
||||
navbar.convert=Bihurtu
|
||||
navbar.security=Segurtasuna
|
||||
navbar.other=Beste bat
|
||||
navbar.darkmode=Modu iluna
|
||||
navbar.pageOps=Orrialde-eragiketak
|
||||
|
||||
home.multiTool.title=Erabilera anitzeko tresna PDF
|
||||
home.multiTool.desc= Orriak konbinatu, biratu, berrantolatu eta ezabatu
|
||||
|
||||
home.merge.title=Elkartu
|
||||
home.merge.desc=Elkartu zenbait PDF dokumentu bakar batean modu errazean
|
||||
|
||||
home.split.title=Zatitu
|
||||
home.split.desc=Zatitu PDFak zenbait dokumentutan
|
||||
|
||||
home.rotate.title=Biratu
|
||||
home.rotate.desc=Biratu PDFak modu errazean
|
||||
|
||||
home.imageToPdf.title=Irudia PDF bihurtu
|
||||
home.imageToPdf.desc=Irudi bat(PNG, JPEG, GIF)PDF bihurtu
|
||||
|
||||
home.pdfToImage.title=PDFa irudi bihurtu
|
||||
home.pdfToImage.desc=PDF bat irudi (PNG, JPEG, GIF) bihurtu
|
||||
|
||||
home.pdfOrganiser.title=Antolatzailea
|
||||
home.pdfOrganiser.desc=Ezabatu/Berrantolatu orrialdeak edozein ordenatan
|
||||
|
||||
home.addImage.title=Gehitu irudia PDFari
|
||||
home.addImage.desc=Gehitu irudi bat PDFan ezarritako kokaleku batean (lanean)
|
||||
|
||||
home.watermark.title=Gehitu ur-marka
|
||||
home.watermark.desc=Gehitu aurrez zehaztutako ur-marka bat PFD dokumentuari
|
||||
|
||||
home.remove-watermark.title= Ezabatu ur-marka
|
||||
home.remove-watermark.desc= Ezabatu ur-marka PDF dokumentutik
|
||||
|
||||
home.permissions.title=Aldatu baimenak
|
||||
home.permissions.desc=Aldatu PDF dokumentuaren baimenak
|
||||
|
||||
home.removePages.title=Ezabatu
|
||||
home.removePages.desc=Ezabatu nahi ez dituzun orrialdeak PDF dokumentutik
|
||||
|
||||
home.addPassword.title=Gehitu pasahitza
|
||||
home.addPassword.desc=Enkriptatu PDF dokumentua pasahitz batekin
|
||||
|
||||
home.removePassword.title=Ezabatu pasahitza
|
||||
home.removePassword.desc=Ezabatu pasahitza PDF dokumentutik
|
||||
|
||||
home.compressPdfs.title=Konprimatu
|
||||
home.compressPdfs.desc=Konprimatu PDFak fitxategiaren tamaina murrizteko
|
||||
|
||||
home.changeMetadata.title=Aldatu metadatuak
|
||||
home.changeMetadata.desc=Aldatu/Ezabatu/Gehitu metadatuak PDF dokumentuari
|
||||
|
||||
home.fileToPDF.title=Fitxategia PDF bihurtu
|
||||
home.fileToPDF.desc=PDF bihurtu ia edozein fitxategi (DOCX, PNG, XLS, PPT, TXT eta gehiago)
|
||||
|
||||
home.ocr.title=OCR exekutatu PDFan eta/edo garbiketa-eskaneatzeak
|
||||
home.ocr.desc=Garbiketa-eskaneatzeak eta irudi-testuak detektatu PDF baten barruan eta berriz ere gehitu testu gisa
|
||||
|
||||
home.extractImages.title=Atera irudiak
|
||||
home.extractImages.desc=Atera irudi guztiak PDF batetik eta ZIPen gorde
|
||||
|
||||
home.pdfToPDFA.title=PDFa PDF/A bihurtu
|
||||
home.pdfToPDFA.desc=PDFa PDF/A bihurtu luzaro biltegiratzeko
|
||||
|
||||
home.PDFToWord.title=PDFa Word Bihurtu
|
||||
home.PDFToWord.desc=PDF formatuak Word bihurtu (DOC, DOCX y ODT)
|
||||
|
||||
home.PDFToPresentation.title=PDFa aurkezpen bihurtu
|
||||
home.PDFToPresentation.desc=PDFa aurkezpen formatu bihurtu (PPT, PPTX y ODP)
|
||||
|
||||
home.PDFToText.title=PDFa TXT edo RTF bihurtu
|
||||
home.PDFToText.desc=PDFa TXT edo RTF formatu bihurtu
|
||||
|
||||
home.PDFToHTML.title=PDFa HTML bihurtu
|
||||
home.PDFToHTML.desc=PDFa HTML formatu bihurtu
|
||||
|
||||
home.PDFToXML.title=PDFa XML bihurtu
|
||||
home.PDFToXML.desc=PDFa XML formatu bihurtu
|
||||
|
||||
home.ScannerImageSplit.title=Detektatu/Zatitu argazki eskaneatuak
|
||||
home.ScannerImageSplit.desc=Hainbat argazki zatitu argazki/PDF baten barruan
|
||||
|
||||
home.sign.title=Sinatu
|
||||
home.sign.desc=Gehitu sinadura PDFari marrazki, testu edo irudi bidez
|
||||
|
||||
home.flatten.title=Lautu
|
||||
home.flatten.desc=PDF batetik elementu eta inprimaki interaktibo guztiak ezabatu
|
||||
|
||||
home.repair.title=Konpondu
|
||||
home.repair.desc=Saiatu PDF hondatu/kaltetu bat konpontzen
|
||||
|
||||
home.removeBlanks.title=Ezabatu orrialde zuriak
|
||||
home.removeBlanks.desc=Detektatu orrialde zuriak eta dokumentutik ezabatu
|
||||
|
||||
home.certSign.title=Sinatu ziurtagiriarekin
|
||||
home.certSign.desc=Sinatu PDF bat Ziurtagiri/Gako batekin (PEM/P12)
|
||||
|
||||
home.compare.title=Konparatu
|
||||
home.compare.desc=Konparatu eta erakutsi 2 PDF dokumenturen aldeak
|
||||
|
||||
home.pageLayout.title=Zenbait orrialderen diseinua
|
||||
home.pageLayout.desc=Elkartu orri bakar batean PDF dokumentu baten zenbait orrialde
|
||||
|
||||
home.scalePages.title=Eskalatu/Doitu orrialdearen tamaina
|
||||
home.scalePages.desc=Eskalatu/Aldatu orrialde baten tamaina eta/edo edukia
|
||||
|
||||
error.pdfPassword=PDF dokumentua pasahitzarekin babestuta dago eta pasahitza ez da sartu edo akastuna da
|
||||
|
||||
downloadPdf=PDFa deskargatu
|
||||
text=Testua
|
||||
font=Letra-tipoa
|
||||
selectFilter=-- Hautatu --
|
||||
pageNum=Orrialde-zenbakia
|
||||
|
||||
pageLayout.title=Hainbat orrialderen diseinua
|
||||
pageLayout.header=Hainbat orrialderen diseinua
|
||||
pageLayout.pagesPerSheet=Orrialdeak orriko:
|
||||
pageLayout.submit=Entregatu
|
||||
|
||||
scalePages.title=Doitu orrialdearen eskala
|
||||
scalePages.header=Doitu orrialdearen eskala
|
||||
scalePages.pageSize=Dokumentuaren orrialdearen tamaina
|
||||
scalePages.scaleFactor=Orriaren zoom maila (moztea)
|
||||
scalePages.submit=Entregatu
|
||||
|
||||
certSign.title=Ziurtagiriaren sinadura
|
||||
certSign.header=Sinatu PDF bat haren ziurtagiriarekin (lanean)
|
||||
certSign.selectPDF=Hautatu PDF fitxategi bat sinatzeko:
|
||||
certSign.selectKey=Hautatu gako pribatuko fitxategia (PKCS#8 formatua, .pem edo .der izan liteke):
|
||||
certSign.selectCert=Hautatu ziurtagiridun fitxategia (X.509 formatua, .pem edo .der izan liteke):
|
||||
certSign.selectP12=Hautatu gakoak gordetzeko fitxategia PKCS#12 (.p12 o .pfx) (Aukerakoa, ematen bada, gako pribatua eta ziurtagiria izan beharko ditu):
|
||||
certSign.certType=Ziurtagiri-mota
|
||||
certSign.password=Sartu zure gakoen biltegia edo gako pribatuko pasahitza (hala badagokio):
|
||||
certSign.showSig=Erakutsi sinadura
|
||||
certSign.reason=Arrazoia
|
||||
certSign.location=Kokalekua
|
||||
certSign.name=Izena
|
||||
certSign.submit=Sinatu PDFa
|
||||
|
||||
removeBlanks.title=Ezabatu zuriuneak
|
||||
removeBlanks.header=Ezabatu orrialde zuriak
|
||||
removeBlanks.threshold=Gutxieneko balioa:
|
||||
removeBlanks.thresholdDesc=Pixel bat zeinen zuri izan behar den ezartzeko gutxieneko balioa
|
||||
removeBlanks.whitePercent=Zuriaren protzentajea (%):
|
||||
removeBlanks.whitePercentDesc=Zuria izan behar den orriaren ehunekoa ezabatua izan dadin
|
||||
removeBlanks.submit=Ezabatu zuriuneak
|
||||
|
||||
compare.title=Konparatu
|
||||
compare.header=Konparatu PDF fitxategiak
|
||||
compare.document.1=1. dokumentua
|
||||
compare.document.2=2. dokumentua
|
||||
compare.submit=Konparatu
|
||||
|
||||
sign.title=Sinatu
|
||||
sign.header=Sinatu PDF fitxategiak
|
||||
sign.upload=Igo irudia
|
||||
sign.draw=Marraztu sinadura
|
||||
sign.text=Testua sartzea
|
||||
sign.clear=Garbitu
|
||||
sign.add=Gehitu
|
||||
|
||||
repair.title=Konpondu
|
||||
repair.header=Konpondu PDF fitxategiak
|
||||
repair.submit=Konpondu
|
||||
|
||||
flatten.title=Lautu
|
||||
flatten.header=Akoplatu PDF fitxategiak
|
||||
flatten.submit=Lautu
|
||||
|
||||
ScannerImageSplit.selectText.1=Angeluaren gutxieneko balioa:
|
||||
ScannerImageSplit.selectText.2=Ezarri eskatutako gutxieneko angelu absolutua irudia biratzeko (lehenetsia: 10).
|
||||
ScannerImageSplit.selectText.3=Tolerantzia:
|
||||
ScannerImageSplit.selectText.4=Ezarri kalkulatutako atzeko kolorearen inguruko kolorearen aldakuntza tartea (lehenetsia: 30).
|
||||
ScannerImageSplit.selectText.5=Gutxieneko area:
|
||||
ScannerImageSplit.selectText.6=Ezarri arearen gutxieneko balioa argazki batentzat (lehenetsia: 10000).
|
||||
ScannerImageSplit.selectText.7=Inguruko area gutxienekoa:
|
||||
ScannerImageSplit.selectText.8=Ezarri inguruko arearen gutxieneko balioa argazki batentzat
|
||||
ScannerImageSplit.selectText.9=Ertzaren tamaina:
|
||||
ScannerImageSplit.selectText.10=Ezarri gehitutako eta ezabatutako ertzaren tamaina irteeran ertz zuriak saihesteko (lehenetsia: 1).
|
||||
|
||||
navbar.settings=Ezarpenak
|
||||
settings.title=Ezarpenak
|
||||
settings.update=Eguneratze eskuragarria
|
||||
settings.appVersion=Aplikazioaren bertsioa:
|
||||
settings.downloadOption.title=Hautatu deskargatzeko aukera (fitxategi bakarra deskargatzeko ZIP gabe):
|
||||
settings.downloadOption.1=Ireki leiho berean
|
||||
settings.downloadOption.2=Ireki leiho berrian
|
||||
settings.downloadOption.3=Deskargatu fitxategia
|
||||
settings.zipThreshold=ZIP fitxategiak deskargatutako fitxategi kopurua gainditzen denean
|
||||
|
||||
|
||||
|
||||
|
||||
#OCR
|
||||
ocr.title=OCR / Garbiketa-eskaneatzea
|
||||
ocr.header=Garbiketa-eskaneatzea / OCR (Karaktere-ezagutze optikoa)
|
||||
ocr.selectText.1=Hautatu PDFan detektatuko diren hizkuntzak (zerrendatutakoak gaur egun detektatzen dituenak dira):
|
||||
ocr.selectText.2=Sortu OCR testua duen testu-fitxategi bat OCR-ren bidez editatutako PDFarekin batera
|
||||
ocr.selectText.3=Zuzendu angelu okertu batean eskaneatu ziren orrialdeak berriro beren lekura biratuta
|
||||
ocr.selectText.4=Garbitu orrialdea OCRk hondoko zaratan testua aurkitzeko probabilitate txikiagoa izan dezan (Irteeran aldatu gabe)
|
||||
ocr.selectText.5=Garbitu orrialdea OCRk hondoko zaratan testua aurkitzeko probabilitate txikiagoa izan dezan, irteeran garbi mantentzen du.
|
||||
ocr.selectText.6=Alde batera utzi testu interaktiboa duten orrialdeak, bakarrik irudi diren OCR orrialdeak
|
||||
ocr.selectText.7=OCR behartu, OCRk orrialde bakoitzean jatorrizko testu guztia ezabatuko du
|
||||
ocr.selectText.8=Normala (Errorea gertatuko da PDFak testua baldin badu)
|
||||
ocr.selectText.9=Ezarpen gehigarriak
|
||||
ocr.selectText.10=OCR modua
|
||||
ocr.selectText.11=Irudiak ezabatu OCR-ren ondoren (Irudi GUZTIAK ezabatzen ditu, bakarrik da erabilgarri bihurketa urratsaren parte baldin bada)
|
||||
ocr.selectText.12=Prozesaketa-mota (aurreratua)
|
||||
ocr.help=Irakurri honen erabilerari buruzko dokumentazioa beste hizkuntza batzuetarako eta/edo ez erabili Docker-en
|
||||
ocr.credit=Zerbitzu honek OCRmyPDF eta OCR-rako Tesseract erabiltzen ditu
|
||||
ocr.submit=PDF prozesatu OCR-rekin
|
||||
|
||||
|
||||
|
||||
extractImages.title=Atera irudiak
|
||||
extractImages.header=Atera irudiak
|
||||
extractImages.selectText=Hautatu irudi-formatua ateratako irudiak bihurtzeko
|
||||
extractImages.submit=Atera
|
||||
|
||||
|
||||
#File to PDF
|
||||
fileToPDF.title=Fitxategia PDF bihurtu
|
||||
fileToPDF.header=Edozein fitxategi PDF bihurtu
|
||||
fileToPDF.credit=Zerbitzu honek LibreOffice eta Unoconv erabiltzen ditu fitxategiak bihurtzeko
|
||||
fileToPDF.supportedFileTypes=Jasandako fitxategi-motek behekoak barne hartu behar dituzte; hala ere, jasandako formatuen zerrenda osoa eta eguneratua izateko, kontsultatu, mesedez, LibreOffice-en dokumentazioa
|
||||
fileToPDF.submit=PDF bihurtu
|
||||
|
||||
|
||||
#compress
|
||||
compress.title=Konprimatu
|
||||
compress.header=PDFa konprimatu
|
||||
compress.credit=Zerbitzu honek Ghostscript erabiltzen du PDFak komprimatzeko/optimizatzeko
|
||||
compress.selectText.1=Eskuz 1etik 4ra
|
||||
compress.selectText.2=Optimizazio maila:
|
||||
compress.selectText.3=4 (Izugarria testu-irudietarako)
|
||||
compress.selectText.4=Automatikoa: automatikoki egokitzen du kalitatea PDFak tamaina doi-doia izan dezan
|
||||
compress.selectText.5=PDFaren espero den tamaina (adibidez, 25 MB, 10.8 MB, 25 KB)
|
||||
compress.submit=Konprimatu
|
||||
|
||||
|
||||
#Add image
|
||||
addImage.title=Gehitu irudia
|
||||
addImage.header=Gehitu PDF-irudia
|
||||
addImage.everyPage=Orrialde guztiak?
|
||||
addImage.upload=Gehitu irudia
|
||||
addImage.submit=Gehitu irudia
|
||||
|
||||
|
||||
#merge
|
||||
merge.title=Elkartu
|
||||
merge.header=Elkartu zenbait PDF (2+)
|
||||
merge.submit=Elkartu
|
||||
|
||||
#pdfOrganiser
|
||||
pdfOrganiser.title=Orrialdeen antolatzailea
|
||||
pdfOrganiser.header=PDF orrialdeen antolatzailea
|
||||
pdfOrganiser.submit=Antolatu orrialdeak
|
||||
|
||||
#herramienta multiple
|
||||
multiTool.title= PDF erabilera anitzeko tresna
|
||||
multiTool.header=PDF erabilera anitzeko tresna
|
||||
|
||||
#pageRemover
|
||||
pageRemover.title=Orrialdeen ezabatzailea
|
||||
pageRemover.header=PDF orrialdeen ezabatzailea
|
||||
pageRemover.pagesToDelete=Ezabatu beharreko orrialdeak (sartu komaz bereizitako orrialde-zenbakien zerrenda):
|
||||
pageRemover.submit=Ezabatu orrialdeak
|
||||
|
||||
#rotate
|
||||
rotate.title=Biratu PDFa
|
||||
rotate.header=Biratu PDFa
|
||||
rotate.SeleccionaAngle=Hautatu errotazio-angelua (90 graduren multiploa):
|
||||
rotate.submit=Biratu
|
||||
|
||||
|
||||
|
||||
|
||||
#merge
|
||||
split.title=Zatitu PDFa
|
||||
split.header=Zatitu PDFa
|
||||
split.desc.1=Hautatzen dituzun zenbakiak zatiketa egin nahi duzun orrialde-zenbakiak dira
|
||||
split.desc.2=Beraz, 1,3,7-8 hautatzean 10 orrialdeko dokumentua zatituko luke 6 PDF fitxategi bereizituetan
|
||||
split.desc.3=#1 Dokumentua: 1. orrialdea
|
||||
split.desc.4=#2 Dokumentua: 2. eta 3. orrialdeak
|
||||
split.desc.5=#3 Dokumentua: 4., 5. eta 6. orrialdeak
|
||||
split.desc.6=#4 Dokumentua: 7. orrialdea
|
||||
split.desc.7=#5 Dokumentua: 8. orrialdea
|
||||
split.desc.8=#6 Dokumentua: 9. eta 10. orrialdeak
|
||||
split.splitPages=Sartu orrialdeak zatitzeko:
|
||||
split.submit=Zatitu
|
||||
|
||||
|
||||
#merge
|
||||
imageToPDF.title=Irudia PDF bihurtu
|
||||
imageToPDF.header=Irudia PDF bihurtu
|
||||
imageToPDF.submit=Bihurtu
|
||||
imageToPDF.selectText.1=Zabaldu doitzeko
|
||||
imageToPDF.selectText.2=PDFaren errotazio automatikoa
|
||||
imageToPDF.selectText.3=Fitxategi askoren logika (gaituta bakarrik zenbait irudirekin ari denean)
|
||||
imageToPDF.selectText.4=Elkartu PDF bakar batean
|
||||
imageToPDF.selectText.5=Bihurtu eta PDF bereizituak sortu
|
||||
|
||||
#pdfToImage
|
||||
pdfToImage.title=PDFa irudi bihurtu
|
||||
pdfToImage.header=PDFa irudi bihurtu
|
||||
pdfToImage.selectText=Irudi-formatua
|
||||
pdfToImage.singleOrMultiple=Ondoriozko irudi-mota
|
||||
pdfToImage.single=Irudi handi bakarra
|
||||
pdfToImage.multi=Zenbait irudi
|
||||
pdfToImage.colorType=Kolore-mota
|
||||
pdfToImage.color=Kolorea
|
||||
pdfToImage.grey=Gris-eskala
|
||||
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
|
||||
pdfToImage.submit=Bihurtu
|
||||
|
||||
#addPassword
|
||||
addPassword.title=Gehitu pasahitza
|
||||
addPassword.header=Gehitu pasahitza (enkriptatu)
|
||||
addPassword.selectText.1=Hautatu PDFa enkriptatzeko
|
||||
addPassword.selectText.2=Pasahitza
|
||||
addPassword.selectText.3=Gakoaren luzera
|
||||
addPassword.selectText.4=Balio altuak sendoagoak dira, baina balio baxuek bateragarritasun hobea dute
|
||||
addPassword.selectText.5=Ezartzeko baimenak
|
||||
addPassword.selectText.6=Galarazi dokumentuaren mihiztaketa
|
||||
addPassword.selectText.7=Galarazi edukia ateratzea
|
||||
addPassword.selectText.8=Galarazi ateratzea irisgarritasunerako
|
||||
addPassword.selectText.9=Galarazi inprimakia betetzea
|
||||
addPassword.selectText.10=Galarazi aldaketak egitea
|
||||
addPassword.selectText.11=Galarazi oharrak aldatzea
|
||||
addPassword.selectText.12=Galarazi inprimatzea
|
||||
addPassword.selectText.13=Galarazi zenbait formatu inprimatzea
|
||||
addPassword.selectText.14=Pasahitza
|
||||
addPassword.selectText.15=Mugatu zer egin daitekeen dokumentuarekin behin zabalduta (Irakurle guztiek onartu gabe)
|
||||
addPassword.selectText.16=Mugatu dokumentu bera zabaltzeko aukera
|
||||
addPassword.submit=Enkriptatu
|
||||
|
||||
#watermark
|
||||
watermark.title=Gehitu ur-marka
|
||||
watermark.header=Gehitu ur-marka
|
||||
watermark.selectText.1=Hautatu PDFa ur-marka gehitzeko:
|
||||
watermark.selectText.2=Ur-markaren testua:
|
||||
watermark.selectText.3=Letra-tipoaren tamaina:
|
||||
watermark.selectText.4=Errotazioa (0-360):
|
||||
watermark.selectText.5=Zabalera (ur-marka bakoitzaren arteko espazioa horizontalean):
|
||||
watermark.selectText.6=Altuera (ur-marka bakoitzaren arteko espazioa bertikalean):
|
||||
watermark.selectText.7=Opakutasuna (0% - 100%):
|
||||
watermark.submit=Gehitu ur-marka
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=Ezabatu ur-marka
|
||||
remove-watermark.header=Ezabatu ur-marka
|
||||
remove-watermark.selectText.1=Hautatu PDFa ur-marka ezabatzeko:
|
||||
remove-watermark.selectText.2=Ur-markaren testua:
|
||||
remove-watermark.submit=Ezabatu ur-marka
|
||||
|
||||
#Change permissions
|
||||
permissions.title=Aldatu baimenak
|
||||
permissions.header=Aldatu baimenak
|
||||
permissions.warning=Oharra: baimen hauek aldatzea ezinezkoa izan dadin, gomendatzen da pasahitz batekin konfiguratzea pasahitza aldatzeko orriaren bitartez
|
||||
permissions.selectText.1=Hautatu PDFa baimenak aldatzeko
|
||||
permissions.selectText.2=Baimenak, ezarri beharrekoak
|
||||
permissions.selectText.3=Galarazi dokumentuaren mihiztaketa
|
||||
permissions.selectText.4=Galarazi edukia ateratzea
|
||||
permissions.selectText.5=Galarazi ateratzea irisgarritasunerako
|
||||
permissions.selectText.6=Galarazi inprimakia betetzea
|
||||
permissions.selectText.7=Galarazi aldaketak egitea
|
||||
permissions.selectText.8=Galarazi oharrak aldatzea
|
||||
permissions.selectText.9=Galarazi inprimatzea
|
||||
permissions.selectText.10=Galarazi zenbait formatu inprimatzea
|
||||
permissions.submit=Aldatu
|
||||
|
||||
#remove password
|
||||
removePassword.title=Ezabatu pasahitza
|
||||
removePassword.header=Ezabatu pasahitza (desenkriptatu)
|
||||
removePassword.selectText.1=Hautatu PDFa desenkriptatzeko
|
||||
removePassword.selectText.2=Pasahitza
|
||||
removePassword.submit=Ezabatu
|
||||
|
||||
changeMetadata.title=Aldatu metadatuak
|
||||
changeMetadata.header=Aldatu metadatuak
|
||||
changeMetadata.selectText.1=Editatu aldatu nahi dituzun aldagaiak
|
||||
changeMetadata.selectText.2=Ezabatu metadatu guztiak
|
||||
changeMetadata.selectText.3=Erakutsi metadatu pertsonalizatuak:
|
||||
changeMetadata.author=Egilea:
|
||||
changeMetadata.creationDate=Sortze-data (aaaa/MM/dd HH:mm:ss):
|
||||
changeMetadata.creator=Sortzailea:
|
||||
changeMetadata.keywords=Gako-hitzak:
|
||||
changeMetadata.modDate=Aldatze-data (aaaa/MM/dd HH:mm:ss):
|
||||
changeMetadata.producer=Ekoizlea:
|
||||
changeMetadata.subject=Gaia:
|
||||
changeMetadata.title=Izenburua:
|
||||
changeMetadata.trapped=Trapped:
|
||||
changeMetadata.selectText.4=Beste metadatu batzuk:
|
||||
changeMetadata.selectText.5=Gehitu metadatu pertsonalizatuen sarrera
|
||||
changeMetadata.submit=Aldatu
|
||||
|
||||
xlsToPdf.title=Excela PDF bihurtu
|
||||
xlsToPdf.header=Excela PDF bihurtu
|
||||
xlsToPdf.selectText.1=Hautatu Excel XLSren edo XLSXren kalkulu-orria bihurtzeko
|
||||
xlsToPdf.convert=Bikurtu
|
||||
|
||||
|
||||
|
||||
|
||||
pdfToPDFA.title=PDFa PDF/A bihurtu
|
||||
pdfToPDFA.header=PDFa PDF/A bihurtu
|
||||
pdfToPDFA.credit=Zerbitzu honek OCRmyPDF erabiltzen du PDFak PDF/A bihurtzeko
|
||||
pdfToPDFA.submit=Bihurtu
|
||||
|
||||
|
||||
|
||||
PDFToWord.title=PDFa Word bihurtu
|
||||
PDFToWord.header=PDFa Word bihurtu
|
||||
PDFToWord.selectText.1=Irteerako fitxategiaren formatua
|
||||
PDFToWord.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||
PDFToWord.submit=Bihurtu
|
||||
|
||||
PDFToPresentation.title=PDFa aurkezpen bihurtu
|
||||
PDFToPresentation.header=PDFa aurkezpen bihurtu
|
||||
PDFToPresentation.selectText.1=Irteerako fitxategiaren formatua
|
||||
PDFToPresentation.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||
PDFToPresentation.submit=Bihurtu
|
||||
|
||||
|
||||
PDFToText.title=PDFa TXT/RTF bihurtu
|
||||
PDFToText.header=PDFa TXT/RTF bihurtu
|
||||
PDFToText.selectText.1=Irteerako fitxategiaren formatua
|
||||
PDFToText.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||
PDFToText.submit=Bihurtu
|
||||
|
||||
|
||||
PDFToHTML.title=PDFa HTML bihurtu
|
||||
PDFToHTML.header=PDFa HTML bihurtu
|
||||
PDFToHTML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||
PDFToHTML.submit=Bihurtu
|
||||
|
||||
PDFToXML.title=PDFa XML bihurtu
|
||||
PDFToXML.header=PDFa XML bihurtu
|
||||
PDFToXML.credit=Zerbitzu honek LibreOffice erabiltzen du fitxategiak bihurtzeko
|
||||
PDFToXML.submit=Bihurtu
|
||||
@@ -24,6 +24,7 @@ close=Fermer
|
||||
filesSelected=fichiers sélectionnés
|
||||
noFavourites=Aucun favori ajouté
|
||||
bored=Ennuyé d'attendre ?
|
||||
alphabet=Alphabet
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -127,6 +128,9 @@ home.repair.desc=Essaye de réparer un PDF corrompu/cassé
|
||||
home.removeBlanks.title=Supprimer les pages vierges
|
||||
home.removeBlanks.desc=Détecte et supprime les pages vierges d'un document
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.compare.title=Comparer
|
||||
home.compare.desc=Compare et affiche les différences entre 2 documents PDF
|
||||
|
||||
@@ -259,6 +263,7 @@ fileToPDF.submit=Convertir en PDF
|
||||
addImage.title=Ajouter une image
|
||||
addImage.header=Ajouter une image au PDF
|
||||
addImage.everyPage=Chaque page?
|
||||
addImage.upload=Ajouter une image
|
||||
addImage.submit=Ajouter une image
|
||||
|
||||
#compress
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Chiudi
|
||||
filesSelected=file selezionati
|
||||
noFavourites=Nessun preferito
|
||||
bored=Stanco di aspettare?
|
||||
alphabet=Alfabeto
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -122,6 +123,9 @@ home.repair.desc=Prova a riparare un PDF corrotto.
|
||||
home.removeBlanks.title=Rimuovi pagine vuote
|
||||
home.removeBlanks.desc=Trova e rimuovi pagine vuote da un PDF.
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.compare.title=Compara
|
||||
home.compare.desc=Vedi e compara le differenze tra due PDF.
|
||||
|
||||
@@ -267,8 +271,9 @@ compress.submit=Comprimi
|
||||
|
||||
#Add image
|
||||
addImage.title=Aggiungi Immagine
|
||||
addImage.header=Aggiungi un'immagine ad un PDF.
|
||||
addImage.header=Aggiungi un'immagine ad un PDF
|
||||
addImage.everyPage=Ogni pagina?
|
||||
addImage.upload=Aggiungi immagine
|
||||
addImage.submit=Aggiungi immagine
|
||||
|
||||
|
||||
|
||||
472
src/main/resources/messages_ja_JP.properties
Normal file
472
src/main/resources/messages_ja_JP.properties
Normal file
@@ -0,0 +1,472 @@
|
||||
###########
|
||||
# Generic #
|
||||
###########
|
||||
# the direction that the language is written (ltr = left to right, rtl = right to left)
|
||||
language.direction=ltr
|
||||
|
||||
pdfPrompt=PDFを選択
|
||||
multiPdfPrompt=PDFを選択 (2つ以上)
|
||||
multiPdfDropPrompt=PDFを選択 (又はドラッグ&ドロップ)
|
||||
imgPrompt=画像を選択
|
||||
genericSubmit=送信
|
||||
processTimeWarning=警告:この処理はファイルサイズによって1分程度かかることがあります
|
||||
pageOrderPrompt=ページ順序 (ページ番号をカンマ区切り又は2n+1のような関数で入力):
|
||||
goToPage=移動
|
||||
true=True
|
||||
false=False
|
||||
unknown=不明
|
||||
save=保存
|
||||
close=閉じる
|
||||
filesSelected=選択されたファイル
|
||||
noFavourites=お気に入りはありません
|
||||
bored=待ち時間が退屈<EFBFBD><EFBFBD>
|
||||
alphabet=\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8<43>
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
home.desc=PDFのあらゆるニーズに対応するローカルホスティングされた総合窓口です。
|
||||
|
||||
|
||||
navbar.convert=変換
|
||||
navbar.security=セキュリティ
|
||||
navbar.other=その他
|
||||
navbar.darkmode=ダークモード
|
||||
navbar.pageOps=ページ操作
|
||||
|
||||
home.multiTool.title=PDFマルチツール
|
||||
home.multiTool.desc=ページの結合、回転、並べ替え、削除します。
|
||||
|
||||
home.merge.title=結合
|
||||
home.merge.desc=複数のPDFを1つに結合します。
|
||||
|
||||
home.split.title=分割
|
||||
home.split.desc=PDFを複数のドキュメントに分割します。
|
||||
|
||||
home.rotate.title=回転
|
||||
home.rotate.desc=PDFを回転します。
|
||||
|
||||
home.imageToPdf.title=画像をPDFに変換
|
||||
home.imageToPdf.desc=画像 (PNG, JPEG, GIF) をPDFに変換します。
|
||||
|
||||
home.pdfToImage.title=PDFを画像に変換
|
||||
home.pdfToImage.desc=PDFを画像 (PNG, JPEG, GIF) に変換します。
|
||||
|
||||
home.pdfOrganiser.title=整理
|
||||
home.pdfOrganiser.desc=ページの削除/並べ替えします。
|
||||
|
||||
home.addImage.title=画像の追加
|
||||
home.addImage.desc=PDF上の任意の場所に画像を追加します。
|
||||
|
||||
home.watermark.title=透かしの追加
|
||||
home.watermark.desc=PDFに独自の透かしを追加します。
|
||||
|
||||
home.remove-watermark.title=透かしの削除
|
||||
home.remove-watermark.desc=PDFから透かしを削除します。
|
||||
|
||||
home.permissions.title=権限の変更
|
||||
home.permissions.desc=PDFの権限を変更します。
|
||||
|
||||
home.removePages.title=削除
|
||||
home.removePages.desc=PDFから不要なページを削除します。
|
||||
|
||||
home.addPassword.title=パスワードの追加
|
||||
home.addPassword.desc=PDFをパスワードで暗号化します。
|
||||
|
||||
home.removePassword.title=パスワードの削除
|
||||
home.removePassword.desc=PDFからパスワードの削除します。
|
||||
|
||||
home.compressPdfs.title=圧縮
|
||||
home.compressPdfs.desc=PDFを圧縮してファイルサイズを小さくします。
|
||||
|
||||
home.changeMetadata.title=メタデータの変更
|
||||
home.changeMetadata.desc=PDFのメタデータを変更/削除/追加します。
|
||||
|
||||
home.fileToPDF.title=ファイルをPDFに変換
|
||||
home.fileToPDF.desc=ほぼすべてのファイルをPDFに変換します。 (DOCX, PNG, XLS, PPT, TXTなど)
|
||||
|
||||
home.ocr.title=OCR / クリーンアップ
|
||||
home.ocr.desc=クリーンアップはPDF内の画像からテキストを検出してテキストとして再追加します。
|
||||
|
||||
home.extractImages.title=画像の抽出
|
||||
home.extractImages.desc=PDFからすべての画像を抽出してzipで保存します。
|
||||
|
||||
home.pdfToPDFA.title=PDFをPDF/Aに変換
|
||||
home.pdfToPDFA.desc=長期保存のためにPDFをPDF/Aに変換。
|
||||
|
||||
home.PDFToWord.title=PDFをWordに変換
|
||||
home.PDFToWord.desc=PDFをWord形式に変換します。 (DOC, DOCX および ODT)
|
||||
|
||||
home.PDFToPresentation.title=PDFをプレゼンテーションに変換
|
||||
home.PDFToPresentation.desc=PDFをプレゼンテーション形式に変換します。 (PPT, PPTX および ODP)
|
||||
|
||||
home.PDFToText.title=PDFをText/RTFに変換
|
||||
home.PDFToText.desc=PDFをTextまたはRTF形式に変換します。
|
||||
|
||||
home.PDFToHTML.title=PDFをHTMLに変換
|
||||
home.PDFToHTML.desc=PDFをHTML形式に変換します。
|
||||
|
||||
home.PDFToXML.title=PDFをXMLに変換
|
||||
home.PDFToXML.desc=PDFをXML形式に変換します。
|
||||
|
||||
home.ScannerImageSplit.title=スキャンされた画像の検出/分割
|
||||
home.ScannerImageSplit.desc=1枚の画像/PDFから複数の写真を分割します。
|
||||
|
||||
home.sign.title=署名
|
||||
home.sign.desc=手書き、テキストまたは画像によってPDFに署名を追加します。
|
||||
|
||||
home.flatten.title=平坦化
|
||||
home.flatten.desc=PDFからインタラクティブな要素とフォームをすべて削除します。
|
||||
|
||||
home.repair.title=修復
|
||||
home.repair.desc=破損したPDFの修復を試みます。
|
||||
|
||||
home.removeBlanks.title=空白ページの削除
|
||||
home.removeBlanks.desc=ドキュメントから空白ページを検出して削除します。
|
||||
|
||||
home.compare.title=比較
|
||||
home.compare.desc=2つのPDFを比較して表示します。
|
||||
|
||||
home.certSign.title=証明書による署名
|
||||
home.certSign.desc=証明書/キーを使用してPDFに署名します。 (PEM/P12)
|
||||
|
||||
home.pageLayout.title=マルチページレイアウト
|
||||
home.pageLayout.desc=PDFの複数のページを1ページに結合します。
|
||||
|
||||
home.scalePages.title=ページの縮尺の調整
|
||||
home.scalePages.desc=ページやコンテンツの縮尺を変更します。
|
||||
|
||||
error.pdfPassword=PDFにパスワードが設定されてますが、パスワードが入力されてないか間違ってます。
|
||||
|
||||
downloadPdf=PDFをダウンロード
|
||||
text=テキスト
|
||||
font=フォント
|
||||
selectFillter=-- 選択 --
|
||||
pageNum=ページ番号
|
||||
|
||||
pageLayout.title=マルチページレイアウト
|
||||
pageLayout.header=マルチページレイアウト
|
||||
pageLayout.pagesPerSheet=1枚あたりのページ数:
|
||||
pageLayout.submit=送信
|
||||
|
||||
scalePages.title=ページの縮尺の調整
|
||||
scalePages.header=ページの縮尺の調整
|
||||
scalePages.pageSize=1ページのサイズ
|
||||
scalePages.scaleFactor=1ページの拡大レベル (トリミング)。
|
||||
scalePages.submit=送信
|
||||
|
||||
certSign.title=証明書による署名
|
||||
certSign.header=証明書を使用してPDFに署名します。 (進行中)
|
||||
certSign.selectPDF=署名するPDFファイルを選択:
|
||||
certSign.selectKey=秘密キーファイルを選択 (PKCS#8形式、.pemまたは.der) :
|
||||
certSign.selectCert=証明書ファイルを選択 (X.509形式、.pemまたは.der) :
|
||||
certSign.selectP12=PKCS#12キーストアファイルを選択 (.p12または.pfx) (オプション。指定する場合は秘密キーと証明書が含まれている必要があります。):
|
||||
certSign.certType=証明書の種類
|
||||
certSign.password=キーストアまたは秘密キーのパスワードを入力 (ある場合) :
|
||||
certSign.showSig=署名を表示
|
||||
certSign.reason=理由
|
||||
certSign.location=場所
|
||||
certSign.name=名前
|
||||
certSign.submit=PDFに署名
|
||||
|
||||
removeBlanks.title=空白の削除
|
||||
removeBlanks.header=空白ページの削除
|
||||
removeBlanks.threshold=しきい値 :
|
||||
removeBlanks.thresholdDesc=白色ピクセルの白さを決めるためのしきい値
|
||||
removeBlanks.whitePercent=白比率
|
||||
removeBlanks.whitePercentDesc=削除するページの白の割合
|
||||
removeBlanks.submit=空白ページの削除
|
||||
|
||||
compare.title=比較
|
||||
compare.header=PDFの比較
|
||||
compare.document.1=ドキュメント 1
|
||||
compare.document.2=ドキュメント 2
|
||||
compare.submit=比較
|
||||
|
||||
sign.title=署名
|
||||
sign.header=PDFに署名
|
||||
sign.upload=画像をアップロード
|
||||
sign.draw=署名を書く
|
||||
sign.text=テキスト入力
|
||||
sign.clear=クリア
|
||||
sign.add=追加
|
||||
|
||||
repair.title=修復
|
||||
repair.header=PDFを修復
|
||||
repair.submit=修復
|
||||
|
||||
flatten.title=平坦化
|
||||
flatten.header=PDFを平坦化する
|
||||
flatten.submit=平坦化
|
||||
|
||||
ScannerImageSplit.selectText.1=角度のしきい値:
|
||||
ScannerImageSplit.selectText.2=画像を回転させるために必要な絶対角度の最小値を設定 (初期値:10)。
|
||||
ScannerImageSplit.selectText.3=許容範囲:
|
||||
ScannerImageSplit.selectText.4=推定された背景色周辺のカラーバリエーションの範囲を決定 (初期値:30)。
|
||||
ScannerImageSplit.selectText.5=最小面積:
|
||||
ScannerImageSplit.selectText.6=画像の最小面積のしきい値を設定 (初期値:10000)。
|
||||
ScannerImageSplit.selectText.7=最小輪郭面積:
|
||||
ScannerImageSplit.selectText.8=画像の最小の輪郭面積のしきい値を設定。
|
||||
ScannerImageSplit.selectText.9=境界線サイズ:
|
||||
ScannerImageSplit.selectText.10=出力に白い縁取りが出ないように追加・削除される境界線の大きさを設定 (初期値:1)。
|
||||
|
||||
navbar.settings=設定
|
||||
settings.title=設定
|
||||
settings.update=利用可能なアップデート
|
||||
settings.appVersion=Appバージョン:
|
||||
settings.downloadOption.title=ダウンロードオプション (zip以外の単一ファイル):
|
||||
settings.downloadOption.1=同じウィンドウで開く
|
||||
settings.downloadOption.2=新しいウィンドウで開く
|
||||
settings.downloadOption.3=ファイルをダウンロード
|
||||
settings.zipThreshold=このファイル数を超えたときにファイルを圧縮する
|
||||
|
||||
|
||||
|
||||
|
||||
#OCR
|
||||
ocr.title=OCR / クリーンアップ
|
||||
ocr.header=クリーンアップ / OCR (光学式文字認識)
|
||||
ocr.selectText.1=PDF内で検出される言語を選択 (リストされているものは現在検出されているものです):
|
||||
ocr.selectText.2=OCR処理されたPDFと一緒に、OCRしたテキストを含むテキストファイルを作成する
|
||||
ocr.selectText.3=斜めにスキャンされたページを回転させて修正する
|
||||
ocr.selectText.4=ページをきれいにして背景ノイズの中からテキストを検出しにくくする。(出力は変わりません)
|
||||
ocr.selectText.5=ページをきれいにして背景ノイズの中からテキストを検出しにくくし、出力はクリーンアップを維持する。
|
||||
ocr.selectText.6=インタラクティブなテキストを含むページを無視し、画像ページのみをOCRする
|
||||
ocr.selectText.7=強制OCR、全てのページで元のテキスト要素を全て削除してOCRする
|
||||
ocr.selectText.8=Normal (PDFにテキストが含まれている場合はエラーになります。)
|
||||
ocr.selectText.9=追加設定
|
||||
ocr.selectText.10=OCRモード
|
||||
ocr.selectText.11=OCR後に画像を削除する (すべての画像を削除します。変換ステップの一部である場合にのみ有効です)。
|
||||
ocr.selectText.12=レンダリングタイプ (高度)
|
||||
ocr.help=他の言語でこれを使用する方法やDocker以外で使用する方法についてはこのドキュメントをお読みください。
|
||||
ocr.credit=本サービスにはOCRにOCRmyPDFとTesseractを使用しています。
|
||||
ocr.submit=OCRでPDFを処理する
|
||||
|
||||
|
||||
|
||||
extractImages.title=画像の抽出
|
||||
extractImages.header=画像の抽出
|
||||
extractImages.selectText=抽出した画像のフォーマットを選択
|
||||
extractImages.submit=抽出
|
||||
|
||||
|
||||
#File to PDF
|
||||
fileToPDF.title=ファイルをPDFに変換
|
||||
fileToPDF.header=あらゆるファイルをPDFに変換
|
||||
fileToPDF.credit=本サービスはファイル変換にLibreOfficeとUnoconvを使用しています。
|
||||
fileToPDF.supportedFileTypes=サポートされるファイル形式には以下が含まれますが、完全な更新リストについてはLibreOfficeのドキュメントを参照してください。
|
||||
fileToPDF.submit=PDFを変換
|
||||
|
||||
|
||||
#compress
|
||||
compress.title=圧縮
|
||||
compress.header=PDFを圧縮
|
||||
compress.credit=本サービスはPDFの圧縮/最適化にGhostscriptを使用しています。
|
||||
compress.selectText.1=手動モード - 1 から 4
|
||||
compress.selectText.2=品質レベル:
|
||||
compress.selectText.3=4 (テキスト画像は最悪)
|
||||
compress.selectText.4=自動モード - PDFを正確なサイズにするために品質を自動調整する。
|
||||
compress.selectText.5=PDFサイズ (例 25MB, 10.8MB, 25KB)
|
||||
compress.submit=圧縮
|
||||
|
||||
|
||||
#Add image
|
||||
addImage.title=画像の追加
|
||||
addImage.header=PDFに画像を追加
|
||||
addImage.everyPage=全ページ?
|
||||
addImage.upload=画像の追加
|
||||
addImage.submit=画像の追加
|
||||
|
||||
|
||||
#merge
|
||||
merge.title=結合
|
||||
merge.header=複数のPDFを結合 (2ファイル以上)
|
||||
merge.submit=結合
|
||||
|
||||
#pdfOrganiser
|
||||
pdfOrganiser.title=整理
|
||||
pdfOrganiser.header=PDFページの整理
|
||||
pdfOrganiser.submit=ページの整理
|
||||
|
||||
#multiTool
|
||||
multiTool.title=PDFマルチツール
|
||||
multiTool.header=PDFマルチツール
|
||||
|
||||
|
||||
#pageRemover
|
||||
pageRemover.title=ページ削除
|
||||
pageRemover.header=PDFページ削除
|
||||
pageRemover.pagesToDelete=削除するページ (ページ番号のカンマ区切りリストを入力してください):
|
||||
pageRemover.submit=ページ削除
|
||||
|
||||
#rotate
|
||||
rotate.title=PDFの回転
|
||||
rotate.header=PDFの回転
|
||||
rotate.selectAngle=回転角度を選択 (90度の倍数):
|
||||
rotate.submit=回転
|
||||
|
||||
|
||||
|
||||
|
||||
#merge
|
||||
split.title=PDFの分割
|
||||
split.header=PDFの分割
|
||||
split.desc.1=選択する番号は分割するページ番号です。
|
||||
split.desc.2=したがって、1,3,7-8を選択すると、10ページのドキュメントが以下のように6つのPDFに分割されることになります。
|
||||
split.desc.3=ドキュメント #1: ページ 1
|
||||
split.desc.4=ドキュメント #2: ページ 2, 3
|
||||
split.desc.5=ドキュメント #3: ページ 4, 5, 6
|
||||
split.desc.6=ドキュメント #4: ページ 7
|
||||
split.desc.7=ドキュメント #5: ページ 8
|
||||
split.desc.8=ドキュメント #6: ページ 9, 10
|
||||
split.splitPages=分割するページ番号を入力:
|
||||
split.submit=分割
|
||||
|
||||
|
||||
#merge
|
||||
imageToPDF.title=画像をPDFに変換
|
||||
imageToPDF.header=画像をPDFに変換
|
||||
imageToPDF.submit=変換
|
||||
imageToPDF.selectText.1=フィットするように引き伸ばす
|
||||
imageToPDF.selectText.2=PDFの自動回転
|
||||
imageToPDF.selectText.3=マルチファイルの処理 (複数の画像を操作する場合に有効になります)
|
||||
imageToPDF.selectText.4=1つのPDFに結合
|
||||
imageToPDF.selectText.5=個別のPDFに変換
|
||||
|
||||
#pdfToImage
|
||||
pdfToImage.title=PDFを画像に変換
|
||||
pdfToImage.header=PDFを画像に変換
|
||||
pdfToImage.selectText=画像の形式
|
||||
pdfToImage.singleOrMultiple=画像出力タイプ
|
||||
pdfToImage.single=単一の大きな画像
|
||||
pdfToImage.multi=複数の画像
|
||||
pdfToImage.colorType=カラーモード
|
||||
pdfToImage.color=カラー
|
||||
pdfToImage.grey=グレースケール
|
||||
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
|
||||
pdfToImage.submit=変換
|
||||
|
||||
#addPassword
|
||||
addPassword.title=パスワードの追加
|
||||
addPassword.header=パスワードの追加 (暗号化)
|
||||
addPassword.selectText.1=暗号化するPDFを選択
|
||||
addPassword.selectText.2=ユーザーパスワード
|
||||
addPassword.selectText.3=暗号化キーの長さ
|
||||
addPassword.selectText.4=値が大きいほど強力ですが、値が小さいほど互換性が高くなります。
|
||||
addPassword.selectText.5=権限の設定 (所有者パスワードとの併用をおすすめします)
|
||||
addPassword.selectText.6=ドキュメントの組立を禁止
|
||||
addPassword.selectText.7=コンテンツの抽出を禁止
|
||||
addPassword.selectText.8=アクセシビリティのための抽出を禁止
|
||||
addPassword.selectText.9=フォームへの入力を禁止
|
||||
addPassword.selectText.10=変更を禁止
|
||||
addPassword.selectText.11=注釈の変更を禁止
|
||||
addPassword.selectText.12=印刷を禁止
|
||||
addPassword.selectText.13=異なる形式の印刷を禁止
|
||||
addPassword.selectText.14=所有者パスワード
|
||||
addPassword.selectText.15=ドキュメントを開いた後に実行できる操作を制限します (すべてのリーダーでサポートされているわけではありません)
|
||||
addPassword.selectText.16=ドキュメントを開くことを制限します
|
||||
addPassword.submit=暗号化
|
||||
|
||||
#watermark
|
||||
watermark.title=透かしの追加
|
||||
watermark.header=透かしの追加
|
||||
watermark.selectText.1=透かしを追加するPDFを選択:
|
||||
watermark.selectText.2=透かしのテキスト:
|
||||
watermark.selectText.3=文字サイズ:
|
||||
watermark.selectText.4=回転 (0-360):
|
||||
watermark.selectText.5=幅スペース (各透かし間の水平方向のスペース):
|
||||
watermark.selectText.6=高さスペース (各透かし間の垂直方向のスペース):
|
||||
watermark.selectText.7=不透明度 (0% - 100%):
|
||||
watermark.submit=透かしを追加
|
||||
|
||||
#remove-watermark
|
||||
remove-watermark.title=透かしの削除
|
||||
remove-watermark.header=透かしの削除
|
||||
remove-watermark.selectText.1=透かしを削除するPDFを選択:
|
||||
remove-watermark.selectText.2=透かしのテキスト:
|
||||
remove-watermark.submit=透かしを削除
|
||||
|
||||
#Change permissions
|
||||
permissions.title=権限の変更
|
||||
permissions.header=権限の変更
|
||||
permissions.warning=警告、これらの権限を変更できないようにするため、パスワードの追加ページでパスワードを設定することを推奨します。
|
||||
permissions.selectText.1=権限を変更するPDFを選択
|
||||
permissions.selectText.2=権限の設定
|
||||
permissions.selectText.3=ドキュメントの組立を禁止
|
||||
permissions.selectText.4=コンテンツの抽出を禁止
|
||||
permissions.selectText.5=アクセシビリティのための抽出を禁止
|
||||
permissions.selectText.6=フォームへの入力を禁止
|
||||
permissions.selectText.7=変更を禁止
|
||||
permissions.selectText.8=注釈の変更を禁止
|
||||
permissions.selectText.9=印刷を禁止
|
||||
permissions.selectText.10=異なる形式の印刷を禁止
|
||||
permissions.submit=変更
|
||||
|
||||
#remove password
|
||||
removePassword.title=パスワードの削除
|
||||
removePassword.header=パスワードの削除 (復号化)
|
||||
removePassword.selectText.1=復号化するPDFを選択
|
||||
removePassword.selectText.2=パスワード
|
||||
removePassword.submit=削除
|
||||
|
||||
changeMetadata.title=メタデータの変更
|
||||
changeMetadata.header=メタデータの変更
|
||||
changeMetadata.selectText.1=変更したい変数を編集してください
|
||||
changeMetadata.selectText.2=すべてのメタデータを削除
|
||||
changeMetadata.selectText.3=カスタムメタデータを表示
|
||||
changeMetadata.author=著者:
|
||||
changeMetadata.creationDate=作成日 (yyyy/MM/dd HH:mm:ss):
|
||||
changeMetadata.creator=作成者:
|
||||
changeMetadata.keywords=キーワード:
|
||||
changeMetadata.modDate=変更日 (yyyy/MM/dd HH:mm:ss):
|
||||
changeMetadata.producer=プロデューサー:
|
||||
changeMetadata.subject=主題:
|
||||
changeMetadata.title=タイトル:
|
||||
changeMetadata.trapped=トラッピング:
|
||||
changeMetadata.selectText.4=その他のメタデータ:
|
||||
changeMetadata.selectText.5=カスタムメタデータの追加
|
||||
changeMetadata.submit=変更
|
||||
|
||||
xlsToPdf.title=ExcelをPDFに変換
|
||||
xlsToPdf.header=ExcelをPDFに変換
|
||||
xlsToPdf.selectText.1=変換するXLSまたはXLSX Execlシートを選択
|
||||
xlsToPdf.convert=変換
|
||||
|
||||
|
||||
|
||||
|
||||
pdfToPDFA.title=PDFをPDF/Aに変換
|
||||
pdfToPDFA.header=PDFをPDF/Aに変換
|
||||
pdfToPDFA.credit=本サービスはPDF/Aの変換にOCRmyPDFを使用しています。
|
||||
pdfToPDFA.submit=変換
|
||||
|
||||
|
||||
|
||||
PDFToWord.title=PDFをWordに変換
|
||||
PDFToWord.header=PDFをWordに変換
|
||||
PDFToWord.selectText.1=出力ファイル形式
|
||||
PDFToWord.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||
PDFToWord.submit=変換
|
||||
|
||||
PDFToPresentation.title=PDFをプレゼンテーションに変換
|
||||
PDFToPresentation.header=PDFをプレゼンテーションに変換
|
||||
PDFToPresentation.selectText.1=出力ファイル形式
|
||||
PDFToPresentation.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||
PDFToPresentation.submit=変換
|
||||
|
||||
|
||||
PDFToText.title=PDFをText/RTFに変換
|
||||
PDFToText.header=PDFをText/RTFに変換
|
||||
PDFToText.selectText.1=出力ファイル形式
|
||||
PDFToText.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||
PDFToText.submit=変換
|
||||
|
||||
|
||||
PDFToHTML.title=PDFをHTMLに変換
|
||||
PDFToHTML.header=PDFをHTMLに変換
|
||||
PDFToHTML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||
PDFToHTML.submit=変換
|
||||
|
||||
PDFToXML.title=PDFをXMLに変換
|
||||
PDFToXML.header=PDFをXMLに変換
|
||||
PDFToXML.credit=本サービスはファイル変換にLibreOfficeを使用しています。
|
||||
PDFToXML.submit=変換
|
||||
@@ -20,6 +20,7 @@ close=닫기
|
||||
filesSelected=개 파일 선택됨
|
||||
noFavourites=즐겨찾기 없음
|
||||
bored=기다리는 게 지루하신가요?
|
||||
alphabet=\uC54C\uD30C\uBCB3
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -276,6 +277,7 @@ compress.submit=압축
|
||||
addImage.title=이미지 추가
|
||||
addImage.header=PDF에 이미지 추가
|
||||
addImage.everyPage=모든 페이지에 적용
|
||||
addImage.upload=이미지 추가
|
||||
addImage.submit=이미지 추가
|
||||
|
||||
|
||||
@@ -386,10 +388,10 @@ addPassword.selectText.9=양식 작성 방지
|
||||
addPassword.selectText.10=수정 방지
|
||||
addPassword.selectText.11=주석 수정 방지
|
||||
addPassword.selectText.12=인쇄 방지
|
||||
addPassword.selectText.13=다른 형식으로 인쇄 방<><EFBFBD>
|
||||
addPassword.selectText.13=다른 형식으로 인쇄 방<>
|
||||
addPassword.selectText.14=Owner Password
|
||||
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
|
||||
addPassword.selectText.16=Restricts the opening of the document itself<6C>
|
||||
addPassword.selectText.16=Restricts the opening of the document itself<6C>
|
||||
addPassword.submit=암호화
|
||||
|
||||
#watermark
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Zamknij
|
||||
filesSelected=wybrane pliki
|
||||
noFavourites=Nie dodano ulubionych
|
||||
bored=Znudzony czekaniem?
|
||||
alphabet=Alfabet
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -272,6 +273,7 @@ compress.submit=Kompresuj
|
||||
addImage.title=Dodaj obraz
|
||||
addImage.header=Dodaj obraz do PDF
|
||||
addImage.everyPage=Każda strona?
|
||||
addImage.upload=Dodaj obraz
|
||||
addImage.submit=Dodaj obraz
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Fechar
|
||||
filesSelected=arquivos selecionados
|
||||
noFavourites=Nenhum favorito adicionado
|
||||
bored=Entediado esperando?
|
||||
alphabet=Alfabeto
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -276,6 +277,7 @@ compress.submit=Comprimir
|
||||
addImage.title=Adicionar imagem
|
||||
addImage.header=Adicionar imagem ao PDF
|
||||
addImage.everyPage=Cada página?
|
||||
addImage.upload=Adicionar imagem
|
||||
addImage.submit=Adicionar imagem
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Închide
|
||||
filesSelected=fișiere selectate
|
||||
noFavourites=Niciun favorit adăugat
|
||||
bored=Plictisit așteptând?
|
||||
alphabet=Alfabet
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -253,6 +254,7 @@ compress.submit=Comprimare
|
||||
addImage.title=Adăugare imagine
|
||||
addImage.header=Adăugare imagine în PDF
|
||||
addImage.everyPage=Pe fiecare pagină?
|
||||
addImage.upload=Adăugare imagine
|
||||
addImage.submit=Adăugare imagine
|
||||
|
||||
#merge
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Закрыть
|
||||
filesSelected=файлов выбрано
|
||||
noFavourites=Нет избранного
|
||||
bored=Скучно ждать?
|
||||
alphabet=\u0430\u043B\u0444\u0430\u0432\u0438\u0442
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -125,6 +126,9 @@ home.removeBlanks.desc=Обнаруживает и удаляет пустые
|
||||
home.compare.title=Сравнение
|
||||
home.compare.desc=Сравнивает и показывает различия между двумя PDF-документами
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.pageLayout.title=Multi-Page Layout
|
||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||
|
||||
@@ -270,6 +274,7 @@ compress.submit=Сжать
|
||||
addImage.title=Добавить изображение
|
||||
addImage.header=Добавить изображение в PDF
|
||||
addImage.everyPage=Каждая страница?
|
||||
addImage.upload=Добавить изображение
|
||||
addImage.submit=Добавить изображение
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ close=Stäng
|
||||
filesSelected=filer valda
|
||||
noFavourites=Inga favoriter har lagts till
|
||||
bored=Utråkad att vänta?
|
||||
alphabet=Alfabet
|
||||
#############
|
||||
# HEMSIDA #
|
||||
#############
|
||||
@@ -125,6 +126,9 @@ home.removeBlanks.desc=Känner av och tar bort tomma sidor från ett dokument
|
||||
home.compare.title=Jämför
|
||||
home.compare.desc=Jämför och visar skillnaderna mellan 2 PDF-dokument
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.pageLayout.title=Multi-Page Layout
|
||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||
|
||||
@@ -270,6 +274,7 @@ compress.submit=Komprimera
|
||||
addImage.title=Lägg till bild
|
||||
addImage.header=Lägg till bild till PDF
|
||||
addImage.everyPage=Varje sida?
|
||||
addImage.upload=Lägg till bild
|
||||
addImage.submit=Lägg till bild
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ close=关闭
|
||||
filesSelected=\u9009\u62E9\u7684\u6587\u4EF6
|
||||
noFavourites=\u6CA1\u6709\u6DFB\u52A0\u6536\u85CF\u5939
|
||||
bored=\u65E0\u804A\u7B49\u5F85\uFF1F
|
||||
alphabet=\u5B57\u6BCD\u8868
|
||||
#############
|
||||
# HOME-PAGE #
|
||||
#############
|
||||
@@ -125,6 +126,9 @@ home.removeBlanks.desc=\u68C0\u6D4B\u5E76\u5220\u9664\u6587\u6863\u4E2D\u7684\u7
|
||||
home.compare.title=\u6BD4\u8F83
|
||||
home.compare.desc=\u6BD4\u8F83\u5E76\u663E\u793A 2 \u4E2A PDF \u6587\u6863\u4E4B\u95F4\u7684\u5DEE\u5F02
|
||||
|
||||
home.certSign.title=Sign with Certificate
|
||||
home.certSign.desc=Signs a PDF with a Certificate/Key (PEM/P12)
|
||||
|
||||
home.pageLayout.title=Multi-Page Layout
|
||||
home.pageLayout.desc=Merge multiple pages of a PDF document into a single page
|
||||
|
||||
@@ -269,6 +273,7 @@ compress.submit=压缩
|
||||
addImage.title=添加图像
|
||||
addImage.header=添加图片到PDF (Work in progress)
|
||||
addImage.everyPage=每一页?
|
||||
addImage.upload=添加图片
|
||||
addImage.submit=添加图片
|
||||
|
||||
|
||||
@@ -355,10 +360,10 @@ addPassword.selectText.9=防止填写表格
|
||||
addPassword.selectText.10=防止修改
|
||||
addPassword.selectText.11=防止修改注释
|
||||
addPassword.selectText.12=防止打印
|
||||
addPassword.selectText.13=闃叉<EFBFBD>鎵撳嵃涓嶅悓鐨勬牸寮
|
||||
addPassword.selectText.13=防止打印不同的格<EFBFBD>
|
||||
addPassword.selectText.14=Owner Password
|
||||
addPassword.selectText.15=Restricts what can be done with the document once it is opened (Not supported by all readers)
|
||||
addPassword.selectText.16=Restricts the opening of the document itself<6C>
|
||||
addPassword.selectText.16=Restricts the opening of the document itself<6C>
|
||||
addPassword.submit=加密
|
||||
|
||||
#watermark
|
||||
|
||||
BIN
src/main/resources/static/favicon.ico
Normal file
BIN
src/main/resources/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 201 KiB |
BIN
src/main/resources/static/fonts/Meiryo.ttf
Normal file
BIN
src/main/resources/static/fonts/Meiryo.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/static/fonts/NotoSans-Regular.ttf
Normal file
BIN
src/main/resources/static/fonts/NotoSans-Regular.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/static/fonts/NotoSansArabic-Regular.ttf
Normal file
BIN
src/main/resources/static/fonts/NotoSansArabic-Regular.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/static/fonts/NotoSansJP-Regular.ttf
Normal file
BIN
src/main/resources/static/fonts/NotoSansJP-Regular.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/static/fonts/NotoSansSC-Regular.ttf
Normal file
BIN
src/main/resources/static/fonts/NotoSansSC-Regular.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/static/fonts/SimSun.ttf
Normal file
BIN
src/main/resources/static/fonts/SimSun.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/static/fonts/malgun.ttf
Normal file
BIN
src/main/resources/static/fonts/malgun.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/main/resources/static/fonts/static/NotoSansJP-Regular.ttf
Normal file
BIN
src/main/resources/static/fonts/static/NotoSansJP-Regular.ttf
Normal file
Binary file not shown.
5
src/main/resources/static/images/flags/eu.svg
Normal file
5
src/main/resources/static/images/flags/eu.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-es-pv" viewBox="0 0 640 480">
|
||||
<path fill="#D52B1E" d="m0 0h640v480h-640z" />
|
||||
<path fill="#009B48" d="m0 0h53.1l133.4 100.1c73.4 55 133.4 100 133.5 100 0.1 0 60.1-45 266.9-200.1h53.1v39.9l-133.4 100c-73.4 55-133.4 100.1-133.4 100.1 0 0 60 45.1 266.8 200.2v39.8h-53.1l-133.4-100c-73.4-55.1-133.4-100.1-133.5-100.1-0.1 0-60.1 45-266.9 200.1h-53.1v-39.8l133.4-100.1c73.4-55 133.4-100.1 133.4-100.1 0 0-60-45.1-266.8-200.1v-20z" />
|
||||
<path fill="#FFF" d="m288.1 0h63.8v208.1h288.1v63.8h-288.1v208.1h-63.8v-208.1h-288.1v-63.8h288.1v-104z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 602 B |
11
src/main/resources/static/images/flags/jp.svg
Normal file
11
src/main/resources/static/images/flags/jp.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-jp" viewBox="0 0 640 480">
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<path fill-opacity=".7" d="M-88 32h640v480H-88z"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g fill-rule="evenodd" stroke-width="1pt" clip-path="url(#a)" transform="translate(88 -32)">
|
||||
<path fill="#fff" d="M-128 32h720v480h-720z"/>
|
||||
<circle cx="523.1" cy="344.1" r="194.9" fill="#bc002d" transform="translate(-168.4 8.6) scale(.76554)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 465 B |
3
src/main/resources/static/images/pipeline.svg
Normal file
3
src/main/resources/static/images/pipeline.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bezier2" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1 2.5A1.5 1.5 0 0 1 2.5 1h1A1.5 1.5 0 0 1 5 2.5h4.134a1 1 0 1 1 0 1h-2.01c.18.18.34.381.484.605.638.992.892 2.354.892 3.895 0 1.993.257 3.092.713 3.7.356.476.895.721 1.787.784A1.5 1.5 0 0 1 12.5 11h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5H6.866a1 1 0 1 1 0-1h1.711a2.839 2.839 0 0 1-.165-.2C7.743 11.407 7.5 10.007 7.5 8c0-1.46-.246-2.597-.733-3.355-.39-.605-.952-1-1.767-1.112A1.5 1.5 0 0 1 3.5 5h-1A1.5 1.5 0 0 1 1 3.5v-1zM2.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm10 10a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 790 B |
@@ -17,14 +17,15 @@ $(document).ready(function() {
|
||||
const override = $('#override').val() || '';
|
||||
const originalButtonText = $('#submitBtn').text();
|
||||
$('#submitBtn').text('Processing...');
|
||||
|
||||
console.log(override);
|
||||
try {
|
||||
if (override === 'multi' || files.length > 1 && override !== 'single') {
|
||||
await submitMultiPdfForm(url, files);
|
||||
} else {
|
||||
await handleSingleDownload(url, formData);
|
||||
if(remoteCall === true) {
|
||||
if (override === 'multi' || (!multiple && files.length > 1) && override !== 'single' ) {
|
||||
await submitMultiPdfForm(url, files);
|
||||
} else {
|
||||
await handleSingleDownload(url, formData);
|
||||
}
|
||||
}
|
||||
|
||||
$('#submitBtn').text(originalButtonText);
|
||||
} catch (error) {
|
||||
handleDownloadError(error);
|
||||
@@ -36,7 +37,7 @@ $(document).ready(function() {
|
||||
|
||||
|
||||
|
||||
async function handleSingleDownload(url, formData, isMulti = false) {
|
||||
async function handleSingleDownload(url, formData, isMulti = false , isZip = false) {
|
||||
try {
|
||||
const response = await fetch(url, { method: 'POST', body: formData });
|
||||
const contentType = response.headers.get('content-type');
|
||||
@@ -53,11 +54,10 @@ async function handleSingleDownload(url, formData, isMulti = false) {
|
||||
let filename = getFilenameFromContentDisposition(contentDisposition);
|
||||
|
||||
const blob = await response.blob();
|
||||
|
||||
if (contentType.includes('application/pdf') || contentType.includes('image/')) {
|
||||
return handleResponse(blob, filename, !isMulti);
|
||||
return handleResponse(blob, filename, !isMulti, isZip);
|
||||
} else {
|
||||
return handleResponse(blob, filename);
|
||||
return handleResponse(blob, filename, false, isZip);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in handleSingleDownload:', error);
|
||||
@@ -94,7 +94,7 @@ async function handleJsonResponse(response) {
|
||||
}
|
||||
|
||||
|
||||
async function handleResponse(blob, filename, considerViewOptions = false) {
|
||||
async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) {
|
||||
if (!blob) return;
|
||||
const downloadOption = localStorage.getItem('downloadOption');
|
||||
if (considerViewOptions) {
|
||||
@@ -106,9 +106,11 @@ async function handleResponse(blob, filename, considerViewOptions = false) {
|
||||
const url = URL.createObjectURL(blob);
|
||||
window.open(url, '_blank');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!isZip){
|
||||
downloadFile(blob, filename);
|
||||
}
|
||||
downloadFile(blob, filename);
|
||||
return { filename, blob };
|
||||
}
|
||||
|
||||
@@ -124,7 +126,6 @@ function downloadFile(blob, filename) {
|
||||
console.error('Invalid blob passed to downloadFile function');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
@@ -175,12 +176,12 @@ async function submitMultiPdfForm(url, files) {
|
||||
}
|
||||
|
||||
try {
|
||||
const downloadDetails = await handleSingleDownload(url, fileFormData, true);
|
||||
const downloadDetails = await handleSingleDownload(url, fileFormData, true, zipFiles);
|
||||
console.log(downloadDetails);
|
||||
if (zipFiles) {
|
||||
jszip.file(downloadDetails.filename, downloadDetails.blob);
|
||||
} else {
|
||||
downloadFile(downloadDetails.blob, downloadDetails.filename);
|
||||
//downloadFile(downloadDetails.blob, downloadDetails.filename);
|
||||
}
|
||||
updateProgressBar(progressBar, Array.from(files).length);
|
||||
} catch (error) {
|
||||
|
||||
@@ -25,33 +25,50 @@ const DraggableUtils = {
|
||||
},
|
||||
})
|
||||
.resizable({
|
||||
edges: { left: true, right: true, bottom: true, top: true },
|
||||
listeners: {
|
||||
move: (event) => {
|
||||
var target = event.target
|
||||
var x = (parseFloat(target.getAttribute('data-x')) || 0)
|
||||
var y = (parseFloat(target.getAttribute('data-y')) || 0)
|
||||
edges: { left: true, right: true, bottom: true, top: true },
|
||||
listeners: {
|
||||
move: (event) => {
|
||||
var target = event.target
|
||||
var x = (parseFloat(target.getAttribute('data-x')) || 0)
|
||||
var y = (parseFloat(target.getAttribute('data-y')) || 0)
|
||||
|
||||
// update the element's style
|
||||
target.style.width = event.rect.width + 'px'
|
||||
target.style.height = event.rect.height + 'px'
|
||||
// check if control key is pressed
|
||||
if (event.ctrlKey) {
|
||||
const aspectRatio = target.offsetWidth / target.offsetHeight;
|
||||
// preserve aspect ratio
|
||||
let width = event.rect.width;
|
||||
let height = event.rect.height;
|
||||
|
||||
// translate when resizing from top or left edges
|
||||
x += event.deltaRect.left
|
||||
y += event.deltaRect.top
|
||||
if (Math.abs(event.deltaRect.width) >= Math.abs(event.deltaRect.height)) {
|
||||
height = width / aspectRatio;
|
||||
} else {
|
||||
width = height * aspectRatio;
|
||||
}
|
||||
|
||||
target.style.transform = 'translate(' + x + 'px,' + y + 'px)'
|
||||
event.rect.width = width;
|
||||
event.rect.height = height;
|
||||
}
|
||||
|
||||
target.setAttribute('data-x', x)
|
||||
target.setAttribute('data-y', y)
|
||||
target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height)
|
||||
target.style.width = event.rect.width + 'px'
|
||||
target.style.height = event.rect.height + 'px'
|
||||
|
||||
// translate when resizing from top or left edges
|
||||
x += event.deltaRect.left
|
||||
y += event.deltaRect.top
|
||||
|
||||
target.style.transform = 'translate(' + x + 'px,' + y + 'px)'
|
||||
|
||||
target.setAttribute('data-x', x)
|
||||
target.setAttribute('data-y', y)
|
||||
target.textContent = Math.round(event.rect.width) + '\u00D7' + Math.round(event.rect.height)
|
||||
|
||||
this.onInteraction(target);
|
||||
},
|
||||
},
|
||||
|
||||
this.onInteraction(target);
|
||||
},
|
||||
},
|
||||
modifiers: [
|
||||
interact.modifiers.restrictSize({
|
||||
min: { width: 50, height: 50 },
|
||||
min: { width: 5, height: 5 },
|
||||
}),
|
||||
],
|
||||
inertia: true,
|
||||
@@ -201,7 +218,7 @@ const DraggableUtils = {
|
||||
},
|
||||
async getOverlayedPdfDocument() {
|
||||
const pdfBytes = await this.pdfDoc.getData();
|
||||
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes);
|
||||
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, { ignoreEncryption: true });
|
||||
this.storePageContents();
|
||||
|
||||
const pagesMap = this.documentsMap.get(this.pdfDoc);
|
||||
|
||||
@@ -62,7 +62,7 @@ class PdfContainer {
|
||||
const files = e.target.files;
|
||||
this.fileName = files[0].name;
|
||||
for (var i=0; i < files.length; i++) {
|
||||
this.addPdfFile(files[i], nextSiblingElement);
|
||||
await this.addPdfFile(files[i], nextSiblingElement);
|
||||
}
|
||||
|
||||
document.querySelectorAll(".enable-on-file").forEach(element => {
|
||||
@@ -152,7 +152,7 @@ class PdfContainer {
|
||||
|
||||
async toPdfLib(objectUrl) {
|
||||
const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer());
|
||||
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes);
|
||||
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes, { ignoreEncryption: true });
|
||||
return pdfDoc;
|
||||
}
|
||||
|
||||
|
||||
419
src/main/resources/static/js/pipeline.js
Normal file
419
src/main/resources/static/js/pipeline.js
Normal file
@@ -0,0 +1,419 @@
|
||||
document.getElementById('validateButton').addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
validatePipeline();
|
||||
});
|
||||
function validatePipeline() {
|
||||
let pipelineListItems = document.getElementById('pipelineList').children;
|
||||
let isValid = true;
|
||||
let containsAddPassword = false;
|
||||
for (let i = 0; i < pipelineListItems.length - 1; i++) {
|
||||
let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent;
|
||||
let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent;
|
||||
if (currentOperation === '/add-password') {
|
||||
containsAddPassword = true;
|
||||
}
|
||||
console.log(currentOperation);
|
||||
console.log(apiDocs[currentOperation]);
|
||||
let currentOperationDescription = apiDocs[currentOperation]?.post?.description || "";
|
||||
let nextOperationDescription = apiDocs[nextOperation]?.post?.description || "";
|
||||
|
||||
console.log("currentOperationDescription", currentOperationDescription);
|
||||
console.log("nextOperationDescription", nextOperationDescription);
|
||||
|
||||
let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || "";
|
||||
let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || "";
|
||||
|
||||
console.log("Operation " + currentOperation + " Output: " + currentOperationOutput);
|
||||
console.log("Operation " + nextOperation + " Input: " + nextOperationInput);
|
||||
|
||||
// Splitting in case of multiple possible output/input
|
||||
let currentOperationOutputArr = currentOperationOutput.split('/');
|
||||
let nextOperationInputArr = nextOperationInput.split('/');
|
||||
|
||||
if (currentOperationOutput !== 'ANY' && nextOperationInput !== 'ANY') {
|
||||
let intersection = currentOperationOutputArr.filter(value => nextOperationInputArr.includes(value));
|
||||
console.log(`Intersection: ${intersection}`);
|
||||
|
||||
if (intersection.length === 0) {
|
||||
isValid = false;
|
||||
console.log(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
|
||||
alert(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (containsAddPassword && pipelineListItems[pipelineListItems.length - 1].querySelector('.operationName').textContent !== '/add-password') {
|
||||
alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.');
|
||||
return false;
|
||||
}
|
||||
if (isValid) {
|
||||
console.log('Pipeline is valid');
|
||||
// Continue with the pipeline operation
|
||||
} else {
|
||||
console.error('Pipeline is not valid');
|
||||
// Stop operation, maybe display an error to the user
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
document.getElementById('submitConfigBtn').addEventListener('click', function() {
|
||||
|
||||
if (validatePipeline() === false) {
|
||||
return;
|
||||
}
|
||||
let selectedOperation = document.getElementById('operationsDropdown').value;
|
||||
let parameters = operationSettings[selectedOperation] || {};
|
||||
|
||||
let pipelineConfig = {
|
||||
"name": "uniquePipelineName",
|
||||
"pipeline": [{
|
||||
"operation": selectedOperation,
|
||||
"parameters": parameters
|
||||
}]
|
||||
};
|
||||
|
||||
let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2);
|
||||
|
||||
let formData = new FormData();
|
||||
|
||||
let fileInput = document.getElementById('fileInput');
|
||||
let files = fileInput.files;
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
console.log("files[i]", files[i].name);
|
||||
formData.append('fileInput', files[i], files[i].name);
|
||||
}
|
||||
|
||||
console.log("pipelineConfigJson", pipelineConfigJson);
|
||||
formData.append('json', pipelineConfigJson);
|
||||
console.log("formData", formData);
|
||||
|
||||
fetch('/handleData', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.blob())
|
||||
.then(blob => {
|
||||
|
||||
let url = window.URL.createObjectURL(blob);
|
||||
let a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'outputfile';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
});
|
||||
|
||||
let apiDocs = {};
|
||||
|
||||
let operationSettings = {};
|
||||
|
||||
fetch('v3/api-docs')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
|
||||
apiDocs = data.paths;
|
||||
let operationsDropdown = document.getElementById('operationsDropdown');
|
||||
const ignoreOperations = ["/handleData", "operationToIgnore"]; // Add the operations you want to ignore here
|
||||
|
||||
operationsDropdown.innerHTML = '';
|
||||
|
||||
let operationsByTag = {};
|
||||
|
||||
// Group operations by tags
|
||||
Object.keys(data.paths).forEach(operationPath => {
|
||||
let operation = data.paths[operationPath].post;
|
||||
if (operation && !ignoreOperations.includes(operationPath) && !operation.description.includes("Type:MISO")) {
|
||||
let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag
|
||||
if (!operationsByTag[operationTag]) {
|
||||
operationsByTag[operationTag] = [];
|
||||
}
|
||||
operationsByTag[operationTag].push(operationPath);
|
||||
}
|
||||
});
|
||||
|
||||
// Specify the order of tags
|
||||
let tagOrder = ["General", "Security", "Convert", "Other", "Filter"];
|
||||
|
||||
// Create dropdown options
|
||||
tagOrder.forEach(tag => {
|
||||
if (operationsByTag[tag]) {
|
||||
let group = document.createElement('optgroup');
|
||||
group.label = tag;
|
||||
|
||||
operationsByTag[tag].forEach(operationPath => {
|
||||
let option = document.createElement('option');
|
||||
let operationWithoutSlash = operationPath.replace(/\//g, ''); // Remove slashes
|
||||
option.textContent = operationWithoutSlash;
|
||||
option.value = operationPath; // Keep the value with slashes for querying
|
||||
group.appendChild(option);
|
||||
});
|
||||
|
||||
operationsDropdown.appendChild(group);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.getElementById('addOperationBtn').addEventListener('click', function() {
|
||||
let selectedOperation = document.getElementById('operationsDropdown').value;
|
||||
let pipelineList = document.getElementById('pipelineList');
|
||||
|
||||
let listItem = document.createElement('li');
|
||||
listItem.className = "list-group-item";
|
||||
let hasSettings = (apiDocs[selectedOperation] && apiDocs[selectedOperation].post &&
|
||||
apiDocs[selectedOperation].post.parameters && apiDocs[selectedOperation].post.parameters.length > 0);
|
||||
|
||||
|
||||
listItem.innerHTML = `
|
||||
<div class="d-flex justify-content-between align-items-center w-100">
|
||||
<div class="operationName">${selectedOperation}</div>
|
||||
<div class="arrows d-flex">
|
||||
<button class="btn btn-secondary move-up btn-margin"><span>↑</span></button>
|
||||
<button class="btn btn-secondary move-down btn-margin"><span>↓</span></button>
|
||||
<button class="btn btn-warning pipelineSettings btn-margin" ${hasSettings ? "" : "disabled"}><span style="color: ${hasSettings ? "black" : "grey"};">⚙️</span></button>
|
||||
<button class="btn btn-danger remove"><span>X</span></button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
pipelineList.appendChild(listItem);
|
||||
|
||||
listItem.querySelector('.move-up').addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
if (listItem.previousElementSibling) {
|
||||
pipelineList.insertBefore(listItem, listItem.previousElementSibling);
|
||||
}
|
||||
});
|
||||
|
||||
listItem.querySelector('.move-down').addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
if (listItem.nextElementSibling) {
|
||||
pipelineList.insertBefore(listItem.nextElementSibling, listItem);
|
||||
}
|
||||
});
|
||||
|
||||
listItem.querySelector('.remove').addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
pipelineList.removeChild(listItem);
|
||||
});
|
||||
|
||||
listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
showpipelineSettingsModal(selectedOperation);
|
||||
});
|
||||
|
||||
function showpipelineSettingsModal(operation) {
|
||||
let pipelineSettingsModal = document.getElementById('pipelineSettingsModal');
|
||||
let pipelineSettingsContent = document.getElementById('pipelineSettingsContent');
|
||||
let operationData = apiDocs[operation].post.parameters || [];
|
||||
|
||||
pipelineSettingsContent.innerHTML = '';
|
||||
|
||||
operationData.forEach(parameter => {
|
||||
let parameterDiv = document.createElement('div');
|
||||
parameterDiv.className = "form-group";
|
||||
|
||||
let parameterLabel = document.createElement('label');
|
||||
parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `;
|
||||
parameterLabel.title = parameter.description;
|
||||
parameterDiv.appendChild(parameterLabel);
|
||||
|
||||
let parameterInput;
|
||||
switch (parameter.schema.type) {
|
||||
case 'string':
|
||||
case 'number':
|
||||
case 'integer':
|
||||
parameterInput = document.createElement('input');
|
||||
parameterInput.type = parameter.schema.type === 'string' ? 'text' : 'number';
|
||||
parameterInput.className = "form-control";
|
||||
break;
|
||||
case 'boolean':
|
||||
parameterInput = document.createElement('input');
|
||||
parameterInput.type = 'checkbox';
|
||||
break;
|
||||
case 'array':
|
||||
case 'object':
|
||||
parameterInput = document.createElement('textarea');
|
||||
parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}`;
|
||||
parameterInput.className = "form-control";
|
||||
break;
|
||||
case 'enum':
|
||||
parameterInput = document.createElement('select');
|
||||
parameterInput.className = "form-control";
|
||||
parameter.schema.enum.forEach(option => {
|
||||
let optionElement = document.createElement('option');
|
||||
optionElement.value = option;
|
||||
optionElement.text = option;
|
||||
parameterInput.appendChild(optionElement);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
parameterInput = document.createElement('input');
|
||||
parameterInput.type = 'text';
|
||||
parameterInput.className = "form-control";
|
||||
}
|
||||
parameterInput.id = parameter.name;
|
||||
|
||||
if (operationSettings[operation] && operationSettings[operation][parameter.name] !== undefined) {
|
||||
let savedValue = operationSettings[operation][parameter.name];
|
||||
|
||||
switch (parameter.schema.type) {
|
||||
case 'number':
|
||||
case 'integer':
|
||||
parameterInput.value = savedValue.toString();
|
||||
break;
|
||||
case 'boolean':
|
||||
parameterInput.checked = savedValue;
|
||||
break;
|
||||
case 'array':
|
||||
case 'object':
|
||||
parameterInput.value = JSON.stringify(savedValue);
|
||||
break;
|
||||
default:
|
||||
parameterInput.value = savedValue;
|
||||
}
|
||||
}
|
||||
|
||||
parameterDiv.appendChild(parameterInput);
|
||||
|
||||
pipelineSettingsContent.appendChild(parameterDiv);
|
||||
});
|
||||
|
||||
let saveButton = document.createElement('button');
|
||||
saveButton.textContent = "Save Settings";
|
||||
saveButton.className = "btn btn-primary";
|
||||
saveButton.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
let settings = {};
|
||||
operationData.forEach(parameter => {
|
||||
let value = document.getElementById(parameter.name).value;
|
||||
switch (parameter.schema.type) {
|
||||
case 'number':
|
||||
case 'integer':
|
||||
settings[parameter.name] = Number(value);
|
||||
break;
|
||||
case 'boolean':
|
||||
settings[parameter.name] = document.getElementById(parameter.name).checked;
|
||||
break;
|
||||
case 'array':
|
||||
case 'object':
|
||||
try {
|
||||
settings[parameter.name] = JSON.parse(value);
|
||||
} catch (err) {
|
||||
console.error(`Invalid JSON format for ${parameter.name}`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
settings[parameter.name] = value;
|
||||
}
|
||||
});
|
||||
operationSettings[operation] = settings;
|
||||
console.log(settings);
|
||||
pipelineSettingsModal.style.display = "none";
|
||||
});
|
||||
pipelineSettingsContent.appendChild(saveButton);
|
||||
|
||||
pipelineSettingsModal.style.display = "block";
|
||||
|
||||
pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() {
|
||||
pipelineSettingsModal.style.display = "none";
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
if (event.target == pipelineSettingsModal) {
|
||||
pipelineSettingsModal.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('savePipelineBtn').addEventListener('click', function() {
|
||||
if (validatePipeline() === false) {
|
||||
return;
|
||||
}
|
||||
let pipelineList = document.getElementById('pipelineList').children;
|
||||
let pipelineConfig = {
|
||||
"name": "uniquePipelineName",
|
||||
"pipeline": []
|
||||
};
|
||||
|
||||
for (let i = 0; i < pipelineList.length; i++) {
|
||||
let operationName = pipelineList[i].querySelector('.operationName').textContent;
|
||||
let parameters = operationSettings[operationName] || {};
|
||||
|
||||
pipelineConfig.pipeline.push({
|
||||
"operation": operationName,
|
||||
"parameters": parameters
|
||||
});
|
||||
}
|
||||
|
||||
let a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(new Blob([JSON.stringify(pipelineConfig, null, 2)], {
|
||||
type: 'application/json'
|
||||
}));
|
||||
a.download = 'pipelineConfig.json';
|
||||
a.style.display = 'none';
|
||||
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
});
|
||||
|
||||
document.getElementById('uploadPipelineBtn').addEventListener('click', function() {
|
||||
document.getElementById('uploadPipelineInput').click();
|
||||
});
|
||||
|
||||
document.getElementById('uploadPipelineInput').addEventListener('change', function(e) {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
let pipelineConfig = JSON.parse(event.target.result);
|
||||
let pipelineList = document.getElementById('pipelineList');
|
||||
|
||||
while (pipelineList.firstChild) {
|
||||
pipelineList.removeChild(pipelineList.firstChild);
|
||||
}
|
||||
|
||||
pipelineConfig.pipeline.forEach(operationConfig => {
|
||||
let operationsDropdown = document.getElementById('operationsDropdown');
|
||||
operationsDropdown.value = operationConfig.operation;
|
||||
operationSettings[operationConfig.operation] = operationConfig.parameters;
|
||||
document.getElementById('addOperationBtn').click();
|
||||
|
||||
let lastOperation = pipelineList.lastChild;
|
||||
|
||||
lastOperation.querySelector('.pipelineSettings').click();
|
||||
|
||||
Object.keys(operationConfig.parameters).forEach(parameterName => {
|
||||
let input = document.getElementById(parameterName);
|
||||
if (input) {
|
||||
switch (input.type) {
|
||||
case 'checkbox':
|
||||
input.checked = operationConfig.parameters[parameterName];
|
||||
break;
|
||||
case 'number':
|
||||
input.value = operationConfig.parameters[parameterName].toString();
|
||||
break;
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
default:
|
||||
input.value = JSON.stringify(operationConfig.parameters[parameterName]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector('#pipelineSettingsModal .btn-primary').click();
|
||||
});
|
||||
};
|
||||
reader.readAsText(e.target.files[0]);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -90,9 +90,11 @@
|
||||
</dialog>
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false">
|
||||
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
|
||||
<script th:inline="javascript">
|
||||
const pdfPasswordPrompt =/*[[#{error.pdfPassword}]]*/ '';
|
||||
const multiple = [[${multiple}]] || false;
|
||||
const remoteCall = [[${remoteCall}]] || true;
|
||||
</script>
|
||||
<script src="js/downloader.js"></script>
|
||||
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!--<li class="nav-item">
|
||||
<a class="nav-link" href="#" th:href="@{pipeline}" th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
|
||||
<img class="icon" src="images/pipeline.svg" alt="icon">
|
||||
<span class="icon-text" th:text="#{home.pipeline.title}"></span>
|
||||
</a>
|
||||
</li>-->
|
||||
|
||||
<li class="nav-item nav-item-separator"></li>
|
||||
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' ? 'active' : ''">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
@@ -152,7 +159,10 @@
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="en_GB">
|
||||
<img src="images/flags/gb.svg" alt="icon" width="20" height="15"> English
|
||||
</a>
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="es_ES">
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="eu_ES">
|
||||
<img src="images/flags/eu.svg" alt="icon" width="20" height="15"> Euskara
|
||||
</a>
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="es_ES">
|
||||
<img src="images/flags/es.svg" alt="icon" width="20" height="15"> Español
|
||||
</a>
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="fr_FR">
|
||||
@@ -179,6 +189,9 @@
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="ko_KR">
|
||||
<img src="images/flags/kr.svg" alt="icon" width="20" height="15"> 한국어
|
||||
</a>
|
||||
<a class="dropdown-item lang_dropdown-item" href="" data-language-code="ja_JP">
|
||||
<img src="images/flags/jp.svg" alt="icon" width="20" height="15"> 日本語
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<!-- Features -->
|
||||
<div class="features-container container">
|
||||
|
||||
<!-- <div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg')}"></div>-->
|
||||
|
||||
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg')}"></div>
|
||||
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', svgPath='images/union.svg')}"></div>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
const processFile = async (file) => {
|
||||
const origFileUrl = URL.createObjectURL(file);
|
||||
const formPdfBytes = await fetch(origFileUrl).then(res => res.arrayBuffer());
|
||||
const pdfDoc = await PDFDocument.load(formPdfBytes);
|
||||
const pdfDoc = await PDFDocument.load(formPdfBytes, { ignoreEncryption: true });
|
||||
|
||||
const form = pdfDoc.getForm();
|
||||
form.flatten();
|
||||
|
||||
111
src/main/resources/templates/pipeline.html
Normal file
111
src/main/resources/templates/pipeline.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.toString()}"
|
||||
th:lang-direction="#{language.direction}"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pipeline.title})}"></th:block>
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
||||
<br> <br>
|
||||
<div class="container" id="dropContainer">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="mb-3">
|
||||
<button id="savePipelineBtn" class="btn btn-success">Download</button>
|
||||
|
||||
<button id="validateButton" class="btn btn-success">Validate</button>
|
||||
<div class="btn-group">
|
||||
<button id="uploadPipelineBtn" class="btn btn-primary">Upload</button>
|
||||
<input type="file" id="uploadPipelineInput" accept=".json"
|
||||
style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pipelineContainer" class="card">
|
||||
|
||||
<!-- Pipeline Configuration Card Header -->
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Pipeline Configuration</h2>
|
||||
</div>
|
||||
|
||||
<!-- Pipeline Configuration Body -->
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<select id="operationsDropdown" class="form-select">
|
||||
<!-- Options will be dynamically populated here -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button id="addOperationBtn" class="btn btn-primary">Add operation</button>
|
||||
</div>
|
||||
<h3>Pipeline:</h3>
|
||||
<ol id="pipelineList" class="list-group">
|
||||
<!-- Pipeline operations will be dynamically populated here -->
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<input type="file" id="fileInput" multiple>
|
||||
|
||||
<button class="btn btn-primary" id="submitConfigBtn">Submit</button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- pipelineSettings modal -->
|
||||
<div id="pipelineSettingsModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<span class="close">×</span>
|
||||
<h2>Operation Settings</h2>
|
||||
<div id="pipelineSettingsContent">
|
||||
<!-- pipelineSettings will be dynamically populated here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/pipeline.js"></script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.modal {
|
||||
display: none; /* Hidden by default */
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 1; /* Sit on top */
|
||||
padding-top: 100px; /* Location of the box */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%; /* Full width */
|
||||
height: 100%; /* Full height */
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
background-color: rgb(0, 0, 0); /* Fallback color */
|
||||
background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
|
||||
}
|
||||
|
||||
/* Modal Content */
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.btn-margin {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -18,6 +18,17 @@
|
||||
<label th:text="#{watermark.selectText.1}"></label>
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="fontSize" th:text="#{alphabet} + ':'"></label>
|
||||
<select class="form-control" name="alphabet" id="alphabet-select">
|
||||
<option value="romain">Roman</option>
|
||||
<option value="arabic">العربية</option>
|
||||
<option value="japanese">日本語</option>
|
||||
<option value="korean">한국어</option>
|
||||
<option value="chinese">简体中文</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="watermarkText" th:text="#{watermark.selectText.2}"></label>
|
||||
<input type="text" id="watermarkText" name="watermarkText" class="form-control" placeholder="Stirling-PDF" required />
|
||||
|
||||
@@ -130,12 +130,13 @@
|
||||
// When zoomed out to less than 100%, for some very strange reason,
|
||||
// some browsers report devicePixelRatio as less than 1
|
||||
// and only part of the canvas is cleared then.
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
var additionalFactor = 10;
|
||||
|
||||
signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio * additionalFactor;
|
||||
signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio * additionalFactor;
|
||||
signaturePadCanvas.getContext("2d").scale(ratio * additionalFactor, ratio * additionalFactor);
|
||||
|
||||
// This part causes the canvas to be cleared
|
||||
signaturePadCanvas.width = signaturePadCanvas.offsetWidth * ratio;
|
||||
signaturePadCanvas.height = signaturePadCanvas.offsetHeight * ratio;
|
||||
signaturePadCanvas.getContext("2d").scale(ratio, ratio);
|
||||
|
||||
// This library does not listen for canvas changes, so after the canvas is automatically
|
||||
// cleared by the browser, SignaturePad#isEmpty might still return false, even though the
|
||||
|
||||
Reference in New Issue
Block a user