Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67de8a9460 | ||
|
|
b26aa3417e | ||
|
|
8dfb5940ca | ||
|
|
0ce479e1e3 | ||
|
|
cca3b6b525 | ||
|
|
03529567ba | ||
|
|
781a52c759 | ||
|
|
be2c103065 | ||
|
|
80fd2eff5f | ||
|
|
65abfd9c7a | ||
|
|
1833d7cd73 | ||
|
|
fd93dad9a5 | ||
|
|
ef18b17890 | ||
|
|
d3ae9f9a81 | ||
|
|
4a70d680a4 | ||
|
|
82ebd3dba9 | ||
|
|
15848e3de6 | ||
|
|
ea0d9301ff | ||
|
|
b27e1f254c | ||
|
|
7f30882e5e | ||
|
|
26c0a92e30 | ||
|
|
5cf53e39d0 | ||
|
|
7f566d5de8 | ||
|
|
caa32c5bae | ||
|
|
41c41cc88c | ||
|
|
c2acd74447 | ||
|
|
4d5d0e3cef | ||
|
|
df6af8766f | ||
|
|
0dd4456ae8 | ||
|
|
b0c8912742 | ||
|
|
467be09749 | ||
|
|
ceabcf2b3d | ||
|
|
361a0c9be8 | ||
|
|
128ca8e224 | ||
|
|
7d1d6d1f12 | ||
|
|
645c786d95 | ||
|
|
862a88e2e9 |
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
@@ -10,5 +10,6 @@ Closes #(issue_number)
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have attached images of the change if it is UI based
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)
|
||||
|
||||
100
.github/scripts/gradle_to_chart.py
vendored
100
.github/scripts/gradle_to_chart.py
vendored
@@ -1,100 +0,0 @@
|
||||
import re
|
||||
import yaml
|
||||
|
||||
# Paths to the files
|
||||
chart_yaml_path = "chart/stirling-pdf/Chart.yaml"
|
||||
gradle_path = "build.gradle"
|
||||
|
||||
|
||||
def get_chart_version(path):
|
||||
"""
|
||||
Reads the version and the appVersion from Chart.yaml.
|
||||
|
||||
Args:
|
||||
path (str): The file path to the Chart.yaml.
|
||||
|
||||
Returns:
|
||||
dict: The version under "chart" key and the appVersion under "app" key.
|
||||
"""
|
||||
with open(path, encoding="utf-8") as file:
|
||||
chart_yaml = yaml.safe_load(file)
|
||||
return {
|
||||
"chart": chart_yaml["version"],
|
||||
"app": chart_yaml["appVersion"]
|
||||
}
|
||||
|
||||
|
||||
def get_gradle_version(path):
|
||||
"""
|
||||
Extracts the version from build.gradle.
|
||||
|
||||
Args:
|
||||
path (str): The file path to the build.gradle.
|
||||
|
||||
Returns:
|
||||
str: The version if found, otherwise an empty string.
|
||||
"""
|
||||
with open(path, encoding="utf-8") as file:
|
||||
for line in file:
|
||||
if "version =" in line:
|
||||
# Extracts the value after 'version ='
|
||||
return re.search(r'version\s*=\s*[\'"](.+?)[\'"]', line).group(1)
|
||||
return ""
|
||||
|
||||
|
||||
def get_new_chart_version(chart_version, old_app_version, new_app_version):
|
||||
"""
|
||||
Get the new chart version from
|
||||
|
||||
Args:
|
||||
str: The current chart version.
|
||||
str: The current app version.
|
||||
str: The new app version.
|
||||
|
||||
Returns:
|
||||
str: The new chart version to update to.
|
||||
"""
|
||||
chart_major, chart_minor, chart_patch = chart_version.split(".")
|
||||
|
||||
old_major, old_minor, old_patch = old_app_version.split(".")
|
||||
new_major, new_minor, new_patch = new_app_version.split(".")
|
||||
|
||||
if old_major != new_major:
|
||||
new_chart_version = f"{int(chart_major)+1}.0.0"
|
||||
elif old_minor != new_minor:
|
||||
new_chart_version = f"{chart_major}.{int(chart_minor)+1}.0"
|
||||
elif old_patch != new_patch:
|
||||
new_chart_version = f"{chart_major}.{chart_minor}.{int(chart_patch)+1}"
|
||||
|
||||
return new_chart_version
|
||||
|
||||
|
||||
def update_chart_version(path, new_chart_version, new_app_version):
|
||||
"""
|
||||
Updates the version and the appVersion in Chart.yaml with a new version.
|
||||
|
||||
Args:
|
||||
path (str): The file path to the Chart.yaml.
|
||||
new_chart_version (str): The new chart version to update to.
|
||||
new_app_version (str): The new app version to update to.
|
||||
"""
|
||||
with open(path, encoding="utf-8") as file:
|
||||
chart_yaml = yaml.safe_load(file)
|
||||
chart_yaml["version"] = new_chart_version
|
||||
chart_yaml["appVersion"] = new_app_version
|
||||
with open(path, "w", encoding="utf-8") as file:
|
||||
yaml.safe_dump(chart_yaml, file)
|
||||
|
||||
|
||||
# Main logic
|
||||
chart_version = get_chart_version(chart_yaml_path)
|
||||
gradle_version = get_gradle_version(gradle_path)
|
||||
|
||||
if chart_version["app"] != gradle_version:
|
||||
new_chart_version = get_new_chart_version(chart_version["chart"], chart_version["app"], gradle_version, )
|
||||
print(
|
||||
f"Versions do not match. Updating Chart.yaml from {chart_version['chart']} to {new_chart_version}."
|
||||
)
|
||||
update_chart_version(chart_yaml_path, new_chart_version, gradle_version)
|
||||
else:
|
||||
print("Versions match. No update required.")
|
||||
47
.github/workflows/lint-helm-charts.yml-disabled
vendored
47
.github/workflows/lint-helm-charts.yml-disabled
vendored
@@ -1,47 +0,0 @@
|
||||
name: Lint and Test Helm Charts
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
lint-test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
|
||||
- name: Set up python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: helm-docs-built
|
||||
|
||||
- name: Set up chart-testing
|
||||
uses: helm/chart-testing-action@v2
|
||||
|
||||
- name: Run chart-testing (list-changed)
|
||||
id: list-changed
|
||||
run: |
|
||||
changed=$(ct list-changed --target-branch ${{ github.event.repository.default_branch }})
|
||||
if [[ -n "$changed" ]]; then
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Run chart-testing
|
||||
if: steps.list-changed.outputs.changed == 'true'
|
||||
run: ct lint --target-branch ${{ github.event.repository.default_branch }} --validate-maintainers=false
|
||||
7
.github/workflows/push-docker.yml
vendored
7
.github/workflows/push-docker.yml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -66,6 +67,8 @@ jobs:
|
||||
images: |
|
||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||
tags: |
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
@@ -93,6 +96,8 @@ jobs:
|
||||
images: |
|
||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||
tags: |
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
@@ -119,6 +124,8 @@ jobs:
|
||||
images: |
|
||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||
tags: |
|
||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
type=raw,value=latest-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
name: Release Helm charts
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up git config
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@v1.6.0
|
||||
with:
|
||||
config: "./cr.yaml"
|
||||
charts_dir: "chart"
|
||||
env:
|
||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
42
.github/workflows/sync_files.yml
vendored
42
.github/workflows/sync_files.yml
vendored
@@ -14,48 +14,6 @@ permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
sync-versions:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install dependencies
|
||||
run: pip install pyyaml
|
||||
- name: Sync versions
|
||||
run: python .github/scripts/gradle_to_chart.py
|
||||
- name: Run pre-commit helm-docs-built
|
||||
uses: pre-commit/action@v3.0.1
|
||||
with:
|
||||
extra_args: helm-docs-built
|
||||
- name: Set up git config
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
- name: Run git add
|
||||
run: |
|
||||
git add .
|
||||
git diff --staged --quiet || git commit -m ":floppy_disk: Sync Versions
|
||||
> Made via sync_files.yml" || echo "no changes"
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update files
|
||||
committer: GitHub Action <action@github.com>
|
||||
author: GitHub Action <action@github.com>
|
||||
signoff: true
|
||||
branch: sync_version
|
||||
title: ":floppy_disk: Update Version"
|
||||
body: |
|
||||
Auto-generated by [create-pull-request][1]
|
||||
|
||||
[1]: https://github.com/peter-evans/create-pull-request
|
||||
draft: false
|
||||
delete-branch: true
|
||||
labels: github-actions
|
||||
sync-readme:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -37,9 +37,3 @@ repos:
|
||||
language: python
|
||||
exclude: ^(src/main/resources/static/pdfjs|src/main/resources/static/pdfjs-legacy)
|
||||
files: ^.*(\.html|\.css|\.js)$
|
||||
- repo: https://github.com/norwoodj/helm-docs
|
||||
rev: v1.14.2
|
||||
hooks:
|
||||
- id: helm-docs-built
|
||||
args:
|
||||
- --chart-search-root=chart
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript |
|
||||
| ------------------- | ------- | ------- | -------- | ----- | --- | ------ | ------ | ----------- | -------- | ---- | ---------- |
|
||||
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ |
|
||||
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||
| crop | ✔️ | | | | | | | | | ✔️ | |
|
||||
| extract-page | ✔️ | | | | | | | | | ✔️ | |
|
||||
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
||||
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | |
|
||||
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ |
|
||||
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | |
|
||||
| remove-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | |
|
||||
| scale-pages | ✔️ | | | | | | | | | ✔️ | |
|
||||
| split-pdfs | ✔️ | | | | | | | | | ✔️ | |
|
||||
| file-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | |
|
||||
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-img | | ✔️ | | | | ✔️ | | | | ✔️ | |
|
||||
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | |
|
||||
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | |
|
||||
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| xlsx-to-pdf | | ✔️ | | | ✔️ | | | ✔️ | | | |
|
||||
| add-password | | | ✔️ | | | | | | | ✔️ | |
|
||||
| add-watermark | | | ✔️ | | | | | | | ✔️ | |
|
||||
| cert-sign | | | ✔️ | | | | | | | ✔️ | |
|
||||
| remove-cert-sign | | | ✔️ | | | | | | | ✔️ | |
|
||||
| change-permissions | | | ✔️ | | | | | | | ✔️ | |
|
||||
| remove-password | | | ✔️ | | | | | | | ✔️ | |
|
||||
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | |
|
||||
| add-image | | | | ✔️ | | | | | | ✔️ | |
|
||||
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | |
|
||||
| auto-rename | | | | ✔️ | | | | | | ✔️ | |
|
||||
| change-metadata | | | | ✔️ | | | | | | ✔️ | |
|
||||
| compare | | | | ✔️ | | | | | | | ✔️ |
|
||||
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||
| extract-images | | | | ✔️ | | | | | | ✔️ | |
|
||||
| flatten | | | | ✔️ | | | | | | | ✔️ |
|
||||
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | |
|
||||
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | |
|
||||
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | |
|
||||
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | |
|
||||
| show-javascript | | | | ✔️ | | | | | | | ✔️ |
|
||||
| sign | | | | ✔️ | | | | | | | ✔️ |
|
||||
| Operation | PageOps | Convert | Security | Other | CLI | Python | OpenCV | LibreOffice | OCRmyPDF | Java | Javascript | Unoconv | Ghostscript |
|
||||
| ------------------- | ------- | ------- | -------- | ----- | --- | ------ | ------ | ----------- | -------- | ---- | ---------- | ------- | ----------- |
|
||||
| adjust-contrast | ✔️ | | | | | | | | | | ✔️ | | |
|
||||
| auto-split-pdf | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| crop | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| extract-page | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| merge-pdfs | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| multi-page-layout | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| pdf-organizer | ✔️ | | | | | | | | | ✔️ | ✔️ | | |
|
||||
| pdf-to-single-page | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| remove-pages | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| rotate-pdf | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| scale-pages | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| split-pdfs | ✔️ | | | | | | | | | ✔️ | | | |
|
||||
| file-to-pdf | | ✔️ | | | ✔️ | ✔️ | | ✔️ | | | | ✔️ | |
|
||||
| img-to-pdf | | ✔️ | | | | | | | | ✔️ | | | |
|
||||
| pdf-to-html | | ✔️ | | | ✔️ | | | ✔️ | | | | | |
|
||||
| pdf-to-img | | ✔️ | | | | ✔️ | | | | ✔️ | | | |
|
||||
| pdf-to-pdfa | | ✔️ | | | ✔️ | | | | ✔️ | | | | ✔️ |
|
||||
| pdf-to-markdown | | ✔️ | | | | | | | | ✔️ | | | |
|
||||
| pdf-to-presentation | | ✔️ | | | ✔️ | | | ✔️ | | | | | |
|
||||
| pdf-to-text | | ✔️ | | | ✔️ | | | ✔️ | | | | | |
|
||||
| pdf-to-word | | ✔️ | | | ✔️ | | | ✔️ | | | | | |
|
||||
| pdf-to-xml | | ✔️ | | | ✔️ | | | ✔️ | | | | | |
|
||||
| add-password | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| add-watermark | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| cert-sign | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| remove-cert-sign | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| change-permissions | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| remove-password | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| sanitize-pdf | | | ✔️ | | | | | | | ✔️ | | | |
|
||||
| add-image | | | | ✔️ | | | | | | ✔️ | | | |
|
||||
| add-page-numbers | | | | ✔️ | | | | | | ✔️ | | | |
|
||||
| auto-rename | | | | ✔️ | | | | | | ✔️ | | | |
|
||||
| change-metadata | | | | ✔️ | | | | | | ✔️ | | | |
|
||||
| compare | | | | ✔️ | | | | | | | ✔️ | | |
|
||||
| compress-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | ✔️ |
|
||||
| extract-image-scans | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | |
|
||||
| extract-images | | | | ✔️ | | | | | | ✔️ | | | |
|
||||
| flatten | | | | ✔️ | | | | | | | ✔️ | | |
|
||||
| get-info-on-pdf | | | | ✔️ | | | | | | ✔️ | | | |
|
||||
| ocr-pdf | | | | ✔️ | ✔️ | | | | ✔️ | | | | |
|
||||
| remove-blanks | | | | ✔️ | ✔️ | ✔️ | ✔️ | | | | | | |
|
||||
| repair | | | | ✔️ | ✔️ | | | ✔️ | | | | | ✔️ |
|
||||
| show-javascript | | | | ✔️ | | | | | | | ✔️ | | |
|
||||
| sign | | | | ✔️ | | | | | | | ✔️ | | |
|
||||
|
||||
@@ -80,3 +80,23 @@ dnf search -C tesseract-langpack-
|
||||
# View installed languages:
|
||||
rpm -qa | grep tesseract-langpack | sed 's/tesseract-langpack-//g'
|
||||
```
|
||||
|
||||
For Windows:
|
||||
|
||||
Ensure ocrmypdf in installed with
|
||||
``pip install ocrmypdf``
|
||||
|
||||
Additional languages must be downloaded manually:
|
||||
Download desired .traineddata files from tessdata or tessdata_fast
|
||||
Place them in the tessdata folder within your Tesseract installation directory
|
||||
(e.g., C:\Program Files\Tesseract-OCR\tessdata)
|
||||
|
||||
Verify installation:
|
||||
``tesseract --list-langs``
|
||||
|
||||
You must then edit your ``/configs/settings.yml`` and change the system.tessdataDir to match the directory containing lang files
|
||||
```
|
||||
system:
|
||||
tessdataDir: C:/Program Files/Tesseract-OCR/tessdata # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored.
|
||||
```
|
||||
|
||||
|
||||
101
README.md
101
README.md
@@ -7,9 +7,8 @@
|
||||
[](https://github.com/Stirling-Tools/stirling-pdf)
|
||||
|
||||
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Stirling-Tools/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
|
||||
[<img src="https://www.ssdnodes.com/wp-content/uploads/2023/11/footer-logo.svg" alt="Name" height="40">](https://www.ssdnodes.com/manage/aff.php?aff=2216®ister=true)
|
||||
|
||||
Stirling-PDF is a robust, locally hosted web-based PDF manipulation tool using Docker. It enables you to carry out various operations on PDF files, including splitting, merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application has evolved to encompass a comprehensive set of features, addressing all your PDF requirements.
|
||||
[Stirling-PDF](https://www.stirlingpdf.com) is a robust, locally hosted web-based PDF manipulation tool using Docker. It enables you to carry out various operations on PDF files, including splitting, merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application has evolved to encompass a comprehensive set of features, addressing all your PDF requirements.
|
||||
|
||||
Stirling-PDF does not initiate any outbound calls for record-keeping or tracking purposes.
|
||||
|
||||
@@ -19,6 +18,7 @@ All files and PDFs exist either exclusively on the client side, reside in server
|
||||
|
||||
## Features
|
||||
|
||||
- Enterprise features like SSO Check [here](https://docs.stirlingpdf.com/Enterprise%20Edition)
|
||||
- Dark mode support
|
||||
- Custom download options
|
||||
- Parallel file processing and downloads
|
||||
@@ -27,6 +27,7 @@ All files and PDFs exist either exclusively on the client side, reside in server
|
||||
- Optional Login and Authentication support (see [here](https://github.com/Stirling-Tools/Stirling-PDF/tree/main#login-authentication) for documentation)
|
||||
- Database Backup and Import (see [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DATABASE.md) for documentation)
|
||||
|
||||
|
||||
## PDF Features
|
||||
|
||||
### Page Operations
|
||||
@@ -46,6 +47,8 @@ All files and PDFs exist either exclusively on the client side, reside in server
|
||||
- Extract page(s)
|
||||
- Convert PDF to a single page
|
||||
- Overlay PDFs on top of each other
|
||||
- PDF to single page
|
||||
- Split PDF by sections
|
||||
|
||||
### Conversion Operations
|
||||
|
||||
@@ -53,6 +56,8 @@ All files and PDFs exist either exclusively on the client side, reside in server
|
||||
- Convert any common file to PDF (using LibreOffice)
|
||||
- Convert PDF to Word/PowerPoint/others (using LibreOffice)
|
||||
- Convert HTML to PDF
|
||||
- Convert PDF to xml
|
||||
- Convert PDF to CSV
|
||||
- URL to PDF
|
||||
- Markdown to PDF
|
||||
|
||||
@@ -68,13 +73,16 @@ All files and PDFs exist either exclusively on the client side, reside in server
|
||||
### Other Operations
|
||||
|
||||
- Add/generate/write signatures
|
||||
- Split by Size or PDF
|
||||
- Repair PDFs
|
||||
- Detect and remove blank pages
|
||||
- Compare two PDFs and show differences in text
|
||||
- Add images to PDFs
|
||||
- Compress PDFs to decrease their filesize (using OCRMyPDF)
|
||||
- Extract images from PDF
|
||||
- Remove images from PDF
|
||||
- Extract images from scans
|
||||
- Remove annotations
|
||||
- Add page numbers
|
||||
- Auto rename file by detecting PDF header text
|
||||
- OCR on PDF (using OCRMyPDF)
|
||||
@@ -161,6 +169,10 @@ services:
|
||||
|
||||
Note: Podman is CLI-compatible with Docker, so simply replace "docker" with "podman".
|
||||
|
||||
### Kubernetes
|
||||
|
||||
See the kubernetes helm chart [here](https://github.com/Stirling-Tools/Stirling-PDF-chart)
|
||||
|
||||
## Enable OCR/Compression Feature
|
||||
|
||||
Please view the [HowToUseOCR.md](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR.md).
|
||||
@@ -178,47 +190,64 @@ Stirling-PDF currently supports 36 languages!
|
||||
|
||||
| Language | Progress |
|
||||
| -------------------------------------------- | -------------------------------------- |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Croatian (Hrvatski) (hr_HR) |  |
|
||||
| Czech (Česky) (cs_CZ) |  |
|
||||
| Danish (Dansk) (da_DK) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| Arabic (العربية) (ar_AR) |  |
|
||||
| Basque (Euskara) (eu_ES) |  |
|
||||
| Bulgarian (Български) (bg_BG) |  |
|
||||
| Catalan (Català) (ca_CA) |  |
|
||||
| Croatian (Hrvatski) (hr_HR) |  |
|
||||
| Czech (Česky) (cs_CZ) |  |
|
||||
| Danish (Dansk) (da_DK) |  |
|
||||
| Dutch (Nederlands) (nl_NL) |  |
|
||||
| English (English) (en_GB) |  |
|
||||
| English (US) (en_US) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| French (Français) (fr_FR) |  |
|
||||
| German (Deutsch) (de_DE) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||
| Irish (Gaeilge) (ga_IE) |  |
|
||||
| Greek (Ελληνικά) (el_GR) |  |
|
||||
| Hindi (हिंदी) (hi_IN) |  |
|
||||
| Hungarian (Magyar) (hu_HU) |  |
|
||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||
| Irish (Gaeilge) (ga_IE) |  |
|
||||
| Italian (Italiano) (it_IT) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Norwegian (Norsk) (no_NB) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Portuguese (Português) (pt_PT) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Thai (ไทย) (th_TH) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||
| Japanese (日本語) (ja_JP) |  |
|
||||
| Korean (한국어) (ko_KR) |  |
|
||||
| Norwegian (Norsk) (no_NB) |  |
|
||||
| Polish (Polski) (pl_PL) |  |
|
||||
| Portuguese (Português) (pt_PT) |  |
|
||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||
| Romanian (Română) (ro_RO) |  |
|
||||
| Russian (Русский) (ru_RU) |  |
|
||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||
| Slovakian (Slovensky) (sk_SK) |  |
|
||||
| Spanish (Español) (es_ES) |  |
|
||||
| Swedish (Svenska) (sv_SE) |  |
|
||||
| Thai (ไทย) (th_TH) |  |
|
||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||
| Turkish (Türkçe) (tr_TR) |  |
|
||||
| Ukrainian (Українська) (uk_UA) |  |
|
||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||
|
||||
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
||||
|
||||
Please see our [Contributing Guide](CONTRIBUTING.md).
|
||||
|
||||
## Stirling PDF Enterprise
|
||||
|
||||
Stirling PDF offers a Enterprise edition of its software, This is the same great software but with added features and comforts
|
||||
|
||||
### Whats included
|
||||
|
||||
- Prioritised Support tickets via support@stirlingpdf.com to reach directly to Stirling-PDF team for support and 1:1 meetings where applicable (Provided they come from same email domain registered with us)
|
||||
- Prioritised Enhancements to Stirling-PDF where applicable
|
||||
- Base SSO support
|
||||
- Advanced SSO such as automated login handling (Coming very soon)
|
||||
- SAML SSO (Coming very soon)
|
||||
- Custom automated metadata handling
|
||||
- Advanced user configurations (Coming soon)
|
||||
- Plus other exciting features to come
|
||||
|
||||
Check out of [docs](https://docs.stirlingpdf.com/Enterprise%20Edition) on it or our official [website](https://www.stirlingpdf.com)
|
||||
|
||||
## Customization
|
||||
|
||||
Stirling-PDF allows easy customization of the app, including things like:
|
||||
@@ -335,6 +364,8 @@ AutomaticallyGenerated:
|
||||
|
||||
There is an additional config file `/configs/custom_settings.yml` where users familiar with Java and Spring `application.properties` can input their own settings on top of Stirling-PDF's existing ones.
|
||||
|
||||
|
||||
|
||||
### Extra Notes
|
||||
|
||||
- **Endpoints**: Currently, the `ENDPOINTS_TO_REMOVE` and `GROUPS_TO_REMOVE` endpoints can include comma-separated lists of endpoints and groups to disable. For example, `ENDPOINTS_TO_REMOVE=img-to-pdf,remove-pages` would disable both image-to-pdf and remove pages, while `GROUPS_TO_REMOVE=LibreOffice` would disable all things that use LibreOffice. You can see a list of all endpoints and groups [here](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Endpoint-groups.md).
|
||||
@@ -385,7 +416,7 @@ For API usage, you must provide a header with `X-API-Key` and the associated API
|
||||
- Multi-page layout (stitch PDF pages together) support x rows y columns and custom page sizing
|
||||
- Fill forms manually or automatically
|
||||
|
||||
### Q2: Why is my application downloading .htm files?
|
||||
### Q2: Why is my application downloading .htm files? Why am i getting HTTP error 413?
|
||||
|
||||
This is an issue commonly caused by your NGINX configuration. The default file upload size for NGINX is 1MB. You need to add the following in your Nginx sites-available file: `client_max_body_size SIZE;` (where "SIZE" is 50M for example for 50MB files).
|
||||
|
||||
|
||||
@@ -54,3 +54,15 @@ The 'Fat' container contains all those found in 'Full' with security jar along w
|
||||
| ocr-pdf | | ✔️ |
|
||||
| pdf-to-pdfa | | ✔️ |
|
||||
| remove-blanks | | ✔️ |
|
||||
pdf-to-text | ✔️ | ✔️
|
||||
pdf-to-html | | ✔️
|
||||
pdf-to-word | | ✔️
|
||||
pdf-to-presentation | | ✔️
|
||||
pdf-to-xml | | ✔️
|
||||
remove-annotations | ✔️ | ✔️
|
||||
remove-cert-sign | ✔️ | ✔️
|
||||
remove-image-pdf | ✔️ | ✔️
|
||||
file-to-pdf | | ✔️
|
||||
html-to-pdf | | ✔️
|
||||
url-to-pdf | | ✔️
|
||||
repair | | ✔️
|
||||
|
||||
@@ -22,7 +22,7 @@ ext {
|
||||
}
|
||||
|
||||
group = "stirling.software"
|
||||
version = "0.32.0"
|
||||
version = "0.33.1"
|
||||
|
||||
java {
|
||||
// 17 is lowest but we support and recommend 21
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
apiVersion: v2
|
||||
appVersion: 0.32.0
|
||||
description: locally hosted web application that allows you to perform various operations
|
||||
on PDF files
|
||||
home: https://github.com/Stirling-Tools/Stirling-PDF
|
||||
keywords:
|
||||
- stirling-pdf
|
||||
- helm
|
||||
- charts repo
|
||||
maintainers:
|
||||
- name: Stirling-Tools
|
||||
url: https://github.com/Stirling-Tools/Stirling-PDF
|
||||
name: stirling-pdf-chart
|
||||
sources:
|
||||
- https://github.com/Stirling-Tools/Stirling-PDF
|
||||
version: 1.1.0
|
||||
@@ -1,95 +0,0 @@
|
||||
# stirling-pdf-chart
|
||||
|
||||
 
|
||||
|
||||
locally hosted web application that allows you to perform various operations on PDF files
|
||||
|
||||
**Homepage:** <https://github.com/Stirling-Tools/Stirling-PDF>
|
||||
|
||||
## Maintainers
|
||||
|
||||
| Name | Email | Url |
|
||||
| ---- | ------ | --- |
|
||||
| Stirling-Tools | | <https://github.com/Stirling-Tools/Stirling-PDF> |
|
||||
|
||||
## Source Code
|
||||
|
||||
* <https://github.com/Stirling-Tools/Stirling-PDF>
|
||||
|
||||
## Chart Repo
|
||||
|
||||
Add the following repo to use the chart:
|
||||
|
||||
```console
|
||||
helm repo add stirling-pdf https://stirling-tools.github.io/Stirling-PDF
|
||||
```
|
||||
|
||||
## Values
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| affinity | object | `{}` | |
|
||||
| commonLabels | object | `{}` | Labels to apply to all resources |
|
||||
| containerSecurityContext | object | `{}` | |
|
||||
| deployment.annotations | object | `{}` | Stirling-pdf Deployment annotations |
|
||||
| deployment.extraVolumeMounts | list | `[]` | Additional volumes to mount |
|
||||
| deployment.extraVolumes | list | `[]` | Additional volumes |
|
||||
| deployment.labels | object | `{}` | |
|
||||
| deployment.sidecarContainers | object | `{}` | of the chart's content, send notifications... |
|
||||
| envs | list | `[]` | |
|
||||
| extraArgs | list | `[]` | |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | |
|
||||
| image.repository | string | `"frooodle/s-pdf"` | |
|
||||
| image.tag | string | `nil` | |
|
||||
| ingress | object | `{"annotations":{},"enabled":false,"hosts":[],"ingressClassName":null,"labels":{},"pathType":"ImplementationSpecific"}` | Ingress for load balancer |
|
||||
| ingress.annotations | object | `{}` | Stirling-pdf Ingress annotations |
|
||||
| ingress.hosts | list | `[]` | Must be provided if Ingress is enabled |
|
||||
| ingress.ingressClassName | string | `nil` | See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress |
|
||||
| ingress.labels | object | `{}` | Stirling-pdf Ingress labels |
|
||||
| nodeSelector | object | `{}` | |
|
||||
| persistence.accessMode | string | `"ReadWriteOnce"` | |
|
||||
| persistence.enabled | bool | `false` | |
|
||||
| persistence.labels | object | `{}` | |
|
||||
| persistence.path | string | `"/tmp"` | |
|
||||
| persistence.pv | object | `{"accessMode":"ReadWriteOnce","capacity":{"storage":"8Gi"},"enabled":false,"nfs":{"path":null,"server":null},"pvname":null}` | stirling-pdf data Persistent Volume Storage Class If defined, storageClassName: <storageClass> If set to "-", storageClassName: "", which disables dynamic provisioning If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner. (gp2 on AWS, standard on GKE, AWS & OpenStack) storageClass: "-" volumeName: |
|
||||
| persistence.size | string | `"8Gi"` | |
|
||||
| podAnnotations | object | `{}` | Read more about kube2iam to provide access to s3 https://github.com/jtblin/kube2iam |
|
||||
| podLabels | object | `{}` | ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ |
|
||||
| priorityClassName | string | `""` | |
|
||||
| probes.liveness.failureThreshold | int | `3` | |
|
||||
| probes.liveness.initialDelaySeconds | int | `5` | |
|
||||
| probes.liveness.periodSeconds | int | `10` | |
|
||||
| probes.liveness.successThreshold | int | `1` | |
|
||||
| probes.liveness.timeoutSeconds | int | `1` | |
|
||||
| probes.livenessHttpGetConfig.scheme | string | `"HTTP"` | |
|
||||
| probes.readiness.failureThreshold | int | `3` | |
|
||||
| probes.readiness.initialDelaySeconds | int | `5` | |
|
||||
| probes.readiness.periodSeconds | int | `10` | |
|
||||
| probes.readiness.successThreshold | int | `1` | |
|
||||
| probes.readiness.timeoutSeconds | int | `1` | |
|
||||
| probes.readinessHttpGetConfig.scheme | string | `"HTTP"` | |
|
||||
| replicaCount | int | `1` | |
|
||||
| resources | object | `{}` | |
|
||||
| rootPath | string | `"/"` | Rootpath for the application |
|
||||
| secret.labels | object | `{}` | |
|
||||
| securityContext | object | `{"enabled":true,"fsGroup":1000}` | does not allow this, try setting securityContext: {} |
|
||||
| service.annotations | object | `{}` | |
|
||||
| service.externalPort | int | `8080` | |
|
||||
| service.externalTrafficPolicy | string | `"Local"` | |
|
||||
| service.labels | object | `{}` | |
|
||||
| service.loadBalancerIP | string | `nil` | Only valid if service.type: LoadBalancer |
|
||||
| service.loadBalancerSourceRanges | list | `[]` | Only valid if service.type: LoadBalancer |
|
||||
| service.nodePort | string | `nil` | |
|
||||
| service.servicename | string | `nil` | |
|
||||
| service.targetPort | string | `nil` | from deployment above. Leave empty to use stirling-pdf directly. |
|
||||
| service.type | string | `"ClusterIP"` | |
|
||||
| serviceAccount.annotations | object | `{}` | |
|
||||
| serviceAccount.automountServiceAccountToken | bool | `false` | |
|
||||
| serviceAccount.create | bool | `true` | |
|
||||
| serviceAccount.name | string | `""` | |
|
||||
| serviceMonitor.enabled | bool | `false` | |
|
||||
| serviceMonitor.labels | object | `{}` | |
|
||||
| serviceMonitor.metricsPath | string | `"/metrics"` | |
|
||||
| strategy.type | string | `"RollingUpdate"` | |
|
||||
| tolerations | list | `[]` | |
|
||||
| volumePermissions | object | `{"image":{"pullPolicy":"Always","registry":"docker.io","repository":"bitnami/minideb","tag":"buster"}}` | volumePermissions: Change the owner of the persistent volume mountpoint to RunAsUser:fsGroup |
|
||||
@@ -1,25 +0,0 @@
|
||||
{{ template "chart.header" . }}
|
||||
|
||||
{{ template "chart.deprecationWarning" . }}
|
||||
|
||||
{{ template "chart.badgesSection" . }}
|
||||
|
||||
{{ template "chart.description" . }}
|
||||
|
||||
{{ template "chart.homepageLine" . }}
|
||||
|
||||
{{ template "chart.maintainersSection" . }}
|
||||
|
||||
{{ template "chart.sourcesSection" . }}
|
||||
|
||||
{{ template "chart.requirementsSection" . }}
|
||||
|
||||
## Chart Repo
|
||||
|
||||
Add the following repo to use the chart:
|
||||
|
||||
```console
|
||||
helm repo add stirling-pdf https://docs.stirlingpdf.com/Stirling-PDF/
|
||||
```
|
||||
|
||||
{{ template "chart.valuesSection" . }}
|
||||
@@ -1,30 +0,0 @@
|
||||
** Please be patient while the chart is being deployed **
|
||||
|
||||
Get the stirlingpdf URL by running:
|
||||
|
||||
{{- if contains "NodePort" .Values.service.type }}
|
||||
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "stirlingpdf.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT/
|
||||
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
|
||||
** Please ensure an external IP is associated to the {{ template "stirlingpdf.fullname" . }} service before proceeding **
|
||||
** Watch the status using: kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "stirlingpdf.fullname" . }} **
|
||||
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "stirlingpdf.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.externalPort }}/
|
||||
|
||||
OR
|
||||
|
||||
export SERVICE_HOST=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "stirlingpdf.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
|
||||
echo http://$SERVICE_HOST:{{ .Values.service.externalPort }}/
|
||||
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "stirlingpdf.name" . }}" -l "release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo http://127.0.0.1:8080/
|
||||
kubectl port-forward $POD_NAME 8080:8080 --namespace {{ .Release.Namespace }}
|
||||
|
||||
{{- end }}
|
||||
@@ -1,129 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "stirlingpdf.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "stirlingpdf.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- /*
|
||||
Create chart name and version as used by the chart label.
|
||||
|
||||
It does minimal escaping for use in Kubernetes labels.
|
||||
|
||||
Example output:
|
||||
|
||||
stirlingpdf-0.4.5
|
||||
*/ -}}
|
||||
{{- define "stirlingpdf.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "stirlingpdf.labels" -}}
|
||||
helm.sh/chart: {{ include "stirlingpdf.chart" . }}
|
||||
{{ include "stirlingpdf.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.commonLabels}}
|
||||
{{ toYaml .Values.commonLabels }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "stirlingpdf.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "stirlingpdf.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "stirlingpdf.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "stirlingpdf.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the proper image name to change the volume permissions
|
||||
*/}}
|
||||
{{- define "stirlingpdf.volumePermissions.image" -}}
|
||||
{{- $registryName := .Values.volumePermissions.image.registry -}}
|
||||
{{- $repositoryName := .Values.volumePermissions.image.repository -}}
|
||||
{{- $tag := .Values.volumePermissions.image.tag | toString -}}
|
||||
{{/*
|
||||
Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
|
||||
but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic.
|
||||
Also, we can't use a single if because lazy evaluation is not an option
|
||||
*/}}
|
||||
{{- if .Values.global }}
|
||||
{{- if .Values.global.imageRegistry }}
|
||||
{{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return the proper Docker Image Registry Secret Names
|
||||
*/}}
|
||||
{{- define "stirlingpdf.imagePullSecrets" -}}
|
||||
{{/*
|
||||
Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
|
||||
but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic.
|
||||
Also, we can not use a single if because lazy evaluation is not an option
|
||||
*/}}
|
||||
{{- if .Values.global }}
|
||||
{{- if .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- range .Values.global.imagePullSecrets }}
|
||||
- name: {{ . }}
|
||||
{{- end }}
|
||||
{{- else if or .Values.image.pullSecrets .Values.volumePermissions.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- range .Values.image.pullSecrets }}
|
||||
- name: {{ . }}
|
||||
{{- end }}
|
||||
{{- range .Values.volumePermissions.image.pullSecrets }}
|
||||
- name: {{ . }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- else if or .Values.image.pullSecrets .Values.volumePermissions.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- range .Values.image.pullSecrets }}
|
||||
- name: {{ . }}
|
||||
{{- end }}
|
||||
{{- range .Values.volumePermissions.image.pullSecrets }}
|
||||
- name: {{ . }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
@@ -1,131 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "stirlingpdf.fullname" . }}
|
||||
{{- with .Values.deployment.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
{{- if .Values.deployment.labels }}
|
||||
{{- toYaml .Values.deployment.labels | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "stirlingpdf.selectorLabels" . | nindent 6 }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
strategy:
|
||||
{{ toYaml .Values.strategy | indent 4 }}
|
||||
revisionHistoryLimit: 10
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.selectorLabels" . | nindent 8 }}
|
||||
{{- if .Values.podLabels }}
|
||||
{{- toYaml .Values.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.priorityClassName }}
|
||||
priorityClassName: "{{ .Values.priorityClassName }}"
|
||||
{{- end }}
|
||||
{{- if .Values.securityContext.enabled }}
|
||||
securityContext:
|
||||
fsGroup: {{ .Values.securityContext.fsGroup }}
|
||||
{{- if .Values.securityContext.runAsNonRoot }}
|
||||
runAsNonRoot: {{ .Values.securityContext.runAsNonRoot }}
|
||||
{{- end }}
|
||||
{{- if .Values.securityContext.supplementalGroups }}
|
||||
supplementalGroups: {{ .Values.securityContext.supplementalGroups }}
|
||||
{{- end }}
|
||||
{{- else if .Values.persistence.enabled }}
|
||||
initContainers:
|
||||
- name: volume-permissions
|
||||
image: {{ template "stirlingpdf.volumePermissions.image" . }}
|
||||
imagePullPolicy: "{{ .Values.volumePermissions.image.pullPolicy }}"
|
||||
securityContext:
|
||||
{{- toYaml .Values.containerSecurityContext | nindent 10 }}
|
||||
command: ['sh', '-c', 'chown -R {{ .Values.securityContext.fsGroup }}:{{ .Values.securityContext.fsGroup }} {{ .Values.persistence.path }}']
|
||||
volumeMounts:
|
||||
- mountPath: {{ .Values.persistence.path }}
|
||||
name: storage-volume
|
||||
{{- end }}
|
||||
{{- include "stirlingpdf.imagePullSecrets" . | indent 6 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: {{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.containerSecurityContext | nindent 10 }}
|
||||
env:
|
||||
- name: SYSTEM_ROOTURIPATH
|
||||
value: {{ .Values.rootPath}}
|
||||
{{- if .Values.envs }}
|
||||
{{ toYaml .Values.envs | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.extraArgs }}
|
||||
args:
|
||||
{{ toYaml .Values.extraArgs | indent 8 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: {{ .Values.rootPath}}
|
||||
port: http
|
||||
{{ toYaml .Values.probes.livenessHttpGetConfig | indent 12 }}
|
||||
{{ toYaml .Values.probes.liveness | indent 10 }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: {{ .Values.rootPath}}
|
||||
port: http
|
||||
{{ toYaml .Values.probes.readinessHttpGetConfig | indent 12 }}
|
||||
{{ toYaml .Values.probes.readiness | indent 10 }}
|
||||
volumeMounts:
|
||||
{{- if .Values.deployment.extraVolumeMounts }}
|
||||
{{- toYaml .Values.deployment.extraVolumeMounts | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.deployment.sidecarContainers }}
|
||||
{{- range $name, $spec := .Values.deployment.sidecarContainers }}
|
||||
- name: {{ $name }}
|
||||
{{- toYaml $spec | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.resources }}
|
||||
resources:
|
||||
{{ toYaml . | indent 10 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.schedulerName }}
|
||||
schedulerName: {{ .Values.schedulerName }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "stirlingpdf.serviceAccountName" . }}
|
||||
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
|
||||
volumes:
|
||||
{{- if .Values.deployment.extraVolumes }}
|
||||
{{- toYaml .Values.deployment.extraVolumes | nindent 6 }}
|
||||
{{- end }}
|
||||
- name: storage-volume
|
||||
{{- if .Values.persistence.enabled }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.persistence.existingClaim | default (include "stirlingpdf.fullname" .) }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
@@ -1,85 +0,0 @@
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- $servicePort := .Values.service.externalPort -}}
|
||||
{{- $serviceName := include "stirlingpdf.fullname" . -}}
|
||||
{{- $ingressExtraPaths := .Values.ingress.extraPaths -}}
|
||||
---
|
||||
{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- else if semverCompare "<1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "stirlingpdf.fullname" . }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ingress.ingressClassName }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .name }}
|
||||
http:
|
||||
paths:
|
||||
{{- range $ingressExtraPaths }}
|
||||
- path: {{ default "/" .path | quote }}
|
||||
backend:
|
||||
{{- if semverCompare "<1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
{{- if $.Values.service.servicename }}
|
||||
serviceName: {{ $.Values.service.servicename }}
|
||||
{{- else }}
|
||||
serviceName: {{ default $serviceName .service }}
|
||||
{{- end }}
|
||||
servicePort: {{ default $servicePort .port }}
|
||||
{{- else }}
|
||||
service:
|
||||
{{- if $.Values.service.servicename }}
|
||||
name: {{ $.Values.service.servicename }}
|
||||
{{- else }}
|
||||
name: {{ default $serviceName .service }}
|
||||
{{- end }}
|
||||
port:
|
||||
number: {{ default $servicePort .port }}
|
||||
pathType: {{ default $.Values.ingress.pathType .pathType }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
- path: {{ default "/" .path | quote }}
|
||||
backend:
|
||||
{{- if semverCompare "<1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
{{- if $.Values.service.servicename }}
|
||||
serviceName: {{ $.Values.service.servicename }}
|
||||
{{- else }}
|
||||
serviceName: {{ default $serviceName .service }}
|
||||
{{- end }}
|
||||
servicePort: {{ default $servicePort .servicePort }}
|
||||
{{- else }}
|
||||
service:
|
||||
{{- if $.Values.service.servicename }}
|
||||
name: {{ $.Values.service.servicename }}
|
||||
{{- else }}
|
||||
name: {{ default $serviceName .service }}
|
||||
{{- end }}
|
||||
port:
|
||||
number: {{ default $servicePort .port }}
|
||||
pathType: {{ $.Values.ingress.pathType }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
tls:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
{{- if .tls }}
|
||||
- hosts:
|
||||
- {{ .name }}
|
||||
secretName: {{ .tlsSecret }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -1,16 +0,0 @@
|
||||
{{- if .Values.persistence.pv.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: {{ .Values.persistence.pv.pvname | default (include "stirlingpdf.fullname" .) }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
spec:
|
||||
capacity:
|
||||
storage: {{ .Values.persistence.pv.capacity.storage }}
|
||||
accessModes:
|
||||
- {{ .Values.persistence.pv.accessMode | quote }}
|
||||
nfs:
|
||||
server: {{ .Values.persistence.pv.nfs.server }}
|
||||
path: {{ .Values.persistence.pv.nfs.path | quote }}
|
||||
{{- end }}
|
||||
@@ -1,27 +0,0 @@
|
||||
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}}
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: {{ include "stirlingpdf.fullname" . }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
{{- with .Values.persistence.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.persistence.accessMode | quote }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size | quote }}
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: "{{ .Values.persistence.storageClass }}"
|
||||
{{- end }}
|
||||
{{- if .Values.persistence.volumeName }}
|
||||
volumeName: "{{ .Values.persistence.volumeName }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,48 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Values.service.servicename | default (include "stirlingpdf.fullname" .) }}
|
||||
{{- with .Values.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
{{- with .Values.service.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
{{- if (or (eq .Values.service.type "LoadBalancer") (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort)))) }}
|
||||
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
|
||||
{{- end }}
|
||||
{{- if (and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP) }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if (and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerSourceRanges) }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- with .Values.service.loadBalancerSourceRanges }}
|
||||
{{ toYaml . | indent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq .Values.service.type "ClusterIP" }}
|
||||
{{- if .Values.service.clusterIP }}
|
||||
clusterIP: {{ .Values.service.clusterIP }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- port: {{ .Values.service.externalPort }}
|
||||
{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
|
||||
nodePort: {{.Values.service.nodePort}}
|
||||
{{- end }}
|
||||
{{- if .Values.service.targetPort }}
|
||||
targetPort: {{ .Values.service.targetPort }}
|
||||
name: {{ .Values.service.targetPort }}
|
||||
{{- else }}
|
||||
targetPort: http
|
||||
name: http
|
||||
{{- end }}
|
||||
protocol: TCP
|
||||
|
||||
selector:
|
||||
{{- include "stirlingpdf.selectorLabels" . | nindent 4 }}
|
||||
@@ -1,13 +0,0 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "stirlingpdf.serviceAccountName" . }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -1,31 +0,0 @@
|
||||
{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) ( .Values.serviceMonitor.enabled ) }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "stirlingpdf.fullname" . }}
|
||||
namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "stirlingpdf.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
- targetPort: 8080
|
||||
{{- if .Values.serviceMonitor.interval }}
|
||||
interval: {{ .Values.serviceMonitor.interval }}
|
||||
{{- end }}
|
||||
{{- if .Values.serviceMonitor.metricsPath }}
|
||||
path: {{ .Values.serviceMonitor.metricsPath }}
|
||||
{{- end }}
|
||||
{{- if .Values.serviceMonitor.timeout }}
|
||||
scrapeTimeout: {{ .Values.serviceMonitor.timeout }}
|
||||
{{- end }}
|
||||
jobLabel: {{ include "stirlingpdf.fullname" . }}
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- {{ .Release.Namespace }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "stirlingpdf.selectorLabels" . | nindent 6 }}
|
||||
{{- end }}
|
||||
@@ -1,239 +0,0 @@
|
||||
extraArgs:
|
||||
[]
|
||||
# - --storage-timestamp-tolerance 1s
|
||||
replicaCount: 1
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
image:
|
||||
repository: frooodle/s-pdf
|
||||
# took Chart appVersion by default
|
||||
tag: ~
|
||||
pullPolicy: IfNotPresent
|
||||
secret:
|
||||
labels: {}
|
||||
# -- Labels to apply to all resources
|
||||
commonLabels: {}
|
||||
# team_name: dev
|
||||
|
||||
# -- Rootpath for the application
|
||||
rootPath: /
|
||||
|
||||
envs: []
|
||||
# - name: UI_APP_NAME
|
||||
# value: "Stirling PDF"
|
||||
# - name: UI_HOME_DESCRIPTION
|
||||
# value: "Your locally hosted one-stop-shop for all your PDF needs."
|
||||
# - name: UI_APP_NAVBAR_NAME
|
||||
# value: "Stirling PDF"
|
||||
# - name: ALLOW_GOOGLE_VISIBILITY
|
||||
# value: "true"
|
||||
# - name: APP_LOCALE
|
||||
# value: "en_GB"
|
||||
|
||||
deployment:
|
||||
# -- Stirling-pdf Deployment annotations
|
||||
annotations: {}
|
||||
# name: value
|
||||
labels: {}
|
||||
# name: value
|
||||
# -- Additional volumes
|
||||
extraVolumes: []
|
||||
# - name: nginx-config
|
||||
# secret:
|
||||
# secretName: nginx-config
|
||||
# -- Additional volumes to mount
|
||||
extraVolumeMounts: []
|
||||
# -- sidecarContainers for the stirling-pdf
|
||||
# -- Can be used to add a proxy to the pod that does
|
||||
# -- scanning for secrets, signing, authentication, validation
|
||||
# -- of the chart's content, send notifications...
|
||||
sidecarContainers: {}
|
||||
## Example sidecarContainer which uses an extraVolume from above and
|
||||
## a named port that can be referenced in the service as targetPort.
|
||||
# proxy:
|
||||
# image: nginx:latest
|
||||
# ports:
|
||||
# - name: proxy
|
||||
# containerPort: 8081
|
||||
# volumeMounts:
|
||||
# - name: nginx-config
|
||||
# readOnly: true
|
||||
# mountPath: /etc/nginx
|
||||
|
||||
# -- Pod annotations
|
||||
# -- ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
# -- Read more about kube2iam to provide access to s3 https://github.com/jtblin/kube2iam
|
||||
podAnnotations:
|
||||
{}
|
||||
# iam.amazonaws.com/role: role-arn
|
||||
|
||||
# -- Pod labels
|
||||
# -- ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels:
|
||||
{}
|
||||
# name: value
|
||||
|
||||
service:
|
||||
servicename:
|
||||
type: ClusterIP
|
||||
externalTrafficPolicy: Local
|
||||
# -- Uses pre-assigned IP address from cloud provider
|
||||
# -- Only valid if service.type: LoadBalancer
|
||||
loadBalancerIP:
|
||||
# -- Limits which cidr blocks can connect to service's load balancer
|
||||
# -- Only valid if service.type: LoadBalancer
|
||||
loadBalancerSourceRanges: []
|
||||
# clusterIP: None
|
||||
externalPort: 8080
|
||||
# -- targetPort of the container to use. If a sidecar should handle the
|
||||
# -- requests first, use the named port from the sidecar. See sidecar example
|
||||
# -- from deployment above. Leave empty to use stirling-pdf directly.
|
||||
targetPort:
|
||||
nodePort:
|
||||
annotations: {}
|
||||
labels: {}
|
||||
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
# namespace: prometheus
|
||||
labels: {}
|
||||
metricsPath: "/metrics"
|
||||
# timeout: 60
|
||||
# interval: 60
|
||||
|
||||
resources: {}
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 80m
|
||||
# memory: 64Mi
|
||||
|
||||
probes:
|
||||
liveness:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 1
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
livenessHttpGetConfig:
|
||||
scheme: HTTP
|
||||
readiness:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 1
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
readinessHttpGetConfig:
|
||||
scheme: HTTP
|
||||
|
||||
serviceAccount:
|
||||
create: true
|
||||
name: ""
|
||||
automountServiceAccountToken: false
|
||||
## Annotations for the Service Account
|
||||
annotations: {}
|
||||
|
||||
# -- UID/GID 1000 is the default user "stirling-pdf" used in
|
||||
# -- the container image starting in v0.8.0 and above. This
|
||||
# -- is required for local persistent storage. If your cluster
|
||||
# -- does not allow this, try setting securityContext: {}
|
||||
securityContext:
|
||||
enabled: true
|
||||
fsGroup: 1000
|
||||
## Optionally, specify supplementalGroups and/or
|
||||
## runAsNonRoot for security purposes
|
||||
# runAsNonRoot: true
|
||||
# supplementalGroups: [1000]
|
||||
|
||||
containerSecurityContext: {}
|
||||
|
||||
priorityClassName: ""
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
persistence:
|
||||
enabled: false
|
||||
accessMode: ReadWriteOnce
|
||||
size: 8Gi
|
||||
labels:
|
||||
{}
|
||||
# name: value
|
||||
path: /tmp
|
||||
## A manually managed Persistent Volume and Claim
|
||||
## Requires persistence.enabled: true
|
||||
## If defined, PVC must be created manually before volume will be bound
|
||||
# existingClaim:
|
||||
|
||||
# -- stirling-pdf data Persistent Volume Storage Class
|
||||
# If defined, storageClassName: <storageClass>
|
||||
# If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||
# If undefined (the default) or set to null, no storageClassName spec is
|
||||
# set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||
# GKE, AWS & OpenStack)
|
||||
# storageClass: "-"
|
||||
# volumeName:
|
||||
pv:
|
||||
enabled: false
|
||||
pvname:
|
||||
capacity:
|
||||
storage: 8Gi
|
||||
accessMode: ReadWriteOnce
|
||||
nfs:
|
||||
server:
|
||||
path:
|
||||
|
||||
# -- Init containers parameters:
|
||||
# -- volumePermissions: Change the owner of the persistent volume mountpoint to RunAsUser:fsGroup
|
||||
volumePermissions:
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: bitnami/minideb
|
||||
tag: buster
|
||||
pullPolicy: Always
|
||||
## Optionally specify an array of imagePullSecrets.
|
||||
## Secrets must be manually created in the namespace.
|
||||
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
##
|
||||
# pullSecrets:
|
||||
# - myRegistryKeySecretName
|
||||
|
||||
# -- Ingress for load balancer
|
||||
ingress:
|
||||
enabled: false
|
||||
pathType: "ImplementationSpecific"
|
||||
# -- Stirling-pdf Ingress labels
|
||||
labels:
|
||||
{}
|
||||
# dns: "route53"
|
||||
|
||||
# -- Stirling-pdf Ingress annotations
|
||||
annotations:
|
||||
{}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
|
||||
# -- Stirling-pdf Ingress hostnames
|
||||
# -- Must be provided if Ingress is enabled
|
||||
hosts:
|
||||
[]
|
||||
# - name: stirling-pdf.domain1.com
|
||||
# path: /
|
||||
# tls: false
|
||||
# - name: stirling-pdf.domain2.com
|
||||
# path: /
|
||||
#
|
||||
# ## Set this to true in order to enable TLS on the ingress record
|
||||
# tls: true
|
||||
#
|
||||
# ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS
|
||||
# ## Secrets must be added manually to the namespace
|
||||
# tlsSecret: stirling-pdf.domain2-tls
|
||||
|
||||
# -- For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
|
||||
# -- See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
|
||||
ingressClassName:
|
||||
@@ -13,7 +13,6 @@ ignore = [
|
||||
'PDFToText.tags',
|
||||
'adminUserSettings.admin',
|
||||
'language.direction',
|
||||
'survey.button',
|
||||
'watermark.type.1',
|
||||
]
|
||||
|
||||
@@ -38,10 +37,12 @@ ignore = [
|
||||
'addPageNumbers.selectText.3',
|
||||
'alphabet',
|
||||
'certSign.name',
|
||||
'home.pipeline.title',
|
||||
'language.direction',
|
||||
'licenses.version',
|
||||
'pipeline.title',
|
||||
'pipelineOptions.pipelineHeader',
|
||||
'pro',
|
||||
'sponsor',
|
||||
'text',
|
||||
'watermark.type.1',
|
||||
|
||||
@@ -117,7 +117,6 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Convert", "img-to-pdf");
|
||||
addEndpointToGroup("Convert", "pdf-to-pdfa");
|
||||
addEndpointToGroup("Convert", "file-to-pdf");
|
||||
addEndpointToGroup("Convert", "xlsx-to-pdf");
|
||||
addEndpointToGroup("Convert", "pdf-to-word");
|
||||
addEndpointToGroup("Convert", "pdf-to-presentation");
|
||||
addEndpointToGroup("Convert", "pdf-to-text");
|
||||
@@ -163,7 +162,6 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("CLI", "repair");
|
||||
addEndpointToGroup("CLI", "pdf-to-pdfa");
|
||||
addEndpointToGroup("CLI", "file-to-pdf");
|
||||
addEndpointToGroup("CLI", "xlsx-to-pdf");
|
||||
addEndpointToGroup("CLI", "pdf-to-word");
|
||||
addEndpointToGroup("CLI", "pdf-to-presentation");
|
||||
addEndpointToGroup("CLI", "pdf-to-html");
|
||||
@@ -184,6 +182,7 @@ public class EndpointConfiguration {
|
||||
addEndpointToGroup("Python", "html-to-pdf");
|
||||
addEndpointToGroup("Python", "url-to-pdf");
|
||||
addEndpointToGroup("Python", "pdf-to-img");
|
||||
addEndpointToGroup("Python", "file-to-pdf");
|
||||
|
||||
// openCV
|
||||
addEndpointToGroup("OpenCV", "extract-image-scans");
|
||||
@@ -191,14 +190,15 @@ public class EndpointConfiguration {
|
||||
// LibreOffice
|
||||
addEndpointToGroup("LibreOffice", "repair");
|
||||
addEndpointToGroup("LibreOffice", "file-to-pdf");
|
||||
addEndpointToGroup("Unoconv", "file-to-pdf");
|
||||
addEndpointToGroup("LibreOffice", "xlsx-to-pdf");
|
||||
addEndpointToGroup("LibreOffice", "pdf-to-word");
|
||||
addEndpointToGroup("LibreOffice", "pdf-to-presentation");
|
||||
addEndpointToGroup("LibreOffice", "pdf-to-rtf");
|
||||
addEndpointToGroup("LibreOffice", "pdf-to-html");
|
||||
addEndpointToGroup("LibreOffice", "pdf-to-xml");
|
||||
|
||||
// Unoconv
|
||||
addEndpointToGroup("Unoconv", "file-to-pdf");
|
||||
|
||||
// OCRmyPDF
|
||||
addEndpointToGroup("OCRmyPDF", "compress-pdf");
|
||||
addEndpointToGroup("OCRmyPDF", "pdf-to-pdfa");
|
||||
@@ -251,6 +251,7 @@ public class EndpointConfiguration {
|
||||
// Ghostscript dependent endpoints
|
||||
addEndpointToGroup("Ghostscript", "compress-pdf");
|
||||
addEndpointToGroup("Ghostscript", "pdf-to-pdfa");
|
||||
addEndpointToGroup("Ghostscript", "repair");
|
||||
|
||||
// Weasyprint dependent endpoints
|
||||
addEndpointToGroup("Weasyprint", "html-to-pdf");
|
||||
|
||||
@@ -19,10 +19,12 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
|
||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
|
||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
||||
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.AuthenticationType;
|
||||
import stirling.software.SPDF.model.Authority;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
@@ -31,6 +33,7 @@ import stirling.software.SPDF.repository.AuthorityRepository;
|
||||
import stirling.software.SPDF.repository.UserRepository;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserService implements UserServiceInterface {
|
||||
|
||||
@Autowired private UserRepository userRepository;
|
||||
@@ -45,6 +48,8 @@ public class UserService implements UserServiceInterface {
|
||||
|
||||
@Autowired DatabaseBackupInterface databaseBackupHelper;
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
// Handle OAUTH2 login and user auto creation.
|
||||
public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
|
||||
throws IllegalArgumentException, IOException {
|
||||
@@ -299,7 +304,13 @@ public class UserService implements UserServiceInterface {
|
||||
boolean isValidEmail =
|
||||
username.matches(
|
||||
"^(?=.{1,64}@)[A-Za-z0-9]+(\\.[A-Za-z0-9_+.-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$");
|
||||
return isValidSimpleUsername || isValidEmail;
|
||||
|
||||
List<String> notAllowedUserList = new ArrayList<>();
|
||||
notAllowedUserList.add("ALL_USERS".toLowerCase());
|
||||
|
||||
boolean notAllowedUser = notAllowedUserList.contains(username.toLowerCase());
|
||||
|
||||
return (isValidSimpleUsername || isValidEmail) && !notAllowedUser;
|
||||
}
|
||||
|
||||
private String getInvalidUsernameMessage() {
|
||||
@@ -354,6 +365,14 @@ public class UserService implements UserServiceInterface {
|
||||
|
||||
if (principal instanceof UserDetails) {
|
||||
return ((UserDetails) principal).getUsername();
|
||||
} else if (principal instanceof OAuth2User) {
|
||||
return ((OAuth2User) principal)
|
||||
.getAttribute(
|
||||
applicationProperties.getSecurity().getOauth2().getUseAsUsername());
|
||||
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
|
||||
return ((CustomSaml2AuthenticatedPrincipal) principal).getName();
|
||||
} else if (principal instanceof String) {
|
||||
return (String) principal;
|
||||
} else {
|
||||
return principal.toString();
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.api.misc.ReplaceAndInvertColorRequest;
|
||||
import stirling.software.SPDF.service.misc.ReplaceAndInvertColorService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/misc")
|
||||
@Tag(name = "Misc", description = "Miscellaneous APIs")
|
||||
public class ReplaceAndInvertColorController {
|
||||
|
||||
private ReplaceAndInvertColorService replaceAndInvertColorService;
|
||||
|
||||
@@ -187,18 +187,31 @@ public class WatermarkController {
|
||||
float watermarkHeight = heightSpacer + fontSize * textLines.length;
|
||||
float pageWidth = page.getMediaBox().getWidth();
|
||||
float pageHeight = page.getMediaBox().getHeight();
|
||||
int watermarkRows = (int) (pageHeight / watermarkHeight + 1);
|
||||
int watermarkCols = (int) (pageWidth / watermarkWidth + 1);
|
||||
|
||||
// Calculating the new width and height depending on the angle.
|
||||
float radians = (float) Math.toRadians(rotation);
|
||||
float newWatermarkWidth =
|
||||
(float)
|
||||
(Math.abs(watermarkWidth * Math.cos(radians))
|
||||
+ Math.abs(watermarkHeight * Math.sin(radians)));
|
||||
float newWatermarkHeight =
|
||||
(float)
|
||||
(Math.abs(watermarkWidth * Math.sin(radians))
|
||||
+ Math.abs(watermarkHeight * Math.cos(radians)));
|
||||
|
||||
// Calculating the number of rows and columns.
|
||||
int watermarkRows = (int) (pageHeight / newWatermarkHeight + 1);
|
||||
int watermarkCols = (int) (pageWidth / newWatermarkWidth + 1);
|
||||
|
||||
// Add the text watermark
|
||||
for (int i = 0; i < watermarkRows; i++) {
|
||||
for (int j = 0; j < watermarkCols; j++) {
|
||||
for (int i = 0; i <= watermarkRows; i++) {
|
||||
for (int j = 0; j <= watermarkCols; j++) {
|
||||
contentStream.beginText();
|
||||
contentStream.setTextMatrix(
|
||||
Matrix.getRotateInstance(
|
||||
(float) Math.toRadians(rotation),
|
||||
j * watermarkWidth,
|
||||
i * watermarkHeight));
|
||||
j * newWatermarkWidth,
|
||||
i * newWatermarkHeight));
|
||||
|
||||
for (int k = 0; k < textLines.length; ++k) {
|
||||
contentStream.showText(textLines[k]);
|
||||
|
||||
@@ -15,7 +15,7 @@ import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
|
||||
import stirling.software.SPDF.service.SignatureService;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/api/v1/general/")
|
||||
@RequestMapping("/api/v1/general")
|
||||
public class SignatureController {
|
||||
|
||||
@Autowired private SignatureService signatureService;
|
||||
|
||||
@@ -81,6 +81,7 @@ page=صفحة
|
||||
pages=صفحات
|
||||
loading=جارٍ التحميل...
|
||||
addToDoc=إضافة إلى المستند
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=سياسة الخصوصية
|
||||
legal.terms=شروط الاستخدام
|
||||
@@ -141,6 +142,7 @@ navbar.language=اللغات
|
||||
navbar.settings=إعدادات
|
||||
navbar.allTools=أدوات
|
||||
navbar.multiTool=أدوات متعددة
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=تنظيم
|
||||
navbar.sections.convertTo=تحويل الى PDF
|
||||
navbar.sections.convertFrom=تحويل من PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(مثال: 1,3,2 أو 4-8,2,10-12 أو 2n-1)
|
||||
multiTool.title=أداة متعددة PDF
|
||||
multiTool.header=أداة متعددة PDF
|
||||
multiTool.uploadPrompts=اسم الملف
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=عرض PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Страница
|
||||
pages=Страници
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Политика за поверителност
|
||||
legal.terms=Правила и условия
|
||||
@@ -141,6 +142,7 @@ navbar.language=Езици
|
||||
navbar.settings=Настройки
|
||||
navbar.allTools=Инструменти
|
||||
navbar.multiTool=Мулти инструменти
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Организирайте
|
||||
navbar.sections.convertTo=Преобразуване в PDF
|
||||
navbar.sections.convertFrom=Преобразуване от PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(напр. 1,3,2 или 4-8,2,10-12 или 2n-1)
|
||||
multiTool.title=PDF Мулти инструмент
|
||||
multiTool.header=PDF Мулти инструмент
|
||||
multiTool.uploadPrompts=Име на файл
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Преглед на PDF
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -81,6 +81,7 @@ page=Strana
|
||||
pages=Strany
|
||||
loading=Načítání...
|
||||
addToDoc=Přidat do dokumentu
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Politika soukromí
|
||||
legal.terms=Podmínky použití
|
||||
@@ -141,6 +142,7 @@ navbar.language=Jazyky
|
||||
navbar.settings=Nastavení
|
||||
navbar.allTools=Nástroje
|
||||
navbar.multiTool=Multifunkční nástroje
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizovat
|
||||
navbar.sections.convertTo=Převést do PDF
|
||||
navbar.sections.convertFrom=Převést z PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(např. 1,3,2 nebo 4-8,2,10-12 nebo 2n-1)
|
||||
multiTool.title=Vícefunkční nástroj pro PDF
|
||||
multiTool.header=Vícefunkční nástroj pro PDF
|
||||
multiTool.uploadPrompts=Název souboru
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Zobrazit PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Sidenummer
|
||||
pages=Sideantal
|
||||
loading=Laster...
|
||||
addToDoc=Tilføj til Dokument
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Vilkår og betingelser
|
||||
@@ -141,6 +142,7 @@ navbar.language=Sprog
|
||||
navbar.settings=Indstillinger
|
||||
navbar.allTools=Værktøjer
|
||||
navbar.multiTool=Multi Værktøjer
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organisér
|
||||
navbar.sections.convertTo=Konvertér til PDF
|
||||
navbar.sections.convertFrom=Konvertér fra PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(f.eks. 1,3,2 eller 4-8,2,10-12 eller 2n-1)
|
||||
multiTool.title=PDF Multi Værktøj
|
||||
multiTool.header=PDF Multi Værktøj
|
||||
multiTool.uploadPrompts=Filnavn
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Se PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Seite
|
||||
pages=Seiten
|
||||
loading=Laden...
|
||||
addToDoc=In Dokument hinzufügen
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Datenschutz
|
||||
legal.terms=AGB
|
||||
@@ -141,6 +142,7 @@ navbar.language=Sprachen
|
||||
navbar.settings=Einstellungen
|
||||
navbar.allTools=Werkzeuge
|
||||
navbar.multiTool=Multitools
|
||||
navbar.search=Suche
|
||||
navbar.sections.organize=Organisieren
|
||||
navbar.sections.convertTo=In PDF konvertieren
|
||||
navbar.sections.convertFrom=Konvertieren von PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(z.B. 1,3,2 oder 4-8,2,10-12 oder 2n-1)
|
||||
multiTool.title=PDF-Multitool
|
||||
multiTool.header=PDF-Multitool
|
||||
multiTool.uploadPrompts=Dateiname
|
||||
multiTool.selectAll=Alle auswählen
|
||||
multiTool.deselectAll=Auswahl aufheben
|
||||
multiTool.selectPages=Seiten auswählen
|
||||
multiTool.selectedPages=Ausgewählte Seiten
|
||||
multiTool.page=Seite
|
||||
multiTool.deleteSelected=Auswahl löschen
|
||||
multiTool.downloadAll=Downloaden
|
||||
multiTool.downloadSelected=Auswahl downloaden
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF anzeigen
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Σελίδα
|
||||
pages=Σελίδες
|
||||
loading=Φόρτωση...
|
||||
addToDoc=Πρόσθεση στο Εκπομπώματο
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Πολιτική Προνομίους
|
||||
legal.terms=Φράσεις Υποχρεωτικότητας
|
||||
@@ -141,6 +142,7 @@ navbar.language=Γλώσσες
|
||||
navbar.settings=Ρυθμίσεις
|
||||
navbar.allTools=Εργαλεία
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Οργάνωση
|
||||
navbar.sections.convertTo=Μετατροπή σε PDF
|
||||
navbar.sections.convertFrom=Μετατροπή από PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(π.χ. 1,3,2 ή 4-8,2,10-12 ή 2n-1)
|
||||
multiTool.title=PDF Πολυεργαλείο
|
||||
multiTool.header=PDF Πολυεργαλείο
|
||||
multiTool.uploadPrompts=Όνομα αρχείου
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Προβολή PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Languages
|
||||
navbar.settings=Settings
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tool
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
multiTool.title=PDF Multi Tool
|
||||
multiTool.header=PDF Multi Tool
|
||||
multiTool.uploadPrompts=File Name
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Languages
|
||||
navbar.settings=Settings
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tool
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
multiTool.title=PDF Multi Tool
|
||||
multiTool.header=PDF Multi Tool
|
||||
multiTool.uploadPrompts=File Name
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Página
|
||||
pages=Páginas
|
||||
loading=Cargando...
|
||||
addToDoc=Agregar al Documento
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Política de Privacidad
|
||||
legal.terms=Términos y Condiciones
|
||||
@@ -141,6 +142,7 @@ navbar.language=Idiomas
|
||||
navbar.settings=Configuración
|
||||
navbar.allTools=Herramientas
|
||||
navbar.multiTool=Multi herramientas
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizar
|
||||
navbar.sections.convertTo=Convertir a PDF
|
||||
navbar.sections.convertFrom=Convertir desde PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(por ej., 1,3,2 o 4-8,2,10-12 o 2n-1)
|
||||
multiTool.title=Multi-herramienta PDF
|
||||
multiTool.header=Multi-herramienta PDF
|
||||
multiTool.uploadPrompts=Nombre del archivo
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Ver PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Languages
|
||||
navbar.settings=Ezarpenak
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
multiTool.title=PDF erabilera anitzeko tresna
|
||||
multiTool.header=PDF erabilera anitzeko tresna
|
||||
multiTool.uploadPrompts=File Name
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=View PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Chargement...
|
||||
addToDoc=Ajouter au Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Politique de Confidentialité
|
||||
legal.terms=Conditions Générales
|
||||
@@ -141,6 +142,7 @@ navbar.language=Langues
|
||||
navbar.settings=Paramètres
|
||||
navbar.allTools=Outils
|
||||
navbar.multiTool=Outils Multiples
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organisation
|
||||
navbar.sections.convertTo=Convertir en PDF
|
||||
navbar.sections.convertFrom=Convertir depuis PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(par exemple 1,3,2 ou 4-8,2,10-12 ou 2n-1)
|
||||
multiTool.title=Outil multifonction PDF
|
||||
multiTool.header=Outil multifonction PDF
|
||||
multiTool.uploadPrompts=Nom du fichier
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visualiser un PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Teangacha
|
||||
navbar.settings=Socruithe
|
||||
navbar.allTools=Uirlisí
|
||||
navbar.multiTool=Uirlisí Il
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Eagraigh
|
||||
navbar.sections.convertTo=Tiontaigh go PDF
|
||||
navbar.sections.convertFrom=Tiontaigh ó PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(m.sh. 1,3,2 nó 4-8,2,10-12 nó 2n-1)
|
||||
multiTool.title=Il-uirlis PDF
|
||||
multiTool.header=Il-uirlis PDF
|
||||
multiTool.uploadPrompts=Ainm comhaid
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Féach PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=पृष्ठ
|
||||
pages=पृष्ठों
|
||||
loading=डालिंग...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=गुप्तता सूचना
|
||||
legal.terms=शर्तें और प्रवाह
|
||||
@@ -141,6 +142,7 @@ navbar.language=भाषा
|
||||
navbar.settings=सेटिंग्स
|
||||
navbar.allTools=साधन
|
||||
navbar.multiTool=विभिन्न साधन
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=संगठित करें
|
||||
navbar.sections.convertTo=पीडीएफ में कनवर्ट करें
|
||||
navbar.sections.convertFrom=पीडीएफ से कनवर्ट करें
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(जैसे 1,3,2 या 4-8,2,10-12 या 2n-1)
|
||||
multiTool.title=पीडीएफ मल्टी टूल
|
||||
multiTool.header=पीडीएफ मल्टी टूल
|
||||
multiTool.uploadPrompts=फाइल का नाम
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=पीडीएफ देखें
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Stranica
|
||||
pages=Stranice
|
||||
loading=Učitavanje...
|
||||
addToDoc=Dodaj u dokument
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Politika privatnosti
|
||||
legal.terms=Uspe sodržine
|
||||
@@ -141,6 +142,7 @@ navbar.language=Jezici
|
||||
navbar.settings=Postavke
|
||||
navbar.allTools=Alati
|
||||
navbar.multiTool=Multi Tools (Alati)
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizirati
|
||||
navbar.sections.convertTo=Pretvori u PDF
|
||||
navbar.sections.convertFrom=Pretvori iz PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(npr. 1,3,2 ili 4-8,2,10-12 ili 2n-1)
|
||||
multiTool.title=PDF Višenamjenski alat
|
||||
multiTool.header=PDF Višenamjenski alat
|
||||
multiTool.uploadPrompts=Naziv datoteke
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Pogledaj
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Oldal
|
||||
pages=Oldalak
|
||||
loading=Betöltés...
|
||||
addToDoc=Hozzáadás dokumentumba
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Adatvédelmi nyilatkozat
|
||||
legal.terms=Feltételek és feltételek
|
||||
@@ -141,6 +142,7 @@ navbar.language=Nyelvek
|
||||
navbar.settings=Beállítások
|
||||
navbar.allTools=Eszközök
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Összeállítás
|
||||
navbar.sections.convertTo=Átalakítás PDF-be
|
||||
navbar.sections.convertFrom=PDF-ből átalakítás
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(pl.: 1,3,2 vagy 4-8,2,10-12 vagy 2n-1)
|
||||
multiTool.title=PDF többfunkciós eszköz
|
||||
multiTool.header=PDF többfunkciós eszköz
|
||||
multiTool.uploadPrompts=Fájl neve
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF megtekintése
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Halaman
|
||||
pages=Halaman-halaman
|
||||
loading=Mengambil data...
|
||||
addToDoc=Tambahkan ke Dokumen
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Kebijakan Privasi
|
||||
legal.terms=Syarat dan Ketentuan
|
||||
@@ -141,6 +142,7 @@ navbar.language=Bahasa
|
||||
navbar.settings=Pengaturan
|
||||
navbar.allTools=Alat
|
||||
navbar.multiTool=Alat Multi
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Atur
|
||||
navbar.sections.convertTo=Konversi ke PDF
|
||||
navbar.sections.convertFrom=Konversi dari PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(misalnya 1,3,2 atau 4-8,2,10-12 atau 2n-1)
|
||||
multiTool.title=Alat Multi PDF
|
||||
multiTool.header=Alat Multi PDF
|
||||
multiTool.uploadPrompts=Nama Berkas
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Lihat PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Pagina
|
||||
pages=Pagine
|
||||
loading=Caricamento...
|
||||
addToDoc=Aggiungi al documento
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Informativa sulla privacy
|
||||
legal.terms=Termini e Condizioni
|
||||
@@ -141,6 +142,7 @@ navbar.language=Lingue
|
||||
navbar.settings=Impostazioni
|
||||
navbar.allTools=Strumenti
|
||||
navbar.multiTool=Strumenti multipli
|
||||
navbar.search=Cerca
|
||||
navbar.sections.organize=Organizza
|
||||
navbar.sections.convertTo=Converti in PDF
|
||||
navbar.sections.convertFrom=Converti da PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(ad es. 1,3,2 o 4-8,2,10-12 o 2n-1)
|
||||
multiTool.title=Multifunzione PDF
|
||||
multiTool.header=Multifunzione PDF
|
||||
multiTool.uploadPrompts=Nome file
|
||||
multiTool.selectAll=Seleziona tutto
|
||||
multiTool.deselectAll=Deseleziona tutto
|
||||
multiTool.selectPages=Seleziona pagina
|
||||
multiTool.selectedPages=Seleziona pagine
|
||||
multiTool.page=Pagina
|
||||
multiTool.deleteSelected=Elimina selezionata
|
||||
multiTool.downloadAll=Esporta
|
||||
multiTool.downloadSelected=Esporta selezionata
|
||||
|
||||
#multiTool-advert
|
||||
multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visualizza PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=プライバシーポリシー
|
||||
legal.terms=利用規約
|
||||
@@ -141,6 +142,7 @@ navbar.language=言語
|
||||
navbar.settings=設定
|
||||
navbar.allTools=ツール
|
||||
navbar.multiTool=マルチツール
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=整理
|
||||
navbar.sections.convertTo=PDFへ変換
|
||||
navbar.sections.convertFrom=PDFから変換
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(例:1,3,2または4-8,2,10-12または2n-1)
|
||||
multiTool.title=PDFマルチツール
|
||||
multiTool.header=PDFマルチツール
|
||||
multiTool.uploadPrompts=ファイル名
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDFを表示
|
||||
|
||||
@@ -81,6 +81,7 @@ page=페이지
|
||||
pages=페이지
|
||||
loading=로딩 중...
|
||||
addToDoc=문서에 추가
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=개인 정보 정책
|
||||
legal.terms=이용 약관
|
||||
@@ -141,6 +142,7 @@ navbar.language=언어
|
||||
navbar.settings=설정
|
||||
navbar.allTools=도구
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=조직
|
||||
navbar.sections.convertTo=PDF로 변환
|
||||
navbar.sections.convertFrom=PDF에서 변환
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(예: 1,3,2 또는 4-8,2,10-12 또는 2n-1)
|
||||
multiTool.title=PDF 멀티툴
|
||||
multiTool.header=PDF 멀티툴
|
||||
multiTool.uploadPrompts=파일 이름
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF 뷰어
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Pagina
|
||||
pages=Pagen
|
||||
loading=Laden...
|
||||
addToDoc=Toevoegen aan document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacybeleid
|
||||
legal.terms=Voorwaarden van gebruik
|
||||
@@ -141,6 +142,7 @@ navbar.language=Talen
|
||||
navbar.settings=Instellingen
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multitools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizeren
|
||||
navbar.sections.convertTo=Converteren naar PDF
|
||||
navbar.sections.convertFrom=Converteren van PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(bijv. 1,3,2 of 4-8,2,10-12 of 2n-1)
|
||||
multiTool.title=PDF Multitool
|
||||
multiTool.header=PDF Multitool
|
||||
multiTool.uploadPrompts=Bestandsnaam
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF bekijken
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Språk
|
||||
navbar.settings=Innstillinger
|
||||
navbar.allTools=Verktøy
|
||||
navbar.multiTool=Multi Verktøy
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organisere
|
||||
navbar.sections.convertTo=Konverter til PDF
|
||||
navbar.sections.convertFrom=Konverter fra PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(f.eks. 1,3,2 eller 4-8,2,10-12 eller 2n-1)
|
||||
multiTool.title=PDF-multiverktøy
|
||||
multiTool.header=PDF-multiverktøy
|
||||
multiTool.uploadPrompts=Filnavn
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Vis PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Strona
|
||||
pages=Strony
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Polityka Prywatności
|
||||
legal.terms=Zasady i Postanowienia
|
||||
@@ -141,6 +142,7 @@ navbar.language=Języki
|
||||
navbar.settings=Ustawienia
|
||||
navbar.allTools=Narzędzia
|
||||
navbar.multiTool=Narzędzie Wielofunkcyjne
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizuj
|
||||
navbar.sections.convertTo=Przetwórz na PDF
|
||||
navbar.sections.convertFrom=Przetwórz z PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(przykład 1,3,2 lub 4-8,2,10-12 lub 2n-1)
|
||||
multiTool.title=Narzędzie Wielofunkcyjne PDF
|
||||
multiTool.header=Narzędzie Wielofunkcyjne PDF
|
||||
multiTool.uploadPrompts=Nazwa pliku
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Podejrzyj PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Página
|
||||
pages=Páginas
|
||||
loading=Carregando...
|
||||
addToDoc=Adicionar ao Documento
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Política de Privacidade
|
||||
legal.terms=Termos e Condições
|
||||
@@ -141,6 +142,7 @@ navbar.language=Idiomas
|
||||
navbar.settings=Configurações
|
||||
navbar.allTools=Ferramentas
|
||||
navbar.multiTool=Multiferramentas
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizar
|
||||
navbar.sections.convertTo=Converter para PDF
|
||||
navbar.sections.convertFrom=Converter de PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(por exemplo 1,3,2 ou 4-8,2,10-12 ou 2n-1)
|
||||
multiTool.title=Multiferramenta de PDF
|
||||
multiTool.header=Multiferramenta de PDF
|
||||
multiTool.uploadPrompts=Nome do arquivo
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visualizar PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Página
|
||||
pages=Páginas
|
||||
loading=A carregar...
|
||||
addToDoc=Adicionar ao Documento
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Política de Privacidade
|
||||
legal.terms=Termos e Condições
|
||||
@@ -141,6 +142,7 @@ navbar.language=Idiomas
|
||||
navbar.settings=Configurações
|
||||
navbar.allTools=Ferramentas
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizar
|
||||
navbar.sections.convertTo=Converter para PDF
|
||||
navbar.sections.convertFrom=Converter de PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(ex: 1,3,2 ou 4-8,2,10-12 ou 2n-1)
|
||||
multiTool.title=Multiferramenta de PDF
|
||||
multiTool.header=Multiferramenta de PDF
|
||||
multiTool.uploadPrompts=Nome do Arquivo
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visualizar PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Limbi
|
||||
navbar.settings=Setări
|
||||
navbar.allTools=Instrumente
|
||||
navbar.multiTool=Instrumente Multiple
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organizează
|
||||
navbar.sections.convertTo=Convertește în PDF
|
||||
navbar.sections.convertFrom=Convertește din PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(ex. 1,3,2 sau 4-8,2,10-12 sau 2n-1)
|
||||
multiTool.title=Instrument PDF multiplu
|
||||
multiTool.header=Instrument PDF multiplu
|
||||
multiTool.uploadPrompts=Nume Fișier
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Vizualizează PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Страница
|
||||
pages=Страницы
|
||||
loading=Загрузка...
|
||||
addToDoc=Добавить в документ
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Политика конфиденциальности
|
||||
legal.terms=Условия использования
|
||||
@@ -141,6 +142,7 @@ navbar.language=Языки
|
||||
navbar.settings=Настройки
|
||||
navbar.allTools=Конвейеры
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Организация
|
||||
navbar.sections.convertTo=Перевести в PDF
|
||||
navbar.sections.convertFrom=Перевести из PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(например, 1,3,2 или 4-8,2,10-12 или 2n-1
|
||||
multiTool.title=Мультиинструмент PDF
|
||||
multiTool.header=Мультиинструмент PDF
|
||||
multiTool.uploadPrompts=Имя файла
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Просмотреть PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Languages
|
||||
navbar.settings=Nastavenia
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(napr. 1,3,2 alebo 4-8,2,10-12 alebo 2n-1)
|
||||
multiTool.title=PDF Multi Nástroj
|
||||
multiTool.header=PDF Multi Nástroj
|
||||
multiTool.uploadPrompts=File Name
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Zobraziť PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Languages
|
||||
navbar.settings=Podešavanja
|
||||
navbar.allTools=Tools
|
||||
navbar.multiTool=Multi Tools
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organize
|
||||
navbar.sections.convertTo=Convert to PDF
|
||||
navbar.sections.convertFrom=Convert from PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(e.g. 1,3,2 or 4-8,2,10-12 or 2n-1)
|
||||
multiTool.title=PDF Multi Alatka
|
||||
multiTool.header=PDF Multi Alatka
|
||||
multiTool.uploadPrompts=File Name
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Prikaz
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Sidan
|
||||
pages=Sidor
|
||||
loading=Laddar...
|
||||
addToDoc=Lägg till i dokument
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Dataprotektionspolicy
|
||||
legal.terms=Villkor och betingelser
|
||||
@@ -141,6 +142,7 @@ navbar.language=Språk
|
||||
navbar.settings=Inställningar
|
||||
navbar.allTools=Verktyg
|
||||
navbar.multiTool=Multiverktyg
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Organisera
|
||||
navbar.sections.convertTo=Konvertera till PDF
|
||||
navbar.sections.convertFrom=Konvertera från PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(t.ex. 1,3,2 eller 4-8,2,10-12 eller 2n-1)
|
||||
multiTool.title=PDF-multiverktyg
|
||||
multiTool.header=PDF Multi-verktyg
|
||||
multiTool.uploadPrompts=Filnamn
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Visa PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=หน้า
|
||||
pages=หน้า
|
||||
loading=กำลังโหลด...
|
||||
addToDoc=เพิ่มเข้าสู่เอกสาร
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=นโยบายความเป็นส่วนตัว
|
||||
legal.terms=ข้อกำหนดการใช้งาน
|
||||
@@ -141,6 +142,7 @@ navbar.language=ภาษา
|
||||
navbar.settings=การตั้งค่า
|
||||
navbar.allTools=เครื่องมือทั้งหมด
|
||||
navbar.multiTool=เครื่องมือหลายตัว
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=จัดระเบียบ
|
||||
navbar.sections.convertTo=แปลงเป็น PDF
|
||||
navbar.sections.convertFrom=แปลงจาก PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(เช่น 1,3,2 หรือ 4-8,2,10-12 หรื
|
||||
multiTool.title=เครื่องมือ PDF หลายตัว
|
||||
multiTool.header=เครื่องมือ PDF หลายตัว
|
||||
multiTool.uploadPrompts=ชื่อไฟล์
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=ดู PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Gizlilik Politikası
|
||||
legal.terms=Şartlar ve koşullar
|
||||
@@ -141,6 +142,7 @@ navbar.language=Diller
|
||||
navbar.settings=Ayarlar
|
||||
navbar.allTools=Araçlar
|
||||
navbar.multiTool=Çoklu Araçlar
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Düzenle
|
||||
navbar.sections.convertTo=PDF'ye dönüştür
|
||||
navbar.sections.convertFrom=PDF'den dönüştür
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(örn. 1,3,2 veya 4-8,2,10-12 veya 2n-1)
|
||||
multiTool.title=PDF Çoklu Araç
|
||||
multiTool.header=PDF Çoklu Araç
|
||||
multiTool.uploadPrompts=Dosya Adı
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=PDF Görüntüle
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Мови
|
||||
navbar.settings=Налаштування
|
||||
navbar.allTools=Інструменти
|
||||
navbar.multiTool=Мультіінструмент
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Організувати
|
||||
navbar.sections.convertTo=Конвертувати в PDF
|
||||
navbar.sections.convertFrom=Конвертувати з PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(наприклад, 1,3,2 або 4-8,2,10-12 або 2n
|
||||
multiTool.title=Мультіінструмент PDF
|
||||
multiTool.header=Мультіінструмент PDF
|
||||
multiTool.uploadPrompts=Ім'я файлу
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Переглянути PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=Ngôn ngữ
|
||||
navbar.settings=Cài đặt
|
||||
navbar.allTools=Công cụ
|
||||
navbar.multiTool=Đa công cụ
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=Sắp xếp
|
||||
navbar.sections.convertTo=Chuyển đổi sang PDF
|
||||
navbar.sections.convertFrom=Chuyển đổi từ PDF
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(ví dụ: 1,3,2 hoặc 4-8,2,10-12 hoặc 2n-1)
|
||||
multiTool.title=Công cụ đa năng PDF
|
||||
multiTool.header=Công cụ đa năng PDF
|
||||
multiTool.uploadPrompts=Tên tệp
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=Xem PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=Page
|
||||
pages=Pages
|
||||
loading=Loading...
|
||||
addToDoc=Add to Document
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=Privacy Policy
|
||||
legal.terms=Terms and Conditions
|
||||
@@ -141,6 +142,7 @@ navbar.language=语言
|
||||
navbar.settings=设置
|
||||
navbar.allTools=工具箱
|
||||
navbar.multiTool=多功能工具
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=组织
|
||||
navbar.sections.convertTo=转换成PDF
|
||||
navbar.sections.convertFrom=从PDF转换
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(例如:1,3,2 或 4-8,2,10-12 或 2n-1)
|
||||
multiTool.title=PDF多功能工具
|
||||
multiTool.header=PDF多功能工具
|
||||
multiTool.uploadPrompts=文件名
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=浏览PDF
|
||||
|
||||
@@ -81,6 +81,7 @@ page=頁面
|
||||
pages=頁面
|
||||
loading=載入中...
|
||||
addToDoc=新增至文件
|
||||
reset=Reset
|
||||
|
||||
legal.privacy=隱私權政策
|
||||
legal.terms=使用條款
|
||||
@@ -141,6 +142,7 @@ navbar.language=語言
|
||||
navbar.settings=設定
|
||||
navbar.allTools=工具
|
||||
navbar.multiTool=複合工具
|
||||
navbar.search=Search
|
||||
navbar.sections.organize=整理
|
||||
navbar.sections.convertTo=轉換為 PDF
|
||||
navbar.sections.convertFrom=從 PDF 轉換
|
||||
@@ -933,6 +935,17 @@ pdfOrganiser.placeholder=(例如 1,3,2 或 4-8,2,10-12 或 2n-1)
|
||||
multiTool.title=PDF 複合工具
|
||||
multiTool.header=PDF 複合工具
|
||||
multiTool.uploadPrompts=檔名
|
||||
multiTool.selectAll=Select All
|
||||
multiTool.deselectAll=Deselect All
|
||||
multiTool.selectPages=Page Select
|
||||
multiTool.selectedPages=Selected Pages
|
||||
multiTool.page=Page
|
||||
multiTool.deleteSelected=Delete Selected
|
||||
multiTool.downloadAll=Export
|
||||
multiTool.downloadSelected=Export Selected
|
||||
|
||||
#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!
|
||||
|
||||
#view pdf
|
||||
viewPdf.title=檢視 PDF
|
||||
|
||||
@@ -212,15 +212,81 @@ label {
|
||||
.page-number {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 0px;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
left: 5px;
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: rgba(162, 201, 255, 0.8);
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
z-index: 2;
|
||||
font-weight: 450;
|
||||
}
|
||||
|
||||
.tool-header {
|
||||
margin: 0.5rem 1rem 2rem;
|
||||
}
|
||||
|
||||
#select-pages-button {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.selected-pages-container {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border-radius: 16px;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.selected-pages-container h3 {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.pages-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
max-height: 10rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.page-item {
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: bold;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
width: 7rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.selected-page-number {
|
||||
width: 4rem;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
cursor: pointer;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,22 @@ html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-butto
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
|
||||
.pdf-actions_checkbox {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 3px;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.pdf-actions_insert-file-blank-button {
|
||||
position: absolute;
|
||||
top: 75%;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
src: url(../../fonts/google-symbol.woff2) format('woff2');
|
||||
}
|
||||
|
||||
|
||||
|
||||
.material-symbols-rounded {
|
||||
font-family: 'Material Symbols Rounded';
|
||||
font-weight: 300;
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
await handleSingleDownload(url, formData);
|
||||
}
|
||||
}
|
||||
|
||||
clearFileInput();
|
||||
clearTimeout(timeoutId);
|
||||
$("#submitBtn").text(originalButtonText);
|
||||
|
||||
@@ -85,6 +87,7 @@
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
clearFileInput();
|
||||
clearTimeout(timeoutId);
|
||||
handleDownloadError(error);
|
||||
$("#submitBtn").text(originalButtonText);
|
||||
@@ -116,11 +119,15 @@
|
||||
|
||||
const blob = await response.blob();
|
||||
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
|
||||
clearFileInput();
|
||||
return handleResponse(blob, filename, !isMulti, isZip);
|
||||
} else {
|
||||
clearFileInput();
|
||||
return handleResponse(blob, filename, false, isZip);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
clearFileInput();
|
||||
console.error("Error in handleSingleDownload:", error);
|
||||
throw error;
|
||||
}
|
||||
@@ -291,4 +298,27 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Clear file input after job
|
||||
function clearFileInput(){
|
||||
let pathname = document.location.pathname;
|
||||
if(pathname != "/merge-pdfs"){
|
||||
let formElement = document.querySelector("#fileInput-input");
|
||||
formElement.value = '';
|
||||
let editSectionElement = document.querySelector("#editSection");
|
||||
if(editSectionElement){
|
||||
editSectionElement.style.display = "none";
|
||||
}
|
||||
let cropPdfCanvas = document.querySelector("#crop-pdf-canvas");
|
||||
let overlayCanvas = document.querySelector("#overlayCanvas");
|
||||
if(cropPdfCanvas && overlayCanvas){
|
||||
cropPdfCanvas.width = 0;
|
||||
cropPdfCanvas.heigth = 0;
|
||||
|
||||
overlayCanvas.width = 0;
|
||||
overlayCanvas.heigth = 0;
|
||||
}
|
||||
} else{
|
||||
console.log("Disabled for 'Merge'");
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -9,81 +9,81 @@ const DraggableUtils = {
|
||||
|
||||
init() {
|
||||
interact(".draggable-canvas")
|
||||
.draggable({
|
||||
listeners: {
|
||||
move: (event) => {
|
||||
const target = event.target;
|
||||
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0)
|
||||
.draggable({
|
||||
listeners: {
|
||||
move: (event) => {
|
||||
const target = event.target;
|
||||
const x = (parseFloat(target.getAttribute("data-bs-x")) || 0)
|
||||
+ event.dx;
|
||||
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
|
||||
const y = (parseFloat(target.getAttribute("data-bs-y")) || 0)
|
||||
+ event.dy;
|
||||
|
||||
target.style.transform = `translate(${x}px, ${y}px)`;
|
||||
target.setAttribute("data-bs-x", x);
|
||||
target.setAttribute("data-bs-y", y);
|
||||
target.style.transform = `translate(${x}px, ${y}px)`;
|
||||
target.setAttribute("data-bs-x", x);
|
||||
target.setAttribute("data-bs-y", y);
|
||||
|
||||
this.onInteraction(target);
|
||||
//update the last interacted element
|
||||
this.lastInteracted = event.target;
|
||||
this.onInteraction(target);
|
||||
//update the last interacted element
|
||||
this.lastInteracted = event.target;
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.resizable({
|
||||
edges: { left: true, right: true, bottom: true, top: true },
|
||||
listeners: {
|
||||
move: (event) => {
|
||||
var target = event.target;
|
||||
var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
|
||||
var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
|
||||
})
|
||||
.resizable({
|
||||
edges: { left: true, right: true, bottom: true, top: true },
|
||||
listeners: {
|
||||
move: (event) => {
|
||||
var target = event.target;
|
||||
var x = parseFloat(target.getAttribute("data-bs-x")) || 0;
|
||||
var y = parseFloat(target.getAttribute("data-bs-y")) || 0;
|
||||
|
||||
// check if control key is pressed
|
||||
if (event.ctrlKey) {
|
||||
const aspectRatio = target.offsetWidth / target.offsetHeight;
|
||||
// preserve aspect ratio
|
||||
let width = event.rect.width;
|
||||
let height = event.rect.height;
|
||||
// check if control key is pressed
|
||||
if (event.ctrlKey) {
|
||||
const aspectRatio = target.offsetWidth / target.offsetHeight;
|
||||
// preserve aspect ratio
|
||||
let width = event.rect.width;
|
||||
let height = event.rect.height;
|
||||
|
||||
if (Math.abs(event.deltaRect.width) >= Math.abs(
|
||||
if (Math.abs(event.deltaRect.width) >= Math.abs(
|
||||
event.deltaRect.height)) {
|
||||
height = width / aspectRatio;
|
||||
} else {
|
||||
width = height * aspectRatio;
|
||||
height = width / aspectRatio;
|
||||
} else {
|
||||
width = height * aspectRatio;
|
||||
}
|
||||
|
||||
event.rect.width = width;
|
||||
event.rect.height = height;
|
||||
}
|
||||
|
||||
event.rect.width = width;
|
||||
event.rect.height = height;
|
||||
}
|
||||
target.style.width = event.rect.width + "px";
|
||||
target.style.height = event.rect.height + "px";
|
||||
|
||||
target.style.width = event.rect.width + "px";
|
||||
target.style.height = event.rect.height + "px";
|
||||
// translate when resizing from top or left edges
|
||||
x += event.deltaRect.left;
|
||||
y += event.deltaRect.top;
|
||||
|
||||
// translate when resizing from top or left edges
|
||||
x += event.deltaRect.left;
|
||||
y += event.deltaRect.top;
|
||||
target.style.transform = "translate(" + x + "px," + y + "px)";
|
||||
|
||||
target.style.transform = "translate(" + x + "px," + y + "px)";
|
||||
|
||||
target.setAttribute("data-bs-x", x);
|
||||
target.setAttribute("data-bs-y", y);
|
||||
target.textContent = Math.round(event.rect.width) + "\u00D7"
|
||||
target.setAttribute("data-bs-x", x);
|
||||
target.setAttribute("data-bs-y", y);
|
||||
target.textContent = Math.round(event.rect.width) + "\u00D7"
|
||||
+ Math.round(event.rect.height);
|
||||
|
||||
this.onInteraction(target);
|
||||
this.onInteraction(target);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
modifiers: [
|
||||
interact.modifiers.restrictSize({
|
||||
min: {width: 5, height: 5},
|
||||
}),
|
||||
],
|
||||
inertia: true,
|
||||
});
|
||||
modifiers: [
|
||||
interact.modifiers.restrictSize({
|
||||
min: { width: 5, height: 5 },
|
||||
}),
|
||||
],
|
||||
inertia: true,
|
||||
});
|
||||
//Arrow key Support for Add-Image and Sign pages
|
||||
if(window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
|
||||
if (window.location.pathname.endsWith('sign') || window.location.pathname.endsWith('add-image')) {
|
||||
window.addEventListener('keydown', (event) => {
|
||||
//Check for last interacted element
|
||||
if (!this.lastInteracted){
|
||||
if (!this.lastInteracted) {
|
||||
return;
|
||||
}
|
||||
// Get the currently selected element
|
||||
@@ -288,7 +288,7 @@ const DraggableUtils = {
|
||||
}
|
||||
},
|
||||
|
||||
parseTransform(element) {},
|
||||
parseTransform(element) { },
|
||||
async getOverlayedPdfDocument() {
|
||||
const pdfBytes = await this.pdfDoc.getData();
|
||||
const pdfDocModified = await PDFLib.PDFDocument.load(pdfBytes, {
|
||||
@@ -308,6 +308,7 @@ const DraggableUtils = {
|
||||
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
|
||||
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
|
||||
|
||||
|
||||
for (const draggableData of draggablesData) {
|
||||
// embed the draggable canvas
|
||||
const draggableElement = draggableData.element;
|
||||
@@ -324,6 +325,24 @@ const DraggableUtils = {
|
||||
width: draggableData.offsetWidth,
|
||||
height: draggableData.offsetHeight,
|
||||
};
|
||||
|
||||
//Auxiliary variables
|
||||
let widthAdjusted = page.getWidth();
|
||||
let heightAdjusted = page.getHeight();
|
||||
const rotation = page.getRotation();
|
||||
|
||||
//Normalizing angle
|
||||
let normalizedAngle = rotation.angle % 360;
|
||||
if (normalizedAngle < 0) {
|
||||
normalizedAngle += 360;
|
||||
}
|
||||
|
||||
//Changing the page dimension if the angle is 90 or 270
|
||||
if (normalizedAngle === 90 || normalizedAngle === 270) {
|
||||
let widthTemp = widthAdjusted;
|
||||
widthAdjusted = heightAdjusted;
|
||||
heightAdjusted = widthTemp;
|
||||
}
|
||||
const draggablePositionRelative = {
|
||||
x: draggablePositionPixels.x / offsetWidth,
|
||||
y: draggablePositionPixels.y / offsetHeight,
|
||||
@@ -331,18 +350,36 @@ const DraggableUtils = {
|
||||
height: draggablePositionPixels.height / offsetHeight,
|
||||
};
|
||||
const draggablePositionPdf = {
|
||||
x: draggablePositionRelative.x * page.getWidth(),
|
||||
y: draggablePositionRelative.y * page.getHeight(),
|
||||
width: draggablePositionRelative.width * page.getWidth(),
|
||||
height: draggablePositionRelative.height * page.getHeight(),
|
||||
x: draggablePositionRelative.x * widthAdjusted,
|
||||
y: draggablePositionRelative.y * heightAdjusted,
|
||||
width: draggablePositionRelative.width * widthAdjusted,
|
||||
height: draggablePositionRelative.height * heightAdjusted,
|
||||
};
|
||||
|
||||
//Defining the image if the page has a 0-degree angle
|
||||
let x = draggablePositionPdf.x
|
||||
let y = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height
|
||||
|
||||
|
||||
//Defining the image position if it is at other angles
|
||||
if (normalizedAngle === 90) {
|
||||
x = draggablePositionPdf.y + draggablePositionPdf.height;
|
||||
y = draggablePositionPdf.x;
|
||||
} else if (normalizedAngle === 180) {
|
||||
x = widthAdjusted - draggablePositionPdf.x;
|
||||
y = draggablePositionPdf.y + draggablePositionPdf.height;
|
||||
} else if (normalizedAngle === 270) {
|
||||
x = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height;
|
||||
y = widthAdjusted - draggablePositionPdf.x;
|
||||
}
|
||||
|
||||
// draw the image
|
||||
page.drawImage(pdfImageObject, {
|
||||
x: draggablePositionPdf.x,
|
||||
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
|
||||
x: x,
|
||||
y: y,
|
||||
width: draggablePositionPdf.width,
|
||||
height: draggablePositionPdf.height,
|
||||
rotate: rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ async function displayFiles(files) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const pageCount = await getPDFPageCount(files[i]);
|
||||
const pageLabel = pageCount === 1 ? pageTranslation : pagesTranslation;
|
||||
|
||||
|
||||
// Create list item
|
||||
const item = document.createElement("li");
|
||||
item.className = "list-group-item";
|
||||
@@ -173,3 +173,18 @@ function updateFiles() {
|
||||
}
|
||||
document.getElementById("fileInput-input").files = dataTransfer.files;
|
||||
}
|
||||
|
||||
document.querySelector("#resetFileInputBtn").addEventListener("click", ()=>{
|
||||
let formElement = document.querySelector("#fileInput-input");
|
||||
formElement.value = '';
|
||||
clearLiElements();
|
||||
updateFiles();
|
||||
|
||||
});
|
||||
|
||||
function clearLiElements(){
|
||||
let listGroupItemNodeList = document.querySelectorAll(".list-group-item");
|
||||
for (let i = 0; i < listGroupItemNodeList.length; i++) {
|
||||
listGroupItemNodeList[i].remove();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class PdfActionsManager {
|
||||
pageDirection;
|
||||
pagesContainer;
|
||||
static selectedPages = []; // Static property shared across all instances
|
||||
|
||||
constructor(id) {
|
||||
this.pagesContainer = document.getElementById(id);
|
||||
@@ -98,6 +99,7 @@ class PdfActionsManager {
|
||||
this.splitFileButtonCallback = this.splitFileButtonCallback.bind(this);
|
||||
}
|
||||
|
||||
|
||||
adapt(div) {
|
||||
div.classList.add("pdf-actions_container");
|
||||
const leftDirection = this.pageDirection === "rtl" ? "right" : "left";
|
||||
@@ -138,6 +140,45 @@ class PdfActionsManager {
|
||||
|
||||
div.appendChild(buttonContainer);
|
||||
|
||||
//enerate checkbox to select individual pages
|
||||
const selectCheckbox = document.createElement("input");
|
||||
selectCheckbox.type = "checkbox";
|
||||
selectCheckbox.classList.add("pdf-actions_checkbox", "form-check-input");
|
||||
selectCheckbox.id = `selectPageCheckbox`;
|
||||
selectCheckbox.checked = window.selectAll;
|
||||
|
||||
div.appendChild(selectCheckbox);
|
||||
|
||||
//only show whenpage select mode is active
|
||||
if (!window.selectPage) {
|
||||
selectCheckbox.classList.add("hidden");
|
||||
} else {
|
||||
selectCheckbox.classList.remove("hidden");
|
||||
}
|
||||
|
||||
selectCheckbox.onchange = () => {
|
||||
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
|
||||
if (selectCheckbox.checked) {
|
||||
//adds to array of selected pages
|
||||
window.selectedPages.push(pageNumber);
|
||||
} else {
|
||||
//remove page from selected pages array
|
||||
const index = window.selectedPages.indexOf(pageNumber);
|
||||
if (index !== -1) {
|
||||
window.selectedPages.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.selectedPages.length > 0 && !window.selectPage) {
|
||||
window.toggleSelectPageVisibility();
|
||||
}
|
||||
if (window.selectedPages.length == 0 && window.selectPage) {
|
||||
window.toggleSelectPageVisibility();
|
||||
}
|
||||
|
||||
window.updateSelectedPagesDisplay();
|
||||
};
|
||||
|
||||
const insertFileButtonContainer = document.createElement("div");
|
||||
|
||||
insertFileButtonContainer.classList.add(
|
||||
@@ -191,15 +232,29 @@ class PdfActionsManager {
|
||||
};
|
||||
|
||||
div.addEventListener("mouseenter", () => {
|
||||
window.updatePageNumbersAndCheckboxes();
|
||||
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
|
||||
adaptPageNumber(pageNumber, div);
|
||||
const checkbox = document.getElementById(`selectPageCheckbox-${pageNumber}`);
|
||||
if (checkbox && !window.selectPage) {
|
||||
checkbox.classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
div.addEventListener("mouseleave", () => {
|
||||
const pageNumber = Array.from(div.parentNode.children).indexOf(div) + 1;
|
||||
const pageNumberElement = div.querySelector(".page-number");
|
||||
if (pageNumberElement) {
|
||||
div.removeChild(pageNumberElement);
|
||||
}
|
||||
const checkbox = document.getElementById(`selectPageCheckbox-${pageNumber}`);
|
||||
if (checkbox && !window.selectPage) {
|
||||
checkbox.classList.add("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("selectedPagesUpdated", () => {
|
||||
window.updateSelectedPagesDisplay();
|
||||
});
|
||||
|
||||
return div;
|
||||
|
||||
@@ -22,7 +22,13 @@ class PdfContainer {
|
||||
this.nameAndArchiveFiles = this.nameAndArchiveFiles.bind(this);
|
||||
this.splitPDF = this.splitPDF.bind(this);
|
||||
this.splitAll = this.splitAll.bind(this);
|
||||
this.deleteSelected = this.deleteSelected.bind(this);
|
||||
this.toggleSelectAll = this.toggleSelectAll.bind(this);
|
||||
this.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay.bind(this);
|
||||
this.toggleSelectPageVisibility = this.toggleSelectPageVisibility.bind(this);
|
||||
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
|
||||
this.addFilesBlankAll = this.addFilesBlankAll.bind(this)
|
||||
this.removeAllElements = this.removeAllElements.bind(this);
|
||||
|
||||
this.pdfAdapters = pdfAdapters;
|
||||
|
||||
@@ -32,6 +38,7 @@ class PdfContainer {
|
||||
addFiles: this.addFiles,
|
||||
rotateElement: this.rotateElement,
|
||||
updateFilename: this.updateFilename,
|
||||
deleteSelected: this.deleteSelected,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,7 +46,15 @@ class PdfContainer {
|
||||
window.exportPdf = this.exportPdf;
|
||||
window.rotateAll = this.rotateAll;
|
||||
window.splitAll = this.splitAll;
|
||||
window.deleteSelected = this.deleteSelected;
|
||||
window.toggleSelectAll = this.toggleSelectAll;
|
||||
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
|
||||
window.toggleSelectPageVisibility = this.toggleSelectPageVisibility;
|
||||
window.updatePagesFromCSV = this.updatePagesFromCSV;
|
||||
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
|
||||
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
|
||||
window.addFilesBlankAll = this.addFilesBlankAll
|
||||
window.removeAllElements = this.removeAllElements;
|
||||
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
@@ -94,6 +109,8 @@ class PdfContainer {
|
||||
|
||||
this.addFilesFromFiles(files, nextSiblingElement);
|
||||
this.updateFilename(files ? files[0].name : "");
|
||||
const selectAll = document.getElementById("select-pages-container");
|
||||
selectAll.classList.toggle("hidden", false);
|
||||
};
|
||||
|
||||
input.click();
|
||||
@@ -264,15 +281,216 @@ class PdfContainer {
|
||||
}
|
||||
|
||||
rotateAll(deg) {
|
||||
for (var i = 0; i < this.pagesContainer.childNodes.length; i++) {
|
||||
for (let i = 0; i < this.pagesContainer.childNodes.length; i++) {
|
||||
const child = this.pagesContainer.children[i];
|
||||
if (!child) continue;
|
||||
|
||||
const pageIndex = i + 1;
|
||||
//if in page select mode is active rotate only selected pages
|
||||
if (window.selectPage && !window.selectedPages.includes(pageIndex)) continue;
|
||||
|
||||
const img = child.querySelector("img");
|
||||
if (!img) continue;
|
||||
|
||||
this.rotateElement(img, deg);
|
||||
}
|
||||
}
|
||||
|
||||
removeAllElements(){
|
||||
let pageContainerNodeList = document.querySelectorAll(".page-container");
|
||||
for (var i = 0; i < pageContainerNodeList.length; i++) {
|
||||
pageContainerNodeList[i].remove();
|
||||
}
|
||||
document.querySelectorAll(".enable-on-file").forEach((element) => {
|
||||
element.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
deleteSelected() {
|
||||
window.selectedPages.sort((a, b) => a - b);
|
||||
let deletions = 0;
|
||||
|
||||
window.selectedPages.forEach((pageIndex) => {
|
||||
const adjustedIndex = pageIndex - 1 - deletions;
|
||||
const child = this.pagesContainer.children[adjustedIndex];
|
||||
if (child) {
|
||||
this.pagesContainer.removeChild(child);
|
||||
deletions++;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.pagesContainer.childElementCount === 0) {
|
||||
const filenameInput = document.getElementById("filename-input");
|
||||
const filenameParagraph = document.getElementById("filename");
|
||||
const downloadBtn = document.getElementById("export-button");
|
||||
|
||||
if (filenameInput)
|
||||
filenameInput.disabled = true;
|
||||
filenameInput.value = "";
|
||||
if (filenameParagraph)
|
||||
filenameParagraph.innerText = "";
|
||||
|
||||
downloadBtn.disabled = true;
|
||||
}
|
||||
|
||||
window.selectedPages = [];
|
||||
this.updatePageNumbersAndCheckboxes();
|
||||
document.dispatchEvent(new Event("selectedPagesUpdated"));
|
||||
}
|
||||
|
||||
toggleSelectAll() {
|
||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
||||
window.selectAll = !window.selectAll;
|
||||
const selectIcon = document.getElementById("select-icon");
|
||||
const deselectIcon = document.getElementById("deselect-icon");
|
||||
|
||||
if (selectIcon.style.display === "none") {
|
||||
selectIcon.style.display = "inline";
|
||||
deselectIcon.style.display = "none";
|
||||
} else {
|
||||
selectIcon.style.display = "none";
|
||||
deselectIcon.style.display = "inline";
|
||||
}
|
||||
checkboxes.forEach((checkbox) => {
|
||||
|
||||
checkbox.checked = window.selectAll;
|
||||
|
||||
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
||||
|
||||
if (checkbox.checked) {
|
||||
if (!window.selectedPages.includes(pageNumber)) {
|
||||
window.selectedPages.push(pageNumber);
|
||||
}
|
||||
} else {
|
||||
const index = window.selectedPages.indexOf(pageNumber);
|
||||
if (index !== -1) {
|
||||
window.selectedPages.splice(index, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.updateSelectedPagesDisplay();
|
||||
}
|
||||
|
||||
parseCSVInput(csvInput, maxPageIndex) {
|
||||
const pages = new Set();
|
||||
|
||||
csvInput.split(",").forEach((item) => {
|
||||
const range = item.split("-").map((p) => parseInt(p.trim()));
|
||||
if (range.length === 2) {
|
||||
const [start, end] = range;
|
||||
for (let i = start; i <= end && i <= maxPageIndex; i++) {
|
||||
if (i > 0) { // Ensure the page number is greater than 0
|
||||
pages.add(i);
|
||||
}
|
||||
}
|
||||
} else if (range.length === 1 && Number.isInteger(range[0])) {
|
||||
const page = range[0];
|
||||
if (page > 0 && page <= maxPageIndex) { // Ensure page is within valid range
|
||||
pages.add(page);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(pages).sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
updatePagesFromCSV() {
|
||||
const csvInput = document.getElementById("csv-input").value;
|
||||
|
||||
const allPages = this.pagesContainer.querySelectorAll(".page-container");
|
||||
const maxPageIndex = allPages.length;
|
||||
|
||||
window.selectedPages = this.parseCSVInput(csvInput, maxPageIndex);
|
||||
|
||||
this.updateSelectedPagesDisplay();
|
||||
|
||||
const allCheckboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
||||
allCheckboxes.forEach((checkbox) => {
|
||||
const page = parseInt(checkbox.getAttribute("data-page-number"));
|
||||
checkbox.checked = window.selectedPages.includes(page);
|
||||
});
|
||||
}
|
||||
|
||||
formatSelectedPages(pages) {
|
||||
if (pages.length === 0) return "";
|
||||
|
||||
pages.sort((a, b) => a - b); // Sort the page numbers in ascending order
|
||||
const ranges = [];
|
||||
let start = pages[0];
|
||||
let end = start;
|
||||
|
||||
for (let i = 1; i < pages.length; i++) {
|
||||
if (pages[i] === end + 1) {
|
||||
// Consecutive page, update end
|
||||
end = pages[i];
|
||||
} else {
|
||||
// Non-consecutive page, finalize current range
|
||||
ranges.push(start === end ? `${start}` : `${start}-${end}`);
|
||||
start = pages[i];
|
||||
end = start;
|
||||
}
|
||||
}
|
||||
// Add the last range
|
||||
ranges.push(start === end ? `${start}` : `${start}-${end}`);
|
||||
|
||||
return ranges.join(", ");
|
||||
}
|
||||
|
||||
updateSelectedPagesDisplay() {
|
||||
const selectedPagesList = document.getElementById("selected-pages-list");
|
||||
const selectedPagesInput = document.getElementById("csv-input");
|
||||
selectedPagesList.innerHTML = ""; // Clear the list
|
||||
|
||||
window.selectedPages.forEach((page) => {
|
||||
const pageItem = document.createElement("div");
|
||||
pageItem.className = "page-item";
|
||||
|
||||
const pageNumber = document.createElement("span");
|
||||
const pagelabel = /*[[#{multiTool.page}]]*/ 'Page';
|
||||
pageNumber.className = "selected-page-number";
|
||||
pageNumber.innerText = `${pagelabel} ${page}`;
|
||||
pageItem.appendChild(pageNumber);
|
||||
|
||||
const removeBtn = document.createElement("span");
|
||||
removeBtn.className = "remove-btn";
|
||||
removeBtn.innerHTML = "✕";
|
||||
|
||||
// Remove page from selected pages list and update display and checkbox
|
||||
removeBtn.onclick = () => {
|
||||
window.selectedPages = window.selectedPages.filter((p) => p !== page);
|
||||
this.updateSelectedPagesDisplay();
|
||||
|
||||
const checkbox = document.getElementById(`selectPageCheckbox-${page}`);
|
||||
if (checkbox) {
|
||||
checkbox.checked = false;
|
||||
}
|
||||
};
|
||||
|
||||
pageItem.appendChild(removeBtn);
|
||||
selectedPagesList.appendChild(pageItem);
|
||||
});
|
||||
|
||||
// Update the input field with the formatted page list
|
||||
selectedPagesInput.value = this.formatSelectedPages(window.selectedPages);
|
||||
}
|
||||
|
||||
parsePageRanges(ranges) {
|
||||
const pages = new Set();
|
||||
|
||||
ranges.split(',').forEach(range => {
|
||||
const [start, end] = range.split('-').map(Number);
|
||||
if (end) {
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.add(i);
|
||||
}
|
||||
} else {
|
||||
pages.add(start);
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(pages).sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
addFilesBlankAll() {
|
||||
const allPages = this.pagesContainer.querySelectorAll(".page-container");
|
||||
@@ -283,20 +501,36 @@ class PdfContainer {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
splitAll() {
|
||||
const allPages = this.pagesContainer.querySelectorAll(".page-container");
|
||||
if (this.pagesContainer.querySelectorAll(".split-before").length > 0) {
|
||||
allPages.forEach(page => {
|
||||
page.classList.remove("split-before");
|
||||
});
|
||||
} else {
|
||||
allPages.forEach(page => {
|
||||
page.classList.add("split-before");
|
||||
});
|
||||
|
||||
if (!window.selectPage) {
|
||||
const hasSplit = this.pagesContainer.querySelectorAll(".split-before").length > 0;
|
||||
if (hasSplit) {
|
||||
allPages.forEach(page => {
|
||||
page.classList.remove("split-before");
|
||||
});
|
||||
} else {
|
||||
allPages.forEach(page => {
|
||||
page.classList.add("split-before");
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
allPages.forEach((page, index) => {
|
||||
const pageIndex = index;
|
||||
if (window.selectPage && !window.selectedPages.includes(pageIndex)) return;
|
||||
|
||||
if (page.classList.contains("split-before")) {
|
||||
page.classList.remove("split-before");
|
||||
} else {
|
||||
page.classList.add("split-before");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async splitPDF(baseDocBytes, splitters) {
|
||||
const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes);
|
||||
const pageNum = baseDocument.getPages().length;
|
||||
@@ -339,52 +573,54 @@ class PdfContainer {
|
||||
return zip;
|
||||
}
|
||||
|
||||
async exportPdf() {
|
||||
async exportPdf(selected) {
|
||||
const pdfDoc = await PDFLib.PDFDocument.create();
|
||||
const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements
|
||||
for (var i = 0; i < pageContainers.length; i++) {
|
||||
const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
|
||||
if (!img) continue;
|
||||
let page;
|
||||
if (img.doc) {
|
||||
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]);
|
||||
page = pages[0];
|
||||
pdfDoc.addPage(page);
|
||||
} else {
|
||||
page = pdfDoc.addPage([img.naturalWidth, img.naturalHeight]);
|
||||
const imageBytes = await fetch(img.src).then((res) => res.arrayBuffer());
|
||||
const uint8Array = new Uint8Array(imageBytes);
|
||||
const imageType = detectImageType(uint8Array);
|
||||
if (!selected || window.selectedPages.includes(i + 1)) {
|
||||
const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
|
||||
if (!img) continue;
|
||||
let page;
|
||||
if (img.doc) {
|
||||
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx]);
|
||||
page = pages[0];
|
||||
pdfDoc.addPage(page);
|
||||
} else {
|
||||
page = pdfDoc.addPage([img.naturalWidth, img.naturalHeight]);
|
||||
const imageBytes = await fetch(img.src).then((res) => res.arrayBuffer());
|
||||
const uint8Array = new Uint8Array(imageBytes);
|
||||
const imageType = detectImageType(uint8Array);
|
||||
|
||||
let image;
|
||||
switch (imageType) {
|
||||
case 'PNG':
|
||||
image = await pdfDoc.embedPng(imageBytes);
|
||||
break;
|
||||
case 'JPEG':
|
||||
image = await pdfDoc.embedJpg(imageBytes);
|
||||
break;
|
||||
case 'TIFF':
|
||||
image = await pdfDoc.embedTiff(imageBytes);
|
||||
break;
|
||||
case 'GIF':
|
||||
console.warn(`Unsupported image type: ${imageType}`);
|
||||
continue; // Skip this image
|
||||
default:
|
||||
console.warn(`Unsupported image type: ${imageType}`);
|
||||
continue; // Skip this image
|
||||
let image;
|
||||
switch (imageType) {
|
||||
case 'PNG':
|
||||
image = await pdfDoc.embedPng(imageBytes);
|
||||
break;
|
||||
case 'JPEG':
|
||||
image = await pdfDoc.embedJpg(imageBytes);
|
||||
break;
|
||||
case 'TIFF':
|
||||
image = await pdfDoc.embedTiff(imageBytes);
|
||||
break;
|
||||
case 'GIF':
|
||||
console.warn(`Unsupported image type: ${imageType}`);
|
||||
continue; // Skip this image
|
||||
default:
|
||||
console.warn(`Unsupported image type: ${imageType}`);
|
||||
continue; // Skip this image
|
||||
}
|
||||
page.drawImage(image, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: img.naturalWidth,
|
||||
height: img.naturalHeight,
|
||||
});
|
||||
}
|
||||
const rotation = img.style.rotate;
|
||||
if (rotation) {
|
||||
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ""));
|
||||
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
|
||||
}
|
||||
page.drawImage(image, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: img.naturalWidth,
|
||||
height: img.naturalHeight,
|
||||
});
|
||||
}
|
||||
const rotation = img.style.rotate;
|
||||
if (rotation) {
|
||||
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ""));
|
||||
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
|
||||
}
|
||||
}
|
||||
pdfDoc.setCreator(stirlingPDFLabel);
|
||||
@@ -496,7 +732,44 @@ class PdfContainer {
|
||||
// filenameInput.value.replace('.','');
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
toggleSelectPageVisibility() {
|
||||
window.selectPage = !window.selectPage;
|
||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.classList.toggle("hidden", !window.selectPage);
|
||||
});
|
||||
const deleteButton = document.getElementById("delete-button");
|
||||
deleteButton.classList.toggle("hidden", !window.selectPage);
|
||||
const selectedPages = document.getElementById("selected-pages-display");
|
||||
selectedPages.classList.toggle("hidden", !window.selectPage);
|
||||
const selectAll = document.getElementById("select-All-Container");
|
||||
selectedPages.classList.toggle("hidden", !window.selectPage);
|
||||
const exportSelected = document.getElementById("export-selected-button");
|
||||
exportSelected.classList.toggle("hidden", !window.selectPage);
|
||||
const selectPagesButton = document.getElementById("select-pages-button");
|
||||
selectPagesButton.style.opacity = window.selectPage ? "1" : "0.5";
|
||||
|
||||
if (window.selectPage) {
|
||||
this.updatePageNumbersAndCheckboxes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updatePageNumbersAndCheckboxes() {
|
||||
const pageDivs = document.querySelectorAll(".pdf-actions_container");
|
||||
|
||||
pageDivs.forEach((div, index) => {
|
||||
const pageNumber = index + 1;
|
||||
const checkbox = div.querySelector(".pdf-actions_checkbox");
|
||||
checkbox.id = `selectPageCheckbox-${pageNumber}`;
|
||||
checkbox.setAttribute("data-page-number", pageNumber);
|
||||
checkbox.checked = window.selectedPages.includes(pageNumber);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function detectImageType(uint8Array) {
|
||||
// Check for PNG signature
|
||||
if (uint8Array[0] === 137 && uint8Array[1] === 80 && uint8Array[2] === 78 && uint8Array[3] === 71) {
|
||||
@@ -521,4 +794,7 @@ function detectImageType(uint8Array) {
|
||||
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default PdfContainer;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/markdown')}"></div>
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='.md')}"></div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>
|
||||
|
||||
@@ -23,23 +23,26 @@
|
||||
</form>
|
||||
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
||||
|
||||
<div style="position: relative; display: inline-block;">
|
||||
<div style="position: relative; width: auto;" id="canvasesContainer">
|
||||
<div>
|
||||
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
|
||||
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button>
|
||||
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button>
|
||||
</div>
|
||||
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
||||
<canvas id="cropPdfCanvas" style="width: 100%"></canvas>
|
||||
</div>
|
||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2; width: 100%"></canvas>
|
||||
</div>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script>
|
||||
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
||||
let pdfCanvas = document.getElementById('cropPdfCanvas');
|
||||
let overlayCanvas = document.getElementById('overlayCanvas');
|
||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||
canvasesContainer.style.display = "none";
|
||||
// let paginationBtnContainer = ;
|
||||
|
||||
let context = pdfCanvas.getContext('2d');
|
||||
let overlayContext = overlayCanvas.getContext('2d');
|
||||
|
||||
let btn1Object = document.getElementById('previous-page-btn');
|
||||
let btn2Object = document.getElementById('next-page-btn');
|
||||
@@ -60,6 +63,8 @@
|
||||
let rectWidth = 0;
|
||||
let rectHeight = 0;
|
||||
|
||||
let timeId = null; // timeout id for resizing canvases event
|
||||
|
||||
btn1Object.addEventListener('click',function (e){
|
||||
if (currentPage !== 1) {
|
||||
currentPage = currentPage - 1;
|
||||
@@ -102,14 +107,13 @@
|
||||
}
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
file = e.target.files[0];
|
||||
function renderPageFromFile(file) {
|
||||
if (file.type === 'application/pdf') {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function(ev) {
|
||||
reader.onload = function (ev) {
|
||||
let typedArray = new Uint8Array(reader.result);
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||
pdfjsLib.getDocument(typedArray).promise.then(function(pdf) {
|
||||
pdfjsLib.getDocument(typedArray).promise.then(function (pdf) {
|
||||
pdfDoc = pdf;
|
||||
totalPages = pdf.numPages;
|
||||
renderPage(currentPage);
|
||||
@@ -117,9 +121,37 @@
|
||||
pageId.value = currentPage;
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
document.getElementById("pagination-button-container").style.display="flex";
|
||||
document.getElementById("instruction-text").style.display="block";
|
||||
document.getElementById("pagination-button-container").style.display = "flex";
|
||||
document.getElementById("instruction-text").style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("resize", function() {
|
||||
clearTimeout(timeId);
|
||||
timeId = setTimeout(function () {
|
||||
if (fileInput.files.length == 0) return;
|
||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||
let containerRect = canvasesContainer.getBoundingClientRect();
|
||||
|
||||
context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height);
|
||||
|
||||
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
||||
|
||||
pdfCanvas.width = containerRect.width;
|
||||
pdfCanvas.height = containerRect.height;
|
||||
|
||||
overlayCanvas.width = containerRect.width;
|
||||
overlayCanvas.height = containerRect.height;
|
||||
|
||||
let file = fileInput.files[0];
|
||||
renderPageFromFile(file);
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
canvasesContainer.style.display = "block"; // set for visual purposes
|
||||
file = e.target.files[0];
|
||||
renderPageFromFile(file);
|
||||
});
|
||||
|
||||
function renderPage(pageNumber) {
|
||||
|
||||
@@ -24,16 +24,20 @@
|
||||
<input id="height" type="hidden" name="height">
|
||||
<button type="submit" class="btn btn-primary" th:text="#{crop.submit}"></button>
|
||||
</form>
|
||||
<div style="position: relative; display: inline-block;">
|
||||
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
||||
<div id="canvasesContainer" style="position: relative; margin: 20px 0; width: auto;">
|
||||
<canvas id="cropPdfCanvas" style="width: 100%"></canvas>
|
||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2; width: 100%"></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script>
|
||||
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
||||
let pdfCanvas = document.getElementById('cropPdfCanvas');
|
||||
let overlayCanvas = document.getElementById('overlayCanvas');
|
||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||
canvasesContainer.style.display = "none";
|
||||
let containerRect = canvasesContainer.getBoundingClientRect();
|
||||
|
||||
let context = pdfCanvas.getContext('2d');
|
||||
let overlayContext = overlayCanvas.getContext('2d');
|
||||
@@ -59,8 +63,11 @@
|
||||
let rectWidth = 0;
|
||||
let rectHeight = 0;
|
||||
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
let file = e.target.files[0];
|
||||
|
||||
let pageScale = 1; // The scale which the pdf page renders
|
||||
let timeId = null; // timeout id for resizing canvases event
|
||||
|
||||
function renderPageFromFile(file) {
|
||||
if (file.type === 'application/pdf') {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function(ev) {
|
||||
@@ -74,6 +81,35 @@
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("resize", function() {
|
||||
clearTimeout(timeId);
|
||||
|
||||
timeId = setTimeout(function () {
|
||||
if (fileInput.files.length == 0) return;
|
||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||
let containerRect = canvasesContainer.getBoundingClientRect();
|
||||
|
||||
context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height);
|
||||
|
||||
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
||||
|
||||
pdfCanvas.width = containerRect.width;
|
||||
pdfCanvas.height = containerRect.height;
|
||||
|
||||
overlayCanvas.width = containerRect.width;
|
||||
overlayCanvas.height = containerRect.height;
|
||||
|
||||
let file = fileInput.files[0];
|
||||
renderPageFromFile(file);
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
canvasesContainer.style.display = "block"; // set for visual purposes
|
||||
let file = e.target.files[0];
|
||||
renderPageFromFile(file);
|
||||
});
|
||||
|
||||
cropForm.addEventListener('submit', function(e) {
|
||||
@@ -81,8 +117,8 @@
|
||||
// Ορίστε συντεταγμένες για ολόκληρη την επιφάνεια του PDF
|
||||
xInput.value = 0;
|
||||
yInput.value = 0;
|
||||
widthInput.value = pdfCanvas.width;
|
||||
heightInput.value = pdfCanvas.height;
|
||||
widthInput.value = containerRect.width;
|
||||
heightInput.value = containerRect.height;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -117,10 +153,10 @@
|
||||
|
||||
let flippedY = pdfCanvas.height - e.offsetY;
|
||||
|
||||
xInput.value = startX;
|
||||
yInput.value = flippedY;
|
||||
widthInput.value = rectWidth;
|
||||
heightInput.value = rectHeight;
|
||||
xInput.value = startX / pageScale;
|
||||
yInput.value = flippedY / pageScale;
|
||||
widthInput.value = rectWidth / pageScale;
|
||||
heightInput.value = rectHeight /pageScale;
|
||||
|
||||
// Draw the final rectangle on the main canvas
|
||||
context.strokeStyle = 'red';
|
||||
@@ -131,7 +167,16 @@
|
||||
|
||||
function renderPage(pageNumber) {
|
||||
pdfDoc.getPage(pageNumber).then(function(page) {
|
||||
let viewport = page.getViewport({ scale: 1.0 });
|
||||
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||
let containerRect = canvasesContainer.getBoundingClientRect();
|
||||
|
||||
pageScale = containerRect.width / page.getViewport({ scale: 1 }).width; // The new scale
|
||||
|
||||
let viewport = page.getViewport({ scale: containerRect.width / page.getViewport({ scale: 1 }).width });
|
||||
|
||||
canvasesContainer.width =viewport.width;
|
||||
canvasesContainer.height = viewport.height;
|
||||
|
||||
pdfCanvas.width = viewport.width;
|
||||
pdfCanvas.height = viewport.height;
|
||||
|
||||
|
||||
@@ -1,36 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pageExtracter.title}, header=#{pageExtracter.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">upload</span>
|
||||
<span class="tool-header-text" th:text="#{pageExtracter.header}"></span>
|
||||
</div>
|
||||
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<input type="hidden" id="customMode" name="customMode" value="">
|
||||
<div class="mb-3">
|
||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||
<input type="text" class="form-control" id="pageOrder" name="pageNumbers" th:placeholder="#{pageExtracter.placeholder}" required>
|
||||
</div>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pageExtracter.title}, header=#{pageExtracter.header})}">
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageExtracter.submit}"></button>
|
||||
</form>
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<th:block th:insert="~{fragments/multi-toolAdvert.html :: multi-toolAdvert}"></th:block>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">upload</span>
|
||||
<span class="tool-header-text" th:text="#{pageExtracter.header}"></span>
|
||||
</div>
|
||||
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<input type="hidden" id="customMode" name="customMode" value="">
|
||||
<div class="mb-3">
|
||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||
<input type="text" class="form-control" id="pageOrder" name="pageNumbers"
|
||||
th:placeholder="#{pageExtracter.placeholder}" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageExtracter.submit}"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
57
src/main/resources/templates/fragments/multi-toolAdvert.html
Normal file
57
src/main/resources/templates/fragments/multi-toolAdvert.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<div th:fragment="multi-toolAdvert" class="mx-auto">
|
||||
<div id="multi-toolAdvert" class="multi-toolAdvert">
|
||||
<div>
|
||||
<span th:utext="#{multiTool-advert.message(|/multi-tool|)}"></span>
|
||||
<button id="closeMultiToolAdvert" style="position: absolute;
|
||||
top: 10px;
|
||||
right: 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1;" aria-label="Close">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.multi-toolAdvert {
|
||||
margin-bottom: 10px;
|
||||
margin-left: 50%;
|
||||
transform: translateX(-50%);
|
||||
max-width: 52rem;
|
||||
z-index: 0;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 2rem;
|
||||
padding: 10px 27px 10px 20px;
|
||||
font-size: 0.9rem;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.multi-toolAdvert a {
|
||||
color: #007bff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.multi-toolAdvert a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const advert = document.getElementById('multi-toolAdvert');
|
||||
const closeBtn = document.getElementById('closeMultiToolAdvert');
|
||||
|
||||
const cacheKey = `closeMultiToolAdvert_${window.location.pathname}`;
|
||||
|
||||
if (localStorage.getItem(cacheKey) !== 'true') {
|
||||
advert.style.display = 'flex';
|
||||
}
|
||||
|
||||
closeBtn.addEventListener('click', () => {
|
||||
advert.style.display = 'none';
|
||||
localStorage.setItem(cacheKey, 'true');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
@@ -9,8 +9,10 @@
|
||||
<script th:inline="javascript">
|
||||
const currentVersion = /*[[${@appVersion}]]*/ '';
|
||||
const noFavourites = /*[[#{noFavourites}]]*/ '';
|
||||
const updateAvailable = /*[[#{settings.updateAvailable}]]*/ '';
|
||||
console.log(noFavourites);
|
||||
const updateAvailable = /*[[#{settings.updateAvailable}]]*/ '';
|
||||
</script>
|
||||
<script th:src="@{'/js/homecard.js'}"></script>
|
||||
<script th:src="@{'/js/githubVersion.js'}"></script>
|
||||
<nav class="navbar navbar-expand-xl">
|
||||
<div class="container ">
|
||||
@@ -308,10 +310,10 @@
|
||||
</li> -->
|
||||
|
||||
</ul>
|
||||
<ul class="navbar-nav flex-nowrap">
|
||||
<ul class="navbar-nav flex-nowrap">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" id="navbarDropdown-5" href="#" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
aria-haspopup="true" aria-expanded="false" th:title="#{navbar.favorite}">
|
||||
<span class="material-symbols-rounded">
|
||||
star
|
||||
</span>
|
||||
@@ -324,7 +326,7 @@
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="dark-mode-toggle" href="#">
|
||||
<a class="nav-link" id="dark-mode-toggle" href="#" th:title="#{navbar.darkmode}">
|
||||
<span class="material-symbols-rounded" id="dark-mode-icon">
|
||||
dark_mode
|
||||
</span>
|
||||
@@ -333,7 +335,7 @@
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
aria-haspopup="true" aria-expanded="false" th:title="#{navbar.language}">
|
||||
<span class="material-symbols-rounded">
|
||||
language
|
||||
</span>
|
||||
@@ -349,7 +351,7 @@
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" href="#" id="searchDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<a class="nav-link" href="#" id="searchDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" th:title="#{navbar.search}">
|
||||
<span class="material-symbols-rounded">
|
||||
search
|
||||
</span>
|
||||
@@ -358,7 +360,7 @@
|
||||
<div class="dropdown-menu dropdown-menu-tp" aria-labelledby="searchDropdown">
|
||||
<div class="dropdown-menu-wrapper px-xl-2 px-2">
|
||||
<form th:action="@{''}" class="d-flex p-2 search-form" id="searchForm">
|
||||
<input class="form-control search-input" type="search" placeholder="Search" aria-label="Search" id="navbarSearchInput">
|
||||
<input class="form-control search-input" type="search" th:placeholder="#{navbar.search}" aria-label="Search" id="navbarSearchInput">
|
||||
</form>
|
||||
<!-- Search Results -->
|
||||
<div id="searchResults" class="search-results scrollable-y dropdown-mw-20"></div>
|
||||
@@ -368,13 +370,13 @@
|
||||
|
||||
<li class="nav-item" th:if="${!@runningEE}">
|
||||
<a href="https://stirlingpdf.com/pricing" class="nav-link go-pro-link" target="_blank" rel="noopener noreferrer">
|
||||
<span class="go-pro-badge" th:text="#{enterpriseEdition.button}"></span>
|
||||
<span class="go-pro-badge" th:text="#{enterpriseEdition.button}"></span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<!-- Settings Button -->
|
||||
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal">
|
||||
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal" th:title="#{navbar.settings}">
|
||||
<span class="material-symbols-rounded">
|
||||
settings
|
||||
</span>
|
||||
@@ -405,14 +407,14 @@
|
||||
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 mt-3">
|
||||
<div class="footer-center" style="flex-direction: row;">
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF" class="mx-1" role="button"
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF" class="mx-1" role="button" target="_blank"
|
||||
th:title="#{visitGithub}">
|
||||
<img th:src="@{'/images/github.svg'}" alt="github">
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" th:title="#{seeDockerHub}">
|
||||
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}">
|
||||
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" th:title="#{joinDiscord}">
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}">
|
||||
<img th:src="@{'/images/discord.svg'}" alt="discord">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<th:block th:insert="~{fragments/multi-toolAdvert.html :: multi-toolAdvert}"></th:block>
|
||||
<div class="container" id="dropContainer">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
@@ -39,6 +40,9 @@
|
||||
<button type="button" id="sortByDateBtn" class="btn btn-info" th:text="#{merge.sortByDate}"></button>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{merge.submit}"></button>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="button" id="resetFileInputBtn" class="btn btn-danger" th:text="#{reset}">Reset</button>
|
||||
</div>
|
||||
</form>
|
||||
<span id="pageTranslation" th:text="#{page}" style="display:none;"></span>
|
||||
<span id="pagesTranslation" th:text="#{pages}" style="display:none;"></span>
|
||||
|
||||
@@ -47,18 +47,53 @@
|
||||
cut
|
||||
</span>
|
||||
</button>
|
||||
<button id="select-pages-container" class="btn btn-secondary enable-on-file"
|
||||
th:title="#{multiTool.selectPages}" onclick="toggleSelectPageVisibility()" disabled>
|
||||
<span id="select-pages-button" class="material-symbols-rounded">
|
||||
event_list
|
||||
</span>
|
||||
</button>
|
||||
<button id="select-All-Container" class="btn btn-secondary enable-on-file hidden"
|
||||
onclick="toggleSelectAll()" disabled>
|
||||
<span th:title="#{multiTool.selectAll}" class="material-symbols-rounded"
|
||||
id="select-icon">select_all</span>
|
||||
<span th:title="#{multiTool.deselectAll}" class="material-symbols-rounded" style="display: none;"
|
||||
id="deselect-icon">deselect</span>
|
||||
</button>
|
||||
<div class=" button-container">
|
||||
<button th:title="#{multiTool.deleteSelected}" id="delete-button" class="btn btn-danger hidden"
|
||||
onclick="deleteSelected()">
|
||||
<span class="material-symbols-rounded">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
<button id="export-selected-button" class="btn btn-primary enable-on-file hidden"
|
||||
onclick="exportPdf(true)" disabled>
|
||||
<span th:title="#{multiTool.downloadSelected}" class="material-symbols-rounded">
|
||||
file_save
|
||||
</span>
|
||||
</button>
|
||||
<button class="btn btn-secondary enable-on-file" onclick="addFilesBlankAll()" disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
insert_page_break
|
||||
</span>
|
||||
</button>
|
||||
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf()" disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf(false)" disabled>
|
||||
<span th:title="#{multiTool.downloadAll}" class="material-symbols-rounded">
|
||||
download
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="selected-pages-display" class="selected-pages-container hidden">
|
||||
<div style="display:flex; height:3rem; margin-right:1rem">
|
||||
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
||||
Pages</h5>
|
||||
<input type="text" id="csv-input" class="form-control" style="height:2.5rem" placeholder="1,3,5-10"
|
||||
value="">
|
||||
</div>
|
||||
<ul id="selected-pages-list" class="pages-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="multi-tool-container">
|
||||
<div class="d-flex flex-wrap" id="pages-container-wrapper">
|
||||
<div id="pages-container">
|
||||
@@ -82,6 +117,20 @@
|
||||
</div>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
||||
<script>
|
||||
window.selectedPages = [];
|
||||
window.selectPage = false;
|
||||
window.selectAll = false;
|
||||
const csvInput = document.getElementById("csv-input");
|
||||
csvInput.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Enter") {
|
||||
updatePagesFromCSV();
|
||||
}
|
||||
});
|
||||
csvInput.addEventListener("blur", function () {
|
||||
updatePagesFromCSV();
|
||||
});
|
||||
</script>
|
||||
<script type="module">
|
||||
import PdfContainer from './js/multitool/PdfContainer.js';
|
||||
import DragDropManager from "./js/multitool/DragDropManager.js";
|
||||
@@ -95,7 +144,6 @@
|
||||
// enables the default action buttons on each file
|
||||
const pdfActionsManager = new PdfActionsManager('pages-container');
|
||||
const fileDragManager = new FileDragManager();
|
||||
|
||||
// Scroll the wrapper horizontally
|
||||
|
||||
// Automatically exposes rotateAll, addFiles and exportPdf to the window for the global buttons.
|
||||
@@ -114,4 +162,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,60 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pdfOrganiser.title}, header=#{pdfOrganiser.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">format_list_bulleted</span>
|
||||
<span class="tool-header-text" th:text="#{pdfOrganiser.header}"></span>
|
||||
</div>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pdfOrganiser.title}, header=#{pdfOrganiser.header})}">
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label for="customMode" th:text="#{pdfOrganiser.mode}">Mode</label>
|
||||
<select class="form-control" id="customMode" name="customMode">
|
||||
<option value="" th:text="#{pdfOrganiser.mode.1}">Custom Page Order</option>
|
||||
<option value="REVERSE_ORDER" th:text="#{pdfOrganiser.mode.2}">Reverse Order</option>
|
||||
<option value="DUPLEX_SORT" th:text="#{pdfOrganiser.mode.3}">Duplex Sort</option>
|
||||
<option value="BOOKLET_SORT" th:text="#{pdfOrganiser.mode.4}">Booklet Sort</option>
|
||||
<option value="SIDE_STITCH_BOOKLET_SORT" th:text="#{pdfOrganiser.mode.5}">Side Stitch Booklet Sort</option>
|
||||
<option value="ODD_EVEN_SPLIT" th:text="#{pdfOrganiser.mode.6}">Odd-Even Split</option>
|
||||
<option value="ODD_EVEN_MERGE" th:text="#{pdfOrganiser.mode.10}">Odd-Even Merge</option>
|
||||
<option value="REMOVE_FIRST" th:text="#{pdfOrganiser.mode.7}">Remove First</option>
|
||||
<option value="REMOVE_LAST" th:text="#{pdfOrganiser.mode.8}">Remove Last</option>
|
||||
<option value="REMOVE_FIRST_AND_LAST" th:text="#{pdfOrganiser.mode.9}">Remove First and Last</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||
<input type="text" class="form-control" id="pageOrder" name="pageNumbers" th:placeholder="#{pdfOrganiser.placeholder}" required>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button>
|
||||
</form>
|
||||
<script>
|
||||
document.getElementById('customMode').addEventListener('change', function () {
|
||||
var pageOrderInput = document.getElementById('pageOrder');
|
||||
if (this.value === "") {
|
||||
pageOrderInput.disabled = false;
|
||||
} else {
|
||||
pageOrderInput.disabled = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<th:block th:insert="~{fragments/multi-toolAdvert.html :: multi-toolAdvert}"></th:block>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">format_list_bulleted</span>
|
||||
<span class="tool-header-text" th:text="#{pdfOrganiser.header}"></span>
|
||||
</div>
|
||||
|
||||
<form th:action="@{'/api/v1/general/rearrange-pages'}" method="post" enctype="multipart/form-data">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="customMode" th:text="#{pdfOrganiser.mode}">Mode</label>
|
||||
<select class="form-control" id="customMode" name="customMode">
|
||||
<option value="" th:text="#{pdfOrganiser.mode.1}">Custom Page Order</option>
|
||||
<option value="REVERSE_ORDER" th:text="#{pdfOrganiser.mode.2}">Reverse Order</option>
|
||||
<option value="DUPLEX_SORT" th:text="#{pdfOrganiser.mode.3}">Duplex Sort</option>
|
||||
<option value="BOOKLET_SORT" th:text="#{pdfOrganiser.mode.4}">Booklet Sort</option>
|
||||
<option value="SIDE_STITCH_BOOKLET_SORT" th:text="#{pdfOrganiser.mode.5}">Side Stitch Booklet Sort
|
||||
</option>
|
||||
<option value="ODD_EVEN_SPLIT" th:text="#{pdfOrganiser.mode.6}">Odd-Even Split</option>
|
||||
<option value="ODD_EVEN_MERGE" th:text="#{pdfOrganiser.mode.10}">Odd-Even Merge</option>
|
||||
<option value="REMOVE_FIRST" th:text="#{pdfOrganiser.mode.7}">Remove First</option>
|
||||
<option value="REMOVE_LAST" th:text="#{pdfOrganiser.mode.8}">Remove Last</option>
|
||||
<option value="REMOVE_FIRST_AND_LAST" th:text="#{pdfOrganiser.mode.9}">Remove First and Last</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pageOrder" th:text="#{pageOrderPrompt}"></label>
|
||||
<input type="text" class="form-control" id="pageOrder" name="pageNumbers"
|
||||
th:placeholder="#{pdfOrganiser.placeholder}" required>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfOrganiser.submit}"></button>
|
||||
</form>
|
||||
<script>
|
||||
document.getElementById('customMode').addEventListener('change', function () {
|
||||
var pageOrderInput = document.getElementById('pageOrder');
|
||||
if (this.value === "") {
|
||||
pageOrderInput.disabled = false;
|
||||
} else {
|
||||
pageOrderInput.disabled = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,40 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pageRemover.title}, header=#{pageRemover.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">delete</span>
|
||||
<span class="tool-header-text" th:text="#{pageRemover.header}"></span>
|
||||
</div>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pageRemover.title}, header=#{pageRemover.header})}">
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<form th:action="@{'/api/v1/general/remove-pages'}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label for="fileInput" th:text="#{pageRemover.pagesToDelete}"></label>
|
||||
<input type="text" class="form-control" id="fileInput" name="pageNumbers" th:placeholder="#{pageRemover.placeholder}" required>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
||||
</form>
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<th:block th:insert="~{fragments/multi-toolAdvert.html :: multi-toolAdvert}"></th:block>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">delete</span>
|
||||
<span class="tool-header-text" th:text="#{pageRemover.header}"></span>
|
||||
</div>
|
||||
|
||||
<form th:action="@{'/api/v1/general/remove-pages'}" method="post" enctype="multipart/form-data">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="fileInput" th:text="#{pageRemover.pagesToDelete}"></label>
|
||||
<input type="text" class="form-control" id="fileInput" name="pageNumbers"
|
||||
th:placeholder="#{pageRemover.placeholder}" required>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('fileInput').addEventListener('input', function(){
|
||||
this.value =this.value.replace(/\s+/g, '');;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('fileInput').addEventListener('input', function () {
|
||||
this.value = this.value.replace(/\s+/g, '');;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,110 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{rotate.title}, header=#{rotate.header})}"></th:block>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">rotate_right</span>
|
||||
<span class="tool-header-text" th:text="#{rotate.header}"></span>
|
||||
</div>
|
||||
|
||||
<form action="#" th:action="@{'/api/v1/general/rotate-pdf'}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<input type="hidden" id="angleInput" name="angle" value="0">
|
||||
|
||||
<div id="editSection" style="display: none">
|
||||
<div id="previewContainer">
|
||||
<!-- pdf-preview -->
|
||||
</div>
|
||||
|
||||
<div class="buttonContainer">
|
||||
<button type="button" class="btn btn-secondary" onclick="rotate(-90)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" />
|
||||
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{rotate.submit}"></button>
|
||||
<button type="button" class="btn btn-secondary" onclick="rotate(90)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
|
||||
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<th:block th:insert="~{fragments/multi-toolAdvert.html :: multi-toolAdvert}"></th:block>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon organize">rotate_right</span>
|
||||
<span class="tool-header-text" th:text="#{rotate.header}"></span>
|
||||
</div>
|
||||
|
||||
<form action="#" th:action="@{'/api/v1/general/rotate-pdf'}" th:object="${rotateForm}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<input type="hidden" id="angleInput" name="angle" value="0">
|
||||
|
||||
<div id="editSection" style="display: none">
|
||||
<div id="previewContainer">
|
||||
<!-- pdf-preview -->
|
||||
</div>
|
||||
|
||||
<div class="buttonContainer">
|
||||
<button type="button" class="btn btn-secondary" onclick="rotate(-90)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" />
|
||||
<path
|
||||
d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{rotate.submit}"></button>
|
||||
<button type="button" class="btn btn-secondary" onclick="rotate(90)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
|
||||
<path
|
||||
d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script>
|
||||
const angleInput = document.getElementById("angleInput");
|
||||
const fileInput = document.getElementById("fileInput-input");
|
||||
const previewContainer = document.getElementById("previewContainer");
|
||||
// const preview = document.getElementById("pdf-preview");
|
||||
fileInput.addEventListener("change", async function() {
|
||||
console.log("loading pdf");
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script>
|
||||
const angleInput = document.getElementById("angleInput");
|
||||
const fileInput = document.getElementById("fileInput-input");
|
||||
const previewContainer = document.getElementById("previewContainer");
|
||||
// const preview = document.getElementById("pdf-preview");
|
||||
fileInput.addEventListener("change", async function () {
|
||||
console.log("loading pdf");
|
||||
|
||||
document.querySelector("#editSection").style.display = "";
|
||||
document.querySelector("#editSection").style.display = "block";
|
||||
|
||||
const existingPreview = document.getElementById("pdf-preview");
|
||||
if (existingPreview) {
|
||||
existingPreview.remove();
|
||||
}
|
||||
var url = URL.createObjectURL(fileInput.files[0])
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'
|
||||
const pdf = await pdfjsLib.getDocument(url).promise;
|
||||
const page = await pdf.getPage(1);
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
|
||||
// set the canvas size to the size of the page
|
||||
if (page.rotate == 90 || page.rotate == 270) {
|
||||
canvas.width = page.view[3];
|
||||
canvas.height = page.view[2];
|
||||
} else {
|
||||
canvas.width = page.view[2];
|
||||
canvas.height = page.view[3];
|
||||
}
|
||||
|
||||
// render the page onto the canvas
|
||||
var renderContext = {
|
||||
canvasContext: canvas.getContext("2d"),
|
||||
viewport: page.getViewport({ scale: 1 })
|
||||
};
|
||||
|
||||
await page.render(renderContext).promise;
|
||||
const preview = document.createElement("img");
|
||||
preview.id = "pdf-preview";
|
||||
preview.alt = "preview";
|
||||
preview.src = canvas.toDataURL();
|
||||
previewContainer.appendChild(preview);
|
||||
});
|
||||
|
||||
function rotate(deg) {
|
||||
const preview = document.getElementById("pdf-preview");
|
||||
var lastTransform = preview.style.rotate;
|
||||
if (!lastTransform) {
|
||||
lastTransform = "0";
|
||||
}
|
||||
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ''));
|
||||
const newAngle = lastAngle + deg;
|
||||
preview.style.rotate = newAngle + "deg";
|
||||
angleInput.value = newAngle;
|
||||
const existingPreview = document.getElementById("pdf-preview");
|
||||
if (existingPreview) {
|
||||
existingPreview.remove();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
var url = URL.createObjectURL(fileInput.files[0])
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'
|
||||
const pdf = await pdfjsLib.getDocument(url).promise;
|
||||
const page = await pdf.getPage(1);
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
|
||||
// set the canvas size to the size of the page
|
||||
if (page.rotate == 90 || page.rotate == 270) {
|
||||
canvas.width = page.view[3];
|
||||
canvas.height = page.view[2];
|
||||
} else {
|
||||
canvas.width = page.view[2];
|
||||
canvas.height = page.view[3];
|
||||
}
|
||||
|
||||
// render the page onto the canvas
|
||||
var renderContext = {
|
||||
canvasContext: canvas.getContext("2d"),
|
||||
viewport: page.getViewport({ scale: 1 })
|
||||
};
|
||||
|
||||
await page.render(renderContext).promise;
|
||||
const preview = document.createElement("img");
|
||||
preview.id = "pdf-preview";
|
||||
preview.alt = "preview";
|
||||
preview.src = canvas.toDataURL();
|
||||
previewContainer.appendChild(preview);
|
||||
});
|
||||
|
||||
function rotate(deg) {
|
||||
const preview = document.getElementById("pdf-preview");
|
||||
var lastTransform = preview.style.rotate;
|
||||
if (!lastTransform) {
|
||||
lastTransform = "0";
|
||||
}
|
||||
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ''));
|
||||
const newAngle = lastAngle + deg;
|
||||
preview.style.rotate = newAngle + "deg";
|
||||
angleInput.value = newAngle;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -30,10 +30,8 @@
|
||||
<!-- Button to download the JSON -->
|
||||
<a href="#" id="downloadJson" class="btn btn-primary mt-3" style="display: none;" th:text="#{getPdfInfo.downloadJson}">Download JSON</a>
|
||||
</div>
|
||||
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
||||
<script>
|
||||
|
||||
import { fetchWithCsrf } from 'js/fetch-utils.js';
|
||||
|
||||
|
||||
document.getElementById("pdfInfoForm").addEventListener("submit", function(event) {
|
||||
event.preventDefault();
|
||||
@@ -156,4 +154,4 @@
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -31,11 +31,13 @@
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="includeMetadata" name="includeMetadata">
|
||||
<label class="form-check-label" for="includeMetadata" th:text="#{splitByChapters.includeMetadata}"></label>
|
||||
<input type="hidden" name="includeMetadata" value="false" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="allowDuplicates" name="allowDuplicates">
|
||||
<label class="form-check-label" for="allowDuplicates" th:text="#{splitByChapters.allowDuplicates}"></label>
|
||||
<input type="hidden" name="allowDuplicates" value="false" />
|
||||
</div>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<th:block th:insert="~{fragments/multi-toolAdvert.html :: multi-toolAdvert}"></th:block>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
|
||||
@@ -184,7 +184,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
|
||||
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
|
||||
<div id="secondaryToolbarButtonContainer">
|
||||
<button id="secondaryOpenFile" class="secondaryToolbarButton" hidden="true" title="Open File" tabindex="51" data-l10n-id="pdfjs-open-file-button">
|
||||
<button id="secondaryOpenFile" class="secondaryToolbarButton visibleMediumView" title="Open File" tabindex="51" data-l10n-id="pdfjs-open-file-button">
|
||||
<span data-l10n-id="pdfjs-open-file-button-label">Open</span>
|
||||
</button>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user