Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7add727a6 | ||
|
|
cd947c2554 | ||
|
|
9422a30ebf | ||
|
|
e754e6012a | ||
|
|
3227da55e0 | ||
|
|
709a79c3d9 | ||
|
|
77bb15bc8b | ||
|
|
beaa86cbf9 | ||
|
|
b8303e3860 | ||
|
|
ed273a6e92 | ||
|
|
0136c25e1d | ||
|
|
cf03bdc17b | ||
|
|
093b882141 | ||
|
|
46507f10b6 | ||
|
|
54fbf666fd | ||
|
|
faecaf1ee4 | ||
|
|
a062b36ee5 | ||
|
|
00b6d60309 | ||
|
|
1e0121b4d6 | ||
|
|
5ba98e4411 | ||
|
|
d7a3708a13 | ||
|
|
73ac17942f | ||
|
|
116dfcc065 | ||
|
|
54e599a18b | ||
|
|
2d76927b3c | ||
|
|
41c269f208 | ||
|
|
38633d4db1 | ||
|
|
0ff45c656a | ||
|
|
bc282c6aa5 | ||
|
|
50575bc80b | ||
|
|
6f04f01c2b | ||
|
|
e80eaaa6d1 | ||
|
|
01288dafe8 | ||
|
|
e3c7b6f955 | ||
|
|
875f5a85ef | ||
|
|
ef174a1e8a |
7
.github/labeler-config.yml
vendored
7
.github/labeler-config.yml
vendored
@@ -49,12 +49,17 @@ Documentation:
|
|||||||
|
|
||||||
Docker:
|
Docker:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: '.github/workflows/build.yml'
|
||||||
|
- any-glob-to-any-file: '.github/workflows/push-docker.yml'
|
||||||
- any-glob-to-any-file: 'Dockerfile'
|
- any-glob-to-any-file: 'Dockerfile'
|
||||||
- any-glob-to-any-file: 'Dockerfile-*'
|
- any-glob-to-any-file: 'Dockerfile.*'
|
||||||
- any-glob-to-any-file: 'exampleYmlFiles/*.yml'
|
- any-glob-to-any-file: 'exampleYmlFiles/*.yml'
|
||||||
|
- any-glob-to-any-file: 'scripts/download-security-jar.sh'
|
||||||
- any-glob-to-any-file: 'scripts/init.sh'
|
- any-glob-to-any-file: 'scripts/init.sh'
|
||||||
- any-glob-to-any-file: 'scripts/init-without-ocr.sh'
|
- any-glob-to-any-file: 'scripts/init-without-ocr.sh'
|
||||||
- any-glob-to-any-file: 'scripts/installFonts.sh'
|
- any-glob-to-any-file: 'scripts/installFonts.sh'
|
||||||
|
- any-glob-to-any-file: 'test.sh'
|
||||||
|
- any-glob-to-any-file: 'test2.sh'
|
||||||
|
|
||||||
Test:
|
Test:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
|
|||||||
13
.github/workflows/PR-Demo-Comment.yml
vendored
13
.github/workflows/PR-Demo-Comment.yml
vendored
@@ -4,9 +4,15 @@ on:
|
|||||||
issue_comment:
|
issue_comment:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-comment:
|
check-comment:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: read
|
||||||
|
issues: read
|
||||||
if: |
|
if: |
|
||||||
github.event.issue.pull_request &&
|
github.event.issue.pull_request &&
|
||||||
(
|
(
|
||||||
@@ -68,6 +74,9 @@ jobs:
|
|||||||
deploy-pr:
|
deploy-pr:
|
||||||
needs: check-comment
|
needs: check-comment
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
@@ -98,7 +107,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
run: |
|
||||||
|
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
|
||||||
|
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||||
|
|||||||
3
.github/workflows/PR-Demo-cleanup.yml
vendored
3
.github/workflows/PR-Demo-cleanup.yml
vendored
@@ -4,7 +4,8 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened, closed]
|
types: [opened, synchronize, reopened, closed]
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
|
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
|
||||||
|
|||||||
3
.github/workflows/auto-labeler.yml
vendored
3
.github/workflows/auto-labeler.yml
vendored
@@ -3,7 +3,8 @@ on:
|
|||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, synchronize]
|
types: [opened, synchronize]
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labeler:
|
labeler:
|
||||||
|
|||||||
17
.github/workflows/build.yml
vendored
17
.github/workflows/build.yml
vendored
@@ -6,13 +6,15 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
actions: read
|
||||||
security-events: write
|
security-events: write
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
@@ -44,6 +46,17 @@ jobs:
|
|||||||
run: ./gradlew clean build
|
run: ./gradlew clean build
|
||||||
env:
|
env:
|
||||||
DOCKER_ENABLE_SECURITY: true
|
DOCKER_ENABLE_SECURITY: true
|
||||||
|
|
||||||
|
- name: Upload Test Reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: test-reports-jdk-${{ matrix.jdk-version }}
|
||||||
|
path: |
|
||||||
|
build/reports/tests/
|
||||||
|
build/test-results/
|
||||||
|
build/reports/problems/
|
||||||
|
retention-days: 3
|
||||||
|
|
||||||
docker-compose-tests:
|
docker-compose-tests:
|
||||||
# if: github.event_name == 'push' && github.ref == 'refs/heads/main' ||
|
# if: github.event_name == 'push' && github.ref == 'refs/heads/main' ||
|
||||||
@@ -82,7 +95,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install Docker Compose
|
- name: Install Docker Compose
|
||||||
run: |
|
run: |
|
||||||
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||||
sudo chmod +x /usr/local/bin/docker-compose
|
sudo chmod +x /usr/local/bin/docker-compose
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
|
|||||||
3
.github/workflows/licenses-update.yml
vendored
3
.github/workflows/licenses-update.yml
vendored
@@ -7,7 +7,8 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "build.gradle"
|
- "build.gradle"
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
generate-license-report:
|
generate-license-report:
|
||||||
|
|||||||
3
.github/workflows/manage-label.yml
vendored
3
.github/workflows/manage-label.yml
vendored
@@ -4,7 +4,8 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: "30 20 * * *"
|
- cron: "30 20 * * *"
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labeler:
|
labeler:
|
||||||
|
|||||||
5
.github/workflows/multiOSReleases.yml
vendored
5
.github/workflows/multiOSReleases.yml
vendored
@@ -5,7 +5,8 @@ on:
|
|||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-installers:
|
build-installers:
|
||||||
@@ -42,7 +43,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
with:
|
with:
|
||||||
gradle-version: 8.7
|
gradle-version: 8.12
|
||||||
|
|
||||||
# Install Windows dependencies
|
# Install Windows dependencies
|
||||||
- name: Install WiX Toolset
|
- name: Install WiX Toolset
|
||||||
|
|||||||
5
.github/workflows/pre_commit.yml
vendored
5
.github/workflows/pre_commit.yml
vendored
@@ -4,7 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update:
|
update:
|
||||||
@@ -19,7 +20,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: 3.12
|
python-version: 3.12
|
||||||
- name: Run Pre-Commit Hooks
|
- name: Run Pre-Commit Hooks
|
||||||
|
|||||||
7
.github/workflows/push-docker.yml
vendored
7
.github/workflows/push-docker.yml
vendored
@@ -9,14 +9,13 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
@@ -33,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
with:
|
with:
|
||||||
gradle-version: 8.7
|
gradle-version: 8.12
|
||||||
|
|
||||||
- name: Run Gradle Command
|
- name: Run Gradle Command
|
||||||
run: ./gradlew clean build
|
run: ./gradlew clean build
|
||||||
@@ -42,7 +41,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install cosign
|
- name: Install cosign
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: sigstore/cosign-installer@v3.7.0
|
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
|
||||||
with:
|
with:
|
||||||
cosign-release: 'v2.4.1'
|
cosign-release: 'v2.4.1'
|
||||||
|
|
||||||
|
|||||||
5
.github/workflows/releaseArtifacts.yml
vendored
5
.github/workflows/releaseArtifacts.yml
vendored
@@ -5,7 +5,8 @@ on:
|
|||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
@@ -37,7 +38,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
with:
|
with:
|
||||||
gradle-version: 8.7
|
gradle-version: 8.12
|
||||||
|
|
||||||
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
||||||
run: ./gradlew clean createExe
|
run: ./gradlew clean createExe
|
||||||
|
|||||||
3
.github/workflows/stale.yml
vendored
3
.github/workflows/stale.yml
vendored
@@ -5,7 +5,8 @@ on:
|
|||||||
- cron: "30 0 * * *"
|
- cron: "30 0 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
|||||||
3
.github/workflows/swagger.yml
vendored
3
.github/workflows/swagger.yml
vendored
@@ -6,7 +6,8 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
|
|||||||
3
.github/workflows/sync_files.yml
vendored
3
.github/workflows/sync_files.yml
vendored
@@ -9,7 +9,8 @@ on:
|
|||||||
- "src/main/resources/messages_*.properties"
|
- "src/main/resources/messages_*.properties"
|
||||||
- "scripts/ignore_translation.toml"
|
- "scripts/ignore_translation.toml"
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
sync-readme:
|
sync-readme:
|
||||||
|
|||||||
3
.github/workflows/update-translations.yml
vendored
3
.github/workflows/update-translations.yml
vendored
@@ -6,7 +6,8 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "src/main/resources/messages_en_GB.properties"
|
- "src/main/resources/messages_en_GB.properties"
|
||||||
|
|
||||||
permissions: read-all
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-translations-main:
|
update-translations-main:
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -4,9 +4,9 @@
|
|||||||
[](https://hub.docker.com/r/frooodle/s-pdf)
|
[](https://hub.docker.com/r/frooodle/s-pdf)
|
||||||
[](https://discord.gg/HYmhKj45pU)
|
[](https://discord.gg/HYmhKj45pU)
|
||||||
[](https://github.com/Stirling-Tools/Stirling-PDF/)
|
[](https://github.com/Stirling-Tools/Stirling-PDF/)
|
||||||
|
[](https://scorecard.dev/viewer/?uri=github.com/Stirling-Tools/Stirling-PDF)
|
||||||
[](https://github.com/Stirling-Tools/stirling-pdf)
|
[](https://github.com/Stirling-Tools/stirling-pdf)
|
||||||
|
|
||||||
|
|
||||||
<a href="https://www.producthunt.com/posts/stirling-pdf?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-stirling-pdf" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=641239&theme=light" alt="Stirling PDF - Open source locally hosted web PDF editor | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
<a href="https://www.producthunt.com/posts/stirling-pdf?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-stirling-pdf" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=641239&theme=light" alt="Stirling PDF - Open source locally hosted web PDF editor | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||||
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
|
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ Stirling-PDF currently supports 38 languages!
|
|||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
@@ -134,9 +134,9 @@ Stirling-PDF currently supports 38 languages!
|
|||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Persian (فارسی) (fa_IR) |  |
|
| Persian (فارسی) (fa_IR) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
@@ -148,8 +148,8 @@ Stirling-PDF currently supports 38 languages!
|
|||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
@@ -169,4 +169,4 @@ Join our community:
|
|||||||
- [Translation Guide (How to add custom languages)](HowToAddNewLanguage.md)
|
- [Translation Guide (How to add custom languages)](HowToAddNewLanguage.md)
|
||||||
- [Issue Tracker](https://github.com/Stirling-Tools/Stirling-PDF/issues)
|
- [Issue Tracker](https://github.com/Stirling-Tools/Stirling-PDF/issues)
|
||||||
- [Discord Community](https://discord.gg/HYmhKj45pU)
|
- [Discord Community](https://discord.gg/HYmhKj45pU)
|
||||||
- [Developer Guide](DeveloperGuide.md)
|
- [Developer Guide](DeveloperGuide.md)
|
||||||
|
|||||||
14
build.gradle
14
build.gradle
@@ -123,11 +123,13 @@ jpackage {
|
|||||||
windows {
|
windows {
|
||||||
launcherAsService = false
|
launcherAsService = false
|
||||||
appVersion = project.version
|
appVersion = project.version
|
||||||
winConsole = false
|
|
||||||
winDirChooser = true
|
winConsole = false
|
||||||
winMenu = true
|
winMenu = true // Creates start menu entry
|
||||||
winShortcut = true
|
winShortcut = true // Creates desktop shortcut
|
||||||
winPerUserInstall = true
|
winShortcutPrompt = true // Lets user choose whether to create shortcuts
|
||||||
|
winDirChooser = true // Allows users to choose installation directory
|
||||||
|
winPerUserInstall = false
|
||||||
winMenuGroup = "Stirling Software"
|
winMenuGroup = "Stirling Software"
|
||||||
winUpgradeUuid = "2a43ed0c-b8c2-40cf-89e1-751129b87641" // Unique identifier for updates
|
winUpgradeUuid = "2a43ed0c-b8c2-40cf-89e1-751129b87641" // Unique identifier for updates
|
||||||
winHelpUrl = "https://github.com/Stirling-Tools/Stirling-PDF"
|
winHelpUrl = "https://github.com/Stirling-Tools/Stirling-PDF"
|
||||||
@@ -257,7 +259,7 @@ spotless {
|
|||||||
// rules=['unused-dependency']
|
// rules=['unused-dependency']
|
||||||
// }
|
// }
|
||||||
tasks.wrapper {
|
tasks.wrapper {
|
||||||
gradleVersion = "8.7"
|
gradleVersion = "8.12"
|
||||||
}
|
}
|
||||||
//tasks.withType(JavaCompile) {
|
//tasks.withType(JavaCompile) {
|
||||||
// options.compilerArgs << "-Xlint:deprecation"
|
// options.compilerArgs << "-Xlint:deprecation"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package stirling.software.SPDF;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -24,6 +25,7 @@ import jakarta.annotation.PreDestroy;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.UI.WebBrowser;
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
import stirling.software.SPDF.config.ConfigInitializer;
|
import stirling.software.SPDF.config.ConfigInitializer;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@@ -76,15 +78,27 @@ public class SPdfApplication {
|
|||||||
props.put("spring.main.web-application-type", "servlet");
|
props.put("spring.main.web-application-type", "servlet");
|
||||||
}
|
}
|
||||||
app.setAdditionalProfiles("default");
|
app.setAdditionalProfiles("default");
|
||||||
app.addInitializers(new ConfigInitializer());
|
|
||||||
|
ConfigInitializer initializer = new ConfigInitializer();
|
||||||
|
try {
|
||||||
|
initializer.ensureConfigExists();
|
||||||
|
} catch (IOException | URISyntaxException e) {
|
||||||
|
log.error("Error initialising configuration", e);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> propertyFiles = new HashMap<>();
|
Map<String, String> propertyFiles = new HashMap<>();
|
||||||
// External config files
|
// External config files
|
||||||
if (Files.exists(Paths.get("configs/settings.yml"))) {
|
log.info("Settings file: {}", InstallationPathConfig.getSettingsPath());
|
||||||
propertyFiles.put("spring.config.additional-location", "file:configs/settings.yml");
|
if (Files.exists(Paths.get(InstallationPathConfig.getSettingsPath()))) {
|
||||||
|
propertyFiles.put(
|
||||||
|
"spring.config.additional-location",
|
||||||
|
"file:" + InstallationPathConfig.getSettingsPath());
|
||||||
} else {
|
} else {
|
||||||
log.warn("External configuration file 'configs/settings.yml' does not exist.");
|
log.warn(
|
||||||
|
"External configuration file '{}' does not exist.",
|
||||||
|
InstallationPathConfig.getSettingsPath());
|
||||||
}
|
}
|
||||||
if (Files.exists(Paths.get("configs/custom_settings.yml"))) {
|
if (Files.exists(Paths.get(InstallationPathConfig.getCustomSettingsPath()))) {
|
||||||
String existingLocation =
|
String existingLocation =
|
||||||
propertyFiles.getOrDefault("spring.config.additional-location", "");
|
propertyFiles.getOrDefault("spring.config.additional-location", "");
|
||||||
if (!existingLocation.isEmpty()) {
|
if (!existingLocation.isEmpty()) {
|
||||||
@@ -92,9 +106,11 @@ public class SPdfApplication {
|
|||||||
}
|
}
|
||||||
propertyFiles.put(
|
propertyFiles.put(
|
||||||
"spring.config.additional-location",
|
"spring.config.additional-location",
|
||||||
existingLocation + "file:configs/custom_settings.yml");
|
existingLocation + "file:" + InstallationPathConfig.getCustomSettingsPath());
|
||||||
} else {
|
} else {
|
||||||
log.warn("Custom configuration file 'configs/custom_settings.yml' does not exist.");
|
log.warn(
|
||||||
|
"Custom configuration file '{}' does not exist.",
|
||||||
|
InstallationPathConfig.getCustomSettingsPath());
|
||||||
}
|
}
|
||||||
Properties finalProps = new Properties();
|
Properties finalProps = new Properties();
|
||||||
if (!propertyFiles.isEmpty()) {
|
if (!propertyFiles.isEmpty()) {
|
||||||
@@ -110,8 +126,8 @@ public class SPdfApplication {
|
|||||||
app.run(args);
|
app.run(args);
|
||||||
// Ensure directories are created
|
// Ensure directories are created
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(Path.of("customFiles/static/"));
|
Files.createDirectories(Path.of(InstallationPathConfig.getTemplatesPath()));
|
||||||
Files.createDirectories(Path.of("customFiles/templates/"));
|
Files.createDirectories(Path.of(InstallationPathConfig.getStaticPath()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error creating directories: {}", e.getMessage());
|
log.error("Error creating directories: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import me.friwi.jcefmaven.EnumProgress;
|
|||||||
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
|
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
|
||||||
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
||||||
import stirling.software.SPDF.UI.WebBrowser;
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -72,7 +73,8 @@ public class DesktopBrowser implements WebBrowser {
|
|||||||
CefAppBuilder builder = new CefAppBuilder();
|
CefAppBuilder builder = new CefAppBuilder();
|
||||||
configureCefSettings(builder);
|
configureCefSettings(builder);
|
||||||
builder.setProgressHandler(createProgressHandler());
|
builder.setProgressHandler(createProgressHandler());
|
||||||
|
builder.setInstallDir(
|
||||||
|
new File(InstallationPathConfig.getClientWebUIPath()));
|
||||||
// Build and initialize CEF
|
// Build and initialize CEF
|
||||||
cefApp = builder.build();
|
cefApp = builder.build();
|
||||||
client = cefApp.createClient();
|
client = cefApp.createClient();
|
||||||
@@ -99,8 +101,16 @@ public class DesktopBrowser implements WebBrowser {
|
|||||||
|
|
||||||
private void configureCefSettings(CefAppBuilder builder) {
|
private void configureCefSettings(CefAppBuilder builder) {
|
||||||
CefSettings settings = builder.getCefSettings();
|
CefSettings settings = builder.getCefSettings();
|
||||||
settings.cache_path = new File("jcef-bundle").getAbsolutePath();
|
String basePath = InstallationPathConfig.getClientWebUIPath();
|
||||||
settings.root_cache_path = new File("jcef-bundle").getAbsolutePath();
|
log.info("basePath " + basePath);
|
||||||
|
settings.cache_path = new File(basePath + "cache").getAbsolutePath();
|
||||||
|
settings.root_cache_path = new File(basePath + "root_cache").getAbsolutePath();
|
||||||
|
// settings.browser_subprocess_path = new File(basePath +
|
||||||
|
// "subprocess").getAbsolutePath();
|
||||||
|
// settings.resources_dir_path = new File(basePath + "resources").getAbsolutePath();
|
||||||
|
// settings.locales_dir_path = new File(basePath + "locales").getAbsolutePath();
|
||||||
|
settings.log_file = new File(basePath, "debug.log").getAbsolutePath();
|
||||||
|
|
||||||
settings.persist_session_cookies = true;
|
settings.persist_session_cookies = true;
|
||||||
settings.windowless_rendering_enabled = false;
|
settings.windowless_rendering_enabled = false;
|
||||||
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_INFO;
|
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_INFO;
|
||||||
@@ -212,6 +222,9 @@ public class DesktopBrowser implements WebBrowser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupLoadHandler() {
|
private void setupLoadHandler() {
|
||||||
|
final long initStartTime = System.currentTimeMillis();
|
||||||
|
log.info("Setting up load handler at: {}", initStartTime);
|
||||||
|
|
||||||
client.addLoadHandler(
|
client.addLoadHandler(
|
||||||
new CefLoadHandlerAdapter() {
|
new CefLoadHandlerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@@ -220,32 +233,77 @@ public class DesktopBrowser implements WebBrowser {
|
|||||||
boolean isLoading,
|
boolean isLoading,
|
||||||
boolean canGoBack,
|
boolean canGoBack,
|
||||||
boolean canGoForward) {
|
boolean canGoForward) {
|
||||||
|
log.debug(
|
||||||
|
"Loading state change - isLoading: {}, canGoBack: {}, canGoForward: {}, "
|
||||||
|
+ "browserInitialized: {}, Time elapsed: {}ms",
|
||||||
|
isLoading,
|
||||||
|
canGoBack,
|
||||||
|
canGoForward,
|
||||||
|
browserInitialized,
|
||||||
|
System.currentTimeMillis() - initStartTime);
|
||||||
|
|
||||||
if (!isLoading && !browserInitialized) {
|
if (!isLoading && !browserInitialized) {
|
||||||
|
log.info(
|
||||||
|
"Browser finished loading, preparing to initialize UI components");
|
||||||
browserInitialized = true;
|
browserInitialized = true;
|
||||||
SwingUtilities.invokeLater(
|
SwingUtilities.invokeLater(
|
||||||
() -> {
|
() -> {
|
||||||
if (loadingWindow != null) {
|
try {
|
||||||
Timer timer =
|
if (loadingWindow != null) {
|
||||||
new Timer(
|
log.info("Starting UI initialization sequence");
|
||||||
500,
|
|
||||||
e -> {
|
|
||||||
loadingWindow.dispose();
|
|
||||||
loadingWindow = null;
|
|
||||||
|
|
||||||
frame.dispose();
|
// Close loading window first
|
||||||
frame.setOpacity(1.0f);
|
loadingWindow.setVisible(false);
|
||||||
frame.setUndecorated(false);
|
loadingWindow.dispose();
|
||||||
frame.pack();
|
loadingWindow = null;
|
||||||
frame.setSize(1280, 800);
|
log.info("Loading window disposed");
|
||||||
frame.setLocationRelativeTo(null);
|
|
||||||
frame.setVisible(true);
|
// Then setup the main frame
|
||||||
frame.requestFocus();
|
frame.setVisible(false);
|
||||||
frame.toFront();
|
frame.dispose();
|
||||||
browser.getUIComponent()
|
frame.setOpacity(1.0f);
|
||||||
.requestFocus();
|
frame.setUndecorated(false);
|
||||||
});
|
frame.pack();
|
||||||
timer.setRepeats(false);
|
frame.setSize(1280, 800);
|
||||||
timer.start();
|
frame.setLocationRelativeTo(null);
|
||||||
|
log.debug("Frame reconfigured");
|
||||||
|
|
||||||
|
// Show the main frame
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.requestFocus();
|
||||||
|
frame.toFront();
|
||||||
|
log.info("Main frame displayed and focused");
|
||||||
|
|
||||||
|
// Focus the browser component
|
||||||
|
Timer focusTimer =
|
||||||
|
new Timer(
|
||||||
|
100,
|
||||||
|
e -> {
|
||||||
|
try {
|
||||||
|
browser.getUIComponent()
|
||||||
|
.requestFocus();
|
||||||
|
log.info(
|
||||||
|
"Browser component focused");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error(
|
||||||
|
"Error focusing browser",
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
focusTimer.setRepeats(false);
|
||||||
|
focusTimer.start();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error during UI initialization", e);
|
||||||
|
// Attempt cleanup on error
|
||||||
|
if (loadingWindow != null) {
|
||||||
|
loadingWindow.dispose();
|
||||||
|
loadingWindow = null;
|
||||||
|
}
|
||||||
|
if (frame != null) {
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.requestFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ public class LoadingWindow extends JDialog {
|
|||||||
private final JLabel statusLabel;
|
private final JLabel statusLabel;
|
||||||
private final JPanel mainPanel;
|
private final JPanel mainPanel;
|
||||||
private final JLabel brandLabel;
|
private final JLabel brandLabel;
|
||||||
|
private long startTime;
|
||||||
|
|
||||||
public LoadingWindow(Frame parent, String initialUrl) {
|
public LoadingWindow(Frame parent, String initialUrl) {
|
||||||
super(parent, "Initializing Stirling-PDF", true);
|
super(parent, "Initializing Stirling-PDF", true);
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
log.info("Creating LoadingWindow - initialization started at: {}", startTime);
|
||||||
|
|
||||||
// Initialize components
|
// Initialize components
|
||||||
mainPanel = new JPanel();
|
mainPanel = new JPanel();
|
||||||
@@ -29,8 +32,8 @@ public class LoadingWindow extends JDialog {
|
|||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
gbc.insets = new Insets(5, 5, 5, 5);
|
gbc.insets = new Insets(5, 5, 5, 5);
|
||||||
gbc.weightx = 1.0; // Add horizontal weight
|
gbc.weightx = 1.0;
|
||||||
gbc.weighty = 0.0; // Add vertical weight
|
gbc.weighty = 0.0;
|
||||||
|
|
||||||
// Add icon
|
// Add icon
|
||||||
try {
|
try {
|
||||||
@@ -43,12 +46,14 @@ public class LoadingWindow extends JDialog {
|
|||||||
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
gbc.gridy = 0;
|
gbc.gridy = 0;
|
||||||
mainPanel.add(iconLabel, gbc);
|
mainPanel.add(iconLabel, gbc);
|
||||||
|
log.debug("Icon loaded and scaled successfully");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to load icon", e);
|
log.error("Failed to load icon", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL Label with explicit size
|
// URL Label with explicit size
|
||||||
brandLabel = new JLabel(initialUrl);
|
brandLabel = new JLabel(initialUrl);
|
||||||
brandLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
brandLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
@@ -63,6 +68,7 @@ public class LoadingWindow extends JDialog {
|
|||||||
statusLabel.setPreferredSize(new Dimension(300, 25));
|
statusLabel.setPreferredSize(new Dimension(300, 25));
|
||||||
gbc.gridy = 2;
|
gbc.gridy = 2;
|
||||||
mainPanel.add(statusLabel, gbc);
|
mainPanel.add(statusLabel, gbc);
|
||||||
|
|
||||||
// Progress bar with explicit size
|
// Progress bar with explicit size
|
||||||
progressBar = new JProgressBar(0, 100);
|
progressBar = new JProgressBar(0, 100);
|
||||||
progressBar.setStringPainted(true);
|
progressBar.setStringPainted(true);
|
||||||
@@ -82,33 +88,78 @@ public class LoadingWindow extends JDialog {
|
|||||||
setAlwaysOnTop(true);
|
setAlwaysOnTop(true);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
setStatus("Starting...");
|
setStatus("Starting...");
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"LoadingWindow initialization completed in {}ms",
|
||||||
|
System.currentTimeMillis() - startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProgress(final int progress) {
|
public void setProgress(final int progress) {
|
||||||
SwingUtilities.invokeLater(
|
SwingUtilities.invokeLater(
|
||||||
() -> {
|
() -> {
|
||||||
try {
|
try {
|
||||||
progressBar.setValue(Math.min(Math.max(progress, 0), 100));
|
int validProgress = Math.min(Math.max(progress, 0), 100);
|
||||||
progressBar.setString(progress + "%");
|
log.info(
|
||||||
|
"Setting progress to {}% at {}ms since start",
|
||||||
|
validProgress, System.currentTimeMillis() - startTime);
|
||||||
|
|
||||||
|
// Log additional details when near 90%
|
||||||
|
if (validProgress >= 85 && validProgress <= 95) {
|
||||||
|
log.info(
|
||||||
|
"Near 90% progress - Current status: {}, Window visible: {}, "
|
||||||
|
+ "Progress bar responding: {}, Memory usage: {}MB",
|
||||||
|
statusLabel.getText(),
|
||||||
|
isVisible(),
|
||||||
|
progressBar.isEnabled(),
|
||||||
|
Runtime.getRuntime().totalMemory() / (1024 * 1024));
|
||||||
|
|
||||||
|
// Add thread state logging
|
||||||
|
Thread currentThread = Thread.currentThread();
|
||||||
|
log.debug(
|
||||||
|
"Current thread state - Name: {}, State: {}, Priority: {}",
|
||||||
|
currentThread.getName(),
|
||||||
|
currentThread.getState(),
|
||||||
|
currentThread.getPriority());
|
||||||
|
}
|
||||||
|
|
||||||
|
progressBar.setValue(validProgress);
|
||||||
|
progressBar.setString(validProgress + "%");
|
||||||
mainPanel.revalidate();
|
mainPanel.revalidate();
|
||||||
mainPanel.repaint();
|
mainPanel.repaint();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error updating progress", e);
|
log.error("Error updating progress to " + progress, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(final String status) {
|
public void setStatus(final String status) {
|
||||||
log.info(status);
|
log.info(
|
||||||
|
"Status update at {}ms - Setting status to: {}",
|
||||||
|
System.currentTimeMillis() - startTime,
|
||||||
|
status);
|
||||||
|
|
||||||
SwingUtilities.invokeLater(
|
SwingUtilities.invokeLater(
|
||||||
() -> {
|
() -> {
|
||||||
try {
|
try {
|
||||||
statusLabel.setText(status != null ? status : "");
|
String validStatus = status != null ? status : "";
|
||||||
|
statusLabel.setText(validStatus);
|
||||||
|
|
||||||
|
// Log UI state when status changes
|
||||||
|
log.debug(
|
||||||
|
"UI State - Window visible: {}, Progress: {}%, Status: {}",
|
||||||
|
isVisible(), progressBar.getValue(), validStatus);
|
||||||
|
|
||||||
mainPanel.revalidate();
|
mainPanel.revalidate();
|
||||||
mainPanel.repaint();
|
mainPanel.repaint();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error updating status", e);
|
log.error("Error updating status to: " + status, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
log.info("LoadingWindow disposing after {}ms", System.currentTimeMillis() - startTime);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,16 +136,6 @@ public class AppConfig {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "watchedFoldersDir")
|
|
||||||
public String watchedFoldersDir() {
|
|
||||||
return "./pipeline/watchedFolders/";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "finishedFoldersDir")
|
|
||||||
public String finishedFoldersDir() {
|
|
||||||
return "./pipeline/finishedFolders/";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "directoryFilter")
|
@Bean(name = "directoryFilter")
|
||||||
public Predicate<Path> processOnlyFiles() {
|
public Predicate<Path> processOnlyFiles() {
|
||||||
return path -> {
|
return path -> {
|
||||||
|
|||||||
@@ -16,27 +16,15 @@ import org.simpleyaml.configuration.comments.CommentType;
|
|||||||
import org.simpleyaml.configuration.file.YamlFile;
|
import org.simpleyaml.configuration.file.YamlFile;
|
||||||
import org.simpleyaml.configuration.implementation.SimpleYamlImplementation;
|
import org.simpleyaml.configuration.implementation.SimpleYamlImplementation;
|
||||||
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
||||||
import org.springframework.context.ApplicationContextInitializer;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ConfigInitializer
|
public class ConfigInitializer {
|
||||||
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
|
||||||
try {
|
|
||||||
ensureConfigExists();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to initialize application configuration", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ensureConfigExists() throws IOException, URISyntaxException {
|
public void ensureConfigExists() throws IOException, URISyntaxException {
|
||||||
// Define the path to the external config directory
|
// Define the path to the external config directory
|
||||||
Path destPath = Paths.get("configs", "settings.yml");
|
Path destPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||||
|
|
||||||
// Check if the file already exists
|
// Check if the file already exists
|
||||||
if (Files.notExists(destPath)) {
|
if (Files.notExists(destPath)) {
|
||||||
@@ -53,10 +41,11 @@ public class ConfigInitializer
|
|||||||
"Resource file not found: settings.yml.template");
|
"Resource file not found: settings.yml.template");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.info("Created settings file from template");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Define the path to the config settings file
|
// Define the path to the config settings file
|
||||||
Path settingsPath = Paths.get("configs", "settings.yml");
|
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||||
// Load the template resource
|
// Load the template resource
|
||||||
URL settingsTemplateResource =
|
URL settingsTemplateResource =
|
||||||
getClass().getClassLoader().getResource("settings.yml.template");
|
getClass().getClassLoader().getResource("settings.yml.template");
|
||||||
@@ -120,7 +109,7 @@ public class ConfigInitializer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create custom settings file if it doesn't exist
|
// Create custom settings file if it doesn't exist
|
||||||
Path customSettingsPath = Paths.get("configs", "custom_settings.yml");
|
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
||||||
if (!Files.exists(customSettingsPath)) {
|
if (!Files.exists(customSettingsPath)) {
|
||||||
Files.createFile(customSettingsPath);
|
Files.createFile(customSettingsPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -265,20 +266,26 @@ public class EndpointConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processEnvironmentConfigs() {
|
private void processEnvironmentConfigs() {
|
||||||
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
if (applicationProperties != null && applicationProperties.getEndpoints() != null) {
|
||||||
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
||||||
if (!bookAndHtmlFormatsInstalled) {
|
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
||||||
groupsToRemove.add("Calibre");
|
|
||||||
}
|
|
||||||
if (endpointsToRemove != null) {
|
|
||||||
for (String endpoint : endpointsToRemove) {
|
|
||||||
disableEndpoint(endpoint.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groupsToRemove != null) {
|
if (!bookAndHtmlFormatsInstalled) {
|
||||||
for (String group : groupsToRemove) {
|
if (groupsToRemove == null) {
|
||||||
disableGroup(group.trim());
|
groupsToRemove = new ArrayList<>();
|
||||||
|
}
|
||||||
|
groupsToRemove.add("Calibre");
|
||||||
|
}
|
||||||
|
if (endpointsToRemove != null) {
|
||||||
|
for (String endpoint : endpointsToRemove) {
|
||||||
|
disableEndpoint(endpoint.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupsToRemove != null) {
|
||||||
|
for (String group : groupsToRemove) {
|
||||||
|
disableGroup(group.trim());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe
|
|||||||
String characterEncoding,
|
String characterEncoding,
|
||||||
Map<String, Object> templateResolutionAttributes) {
|
Map<String, Object> templateResolutionAttributes) {
|
||||||
Resource resource =
|
Resource resource =
|
||||||
resourceLoader.getResource("file:./customFiles/templates/" + resourceName);
|
resourceLoader.getResource(
|
||||||
|
"file:" + InstallationPathConfig.getTemplatesPath() + resourceName);
|
||||||
try {
|
try {
|
||||||
if (resource.exists() && resource.isReadable()) {
|
if (resource.exists() && resource.isReadable()) {
|
||||||
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
return new FileTemplateResource(resource.getFile().getPath(), characterEncoding);
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class InstallationPathConfig {
|
||||||
|
private static final String BASE_PATH;
|
||||||
|
|
||||||
|
// Root paths
|
||||||
|
private static final String LOG_PATH;
|
||||||
|
private static final String CONFIG_PATH;
|
||||||
|
private static final String PIPELINE_PATH;
|
||||||
|
private static final String CUSTOM_FILES_PATH;
|
||||||
|
private static final String CLIENT_WEBUI_PATH;
|
||||||
|
|
||||||
|
// Config paths
|
||||||
|
private static final String SETTINGS_PATH;
|
||||||
|
private static final String CUSTOM_SETTINGS_PATH;
|
||||||
|
|
||||||
|
// Pipeline paths
|
||||||
|
private static final String PIPELINE_WATCHED_FOLDERS_PATH;
|
||||||
|
private static final String PIPELINE_FINISHED_FOLDERS_PATH;
|
||||||
|
|
||||||
|
// Custom file paths
|
||||||
|
private static final String STATIC_PATH;
|
||||||
|
private static final String TEMPLATES_PATH;
|
||||||
|
private static final String SIGNATURES_PATH;
|
||||||
|
|
||||||
|
static {
|
||||||
|
BASE_PATH = initializeBasePath();
|
||||||
|
|
||||||
|
// Initialize root paths
|
||||||
|
LOG_PATH = BASE_PATH + "logs" + File.separator;
|
||||||
|
CONFIG_PATH = BASE_PATH + "configs" + File.separator;
|
||||||
|
PIPELINE_PATH = BASE_PATH + "pipeline" + File.separator;
|
||||||
|
CUSTOM_FILES_PATH = BASE_PATH + "customFiles" + File.separator;
|
||||||
|
CLIENT_WEBUI_PATH = BASE_PATH + "clientWebUI" + File.separator;
|
||||||
|
|
||||||
|
// Initialize config paths
|
||||||
|
SETTINGS_PATH = CONFIG_PATH + "settings.yml";
|
||||||
|
CUSTOM_SETTINGS_PATH = CONFIG_PATH + "custom_settings.yml";
|
||||||
|
|
||||||
|
// Initialize pipeline paths
|
||||||
|
PIPELINE_WATCHED_FOLDERS_PATH = PIPELINE_PATH + "watchedFolders" + File.separator;
|
||||||
|
PIPELINE_FINISHED_FOLDERS_PATH = PIPELINE_PATH + "finishedFolders" + File.separator;
|
||||||
|
|
||||||
|
// Initialize custom file paths
|
||||||
|
STATIC_PATH = CUSTOM_FILES_PATH + "static" + File.separator;
|
||||||
|
TEMPLATES_PATH = CUSTOM_FILES_PATH + "templates" + File.separator;
|
||||||
|
SIGNATURES_PATH = CUSTOM_FILES_PATH + "signatures" + File.separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String initializeBasePath() {
|
||||||
|
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
||||||
|
String os = System.getProperty("os.name").toLowerCase();
|
||||||
|
if (os.contains("win")) {
|
||||||
|
return System.getenv("APPDATA") + File.separator + "Stirling-PDF" + File.separator;
|
||||||
|
} else if (os.contains("mac")) {
|
||||||
|
return System.getProperty("user.home")
|
||||||
|
+ File.separator
|
||||||
|
+ "Library"
|
||||||
|
+ File.separator
|
||||||
|
+ "Application Support"
|
||||||
|
+ File.separator
|
||||||
|
+ "Stirling-PDF"
|
||||||
|
+ File.separator;
|
||||||
|
} else {
|
||||||
|
return System.getProperty("user.home")
|
||||||
|
+ File.separator
|
||||||
|
+ ".config"
|
||||||
|
+ File.separator
|
||||||
|
+ "Stirling-PDF"
|
||||||
|
+ File.separator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "./";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPath() {
|
||||||
|
return BASE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLogPath() {
|
||||||
|
return LOG_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigPath() {
|
||||||
|
return CONFIG_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPipelinePath() {
|
||||||
|
return PIPELINE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCustomFilesPath() {
|
||||||
|
return CUSTOM_FILES_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getClientWebUIPath() {
|
||||||
|
return CLIENT_WEBUI_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSettingsPath() {
|
||||||
|
return SETTINGS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCustomSettingsPath() {
|
||||||
|
return CUSTOM_SETTINGS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPipelineWatchedFoldersDir() {
|
||||||
|
return PIPELINE_WATCHED_FOLDERS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPipelineFinishedFoldersDir() {
|
||||||
|
return PIPELINE_FINISHED_FOLDERS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStaticPath() {
|
||||||
|
return STATIC_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTemplatesPath() {
|
||||||
|
return TEMPLATES_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSignaturesPath() {
|
||||||
|
return SIGNATURES_PATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import ch.qos.logback.core.PropertyDefinerBase;
|
||||||
|
|
||||||
|
public class LogbackPropertyLoader extends PropertyDefinerBase {
|
||||||
|
@Override
|
||||||
|
public String getPropertyValue() {
|
||||||
|
return InstallationPathConfig.getLogPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,8 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
|||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
// Handler for external static resources
|
// Handler for external static resources
|
||||||
registry.addResourceHandler("/**")
|
registry.addResourceHandler("/**")
|
||||||
.addResourceLocations("file:customFiles/static/", "classpath:/static/");
|
.addResourceLocations(
|
||||||
|
"file:" + InstallationPathConfig.getStaticPath(), "classpath:/static/");
|
||||||
// .setCachePeriod(0); // Optional: disable caching
|
// .setCachePeriod(0); // Optional: disable caching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ public class YamlPropertySourceFactory implements PropertySourceFactory {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||||
factory.setResources(encodedResource.getResource());
|
factory.setResources(encodedResource.getResource());
|
||||||
|
|
||||||
Properties properties = factory.getObject();
|
Properties properties = factory.getObject();
|
||||||
|
|
||||||
return new PropertiesPropertySource(
|
return new PropertiesPropertySource(
|
||||||
|
|||||||
@@ -11,13 +11,11 @@ import org.springframework.core.convert.converter.Converter;
|
|||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
|
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.security.UserService;
|
import stirling.software.SPDF.config.security.UserService;
|
||||||
import stirling.software.SPDF.model.User;
|
import stirling.software.SPDF.model.User;
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CustomSaml2ResponseAuthenticationConverter
|
public class CustomSaml2ResponseAuthenticationConverter
|
||||||
implements Converter<ResponseToken, Saml2Authentication> {
|
implements Converter<ResponseToken, Saml2Authentication> {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import io.swagger.v3.oas.annotations.Hidden;
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@@ -33,7 +34,8 @@ public class SettingsController {
|
|||||||
if (!"undefined".equals(applicationProperties.getSystem().getEnableAnalytics())) {
|
if (!"undefined".equals(applicationProperties.getSystem().getEnableAnalytics())) {
|
||||||
return ResponseEntity.status(HttpStatus.ALREADY_REPORTED)
|
return ResponseEntity.status(HttpStatus.ALREADY_REPORTED)
|
||||||
.body(
|
.body(
|
||||||
"Setting has already been set, To adjust please edit /config/settings.yml");
|
"Setting has already been set, To adjust please edit "
|
||||||
|
+ InstallationPathConfig.getSettingsPath());
|
||||||
}
|
}
|
||||||
GeneralUtils.saveKeyToConfig("system.enableAnalytics", String.valueOf(enabled), false);
|
GeneralUtils.saveKeyToConfig("system.enableAnalytics", String.valueOf(enabled), false);
|
||||||
applicationProperties.getSystem().setEnableAnalytics(String.valueOf(enabled));
|
applicationProperties.getSystem().setEnableAnalytics(String.valueOf(enabled));
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import java.util.zip.ZipEntry;
|
|||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.rendering.ImageType;
|
import org.apache.pdfbox.rendering.ImageType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@@ -31,11 +34,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
|
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
|
||||||
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
|
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
|
||||||
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||||
import stirling.software.SPDF.utils.CheckProgramInstall;
|
import stirling.software.SPDF.utils.*;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor;
|
|
||||||
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/convert")
|
@RequestMapping("/api/v1/convert")
|
||||||
@@ -62,14 +62,20 @@ public class ConvertImgPDFController {
|
|||||||
String singleOrMultiple = request.getSingleOrMultiple();
|
String singleOrMultiple = request.getSingleOrMultiple();
|
||||||
String colorType = request.getColorType();
|
String colorType = request.getColorType();
|
||||||
String dpi = request.getDpi();
|
String dpi = request.getDpi();
|
||||||
|
String pageNumbers = request.getPageNumbers();
|
||||||
Path tempFile = null;
|
Path tempFile = null;
|
||||||
Path tempOutputDir = null;
|
Path tempOutputDir = null;
|
||||||
Path tempPdfPath = null;
|
Path tempPdfPath = null;
|
||||||
byte[] result = null;
|
byte[] result = null;
|
||||||
|
String[] pageOrderArr =
|
||||||
|
(pageNumbers != null && !pageNumbers.trim().isEmpty())
|
||||||
|
? pageNumbers.split(",")
|
||||||
|
: new String[] {"all"};
|
||||||
|
;
|
||||||
try {
|
try {
|
||||||
byte[] pdfBytes = file.getBytes();
|
// Load the input PDF
|
||||||
|
byte[] newPdfBytes = rearrangePdfPages(file.getBytes(), pageOrderArr);
|
||||||
|
|
||||||
ImageType colorTypeResult = ImageType.RGB;
|
ImageType colorTypeResult = ImageType.RGB;
|
||||||
if ("greyscale".equals(colorType)) {
|
if ("greyscale".equals(colorType)) {
|
||||||
colorTypeResult = ImageType.GRAY;
|
colorTypeResult = ImageType.GRAY;
|
||||||
@@ -84,7 +90,7 @@ public class ConvertImgPDFController {
|
|||||||
|
|
||||||
result =
|
result =
|
||||||
PdfUtils.convertFromPdf(
|
PdfUtils.convertFromPdf(
|
||||||
pdfBytes,
|
newPdfBytes,
|
||||||
"webp".equalsIgnoreCase(imageFormat)
|
"webp".equalsIgnoreCase(imageFormat)
|
||||||
? "png"
|
? "png"
|
||||||
: imageFormat.toUpperCase(),
|
: imageFormat.toUpperCase(),
|
||||||
@@ -227,4 +233,46 @@ public class ConvertImgPDFController {
|
|||||||
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
|
String mimeType = URLConnection.guessContentTypeFromName("." + imageFormat);
|
||||||
return "null".equals(mimeType) ? "application/octet-stream" : mimeType;
|
return "null".equals(mimeType) ? "application/octet-stream" : mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rearranges the pages of the given PDF document based on the specified page order.
|
||||||
|
*
|
||||||
|
* @param pdfBytes The byte array of the original PDF file.
|
||||||
|
* @param pageOrderArr An array of page numbers indicating the new order.
|
||||||
|
* @return A byte array of the rearranged PDF.
|
||||||
|
* @throws IOException If an error occurs while processing the PDF.
|
||||||
|
*/
|
||||||
|
private byte[] rearrangePdfPages(byte[] pdfBytes, String[] pageOrderArr) throws IOException {
|
||||||
|
// Load the input PDF
|
||||||
|
PDDocument document = Loader.loadPDF(pdfBytes);
|
||||||
|
int totalPages = document.getNumberOfPages();
|
||||||
|
List<Integer> newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, false);
|
||||||
|
|
||||||
|
// Create a new list to hold the pages in the new order
|
||||||
|
List<PDPage> newPages = new ArrayList<>();
|
||||||
|
for (int pageIndex : newPageOrder) {
|
||||||
|
newPages.add(document.getPage(pageIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all the pages from the original document
|
||||||
|
for (int i = document.getNumberOfPages() - 1; i >= 0; i--) {
|
||||||
|
document.removePage(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the pages in the new order
|
||||||
|
for (PDPage page : newPages) {
|
||||||
|
document.addPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert PDDocument to byte array
|
||||||
|
byte[] newPdfBytes;
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
|
document.save(baos);
|
||||||
|
newPdfBytes = baos.toByteArray();
|
||||||
|
} finally {
|
||||||
|
document.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPdfBytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
|
||||||
import stirling.software.SPDF.model.PipelineConfig;
|
import stirling.software.SPDF.model.PipelineConfig;
|
||||||
import stirling.software.SPDF.model.api.HandleDataRequest;
|
import stirling.software.SPDF.model.api.HandleDataRequest;
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
@@ -35,22 +34,12 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
|||||||
@Tag(name = "Pipeline", description = "Pipeline APIs")
|
@Tag(name = "Pipeline", description = "Pipeline APIs")
|
||||||
public class PipelineController {
|
public class PipelineController {
|
||||||
|
|
||||||
final String watchedFoldersDir = "./pipeline/watchedFolders/";
|
|
||||||
|
|
||||||
final String finishedFoldersDir = "./pipeline/finishedFolders/";
|
|
||||||
|
|
||||||
private final PipelineProcessor processor;
|
private final PipelineProcessor processor;
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
public PipelineController(
|
public PipelineController(PipelineProcessor processor, ObjectMapper objectMapper) {
|
||||||
PipelineProcessor processor,
|
|
||||||
ApplicationProperties applicationProperties,
|
|
||||||
ObjectMapper objectMapper) {
|
|
||||||
this.processor = processor;
|
this.processor = processor;
|
||||||
this.applicationProperties = applicationProperties;
|
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@@ -25,6 +24,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.model.PipelineConfig;
|
import stirling.software.SPDF.model.PipelineConfig;
|
||||||
import stirling.software.SPDF.model.PipelineOperation;
|
import stirling.software.SPDF.model.PipelineOperation;
|
||||||
import stirling.software.SPDF.utils.FileMonitor;
|
import stirling.software.SPDF.utils.FileMonitor;
|
||||||
@@ -48,14 +48,12 @@ public class PipelineDirectoryProcessor {
|
|||||||
public PipelineDirectoryProcessor(
|
public PipelineDirectoryProcessor(
|
||||||
ObjectMapper objectMapper,
|
ObjectMapper objectMapper,
|
||||||
ApiDocService apiDocService,
|
ApiDocService apiDocService,
|
||||||
@Qualifier("watchedFoldersDir") String watchedFoldersDir,
|
|
||||||
@Qualifier("finishedFoldersDir") String finishedFoldersDir,
|
|
||||||
PipelineProcessor processor,
|
PipelineProcessor processor,
|
||||||
FileMonitor fileMonitor) {
|
FileMonitor fileMonitor) {
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
this.apiDocService = apiDocService;
|
this.apiDocService = apiDocService;
|
||||||
this.watchedFoldersDir = watchedFoldersDir;
|
this.watchedFoldersDir = InstallationPathConfig.getPipelineWatchedFoldersDir();
|
||||||
this.finishedFoldersDir = finishedFoldersDir;
|
this.finishedFoldersDir = InstallationPathConfig.getPipelineFinishedFoldersDir();
|
||||||
this.processor = processor;
|
this.processor = processor;
|
||||||
this.fileMonitor = fileMonitor;
|
this.fileMonitor = fileMonitor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.Hidden;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||||
import stirling.software.SPDF.model.SignatureFile;
|
import stirling.software.SPDF.model.SignatureFile;
|
||||||
import stirling.software.SPDF.service.SignatureService;
|
import stirling.software.SPDF.service.SignatureService;
|
||||||
@@ -34,8 +35,6 @@ import stirling.software.SPDF.service.SignatureService;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class GeneralWebController {
|
public class GeneralWebController {
|
||||||
|
|
||||||
private static final String SIGNATURE_BASE_PATH = "customFiles/static/signatures/";
|
|
||||||
private static final String ALL_USERS_FOLDER = "ALL_USERS";
|
|
||||||
private final SignatureService signatureService;
|
private final SignatureService signatureService;
|
||||||
private final UserServiceInterface userService;
|
private final UserServiceInterface userService;
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
@@ -223,7 +222,9 @@ public class GeneralWebController {
|
|||||||
// Extract font names from classpath
|
// Extract font names from classpath
|
||||||
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
|
fontNames.addAll(getFontNamesFromLocation("classpath:static/fonts/*.woff2"));
|
||||||
// Extract font names from external directory
|
// Extract font names from external directory
|
||||||
fontNames.addAll(getFontNamesFromLocation("file:customFiles/static/fonts/*"));
|
fontNames.addAll(
|
||||||
|
getFontNamesFromLocation(
|
||||||
|
"file:" + InstallationPathConfig.getStaticPath() + "fonts/*"));
|
||||||
return fontNames;
|
return fontNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package stirling.software.SPDF.model;
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
@@ -13,18 +15,23 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.support.EncodedResource;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.config.YamlPropertySourceFactory;
|
import stirling.software.SPDF.config.YamlPropertySourceFactory;
|
||||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||||
@@ -33,11 +40,37 @@ import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConfigurationProperties(prefix = "")
|
@ConfigurationProperties(prefix = "")
|
||||||
@PropertySource(value = "file:./configs/settings.yml", factory = YamlPropertySourceFactory.class)
|
|
||||||
@Data
|
@Data
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@Slf4j
|
||||||
public class ApplicationProperties {
|
public class ApplicationProperties {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PropertySource<?> dynamicYamlPropertySource(ConfigurableEnvironment environment)
|
||||||
|
throws IOException {
|
||||||
|
String configPath = InstallationPathConfig.getSettingsPath();
|
||||||
|
log.debug("Attempting to load settings from: " + configPath);
|
||||||
|
|
||||||
|
File file = new File(configPath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
log.error("Warning: Settings file does not exist at: " + configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource resource = new FileSystemResource(configPath);
|
||||||
|
if (!resource.exists()) {
|
||||||
|
throw new FileNotFoundException("Settings file not found at: " + configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedResource encodedResource = new EncodedResource(resource);
|
||||||
|
PropertySource<?> propertySource =
|
||||||
|
new YamlPropertySourceFactory().createPropertySource(null, encodedResource);
|
||||||
|
environment.getPropertySources().addFirst(propertySource);
|
||||||
|
|
||||||
|
log.debug("Loaded properties: " + propertySource.getSource());
|
||||||
|
|
||||||
|
return propertySource;
|
||||||
|
}
|
||||||
|
|
||||||
private Legal legal = new Legal();
|
private Legal legal = new Legal();
|
||||||
private Security security = new Security();
|
private Security security = new Security();
|
||||||
private System system = new System();
|
private System system = new System();
|
||||||
@@ -153,6 +186,7 @@ public class ApplicationProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Resource getSpCert() {
|
public Resource getSpCert() {
|
||||||
|
if (spCert == null) return null;
|
||||||
if (spCert.startsWith("classpath:")) {
|
if (spCert.startsWith("classpath:")) {
|
||||||
return new ClassPathResource(spCert.substring("classpath:".length()));
|
return new ClassPathResource(spCert.substring("classpath:".length()));
|
||||||
} else {
|
} else {
|
||||||
@@ -161,6 +195,7 @@ public class ApplicationProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Resource getidpCert() {
|
public Resource getidpCert() {
|
||||||
|
if (idpCert == null) return null;
|
||||||
if (idpCert.startsWith("classpath:")) {
|
if (idpCert.startsWith("classpath:")) {
|
||||||
return new ClassPathResource(idpCert.substring("classpath:".length()));
|
return new ClassPathResource(idpCert.substring("classpath:".length()));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ public class ConvertToImageRequest extends PDFFile {
|
|||||||
allowableValues = {"single", "multiple"})
|
allowableValues = {"single", "multiple"})
|
||||||
private String singleOrMultiple;
|
private String singleOrMultiple;
|
||||||
|
|
||||||
|
@Schema(
|
||||||
|
description =
|
||||||
|
"The pages to select, Supports ranges (e.g., '1,3,5-9'), or 'all' 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')\"")
|
||||||
|
private String pageNumbers;
|
||||||
|
|
||||||
@Schema(
|
@Schema(
|
||||||
description = "The color type of the output image(s)",
|
description = "The color type of the output image(s)",
|
||||||
allowableValues = {"color", "greyscale", "blackwhite"})
|
allowableValues = {"color", "greyscale", "blackwhite"})
|
||||||
|
|||||||
@@ -13,14 +13,19 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.thymeleaf.util.StringUtils;
|
import org.thymeleaf.util.StringUtils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.model.SignatureFile;
|
import stirling.software.SPDF.model.SignatureFile;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SignatureService {
|
public class SignatureService {
|
||||||
|
|
||||||
private static final String SIGNATURE_BASE_PATH = "customFiles/signatures/";
|
private final String SIGNATURE_BASE_PATH;
|
||||||
private static final String ALL_USERS_FOLDER = "ALL_USERS";
|
private final String ALL_USERS_FOLDER = "ALL_USERS";
|
||||||
|
|
||||||
|
public SignatureService() {
|
||||||
|
SIGNATURE_BASE_PATH = InstallationPathConfig.getSignaturesPath();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasAccessToFile(String username, String fileName) throws IOException {
|
public boolean hasAccessToFile(String username, String fileName) throws IOException {
|
||||||
validateFileName(fileName);
|
validateFileName(fileName);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -34,9 +35,7 @@ public class FileMonitor {
|
|||||||
* monitored, false otherwise
|
* monitored, false otherwise
|
||||||
*/
|
*/
|
||||||
@Autowired
|
@Autowired
|
||||||
public FileMonitor(
|
public FileMonitor(@Qualifier("directoryFilter") Predicate<Path> pathFilter)
|
||||||
@Qualifier("watchedFoldersDir") String rootDirectory,
|
|
||||||
@Qualifier("directoryFilter") Predicate<Path> pathFilter)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
this.newlyDiscoveredFiles = new HashSet<>();
|
this.newlyDiscoveredFiles = new HashSet<>();
|
||||||
this.path2KeyMapping = new HashMap<>();
|
this.path2KeyMapping = new HashMap<>();
|
||||||
@@ -44,7 +43,7 @@ public class FileMonitor {
|
|||||||
this.pathFilter = pathFilter;
|
this.pathFilter = pathFilter;
|
||||||
this.readyForProcessingFiles = ConcurrentHashMap.newKeySet();
|
this.readyForProcessingFiles = ConcurrentHashMap.newKeySet();
|
||||||
this.watchService = FileSystems.getDefault().newWatchService();
|
this.watchService = FileSystems.getDefault().newWatchService();
|
||||||
this.rootDir = Path.of(rootDirectory);
|
this.rootDir = Path.of(InstallationPathConfig.getPipelineWatchedFoldersDir());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldNotProcess(Path path) {
|
private boolean shouldNotProcess(Path path) {
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.simpleyaml.configuration.file.YamlFile;
|
import org.simpleyaml.configuration.file.YamlFile;
|
||||||
import org.simpleyaml.configuration.file.YamlFileWrapper;
|
import org.simpleyaml.configuration.file.YamlFileWrapper;
|
||||||
@@ -28,6 +26,7 @@ import io.github.pixee.security.HostValidator;
|
|||||||
import io.github.pixee.security.Urls;
|
import io.github.pixee.security.Urls;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GeneralUtils {
|
public class GeneralUtils {
|
||||||
@@ -85,7 +84,7 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
// Allow only http and https protocols
|
// Allow only http and https protocols
|
||||||
String protocol = url.getProtocol();
|
String protocol = url.getProtocol();
|
||||||
if (!protocol.equals("http") && !protocol.equals("https")) {
|
if (!"http".equals(protocol) && !"https".equals(protocol)) {
|
||||||
return false; // Disallow other protocols
|
return false; // Disallow other protocols
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +228,7 @@ public class GeneralUtils {
|
|||||||
Double result = evaluator.evaluate(sanitizedExpression);
|
Double result = evaluator.evaluate(sanitizedExpression);
|
||||||
|
|
||||||
// Check if the result is null or not within bounds
|
// Check if the result is null or not within bounds
|
||||||
if (result == null)
|
if (result == null) break;
|
||||||
break;
|
|
||||||
|
|
||||||
if (result.intValue() > 0 && result.intValue() <= maxValue)
|
if (result.intValue() > 0 && result.intValue() <= maxValue)
|
||||||
results.add(result.intValue());
|
results.add(result.intValue());
|
||||||
@@ -241,11 +239,15 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
private static String sanitizeNFunction(String expression, int nValue) {
|
private static String sanitizeNFunction(String expression, int nValue) {
|
||||||
String sanitizedExpression = expression.replace(" ", "");
|
String sanitizedExpression = expression.replace(" ", "");
|
||||||
String multiplyByOpeningRoundBracketPattern = "([0-9n)])\\("; // example: n(n-1), 9(n-1), (n-1)(n-2)
|
String multiplyByOpeningRoundBracketPattern =
|
||||||
sanitizedExpression = sanitizedExpression.replaceAll(multiplyByOpeningRoundBracketPattern, "$1*(");
|
"([0-9n)])\\("; // example: n(n-1), 9(n-1), (n-1)(n-2)
|
||||||
|
sanitizedExpression =
|
||||||
|
sanitizedExpression.replaceAll(multiplyByOpeningRoundBracketPattern, "$1*(");
|
||||||
|
|
||||||
String multiplyByClosingRoundBracketPattern = "\\)([0-9n)])"; // example: (n-1)n, (n-1)9, (n-1)(n-2)
|
String multiplyByClosingRoundBracketPattern =
|
||||||
sanitizedExpression = sanitizedExpression.replaceAll(multiplyByClosingRoundBracketPattern, ")*$1");
|
"\\)([0-9n)])"; // example: (n-1)n, (n-1)9, (n-1)(n-2)
|
||||||
|
sanitizedExpression =
|
||||||
|
sanitizedExpression.replaceAll(multiplyByClosingRoundBracketPattern, ")*$1");
|
||||||
|
|
||||||
sanitizedExpression = insertMultiplicationBeforeN(sanitizedExpression, nValue);
|
sanitizedExpression = insertMultiplicationBeforeN(sanitizedExpression, nValue);
|
||||||
return sanitizedExpression;
|
return sanitizedExpression;
|
||||||
@@ -341,7 +343,10 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
public static void saveKeyToConfig(String id, String key, boolean autoGenerated)
|
public static void saveKeyToConfig(String id, String key, boolean autoGenerated)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml
|
Path path =
|
||||||
|
Paths.get(
|
||||||
|
InstallationPathConfig
|
||||||
|
.getSettingsPath()); // Target the configs/settings.yml
|
||||||
|
|
||||||
final YamlFile settingsYml = new YamlFile(path.toFile());
|
final YamlFile settingsYml = new YamlFile(path.toFile());
|
||||||
DumperOptions yamlOptionssettingsYml =
|
DumperOptions yamlOptionssettingsYml =
|
||||||
@@ -359,7 +364,7 @@ public class GeneralUtils {
|
|||||||
|
|
||||||
public static void saveKeyToConfig(String id, boolean key, boolean autoGenerated)
|
public static void saveKeyToConfig(String id, boolean key, boolean autoGenerated)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Path path = Paths.get("configs", "settings.yml");
|
Path path = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||||
|
|
||||||
final YamlFile settingsYml = new YamlFile(path.toFile());
|
final YamlFile settingsYml = new YamlFile(path.toFile());
|
||||||
DumperOptions yamlOptionssettingsYml =
|
DumperOptions yamlOptionssettingsYml =
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
package stirling.software.SPDF.utils;
|
|
||||||
|
|
||||||
public class PDFManipulationUtils {}
|
|
||||||
@@ -9,6 +9,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ public class PDFToFile {
|
|||||||
.runCommandWithOutputHandling(command, tempOutputDir.toFile());
|
.runCommandWithOutputHandling(command, tempOutputDir.toFile());
|
||||||
|
|
||||||
// Get output files
|
// Get output files
|
||||||
List<File> outputFiles = Arrays.asList(tempOutputDir.toFile().listFiles());
|
File[] outputFiles = Objects.requireNonNull(tempOutputDir.toFile().listFiles());
|
||||||
|
|
||||||
// Return output files in a ZIP archive
|
// Return output files in a ZIP archive
|
||||||
fileName = pdfBaseName + "ToHtml.zip";
|
fileName = pdfBaseName + "ToHtml.zip";
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ import org.apache.pdfbox.text.TextPosition;
|
|||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
|
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
|
||||||
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {
|
public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {
|
||||||
|
|
||||||
private String textColor;
|
private String textColor;
|
||||||
@@ -93,17 +95,17 @@ public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {
|
|||||||
try {
|
try {
|
||||||
font = PDFontFactory.createFont(text.getFont().getCOSObject());
|
font = PDFontFactory.createFont(text.getFont().getCOSObject());
|
||||||
} catch (IOException io) {
|
} catch (IOException io) {
|
||||||
System.out.println("Primary font not found, using fallback font.");
|
log.info("Primary font not found, using fallback font.");
|
||||||
font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
|
||||||
}
|
}
|
||||||
// if a character is not supported by font, then look for supported font
|
// if a character is not supported by font, then look for supported font
|
||||||
try {
|
try {
|
||||||
byte[] bytes = font.encode(unicodeText);
|
byte[] bytes = font.encode(unicodeText);
|
||||||
} catch (IOException io) {
|
} catch (IOException io) {
|
||||||
System.out.println("text could not be encoded ");
|
log.info("text could not be encoded ");
|
||||||
font = checkSupportedFontForCharacter(unicodeText);
|
font = checkSupportedFontForCharacter(unicodeText);
|
||||||
} catch (IllegalArgumentException ie) {
|
} catch (IllegalArgumentException ie) {
|
||||||
System.out.println("text not supported by font ");
|
log.info("text not supported by font ");
|
||||||
font = checkSupportedFontForCharacter(unicodeText);
|
font = checkSupportedFontForCharacter(unicodeText);
|
||||||
} finally {
|
} finally {
|
||||||
// if any other font is not supported, then replace default character *
|
// if any other font is not supported, then replace default character *
|
||||||
@@ -157,9 +159,9 @@ public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {
|
|||||||
byte[] bytes = currentFont.encode(unicodeText);
|
byte[] bytes = currentFont.encode(unicodeText);
|
||||||
return currentFont;
|
return currentFont;
|
||||||
} catch (IOException io) {
|
} catch (IOException io) {
|
||||||
System.out.println("text could not be encoded ");
|
log.info("text could not be encoded ");
|
||||||
} catch (IllegalArgumentException ie) {
|
} catch (IllegalArgumentException ie) {
|
||||||
System.out.println("text not supported by font ");
|
log.info("text not supported by font ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ spring.devtools.restart.exclude=stirling.software.SPDF.config.security/**
|
|||||||
spring.thymeleaf.encoding=UTF-8
|
spring.thymeleaf.encoding=UTF-8
|
||||||
spring.web.resources.mime-mappings.webmanifest=application/manifest+json
|
spring.web.resources.mime-mappings.webmanifest=application/manifest+json
|
||||||
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
|
spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000}
|
||||||
#spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/
|
|
||||||
#spring.thymeleaf.cache=false
|
|
||||||
spring.datasource.url=jdbc:h2:file:./configs/stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
spring.datasource.url=jdbc:h2:file:./configs/stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||||
spring.datasource.driver-class-name=org.h2.Driver
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
spring.datasource.username=sa
|
spring.datasource.username=sa
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<define name="LOG_PATH" class="stirling.software.SPDF.config.LogbackPropertyLoader" />
|
||||||
|
|
||||||
<!-- Console Appender -->
|
<!-- Console Appender -->
|
||||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
@@ -7,35 +9,30 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!-- Rolling File Appender -->
|
<!-- Rolling File Appender for Auth Logs -->
|
||||||
<appender name="AUTHLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="AUTHLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>logs/invalid-auths.log</file>
|
<file>${LOG_PATH}/invalid-auths.log</file>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d %p %c{1} [%thread] %m%n</pattern>
|
<pattern>%d %p %c{1} [%thread] %m%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
<!-- daily rollover and keep 7 days' worth of history -->
|
<fileNamePattern>${LOG_PATH}/auth-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
<fileNamePattern>logs/auth-%d{yyyy-MM-dd}.log</fileNamePattern>
|
|
||||||
<maxHistory>1</maxHistory>
|
<maxHistory>1</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<!-- Rolling File Appender -->
|
<!-- Rolling File Appender for General Logs -->
|
||||||
<appender name="GENERAL" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="GENERAL" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>logs/info.log</file>
|
<file>${LOG_PATH}/info.log</file>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d %p %c{1} [%thread] %m%n</pattern>
|
<pattern>%d %p %c{1} [%thread] %m%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
<!-- daily rollover and keep 7 days' worth of history -->
|
<fileNamePattern>${LOG_PATH}/info-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
<fileNamePattern>logs/info-%d{yyyy-MM-dd}.log</fileNamePattern>
|
|
||||||
<maxHistory>1</maxHistory>
|
<maxHistory>1</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
|
||||||
<!-- Root Logger -->
|
<!-- Root Logger -->
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="CONSOLE"/>
|
<appender-ref ref="CONSOLE"/>
|
||||||
@@ -43,10 +40,9 @@
|
|||||||
</root>
|
</root>
|
||||||
|
|
||||||
<!-- Specific Logger -->
|
<!-- Specific Logger -->
|
||||||
<logger name="stirling.software.SPDF.config.security.CustomAuthenticationFailureHandler" level="ERROR"
|
<logger name="stirling.software.SPDF.config.security.CustomAuthenticationFailureHandler"
|
||||||
additivity="false">
|
level="ERROR" additivity="false">
|
||||||
<appender-ref ref="CONSOLE"/>
|
<appender-ref ref="CONSOLE"/>
|
||||||
<appender-ref ref="AUTHLOG"/>
|
<appender-ref ref="AUTHLOG"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
</configuration>
|
||||||
</configuration>
|
|
||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=تدرج الرمادي
|
|||||||
pdfToImage.blackwhite=أبيض وأسود (قد يفقد البيانات!)
|
pdfToImage.blackwhite=أبيض وأسود (قد يفقد البيانات!)
|
||||||
pdfToImage.submit=تحويل
|
pdfToImage.submit=تحويل
|
||||||
pdfToImage.info=Python غير مثبت. مطلوب لتحويل WebP.
|
pdfToImage.info=Python غير مثبت. مطلوب لتحويل WebP.
|
||||||
|
pdfToImage.placeholder=(مثال: 1,2,8 أو 4,7,12-16 أو 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Boz Tonlama
|
|||||||
pdfToImage.blackwhite=Qara və Ağ (Data İtə Bilər)
|
pdfToImage.blackwhite=Qara və Ağ (Data İtə Bilər)
|
||||||
pdfToImage.submit=Çevir
|
pdfToImage.submit=Çevir
|
||||||
pdfToImage.info=Python Yüklü Deyil.WebP Çevirməsi Üçün Vacibdir
|
pdfToImage.info=Python Yüklü Deyil.WebP Çevirməsi Üçün Vacibdir
|
||||||
|
pdfToImage.placeholder=(məsələn, 1,2,8 və ya 4,7,12-16 və ya 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Скала на сивото
|
|||||||
pdfToImage.blackwhite=Черно и бяло (може да загубите данни!)
|
pdfToImage.blackwhite=Черно и бяло (може да загубите данни!)
|
||||||
pdfToImage.submit=Преобразуване
|
pdfToImage.submit=Преобразуване
|
||||||
pdfToImage.info=Python не е инсталиран. Изисква се за конвертиране на WebP.
|
pdfToImage.info=Python не е инсталиран. Изисква се за конвертиране на WebP.
|
||||||
|
pdfToImage.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Escala de Grisos
|
|||||||
pdfToImage.blackwhite=Blanc i Negre (Pot perdre dades!)
|
pdfToImage.blackwhite=Blanc i Negre (Pot perdre dades!)
|
||||||
pdfToImage.submit=Converteix
|
pdfToImage.submit=Converteix
|
||||||
pdfToImage.info=Python no està instal·lat. És necessari per a la conversió a WebP.
|
pdfToImage.info=Python no està instal·lat. És necessari per a la conversió a WebP.
|
||||||
|
pdfToImage.placeholder=(p. ex. 1,2,8 o 4,7,12-16 o 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Stupně šedi
|
|||||||
pdfToImage.blackwhite=Černobílý (Může dojít k ztrátě dat!)
|
pdfToImage.blackwhite=Černobílý (Může dojít k ztrátě dat!)
|
||||||
pdfToImage.submit=Převést
|
pdfToImage.submit=Převést
|
||||||
pdfToImage.info=Python není nainstalován. Potřebuje se pro konverzi do WebP.
|
pdfToImage.info=Python není nainstalován. Potřebuje se pro konverzi do WebP.
|
||||||
|
pdfToImage.placeholder=(např. 1,2,8 nebo 4,7,12-16 nebo 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Gråtone
|
|||||||
pdfToImage.blackwhite=Sort og Hvid (Kan miste data!)
|
pdfToImage.blackwhite=Sort og Hvid (Kan miste data!)
|
||||||
pdfToImage.submit=Konvertér
|
pdfToImage.submit=Konvertér
|
||||||
pdfToImage.info=Python er ikke installeret. Påkrævet for WebP-konvertering.
|
pdfToImage.info=Python er ikke installeret. Påkrævet for WebP-konvertering.
|
||||||
|
pdfToImage.placeholder=(f.eks. 1,2,8 eller 4,7,12-16 eller 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Graustufen
|
|||||||
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
|
pdfToImage.blackwhite=Schwarzweiß (Datenverlust möglich!)
|
||||||
pdfToImage.submit=Umwandeln
|
pdfToImage.submit=Umwandeln
|
||||||
pdfToImage.info=Python ist nicht installiert. Erforderlich für die WebP-Konvertierung.
|
pdfToImage.info=Python ist nicht installiert. Erforderlich für die WebP-Konvertierung.
|
||||||
|
pdfToImage.placeholder=(z.B. 1,2,8 oder 4,7,12-16 oder 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Κλίμακα του γκρι
|
|||||||
pdfToImage.blackwhite=Ασπρόμαυρο (Μπορεί να χαθούν δεδομένα!)
|
pdfToImage.blackwhite=Ασπρόμαυρο (Μπορεί να χαθούν δεδομένα!)
|
||||||
pdfToImage.submit=Μετατροπή
|
pdfToImage.submit=Μετατροπή
|
||||||
pdfToImage.info=Δεν είναι ιστάμενος Python. Είναι απαιτήτων για τη μετατροπή σε WebP.
|
pdfToImage.info=Δεν είναι ιστάμενος Python. Είναι απαιτήτων για τη μετατροπή σε WebP.
|
||||||
|
pdfToImage.placeholder=(π.χ. 1,2,8 ή 4,7,12-16 ή 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Greyscale
|
|||||||
pdfToImage.blackwhite=Black and White (May lose data!)
|
pdfToImage.blackwhite=Black and White (May lose data!)
|
||||||
pdfToImage.submit=Convert
|
pdfToImage.submit=Convert
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Grayscale
|
|||||||
pdfToImage.blackwhite=Black and White (May lose data!)
|
pdfToImage.blackwhite=Black and White (May lose data!)
|
||||||
pdfToImage.submit=Convert
|
pdfToImage.submit=Convert
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Escala de grises
|
|||||||
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
|
pdfToImage.blackwhite=Blanco y Negro (¡Puede perder datos!)
|
||||||
pdfToImage.submit=Convertir
|
pdfToImage.submit=Convertir
|
||||||
pdfToImage.info=Python no está instalado. Se requiere para la conversión WebP.
|
pdfToImage.info=Python no está instalado. Se requiere para la conversión WebP.
|
||||||
|
pdfToImage.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Gris-eskala
|
|||||||
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
|
pdfToImage.blackwhite=Zuria eta Beltza (Datuak galdu ditzake!)
|
||||||
pdfToImage.submit=Bihurtu
|
pdfToImage.submit=Bihurtu
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=خاکستری
|
|||||||
pdfToImage.blackwhite=سیاه و سفید (ممکن است اطلاعات از دست برود!)
|
pdfToImage.blackwhite=سیاه و سفید (ممکن است اطلاعات از دست برود!)
|
||||||
pdfToImage.submit=تبدیل
|
pdfToImage.submit=تبدیل
|
||||||
pdfToImage.info=پایتون نصب نشده است. برای تبدیل WebP لازم است.
|
pdfToImage.info=پایتون نصب نشده است. برای تبدیل WebP لازم است.
|
||||||
|
pdfToImage.placeholder=(مثال: 1,2,8 یا 4,7,12-16 یا 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Niveaux de gris
|
|||||||
pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données !)
|
pdfToImage.blackwhite=Noir et blanc (peut engendrer une perte de données !)
|
||||||
pdfToImage.submit=Convertir
|
pdfToImage.submit=Convertir
|
||||||
pdfToImage.info=Python n’est pas installé. Nécessaire pour la conversion WebP.
|
pdfToImage.info=Python n’est pas installé. Nécessaire pour la conversion WebP.
|
||||||
|
pdfToImage.placeholder=(par exemple : 1,2,8 ou 4,7,12-16 ou 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Scála Liath
|
|||||||
pdfToImage.blackwhite=Dubh agus Bán (D’fhéadfadh sonraí a chailleadh!)
|
pdfToImage.blackwhite=Dubh agus Bán (D’fhéadfadh sonraí a chailleadh!)
|
||||||
pdfToImage.submit=Tiontaigh
|
pdfToImage.submit=Tiontaigh
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(m.sh. 1,2,8 nó 4,7,12-16 nó 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=ग्रे स्केल
|
|||||||
pdfToImage.blackwhite=काला और सफेद (डेटा खो सकता है!)
|
pdfToImage.blackwhite=काला और सफेद (डेटा खो सकता है!)
|
||||||
pdfToImage.submit=परिवर्तित करें
|
pdfToImage.submit=परिवर्तित करें
|
||||||
pdfToImage.info=पायथन नहीं अनिस्तारित है। वेबP परिवर्तन के लिए आवश्यक है।
|
pdfToImage.info=पायथन नहीं अनिस्तारित है। वेबP परिवर्तन के लिए आवश्यक है।
|
||||||
|
pdfToImage.placeholder=(उदाहरण के लिए 1,2,8 या 4,7,12-16 या 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Sivi tonovi
|
|||||||
pdfToImage.blackwhite=Crno-bijelo (mogu se izgubiti podaci!)
|
pdfToImage.blackwhite=Crno-bijelo (mogu se izgubiti podaci!)
|
||||||
pdfToImage.submit=Pretvori
|
pdfToImage.submit=Pretvori
|
||||||
pdfToImage.info=Python nije instaliran. Treba je za konverziju na WebP.
|
pdfToImage.info=Python nije instaliran. Treba je za konverziju na WebP.
|
||||||
|
pdfToImage.placeholder=(t.j. 1,2,8 ili 4,7,12-16 ili 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=szürkeárnyalatos
|
|||||||
pdfToImage.blackwhite=fekete-fehér (adatvesztéssel járhat!)
|
pdfToImage.blackwhite=fekete-fehér (adatvesztéssel járhat!)
|
||||||
pdfToImage.submit=Átalakítás
|
pdfToImage.submit=Átalakítás
|
||||||
pdfToImage.info=Nincs telepítve a Python. Szükséges a WebP konverzióhoz.
|
pdfToImage.info=Nincs telepítve a Python. Szükséges a WebP konverzióhoz.
|
||||||
|
pdfToImage.placeholder=(pl. 1,2,8 vagy 4,7,12-16 vagy 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Skala abu-abu
|
|||||||
pdfToImage.blackwhite=Black and White (Bisa kehilangan data!)
|
pdfToImage.blackwhite=Black and White (Bisa kehilangan data!)
|
||||||
pdfToImage.submit=Konversi
|
pdfToImage.submit=Konversi
|
||||||
pdfToImage.info=Python tidak terinstal. Diperlukan untuk konversi WebP.
|
pdfToImage.info=Python tidak terinstal. Diperlukan untuk konversi WebP.
|
||||||
|
pdfToImage.placeholder=(misalnya 1,2,8 atau 4,7,12-16 atau 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ login.oauth2invalidRequest=Richiesta non valida
|
|||||||
login.oauth2AccessDenied=Accesso negato
|
login.oauth2AccessDenied=Accesso negato
|
||||||
login.oauth2InvalidTokenResponse=Risposta token non valida
|
login.oauth2InvalidTokenResponse=Risposta token non valida
|
||||||
login.oauth2InvalidIdToken=Id Token non valido
|
login.oauth2InvalidIdToken=Id Token non valido
|
||||||
login.relyingPartyRegistrationNotFound=No relying party registration found
|
login.relyingPartyRegistrationNotFound=Nessuna registrazione di parte affidabile trovata
|
||||||
login.userIsDisabled=L'utente è disattivato, l'accesso è attualmente bloccato con questo nome utente. Si prega di contattare l'amministratore.
|
login.userIsDisabled=L'utente è disattivato, l'accesso è attualmente bloccato con questo nome utente. Si prega di contattare l'amministratore.
|
||||||
login.alreadyLoggedIn=Hai già effettuato l'accesso a
|
login.alreadyLoggedIn=Hai già effettuato l'accesso a
|
||||||
login.alreadyLoggedIn2=dispositivi. Esci dai dispositivi e riprova.
|
login.alreadyLoggedIn2=dispositivi. Esci dai dispositivi e riprova.
|
||||||
@@ -831,7 +831,7 @@ sign.first=Prima pagina
|
|||||||
sign.last=Ultima pagina
|
sign.last=Ultima pagina
|
||||||
sign.next=Prossima pagina
|
sign.next=Prossima pagina
|
||||||
sign.previous=Pagina precedente
|
sign.previous=Pagina precedente
|
||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Attiva il mantenimento delle proporzioni
|
||||||
#repair
|
#repair
|
||||||
repair.title=Ripara
|
repair.title=Ripara
|
||||||
repair.header=Ripara PDF
|
repair.header=Ripara PDF
|
||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Scala di grigi
|
|||||||
pdfToImage.blackwhite=Bianco e Nero (potresti perdere dettagli!)
|
pdfToImage.blackwhite=Bianco e Nero (potresti perdere dettagli!)
|
||||||
pdfToImage.submit=Converti
|
pdfToImage.submit=Converti
|
||||||
pdfToImage.info=Python non è installato.È richiesto per la conversione WebP.
|
pdfToImage.info=Python non è installato.È richiesto per la conversione WebP.
|
||||||
|
pdfToImage.placeholder=(es. 1,2,8 o 4,7,12-16 o 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
@@ -1285,8 +1286,8 @@ splitByChapters.submit=Dividi PDF
|
|||||||
fileChooser.click=Clicca
|
fileChooser.click=Clicca
|
||||||
fileChooser.or=o
|
fileChooser.or=o
|
||||||
fileChooser.dragAndDrop=Trascina & Rilascia
|
fileChooser.dragAndDrop=Trascina & Rilascia
|
||||||
fileChooser.dragAndDropPDF=Drag & Drop PDF file
|
fileChooser.dragAndDropPDF=Trascina & rilascia il file PDF
|
||||||
fileChooser.dragAndDropImage=Drag & Drop Image file
|
fileChooser.dragAndDropImage=Trascina & rilascia il file immagine
|
||||||
fileChooser.hoveredDragAndDrop=Trascina & rilascia i file qui
|
fileChooser.hoveredDragAndDrop=Trascina & rilascia i file qui
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=グレースケール
|
|||||||
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
|
pdfToImage.blackwhite=白黒 (データが失われる可能性があります!)
|
||||||
pdfToImage.submit=変換
|
pdfToImage.submit=変換
|
||||||
pdfToImage.info=Pythonがインストールされていません。WebPの変換に必要です。
|
pdfToImage.info=Pythonがインストールされていません。WebPの変換に必要です。
|
||||||
|
pdfToImage.placeholder=(例:1,2,8、4,7,12-16、2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=그레이스케일
|
|||||||
pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!)
|
pdfToImage.blackwhite=흑백 (데이터 손실 가능성 있음!)
|
||||||
pdfToImage.submit=변환
|
pdfToImage.submit=변환
|
||||||
pdfToImage.info=Python이 설치되어 있지 않습니다. WebP 변환에 필요합니다.
|
pdfToImage.info=Python이 설치되어 있지 않습니다. WebP 변환에 필요합니다.
|
||||||
|
pdfToImage.placeholder=(예: 1,2,8 또는 4,7,12-16 또는 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Grijstinten
|
|||||||
pdfToImage.blackwhite=Zwart en wit (kan data verliezen!)
|
pdfToImage.blackwhite=Zwart en wit (kan data verliezen!)
|
||||||
pdfToImage.submit=Omzetten
|
pdfToImage.submit=Omzetten
|
||||||
pdfToImage.info=Python is niet geïnstalleerd. Vereist voor WebP-conversie.
|
pdfToImage.info=Python is niet geïnstalleerd. Vereist voor WebP-conversie.
|
||||||
|
pdfToImage.placeholder=(bijv. 1,2,8 of 4,7,12-16 of 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Gråtone
|
|||||||
pdfToImage.blackwhite=Svart-hvitt (kan miste data!)
|
pdfToImage.blackwhite=Svart-hvitt (kan miste data!)
|
||||||
pdfToImage.submit=Konverter
|
pdfToImage.submit=Konverter
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(f.eks. 1,2,8 eller 4,7,12-16 eller 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Odcień szarości
|
|||||||
pdfToImage.blackwhite=Czarno-biały (może spowodować utratę danych!)
|
pdfToImage.blackwhite=Czarno-biały (może spowodować utratę danych!)
|
||||||
pdfToImage.submit=Konwertuj
|
pdfToImage.submit=Konwertuj
|
||||||
pdfToImage.info=Python nie został zainstalowany. Jest wymagany do konwersji WebP.
|
pdfToImage.info=Python nie został zainstalowany. Jest wymagany do konwersji WebP.
|
||||||
|
pdfToImage.placeholder=(przykład 1,2,8 lub 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Escala de Cinza
|
|||||||
pdfToImage.blackwhite=Preto e Branco (pode perder informações!)
|
pdfToImage.blackwhite=Preto e Branco (pode perder informações!)
|
||||||
pdfToImage.submit=Converter
|
pdfToImage.submit=Converter
|
||||||
pdfToImage.info=Python não está instalado. Necessário para conversão WebP.
|
pdfToImage.info=Python não está instalado. Necessário para conversão WebP.
|
||||||
|
pdfToImage.placeholder=(por exemplo 1,2,8 or 4,7,12-16 ou 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Escala de Cinza
|
|||||||
pdfToImage.blackwhite=Preto e Branco (pode resultar em perda de dados!)
|
pdfToImage.blackwhite=Preto e Branco (pode resultar em perda de dados!)
|
||||||
pdfToImage.submit=Converter
|
pdfToImage.submit=Converter
|
||||||
pdfToImage.info=O Python não está instalado. Necessário para a conversão de WebP.
|
pdfToImage.info=O Python não está instalado. Necessário para a conversão de WebP.
|
||||||
|
pdfToImage.placeholder=(ex: 1,2,8 ou 4,7,12-16 ou 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Scală de gri
|
|||||||
pdfToImage.blackwhite=Alb și negru (Poate pierde date!)
|
pdfToImage.blackwhite=Alb și negru (Poate pierde date!)
|
||||||
pdfToImage.submit=Convertește
|
pdfToImage.submit=Convertește
|
||||||
pdfToImage.info=Python nu este instalat. Necesar pentru conversia WebP.
|
pdfToImage.info=Python nu este instalat. Necesar pentru conversia WebP.
|
||||||
|
pdfToImage.placeholder=(ex. 1,2,8 sau 4,7,12-16 sau 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Оттенки серого
|
|||||||
pdfToImage.blackwhite=Черно-белый (может потерять данные!)
|
pdfToImage.blackwhite=Черно-белый (может потерять данные!)
|
||||||
pdfToImage.submit=Конвертировать
|
pdfToImage.submit=Конвертировать
|
||||||
pdfToImage.info=Питон не установлен. Необходим для конвертации в WebP.
|
pdfToImage.info=Питон не установлен. Необходим для конвертации в WebP.
|
||||||
|
pdfToImage.placeholder=(например 1,2,8 или 4,7,12-16 или 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Odtiene šedej
|
|||||||
pdfToImage.blackwhite=Čierno-biele (Môže stratiť údaje!)
|
pdfToImage.blackwhite=Čierno-biele (Môže stratiť údaje!)
|
||||||
pdfToImage.submit=Konvertovať
|
pdfToImage.submit=Konvertovať
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(napr. 1,2,8 alebo 4,7,12-16 alebo 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Nijanse sive
|
|||||||
pdfToImage.blackwhite=Crno-belo (Može izgubiti podatke!)
|
pdfToImage.blackwhite=Crno-belo (Može izgubiti podatke!)
|
||||||
pdfToImage.submit=Konvertuj
|
pdfToImage.submit=Konvertuj
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(e.g. 1,2,8 or 4,7,12-16 or 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ database.fileNullOrEmpty=Filen får inte vara null eller tom
|
|||||||
database.failedImportFile=Misslyckades med att importera fil
|
database.failedImportFile=Misslyckades med att importera fil
|
||||||
|
|
||||||
session.expired=Din session har löpt ut. Uppdatera sidan och försök igen.
|
session.expired=Din session har löpt ut. Uppdatera sidan och försök igen.
|
||||||
session.refreshPage=Refresh Page
|
session.refreshPage=Uppdatera sida
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
@@ -519,9 +519,9 @@ home.validateSignature.desc=Verify digital signatures and certificates in PDF do
|
|||||||
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Ersätt-Invertera-Färg
|
||||||
replace-color.header=Ersätt-Invertera färg på PDF
|
replace-color.header=Ersätt-Invertera färg på PDF
|
||||||
home.replaceColorPdf.title=Replace and Invert Color
|
home.replaceColorPdf.title=Ersätt och Invertera färg
|
||||||
home.replaceColorPdf.desc=Ersätt färg för text och bakgrund i PDF och invertera hela färgen på PDF för att minska filstorlek
|
home.replaceColorPdf.desc=Ersätt färg för text och bakgrund i PDF och invertera hela färgen på PDF för att minska filstorlek
|
||||||
replaceColorPdf.tags=Ersätt Färg, Sidåtgärder, Bakomliggande, Serversid
|
replaceColorPdf.tags=Ersätt Färg, Sidåtgärder, Bakomliggande, Serversid
|
||||||
replace-color.selectText.1=Ersätt eller Invertera färgalternativ
|
replace-color.selectText.1=Ersätt eller Invertera färgalternativ
|
||||||
@@ -969,17 +969,17 @@ multiTool.undo=Undo
|
|||||||
multiTool.redo=Redo
|
multiTool.redo=Redo
|
||||||
|
|
||||||
#decrypt
|
#decrypt
|
||||||
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
decrypt.passwordPrompt=Denna fil är lösenordsskyddad. Fyll i lösenord:
|
||||||
decrypt.cancelled=Operation cancelled for PDF: {0}
|
decrypt.cancelled=Operation misslyckades för PDF: {0}
|
||||||
decrypt.noPassword=No password provided for encrypted PDF: {0}
|
decrypt.noPassword=Inget lösenord angivet för krypterad PDF: {0}
|
||||||
decrypt.invalidPassword=Please try again with the correct password.
|
decrypt.invalidPassword=Försök igen med korrekt lösenord.
|
||||||
decrypt.invalidPasswordHeader=Incorrect password or unsupported encryption for PDF: {0}
|
decrypt.invalidPasswordHeader=Felaktigt lösenord eller osupportad kryptering för PDF: {0}
|
||||||
decrypt.unexpectedError=There was an error processing the file. Please try again.
|
decrypt.unexpectedError=Det uppstod ett fel vid processering av filen. Vänligen försök igen.
|
||||||
decrypt.serverError=Server error while decrypting: {0}
|
decrypt.serverError=Serverfel vid avkryptering: {0}
|
||||||
decrypt.success=File decrypted successfully.
|
decrypt.success=Fil avkrypterad.
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=Denna funktion finns också tillgänglig i vår <a href="{0}">multi-tool page</a>. Spana in den för bättre sida-för-sida anpassning och ytterligare funktioner!
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=Visa PDF
|
viewPdf.title=Visa PDF
|
||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Gråskala
|
|||||||
pdfToImage.blackwhite=Svartvitt (kan förlora data!)
|
pdfToImage.blackwhite=Svartvitt (kan förlora data!)
|
||||||
pdfToImage.submit=Konvertera
|
pdfToImage.submit=Konvertera
|
||||||
pdfToImage.info=Python är inte installerat. Krävs för WebP-konvertering.
|
pdfToImage.info=Python är inte installerat. Krävs för WebP-konvertering.
|
||||||
|
pdfToImage.placeholder=(t.ex. 1,2,8 eller 4,7,12-16 eller 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=ระดับสีเทา
|
|||||||
pdfToImage.blackwhite=ขาวดำ (อาจสูญเสียข้อมูล!)
|
pdfToImage.blackwhite=ขาวดำ (อาจสูญเสียข้อมูล!)
|
||||||
pdfToImage.submit=แปลง
|
pdfToImage.submit=แปลง
|
||||||
pdfToImage.info=Python ไม่มีการติดตั้ง จำเป็นสำหรับการแปลง WebP
|
pdfToImage.info=Python ไม่มีการติดตั้ง จำเป็นสำหรับการแปลง WebP
|
||||||
|
pdfToImage.placeholder=(เช่น 1,2,8 หรือ 4,7,12-16 หรือ 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Gri tonlama
|
|||||||
pdfToImage.blackwhite=Siyah ve Beyaz (Veri kaybolabilir!)
|
pdfToImage.blackwhite=Siyah ve Beyaz (Veri kaybolabilir!)
|
||||||
pdfToImage.submit=Dönüştür
|
pdfToImage.submit=Dönüştür
|
||||||
pdfToImage.info=Python kurulu değil. WebP dönüşümü için gereklidir.
|
pdfToImage.info=Python kurulu değil. WebP dönüşümü için gereklidir.
|
||||||
|
pdfToImage.placeholder=(örneğin 1,2,8 veya 4,7,12-16 ya da 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Відтінки сірого
|
|||||||
pdfToImage.blackwhite=Чорно-білий (може втратити дані!)
|
pdfToImage.blackwhite=Чорно-білий (може втратити дані!)
|
||||||
pdfToImage.submit=Конвертувати
|
pdfToImage.submit=Конвертувати
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(наприклад 1,2,8 або 4,7,12-16 або 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=Thang độ xám
|
|||||||
pdfToImage.blackwhite=Đen trắng (Có thể mất dữ liệu!)
|
pdfToImage.blackwhite=Đen trắng (Có thể mất dữ liệu!)
|
||||||
pdfToImage.submit=Chuyển đổi
|
pdfToImage.submit=Chuyển đổi
|
||||||
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
pdfToImage.info=Python is not installed. Required for WebP conversion.
|
||||||
|
pdfToImage.placeholder=(ví dụ: 1,2,8 hoặc 4,7,12-16 hoặc 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=灰度
|
|||||||
pdfToImage.blackwhite=黑白(可能会丢失数据!)。
|
pdfToImage.blackwhite=黑白(可能会丢失数据!)。
|
||||||
pdfToImage.submit=转换
|
pdfToImage.submit=转换
|
||||||
pdfToImage.info=WebP 转换需要安装 Python
|
pdfToImage.info=WebP 转换需要安装 Python
|
||||||
|
pdfToImage.placeholder=(例如:1,2,8 或 4,7,12-16 或 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -1042,6 +1042,7 @@ pdfToImage.grey=灰度
|
|||||||
pdfToImage.blackwhite=黑白(可能會遺失資料!)
|
pdfToImage.blackwhite=黑白(可能會遺失資料!)
|
||||||
pdfToImage.submit=轉換
|
pdfToImage.submit=轉換
|
||||||
pdfToImage.info=尚未安裝 Python。需要安裝 Python 才能進行 WebP 轉換。
|
pdfToImage.info=尚未安裝 Python。需要安裝 Python 才能進行 WebP 轉換。
|
||||||
|
pdfToImage.placeholder=(例如 1,2,8 或 4,7,12-16 或 2n-1)
|
||||||
|
|
||||||
|
|
||||||
#addPassword
|
#addPassword
|
||||||
|
|||||||
@@ -84,27 +84,6 @@
|
|||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
"moduleLicense": "The Apache Software License, Version 2.0",
|
||||||
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
"moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base",
|
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-base",
|
|
||||||
"moduleVersion": "2.18.2",
|
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider",
|
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-jaxrs-providers/jackson-jaxrs-json-provider",
|
|
||||||
"moduleVersion": "2.18.2",
|
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.fasterxml.jackson.module:jackson-module-jaxb-annotations",
|
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-base",
|
|
||||||
"moduleVersion": "2.18.2",
|
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0",
|
|
||||||
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "com.fasterxml.jackson.module:jackson-module-parameter-names",
|
"moduleName": "com.fasterxml.jackson.module:jackson-module-parameter-names",
|
||||||
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names",
|
"moduleUrl": "https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names",
|
||||||
@@ -362,20 +341,6 @@
|
|||||||
"moduleLicense": "The BSD License",
|
"moduleLicense": "The BSD License",
|
||||||
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
"moduleLicenseUrl": "https://github.com/haraldk/TwelveMonkeys#license"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "com.unboundid.product.scim2:scim2-sdk-client",
|
|
||||||
"moduleUrl": "https://github.com/pingidentity/scim2",
|
|
||||||
"moduleVersion": "2.3.5",
|
|
||||||
"moduleLicense": "UnboundID SCIM2 SDK Free Use License",
|
|
||||||
"moduleLicenseUrl": "https://github.com/pingidentity/scim2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.unboundid.product.scim2:scim2-sdk-common",
|
|
||||||
"moduleUrl": "https://github.com/pingidentity/scim2",
|
|
||||||
"moduleVersion": "2.3.5",
|
|
||||||
"moduleLicense": "UnboundID SCIM2 SDK Free Use License",
|
|
||||||
"moduleLicenseUrl": "https://github.com/pingidentity/scim2"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "com.zaxxer:HikariCP",
|
"moduleName": "com.zaxxer:HikariCP",
|
||||||
"moduleUrl": "https://github.com/brettwooldridge/HikariCP",
|
"moduleUrl": "https://github.com/brettwooldridge/HikariCP",
|
||||||
@@ -584,20 +549,6 @@
|
|||||||
"moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception",
|
"moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception",
|
||||||
"moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html"
|
"moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"moduleName": "javax.activation:javax.activation-api",
|
|
||||||
"moduleUrl": "http://www.oracle.com",
|
|
||||||
"moduleVersion": "1.2.0",
|
|
||||||
"moduleLicense": "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0",
|
|
||||||
"moduleLicenseUrl": "https://opensource.org/licenses/CDDL-1.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "javax.xml.bind:jaxb-api",
|
|
||||||
"moduleUrl": "http://www.oracle.com/",
|
|
||||||
"moduleVersion": "2.3.1",
|
|
||||||
"moduleLicense": "GPL2 w/ CPE",
|
|
||||||
"moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"moduleName": "me.friwi:gluegen-rt",
|
"moduleName": "me.friwi:gluegen-rt",
|
||||||
"moduleUrl": "http://jogamp.org/gluegen/www/",
|
"moduleUrl": "http://jogamp.org/gluegen/www/",
|
||||||
|
|||||||
@@ -39,6 +39,12 @@
|
|||||||
<option value="single" th:text="#{pdfToImage.single}"></option>
|
<option value="single" th:text="#{pdfToImage.single}"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="singleOptionSection" >
|
||||||
|
<label for="pageNumbers" th:text="#{pageSelectionPrompt}"></label>
|
||||||
|
<input type="text" name="pageNumbers" class="form-control" id="pageNumbers" value="all"
|
||||||
|
th:placeholder="#{pdfToImage.placeholder}" required>
|
||||||
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{pdfToImage.colorType}"></label>
|
<label th:text="#{pdfToImage.colorType}"></label>
|
||||||
<select class="form-control" name="colorType">
|
<select class="form-control" name="colorType">
|
||||||
@@ -59,5 +65,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
||||||
</button>
|
</button>
|
||||||
<button id="download-pdf" class="btn btn-outline-secondary"
|
<button id="download-pdf" class="btn btn-outline-secondary"
|
||||||
style="color: green; border-color: green; background: rgba(0, 128, 0, 0.2)">
|
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)">
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
download
|
download
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -88,31 +88,31 @@
|
|||||||
</button>
|
</button>
|
||||||
<button id="deselect-All-Container" class="btn btn-secondary enable-on-file hidden"
|
<button id="deselect-All-Container" class="btn btn-secondary enable-on-file hidden"
|
||||||
onclick="toggleSelectAll()" disabled>
|
onclick="toggleSelectAll()" disabled>
|
||||||
<span class="material-symbols-rounded" id="deselect-icon">deselect</span>
|
<span class="material-symbols-rounded" id="deselect-icon">deselect</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.deselectAll}"></span>
|
<span class="btn-tooltip" th:text="#{multiTool.deselectAll}"></span>
|
||||||
</button>
|
</button>
|
||||||
<button id="select-All-Container" class="btn btn-secondary enable-on-file hidden"
|
<button id="select-All-Container" class="btn btn-secondary enable-on-file hidden"
|
||||||
onclick="toggleSelectAll()" disabled>
|
onclick="toggleSelectAll()" disabled>
|
||||||
<span class="material-symbols-rounded"
|
<span class="material-symbols-rounded" id="select-icon">select_all</span>
|
||||||
id="select-icon">select_all</span>
|
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.selectAll}"></span>
|
<span class="btn-tooltip" th:text="#{multiTool.selectAll}"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<button id="delete-button" class="btn btn-danger delete hidden" onclick="deleteSelected()">
|
<button id="delete-button" class="btn btn-danger delete hidden" onclick="deleteSelected()">
|
||||||
<span class="material-symbols-rounded">delete</span>
|
<span class="material-symbols-rounded">delete</span>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.deleteSelected}"></span>
|
<span class="btn-tooltip" th:text="#{multiTool.deleteSelected}"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-left:auto">
|
<div style="margin-left:auto">
|
||||||
<button id="export-selected-button" class="btn btn-primary enable-on-file hidden"
|
<button id="export-selected-button"
|
||||||
onclick="exportPdf(true)" disabled>
|
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)"
|
||||||
|
class="btn btn-primary enable-on-file hidden" onclick="exportPdf(true)" disabled>
|
||||||
<span class="btn-tooltip" th:text="#{multiTool.downloadSelected}"></span>
|
<span class="btn-tooltip" th:text="#{multiTool.downloadSelected}"></span>
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
file_save
|
file_save
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf(false)"
|
<button style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)"
|
||||||
disabled>
|
id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf(false)" disabled>
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
download
|
download
|
||||||
</span>
|
</span>
|
||||||
@@ -124,7 +124,8 @@
|
|||||||
<div style="display:flex; height:3rem; margin-right:1rem">
|
<div style="display:flex; height:3rem; margin-right:1rem">
|
||||||
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
||||||
Pages</h5>
|
Pages</h5>
|
||||||
<input type="text" id="csv-input" class="form-control" style="height:2.5rem" placeholder="1,3,5-10" value="">
|
<input type="text" id="csv-input" class="form-control" style="height:2.5rem" placeholder="1,3,5-10"
|
||||||
|
value="">
|
||||||
</div>
|
</div>
|
||||||
<ul id="selected-pages-list" class="pages-list"></ul>
|
<ul id="selected-pages-list" class="pages-list"></ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,29 +152,29 @@
|
|||||||
window.selectAll = false;
|
window.selectAll = false;
|
||||||
|
|
||||||
window.translations = {
|
window.translations = {
|
||||||
rotateLeft: '[[#{multiTool.rotateLeft}]]',
|
rotateLeft: '[[#{multiTool.rotateLeft}]]',
|
||||||
rotateRight: '[[#{multiTool.rotateRight}]]',
|
rotateRight: '[[#{multiTool.rotateRight}]]',
|
||||||
moveLeft: '[[#{multiTool.moveLeft}]]',
|
moveLeft: '[[#{multiTool.moveLeft}]]',
|
||||||
moveRight: '[[#{multiTool.moveRight}]]',
|
moveRight: '[[#{multiTool.moveRight}]]',
|
||||||
delete: '[[#{multiTool.delete}]]',
|
delete: '[[#{multiTool.delete}]]',
|
||||||
split: '[[#{multiTool.split}]]',
|
split: '[[#{multiTool.split}]]',
|
||||||
addFile: '[[#{multiTool.addFile}]]',
|
addFile: '[[#{multiTool.addFile}]]',
|
||||||
insertPageBreak:'[[#{multiTool.insertPageBreak}]]',
|
insertPageBreak: '[[#{multiTool.insertPageBreak}]]',
|
||||||
dragDropMessage:'[[#{multiTool.dragDropMessage}]]',
|
dragDropMessage: '[[#{multiTool.dragDropMessage}]]',
|
||||||
undo: '[[#{multiTool.undo}]]',
|
undo: '[[#{multiTool.undo}]]',
|
||||||
redo: '[[#{multiTool.redo}]]',
|
redo: '[[#{multiTool.redo}]]',
|
||||||
};
|
};
|
||||||
|
|
||||||
window.decrypt = {
|
window.decrypt = {
|
||||||
passwordPrompt: '[[#{decrypt.passwordPrompt}]]',
|
passwordPrompt: '[[#{decrypt.passwordPrompt}]]',
|
||||||
cancelled: '[[#{decrypt.cancelled}]]',
|
cancelled: '[[#{decrypt.cancelled}]]',
|
||||||
noPassword: '[[#{decrypt.noPassword}]]',
|
noPassword: '[[#{decrypt.noPassword}]]',
|
||||||
invalidPassword: '[[#{decrypt.invalidPassword}]]',
|
invalidPassword: '[[#{decrypt.invalidPassword}]]',
|
||||||
invalidPasswordHeader: '[[#{decrypt.invalidPasswordHeader}]]',
|
invalidPasswordHeader: '[[#{decrypt.invalidPasswordHeader}]]',
|
||||||
unexpectedError: '[[#{decrypt.unexpectedError}]]',
|
unexpectedError: '[[#{decrypt.unexpectedError}]]',
|
||||||
serverError: '[[#{decrypt.serverError}]]',
|
serverError: '[[#{decrypt.serverError}]]',
|
||||||
success: '[[#{decrypt.success}]]',
|
success: '[[#{decrypt.success}]]',
|
||||||
}
|
}
|
||||||
|
|
||||||
const csvInput = document.getElementById("csv-input");
|
const csvInput = document.getElementById("csv-input");
|
||||||
csvInput.addEventListener("keydown", function (event) {
|
csvInput.addEventListener("keydown", function (event) {
|
||||||
@@ -217,18 +218,18 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
fileDragManager.setCallback(async (files) => pdfContainer.handleDroppedFiles(files));
|
fileDragManager.setCallback(async (files) => pdfContainer.handleDroppedFiles(files));
|
||||||
document.addEventListener('keydown', function(event) {
|
document.addEventListener('keydown', function (event) {
|
||||||
let targetElementId = event.target.id;
|
let targetElementId = event.target.id;
|
||||||
|
|
||||||
// To avoid undoing/redoing the page when the user is simply undoing/redoing text
|
// To avoid undoing/redoing the page when the user is simply undoing/redoing text
|
||||||
const isFilenameInputField = (targetElementId === 'filename-input') && (event.target === document.activeElement);
|
const isFilenameInputField = (targetElementId === 'filename-input') && (event.target === document.activeElement);
|
||||||
|
|
||||||
const isUndo = (event.ctrlKey && event.key === 'z');
|
const isUndo = (event.ctrlKey && event.key === 'z');
|
||||||
const isRedo = (event.ctrlKey && event.key == 'y');
|
const isRedo = (event.ctrlKey && event.key == 'y');
|
||||||
if (isUndo && !isFilenameInputField)
|
if (isUndo && !isFilenameInputField)
|
||||||
undoManager.undo();
|
undoManager.undo();
|
||||||
else if (isRedo && !isFilenameInputField) undoManager.redo();
|
else if (isRedo && !isFilenameInputField) undoManager.redo();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@
|
|||||||
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
||||||
</button>
|
</button>
|
||||||
<button id="download-pdf" class="btn btn-outline-secondary"
|
<button id="download-pdf" class="btn btn-outline-secondary"
|
||||||
style="color: green;border-color: green; background: rgba(0, 128, 0, 0.2);">
|
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)">
|
||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
download
|
download
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user